@@ -39,23 +39,14 @@ def log_messages(log_file):
3939 yield line
4040
4141
42- def collect_chunks (log_files ):
43- """Returns the chunk texts keyed by index, plus the expected total."""
44- chunks = {}
45- total = None
46- for log_file in log_files :
47- for message in log_messages (log_file ):
48- match = CHUNK_RE .search (message )
49- if not match :
50- continue
51- index , chunk_total , text = int (match .group (1 )), int (match .group (2 )), match .group (3 )
52- if total is not None and chunk_total != total :
53- sys .exit (
54- f"Found chunks from more than one benchmark run "
55- f"(totals { total } and { chunk_total } ) in { log_file } "
56- )
57- total = chunk_total
58- chunks [index ] = text
42+ def collect_chunks (log_file ):
43+ """Returns one log's chunk texts keyed by index, plus the expected total."""
44+ chunks , total = {}, None
45+ for message in log_messages (log_file ):
46+ match = CHUNK_RE .search (message )
47+ if match :
48+ index , total = int (match .group (1 )), int (match .group (2 ))
49+ chunks [index ] = match .group (3 )
5950 return chunks , total
6051
6152
@@ -86,25 +77,30 @@ def format_summary(data):
8677 "" ,
8778 ]
8879
89- lines += ["| Benchmark | Metric | min | median | max | CoV | iterations |" , "|---|---|--:|--:|--:|--:|--:|" ]
80+ table = [
81+ "| Benchmark | Metric | min | median | max | CoV | iterations |" ,
82+ "|---|---|--:|--:|--:|--:|--:|" ,
83+ ]
84+ details = []
9085 for benchmark in data ["benchmarks" ]:
86+ name = f"{ benchmark ['className' ].rsplit ('.' , 1 )[- 1 ]} .{ benchmark ['name' ]} "
9187 for metric , result in sorted (benchmark ["metrics" ].items ()):
92- lines .append (
93- f"| `{ benchmark ['className' ].rsplit ('.' , 1 )[- 1 ]} .{ benchmark ['name' ]} ` "
94- f"| { metric } "
95- f"| { result ['minimum' ]:.1f} "
96- f"| { result ['median' ]:.1f} "
97- f"| { result ['maximum' ]:.1f} "
98- f"| { result ['coefficientOfVariation' ] * 100 :.1f} % "
99- f"| { len (result ['runs' ])} |"
88+ table .append (
89+ f"| `{ name } ` | { metric } "
90+ f"| { result ['minimum' ]:.1f} | { result ['median' ]:.1f} | { result ['maximum' ]:.1f} "
91+ f"| { result ['coefficientOfVariation' ] * 100 :.1f} % | { len (result ['runs' ])} |"
10092 )
101-
102- for benchmark in data ["benchmarks" ]:
103- for metric , result in sorted (benchmark ["metrics" ].items ()):
10493 runs = ", " .join (f"{ run :.1f} " for run in result ["runs" ])
105- lines += ["" , f"<details><summary>{ metric } per iteration</summary>" , "" , runs , "" , "</details>" ]
94+ details += [
95+ "" ,
96+ f"<details><summary>{ metric } per iteration</summary>" ,
97+ "" ,
98+ runs ,
99+ "" ,
100+ "</details>" ,
101+ ]
106102
107- return "\n " .join (lines )
103+ return "\n " .join (lines + table + details )
108104
109105
110106def main ():
@@ -117,12 +113,22 @@ def main():
117113 if not log_files :
118114 sys .exit (f"No *.log files under { args .artifacts_dir } " )
119115
120- chunks , total = collect_chunks (log_files )
121- if total is None :
116+ # Keyed by file so chunks from two devices can never be merged into one bogus document.
117+ per_log = {log : collect_chunks (log ) for log in log_files }
118+ with_chunks = {log : result for log , (result , total ) in per_log .items () if total }
119+ if not with_chunks :
122120 sys .exit (
123121 "No SentryBenchmarkData chunks in the device log. The benchmark most likely "
124122 "failed before reporting — check junit.xml and the log for Macrobenchmark errors."
125123 )
124+ if len (with_chunks ) > 1 :
125+ sys .exit (
126+ "Chunks from more than one run: "
127+ + ", " .join (str (log ) for log in with_chunks )
128+ + ". This parser reports a single device."
129+ )
130+ log_file = next (iter (with_chunks ))
131+ chunks , total = per_log [log_file ]
126132
127133 data = json .loads (reassemble (chunks , total ))
128134
0 commit comments