blob: 13e33fbae31e54e7d0aafc742add0157adefc5a4 [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 Kempin19e972b2013-06-20 13:21:38 -070087"""
88
89def main():
90 parser = OptionParser(usage=usage)
Dennis Kempin253ee052013-07-01 14:58:22 -070091 parser.add_option('-d', '--download',
Dennis Kempin19e972b2013-06-20 13:21:38 -070092 dest='download', default=None,
93 help='download more log files')
Dennis Kempin253ee052013-07-01 14:58:22 -070094 parser.add_option('-o', '--offset',
Dennis Kempin19e972b2013-06-20 13:21:38 -070095 dest='offset', default=0,
96 help='offset for downloading log files')
Dennis Kempin253ee052013-07-01 14:58:22 -070097 parser.add_option('-n', '--number',
Dennis Kempin19e972b2013-06-20 13:21:38 -070098 dest='number', default=None,
99 help='number of log files to gather stats on')
Dennis Kempin253ee052013-07-01 14:58:22 -0700100 parser.add_option('-s', '--search',
Dennis Kempin6e03a432013-06-25 09:00:53 -0700101 dest='search', default=None,
102 help='search for specific tags')
Dennis Kempin253ee052013-07-01 14:58:22 -0700103 parser.add_option('-l', '--list',
104 dest='list', action='store_true', default=False,
105 help='just print list, don\'t view search results')
106 parser.add_option('-r', '--regex',
107 dest='regex', default=None,
108 help='search log output for regex')
Dennis Kempin19e972b2013-06-20 13:21:38 -0700109 (options, args) = parser.parse_args()
110
111 stat = MTStat()
112 if options.download:
113 stat.Download(options.download, options.offset)
114 return
115
116 number = None if options.number is None else int(options.number)
Dennis Kempin6e03a432013-06-25 09:00:53 -0700117
Dennis Kempin253ee052013-07-01 14:58:22 -0700118 if options.search or options.regex:
119 if options.search:
120 results = stat.Search(query=options.search, number=number)
121 else:
122 results = stat.Search(regex=options.regex, number=number)
123
Dennis Kempin6e03a432013-06-25 09:00:53 -0700124 print "Found occurences in %d files" % len(results)
125 print "Serving results, press CTRL-C to abort"
126 for filename, entries in results.items():
127 print "%d occurences in %s:" % (len(entries), filename)
128 for entry in entries:
Dennis Kempin253ee052013-07-01 14:58:22 -0700129 print " " + entry.line
Dennis Kempin6e03a432013-06-25 09:00:53 -0700130
Dennis Kempin253ee052013-07-01 14:58:22 -0700131 # display link to MTEdit session
132 if not options.list:
133 first = entries[0]
134 replay_results = MTReplay().Replay(Log(filename))
135 editor = MTEdit()
136
137 # for MTStat results we have
138 editor.View(replay_results.log, first.timestamp)
139 raw_input("Press Enter to continue...")
Dennis Kempin6e03a432013-06-25 09:00:53 -0700140 return
141
Dennis Kempin19e972b2013-06-20 13:21:38 -0700142 results = stat.GatherStats(number)
Dennis Kempin253ee052013-07-01 14:58:22 -0700143 for key, hist in results.items():
144 print "%s:" % key
145 overall_count = sum(hist.values())
146 for value, count in hist.items():
147 percent = int(round(float(count) / float(overall_count) * 100))
148 percent_str = "(" + str(percent) + "%)"
149 graph = "=" * int(round(percent / 2))
150 print " {0:>6} {1:<6} {2:6} |{3}".format(
151 str(value) + ":", count, percent_str, graph)
Dennis Kempin19e972b2013-06-20 13:21:38 -0700152
153if __name__ == '__main__':
154 main()