blob: 68a834b8867483cd2e508fd35e2f47b69fe9d1d4 [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
6from __future__ import print_function
7
Dennis Kempin6e03a432013-06-25 09:00:53 -07008from mtedit import MTEdit
9from mtlib import Log
10from mtreplay import MTReplay
Dennis Kempin19e972b2013-06-20 13:21:38 -070011from mtstat import MTStat
Dennis Kempin6e03a432013-06-25 09:00:53 -070012from optparse import OptionParser
Dennis Kempin19e972b2013-06-20 13:21:38 -070013
14usage = """Multitouch Statistic Collector
15
Dennis Kempin253ee052013-07-01 14:58:22 -070016This tool is used to gather statistics on large amounts of touchpad data from
17feedback reports. Samples are gathered by parsing the log output of the
18gestures library. The gesture library provides the MTStatSample/Set commands to
19create samples.
Dennis Kempin6e03a432013-06-25 09:00:53 -070020
Dennis Kempin253ee052013-07-01 14:58:22 -070021Gestures Library API
22--------------------
Dennis Kempin6e03a432013-06-25 09:00:53 -070023
Dennis Kempin253ee052013-07-01 14:58:22 -070024For example you can extend a decision tree in the gestures library code with
25calls to:
Dennis Kempin6e03a432013-06-25 09:00:53 -070026
Dennis Kempin253ee052013-07-01 14:58:22 -070027MTStatSample("MyDecision", "CaseA");
28MTStatSample("MyDecision", "CaseB");
29MTStatSample("MyDecision", "CaseC");
30
31Next to string samples you can also sample integers with MTStatSampleInt.
32For example you can sample the number of fingers in each hardware state:
33
34MTStatSampleInt("NumFingers", hwstate.num_fingers);
35
36Sometimes you want to only generate one sample per file, for example to
37count the number of clicks in each file. Call MTStatUpdate[Int] every time
38your value is changed and the last update will be used by MTStat.
39For example every time a click is performed you call the following:
40
41static int num_of_clicks = 0;
42MTStatUpdateInt("NumClicks", ++num_of_clicks);
43
44Preparing MTStat
45----------------
46
47To run on feedback reports you first have to download a bunch of them. MTStat
48does this for you, for example by downloading the latest 1000 reports:
49
50$ %prog -d 1000
51
52Sample Histograms
53------------------
54
55Running mtstat will then generate statistic on how often each of the logged
56cases happened. Optionally you can specify the number of log files to process,
57per default it will always run all downloaded reports:
58
59$ %prog [-n 1000]
60
61The output will be presented as a histogram of how often each case appeared.
62For integer samples with a lot of different values, a bin-based histogram is
63used.
64
65Searching Samples
66-----------------
67
68You can then also search for cases and view their activity log to figure out
69which user activity lead to this decision. For example:
70
71$ %prog -s "MyDecision == CaseC" [-n 100]
72
73When searching integer samples, unequality operators are supported:
74
75$ %prog -s "NumFingers >= 3" [-n 100]
76
77Of course the same thing works on samples made with MTStatUpdate. For example
78to find files with a lot of clicks:
79
80$ %prog -s "NumClicks > 300" [-n 100]
81
82Advanced Search
83---------------
84
85You can search the gestures library log output with regular expressions.
86For example to see if any ERROR messages happen:
87
88$ %prog -r "ERROR:"
89
Dennis Kempind5b59022013-07-17 14:12:55 -070090Searching for Changed Gestures
91------------------------------
92
93MTStat can also be used to search for changes in the generated gestures
94introduced by changes to the code of the gestures library.
95
96In order to do so make local changes to the gestures library without
97commiting them. Then run:
98
99$ %prog -c [-n 100]
100
101This command will compare to the HEAD version of gestures and present all
102changed gestures.
103
104You can also limit the search to a certain type of gestures:
105
106$ %prog -c -g "ButtonDown" [-n 100]
Dennis Kempin19e972b2013-06-20 13:21:38 -0700107"""
108
109def main():
110 parser = OptionParser(usage=usage)
Dennis Kempin253ee052013-07-01 14:58:22 -0700111 parser.add_option('-d', '--download',
Dennis Kempin19e972b2013-06-20 13:21:38 -0700112 dest='download', default=None,
113 help='download more 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:
Sean O'Brienfd204da2017-05-02 15:13:11 -0700144 stat.Download(options.download)
Dennis Kempin19e972b2013-06-20 13:21:38 -0700145 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
Harry Cutts0edf1572020-01-21 15:42:10 -0800159 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():
Harry Cutts0edf1572020-01-21 15:42:10 -0800162 print("%d occurences in %s:" % (len(result.matches), filename))
Dennis Kempind5b59022013-07-17 14:12:55 -0700163 for match in result.matches:
Harry Cutts0edf1572020-01-21 15:42:10 -0800164 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():
Harry Cutts0edf1572020-01-21 15:42:10 -0800176 print("%s:" % key)
Dennis Kempin253ee052013-07-01 14:58:22 -0700177 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))
Harry Cutts0edf1572020-01-21 15:42:10 -0800182 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__':
Sean O'Brienfd204da2017-05-02 15:13:11 -0700186 main()