blob: 85eae512a0f5af60e9ad070888ea90037c6be094 [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.
Dennis Kempin6e03a432013-06-25 09:00:53 -07005from mtedit import MTEdit
6from mtlib import Log
7from mtreplay import MTReplay
Dennis Kempin19e972b2013-06-20 13:21:38 -07008from mtstat import MTStat
Dennis Kempin6e03a432013-06-25 09:00:53 -07009from optparse import OptionParser
Dennis Kempin19e972b2013-06-20 13:21:38 -070010
11usage = """Multitouch Statistic Collector
12
Dennis Kempin253ee052013-07-01 14:58:22 -070013This tool is used to gather statistics on large amounts of touchpad data from
14feedback reports. Samples are gathered by parsing the log output of the
15gestures library. The gesture library provides the MTStatSample/Set commands to
16create samples.
Dennis Kempin6e03a432013-06-25 09:00:53 -070017
Dennis Kempin253ee052013-07-01 14:58:22 -070018Gestures Library API
19--------------------
Dennis Kempin6e03a432013-06-25 09:00:53 -070020
Dennis Kempin253ee052013-07-01 14:58:22 -070021For example you can extend a decision tree in the gestures library code with
22calls to:
Dennis Kempin6e03a432013-06-25 09:00:53 -070023
Dennis Kempin253ee052013-07-01 14:58:22 -070024MTStatSample("MyDecision", "CaseA");
25MTStatSample("MyDecision", "CaseB");
26MTStatSample("MyDecision", "CaseC");
27
28Next to string samples you can also sample integers with MTStatSampleInt.
29For example you can sample the number of fingers in each hardware state:
30
31MTStatSampleInt("NumFingers", hwstate.num_fingers);
32
33Sometimes you want to only generate one sample per file, for example to
34count the number of clicks in each file. Call MTStatUpdate[Int] every time
35your value is changed and the last update will be used by MTStat.
36For example every time a click is performed you call the following:
37
38static int num_of_clicks = 0;
39MTStatUpdateInt("NumClicks", ++num_of_clicks);
40
41Preparing MTStat
42----------------
43
44To run on feedback reports you first have to download a bunch of them. MTStat
45does this for you, for example by downloading the latest 1000 reports:
46
47$ %prog -d 1000
48
49Sample Histograms
50------------------
51
52Running mtstat will then generate statistic on how often each of the logged
53cases happened. Optionally you can specify the number of log files to process,
54per default it will always run all downloaded reports:
55
56$ %prog [-n 1000]
57
58The output will be presented as a histogram of how often each case appeared.
59For integer samples with a lot of different values, a bin-based histogram is
60used.
61
62Searching Samples
63-----------------
64
65You can then also search for cases and view their activity log to figure out
66which user activity lead to this decision. For example:
67
68$ %prog -s "MyDecision == CaseC" [-n 100]
69
70When searching integer samples, unequality operators are supported:
71
72$ %prog -s "NumFingers >= 3" [-n 100]
73
74Of course the same thing works on samples made with MTStatUpdate. For example
75to find files with a lot of clicks:
76
77$ %prog -s "NumClicks > 300" [-n 100]
78
79Advanced Search
80---------------
81
82You can search the gestures library log output with regular expressions.
83For example to see if any ERROR messages happen:
84
85$ %prog -r "ERROR:"
86
Dennis Kempind5b59022013-07-17 14:12:55 -070087Searching for Changed Gestures
88------------------------------
89
90MTStat can also be used to search for changes in the generated gestures
91introduced by changes to the code of the gestures library.
92
93In order to do so make local changes to the gestures library without
94commiting them. Then run:
95
96$ %prog -c [-n 100]
97
98This command will compare to the HEAD version of gestures and present all
99changed gestures.
100
101You can also limit the search to a certain type of gestures:
102
103$ %prog -c -g "ButtonDown" [-n 100]
Dennis Kempin19e972b2013-06-20 13:21:38 -0700104"""
105
106def main():
107 parser = OptionParser(usage=usage)
Dennis Kempin253ee052013-07-01 14:58:22 -0700108 parser.add_option('-d', '--download',
Dennis Kempin19e972b2013-06-20 13:21:38 -0700109 dest='download', default=None,
110 help='download more log files')
Dennis Kempin253ee052013-07-01 14:58:22 -0700111 parser.add_option('-o', '--offset',
Dennis Kempin19e972b2013-06-20 13:21:38 -0700112 dest='offset', default=0,
113 help='offset for downloading log files')
Dennis Kempin253ee052013-07-01 14:58:22 -0700114 parser.add_option('-n', '--number',
Dennis Kempin19e972b2013-06-20 13:21:38 -0700115 dest='number', default=None,
116 help='number of log files to gather stats on')
Dennis Kempin7432eb02014-03-18 13:41:41 -0700117 parser.add_option('-p', '--platform',
118 dest='platform', default=None,
119 help='only use log files from specified platform')
Dennis Kempin253ee052013-07-01 14:58:22 -0700120 parser.add_option('-s', '--search',
Dennis Kempin6e03a432013-06-25 09:00:53 -0700121 dest='search', default=None,
122 help='search for specific tags')
Dennis Kempin253ee052013-07-01 14:58:22 -0700123 parser.add_option('-l', '--list',
124 dest='list', action='store_true', default=False,
125 help='just print list, don\'t view search results')
126 parser.add_option('-r', '--regex',
127 dest='regex', default=None,
128 help='search log output for regex')
Dennis Kempind5b59022013-07-17 14:12:55 -0700129 parser.add_option('-g', '--gestures',
130 dest='gestures', default=None,
131 help='search log for gestures')
132 parser.add_option('-b', '--bins',
133 dest='bins', default=10,
134 help='number of bins for histograms')
135 parser.add_option('-c', '--changes',
136 dest='changes', action='store_true', default=False,
137 help='search for changes introduced by ' +
138 'local code changes to the gestures library')
139
Dennis Kempin19e972b2013-06-20 13:21:38 -0700140 (options, args) = parser.parse_args()
141
142 stat = MTStat()
143 if options.download:
144 stat.Download(options.download, options.offset)
145 return
146
147 number = None if options.number is None else int(options.number)
Dennis Kempin6e03a432013-06-25 09:00:53 -0700148
Dennis Kempind5b59022013-07-17 14:12:55 -0700149 if (options.search or options.regex or options.gestures or
150 options.changes):
151 if options.changes:
152 results = stat.SearchChanges(options.gestures,
Dennis Kempin7432eb02014-03-18 13:41:41 -0700153 number=number, platform=options.platform)
Dennis Kempin253ee052013-07-01 14:58:22 -0700154 else:
Dennis Kempind5b59022013-07-17 14:12:55 -0700155 results = stat.Search(search=options.search, gestures=options.gestures,
Dennis Kempin7432eb02014-03-18 13:41:41 -0700156 regex=options.regex, number=number,
157 platform=options.platform)
Dennis Kempin253ee052013-07-01 14:58:22 -0700158
Dennis Kempin6e03a432013-06-25 09:00:53 -0700159 print "Found occurences in %d files" % len(results)
160 print "Serving results, press CTRL-C to abort"
Dennis Kempind5b59022013-07-17 14:12:55 -0700161 for filename, result in results.items():
162 print "%d occurences in %s:" % (len(result.matches), filename)
163 for match in result.matches:
164 print " ", match
Dennis Kempin6e03a432013-06-25 09:00:53 -0700165
Dennis Kempin253ee052013-07-01 14:58:22 -0700166 # display link to MTEdit session
167 if not options.list:
Dennis Kempind5b59022013-07-17 14:12:55 -0700168 MTEdit().View(result.log, result.matches[0].timestamp)
Dennis Kempin253ee052013-07-01 14:58:22 -0700169 raw_input("Press Enter to continue...")
Dennis Kempin6e03a432013-06-25 09:00:53 -0700170 return
171
Dennis Kempind5b59022013-07-17 14:12:55 -0700172
173 bins = int(options.bins)
Dennis Kempin7432eb02014-03-18 13:41:41 -0700174 results = stat.GatherStats(number, platform=options.platform, num_bins=bins)
Dennis Kempin253ee052013-07-01 14:58:22 -0700175 for key, hist in results.items():
176 print "%s:" % key
177 overall_count = sum(hist.values())
178 for value, count in hist.items():
179 percent = int(round(float(count) / float(overall_count) * 100))
180 percent_str = "(" + str(percent) + "%)"
181 graph = "=" * int(round(percent / 2))
182 print " {0:>6} {1:<6} {2:6} |{3}".format(
183 str(value) + ":", count, percent_str, graph)
Dennis Kempin19e972b2013-06-20 13:21:38 -0700184
185if __name__ == '__main__':
186 main()