blob: 971ea7f3af3faaf95a64dd526f9c4fe182f084c1 [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 Kempin253ee052013-07-01 14:58:22 -0700117 parser.add_option('-s', '--search',
Dennis Kempin6e03a432013-06-25 09:00:53 -0700118 dest='search', default=None,
119 help='search for specific tags')
Dennis Kempin253ee052013-07-01 14:58:22 -0700120 parser.add_option('-l', '--list',
121 dest='list', action='store_true', default=False,
122 help='just print list, don\'t view search results')
123 parser.add_option('-r', '--regex',
124 dest='regex', default=None,
125 help='search log output for regex')
Dennis Kempind5b59022013-07-17 14:12:55 -0700126 parser.add_option('-g', '--gestures',
127 dest='gestures', default=None,
128 help='search log for gestures')
129 parser.add_option('-b', '--bins',
130 dest='bins', default=10,
131 help='number of bins for histograms')
132 parser.add_option('-c', '--changes',
133 dest='changes', action='store_true', default=False,
134 help='search for changes introduced by ' +
135 'local code changes to the gestures library')
136
Dennis Kempin19e972b2013-06-20 13:21:38 -0700137 (options, args) = parser.parse_args()
138
139 stat = MTStat()
140 if options.download:
141 stat.Download(options.download, options.offset)
142 return
143
144 number = None if options.number is None else int(options.number)
Dennis Kempin6e03a432013-06-25 09:00:53 -0700145
Dennis Kempind5b59022013-07-17 14:12:55 -0700146 if (options.search or options.regex or options.gestures or
147 options.changes):
148 if options.changes:
149 results = stat.SearchChanges(options.gestures,
150 number=number)
Dennis Kempin253ee052013-07-01 14:58:22 -0700151 else:
Dennis Kempind5b59022013-07-17 14:12:55 -0700152 results = stat.Search(search=options.search, gestures=options.gestures,
153 regex=options.regex, number=number)
Dennis Kempin253ee052013-07-01 14:58:22 -0700154
Dennis Kempin6e03a432013-06-25 09:00:53 -0700155 print "Found occurences in %d files" % len(results)
156 print "Serving results, press CTRL-C to abort"
Dennis Kempind5b59022013-07-17 14:12:55 -0700157 for filename, result in results.items():
158 print "%d occurences in %s:" % (len(result.matches), filename)
159 for match in result.matches:
160 print " ", match
Dennis Kempin6e03a432013-06-25 09:00:53 -0700161
Dennis Kempin253ee052013-07-01 14:58:22 -0700162 # display link to MTEdit session
163 if not options.list:
Dennis Kempind5b59022013-07-17 14:12:55 -0700164 MTEdit().View(result.log, result.matches[0].timestamp)
Dennis Kempin253ee052013-07-01 14:58:22 -0700165 raw_input("Press Enter to continue...")
Dennis Kempin6e03a432013-06-25 09:00:53 -0700166 return
167
Dennis Kempind5b59022013-07-17 14:12:55 -0700168
169 bins = int(options.bins)
170 results = stat.GatherStats(number, num_bins=bins)
Dennis Kempin253ee052013-07-01 14:58:22 -0700171 for key, hist in results.items():
172 print "%s:" % key
173 overall_count = sum(hist.values())
174 for value, count in hist.items():
175 percent = int(round(float(count) / float(overall_count) * 100))
176 percent_str = "(" + str(percent) + "%)"
177 graph = "=" * int(round(percent / 2))
178 print " {0:>6} {1:<6} {2:6} |{3}".format(
179 str(value) + ":", count, percent_str, graph)
Dennis Kempin19e972b2013-06-20 13:21:38 -0700180
181if __name__ == '__main__':
182 main()