Skip to content

Commit 541d520

Browse files
Fix CI analytics date range filtering (#10795)
## Summary - make Average Concurrent Runners follow the selected statistics date range - make Queue Wait Time Percentiles follow the selected statistics date range - add regression coverage for the range-aware chart wiring ## Testing - python3 -m unittest extras.ci.analytics.tests.test_ci_analytics
1 parent c01388b commit 541d520

2 files changed

Lines changed: 79 additions & 11 deletions

File tree

extras/ci/analytics/ci_visualization.py

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,20 @@ def generate_statistics(data, config, output_dir):
973973
"fill": True,
974974
"tension": 0.1,
975975
})
976+
parallel_datasets_js = ",".join(
977+
(
978+
"{"
979+
f"label:{json.dumps(ds['label'])}, "
980+
f"data:sliceData({json.dumps(ds['data'])},30), "
981+
f"_allData:{json.dumps(ds['data'])}, "
982+
f"borderColor:{json.dumps(ds['borderColor'])}, "
983+
f"backgroundColor:{json.dumps(ds['backgroundColor'])}, "
984+
f"fill:{json.dumps(ds['fill'])}, "
985+
f"tension:{json.dumps(ds['tension'])}"
986+
"}"
987+
)
988+
for ds in parallel_datasets
989+
)
976990

977991
# Build and test wait times per day
978992
build_wait_by_date = data.get("build_wait_by_date", {})
@@ -1143,6 +1157,10 @@ def generate_statistics(data, config, output_dir):
11431157
const allMqCancelled = {json.dumps(mq_cancelled_per_day)};
11441158
const allMqFailRate = {json.dumps(mq_fail_rate_per_day)};
11451159
const allMqTat = {json.dumps(mq_avg_tat_per_day)};
1160+
const allQueueWaitAvg = {json.dumps(cap_avg_queue)};
1161+
const allQueueWaitP50 = {json.dumps(cap_p50_queue)};
1162+
const allQueueWaitP90 = {json.dumps(cap_p90_queue)};
1163+
const allQueueWaitP95 = {json.dumps(cap_p95_queue)};
11461164
const hasMqData = {json.dumps(has_mq_data)};
11471165
11481166
let charts = [];
@@ -1300,25 +1318,25 @@ def generate_statistics(data, config, output_dir):
13001318
}});
13011319
13021320
// Parallelization rate
1303-
new Chart(document.getElementById('parallelRate_canvas').getContext('2d'), {{
1304-
type: 'line',
1321+
makeChart('parallelRate_canvas', 'line', {{
13051322
data: {{
1306-
labels: {json.dumps(dates)},
1307-
datasets: {json.dumps(parallel_datasets)}
1323+
labels: sliceData(allLabels, 30),
1324+
datasets: [
1325+
{parallel_datasets_js}
1326+
]
13081327
}},
13091328
options: {{responsive:true, scales:{{y:{{stacked:true,min:0,title:{{display:true,text:'Avg Concurrent Runners'}}}}}}}}
13101329
}});
13111330
13121331
// Queue wait time percentiles
1313-
new Chart(document.getElementById('queueWait_canvas').getContext('2d'), {{
1314-
type: 'line',
1332+
makeChart('queueWait_canvas', 'line', {{
13151333
data: {{
1316-
labels: {json.dumps(dates)},
1334+
labels: sliceData(allLabels, 30),
13171335
datasets: [
1318-
{{label:'Avg', data:{json.dumps(cap_avg_queue)}, borderColor:'#0d6efd', fill:false, tension:0.1}},
1319-
{{label:'p50', data:{json.dumps(cap_p50_queue)}, borderColor:'#28a745', borderDash:[5,5], fill:false, tension:0.1}},
1320-
{{label:'p90', data:{json.dumps(cap_p90_queue)}, borderColor:'#ffc107', borderDash:[5,5], fill:false, tension:0.1}},
1321-
{{label:'p95', data:{json.dumps(cap_p95_queue)}, borderColor:'#dc3545', borderDash:[5,5], fill:false, tension:0.1}},
1336+
{{label:'Avg', data:sliceData(allQueueWaitAvg,30), _allData:allQueueWaitAvg, borderColor:'#0d6efd', fill:false, tension:0.1}},
1337+
{{label:'p50', data:sliceData(allQueueWaitP50,30), _allData:allQueueWaitP50, borderColor:'#28a745', borderDash:[5,5], fill:false, tension:0.1}},
1338+
{{label:'p90', data:sliceData(allQueueWaitP90,30), _allData:allQueueWaitP90, borderColor:'#ffc107', borderDash:[5,5], fill:false, tension:0.1}},
1339+
{{label:'p95', data:sliceData(allQueueWaitP95,30), _allData:allQueueWaitP95, borderColor:'#dc3545', borderDash:[5,5], fill:false, tension:0.1}},
13221340
]
13231341
}},
13241342
options: {{responsive:true, scales:{{y:{{title:{{display:true,text:'Minutes'}}}}}}}}

extras/ci/analytics/tests/test_ci_analytics.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,56 @@ def test_statistics_parallel_chart_includes_runner_name_prefix_groups(self):
270270

271271
self.assertIn("Windows Build (GCP)", html)
272272

273+
def test_statistics_range_filter_wires_parallel_and_queue_percentile_charts(self):
274+
"""Range selector must update Average Concurrent Runners and queue percentiles."""
275+
config = {
276+
"label_groups": [],
277+
"runner_name_prefixes": [
278+
{"prefix": "linux-runner-", "name": "Linux GPU (GCP)", "self_hosted": True},
279+
],
280+
"non_production_periods": {"runners": {}},
281+
}
282+
283+
base = datetime.now(timezone.utc).replace(hour=12, minute=0, second=0, microsecond=0)
284+
jobs = []
285+
for offset in (3, 2):
286+
created = (base - ci_health.timedelta(days=offset)).strftime("%Y-%m-%dT%H:%M:%SZ")
287+
completed = (
288+
base - ci_health.timedelta(days=offset) + ci_health.timedelta(minutes=30)
289+
).strftime("%Y-%m-%dT%H:%M:%SZ")
290+
jobs.append(
291+
{
292+
"name": "build-linux-debug",
293+
"workflow_name": "CI",
294+
"run_id": offset,
295+
"run_created_at": created,
296+
"created_at": created,
297+
"started_at": created,
298+
"completed_at": completed,
299+
"conclusion": "success",
300+
"event": "push",
301+
"head_branch": "main",
302+
"labels": [],
303+
"runner_name": "linux-runner-1",
304+
"duration_seconds": 1800,
305+
"queued_seconds": offset * 60,
306+
"html_url": "",
307+
}
308+
)
309+
310+
data = ci_visualization.process_jobs(jobs, config)
311+
312+
with tempfile.TemporaryDirectory() as tmp:
313+
ci_visualization.generate_statistics(data, config, tmp)
314+
with open(os.path.join(tmp, "statistics.html"), encoding="utf-8") as f:
315+
html = f.read()
316+
317+
self.assertIn("makeChart('parallelRate_canvas', 'line'", html)
318+
self.assertIn("_allData", html)
319+
self.assertIn("const allQueueWaitAvg =", html)
320+
self.assertIn("const allQueueWaitP95 =", html)
321+
self.assertIn("makeChart('queueWait_canvas', 'line'", html)
322+
273323

274324
class TestPRsMergedChart(unittest.TestCase):
275325
def test_statistics_includes_prs_merged_chart_when_data_present(self):

0 commit comments

Comments
 (0)