11#!/usr/bin/env python3
22"""
3- compare_metrics.py [--format {table|sparkline|html}]
3+ compare_metrics.py [--format {table|sparkline|html}] [--branch NAME]
44
55Fetches bench_history.csv and size_history.csv from the metrics branch,
6- groups by benchmark/metric name, and displays evolution over time.
6+ groups by benchmark/metric name, filters by branch, and displays evolution over time.
77
88Output formats:
99 table - Simple ASCII table (default)
1010 sparkline - Compact sparkline visualization
1111 html - Interactive HTML report
12+
13+ Options:
14+ --branch NAME - Filter by git branch name (default: current branch)
1215"""
1316
1417import sys
@@ -43,6 +46,20 @@ def fetch_csv_from_branch(filename: str, branch: str = "metrics") -> List[Dict]:
4346 return []
4447
4548
49+ def get_current_branch () -> str :
50+ """Get the current git branch name."""
51+ try :
52+ result = subprocess .run (
53+ ["git" , "rev-parse" , "--abbrev-ref" , "HEAD" ],
54+ capture_output = True ,
55+ text = True ,
56+ check = True ,
57+ )
58+ return result .stdout .strip ()
59+ except subprocess .CalledProcessError :
60+ return "main"
61+
62+
4663def parse_timestamp (ts : str ) -> datetime :
4764 """Parse ISO timestamp."""
4865 try :
@@ -51,12 +68,14 @@ def parse_timestamp(ts: str) -> datetime:
5168 return datetime .min
5269
5370
54- def group_metrics (bench_rows : List [Dict ], size_rows : List [Dict ]) -> Dict [str , List [Dict ]]:
55- """Group metrics by name (benchmark_name or metric_name) with timestamps ."""
71+ def group_metrics (bench_rows : List [Dict ], size_rows : List [Dict ], branch : str = None ) -> Dict [str , List [Dict ]]:
72+ """Group metrics by name, filtered by branch and sorted by timestamp ."""
5673 groups = defaultdict (list )
5774
5875 # Group benchmarks
5976 for row in bench_rows :
77+ if branch and row .get ("branch" , "" ) != branch :
78+ continue
6079 name = row .get ("benchmark_name" , "" ).strip ()
6180 if name :
6281 groups [f"bench/{ name } " ].append ({
@@ -70,6 +89,8 @@ def group_metrics(bench_rows: List[Dict], size_rows: List[Dict]) -> Dict[str, Li
7089
7190 # Group file sizes
7291 for row in size_rows :
92+ if branch and row .get ("branch" , "" ) != branch :
93+ continue
7394 name = row .get ("metric_name" , "" ).strip ()
7495 if name :
7596 groups [f"size/{ name } " ].append ({
@@ -134,9 +155,11 @@ def sparkline(values: List[float], width: int = 10) -> str:
134155 return sparkline_str
135156
136157
137- def display_table (groups : Dict [str , List [Dict ]]) -> None :
158+ def display_table (groups : Dict [str , List [Dict ]], branch : str = None ) -> None :
138159 """Display metrics as ASCII table."""
139160 print ("\n " + "=" * 120 )
161+ if branch :
162+ print (f"Metrics for branch: { branch } " )
140163 print (f"{ 'Metric' :<40} { 'Latest' :<20} { 'Prev' :<20} { 'Change' :<15} { 'Trend' :<20} " )
141164 print ("=" * 120 )
142165
@@ -166,9 +189,11 @@ def display_table(groups: Dict[str, List[Dict]]) -> None:
166189 print ("=" * 120 )
167190
168191
169- def display_sparkline (groups : Dict [str , List [Dict ]]) -> None :
192+ def display_sparkline (groups : Dict [str , List [Dict ]], branch : str = None ) -> None :
170193 """Display metrics with sparklines for compact view."""
171194 print ("\n " + "─" * 100 )
195+ if branch :
196+ print (f"Metrics for branch: { branch } " )
172197 print (f"{ 'Metric' :<45} { 'Sparkline' :<40} { 'Latest' :<15} " )
173198 print ("─" * 100 )
174199
@@ -186,7 +211,7 @@ def display_sparkline(groups: Dict[str, List[Dict]]) -> None:
186211 print ("─" * 100 )
187212
188213
189- def display_html (groups : Dict [str , List [Dict ]], output_path : str = "metrics_report.html" ) -> None :
214+ def display_html (groups : Dict [str , List [Dict ]], output_path : str = "metrics_report.html" , branch : str = None ) -> None :
190215 """Generate an interactive HTML report (requires plotly)."""
191216 try :
192217 import plotly .graph_objects as go
@@ -226,8 +251,12 @@ def display_html(groups: Dict[str, List[Dict]], output_path: str = "metrics_repo
226251 col = col ,
227252 )
228253
254+ title = "herkos Metrics Evolution"
255+ if branch :
256+ title += f" (branch: { branch } )"
257+
229258 fig .update_layout (
230- title_text = "herkos Metrics Evolution" ,
259+ title_text = title ,
231260 height = 300 * ((num_metrics + 1 ) // 2 ),
232261 showlegend = False ,
233262 )
@@ -251,9 +280,17 @@ def main() -> int:
251280 default = "metrics_report.html" ,
252281 help = "Output file for HTML format (default: metrics_report.html)" ,
253282 )
283+ parser .add_argument (
284+ "--branch" ,
285+ default = None ,
286+ help = "Filter metrics by branch name (default: current git branch)" ,
287+ )
254288
255289 args = parser .parse_args ()
256290
291+ # Use current branch as default if not specified
292+ target_branch = args .branch or get_current_branch ()
293+
257294 print ("Fetching metrics from 'metrics' branch..." )
258295 bench_rows = fetch_csv_from_branch ("bench_history.csv" )
259296 size_rows = fetch_csv_from_branch ("size_history.csv" )
@@ -263,19 +300,20 @@ def main() -> int:
263300 return 1
264301
265302 print (f" Loaded { len (bench_rows )} benchmark entries, { len (size_rows )} size entries" )
303+ print (f" Filtering for branch: { target_branch } " )
266304
267- groups = group_metrics (bench_rows , size_rows )
305+ groups = group_metrics (bench_rows , size_rows , target_branch )
268306
269307 if not groups :
270- print ("No metrics found." , file = sys .stderr )
308+ print (f "No metrics found for branch ' { target_branch } ' ." , file = sys .stderr )
271309 return 1
272310
273311 if args .format == "table" :
274- display_table (groups )
312+ display_table (groups , target_branch )
275313 elif args .format == "sparkline" :
276- display_sparkline (groups )
314+ display_sparkline (groups , target_branch )
277315 elif args .format == "html" :
278- display_html (groups , args .output )
316+ display_html (groups , args .output , target_branch )
279317
280318 return 0
281319
0 commit comments