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