Skip to content

Commit e5d1286

Browse files
committed
Merge remote-tracking branch 'intel/sycl' into HEAD
2 parents c1477b8 + ea4d68c commit e5d1286

File tree

3 files changed

+192
-9
lines changed

3 files changed

+192
-9
lines changed

devops/scripts/benchmarks/CONTRIB.md

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,104 @@ The suite is structured around three main components: Suites, Benchmarks, and Re
6767
* `display_name`: Optional user-friendly name for the benchmark (string). Defaults to `name()`.
6868
* `explicit_group`: Optional explicit group name for results (string). Used to group results in visualizations.
6969

70+
## Dashboard and Visualization
71+
72+
The benchmark suite generates an interactive HTML dashboard that visualizes `Result` objects and their metadata.
73+
74+
### Data Flow from Results to Dashboard
75+
76+
1. **Collection Phase:**
77+
* Benchmarks generate `Result` objects containing performance measurements.
78+
* The framework combines these with `BenchmarkMetadata` from benchmarks and suites. The metadata
79+
is used for defining charts.
80+
* All data is packaged into a `BenchmarkOutput` object containing runs, metadata, and tags for serialization.
81+
82+
2. **Serialization:**
83+
* For local viewing (`--output-html local`): Data is written as JavaScript variables in `data.js`.
84+
These are directly loaded in the HTML dashboard.
85+
* For remote deployment (`--output-html remote`): Data is written as JSON in `data.json`.
86+
The `config.js` file contains the URL where the json file is hosted.
87+
* Historical runs may be separated into archive files for better dashboard load times.
88+
89+
3. **Dashboard Rendering:**
90+
* JavaScript processes the data to create three chart types:
91+
* **Historical Results**: Time-series charts showing performance trends over multiple runs. One chart for each unique benchmark scenario.
92+
* **Historical Layer Comparisons**: Time-series charts for grouped results. Benchmark scenarios that can be directly compared are grouped either by using `explicit_group()` or matching the beginning of their labels with predefined groups.
93+
* **Comparisons**: Bar charts comparing selected runs side-by-side. Again, based on the `explicit_group()` or labels.
94+
95+
### Chart Types and Result Mapping
96+
97+
**Historical Results (Time-series):**
98+
* One chart per unique `result.label`.
99+
* X-axis: `BenchmarkRun.date` (time).
100+
* Y-axis: `result.value` with `result.unit`.
101+
* Multiple lines for different `BenchmarkRun.name` entries.
102+
* Points include `result.stddev`, `result.git_hash`, and environment info in tooltips.
103+
104+
**Historical Layer Comparisons:**
105+
* Groups related results using `benchmark.explicit_group()` or `result.label` prefixes.
106+
* Useful for comparing different implementations/configurations of the same benchmark.
107+
* Same time-series format but with grouped data.
108+
109+
**Comparisons (Bar charts):**
110+
* Compares selected runs side-by-side.
111+
* X-axis: `BenchmarkRun.name`.
112+
* Y-axis: `result.value` with `result.unit`.
113+
* One bar per selected run.
114+
115+
### Dashboard Features Controlled by Results/Metadata
116+
117+
**Visual Properties:**
118+
* **Chart Title**: `metadata.display_name` or `result.label`.
119+
* **Y-axis Range**: `metadata.range_min` and `range_max` (when custom ranges enabled).
120+
* **Direction Indicator**: `result.lower_is_better` (shows "Lower/Higher is better").
121+
* **Grouping**: `benchmark.explicit_group()` groups related results together.
122+
123+
**Filtering and Organization:**
124+
* **Suite Filters**: Filter by `result.suite`.
125+
* **Tag Filters**: Filter by `metadata.tags`.
126+
* **Regex Search**: Search by `result.label` patterns, `metadata.display_name` patterns are not searchable.
127+
* **Stability**: Hide/show based on `metadata.unstable`.
128+
129+
**Information Display:**
130+
* **Description**: `metadata.description` appears prominently above charts.
131+
* **Notes**: `metadata.notes` provides additional context (toggleable).
132+
* **Tags**: `metadata.tags` displayed as colored badges with descriptions.
133+
* **Command Details**: Shows `result.command` and `result.env` in expandable sections.
134+
* **Git Information**: `result.git_url` and `result.git_hash` for benchmark source tracking.
135+
136+
### Dashboard Interaction
137+
138+
**Run Selection:**
139+
* Users select which `BenchmarkRun.name` entries to compare.
140+
* Default selection uses `BenchmarkOutput.default_compare_names`.
141+
* Changes affect all chart types simultaneously.
142+
143+
**URL State Preservation:**
144+
* All filters, selections, and options are preserved in URL parameters.
145+
* Enables sharing specific dashboard views via URL address copy.
146+
147+
### Best Practices for Dashboard-Friendly Results
148+
149+
**Naming:**
150+
* Use unique `result.label` names that will be most descriptive.
151+
* Consider `metadata.display_name` for prettier chart titles.
152+
* Ensure `benchmark.name()` is unique across all suites.
153+
154+
**Grouping:**
155+
* Use `benchmark.explicit_group()` to group related measurements.
156+
* Ensure grouped results have the same `result.unit`.
157+
* Group metadata keys in `Suite.additional_metadata()` should match group prefixes.
158+
159+
**Metadata:**
160+
* Provide `metadata.description` for user understanding.
161+
* Use `metadata.notes` for implementation details or caveats.
162+
* Tag with relevant `metadata.tags` for filtering.
163+
* Set `metadata.range_min`/`range_max` for consistent comparisons when needed.
164+
165+
**Stability:**
166+
* Mark unstable benchmarks with `metadata.unstable` to hide them by default.
167+
70168
## Adding New Benchmarks
71169

72170
1. **Create Benchmark Class:** Implement a new class inheriting from `benches.base.Benchmark`. Implement required methods (`setup`, `run`, `teardown`, `name`) and optional ones (`description`, `get_tags`, etc.) as needed.
@@ -84,6 +182,14 @@ The suite is structured around three main components: Suites, Benchmarks, and Re
84182
* **Use unique names:** Ensure `benchmark.name()` and `result.label` are descriptive and unique.
85183
* **Group related results:** Use `benchmark.explicit_group()` consistently for results you want to compare directly in outputs. Ensure units match within a group. If defining group-level metadata in the Suite, ensure the chosen explicit_group name starts with the corresponding key defined in additional_metadata.
86184
* **Test locally:** Before submitting changes, test with relevant drivers/backends (e.g., using `--compute-runtime --build-igc` for L0). Check the visualization locally if possible (--output-markdown --output-html, then open the generated files).
185+
* **Test dashboard visualization:** When adding new benchmarks, always generate and review the HTML dashboard to ensure:
186+
* Chart titles and labels are clear and readable.
187+
* Results are grouped logically using `explicit_group()`.
188+
* Metadata (description, notes, tags) displays correctly.
189+
* Y-axis ranges are appropriate (consider setting `range_min`/`range_max` if needed).
190+
* Filtering by suite and tags works as expected.
191+
* Time-series trends make sense for historical data.
192+
* **Tip**: Use `--dry-run --output-html local` to regenerate the dashboard without re-running benchmarks. This uses existing historical data and is useful for testing metadata changes, new groupings, or dashboard improvements.
87193

88194
## Utilities
89195

devops/scripts/benchmarks/html/scripts.js

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,10 @@ function createChart(data, containerId, type) {
123123
}
124124

125125
const ctx = document.getElementById(containerId).getContext('2d');
126+
126127
const options = {
127128
responsive: true,
129+
maintainAspectRatio: false,
128130
plugins: {
129131
title: {
130132
display: true,
@@ -157,6 +159,13 @@ function createChart(data, containerId, type) {
157159
}
158160
}
159161
},
162+
legend: {
163+
position: 'top',
164+
labels: {
165+
boxWidth: 12,
166+
padding: 10,
167+
}
168+
},
160169
annotation: type === 'time' ? {
161170
annotations: {}
162171
} : undefined
@@ -227,6 +236,32 @@ function createChart(data, containerId, type) {
227236
const chart = new Chart(ctx, chartConfig);
228237
chartInstances.set(containerId, chart);
229238

239+
// Set explicit canvas size after chart creation to ensure proper sizing
240+
const canvas = document.getElementById(containerId);
241+
const rect = canvas.getBoundingClientRect();
242+
const dpr = window.devicePixelRatio || 1;
243+
244+
// Calculate dynamic height based on number of legend items
245+
const legendItemCount = type === 'time' ?
246+
Object.values(data.runs).length :
247+
data.datasets.length;
248+
249+
// Base chart height + legend height (25px per line + padding)
250+
const baseChartHeight = 350;
251+
const legendHeight = Math.max(legendItemCount * 25, 50); // minimum 50px for legend
252+
const totalHeight = baseChartHeight + legendHeight;
253+
254+
// Set canvas dimensions for crisp rendering
255+
canvas.width = rect.width * dpr;
256+
canvas.height = totalHeight * dpr;
257+
258+
// Scale the context to ensure correct drawing operations
259+
const context = canvas.getContext('2d');
260+
context.scale(dpr, dpr);
261+
262+
// Force chart to use these exact dimensions
263+
chart.resize(rect.width, totalHeight);
264+
230265
// Add annotation interaction handlers for time-series charts
231266
if (type === 'time') {
232267
ChartAnnotations.setupAnnotationListeners(chart, ctx, options);
@@ -306,6 +341,10 @@ function createChartContainer(data, canvasId, type) {
306341
container.setAttribute('data-label', data.label);
307342
container.setAttribute('data-suite', data.suite);
308343

344+
// Create header section for metadata
345+
const headerSection = document.createElement('div');
346+
headerSection.className = 'chart-header';
347+
309348
// Check if this benchmark is marked as unstable
310349
const metadata = metadataForLabel(data.label, type);
311350
if (metadata && metadata.unstable) {
@@ -316,15 +355,17 @@ function createChartContainer(data, canvasId, type) {
316355
unstableWarning.className = 'benchmark-unstable';
317356
unstableWarning.textContent = metadata.unstable;
318357
unstableWarning.style.display = isUnstableEnabled() ? 'block' : 'none';
319-
container.appendChild(unstableWarning);
358+
unstableWarning.style.marginBottom = '5px';
359+
headerSection.appendChild(unstableWarning);
320360
}
321361

322-
// Add description if present in metadata (moved outside of details)
362+
// Add description if present in metadata
323363
if (metadata && metadata.description) {
324364
const descElement = document.createElement('div');
325365
descElement.className = 'benchmark-description';
326366
descElement.textContent = metadata.description;
327-
container.appendChild(descElement);
367+
descElement.style.marginBottom = '5px';
368+
headerSection.appendChild(descElement);
328369
}
329370

330371
// Add notes if present
@@ -333,7 +374,7 @@ function createChartContainer(data, canvasId, type) {
333374
noteElement.className = 'benchmark-note';
334375
noteElement.textContent = metadata.notes;
335376
noteElement.style.display = isNotesEnabled() ? 'block' : 'none';
336-
container.appendChild(noteElement);
377+
headerSection.appendChild(noteElement);
337378
}
338379

339380
// Add tags if present
@@ -358,12 +399,31 @@ function createChartContainer(data, canvasId, type) {
358399
tagsContainer.appendChild(tagElement);
359400
});
360401

361-
container.appendChild(tagsContainer);
402+
headerSection.appendChild(tagsContainer);
362403
}
363404

405+
// Add header section to container
406+
container.appendChild(headerSection);
407+
408+
// Create main content section (chart + legend area)
409+
const contentSection = document.createElement('div');
410+
contentSection.className = 'chart-content';
411+
412+
// Canvas for the chart - fixed position in content flow
364413
const canvas = document.createElement('canvas');
365414
canvas.id = canvasId;
366-
container.appendChild(canvas);
415+
canvas.style.width = '100%';
416+
417+
// Set a default height - will be properly sized later in createChart
418+
canvas.style.height = '400px';
419+
canvas.style.marginBottom = '10px';
420+
contentSection.appendChild(canvas);
421+
422+
container.appendChild(contentSection);
423+
424+
// Create footer section for details
425+
const footerSection = document.createElement('div');
426+
footerSection.className = 'chart-footer';
367427

368428
// Create details section for extra info
369429
const details = document.createElement('details');
@@ -387,7 +447,8 @@ function createChartContainer(data, canvasId, type) {
387447
extraInfo.innerHTML = generateExtraInfo(data, 'benchmark');
388448
details.appendChild(extraInfo);
389449

390-
container.appendChild(details);
450+
footerSection.appendChild(details);
451+
container.appendChild(footerSection);
391452

392453
return container;
393454
}

devops/scripts/benchmarks/html/styles.css

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,24 @@ h1, h2 {
1818
background: white;
1919
border-radius: 8px;
2020
padding: 24px;
21-
margin-bottom: 24px;
22-
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
21+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
22+
position: relative;
23+
display: flex;
24+
flex-direction: column;
25+
box-sizing: border-box;
26+
min-height: fit-content;
27+
margin: 10px 0;
28+
overflow: visible;
29+
}
30+
.chart-header {
31+
padding: 10px;
32+
border-radius: 6px 6px 0 0;
33+
}
34+
.chart-content {
35+
padding: 10px;
36+
display: flex;
37+
flex-direction: column;
38+
min-height: fit-content;
2339
}
2440
@media (max-width: 768px) {
2541
body {

0 commit comments

Comments
 (0)