1*9e94795aSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*9e94795aSAndroid Build Coastguard Worker# Copyright (C) 2023 The Android Open Source Project 3*9e94795aSAndroid Build Coastguard Worker# 4*9e94795aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 5*9e94795aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 6*9e94795aSAndroid Build Coastguard Worker# You may obtain a copy of the License at 7*9e94795aSAndroid Build Coastguard Worker# 8*9e94795aSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 9*9e94795aSAndroid Build Coastguard Worker# 10*9e94795aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 11*9e94795aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 12*9e94795aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*9e94795aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 14*9e94795aSAndroid Build Coastguard Worker# limitations under the License. 15*9e94795aSAndroid Build Coastguard Worker 16*9e94795aSAndroid Build Coastguard Workerimport sys 17*9e94795aSAndroid Build Coastguard Workerif __name__ == "__main__": 18*9e94795aSAndroid Build Coastguard Worker sys.dont_write_bytecode = True 19*9e94795aSAndroid Build Coastguard Worker 20*9e94795aSAndroid Build Coastguard Workerimport argparse 21*9e94795aSAndroid Build Coastguard Workerimport dataclasses 22*9e94795aSAndroid Build Coastguard Workerimport datetime 23*9e94795aSAndroid Build Coastguard Workerimport json 24*9e94795aSAndroid Build Coastguard Workerimport os 25*9e94795aSAndroid Build Coastguard Workerimport pathlib 26*9e94795aSAndroid Build Coastguard Workerimport random 27*9e94795aSAndroid Build Coastguard Workerimport re 28*9e94795aSAndroid Build Coastguard Workerimport shutil 29*9e94795aSAndroid Build Coastguard Workerimport subprocess 30*9e94795aSAndroid Build Coastguard Workerimport time 31*9e94795aSAndroid Build Coastguard Workerimport uuid 32*9e94795aSAndroid Build Coastguard Workerfrom typing import Optional 33*9e94795aSAndroid Build Coastguard Worker 34*9e94795aSAndroid Build Coastguard Workerimport pretty 35*9e94795aSAndroid Build Coastguard Workerimport utils 36*9e94795aSAndroid Build Coastguard Worker 37*9e94795aSAndroid Build Coastguard Worker 38*9e94795aSAndroid Build Coastguard Workerclass FatalError(Exception): 39*9e94795aSAndroid Build Coastguard Worker def __init__(self): 40*9e94795aSAndroid Build Coastguard Worker pass 41*9e94795aSAndroid Build Coastguard Worker 42*9e94795aSAndroid Build Coastguard Worker 43*9e94795aSAndroid Build Coastguard Workerclass OptionsError(Exception): 44*9e94795aSAndroid Build Coastguard Worker def __init__(self, message): 45*9e94795aSAndroid Build Coastguard Worker self.message = message 46*9e94795aSAndroid Build Coastguard Worker 47*9e94795aSAndroid Build Coastguard Worker 48*9e94795aSAndroid Build Coastguard Worker@dataclasses.dataclass(frozen=True) 49*9e94795aSAndroid Build Coastguard Workerclass Lunch: 50*9e94795aSAndroid Build Coastguard Worker "Lunch combination" 51*9e94795aSAndroid Build Coastguard Worker 52*9e94795aSAndroid Build Coastguard Worker target_product: str 53*9e94795aSAndroid Build Coastguard Worker "TARGET_PRODUCT" 54*9e94795aSAndroid Build Coastguard Worker 55*9e94795aSAndroid Build Coastguard Worker target_release: str 56*9e94795aSAndroid Build Coastguard Worker "TARGET_RELEASE" 57*9e94795aSAndroid Build Coastguard Worker 58*9e94795aSAndroid Build Coastguard Worker target_build_variant: str 59*9e94795aSAndroid Build Coastguard Worker "TARGET_BUILD_VARIANT" 60*9e94795aSAndroid Build Coastguard Worker 61*9e94795aSAndroid Build Coastguard Worker def ToDict(self): 62*9e94795aSAndroid Build Coastguard Worker return { 63*9e94795aSAndroid Build Coastguard Worker "TARGET_PRODUCT": self.target_product, 64*9e94795aSAndroid Build Coastguard Worker "TARGET_RELEASE": self.target_release, 65*9e94795aSAndroid Build Coastguard Worker "TARGET_BUILD_VARIANT": self.target_build_variant, 66*9e94795aSAndroid Build Coastguard Worker } 67*9e94795aSAndroid Build Coastguard Worker 68*9e94795aSAndroid Build Coastguard Worker def Combine(self): 69*9e94795aSAndroid Build Coastguard Worker return f"{self.target_product}-{self.target_release}-{self.target_build_variant}" 70*9e94795aSAndroid Build Coastguard Worker 71*9e94795aSAndroid Build Coastguard Worker 72*9e94795aSAndroid Build Coastguard Worker@dataclasses.dataclass(frozen=True) 73*9e94795aSAndroid Build Coastguard Workerclass Change: 74*9e94795aSAndroid Build Coastguard Worker "A change that we make to the tree, and how to undo it" 75*9e94795aSAndroid Build Coastguard Worker label: str 76*9e94795aSAndroid Build Coastguard Worker "String to print in the log when the change is made" 77*9e94795aSAndroid Build Coastguard Worker 78*9e94795aSAndroid Build Coastguard Worker change: callable 79*9e94795aSAndroid Build Coastguard Worker "Function to change the source tree" 80*9e94795aSAndroid Build Coastguard Worker 81*9e94795aSAndroid Build Coastguard Worker undo: callable 82*9e94795aSAndroid Build Coastguard Worker "Function to revert the source tree to its previous condition in the most minimal way possible." 83*9e94795aSAndroid Build Coastguard Worker 84*9e94795aSAndroid Build Coastguard Worker_DUMPVARS_VARS=[ 85*9e94795aSAndroid Build Coastguard Worker "COMMON_LUNCH_CHOICES", 86*9e94795aSAndroid Build Coastguard Worker "HOST_PREBUILT_TAG", 87*9e94795aSAndroid Build Coastguard Worker "print", 88*9e94795aSAndroid Build Coastguard Worker "PRODUCT_OUT", 89*9e94795aSAndroid Build Coastguard Worker "report_config", 90*9e94795aSAndroid Build Coastguard Worker "TARGET_ARCH", 91*9e94795aSAndroid Build Coastguard Worker "TARGET_BUILD_VARIANT", 92*9e94795aSAndroid Build Coastguard Worker "TARGET_DEVICE", 93*9e94795aSAndroid Build Coastguard Worker "TARGET_PRODUCT", 94*9e94795aSAndroid Build Coastguard Worker] 95*9e94795aSAndroid Build Coastguard Worker 96*9e94795aSAndroid Build Coastguard Worker_DUMPVARS_ABS_VARS =[ 97*9e94795aSAndroid Build Coastguard Worker "ANDROID_CLANG_PREBUILTS", 98*9e94795aSAndroid Build Coastguard Worker "ANDROID_JAVA_HOME", 99*9e94795aSAndroid Build Coastguard Worker "ANDROID_JAVA_TOOLCHAIN", 100*9e94795aSAndroid Build Coastguard Worker "ANDROID_PREBUILTS", 101*9e94795aSAndroid Build Coastguard Worker "HOST_OUT", 102*9e94795aSAndroid Build Coastguard Worker "HOST_OUT_EXECUTABLES", 103*9e94795aSAndroid Build Coastguard Worker "HOST_OUT_TESTCASES", 104*9e94795aSAndroid Build Coastguard Worker "OUT_DIR", 105*9e94795aSAndroid Build Coastguard Worker "print", 106*9e94795aSAndroid Build Coastguard Worker "PRODUCT_OUT", 107*9e94795aSAndroid Build Coastguard Worker "SOONG_HOST_OUT", 108*9e94795aSAndroid Build Coastguard Worker "SOONG_HOST_OUT_EXECUTABLES", 109*9e94795aSAndroid Build Coastguard Worker "TARGET_OUT_TESTCASES", 110*9e94795aSAndroid Build Coastguard Worker] 111*9e94795aSAndroid Build Coastguard Worker 112*9e94795aSAndroid Build Coastguard Worker@dataclasses.dataclass(frozen=True) 113*9e94795aSAndroid Build Coastguard Workerclass Benchmark: 114*9e94795aSAndroid Build Coastguard Worker "Something we measure" 115*9e94795aSAndroid Build Coastguard Worker 116*9e94795aSAndroid Build Coastguard Worker id: str 117*9e94795aSAndroid Build Coastguard Worker "Short ID for the benchmark, for the command line" 118*9e94795aSAndroid Build Coastguard Worker 119*9e94795aSAndroid Build Coastguard Worker title: str 120*9e94795aSAndroid Build Coastguard Worker "Title for reports" 121*9e94795aSAndroid Build Coastguard Worker 122*9e94795aSAndroid Build Coastguard Worker change: Change 123*9e94795aSAndroid Build Coastguard Worker "Source tree modification for the benchmark that will be measured" 124*9e94795aSAndroid Build Coastguard Worker 125*9e94795aSAndroid Build Coastguard Worker dumpvars: Optional[bool] = False 126*9e94795aSAndroid Build Coastguard Worker "If specified, soong will run in dumpvars mode rather than build-mode." 127*9e94795aSAndroid Build Coastguard Worker 128*9e94795aSAndroid Build Coastguard Worker modules: Optional[list[str]] = None 129*9e94795aSAndroid Build Coastguard Worker "Build modules to build on soong command line" 130*9e94795aSAndroid Build Coastguard Worker 131*9e94795aSAndroid Build Coastguard Worker preroll: Optional[int] = 0 132*9e94795aSAndroid Build Coastguard Worker "Number of times to run the build command to stabilize" 133*9e94795aSAndroid Build Coastguard Worker 134*9e94795aSAndroid Build Coastguard Worker postroll: Optional[int] = 3 135*9e94795aSAndroid Build Coastguard Worker "Number of times to run the build command after reverting the action to stabilize" 136*9e94795aSAndroid Build Coastguard Worker 137*9e94795aSAndroid Build Coastguard Worker def build_description(self): 138*9e94795aSAndroid Build Coastguard Worker "Short description of the benchmark's Soong invocation." 139*9e94795aSAndroid Build Coastguard Worker if self.dumpvars: 140*9e94795aSAndroid Build Coastguard Worker return "dumpvars" 141*9e94795aSAndroid Build Coastguard Worker elif self.modules: 142*9e94795aSAndroid Build Coastguard Worker return " ".join(self.modules) 143*9e94795aSAndroid Build Coastguard Worker return "" 144*9e94795aSAndroid Build Coastguard Worker 145*9e94795aSAndroid Build Coastguard Worker 146*9e94795aSAndroid Build Coastguard Worker def soong_command(self, root): 147*9e94795aSAndroid Build Coastguard Worker "Command line args to soong_ui for this benchmark." 148*9e94795aSAndroid Build Coastguard Worker if self.dumpvars: 149*9e94795aSAndroid Build Coastguard Worker return [ 150*9e94795aSAndroid Build Coastguard Worker "--dumpvars-mode", 151*9e94795aSAndroid Build Coastguard Worker f"--vars=\"{' '.join(_DUMPVARS_VARS)}\"", 152*9e94795aSAndroid Build Coastguard Worker f"--abs-vars=\"{' '.join(_DUMPVARS_ABS_VARS)}\"", 153*9e94795aSAndroid Build Coastguard Worker "--var-prefix=var_cache_", 154*9e94795aSAndroid Build Coastguard Worker "--abs-var-prefix=abs_var_cache_", 155*9e94795aSAndroid Build Coastguard Worker ] 156*9e94795aSAndroid Build Coastguard Worker elif self.modules: 157*9e94795aSAndroid Build Coastguard Worker return [ 158*9e94795aSAndroid Build Coastguard Worker "--build-mode", 159*9e94795aSAndroid Build Coastguard Worker "--all-modules", 160*9e94795aSAndroid Build Coastguard Worker f"--dir={root}", 161*9e94795aSAndroid Build Coastguard Worker "--skip-metrics-upload", 162*9e94795aSAndroid Build Coastguard Worker ] + self.modules 163*9e94795aSAndroid Build Coastguard Worker else: 164*9e94795aSAndroid Build Coastguard Worker raise Exception("Benchmark must specify dumpvars or modules") 165*9e94795aSAndroid Build Coastguard Worker 166*9e94795aSAndroid Build Coastguard Worker 167*9e94795aSAndroid Build Coastguard Worker@dataclasses.dataclass(frozen=True) 168*9e94795aSAndroid Build Coastguard Workerclass FileSnapshot: 169*9e94795aSAndroid Build Coastguard Worker "Snapshot of a file's contents." 170*9e94795aSAndroid Build Coastguard Worker 171*9e94795aSAndroid Build Coastguard Worker filename: str 172*9e94795aSAndroid Build Coastguard Worker "The file that was snapshottened" 173*9e94795aSAndroid Build Coastguard Worker 174*9e94795aSAndroid Build Coastguard Worker contents: str 175*9e94795aSAndroid Build Coastguard Worker "The contents of the file" 176*9e94795aSAndroid Build Coastguard Worker 177*9e94795aSAndroid Build Coastguard Worker def write(self): 178*9e94795aSAndroid Build Coastguard Worker "Write the contents back to the file" 179*9e94795aSAndroid Build Coastguard Worker with open(self.filename, "w") as f: 180*9e94795aSAndroid Build Coastguard Worker f.write(self.contents) 181*9e94795aSAndroid Build Coastguard Worker 182*9e94795aSAndroid Build Coastguard Worker 183*9e94795aSAndroid Build Coastguard Workerdef Snapshot(filename): 184*9e94795aSAndroid Build Coastguard Worker """Return a FileSnapshot with the file's current contents.""" 185*9e94795aSAndroid Build Coastguard Worker with open(filename) as f: 186*9e94795aSAndroid Build Coastguard Worker contents = f.read() 187*9e94795aSAndroid Build Coastguard Worker return FileSnapshot(filename, contents) 188*9e94795aSAndroid Build Coastguard Worker 189*9e94795aSAndroid Build Coastguard Worker 190*9e94795aSAndroid Build Coastguard Workerdef Clean(): 191*9e94795aSAndroid Build Coastguard Worker """Remove the out directory.""" 192*9e94795aSAndroid Build Coastguard Worker def remove_out(): 193*9e94795aSAndroid Build Coastguard Worker out_dir = utils.get_out_dir() 194*9e94795aSAndroid Build Coastguard Worker #only remove actual contents, in case out is a symlink (as is the case for cog) 195*9e94795aSAndroid Build Coastguard Worker if os.path.exists(out_dir): 196*9e94795aSAndroid Build Coastguard Worker for filename in os.listdir(out_dir): 197*9e94795aSAndroid Build Coastguard Worker p = os.path.join(out_dir, filename) 198*9e94795aSAndroid Build Coastguard Worker if os.path.isfile(p) or os.path.islink(p): 199*9e94795aSAndroid Build Coastguard Worker os.remove(p) 200*9e94795aSAndroid Build Coastguard Worker elif os.path.isdir(p): 201*9e94795aSAndroid Build Coastguard Worker shutil.rmtree(p) 202*9e94795aSAndroid Build Coastguard Worker return Change(label="Remove out", change=remove_out, undo=lambda: None) 203*9e94795aSAndroid Build Coastguard Worker 204*9e94795aSAndroid Build Coastguard Worker 205*9e94795aSAndroid Build Coastguard Workerdef NoChange(): 206*9e94795aSAndroid Build Coastguard Worker """No change to the source tree.""" 207*9e94795aSAndroid Build Coastguard Worker return Change(label="No change", change=lambda: None, undo=lambda: None) 208*9e94795aSAndroid Build Coastguard Worker 209*9e94795aSAndroid Build Coastguard Worker 210*9e94795aSAndroid Build Coastguard Workerdef Create(filename): 211*9e94795aSAndroid Build Coastguard Worker "Create an action to create `filename`. The parent directory must exist." 212*9e94795aSAndroid Build Coastguard Worker def create(): 213*9e94795aSAndroid Build Coastguard Worker with open(filename, "w") as f: 214*9e94795aSAndroid Build Coastguard Worker pass 215*9e94795aSAndroid Build Coastguard Worker def delete(): 216*9e94795aSAndroid Build Coastguard Worker os.remove(filename) 217*9e94795aSAndroid Build Coastguard Worker return Change( 218*9e94795aSAndroid Build Coastguard Worker label=f"Create {filename}", 219*9e94795aSAndroid Build Coastguard Worker change=create, 220*9e94795aSAndroid Build Coastguard Worker undo=delete, 221*9e94795aSAndroid Build Coastguard Worker ) 222*9e94795aSAndroid Build Coastguard Worker 223*9e94795aSAndroid Build Coastguard Worker 224*9e94795aSAndroid Build Coastguard Workerdef Modify(filename, contents, before=None): 225*9e94795aSAndroid Build Coastguard Worker """Create an action to modify `filename` by appending the result of `contents` 226*9e94795aSAndroid Build Coastguard Worker before the last instances of `before` in the file. 227*9e94795aSAndroid Build Coastguard Worker 228*9e94795aSAndroid Build Coastguard Worker Raises an error if `before` doesn't appear in the file. 229*9e94795aSAndroid Build Coastguard Worker """ 230*9e94795aSAndroid Build Coastguard Worker orig = Snapshot(filename) 231*9e94795aSAndroid Build Coastguard Worker if before: 232*9e94795aSAndroid Build Coastguard Worker index = orig.contents.rfind(before) 233*9e94795aSAndroid Build Coastguard Worker if index < 0: 234*9e94795aSAndroid Build Coastguard Worker report_error(f"{filename}: Unable to find string '{before}' for modify operation.") 235*9e94795aSAndroid Build Coastguard Worker raise FatalError() 236*9e94795aSAndroid Build Coastguard Worker else: 237*9e94795aSAndroid Build Coastguard Worker index = len(orig.contents) 238*9e94795aSAndroid Build Coastguard Worker modified = FileSnapshot(filename, orig.contents[:index] + contents() + orig.contents[index:]) 239*9e94795aSAndroid Build Coastguard Worker if False: 240*9e94795aSAndroid Build Coastguard Worker print(f"Modify: {filename}") 241*9e94795aSAndroid Build Coastguard Worker x = orig.contents.replace("\n", "\n ORIG") 242*9e94795aSAndroid Build Coastguard Worker print(f" ORIG {x}") 243*9e94795aSAndroid Build Coastguard Worker x = modified.contents.replace("\n", "\n MODIFIED") 244*9e94795aSAndroid Build Coastguard Worker print(f" MODIFIED {x}") 245*9e94795aSAndroid Build Coastguard Worker 246*9e94795aSAndroid Build Coastguard Worker return Change( 247*9e94795aSAndroid Build Coastguard Worker label="Modify " + filename, 248*9e94795aSAndroid Build Coastguard Worker change=lambda: modified.write(), 249*9e94795aSAndroid Build Coastguard Worker undo=lambda: orig.write() 250*9e94795aSAndroid Build Coastguard Worker ) 251*9e94795aSAndroid Build Coastguard Worker 252*9e94795aSAndroid Build Coastguard Workerdef ChangePublicApi(): 253*9e94795aSAndroid Build Coastguard Worker change = AddJavaField("frameworks/base/core/java/android/provider/Settings.java", 254*9e94795aSAndroid Build Coastguard Worker "@android.annotation.SuppressLint(\"UnflaggedApi\") public") 255*9e94795aSAndroid Build Coastguard Worker orig_current_text = Snapshot("frameworks/base/core/api/current.txt") 256*9e94795aSAndroid Build Coastguard Worker 257*9e94795aSAndroid Build Coastguard Worker def undo(): 258*9e94795aSAndroid Build Coastguard Worker change.undo() 259*9e94795aSAndroid Build Coastguard Worker orig_current_text.write() 260*9e94795aSAndroid Build Coastguard Worker 261*9e94795aSAndroid Build Coastguard Worker return Change( 262*9e94795aSAndroid Build Coastguard Worker label=change.label, 263*9e94795aSAndroid Build Coastguard Worker change=change.change, 264*9e94795aSAndroid Build Coastguard Worker undo=lambda: undo() 265*9e94795aSAndroid Build Coastguard Worker ) 266*9e94795aSAndroid Build Coastguard Worker 267*9e94795aSAndroid Build Coastguard Workerdef AddJavaField(filename, prefix): 268*9e94795aSAndroid Build Coastguard Worker return Modify(filename, 269*9e94795aSAndroid Build Coastguard Worker lambda: f"{prefix} static final int BENCHMARK = {random.randint(0, 1000000)};\n", 270*9e94795aSAndroid Build Coastguard Worker before="}") 271*9e94795aSAndroid Build Coastguard Worker 272*9e94795aSAndroid Build Coastguard Worker 273*9e94795aSAndroid Build Coastguard Workerdef Comment(prefix, suffix=""): 274*9e94795aSAndroid Build Coastguard Worker return lambda: prefix + " " + str(uuid.uuid4()) + suffix 275*9e94795aSAndroid Build Coastguard Worker 276*9e94795aSAndroid Build Coastguard Worker 277*9e94795aSAndroid Build Coastguard Workerclass BenchmarkReport(): 278*9e94795aSAndroid Build Coastguard Worker "Information about a run of the benchmark" 279*9e94795aSAndroid Build Coastguard Worker 280*9e94795aSAndroid Build Coastguard Worker lunch: Lunch 281*9e94795aSAndroid Build Coastguard Worker "lunch combo" 282*9e94795aSAndroid Build Coastguard Worker 283*9e94795aSAndroid Build Coastguard Worker benchmark: Benchmark 284*9e94795aSAndroid Build Coastguard Worker "The benchmark object." 285*9e94795aSAndroid Build Coastguard Worker 286*9e94795aSAndroid Build Coastguard Worker iteration: int 287*9e94795aSAndroid Build Coastguard Worker "Which iteration of the benchmark" 288*9e94795aSAndroid Build Coastguard Worker 289*9e94795aSAndroid Build Coastguard Worker log_dir: str 290*9e94795aSAndroid Build Coastguard Worker "Path the the log directory, relative to the root of the reports directory" 291*9e94795aSAndroid Build Coastguard Worker 292*9e94795aSAndroid Build Coastguard Worker preroll_duration_ns: [int] 293*9e94795aSAndroid Build Coastguard Worker "Durations of the in nanoseconds." 294*9e94795aSAndroid Build Coastguard Worker 295*9e94795aSAndroid Build Coastguard Worker duration_ns: int 296*9e94795aSAndroid Build Coastguard Worker "Duration of the measured portion of the benchmark in nanoseconds." 297*9e94795aSAndroid Build Coastguard Worker 298*9e94795aSAndroid Build Coastguard Worker postroll_duration_ns: [int] 299*9e94795aSAndroid Build Coastguard Worker "Durations of the postrolls in nanoseconds." 300*9e94795aSAndroid Build Coastguard Worker 301*9e94795aSAndroid Build Coastguard Worker complete: bool 302*9e94795aSAndroid Build Coastguard Worker "Whether the benchmark made it all the way through the postrolls." 303*9e94795aSAndroid Build Coastguard Worker 304*9e94795aSAndroid Build Coastguard Worker def __init__(self, lunch, benchmark, iteration, log_dir): 305*9e94795aSAndroid Build Coastguard Worker self.lunch = lunch 306*9e94795aSAndroid Build Coastguard Worker self.benchmark = benchmark 307*9e94795aSAndroid Build Coastguard Worker self.iteration = iteration 308*9e94795aSAndroid Build Coastguard Worker self.log_dir = log_dir 309*9e94795aSAndroid Build Coastguard Worker self.preroll_duration_ns = [] 310*9e94795aSAndroid Build Coastguard Worker self.duration_ns = -1 311*9e94795aSAndroid Build Coastguard Worker self.postroll_duration_ns = [] 312*9e94795aSAndroid Build Coastguard Worker self.complete = False 313*9e94795aSAndroid Build Coastguard Worker 314*9e94795aSAndroid Build Coastguard Worker def ToDict(self): 315*9e94795aSAndroid Build Coastguard Worker return { 316*9e94795aSAndroid Build Coastguard Worker "lunch": self.lunch.ToDict(), 317*9e94795aSAndroid Build Coastguard Worker "id": self.benchmark.id, 318*9e94795aSAndroid Build Coastguard Worker "title": self.benchmark.title, 319*9e94795aSAndroid Build Coastguard Worker "modules": self.benchmark.modules, 320*9e94795aSAndroid Build Coastguard Worker "dumpvars": self.benchmark.dumpvars, 321*9e94795aSAndroid Build Coastguard Worker "change": self.benchmark.change.label, 322*9e94795aSAndroid Build Coastguard Worker "iteration": self.iteration, 323*9e94795aSAndroid Build Coastguard Worker "log_dir": self.log_dir, 324*9e94795aSAndroid Build Coastguard Worker "preroll_duration_ns": self.preroll_duration_ns, 325*9e94795aSAndroid Build Coastguard Worker "duration_ns": self.duration_ns, 326*9e94795aSAndroid Build Coastguard Worker "postroll_duration_ns": self.postroll_duration_ns, 327*9e94795aSAndroid Build Coastguard Worker "complete": self.complete, 328*9e94795aSAndroid Build Coastguard Worker } 329*9e94795aSAndroid Build Coastguard Worker 330*9e94795aSAndroid Build Coastguard Workerclass Runner(): 331*9e94795aSAndroid Build Coastguard Worker """Runs the benchmarks.""" 332*9e94795aSAndroid Build Coastguard Worker 333*9e94795aSAndroid Build Coastguard Worker def __init__(self, options): 334*9e94795aSAndroid Build Coastguard Worker self._options = options 335*9e94795aSAndroid Build Coastguard Worker self._reports = [] 336*9e94795aSAndroid Build Coastguard Worker self._complete = False 337*9e94795aSAndroid Build Coastguard Worker 338*9e94795aSAndroid Build Coastguard Worker def Run(self): 339*9e94795aSAndroid Build Coastguard Worker """Run all of the user-selected benchmarks.""" 340*9e94795aSAndroid Build Coastguard Worker # Clean out the log dir or create it if necessary 341*9e94795aSAndroid Build Coastguard Worker prepare_log_dir(self._options.LogDir()) 342*9e94795aSAndroid Build Coastguard Worker 343*9e94795aSAndroid Build Coastguard Worker try: 344*9e94795aSAndroid Build Coastguard Worker for lunch in self._options.Lunches(): 345*9e94795aSAndroid Build Coastguard Worker print(lunch) 346*9e94795aSAndroid Build Coastguard Worker for benchmark in self._options.Benchmarks(): 347*9e94795aSAndroid Build Coastguard Worker for iteration in range(self._options.Iterations()): 348*9e94795aSAndroid Build Coastguard Worker self._run_benchmark(lunch, benchmark, iteration) 349*9e94795aSAndroid Build Coastguard Worker self._complete = True 350*9e94795aSAndroid Build Coastguard Worker finally: 351*9e94795aSAndroid Build Coastguard Worker self._write_summary() 352*9e94795aSAndroid Build Coastguard Worker 353*9e94795aSAndroid Build Coastguard Worker 354*9e94795aSAndroid Build Coastguard Worker def _run_benchmark(self, lunch, benchmark, iteration): 355*9e94795aSAndroid Build Coastguard Worker """Run a single benchmark.""" 356*9e94795aSAndroid Build Coastguard Worker benchmark_log_subdir = self._benchmark_log_dir(lunch, benchmark, iteration) 357*9e94795aSAndroid Build Coastguard Worker benchmark_log_dir = self._options.LogDir().joinpath(benchmark_log_subdir) 358*9e94795aSAndroid Build Coastguard Worker 359*9e94795aSAndroid Build Coastguard Worker sys.stderr.write(f"STARTING BENCHMARK: {benchmark.id}\n") 360*9e94795aSAndroid Build Coastguard Worker sys.stderr.write(f" lunch: {lunch.Combine()}\n") 361*9e94795aSAndroid Build Coastguard Worker sys.stderr.write(f" iteration: {iteration}\n") 362*9e94795aSAndroid Build Coastguard Worker sys.stderr.write(f" benchmark_log_dir: {benchmark_log_dir}\n") 363*9e94795aSAndroid Build Coastguard Worker 364*9e94795aSAndroid Build Coastguard Worker report = BenchmarkReport(lunch, benchmark, iteration, benchmark_log_subdir) 365*9e94795aSAndroid Build Coastguard Worker self._reports.append(report) 366*9e94795aSAndroid Build Coastguard Worker 367*9e94795aSAndroid Build Coastguard Worker # Preroll builds 368*9e94795aSAndroid Build Coastguard Worker for i in range(benchmark.preroll): 369*9e94795aSAndroid Build Coastguard Worker ns = self._run_build(lunch, benchmark_log_dir.joinpath(f"pre_{i}"), benchmark) 370*9e94795aSAndroid Build Coastguard Worker report.preroll_duration_ns.append(ns) 371*9e94795aSAndroid Build Coastguard Worker 372*9e94795aSAndroid Build Coastguard Worker sys.stderr.write(f"PERFORMING CHANGE: {benchmark.change.label}\n") 373*9e94795aSAndroid Build Coastguard Worker if not self._options.DryRun(): 374*9e94795aSAndroid Build Coastguard Worker benchmark.change.change() 375*9e94795aSAndroid Build Coastguard Worker try: 376*9e94795aSAndroid Build Coastguard Worker 377*9e94795aSAndroid Build Coastguard Worker # Measured build 378*9e94795aSAndroid Build Coastguard Worker ns = self._run_build(lunch, benchmark_log_dir.joinpath("measured"), benchmark) 379*9e94795aSAndroid Build Coastguard Worker report.duration_ns = ns 380*9e94795aSAndroid Build Coastguard Worker 381*9e94795aSAndroid Build Coastguard Worker dist_one = self._options.DistOne() 382*9e94795aSAndroid Build Coastguard Worker if dist_one: 383*9e94795aSAndroid Build Coastguard Worker # If we're disting just one benchmark, save the logs and we can stop here. 384*9e94795aSAndroid Build Coastguard Worker self._dist(utils.get_dist_dir(), benchmark.dumpvars) 385*9e94795aSAndroid Build Coastguard Worker else: 386*9e94795aSAndroid Build Coastguard Worker self._dist(benchmark_log_dir, benchmark.dumpvars, store_metrics_only=True) 387*9e94795aSAndroid Build Coastguard Worker # Postroll builds 388*9e94795aSAndroid Build Coastguard Worker for i in range(benchmark.postroll): 389*9e94795aSAndroid Build Coastguard Worker ns = self._run_build(lunch, benchmark_log_dir.joinpath(f"post_{i}"), 390*9e94795aSAndroid Build Coastguard Worker benchmark) 391*9e94795aSAndroid Build Coastguard Worker report.postroll_duration_ns.append(ns) 392*9e94795aSAndroid Build Coastguard Worker 393*9e94795aSAndroid Build Coastguard Worker finally: 394*9e94795aSAndroid Build Coastguard Worker # Always undo, even if we crashed or the build failed and we stopped. 395*9e94795aSAndroid Build Coastguard Worker sys.stderr.write(f"UNDOING CHANGE: {benchmark.change.label}\n") 396*9e94795aSAndroid Build Coastguard Worker if not self._options.DryRun(): 397*9e94795aSAndroid Build Coastguard Worker benchmark.change.undo() 398*9e94795aSAndroid Build Coastguard Worker 399*9e94795aSAndroid Build Coastguard Worker self._write_summary() 400*9e94795aSAndroid Build Coastguard Worker sys.stderr.write(f"FINISHED BENCHMARK: {benchmark.id}\n") 401*9e94795aSAndroid Build Coastguard Worker 402*9e94795aSAndroid Build Coastguard Worker def _benchmark_log_dir(self, lunch, benchmark, iteration): 403*9e94795aSAndroid Build Coastguard Worker """Construct the log directory fir a benchmark run.""" 404*9e94795aSAndroid Build Coastguard Worker path = f"{lunch.Combine()}/{benchmark.id}" 405*9e94795aSAndroid Build Coastguard Worker # Zero pad to the correct length for correct alpha sorting 406*9e94795aSAndroid Build Coastguard Worker path += ("/%0" + str(len(str(self._options.Iterations()))) + "d") % iteration 407*9e94795aSAndroid Build Coastguard Worker return path 408*9e94795aSAndroid Build Coastguard Worker 409*9e94795aSAndroid Build Coastguard Worker def _run_build(self, lunch, build_log_dir, benchmark): 410*9e94795aSAndroid Build Coastguard Worker """Builds the modules. Saves interesting log files to log_dir. Raises FatalError 411*9e94795aSAndroid Build Coastguard Worker if the build fails. 412*9e94795aSAndroid Build Coastguard Worker """ 413*9e94795aSAndroid Build Coastguard Worker sys.stderr.write(f"STARTING BUILD {benchmark.build_description()}\n") 414*9e94795aSAndroid Build Coastguard Worker 415*9e94795aSAndroid Build Coastguard Worker before_ns = time.perf_counter_ns() 416*9e94795aSAndroid Build Coastguard Worker if not self._options.DryRun(): 417*9e94795aSAndroid Build Coastguard Worker cmd = [ 418*9e94795aSAndroid Build Coastguard Worker "build/soong/soong_ui.bash", 419*9e94795aSAndroid Build Coastguard Worker ] + benchmark.soong_command(self._options.root) 420*9e94795aSAndroid Build Coastguard Worker env = dict(os.environ) 421*9e94795aSAndroid Build Coastguard Worker env["TARGET_PRODUCT"] = lunch.target_product 422*9e94795aSAndroid Build Coastguard Worker env["TARGET_RELEASE"] = lunch.target_release 423*9e94795aSAndroid Build Coastguard Worker env["TARGET_BUILD_VARIANT"] = lunch.target_build_variant 424*9e94795aSAndroid Build Coastguard Worker returncode = subprocess.call(cmd, env=env) 425*9e94795aSAndroid Build Coastguard Worker if returncode != 0: 426*9e94795aSAndroid Build Coastguard Worker report_error(f"Build failed: {' '.join(cmd)}") 427*9e94795aSAndroid Build Coastguard Worker raise FatalError() 428*9e94795aSAndroid Build Coastguard Worker 429*9e94795aSAndroid Build Coastguard Worker after_ns = time.perf_counter_ns() 430*9e94795aSAndroid Build Coastguard Worker 431*9e94795aSAndroid Build Coastguard Worker # TODO: Copy some log files. 432*9e94795aSAndroid Build Coastguard Worker 433*9e94795aSAndroid Build Coastguard Worker sys.stderr.write(f"FINISHED BUILD {benchmark.build_description()}\n") 434*9e94795aSAndroid Build Coastguard Worker 435*9e94795aSAndroid Build Coastguard Worker return after_ns - before_ns 436*9e94795aSAndroid Build Coastguard Worker 437*9e94795aSAndroid Build Coastguard Worker def _dist(self, dist_dir, dumpvars, store_metrics_only=False): 438*9e94795aSAndroid Build Coastguard Worker out_dir = utils.get_out_dir() 439*9e94795aSAndroid Build Coastguard Worker dest_dir = dist_dir.joinpath("logs") 440*9e94795aSAndroid Build Coastguard Worker os.makedirs(dest_dir, exist_ok=True) 441*9e94795aSAndroid Build Coastguard Worker basenames = [ 442*9e94795aSAndroid Build Coastguard Worker "soong_build_metrics.pb", 443*9e94795aSAndroid Build Coastguard Worker "soong_metrics", 444*9e94795aSAndroid Build Coastguard Worker ] 445*9e94795aSAndroid Build Coastguard Worker if not store_metrics_only: 446*9e94795aSAndroid Build Coastguard Worker basenames.extend([ 447*9e94795aSAndroid Build Coastguard Worker "build.trace.gz", 448*9e94795aSAndroid Build Coastguard Worker "soong.log", 449*9e94795aSAndroid Build Coastguard Worker ]) 450*9e94795aSAndroid Build Coastguard Worker if dumpvars: 451*9e94795aSAndroid Build Coastguard Worker basenames = ['dumpvars-'+b for b in basenames] 452*9e94795aSAndroid Build Coastguard Worker for base in basenames: 453*9e94795aSAndroid Build Coastguard Worker src = out_dir.joinpath(base) 454*9e94795aSAndroid Build Coastguard Worker if src.exists(): 455*9e94795aSAndroid Build Coastguard Worker sys.stderr.write(f"DIST: copied {src} to {dest_dir}\n") 456*9e94795aSAndroid Build Coastguard Worker shutil.copy(src, dest_dir) 457*9e94795aSAndroid Build Coastguard Worker 458*9e94795aSAndroid Build Coastguard Worker def _write_summary(self): 459*9e94795aSAndroid Build Coastguard Worker # Write the results, even if the build failed or we crashed, including 460*9e94795aSAndroid Build Coastguard Worker # whether we finished all of the benchmarks. 461*9e94795aSAndroid Build Coastguard Worker data = { 462*9e94795aSAndroid Build Coastguard Worker "start_time": self._options.Timestamp().isoformat(), 463*9e94795aSAndroid Build Coastguard Worker "branch": self._options.Branch(), 464*9e94795aSAndroid Build Coastguard Worker "tag": self._options.Tag(), 465*9e94795aSAndroid Build Coastguard Worker "benchmarks": [report.ToDict() for report in self._reports], 466*9e94795aSAndroid Build Coastguard Worker "complete": self._complete, 467*9e94795aSAndroid Build Coastguard Worker } 468*9e94795aSAndroid Build Coastguard Worker with open(self._options.LogDir().joinpath("summary.json"), "w", encoding="utf-8") as f: 469*9e94795aSAndroid Build Coastguard Worker json.dump(data, f, indent=2, sort_keys=True) 470*9e94795aSAndroid Build Coastguard Worker 471*9e94795aSAndroid Build Coastguard Worker 472*9e94795aSAndroid Build Coastguard Workerdef benchmark_table(benchmarks): 473*9e94795aSAndroid Build Coastguard Worker rows = [("ID", "DESCRIPTION", "REBUILD"),] 474*9e94795aSAndroid Build Coastguard Worker rows += [(benchmark.id, benchmark.title, benchmark.build_description()) for benchmark in 475*9e94795aSAndroid Build Coastguard Worker benchmarks] 476*9e94795aSAndroid Build Coastguard Worker return rows 477*9e94795aSAndroid Build Coastguard Worker 478*9e94795aSAndroid Build Coastguard Worker 479*9e94795aSAndroid Build Coastguard Workerdef prepare_log_dir(directory): 480*9e94795aSAndroid Build Coastguard Worker if os.path.exists(directory): 481*9e94795aSAndroid Build Coastguard Worker # If it exists and isn't a directory, fail. 482*9e94795aSAndroid Build Coastguard Worker if not os.path.isdir(directory): 483*9e94795aSAndroid Build Coastguard Worker report_error(f"Log directory already exists but isn't a directory: {directory}") 484*9e94795aSAndroid Build Coastguard Worker raise FatalError() 485*9e94795aSAndroid Build Coastguard Worker # Make sure the directory is empty. Do this rather than deleting it to handle 486*9e94795aSAndroid Build Coastguard Worker # symlinks cleanly. 487*9e94795aSAndroid Build Coastguard Worker for filename in os.listdir(directory): 488*9e94795aSAndroid Build Coastguard Worker entry = os.path.join(directory, filename) 489*9e94795aSAndroid Build Coastguard Worker if os.path.isdir(entry): 490*9e94795aSAndroid Build Coastguard Worker shutil.rmtree(entry) 491*9e94795aSAndroid Build Coastguard Worker else: 492*9e94795aSAndroid Build Coastguard Worker os.unlink(entry) 493*9e94795aSAndroid Build Coastguard Worker else: 494*9e94795aSAndroid Build Coastguard Worker # Create it 495*9e94795aSAndroid Build Coastguard Worker os.makedirs(directory) 496*9e94795aSAndroid Build Coastguard Worker 497*9e94795aSAndroid Build Coastguard Worker 498*9e94795aSAndroid Build Coastguard Workerclass Options(): 499*9e94795aSAndroid Build Coastguard Worker def __init__(self): 500*9e94795aSAndroid Build Coastguard Worker self._had_error = False 501*9e94795aSAndroid Build Coastguard Worker 502*9e94795aSAndroid Build Coastguard Worker # Wall time clock when we started 503*9e94795aSAndroid Build Coastguard Worker self._timestamp = datetime.datetime.now(datetime.timezone.utc) 504*9e94795aSAndroid Build Coastguard Worker 505*9e94795aSAndroid Build Coastguard Worker # Move to the root of the tree right away. Everything must happen from there. 506*9e94795aSAndroid Build Coastguard Worker self.root = utils.get_root() 507*9e94795aSAndroid Build Coastguard Worker if not self.root: 508*9e94795aSAndroid Build Coastguard Worker report_error("Unable to find root of tree from cwd.") 509*9e94795aSAndroid Build Coastguard Worker raise FatalError() 510*9e94795aSAndroid Build Coastguard Worker os.chdir(self.root) 511*9e94795aSAndroid Build Coastguard Worker 512*9e94795aSAndroid Build Coastguard Worker # Initialize the Benchmarks. Note that this pre-loads all of the files, etc. 513*9e94795aSAndroid Build Coastguard Worker # Doing all that here forces us to fail fast if one of them can't load a required 514*9e94795aSAndroid Build Coastguard Worker # file, at the cost of a small startup speed. Don't make this do something slow 515*9e94795aSAndroid Build Coastguard Worker # like scan the whole tree. 516*9e94795aSAndroid Build Coastguard Worker self._init_benchmarks() 517*9e94795aSAndroid Build Coastguard Worker 518*9e94795aSAndroid Build Coastguard Worker # Argument parsing 519*9e94795aSAndroid Build Coastguard Worker epilog = f""" 520*9e94795aSAndroid Build Coastguard Workerbenchmarks: 521*9e94795aSAndroid Build Coastguard Worker{pretty.FormatTable(benchmark_table(self._benchmarks), prefix=" ")} 522*9e94795aSAndroid Build Coastguard Worker""" 523*9e94795aSAndroid Build Coastguard Worker 524*9e94795aSAndroid Build Coastguard Worker parser = argparse.ArgumentParser( 525*9e94795aSAndroid Build Coastguard Worker prog="benchmarks", 526*9e94795aSAndroid Build Coastguard Worker allow_abbrev=False, # Don't let people write unsupportable scripts. 527*9e94795aSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter, 528*9e94795aSAndroid Build Coastguard Worker epilog=epilog, 529*9e94795aSAndroid Build Coastguard Worker description="Run build system performance benchmarks.") 530*9e94795aSAndroid Build Coastguard Worker self.parser = parser 531*9e94795aSAndroid Build Coastguard Worker 532*9e94795aSAndroid Build Coastguard Worker parser.add_argument("--log-dir", 533*9e94795aSAndroid Build Coastguard Worker help="Directory for logs. Default is $TOP/../benchmarks/.") 534*9e94795aSAndroid Build Coastguard Worker parser.add_argument("--dated-logs", action="store_true", 535*9e94795aSAndroid Build Coastguard Worker help="Append timestamp to log dir.") 536*9e94795aSAndroid Build Coastguard Worker parser.add_argument("-n", action="store_true", dest="dry_run", 537*9e94795aSAndroid Build Coastguard Worker help="Dry run. Don't run the build commands but do everything else.") 538*9e94795aSAndroid Build Coastguard Worker parser.add_argument("--tag", 539*9e94795aSAndroid Build Coastguard Worker help="Variant of the run, for when there are multiple perf runs.") 540*9e94795aSAndroid Build Coastguard Worker parser.add_argument("--lunch", nargs="*", 541*9e94795aSAndroid Build Coastguard Worker help="Lunch combos to test") 542*9e94795aSAndroid Build Coastguard Worker parser.add_argument("--iterations", type=int, default=1, 543*9e94795aSAndroid Build Coastguard Worker help="Number of iterations of each test to run.") 544*9e94795aSAndroid Build Coastguard Worker parser.add_argument("--branch", type=str, 545*9e94795aSAndroid Build Coastguard Worker help="Specify branch. Otherwise a guess will be made based on repo.") 546*9e94795aSAndroid Build Coastguard Worker parser.add_argument("--benchmark", nargs="*", default=[b.id for b in self._benchmarks], 547*9e94795aSAndroid Build Coastguard Worker metavar="BENCHMARKS", 548*9e94795aSAndroid Build Coastguard Worker help="Benchmarks to run. Default suite will be run if omitted.") 549*9e94795aSAndroid Build Coastguard Worker parser.add_argument("--dist-one", action="store_true", 550*9e94795aSAndroid Build Coastguard Worker help="Copy logs and metrics to the given dist dir. Requires that only" 551*9e94795aSAndroid Build Coastguard Worker + " one benchmark be supplied. Postroll steps will be skipped.") 552*9e94795aSAndroid Build Coastguard Worker 553*9e94795aSAndroid Build Coastguard Worker self._args = parser.parse_args() 554*9e94795aSAndroid Build Coastguard Worker 555*9e94795aSAndroid Build Coastguard Worker self._branch = self._branch() 556*9e94795aSAndroid Build Coastguard Worker self._log_dir = self._log_dir() 557*9e94795aSAndroid Build Coastguard Worker self._lunches = self._lunches() 558*9e94795aSAndroid Build Coastguard Worker 559*9e94795aSAndroid Build Coastguard Worker # Validate the benchmark ids 560*9e94795aSAndroid Build Coastguard Worker all_ids = [benchmark.id for benchmark in self._benchmarks] 561*9e94795aSAndroid Build Coastguard Worker bad_ids = [id for id in self._args.benchmark if id not in all_ids] 562*9e94795aSAndroid Build Coastguard Worker if bad_ids: 563*9e94795aSAndroid Build Coastguard Worker for id in bad_ids: 564*9e94795aSAndroid Build Coastguard Worker self._error(f"Invalid benchmark: {id}") 565*9e94795aSAndroid Build Coastguard Worker 566*9e94795aSAndroid Build Coastguard Worker # --dist-one requires that only one benchmark be supplied 567*9e94795aSAndroid Build Coastguard Worker if self._args.dist_one and len(self.Benchmarks()) != 1: 568*9e94795aSAndroid Build Coastguard Worker self._error("--dist-one requires that exactly one --benchmark.") 569*9e94795aSAndroid Build Coastguard Worker 570*9e94795aSAndroid Build Coastguard Worker if self._had_error: 571*9e94795aSAndroid Build Coastguard Worker raise FatalError() 572*9e94795aSAndroid Build Coastguard Worker 573*9e94795aSAndroid Build Coastguard Worker def Timestamp(self): 574*9e94795aSAndroid Build Coastguard Worker return self._timestamp 575*9e94795aSAndroid Build Coastguard Worker 576*9e94795aSAndroid Build Coastguard Worker def _branch(self): 577*9e94795aSAndroid Build Coastguard Worker """Return the branch, either from the command line or by guessing from repo.""" 578*9e94795aSAndroid Build Coastguard Worker if self._args.branch: 579*9e94795aSAndroid Build Coastguard Worker return self._args.branch 580*9e94795aSAndroid Build Coastguard Worker try: 581*9e94795aSAndroid Build Coastguard Worker branch = subprocess.check_output(f"cd {self.root}/.repo/manifests" 582*9e94795aSAndroid Build Coastguard Worker + " && git rev-parse --abbrev-ref --symbolic-full-name @{u}", 583*9e94795aSAndroid Build Coastguard Worker shell=True, encoding="utf-8") 584*9e94795aSAndroid Build Coastguard Worker return branch.strip().split("/")[-1] 585*9e94795aSAndroid Build Coastguard Worker except subprocess.CalledProcessError as ex: 586*9e94795aSAndroid Build Coastguard Worker report_error("Can't get branch from .repo dir. Specify --branch argument") 587*9e94795aSAndroid Build Coastguard Worker report_error(str(ex)) 588*9e94795aSAndroid Build Coastguard Worker raise FatalError() 589*9e94795aSAndroid Build Coastguard Worker 590*9e94795aSAndroid Build Coastguard Worker def Branch(self): 591*9e94795aSAndroid Build Coastguard Worker return self._branch 592*9e94795aSAndroid Build Coastguard Worker 593*9e94795aSAndroid Build Coastguard Worker def _log_dir(self): 594*9e94795aSAndroid Build Coastguard Worker "The log directory to use, based on the current options" 595*9e94795aSAndroid Build Coastguard Worker if self._args.log_dir: 596*9e94795aSAndroid Build Coastguard Worker d = pathlib.Path(self._args.log_dir).resolve().absolute() 597*9e94795aSAndroid Build Coastguard Worker else: 598*9e94795aSAndroid Build Coastguard Worker d = self.root.joinpath("..", utils.DEFAULT_REPORT_DIR) 599*9e94795aSAndroid Build Coastguard Worker if self._args.dated_logs: 600*9e94795aSAndroid Build Coastguard Worker d = d.joinpath(self._timestamp.strftime('%Y-%m-%d')) 601*9e94795aSAndroid Build Coastguard Worker d = d.joinpath(self._branch) 602*9e94795aSAndroid Build Coastguard Worker if self._args.tag: 603*9e94795aSAndroid Build Coastguard Worker d = d.joinpath(self._args.tag) 604*9e94795aSAndroid Build Coastguard Worker return d.resolve().absolute() 605*9e94795aSAndroid Build Coastguard Worker 606*9e94795aSAndroid Build Coastguard Worker def LogDir(self): 607*9e94795aSAndroid Build Coastguard Worker return self._log_dir 608*9e94795aSAndroid Build Coastguard Worker 609*9e94795aSAndroid Build Coastguard Worker def Benchmarks(self): 610*9e94795aSAndroid Build Coastguard Worker return [b for b in self._benchmarks if b.id in self._args.benchmark] 611*9e94795aSAndroid Build Coastguard Worker 612*9e94795aSAndroid Build Coastguard Worker def Tag(self): 613*9e94795aSAndroid Build Coastguard Worker return self._args.tag 614*9e94795aSAndroid Build Coastguard Worker 615*9e94795aSAndroid Build Coastguard Worker def DryRun(self): 616*9e94795aSAndroid Build Coastguard Worker return self._args.dry_run 617*9e94795aSAndroid Build Coastguard Worker 618*9e94795aSAndroid Build Coastguard Worker def _lunches(self): 619*9e94795aSAndroid Build Coastguard Worker def parse_lunch(lunch): 620*9e94795aSAndroid Build Coastguard Worker parts = lunch.split("-") 621*9e94795aSAndroid Build Coastguard Worker if len(parts) != 3: 622*9e94795aSAndroid Build Coastguard Worker raise OptionsError(f"Invalid lunch combo: {lunch}") 623*9e94795aSAndroid Build Coastguard Worker return Lunch(parts[0], parts[1], parts[2]) 624*9e94795aSAndroid Build Coastguard Worker # If they gave lunch targets on the command line use that 625*9e94795aSAndroid Build Coastguard Worker if self._args.lunch: 626*9e94795aSAndroid Build Coastguard Worker result = [] 627*9e94795aSAndroid Build Coastguard Worker # Split into Lunch objects 628*9e94795aSAndroid Build Coastguard Worker for lunch in self._args.lunch: 629*9e94795aSAndroid Build Coastguard Worker try: 630*9e94795aSAndroid Build Coastguard Worker result.append(parse_lunch(lunch)) 631*9e94795aSAndroid Build Coastguard Worker except OptionsError as ex: 632*9e94795aSAndroid Build Coastguard Worker self._error(ex.message) 633*9e94795aSAndroid Build Coastguard Worker return result 634*9e94795aSAndroid Build Coastguard Worker # Use whats in the environment 635*9e94795aSAndroid Build Coastguard Worker product = os.getenv("TARGET_PRODUCT") 636*9e94795aSAndroid Build Coastguard Worker release = os.getenv("TARGET_RELEASE") 637*9e94795aSAndroid Build Coastguard Worker variant = os.getenv("TARGET_BUILD_VARIANT") 638*9e94795aSAndroid Build Coastguard Worker if (not product) or (not release) or (not variant): 639*9e94795aSAndroid Build Coastguard Worker # If they didn't give us anything, fail rather than guessing. There's no good 640*9e94795aSAndroid Build Coastguard Worker # default for AOSP. 641*9e94795aSAndroid Build Coastguard Worker self._error("No lunch combo specified. Either pass --lunch argument or run lunch.") 642*9e94795aSAndroid Build Coastguard Worker return [] 643*9e94795aSAndroid Build Coastguard Worker return [Lunch(product, release, variant),] 644*9e94795aSAndroid Build Coastguard Worker 645*9e94795aSAndroid Build Coastguard Worker def Lunches(self): 646*9e94795aSAndroid Build Coastguard Worker return self._lunches 647*9e94795aSAndroid Build Coastguard Worker 648*9e94795aSAndroid Build Coastguard Worker def Iterations(self): 649*9e94795aSAndroid Build Coastguard Worker return self._args.iterations 650*9e94795aSAndroid Build Coastguard Worker 651*9e94795aSAndroid Build Coastguard Worker def DistOne(self): 652*9e94795aSAndroid Build Coastguard Worker return self._args.dist_one 653*9e94795aSAndroid Build Coastguard Worker 654*9e94795aSAndroid Build Coastguard Worker def _init_benchmarks(self): 655*9e94795aSAndroid Build Coastguard Worker """Initialize the list of benchmarks.""" 656*9e94795aSAndroid Build Coastguard Worker # Assumes that we've already chdired to the root of the tree. 657*9e94795aSAndroid Build Coastguard Worker self._benchmarks = [ 658*9e94795aSAndroid Build Coastguard Worker Benchmark( 659*9e94795aSAndroid Build Coastguard Worker id="full_lunch", 660*9e94795aSAndroid Build Coastguard Worker title="Lunch from clean out", 661*9e94795aSAndroid Build Coastguard Worker change=Clean(), 662*9e94795aSAndroid Build Coastguard Worker dumpvars=True, 663*9e94795aSAndroid Build Coastguard Worker preroll=0, 664*9e94795aSAndroid Build Coastguard Worker postroll=0, 665*9e94795aSAndroid Build Coastguard Worker ), 666*9e94795aSAndroid Build Coastguard Worker Benchmark( 667*9e94795aSAndroid Build Coastguard Worker id="noop_lunch", 668*9e94795aSAndroid Build Coastguard Worker title="Lunch with no change", 669*9e94795aSAndroid Build Coastguard Worker change=NoChange(), 670*9e94795aSAndroid Build Coastguard Worker dumpvars=True, 671*9e94795aSAndroid Build Coastguard Worker preroll=1, 672*9e94795aSAndroid Build Coastguard Worker postroll=0, 673*9e94795aSAndroid Build Coastguard Worker ), 674*9e94795aSAndroid Build Coastguard Worker Benchmark(id="full", 675*9e94795aSAndroid Build Coastguard Worker title="Full build", 676*9e94795aSAndroid Build Coastguard Worker change=Clean(), 677*9e94795aSAndroid Build Coastguard Worker modules=["droid"], 678*9e94795aSAndroid Build Coastguard Worker preroll=0, 679*9e94795aSAndroid Build Coastguard Worker postroll=3, 680*9e94795aSAndroid Build Coastguard Worker ), 681*9e94795aSAndroid Build Coastguard Worker Benchmark(id="nochange", 682*9e94795aSAndroid Build Coastguard Worker title="No change", 683*9e94795aSAndroid Build Coastguard Worker change=NoChange(), 684*9e94795aSAndroid Build Coastguard Worker modules=["droid"], 685*9e94795aSAndroid Build Coastguard Worker preroll=2, 686*9e94795aSAndroid Build Coastguard Worker postroll=3, 687*9e94795aSAndroid Build Coastguard Worker ), 688*9e94795aSAndroid Build Coastguard Worker Benchmark(id="unreferenced", 689*9e94795aSAndroid Build Coastguard Worker title="Create unreferenced file", 690*9e94795aSAndroid Build Coastguard Worker change=Create("bionic/unreferenced.txt"), 691*9e94795aSAndroid Build Coastguard Worker modules=["droid"], 692*9e94795aSAndroid Build Coastguard Worker preroll=1, 693*9e94795aSAndroid Build Coastguard Worker postroll=2, 694*9e94795aSAndroid Build Coastguard Worker ), 695*9e94795aSAndroid Build Coastguard Worker Benchmark(id="modify_bp", 696*9e94795aSAndroid Build Coastguard Worker title="Modify Android.bp", 697*9e94795aSAndroid Build Coastguard Worker change=Modify("bionic/libc/Android.bp", Comment("//")), 698*9e94795aSAndroid Build Coastguard Worker modules=["droid"], 699*9e94795aSAndroid Build Coastguard Worker preroll=1, 700*9e94795aSAndroid Build Coastguard Worker postroll=3, 701*9e94795aSAndroid Build Coastguard Worker ), 702*9e94795aSAndroid Build Coastguard Worker Benchmark(id="modify_stdio", 703*9e94795aSAndroid Build Coastguard Worker title="Modify stdio.cpp", 704*9e94795aSAndroid Build Coastguard Worker change=Modify("bionic/libc/stdio/stdio.cpp", Comment("//")), 705*9e94795aSAndroid Build Coastguard Worker modules=["libc"], 706*9e94795aSAndroid Build Coastguard Worker preroll=1, 707*9e94795aSAndroid Build Coastguard Worker postroll=2, 708*9e94795aSAndroid Build Coastguard Worker ), 709*9e94795aSAndroid Build Coastguard Worker Benchmark(id="modify_adbd", 710*9e94795aSAndroid Build Coastguard Worker title="Modify adbd", 711*9e94795aSAndroid Build Coastguard Worker change=Modify("packages/modules/adb/daemon/main.cpp", Comment("//")), 712*9e94795aSAndroid Build Coastguard Worker modules=["adbd"], 713*9e94795aSAndroid Build Coastguard Worker preroll=1, 714*9e94795aSAndroid Build Coastguard Worker postroll=2, 715*9e94795aSAndroid Build Coastguard Worker ), 716*9e94795aSAndroid Build Coastguard Worker Benchmark(id="services_private_field", 717*9e94795aSAndroid Build Coastguard Worker title="Add private field to ActivityManagerService.java", 718*9e94795aSAndroid Build Coastguard Worker change=AddJavaField("frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java", 719*9e94795aSAndroid Build Coastguard Worker "private"), 720*9e94795aSAndroid Build Coastguard Worker modules=["services"], 721*9e94795aSAndroid Build Coastguard Worker preroll=1, 722*9e94795aSAndroid Build Coastguard Worker postroll=2, 723*9e94795aSAndroid Build Coastguard Worker ), 724*9e94795aSAndroid Build Coastguard Worker Benchmark(id="services_public_field", 725*9e94795aSAndroid Build Coastguard Worker title="Add public field to ActivityManagerService.java", 726*9e94795aSAndroid Build Coastguard Worker change=AddJavaField("frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java", 727*9e94795aSAndroid Build Coastguard Worker "/** @hide */ public"), 728*9e94795aSAndroid Build Coastguard Worker modules=["services"], 729*9e94795aSAndroid Build Coastguard Worker preroll=1, 730*9e94795aSAndroid Build Coastguard Worker postroll=2, 731*9e94795aSAndroid Build Coastguard Worker ), 732*9e94795aSAndroid Build Coastguard Worker Benchmark(id="services_api", 733*9e94795aSAndroid Build Coastguard Worker title="Add API to ActivityManagerService.javaa", 734*9e94795aSAndroid Build Coastguard Worker change=AddJavaField("frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java", 735*9e94795aSAndroid Build Coastguard Worker "@android.annotation.SuppressLint(\"UnflaggedApi\") public"), 736*9e94795aSAndroid Build Coastguard Worker modules=["services"], 737*9e94795aSAndroid Build Coastguard Worker preroll=1, 738*9e94795aSAndroid Build Coastguard Worker postroll=2, 739*9e94795aSAndroid Build Coastguard Worker ), 740*9e94795aSAndroid Build Coastguard Worker Benchmark(id="framework_private_field", 741*9e94795aSAndroid Build Coastguard Worker title="Add private field to Settings.java", 742*9e94795aSAndroid Build Coastguard Worker change=AddJavaField("frameworks/base/core/java/android/provider/Settings.java", 743*9e94795aSAndroid Build Coastguard Worker "private"), 744*9e94795aSAndroid Build Coastguard Worker modules=["framework-minus-apex"], 745*9e94795aSAndroid Build Coastguard Worker preroll=1, 746*9e94795aSAndroid Build Coastguard Worker postroll=2, 747*9e94795aSAndroid Build Coastguard Worker ), 748*9e94795aSAndroid Build Coastguard Worker Benchmark(id="framework_public_field", 749*9e94795aSAndroid Build Coastguard Worker title="Add public field to Settings.java", 750*9e94795aSAndroid Build Coastguard Worker change=AddJavaField("frameworks/base/core/java/android/provider/Settings.java", 751*9e94795aSAndroid Build Coastguard Worker "/** @hide */ public"), 752*9e94795aSAndroid Build Coastguard Worker modules=["framework-minus-apex"], 753*9e94795aSAndroid Build Coastguard Worker preroll=1, 754*9e94795aSAndroid Build Coastguard Worker postroll=2, 755*9e94795aSAndroid Build Coastguard Worker ), 756*9e94795aSAndroid Build Coastguard Worker Benchmark(id="framework_api", 757*9e94795aSAndroid Build Coastguard Worker title="Add API to Settings.java", 758*9e94795aSAndroid Build Coastguard Worker change=ChangePublicApi(), 759*9e94795aSAndroid Build Coastguard Worker modules=["api-stubs-docs-non-updatable-update-current-api", "framework-minus-apex"], 760*9e94795aSAndroid Build Coastguard Worker preroll=1, 761*9e94795aSAndroid Build Coastguard Worker postroll=2, 762*9e94795aSAndroid Build Coastguard Worker ), 763*9e94795aSAndroid Build Coastguard Worker Benchmark(id="modify_framework_resource", 764*9e94795aSAndroid Build Coastguard Worker title="Modify framework resource", 765*9e94795aSAndroid Build Coastguard Worker change=Modify("frameworks/base/core/res/res/values/config.xml", 766*9e94795aSAndroid Build Coastguard Worker lambda: str(uuid.uuid4()), 767*9e94795aSAndroid Build Coastguard Worker before="</string>"), 768*9e94795aSAndroid Build Coastguard Worker modules=["framework-minus-apex"], 769*9e94795aSAndroid Build Coastguard Worker preroll=1, 770*9e94795aSAndroid Build Coastguard Worker postroll=2, 771*9e94795aSAndroid Build Coastguard Worker ), 772*9e94795aSAndroid Build Coastguard Worker Benchmark(id="add_framework_resource", 773*9e94795aSAndroid Build Coastguard Worker title="Add framework resource", 774*9e94795aSAndroid Build Coastguard Worker change=Modify("frameworks/base/core/res/res/values/config.xml", 775*9e94795aSAndroid Build Coastguard Worker lambda: f"<string name=\"BENCHMARK\">{uuid.uuid4()}</string>", 776*9e94795aSAndroid Build Coastguard Worker before="</resources>"), 777*9e94795aSAndroid Build Coastguard Worker modules=["framework-minus-apex"], 778*9e94795aSAndroid Build Coastguard Worker preroll=1, 779*9e94795aSAndroid Build Coastguard Worker postroll=2, 780*9e94795aSAndroid Build Coastguard Worker ), 781*9e94795aSAndroid Build Coastguard Worker Benchmark(id="add_systemui_field", 782*9e94795aSAndroid Build Coastguard Worker title="Add SystemUI field", 783*9e94795aSAndroid Build Coastguard Worker change=AddJavaField("frameworks/base/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java", 784*9e94795aSAndroid Build Coastguard Worker "public"), 785*9e94795aSAndroid Build Coastguard Worker modules=["SystemUI"], 786*9e94795aSAndroid Build Coastguard Worker preroll=1, 787*9e94795aSAndroid Build Coastguard Worker postroll=2, 788*9e94795aSAndroid Build Coastguard Worker ), 789*9e94795aSAndroid Build Coastguard Worker ] 790*9e94795aSAndroid Build Coastguard Worker 791*9e94795aSAndroid Build Coastguard Worker def _error(self, message): 792*9e94795aSAndroid Build Coastguard Worker report_error(message) 793*9e94795aSAndroid Build Coastguard Worker self._had_error = True 794*9e94795aSAndroid Build Coastguard Worker 795*9e94795aSAndroid Build Coastguard Worker 796*9e94795aSAndroid Build Coastguard Workerdef report_error(message): 797*9e94795aSAndroid Build Coastguard Worker sys.stderr.write(f"error: {message}\n") 798*9e94795aSAndroid Build Coastguard Worker 799*9e94795aSAndroid Build Coastguard Worker 800*9e94795aSAndroid Build Coastguard Workerdef main(argv): 801*9e94795aSAndroid Build Coastguard Worker try: 802*9e94795aSAndroid Build Coastguard Worker options = Options() 803*9e94795aSAndroid Build Coastguard Worker runner = Runner(options) 804*9e94795aSAndroid Build Coastguard Worker runner.Run() 805*9e94795aSAndroid Build Coastguard Worker except FatalError: 806*9e94795aSAndroid Build Coastguard Worker sys.stderr.write(f"FAILED\n") 807*9e94795aSAndroid Build Coastguard Worker sys.exit(1) 808*9e94795aSAndroid Build Coastguard Worker 809*9e94795aSAndroid Build Coastguard Worker 810*9e94795aSAndroid Build Coastguard Workerif __name__ == "__main__": 811*9e94795aSAndroid Build Coastguard Worker main(sys.argv) 812