Dennis Kempin | 19e972b | 2013-06-20 13:21:38 -0700 | [diff] [blame] | 1 | #! /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 Cutts | 0edf157 | 2020-01-21 15:42:10 -0800 | [diff] [blame] | 5 | |
Harry Cutts | 85378ee | 2020-02-07 15:53:46 -0800 | [diff] [blame] | 6 | from __future__ import absolute_import |
| 7 | from __future__ import division |
Harry Cutts | 0edf157 | 2020-01-21 15:42:10 -0800 | [diff] [blame] | 8 | from __future__ import print_function |
| 9 | |
Dennis Kempin | 6e03a43 | 2013-06-25 09:00:53 -0700 | [diff] [blame] | 10 | from mtedit import MTEdit |
| 11 | from mtlib import Log |
| 12 | from mtreplay import MTReplay |
Dennis Kempin | 19e972b | 2013-06-20 13:21:38 -0700 | [diff] [blame] | 13 | from mtstat import MTStat |
Dennis Kempin | 6e03a43 | 2013-06-25 09:00:53 -0700 | [diff] [blame] | 14 | from optparse import OptionParser |
Dennis Kempin | 19e972b | 2013-06-20 13:21:38 -0700 | [diff] [blame] | 15 | |
| 16 | usage = """Multitouch Statistic Collector |
| 17 | |
Dennis Kempin | 253ee05 | 2013-07-01 14:58:22 -0700 | [diff] [blame] | 18 | This tool is used to gather statistics on large amounts of touchpad data from |
| 19 | feedback reports. Samples are gathered by parsing the log output of the |
| 20 | gestures library. The gesture library provides the MTStatSample/Set commands to |
| 21 | create samples. |
Dennis Kempin | 6e03a43 | 2013-06-25 09:00:53 -0700 | [diff] [blame] | 22 | |
Dennis Kempin | 253ee05 | 2013-07-01 14:58:22 -0700 | [diff] [blame] | 23 | Gestures Library API |
| 24 | -------------------- |
Dennis Kempin | 6e03a43 | 2013-06-25 09:00:53 -0700 | [diff] [blame] | 25 | |
Dennis Kempin | 253ee05 | 2013-07-01 14:58:22 -0700 | [diff] [blame] | 26 | For example you can extend a decision tree in the gestures library code with |
| 27 | calls to: |
Dennis Kempin | 6e03a43 | 2013-06-25 09:00:53 -0700 | [diff] [blame] | 28 | |
Dennis Kempin | 253ee05 | 2013-07-01 14:58:22 -0700 | [diff] [blame] | 29 | MTStatSample("MyDecision", "CaseA"); |
| 30 | MTStatSample("MyDecision", "CaseB"); |
| 31 | MTStatSample("MyDecision", "CaseC"); |
| 32 | |
| 33 | Next to string samples you can also sample integers with MTStatSampleInt. |
| 34 | For example you can sample the number of fingers in each hardware state: |
| 35 | |
| 36 | MTStatSampleInt("NumFingers", hwstate.num_fingers); |
| 37 | |
| 38 | Sometimes you want to only generate one sample per file, for example to |
| 39 | count the number of clicks in each file. Call MTStatUpdate[Int] every time |
| 40 | your value is changed and the last update will be used by MTStat. |
| 41 | For example every time a click is performed you call the following: |
| 42 | |
| 43 | static int num_of_clicks = 0; |
| 44 | MTStatUpdateInt("NumClicks", ++num_of_clicks); |
| 45 | |
| 46 | Preparing MTStat |
| 47 | ---------------- |
| 48 | |
| 49 | To run on feedback reports you first have to download a bunch of them. MTStat |
| 50 | does this for you, for example by downloading the latest 1000 reports: |
| 51 | |
| 52 | $ %prog -d 1000 |
| 53 | |
| 54 | Sample Histograms |
| 55 | ------------------ |
| 56 | |
| 57 | Running mtstat will then generate statistic on how often each of the logged |
| 58 | cases happened. Optionally you can specify the number of log files to process, |
| 59 | per default it will always run all downloaded reports: |
| 60 | |
| 61 | $ %prog [-n 1000] |
| 62 | |
| 63 | The output will be presented as a histogram of how often each case appeared. |
| 64 | For integer samples with a lot of different values, a bin-based histogram is |
| 65 | used. |
| 66 | |
| 67 | Searching Samples |
| 68 | ----------------- |
| 69 | |
| 70 | You can then also search for cases and view their activity log to figure out |
| 71 | which user activity lead to this decision. For example: |
| 72 | |
| 73 | $ %prog -s "MyDecision == CaseC" [-n 100] |
| 74 | |
| 75 | When searching integer samples, unequality operators are supported: |
| 76 | |
| 77 | $ %prog -s "NumFingers >= 3" [-n 100] |
| 78 | |
| 79 | Of course the same thing works on samples made with MTStatUpdate. For example |
| 80 | to find files with a lot of clicks: |
| 81 | |
| 82 | $ %prog -s "NumClicks > 300" [-n 100] |
| 83 | |
| 84 | Advanced Search |
| 85 | --------------- |
| 86 | |
| 87 | You can search the gestures library log output with regular expressions. |
| 88 | For example to see if any ERROR messages happen: |
| 89 | |
| 90 | $ %prog -r "ERROR:" |
| 91 | |
Dennis Kempin | d5b5902 | 2013-07-17 14:12:55 -0700 | [diff] [blame] | 92 | Searching for Changed Gestures |
| 93 | ------------------------------ |
| 94 | |
| 95 | MTStat can also be used to search for changes in the generated gestures |
| 96 | introduced by changes to the code of the gestures library. |
| 97 | |
| 98 | In order to do so make local changes to the gestures library without |
| 99 | commiting them. Then run: |
| 100 | |
| 101 | $ %prog -c [-n 100] |
| 102 | |
| 103 | This command will compare to the HEAD version of gestures and present all |
| 104 | changed gestures. |
| 105 | |
| 106 | You can also limit the search to a certain type of gestures: |
| 107 | |
| 108 | $ %prog -c -g "ButtonDown" [-n 100] |
Dennis Kempin | 19e972b | 2013-06-20 13:21:38 -0700 | [diff] [blame] | 109 | """ |
| 110 | |
| 111 | def main(): |
| 112 | parser = OptionParser(usage=usage) |
Dennis Kempin | 253ee05 | 2013-07-01 14:58:22 -0700 | [diff] [blame] | 113 | parser.add_option('-d', '--download', |
Dennis Kempin | 19e972b | 2013-06-20 13:21:38 -0700 | [diff] [blame] | 114 | dest='download', default=None, |
| 115 | help='download more log files') |
Dennis Kempin | 253ee05 | 2013-07-01 14:58:22 -0700 | [diff] [blame] | 116 | parser.add_option('-n', '--number', |
Dennis Kempin | 19e972b | 2013-06-20 13:21:38 -0700 | [diff] [blame] | 117 | dest='number', default=None, |
| 118 | help='number of log files to gather stats on') |
Dennis Kempin | 7432eb0 | 2014-03-18 13:41:41 -0700 | [diff] [blame] | 119 | parser.add_option('-p', '--platform', |
| 120 | dest='platform', default=None, |
| 121 | help='only use log files from specified platform') |
Dennis Kempin | 253ee05 | 2013-07-01 14:58:22 -0700 | [diff] [blame] | 122 | parser.add_option('-s', '--search', |
Dennis Kempin | 6e03a43 | 2013-06-25 09:00:53 -0700 | [diff] [blame] | 123 | dest='search', default=None, |
| 124 | help='search for specific tags') |
Dennis Kempin | 253ee05 | 2013-07-01 14:58:22 -0700 | [diff] [blame] | 125 | 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 Kempin | d5b5902 | 2013-07-17 14:12:55 -0700 | [diff] [blame] | 131 | 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 Kempin | 19e972b | 2013-06-20 13:21:38 -0700 | [diff] [blame] | 142 | (options, args) = parser.parse_args() |
| 143 | |
| 144 | stat = MTStat() |
| 145 | if options.download: |
Sean O'Brien | fd204da | 2017-05-02 15:13:11 -0700 | [diff] [blame] | 146 | stat.Download(options.download) |
Dennis Kempin | 19e972b | 2013-06-20 13:21:38 -0700 | [diff] [blame] | 147 | return |
| 148 | |
| 149 | number = None if options.number is None else int(options.number) |
Dennis Kempin | 6e03a43 | 2013-06-25 09:00:53 -0700 | [diff] [blame] | 150 | |
Dennis Kempin | d5b5902 | 2013-07-17 14:12:55 -0700 | [diff] [blame] | 151 | if (options.search or options.regex or options.gestures or |
| 152 | options.changes): |
| 153 | if options.changes: |
| 154 | results = stat.SearchChanges(options.gestures, |
Dennis Kempin | 7432eb0 | 2014-03-18 13:41:41 -0700 | [diff] [blame] | 155 | number=number, platform=options.platform) |
Dennis Kempin | 253ee05 | 2013-07-01 14:58:22 -0700 | [diff] [blame] | 156 | else: |
Dennis Kempin | d5b5902 | 2013-07-17 14:12:55 -0700 | [diff] [blame] | 157 | results = stat.Search(search=options.search, gestures=options.gestures, |
Dennis Kempin | 7432eb0 | 2014-03-18 13:41:41 -0700 | [diff] [blame] | 158 | regex=options.regex, number=number, |
| 159 | platform=options.platform) |
Dennis Kempin | 253ee05 | 2013-07-01 14:58:22 -0700 | [diff] [blame] | 160 | |
Harry Cutts | 0edf157 | 2020-01-21 15:42:10 -0800 | [diff] [blame] | 161 | print("Found occurences in %d files" % len(results)) |
| 162 | print("Serving results, press CTRL-C to abort") |
Dennis Kempin | d5b5902 | 2013-07-17 14:12:55 -0700 | [diff] [blame] | 163 | for filename, result in results.items(): |
Harry Cutts | 0edf157 | 2020-01-21 15:42:10 -0800 | [diff] [blame] | 164 | print("%d occurences in %s:" % (len(result.matches), filename)) |
Dennis Kempin | d5b5902 | 2013-07-17 14:12:55 -0700 | [diff] [blame] | 165 | for match in result.matches: |
Harry Cutts | 0edf157 | 2020-01-21 15:42:10 -0800 | [diff] [blame] | 166 | print(" ", match) |
Dennis Kempin | 6e03a43 | 2013-06-25 09:00:53 -0700 | [diff] [blame] | 167 | |
Dennis Kempin | 253ee05 | 2013-07-01 14:58:22 -0700 | [diff] [blame] | 168 | # display link to MTEdit session |
| 169 | if not options.list: |
Dennis Kempin | d5b5902 | 2013-07-17 14:12:55 -0700 | [diff] [blame] | 170 | MTEdit().View(result.log, result.matches[0].timestamp) |
Dennis Kempin | 253ee05 | 2013-07-01 14:58:22 -0700 | [diff] [blame] | 171 | raw_input("Press Enter to continue...") |
Dennis Kempin | 6e03a43 | 2013-06-25 09:00:53 -0700 | [diff] [blame] | 172 | return |
| 173 | |
Dennis Kempin | d5b5902 | 2013-07-17 14:12:55 -0700 | [diff] [blame] | 174 | |
| 175 | bins = int(options.bins) |
Dennis Kempin | 7432eb0 | 2014-03-18 13:41:41 -0700 | [diff] [blame] | 176 | results = stat.GatherStats(number, platform=options.platform, num_bins=bins) |
Dennis Kempin | 253ee05 | 2013-07-01 14:58:22 -0700 | [diff] [blame] | 177 | for key, hist in results.items(): |
Harry Cutts | 0edf157 | 2020-01-21 15:42:10 -0800 | [diff] [blame] | 178 | print("%s:" % key) |
Dennis Kempin | 253ee05 | 2013-07-01 14:58:22 -0700 | [diff] [blame] | 179 | 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 Cutts | 0edf157 | 2020-01-21 15:42:10 -0800 | [diff] [blame] | 184 | print(" {0:>6} {1:<6} {2:6} |{3}".format( |
| 185 | str(value) + ":", count, percent_str, graph)) |
Dennis Kempin | 19e972b | 2013-06-20 13:21:38 -0700 | [diff] [blame] | 186 | |
| 187 | if __name__ == '__main__': |
Sean O'Brien | fd204da | 2017-05-02 15:13:11 -0700 | [diff] [blame] | 188 | main() |