blob: 0c72862bf1c7350cfb6f8896e0b05b872311317d [file] [log] [blame]
Dennis Kempin19e972b2013-06-20 13:21:38 -07001#! /usr/bin/env python
2# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
Harry Cutts0edf1572020-01-21 15:42:10 -08005
Harry Cutts85378ee2020-02-07 15:53:46 -08006from __future__ import absolute_import
7from __future__ import division
Harry Cutts0edf1572020-01-21 15:42:10 -08008from __future__ import print_function
9
Dennis Kempin6e03a432013-06-25 09:00:53 -070010from mtedit import MTEdit
11from mtlib import Log
12from mtreplay import MTReplay
Dennis Kempin19e972b2013-06-20 13:21:38 -070013from mtstat import MTStat
Dennis Kempin6e03a432013-06-25 09:00:53 -070014from optparse import OptionParser
Dennis Kempin19e972b2013-06-20 13:21:38 -070015
16usage = """Multitouch Statistic Collector
17
Dennis Kempin253ee052013-07-01 14:58:22 -070018This tool is used to gather statistics on large amounts of touchpad data from
19feedback reports. Samples are gathered by parsing the log output of the
20gestures library. The gesture library provides the MTStatSample/Set commands to
21create samples.
Dennis Kempin6e03a432013-06-25 09:00:53 -070022
Dennis Kempin253ee052013-07-01 14:58:22 -070023Gestures Library API
24--------------------
Dennis Kempin6e03a432013-06-25 09:00:53 -070025
Dennis Kempin253ee052013-07-01 14:58:22 -070026For example you can extend a decision tree in the gestures library code with
27calls to:
Dennis Kempin6e03a432013-06-25 09:00:53 -070028
Dennis Kempin253ee052013-07-01 14:58:22 -070029MTStatSample("MyDecision", "CaseA");
30MTStatSample("MyDecision", "CaseB");
31MTStatSample("MyDecision", "CaseC");
32
33Next to string samples you can also sample integers with MTStatSampleInt.
34For example you can sample the number of fingers in each hardware state:
35
36MTStatSampleInt("NumFingers", hwstate.num_fingers);
37
38Sometimes you want to only generate one sample per file, for example to
39count the number of clicks in each file. Call MTStatUpdate[Int] every time
40your value is changed and the last update will be used by MTStat.
41For example every time a click is performed you call the following:
42
43static int num_of_clicks = 0;
44MTStatUpdateInt("NumClicks", ++num_of_clicks);
45
46Preparing MTStat
47----------------
48
49To run on feedback reports you first have to download a bunch of them. MTStat
50does this for you, for example by downloading the latest 1000 reports:
51
52$ %prog -d 1000
53
54Sample Histograms
55------------------
56
57Running mtstat will then generate statistic on how often each of the logged
58cases happened. Optionally you can specify the number of log files to process,
59per default it will always run all downloaded reports:
60
61$ %prog [-n 1000]
62
63The output will be presented as a histogram of how often each case appeared.
64For integer samples with a lot of different values, a bin-based histogram is
65used.
66
67Searching Samples
68-----------------
69
70You can then also search for cases and view their activity log to figure out
71which user activity lead to this decision. For example:
72
73$ %prog -s "MyDecision == CaseC" [-n 100]
74
75When searching integer samples, unequality operators are supported:
76
77$ %prog -s "NumFingers >= 3" [-n 100]
78
79Of course the same thing works on samples made with MTStatUpdate. For example
80to find files with a lot of clicks:
81
82$ %prog -s "NumClicks > 300" [-n 100]
83
84Advanced Search
85---------------
86
87You can search the gestures library log output with regular expressions.
88For example to see if any ERROR messages happen:
89
90$ %prog -r "ERROR:"
91
Dennis Kempind5b59022013-07-17 14:12:55 -070092Searching for Changed Gestures
93------------------------------
94
95MTStat can also be used to search for changes in the generated gestures
96introduced by changes to the code of the gestures library.
97
98In order to do so make local changes to the gestures library without
99commiting them. Then run:
100
101$ %prog -c [-n 100]
102
103This command will compare to the HEAD version of gestures and present all
104changed gestures.
105
106You can also limit the search to a certain type of gestures:
107
108$ %prog -c -g "ButtonDown" [-n 100]
Dennis Kempin19e972b2013-06-20 13:21:38 -0700109"""
110
111def main():
112 parser = OptionParser(usage=usage)
Dennis Kempin253ee052013-07-01 14:58:22 -0700113 parser.add_option('-d', '--download',
Dennis Kempin19e972b2013-06-20 13:21:38 -0700114 dest='download', default=None,
115 help='download more log files')
Dennis Kempin253ee052013-07-01 14:58:22 -0700116 parser.add_option('-n', '--number',
Dennis Kempin19e972b2013-06-20 13:21:38 -0700117 dest='number', default=None,
118 help='number of log files to gather stats on')
Dennis Kempin7432eb02014-03-18 13:41:41 -0700119 parser.add_option('-p', '--platform',
120 dest='platform', default=None,
121 help='only use log files from specified platform')
Dennis Kempin253ee052013-07-01 14:58:22 -0700122 parser.add_option('-s', '--search',
Dennis Kempin6e03a432013-06-25 09:00:53 -0700123 dest='search', default=None,
124 help='search for specific tags')
Dennis Kempin253ee052013-07-01 14:58:22 -0700125 parser.add_option('-l', '--list',
126 dest='list', action='store_true', default=False,
127 help='just print list, don\'t view search results')
128 parser.add_option('-r', '--regex',
129 dest='regex', default=None,
130 help='search log output for regex')
Dennis Kempind5b59022013-07-17 14:12:55 -0700131 parser.add_option('-g', '--gestures',
132 dest='gestures', default=None,
133 help='search log for gestures')
134 parser.add_option('-b', '--bins',
135 dest='bins', default=10,
136 help='number of bins for histograms')
137 parser.add_option('-c', '--changes',
138 dest='changes', action='store_true', default=False,
139 help='search for changes introduced by ' +
140 'local code changes to the gestures library')
141
Dennis Kempin19e972b2013-06-20 13:21:38 -0700142 (options, args) = parser.parse_args()
143
144 stat = MTStat()
145 if options.download:
Sean O'Brienfd204da2017-05-02 15:13:11 -0700146 stat.Download(options.download)
Dennis Kempin19e972b2013-06-20 13:21:38 -0700147 return
148
149 number = None if options.number is None else int(options.number)
Dennis Kempin6e03a432013-06-25 09:00:53 -0700150
Dennis Kempind5b59022013-07-17 14:12:55 -0700151 if (options.search or options.regex or options.gestures or
152 options.changes):
153 if options.changes:
154 results = stat.SearchChanges(options.gestures,
Dennis Kempin7432eb02014-03-18 13:41:41 -0700155 number=number, platform=options.platform)
Dennis Kempin253ee052013-07-01 14:58:22 -0700156 else:
Dennis Kempind5b59022013-07-17 14:12:55 -0700157 results = stat.Search(search=options.search, gestures=options.gestures,
Dennis Kempin7432eb02014-03-18 13:41:41 -0700158 regex=options.regex, number=number,
159 platform=options.platform)
Dennis Kempin253ee052013-07-01 14:58:22 -0700160
Harry Cutts0edf1572020-01-21 15:42:10 -0800161 print("Found occurences in %d files" % len(results))
162 print("Serving results, press CTRL-C to abort")
Dennis Kempind5b59022013-07-17 14:12:55 -0700163 for filename, result in results.items():
Harry Cutts0edf1572020-01-21 15:42:10 -0800164 print("%d occurences in %s:" % (len(result.matches), filename))
Dennis Kempind5b59022013-07-17 14:12:55 -0700165 for match in result.matches:
Harry Cutts0edf1572020-01-21 15:42:10 -0800166 print(" ", match)
Dennis Kempin6e03a432013-06-25 09:00:53 -0700167
Dennis Kempin253ee052013-07-01 14:58:22 -0700168 # display link to MTEdit session
169 if not options.list:
Dennis Kempind5b59022013-07-17 14:12:55 -0700170 MTEdit().View(result.log, result.matches[0].timestamp)
Dennis Kempin253ee052013-07-01 14:58:22 -0700171 raw_input("Press Enter to continue...")
Dennis Kempin6e03a432013-06-25 09:00:53 -0700172 return
173
Dennis Kempind5b59022013-07-17 14:12:55 -0700174
175 bins = int(options.bins)
Dennis Kempin7432eb02014-03-18 13:41:41 -0700176 results = stat.GatherStats(number, platform=options.platform, num_bins=bins)
Dennis Kempin253ee052013-07-01 14:58:22 -0700177 for key, hist in results.items():
Harry Cutts0edf1572020-01-21 15:42:10 -0800178 print("%s:" % key)
Dennis Kempin253ee052013-07-01 14:58:22 -0700179 overall_count = sum(hist.values())
180 for value, count in hist.items():
181 percent = int(round(float(count) / float(overall_count) * 100))
182 percent_str = "(" + str(percent) + "%)"
183 graph = "=" * int(round(percent / 2))
Harry Cutts0edf1572020-01-21 15:42:10 -0800184 print(" {0:>6} {1:<6} {2:6} |{3}".format(
185 str(value) + ":", count, percent_str, graph))
Dennis Kempin19e972b2013-06-20 13:21:38 -0700186
187if __name__ == '__main__':
Sean O'Brienfd204da2017-05-02 15:13:11 -0700188 main()