blob: 1413af15a6cdfa6ee71c0f69fa447309d7a9222a [file] [log] [blame]
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -07001#!/usr/bin/env python
2#
3# Copyright (C) 2019 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17# Sample Usage:
Pirama Arumuga Nainarf5db7772019-11-04 21:19:59 -080018# $ python update_profiles.py 500000 ALL --profdata-suffix 2019-04-15
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -070019#
20# Additional/frequently-used arguments:
21# -b BUG adds a 'Bug: <BUG>' to the commit message when adding the profiles.
22# --do-not-merge adds a 'DO NOT MERGE' tag to the commit message to restrict
23# automerge of profiles from release branches.
24#
25# Try '-h' for a full list of command line arguments.
26
27import argparse
28import os
29import shutil
30import subprocess
31import sys
32import tempfile
33import zipfile
34
35import utils
36
Pirama Arumuga Nainar19a588f2019-11-04 13:22:07 -080037from android_build_client import AndroidBuildClient
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -070038
Pirama Arumuga Nainar75e97322019-11-04 21:26:19 -080039
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -070040class Benchmark(object):
Pirama Arumuga Nainar75e97322019-11-04 21:26:19 -080041
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -070042 def __init__(self, name):
43 self.name = name
44
Pirama Arumuga Nainar19a588f2019-11-04 13:22:07 -080045 def apct_test_tag(self):
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -070046 raise NotImplementedError()
47
48 def profdata_file(self, suffix=''):
49 profdata = os.path.join(self.name, '{}.profdata'.format(self.name))
50 if suffix:
51 profdata += '.' + suffix
52 return profdata
53
54 def profraw_files(self):
55 raise NotImplementedError()
56
57 def merge_profraws(self, profile_dir, output):
Pirama Arumuga Nainar75e97322019-11-04 21:26:19 -080058 profraws = [
59 os.path.join(profile_dir, p)
60 for p in self.profraw_files(profile_dir)
61 ]
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -070062 utils.run_llvm_profdata(profraws, output)
63
64
65class NativeExeBenchmark(Benchmark):
Pirama Arumuga Nainar75e97322019-11-04 21:26:19 -080066
Pirama Arumuga Nainar19a588f2019-11-04 13:22:07 -080067 def apct_test_tag(self):
68 return 'apct/perf/pgo/profile-collector'
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -070069
70 def profraw_files(self, profile_dir):
71 if self.name == 'hwui':
Pirama Arumuga Nainar75e97322019-11-04 21:26:19 -080072 return [
73 'hwuimacro.profraw', 'hwuimacro_64.profraw',
74 'hwuimicro.profraw', 'hwuimicro_64.profraw',
75 'skia_nanobench.profraw', 'skia_nanobench_64.profraw'
76 ]
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -070077 elif self.name == 'hwbinder':
78 return ['hwbinder.profraw', 'hwbinder_64.profraw']
79
80
81class APKBenchmark(Benchmark):
Pirama Arumuga Nainar75e97322019-11-04 21:26:19 -080082
Pirama Arumuga Nainar19a588f2019-11-04 13:22:07 -080083 def apct_test_tag(self):
84 return 'apct/perf/pgo/apk-profile-collector'
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -070085
86 def profdata_file(self, suffix=''):
Pirama Arumuga Nainar75e97322019-11-04 21:26:19 -080087 profdata = os.path.join('art',
88 '{}_arm_arm64.profdata'.format(self.name))
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -070089 if suffix:
90 profdata += '.' + suffix
91 return profdata
92
93 def profraw_files(self, profile_dir):
94 return os.listdir(profile_dir)
95
96
97def BenchmarkFactory(benchmark_name):
98 if benchmark_name == 'dex2oat':
99 return APKBenchmark(benchmark_name)
100 elif benchmark_name in ['hwui', 'hwbinder']:
101 return NativeExeBenchmark(benchmark_name)
102 else:
103 raise RuntimeError('Unknown benchmark ' + benchmark_name)
104
105
Pirama Arumuga Nainar19a588f2019-11-04 13:22:07 -0800106def extract_profiles(build, test_tag, build_client, output_dir):
107 pgo_zip = build_client.download_pgo_zip(build, test_tag, output_dir)
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -0700108
Pirama Arumuga Nainar19a588f2019-11-04 13:22:07 -0800109 zipfile_name = os.path.join(pgo_zip)
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -0700110 zip_ref = zipfile.ZipFile(zipfile_name)
111 zip_ref.extractall(output_dir)
112 zip_ref.close()
113
114
115KNOWN_BENCHMARKS = ['ALL', 'dex2oat', 'hwui', 'hwbinder']
116
Pirama Arumuga Nainar75e97322019-11-04 21:26:19 -0800117
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -0700118def parse_args():
119 """Parses and returns command line arguments."""
120 parser = argparse.ArgumentParser()
121
122 parser.add_argument(
Pirama Arumuga Nainar75e97322019-11-04 21:26:19 -0800123 'build',
124 metavar='BUILD',
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -0700125 help='Build number to pull from the build server.')
126
127 parser.add_argument(
Pirama Arumuga Nainar75e97322019-11-04 21:26:19 -0800128 '-b', '--bug', type=int, help='Bug to reference in commit message.')
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -0700129
130 parser.add_argument(
Pirama Arumuga Nainar75e97322019-11-04 21:26:19 -0800131 '--use-current-branch',
132 action='store_true',
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -0700133 help='Do not repo start a new branch for the update.')
134
135 parser.add_argument(
Pirama Arumuga Nainar75e97322019-11-04 21:26:19 -0800136 '--add-do-not-merge',
137 action='store_true',
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -0700138 help='Add \'DO NOT MERGE\' to the commit message.')
139
140 parser.add_argument(
Pirama Arumuga Nainar75e97322019-11-04 21:26:19 -0800141 '--profdata-suffix',
142 type=str,
143 default='',
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -0700144 help='Suffix to append to merged profdata file')
145
146 parser.add_argument(
Pirama Arumuga Nainar75e97322019-11-04 21:26:19 -0800147 'benchmark',
148 metavar='BENCHMARK',
149 help='Update profiles for BENCHMARK. Choices are {}'.format(
150 KNOWN_BENCHMARKS))
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -0700151
152 parser.add_argument(
Pirama Arumuga Nainar75e97322019-11-04 21:26:19 -0800153 '--skip-cleanup',
154 '-sc',
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -0700155 action='store_true',
156 default=False,
Pirama Arumuga Nainar75e97322019-11-04 21:26:19 -0800157 help='Skip the cleanup, and leave intermediate files (in /tmp/pgo-profiles-*)'
158 )
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -0700159
160 return parser.parse_args()
161
162
163def get_current_profile(benchmark):
164 profile = benchmark.profdata_file()
165 dirname, basename = os.path.split(profile)
166
167 old_profiles = [f for f in os.listdir(dirname) if f.startswith(basename)]
168 if len(old_profiles) == 0:
169 return ''
170 return os.path.join(dirname, old_profiles[0])
171
172
173def main():
174 args = parse_args()
175
176 if args.benchmark == 'ALL':
177 worklist = KNOWN_BENCHMARKS[1:]
178 else:
Pirama Arumuga Nainar75e97322019-11-04 21:26:19 -0800179 worklist = [args.benchmark]
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -0700180
181 profiles_project = os.path.join(utils.android_build_top(), 'toolchain',
182 'pgo-profiles')
183 os.chdir(profiles_project)
184
185 if not args.use_current_branch:
186 branch_name = 'update-profiles-' + args.build
187 utils.check_call(['repo', 'start', branch_name, '.'])
188
Pirama Arumuga Nainar19a588f2019-11-04 13:22:07 -0800189 build_client = AndroidBuildClient()
190
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -0700191 for benchmark_name in worklist:
192 benchmark = BenchmarkFactory(benchmark_name)
193
194 # Existing profile file, which gets 'rm'-ed from 'git' down below.
195 current_profile = get_current_profile(benchmark)
196
197 # Extract profiles to a temporary directory. After extraction, we
198 # expect to find one subdirectory with profraw files under the temporary
199 # directory.
Pirama Arumuga Nainar75e97322019-11-04 21:26:19 -0800200 extract_dir = tempfile.mkdtemp(prefix='pgo-profiles-' + benchmark_name)
Pirama Arumuga Nainar19a588f2019-11-04 13:22:07 -0800201 extract_profiles(args.build, benchmark.apct_test_tag(), build_client,
202 extract_dir)
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -0700203
Pirama Arumuga Nainar19a588f2019-11-04 13:22:07 -0800204 extract_subdirs = [
205 os.path.join(extract_dir, sub)
206 for sub in os.listdir(extract_dir)
207 if os.path.isdir(os.path.join(extract_dir, sub))
208 ]
209 if len(extract_subdirs) != 1:
210 raise RuntimeError(
Pirama Arumuga Nainar75e97322019-11-04 21:26:19 -0800211 'Expected one subdir under {}'.format(extract_dir))
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -0700212
213 # Merge profiles.
214 profdata = benchmark.profdata_file(args.profdata_suffix)
Pirama Arumuga Nainar19a588f2019-11-04 13:22:07 -0800215 benchmark.merge_profraws(extract_subdirs[0], profdata)
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -0700216
217 # Construct 'git' commit message.
218 message_lines = [
Pirama Arumuga Nainar75e97322019-11-04 21:26:19 -0800219 'Update PGO profiles for {}'.format(benchmark_name), '',
220 'The profiles are from build {}.'.format(args.build), ''
Pirama Arumuga Nainar799180e2019-04-11 14:31:57 -0700221 ]
222
223 if args.add_do_not_merge:
224 message_lines[0] = '[DO NOT MERGE] ' + message_lines[0]
225
226 if args.bug:
227 message_lines.append('')
228 message_lines.append('Bug: http://b/{}'.format(args.bug))
229 message_lines.append('Test: Build (TH)')
230 message = '\n'.join(message_lines)
231
232 # Invoke git: Delete current profile, add new profile and commit these
233 # changes.
234 if current_profile:
235 utils.check_call(['git', 'rm', current_profile])
236 utils.check_call(['git', 'add', profdata])
237 utils.check_call(['git', 'commit', '-m', message])
238
239 if not args.skip_cleanup:
240 shutil.rmtree(extract_dir)
241
242
243if __name__ == '__main__':
244 main()