20
20
import random
21
21
import re
22
22
import shutil
23
- import statistics
24
23
import sys
25
24
import uuid
26
25
27
26
import click
27
+ import numpy
28
28
import pystache
29
29
import yaml
30
30
from google .cloud import storage
31
31
32
32
from fireci import ci_command
33
33
from fireci .dir_utils import chdir
34
+ from fireci import prow_utils
35
+ from fireci import uploader
34
36
35
37
_logger = logging .getLogger ('fireci.macrobenchmark' )
36
38
@@ -55,9 +57,7 @@ async def _launch_macrobenchmark_test():
55
57
runners = [MacrobenchmarkTest (k , v , artifact_versions ) for k , v in config .items ()]
56
58
results = await asyncio .gather (* [x .run () for x in runners ], return_exceptions = True )
57
59
58
- if any (map (lambda x : isinstance (x , Exception ), results )):
59
- _logger .error (f'Exceptions: { [x for x in results if (isinstance (x , Exception ))]} ' )
60
- raise click .ClickException ('Macrobenchmark test failed with above errors.' )
60
+ await _post_processing (results )
61
61
62
62
_logger .info ('Macrobenchmark test finished.' )
63
63
@@ -104,6 +104,23 @@ async def _copy_google_services():
104
104
shutil .copyfile (src , dst )
105
105
106
106
107
+ async def _post_processing (results ):
108
+ # Upload successful measurements to the metric service
109
+ measurements = []
110
+ for result in results :
111
+ if not isinstance (result , Exception ):
112
+ measurements .extend (result )
113
+
114
+ metrics_service_url = os .getenv ('METRICS_SERVICE_URL' )
115
+ access_token = prow_utils .gcloud_identity_token ()
116
+ uploader .post_report (measurements , metrics_service_url , access_token , metric = 'macrobenchmark' )
117
+
118
+ # Raise exceptions for failed measurements
119
+ if any (map (lambda x : isinstance (x , Exception ), results )):
120
+ _logger .error (f'Exceptions: { [x for x in results if isinstance (x , Exception )]} ' )
121
+ raise click .ClickException ('Macrobenchmark test failed with above errors.' )
122
+
123
+
107
124
class MacrobenchmarkTest :
108
125
"""Builds the test based on configurations and runs the test on FTL."""
109
126
def __init__ (
@@ -127,7 +144,7 @@ async def run(self):
127
144
await self ._create_benchmark_projects ()
128
145
await self ._assemble_benchmark_apks ()
129
146
await self ._execute_benchmark_tests ()
130
- await self ._upload_benchmark_results ()
147
+ return await self ._aggregate_benchmark_results ()
131
148
132
149
async def _create_benchmark_projects (self ):
133
150
app_name = self .test_app_config ['name' ]
@@ -205,7 +222,7 @@ async def _prepare_mustache_context(self):
205
222
206
223
return mustache_context
207
224
208
- async def _upload_benchmark_results (self ):
225
+ async def _aggregate_benchmark_results (self ):
209
226
results = []
210
227
blobs = self .gcs_client .list_blobs (self .test_results_bucket , prefix = self .test_results_dir )
211
228
files = [x for x in blobs if re .search (r'artifacts/[^/]*\.json' , x .name )]
@@ -222,14 +239,13 @@ async def _upload_benchmark_results(self):
222
239
'name' : f'{ clazz } .{ method } ' ,
223
240
'min' : min (runs ),
224
241
'max' : max (runs ),
225
- 'mean ' : statistics . mean (runs ),
226
- 'median ' : statistics . median (runs ),
227
- 'stdev ' : statistics . stdev (runs ),
242
+ 'p50 ' : numpy . percentile (runs , 50 ),
243
+ 'p90 ' : numpy . percentile (runs , 90 ),
244
+ 'p99 ' : numpy . percentile (runs , 99 ),
228
245
'unit' : 'ms' ,
229
246
})
230
247
self .logger .info (f'Benchmark results: { results } ' )
231
-
232
- # TODO(yifany): upload to metric service once it is ready
248
+ return results
233
249
234
250
async def _exec_subprocess (self , executable , args ):
235
251
command = " " .join ([executable , * args ])
0 commit comments