1ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda#!/usr/bin/env python
2ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda# Copyright (C) 2015 The Android Open Source Project
3ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda#
4ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda# Licensed under the Apache License, Version 2.0 (the "License");
5ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda# you may not use this file except in compliance with the License.
6ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda# You may obtain a copy of the License at
7ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda#
8ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda#      http://www.apache.org/licenses/LICENSE-2.0
9ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda#
10ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda# Unless required by applicable law or agreed to in writing, software
11ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda# distributed under the License is distributed on an "AS IS" BASIS,
12ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda# See the License for the specific language governing permissions and
14ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda# limitations under the License.
15ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda"""Record the event logs during boot and output them to a file.
16ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
17ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro MatsudaThis script repeats the record of each event log during Android boot specified
18ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudatimes. By default, interval between measurements is adjusted in such a way that
19ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro MatsudaCPUs are cooled down sufficiently to avoid boot time slowdown caused by CPU
20ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudathermal throttling. The result is output in a tab-separated value format.
21ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
22ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro MatsudaExamples:
23ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
24ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro MatsudaRepeat measurements 10 times. Interval between iterations is adjusted based on
25ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro MatsudaCPU temperature of the device.
26ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
27ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda$ ./perfboot.py --iterations=10
28ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
29ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro MatsudaRepeat measurements 20 times. 60 seconds interval is taken between each
30ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudaiteration.
31ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
32ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda$ ./perfboot.py --iterations=20 --interval=60
33ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
34ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro MatsudaRepeat measurements 20 times, show verbose output, output the result to
35ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudadata.tsv, and read event tags from eventtags.txt.
36ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
37ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda$ ./perfboot.py --iterations=30 -v --output=data.tsv --tags=eventtags.txt
38ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda"""
39ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
40ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudaimport argparse
41ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudaimport atexit
42ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudaimport cStringIO
43c0822e83ad11e42e02f2304e9cf925ea944b8f53Yasuhiro Matsudaimport glob
44ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudaimport inspect
45ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudaimport logging
46ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudaimport math
47ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudaimport os
48ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudaimport re
49ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudaimport subprocess
50ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudaimport sys
51ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudaimport threading
52ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudaimport time
53ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
54ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudasys.path.append(os.path.dirname(os.path.dirname(__file__)))
55ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudaimport adb
56ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
57ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda# The default event tags to record.
58ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda_DEFAULT_EVENT_TAGS = [
59ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    'boot_progress_start',
60ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    'boot_progress_preload_start',
61ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    'boot_progress_preload_end',
62ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    'boot_progress_system_run',
63ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    'boot_progress_pms_start',
64ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    'boot_progress_pms_system_scan_start',
65ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    'boot_progress_pms_data_scan_start',
66ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    'boot_progress_pms_scan_end',
67ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    'boot_progress_pms_ready',
68ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    'boot_progress_ams_ready',
69ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    'boot_progress_enable_screen',
7043c4d998cf8bb5875479d84cb5e5c253a7a11af6Yusuke Sato    'sf_stop_bootanim',
7143c4d998cf8bb5875479d84cb5e5c253a7a11af6Yusuke Sato    'wm_boot_animation_done',
72ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda]
73ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
74ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
75ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudaclass IntervalAdjuster(object):
76ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    """A helper class to take suffficient interval between iterations."""
77ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
78ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    # CPU temperature values per product used to decide interval
79ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    _CPU_COOL_DOWN_THRESHOLDS = {
80ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        'flo': 40,
81ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        'flounder': 40000,
82ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        'razor': 40,
83ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        'volantis': 40000,
84ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    }
85ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    # The interval between CPU temperature checks
86ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    _CPU_COOL_DOWN_WAIT_INTERVAL = 10
87ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    # The wait time used when the value of _CPU_COOL_DOWN_THRESHOLDS for
88ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    # the product is not defined.
89ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    _CPU_COOL_DOWN_WAIT_TIME_DEFAULT = 120
90ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
91ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    def __init__(self, interval, device):
92ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        self._interval = interval
93ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        self._device = device
94ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        self._temp_paths = device.shell(
956ee194013ae27a9b73d011e9fe246c6d8ecef6d5Yasuhiro Matsuda            ['ls', '/sys/class/thermal/thermal_zone*/temp'])[0].splitlines()
96ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        self._product = device.get_prop('ro.build.product')
97ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        self._waited = False
98ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
99ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    def wait(self):
100ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        """Waits certain amount of time for CPUs cool-down."""
101ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        if self._interval is None:
102ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            self._wait_cpu_cool_down(self._product, self._temp_paths)
103ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        else:
104ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            if self._waited:
105ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                print 'Waiting for %d seconds' % self._interval
106ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                time.sleep(self._interval)
107ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        self._waited = True
108ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
109ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    def _get_cpu_temp(self, threshold):
110ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        max_temp = 0
111ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        for temp_path in self._temp_paths:
1126ee194013ae27a9b73d011e9fe246c6d8ecef6d5Yasuhiro Matsuda            temp = int(self._device.shell(['cat', temp_path])[0].rstrip())
113ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            max_temp = max(max_temp, temp)
114ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            if temp >= threshold:
115ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                return temp
116ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        return max_temp
117ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
118ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    def _wait_cpu_cool_down(self, product, temp_paths):
119ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        threshold = IntervalAdjuster._CPU_COOL_DOWN_THRESHOLDS.get(
120ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            self._product)
121ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        if threshold is None:
122ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            print 'No CPU temperature threshold is set for ' + self._product
123ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            print ('Just wait %d seconds' %
124ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                   IntervalAdjuster._CPU_COOL_DOWN_WAIT_TIME_DEFAULT)
125ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            time.sleep(IntervalAdjuster._CPU_COOL_DOWN_WAIT_TIME_DEFAULT)
126ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            return
127ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        while True:
128ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            temp = self._get_cpu_temp(threshold)
129ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            if temp < threshold:
130ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                logging.info('Current CPU temperature %s' % temp)
131ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                return
132ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            print 'Waiting until CPU temperature (%d) falls below %d' % (
133ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                temp, threshold)
134ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            time.sleep(IntervalAdjuster._CPU_COOL_DOWN_WAIT_INTERVAL)
135ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
136ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
137ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudaclass WatchdogTimer(object):
138ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    """A timer that makes is_timedout() return true in |timeout| seconds."""
139ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    def __init__(self, timeout):
140ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        self._timedout = False
141ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
142ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        def notify_timeout():
143ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            self._timedout = True
144ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        self._timer = threading.Timer(timeout, notify_timeout)
14559d32a7515c757d6171605bea0ef631d1837b365Yasuhiro Matsuda        self._timer.daemon = True
146ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        self._timer.start()
147ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
148ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    def is_timedout(self):
149ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        return self._timedout
150ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
151ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    def cancel(self):
152ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        self._timer.cancel()
153ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
154ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
155ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudadef readlines_unbuffered(proc):
156ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    """Read lines from |proc|'s standard out without buffering."""
157ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    while True:
158ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        buf = []
159ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        c = proc.stdout.read(1)
160ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        if c == '' and proc.poll() is not None:
161ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            break
162ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        while c != '\n':
163ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            if c == '' and proc.poll() is not None:
164ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                break
165ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            buf.append(c)
166ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            c = proc.stdout.read(1)
167ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        yield ''.join(buf)
168ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
169ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
170ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudadef disable_dropbox(device):
171ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    """Removes the files created by Dropbox and avoids creating the files."""
172ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    device.root()
173ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    device.wait()
174ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    device.shell(['rm', '-rf', '/system/data/dropbox'])
175ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    original_dropbox_max_files = device.shell(
1766ee194013ae27a9b73d011e9fe246c6d8ecef6d5Yasuhiro Matsuda        ['settings', 'get', 'global', 'dropbox_max_files'])[0].rstrip()
177ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    device.shell(['settings', 'put', 'global', 'dropbox_max_files', '0'])
178ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    return original_dropbox_max_files
179ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
180ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
181ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudadef restore_dropbox(device, original_dropbox_max_files):
182ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    """Restores the dropbox_max_files setting."""
183ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    device.root()
184ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    device.wait()
185ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    if original_dropbox_max_files == 'null':
186ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        device.shell(['settings', 'delete', 'global', 'dropbox_max_files'])
187ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    else:
188ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        device.shell(['settings', 'put', 'global', 'dropbox_max_files',
189ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                      original_dropbox_max_files])
190ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
191ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
192ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudadef init_perf(device, output, record_list, tags):
193ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    device.wait()
194246b0fd0d9cccc28150f71d55d817f9cacf2a7e0Yusuke Sato    debuggable = device.get_prop('ro.debuggable')
195ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    original_dropbox_max_files = None
196246b0fd0d9cccc28150f71d55d817f9cacf2a7e0Yusuke Sato    if debuggable == '1':
197ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        # Workaround for Dropbox issue (http://b/20890386).
198ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        original_dropbox_max_files = disable_dropbox(device)
199ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
200ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    def cleanup():
201ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        try:
202ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            if record_list:
203ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                print_summary(record_list, tags[-1])
204ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                output_results(output, record_list, tags)
205ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            if original_dropbox_max_files is not None:
206ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                restore_dropbox(device, original_dropbox_max_files)
207f3d0d42f1a38906e0e80ab96368ad01b8a58f8d0Yasuhiro Matsuda        except (subprocess.CalledProcessError, RuntimeError):
208ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            pass
209ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    atexit.register(cleanup)
210ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
211ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
212b6c66dc0a3fbd8f76ad9ca5fb6d9049a784b7396Yusuke Satodef check_dm_verity_settings(device):
213b6c66dc0a3fbd8f76ad9ca5fb6d9049a784b7396Yusuke Sato    device.wait()
214b6c66dc0a3fbd8f76ad9ca5fb6d9049a784b7396Yusuke Sato    for partition in ['system', 'vendor']:
215b6c66dc0a3fbd8f76ad9ca5fb6d9049a784b7396Yusuke Sato        verity_mode = device.get_prop('partition.%s.verified' % partition)
216b6c66dc0a3fbd8f76ad9ca5fb6d9049a784b7396Yusuke Sato        if verity_mode is None:
217b6c66dc0a3fbd8f76ad9ca5fb6d9049a784b7396Yusuke Sato            logging.warning('dm-verity is not enabled for /%s. Did you run '
218b6c66dc0a3fbd8f76ad9ca5fb6d9049a784b7396Yusuke Sato                            'adb disable-verity? That may skew the result.',
219b6c66dc0a3fbd8f76ad9ca5fb6d9049a784b7396Yusuke Sato                            partition)
220b6c66dc0a3fbd8f76ad9ca5fb6d9049a784b7396Yusuke Sato
221b6c66dc0a3fbd8f76ad9ca5fb6d9049a784b7396Yusuke Sato
222ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudadef read_event_tags(tags_file):
223ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    """Reads event tags from |tags_file|."""
224ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    if not tags_file:
225ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        return _DEFAULT_EVENT_TAGS
226ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    tags = []
227ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    with open(tags_file) as f:
228ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        for line in f:
229ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            if '#' in line:
230ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                line = line[:line.find('#')]
231ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            line = line.strip()
232ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            if line:
233ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                tags.append(line)
234ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    return tags
235ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
236ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
237ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudadef make_event_tags_re(tags):
238ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    """Makes a regular expression object that matches event logs of |tags|."""
239ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    return re.compile(r'(?P<pid>[0-9]+) +[0-9]+ I (?P<tag>%s): (?P<time>\d+)' %
240ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                      '|'.join(tags))
241ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
242ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
243e801cc0b4e26d13a4d5dc3ef771172dec96ad4ecYusuke Satodef filter_event_tags(tags, device):
244e801cc0b4e26d13a4d5dc3ef771172dec96ad4ecYusuke Sato    """Drop unknown tags not listed in device's event-log-tags file."""
245e801cc0b4e26d13a4d5dc3ef771172dec96ad4ecYusuke Sato    device.wait()
246e801cc0b4e26d13a4d5dc3ef771172dec96ad4ecYusuke Sato    supported_tags = set()
2476ee194013ae27a9b73d011e9fe246c6d8ecef6d5Yasuhiro Matsuda    for l in device.shell(
2486ee194013ae27a9b73d011e9fe246c6d8ecef6d5Yasuhiro Matsuda        ['cat', '/system/etc/event-log-tags'])[0].splitlines():
249e801cc0b4e26d13a4d5dc3ef771172dec96ad4ecYusuke Sato        tokens = l.split(' ')
250e801cc0b4e26d13a4d5dc3ef771172dec96ad4ecYusuke Sato        if len(tokens) >= 2:
251e801cc0b4e26d13a4d5dc3ef771172dec96ad4ecYusuke Sato            supported_tags.add(tokens[1])
252e801cc0b4e26d13a4d5dc3ef771172dec96ad4ecYusuke Sato    filtered = []
253e801cc0b4e26d13a4d5dc3ef771172dec96ad4ecYusuke Sato    for tag in tags:
254e801cc0b4e26d13a4d5dc3ef771172dec96ad4ecYusuke Sato        if tag in supported_tags:
255e801cc0b4e26d13a4d5dc3ef771172dec96ad4ecYusuke Sato            filtered.append(tag)
256e801cc0b4e26d13a4d5dc3ef771172dec96ad4ecYusuke Sato        else:
257e801cc0b4e26d13a4d5dc3ef771172dec96ad4ecYusuke Sato            logging.warning('Unknown tag \'%s\'. Ignoring...', tag)
258e801cc0b4e26d13a4d5dc3ef771172dec96ad4ecYusuke Sato    return filtered
259e801cc0b4e26d13a4d5dc3ef771172dec96ad4ecYusuke Sato
260e801cc0b4e26d13a4d5dc3ef771172dec96ad4ecYusuke Sato
261ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudadef get_values(record, tag):
262ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    """Gets values that matches |tag| from |record|."""
263ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    keys = [key for key in record.keys() if key[0] == tag]
264ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    return [record[k] for k in sorted(keys)]
265ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
266ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
267ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudadef get_last_value(record, tag):
268ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    """Gets the last value that matches |tag| from |record|."""
269ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    values = get_values(record, tag)
270ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    if not values:
271ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        return 0
272ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    return values[-1]
273ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
274ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
275ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudadef output_results(filename, record_list, tags):
276ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    """Outputs |record_list| into |filename| in a TSV format."""
277ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    # First, count the number of the values of each tag.
278ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    # This is for dealing with events that occur multiple times.
279ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    # For instance, boot_progress_preload_start and boot_progress_preload_end
280ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    # are recorded twice on 64-bit system. One is for 64-bit zygote process
281ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    # and the other is for 32-bit zygote process.
282ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    values_counter = {}
283ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    for record in record_list:
284ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        for tag in tags:
285ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            # Some record might lack values for some tags due to unanticipated
286ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            # problems (e.g. timeout), so take the maximum count among all the
287ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            # record.
288ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            values_counter[tag] = max(values_counter.get(tag, 1),
289ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                                      len(get_values(record, tag)))
290ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
291ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    # Then creates labels for the data. If there are multiple values for one
292ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    # tag, labels for these values are numbered except the first one as
293ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    # follows:
294ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    #
295ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    # event_tag event_tag2 event_tag3
296ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    #
297ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    # The corresponding values are sorted in an ascending order of PID.
298ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    labels = []
299ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    for tag in tags:
300ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        for i in range(1, values_counter[tag] + 1):
301ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            labels.append('%s%s' % (tag, '' if i == 1 else str(i)))
302ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
303ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    # Finally write the data into the file.
304ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    with open(filename, 'w') as f:
305ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        f.write('\t'.join(labels) + '\n')
306ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        for record in record_list:
307ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            line = cStringIO.StringIO()
308ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            invalid_line = False
309ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            for i, tag in enumerate(tags):
310ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                if i != 0:
311ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                    line.write('\t')
312ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                values = get_values(record, tag)
313ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                if len(values) < values_counter[tag]:
314ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                    invalid_line = True
315ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                    # Fill invalid record with 0
316ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                    values += [0] * (values_counter[tag] - len(values))
317ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                line.write('\t'.join(str(t) for t in values))
318ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            if invalid_line:
319ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                logging.error('Invalid record found: ' + line.getvalue())
320ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            line.write('\n')
321ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            f.write(line.getvalue())
322ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    print 'Wrote: ' + filename
323ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
324ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
325ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudadef median(data):
326ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    """Calculates the median value from |data|."""
327ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    data = sorted(data)
328ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    n = len(data)
329ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    if n % 2 == 1:
330ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        return data[n / 2]
331ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    else:
332ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        n2 = n / 2
333ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        return (data[n2 - 1] + data[n2]) / 2.0
334ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
335ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
336ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudadef mean(data):
337ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    """Calculates the mean value from |data|."""
338ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    return float(sum(data)) / len(data)
339ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
340ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
341ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudadef stddev(data):
342ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    """Calculates the standard deviation value from |value|."""
343ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    m = mean(data)
344ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    return math.sqrt(sum((x - m) ** 2 for x in data) / len(data))
345ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
346ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
347ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudadef print_summary(record_list, end_tag):
348ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    """Prints the summary of |record_list|."""
349ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    # Filter out invalid data.
350ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    end_times = [get_last_value(record, end_tag) for record in record_list
351ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                 if get_last_value(record, end_tag) != 0]
352ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    print 'mean: ', mean(end_times)
353ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    print 'median:', median(end_times)
354ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    print 'standard deviation:', stddev(end_times)
355ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
356ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
357ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudadef do_iteration(device, interval_adjuster, event_tags_re, end_tag):
358ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    """Measures the boot time once."""
359ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    device.wait()
360ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    interval_adjuster.wait()
361ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    device.reboot()
362ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    print 'Rebooted the device'
363ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    record = {}
364ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    booted = False
365ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    while not booted:
366ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        device.wait()
367ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        # Stop the iteration if it does not finish within 120 seconds.
368ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        timeout = 120
369ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        t = WatchdogTimer(timeout)
370ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        p = subprocess.Popen(
371ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                ['adb', 'logcat', '-b', 'events', '-v', 'threadtime'],
372ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                stdout=subprocess.PIPE)
373ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        for line in readlines_unbuffered(p):
374ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            if t.is_timedout():
375ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                print '*** Timed out ***'
376ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                return record
377ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            m = event_tags_re.search(line)
378ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            if not m:
379ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                continue
380ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            tag = m.group('tag')
381ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            event_time = int(m.group('time'))
382ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            pid = m.group('pid')
383ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            record[(tag, pid)] = event_time
384ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            print 'Event log recorded: %s (%s) - %d ms' % (
385ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                tag, pid, event_time)
386ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            if tag == end_tag:
387ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                booted = True
388ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                t.cancel()
389ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                break
390ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    return record
391ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
392ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
393ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudadef parse_args():
394ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    """Parses the command line arguments."""
395ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    parser = argparse.ArgumentParser(
396ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        description=inspect.getdoc(sys.modules[__name__]),
397ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        formatter_class=argparse.RawDescriptionHelpFormatter)
398ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    parser.add_argument('--iterations', type=int, default=5,
399ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                        help='Number of times to repeat boot measurements.')
400ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    parser.add_argument('--interval', type=int,
401ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                        help=('Duration between iterations. If this is not '
402ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                              'set explicitly, durations are determined '
403ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                              'adaptively based on CPUs temperature.'))
404ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    parser.add_argument('-o', '--output', help='File name of output data.')
405ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    parser.add_argument('-v', '--verbose', action='store_true',
406ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                        help='Show verbose output.')
407ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    parser.add_argument('-s', '--serial', default=os.getenv('ANDROID_SERIAL'),
408ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                        help='Adb device serial number.')
409ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    parser.add_argument('-t', '--tags', help='Specify the filename from which '
410ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                        'event tags are read. Every line contains one event '
411ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda                        'tag and the last event tag is used to detect that '
4123966ebb74d7aec08169b99d3cecf23ea3815435fYusuke Sato                        'the device has finished booting unless --end-tag is '
4133966ebb74d7aec08169b99d3cecf23ea3815435fYusuke Sato                        'specified.')
4143966ebb74d7aec08169b99d3cecf23ea3815435fYusuke Sato    parser.add_argument('--end-tag', help='An event tag on which the script '
4153966ebb74d7aec08169b99d3cecf23ea3815435fYusuke Sato                        'stops measuring the boot time.')
416c0822e83ad11e42e02f2304e9cf925ea944b8f53Yasuhiro Matsuda    parser.add_argument('--apk-dir', help='Specify the directory which contains '
417c0822e83ad11e42e02f2304e9cf925ea944b8f53Yasuhiro Matsuda                        'APK files to be installed before measuring boot time.')
418ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    return parser.parse_args()
419ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
420ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
421c0822e83ad11e42e02f2304e9cf925ea944b8f53Yasuhiro Matsudadef install_apks(device, apk_dir):
422c0822e83ad11e42e02f2304e9cf925ea944b8f53Yasuhiro Matsuda    for apk in glob.glob(os.path.join(apk_dir, '*.apk')):
423c0822e83ad11e42e02f2304e9cf925ea944b8f53Yasuhiro Matsuda        print 'Installing: ' + apk
424c0822e83ad11e42e02f2304e9cf925ea944b8f53Yasuhiro Matsuda        device.install(apk, replace=True)
425c0822e83ad11e42e02f2304e9cf925ea944b8f53Yasuhiro Matsuda
426c0822e83ad11e42e02f2304e9cf925ea944b8f53Yasuhiro Matsuda
427ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudadef main():
428ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    args = parse_args()
429ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    if args.verbose:
430ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        logging.getLogger().setLevel(logging.INFO)
431ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
432ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    device = adb.get_device(args.serial)
433ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
434ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    if not args.output:
435ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        device.wait()
436ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        args.output = 'perf-%s-%s.tsv' % (
437ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            device.get_prop('ro.build.flavor'),
438ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            device.get_prop('ro.build.version.incremental'))
439b6c66dc0a3fbd8f76ad9ca5fb6d9049a784b7396Yusuke Sato    check_dm_verity_settings(device)
440ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
441c0822e83ad11e42e02f2304e9cf925ea944b8f53Yasuhiro Matsuda    if args.apk_dir:
442c0822e83ad11e42e02f2304e9cf925ea944b8f53Yasuhiro Matsuda        install_apks(device, args.apk_dir)
443c0822e83ad11e42e02f2304e9cf925ea944b8f53Yasuhiro Matsuda
444ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    record_list = []
445e801cc0b4e26d13a4d5dc3ef771172dec96ad4ecYusuke Sato    event_tags = filter_event_tags(read_event_tags(args.tags), device)
4463966ebb74d7aec08169b99d3cecf23ea3815435fYusuke Sato    end_tag = args.end_tag or event_tags[-1]
4473966ebb74d7aec08169b99d3cecf23ea3815435fYusuke Sato    if end_tag not in event_tags:
4483966ebb74d7aec08169b99d3cecf23ea3815435fYusuke Sato        sys.exit('%s is not a valid tag.' % end_tag)
4493966ebb74d7aec08169b99d3cecf23ea3815435fYusuke Sato    event_tags = event_tags[0 : event_tags.index(end_tag) + 1]
450ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    init_perf(device, args.output, record_list, event_tags)
451ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    interval_adjuster = IntervalAdjuster(args.interval, device)
452ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    event_tags_re = make_event_tags_re(event_tags)
4533966ebb74d7aec08169b99d3cecf23ea3815435fYusuke Sato
454ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    for i in range(args.iterations):
455ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        print 'Run #%d ' % i
456ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        record = do_iteration(
457ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda            device, interval_adjuster, event_tags_re, end_tag)
458ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda        record_list.append(record)
459ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
460ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda
461ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsudaif __name__ == '__main__':
462ab3798399dfe970a12a25f79c4392602b6d7515bYasuhiro Matsuda    main()
463