Skip to content

Commit 7ecbc83

Browse files
committed
[Benchmarks] Archive old data
Archive old benchmark data so it is not loaded in the dashboard. The default value for archiving is: - for Baseline_* runs for data older than 90 days, - for all other runs for data older than 14 days. Add a UI option for loading archived data.
1 parent 8b445d6 commit 7ecbc83

File tree

6 files changed

+256
-49
lines changed

6 files changed

+256
-49
lines changed

devops/scripts/benchmarks/history.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import socket
1010
from utils.result import Result, BenchmarkRun
1111
from options import Compare, options
12-
from datetime import datetime, timezone
12+
from datetime import datetime, timezone, timedelta
1313
from utils.utils import run
1414
from utils.validate import Validate
1515

@@ -223,3 +223,23 @@ def get_compare(self, name: str) -> BenchmarkRun:
223223
return self.compute_average(data)
224224

225225
raise Exception("invalid compare type")
226+
227+
def partition_runs_by_age(self) -> tuple[list[BenchmarkRun], list[BenchmarkRun]]:
228+
"""
229+
Partition runs into current and archived based on their age.
230+
Returns:
231+
tuple: (current_runs, archived_runs)
232+
"""
233+
current_runs = []
234+
archived_runs = []
235+
236+
for run in self.runs:
237+
archive_after = options.archive_baseline_days if run.name.startswith("Baseline_") else options.archive_pr_days
238+
cutoff_date = datetime.now(timezone.utc) - timedelta(days=archive_after)
239+
240+
if run.date > cutoff_date:
241+
current_runs.append(run)
242+
else:
243+
archived_runs.append(run)
244+
245+
return current_runs, archived_runs

devops/scripts/benchmarks/html/index.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ <h3>Display Options</h3>
5353
<input type="checkbox" id="custom-range">
5454
Adjust Y-axis for comparisons
5555
</label>
56+
<label title="Load older benchmark results that have been archived.">
57+
<input type="checkbox" id="show-archived-data">
58+
Include archived runs
59+
</label>
5660
</div>
5761
</div>
5862

devops/scripts/benchmarks/html/scripts.js

Lines changed: 151 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@
77
let activeRuns = new Set(defaultCompareNames);
88
let chartInstances = new Map();
99
let suiteNames = new Set();
10-
let timeseriesData, barChartsData, allRunNames;
1110
let activeTags = new Set();
11+
let timeseriesData, barChartsData, allRunNames;
1212
let layerComparisonsData;
1313
let latestRunsLookup = new Map();
1414
let pendingCharts = new Map(); // Store chart data for lazy loading
1515
let chartObserver; // Intersection observer for lazy loading charts
1616
let annotationsOptions = new Map(); // Global options map for annotations
17+
let archivedDataLoaded = false;
1718

1819
// DOM Elements
1920
let runSelect, selectedRunsDiv, suiteFiltersContainer, tagFiltersContainer;
@@ -577,6 +578,12 @@ function updateURL() {
577578
} else {
578579
url.searchParams.set('customRange', 'true');
579580
}
581+
582+
if (!isArchivedDataEnabled()) {
583+
url.searchParams.delete('archived');
584+
} else {
585+
url.searchParams.set('archived', 'true');
586+
}
580587

581588
history.replaceState(null, '', url);
582589
}
@@ -835,6 +842,9 @@ function setupRunSelector() {
835842
runSelect = document.getElementById('run-select');
836843
selectedRunsDiv = document.getElementById('selected-runs');
837844

845+
// Clear existing options first to prevent duplicates when reloading with archived data
846+
runSelect.innerHTML = '';
847+
838848
allRunNames.forEach(name => {
839849
const option = document.createElement('option');
840850
option.value = name;
@@ -848,6 +858,9 @@ function setupRunSelector() {
848858
function setupSuiteFilters() {
849859
suiteFiltersContainer = document.getElementById('suite-filters');
850860

861+
// Clear existing suite filters before adding new ones
862+
suiteFiltersContainer.innerHTML = '';
863+
851864
benchmarkRuns.forEach(run => {
852865
run.results.forEach(result => {
853866
suiteNames.add(result.suite);
@@ -883,10 +896,16 @@ function isCustomRangesEnabled() {
883896
return rangesToggle.checked;
884897
}
885898

899+
function isArchivedDataEnabled() {
900+
const archivedDataToggle = document.getElementById('show-archived-data');
901+
return archivedDataToggle.checked;
902+
}
903+
886904
function setupToggles() {
887905
const notesToggle = document.getElementById('show-notes');
888906
const unstableToggle = document.getElementById('show-unstable');
889907
const customRangeToggle = document.getElementById('custom-range');
908+
const archivedDataToggle = document.getElementById('show-archived-data');
890909

891910
notesToggle.addEventListener('change', function () {
892911
// Update all note elements visibility
@@ -908,10 +927,26 @@ function setupToggles() {
908927
// redraw all charts
909928
updateCharts();
910929
});
930+
931+
// Add event listener for archived data toggle
932+
if (archivedDataToggle) {
933+
archivedDataToggle.addEventListener('change', function() {
934+
if (archivedDataToggle.checked) {
935+
loadArchivedData();
936+
} else {
937+
if (archivedDataLoaded) {
938+
// Reload the page to reset
939+
location.reload();
940+
}
941+
}
942+
updateURL();
943+
});
944+
}
911945

912946
// Initialize from URL params if present
913947
const notesParam = getQueryParam('notes');
914948
const unstableParam = getQueryParam('unstable');
949+
const archivedParam = getQueryParam('archived');
915950

916951
if (notesParam !== null) {
917952
let showNotes = notesParam === 'true';
@@ -927,11 +962,22 @@ function setupToggles() {
927962
if (customRangesParam !== null) {
928963
customRangeToggle.checked = customRangesParam === 'true';
929964
}
965+
966+
if (archivedDataToggle && archivedParam !== null) {
967+
archivedDataToggle.checked = archivedParam === 'true';
968+
969+
if (archivedDataToggle.checked) {
970+
loadArchivedData();
971+
}
972+
}
930973
}
931974

932975
function setupTagFilters() {
933976
tagFiltersContainer = document.getElementById('tag-filters');
934977

978+
// Clear existing tag filters before adding new ones
979+
tagFiltersContainer.innerHTML = '';
980+
935981
const allTags = [];
936982

937983
if (benchmarkTags) {
@@ -1087,38 +1133,124 @@ window.addSelectedRun = addSelectedRun;
10871133
window.removeRun = removeRun;
10881134
window.toggleAllTags = toggleAllTags;
10891135

1136+
// Helper function to fetch and process benchmark data
1137+
function fetchAndProcessData(url, isArchived = false) {
1138+
const loadingIndicator = document.getElementById('loading-indicator');
1139+
1140+
return fetch(url)
1141+
.then(response => {
1142+
if (!response.ok) { throw new Error(`Got response status ${response.status}.`) }
1143+
return response.json();
1144+
})
1145+
.then(data => {
1146+
const newRuns = data.runs || data;
1147+
1148+
if (isArchived) {
1149+
// Merge with existing data for archived data
1150+
benchmarkRuns = benchmarkRuns.concat(newRuns);
1151+
1152+
// Merge metadata and tags if available
1153+
if (data.metadata) {
1154+
benchmarkMetadata = { ...benchmarkMetadata, ...data.metadata };
1155+
}
1156+
1157+
if (data.tags) {
1158+
benchmarkTags = { ...benchmarkTags, ...data.tags };
1159+
}
1160+
1161+
archivedDataLoaded = true;
1162+
} else {
1163+
// Replace existing data for primary data
1164+
benchmarkRuns = newRuns;
1165+
benchmarkMetadata = data.metadata || benchmarkMetadata || {};
1166+
benchmarkTags = data.tags || benchmarkTags || {};
1167+
}
1168+
1169+
initializeCharts();
1170+
})
1171+
.catch(error => {
1172+
console.error(`Error fetching ${isArchived ? 'archived' : 'remote'} data:`, error);
1173+
loadingIndicator.textContent = 'Fetching remote data failed.';
1174+
})
1175+
.finally(() => {
1176+
loadingIndicator.style.display = 'none';
1177+
});
1178+
}
1179+
10901180
// Load data based on configuration
10911181
function loadData() {
10921182
const loadingIndicator = document.getElementById('loading-indicator');
10931183
loadingIndicator.style.display = 'block'; // Show loading indicator
10941184

10951185
if (typeof remoteDataUrl !== 'undefined' && remoteDataUrl !== '') {
10961186
// Fetch data from remote URL
1097-
fetch(remoteDataUrl)
1098-
.then(response => {
1099-
if (!response.ok) { throw new Error(`Got response status ${response.status}.`) }
1100-
return response.json();
1101-
})
1102-
.then(data => {
1103-
benchmarkRuns = data.runs || data;
1104-
benchmarkMetadata = data.metadata || benchmarkMetadata || {};
1105-
benchmarkTags = data.tags || benchmarkTags || {};
1106-
initializeCharts();
1107-
})
1108-
.catch(error => {
1109-
console.error('Error fetching remote data:', error);
1110-
loadingIndicator.textContent = 'Fetching remote data failed.';
1111-
})
1112-
.finally(() => {
1113-
loadingIndicator.style.display = 'none'; // Hide loading indicator
1114-
});
1187+
fetchAndProcessData(remoteDataUrl);
11151188
} else {
11161189
// Use local data (benchmarkRuns and benchmarkMetadata should be defined in data.js)
11171190
initializeCharts();
11181191
loadingIndicator.style.display = 'none'; // Hide loading indicator
11191192
}
11201193
}
11211194

1195+
// Function to load archived data and merge with current data
1196+
// Archived data consists of older benchmark results that have been separated from
1197+
// the primary dataset but are still available for historical analysis.
1198+
function loadArchivedData() {
1199+
const loadingIndicator = document.getElementById('loading-indicator');
1200+
loadingIndicator.style.display = 'block';
1201+
1202+
if (archivedDataLoaded) {
1203+
updateCharts();
1204+
loadingIndicator.style.display = 'none';
1205+
return;
1206+
}
1207+
1208+
if (typeof remoteDataUrl !== 'undefined' && remoteDataUrl !== '') {
1209+
// For remote data, construct the archive URL by adding _archive before the extension
1210+
const archiveUrl = remoteDataUrl.replace(/(\.[^.]+)$/, '_archive$1');
1211+
1212+
// Check if we're using local JSON files
1213+
if (remoteDataUrl.startsWith('./') && remoteDataUrl.endsWith('.json')) {
1214+
fetchAndProcessData(archiveUrl, true);
1215+
} else {
1216+
fetchAndProcessData(archiveUrl, true);
1217+
}
1218+
} else {
1219+
// For local data using a static js file
1220+
const script = document.createElement('script');
1221+
script.src = 'data_archive.js';
1222+
script.onload = () => {
1223+
if (typeof archivedBenchmarkRuns !== 'undefined') {
1224+
// Merge the archived runs with current runs
1225+
benchmarkRuns = benchmarkRuns.concat(archivedBenchmarkRuns);
1226+
1227+
// Merge metadata and tags if available
1228+
if (typeof archivedBenchmarkMetadata !== 'undefined') {
1229+
benchmarkMetadata = { ...benchmarkMetadata, ...archivedBenchmarkMetadata };
1230+
}
1231+
1232+
if (typeof archivedBenchmarkTags !== 'undefined') {
1233+
benchmarkTags = { ...benchmarkTags, ...archivedBenchmarkTags };
1234+
}
1235+
1236+
archivedDataLoaded = true;
1237+
1238+
initializeCharts();
1239+
} else {
1240+
console.error('Archived runs data not found in data_archive.js');
1241+
}
1242+
loadingIndicator.style.display = 'none';
1243+
};
1244+
1245+
script.onerror = () => {
1246+
console.error('Failed to load data_archive.js');
1247+
loadingIndicator.style.display = 'none';
1248+
};
1249+
1250+
document.head.appendChild(script);
1251+
}
1252+
}
1253+
11221254
// Initialize when DOM is ready
11231255
document.addEventListener('DOMContentLoaded', () => {
11241256
loadData();

devops/scripts/benchmarks/main.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ def main(directory, additional_env_vars, save_name, compare_names, filter):
316316
if options.output_directory is None:
317317
html_path = os.path.join(os.path.dirname(__file__), "html")
318318

319-
generate_html(history.runs, compare_names, html_path, metadata)
319+
generate_html(history, compare_names, html_path, metadata)
320320

321321

322322
def validate_and_parse_env_args(env_args):
@@ -558,6 +558,22 @@ def validate_and_parse_env_args(env_args):
558558
help="Location of detect_version.cpp used to query e.g. DPC++, L0",
559559
default=None,
560560
)
561+
parser.add_argument(
562+
"--archive-baseline-after",
563+
type=int,
564+
help="Archive baseline results (runs starting with 'Baseline_') older than this many days. "
565+
"Archived results are stored separately and can be viewed in the HTML UI by enabling "
566+
"'Include archived runs'. This helps manage the size of the primary dataset.",
567+
default=options.archive_baseline_days,
568+
)
569+
parser.add_argument(
570+
"--archive-pr-after",
571+
type=int,
572+
help="Archive PR and other non-baseline results older than this many days. "
573+
"Archived results are stored separately and can be viewed in the HTML UI by enabling "
574+
"'Include archived runs'. PR runs typically have a shorter retention period than baselines.",
575+
default=options.archive_pr_days,
576+
)
561577

562578
args = parser.parse_args()
563579
additional_env_vars = validate_and_parse_env_args(args.env)

devops/scripts/benchmarks/options.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
from enum import Enum
33
import multiprocessing
44

5-
from presets import presets
6-
75

86
class Compare(Enum):
97
LATEST = "latest"
@@ -88,6 +86,12 @@ class Options:
8886
# CI scripts vs SYCl build source.
8987
github_repo_override: str = None
9088
git_commit_override: str = None
89+
# Archiving settings
90+
# Archived runs are stored separately from the main dataset but are still accessible
91+
# via the HTML UI when "Include archived runs" is enabled
92+
archive_baseline_days: int = 90 # Archive Baseline_* runs after 90 days
93+
archive_pr_days: int = 14 # Archive other (PR/dev) runs after 14 days
94+
9195

9296
detect_versions: DetectVersionsOptions = field(
9397
default_factory=DetectVersionsOptions

0 commit comments

Comments
 (0)