18
18
import logging
19
19
import os
20
20
import random
21
+ import re
21
22
import shutil
23
+ import statistics
22
24
import sys
25
+ import uuid
23
26
24
27
import click
25
28
import pystache
26
29
import yaml
30
+ from google .cloud import storage
27
31
28
32
from fireci import ci_command
29
33
from fireci .dir_utils import chdir
@@ -114,14 +118,18 @@ def __init__(
114
118
self .artifact_versions = artifact_versions
115
119
self .logger = MacrobenchmarkLoggerAdapter (logger , sdk_name )
116
120
self .test_app_dir = os .path .join ('test-apps' , test_app_config ['name' ])
121
+ self .test_results_bucket = 'fireescape-benchmark-results'
122
+ self .test_results_dir = str (uuid .uuid4 ())
123
+ self .gcs_client = storage .Client ()
117
124
118
125
async def run (self ):
119
- """Starts the workflow of src creation, apks assembling, and FTL testing in order."""
120
- await self ._create_test_src ()
121
- await self ._assemble_apks ()
122
- await self ._upload_apks_to_ftl ()
126
+ """Starts the workflow of src creation, apks assembly, FTL testing and results upload."""
127
+ await self ._create_benchmark_projects ()
128
+ await self ._assemble_benchmark_apks ()
129
+ await self ._execute_benchmark_tests ()
130
+ await self ._upload_benchmark_results ()
123
131
124
- async def _create_test_src (self ):
132
+ async def _create_benchmark_projects (self ):
125
133
app_name = self .test_app_config ['name' ]
126
134
app_id = self .test_app_config ['application-id' ]
127
135
self .logger .info (f'Creating test app "{ app_name } " with application-id "{ app_id } "...' )
@@ -138,12 +146,12 @@ async def _create_test_src(self):
138
146
with open (original_name , 'w' ) as file :
139
147
file .write (result )
140
148
141
- async def _assemble_apks (self ):
149
+ async def _assemble_benchmark_apks (self ):
142
150
executable = './gradlew'
143
151
args = ['assemble' , 'assembleAndroidTest' , '--project-dir' , self .test_app_dir ]
144
152
await self ._exec_subprocess (executable , args )
145
153
146
- async def _upload_apks_to_ftl (self ):
154
+ async def _execute_benchmark_tests (self ):
147
155
app_apk_path = glob .glob (f'{ self .test_app_dir } /app/**/*.apk' , recursive = True )[0 ]
148
156
test_apk_path = glob .glob (f'{ self .test_app_dir } /benchmark/**/*.apk' , recursive = True )[0 ]
149
157
@@ -162,7 +170,8 @@ async def _upload_apks_to_ftl(self):
162
170
args += ['--test' , test_apk_path ]
163
171
args += ['--device' , 'model=flame,version=30,locale=en,orientation=portrait' ]
164
172
args += ['--directories-to-pull' , '/sdcard/Download' ]
165
- args += ['--results-bucket' , 'gs://fireescape-macrobenchmark' ]
173
+ args += ['--results-bucket' , f'gs://{ self .test_results_bucket } ' ]
174
+ args += ['--results-dir' , self .test_results_dir ]
166
175
args += ['--environment-variables' , ',' .join (ftl_environment_variables )]
167
176
args += ['--timeout' , '30m' ]
168
177
args += ['--project' , 'fireescape-c4819' ]
@@ -196,6 +205,32 @@ async def _prepare_mustache_context(self):
196
205
197
206
return mustache_context
198
207
208
+ async def _upload_benchmark_results (self ):
209
+ results = []
210
+ blobs = self .gcs_client .list_blobs (self .test_results_bucket , prefix = self .test_results_dir )
211
+ files = [x for x in blobs if re .search (r'artifacts/[^/]*\.json' , x .name )]
212
+ for file in files :
213
+ device = re .search (r'([^/]*)/artifacts/' , file .name ).group (1 )
214
+ benchmarks = json .loads (file .download_as_bytes ())['benchmarks' ]
215
+ for benchmark in benchmarks :
216
+ method = benchmark ['name' ]
217
+ clazz = benchmark ['className' ].split ('.' )[- 1 ]
218
+ runs = benchmark ['metrics' ]['startupMs' ]['runs' ]
219
+ results .append ({
220
+ 'sdk' : self .sdk_name ,
221
+ 'device' : device ,
222
+ 'name' : f'{ clazz } .{ method } ' ,
223
+ 'min' : min (runs ),
224
+ 'max' : max (runs ),
225
+ 'mean' : statistics .mean (runs ),
226
+ 'median' : statistics .median (runs ),
227
+ 'stdev' : statistics .stdev (runs ),
228
+ 'unit' : 'ms' ,
229
+ })
230
+ self .logger .info (f'Benchmark results: { results } ' )
231
+
232
+ # TODO(yifany): upload to metric service once it is ready
233
+
199
234
async def _exec_subprocess (self , executable , args ):
200
235
command = " " .join ([executable , * args ])
201
236
self .logger .info (f'Executing command: "{ command } "...' )
0 commit comments