mirror of
https://github.com/django-components/django-components.git
synced 2025-07-08 01:45:00 +00:00

* feat: add benchmarking dashboard, CI hook on PR, and store lifetime results * refactor: change python env to 3.13 in benchmarks * refactor: add verbosity, use 3.11 for benchmarking * fix: OSError: [Errno 7] Argument list too long * refactor: add debug statements * refactor: remove extraneous -e * refactor: fix tests and linter errors * fix: track main package in coverage * refactor: fix test coverage testing * refactor: fix repo owner name in benchmark on pushing comment * refactor: add asv monkeypatch to docs workflow * refactor: temporarily allow building docs in forks * refactor: use py 3.13 for benchmarking * refactor: run only a single benchmark for PRs to speed them up * refactor: install asv in the docs build workflow * refactor: use hatch docs env to generate benhcmarks in docs CI * refactor: more trying * refactor: move tests * Add benchmark results for 0.137 * Trigger Build * Add benchmark results for 0.138 * refactor: set constant machine name when benchmarking * Add benchmark results for 0.139 * refactor: fix issue with paths too long * Add benchmark results for 0.140 * docs: update comment * refactor: remove test benchmarking data * refactor: fix comment * refactor: allow the benchmark workflow to write to PRs * refactor: use personal access token to set up the PR benchmark bot * refactor: split the benchmark PR flow into two to make it work with PRs from forks * refactor: update deprecated actions/upload-artifact@v3 to v4 * refactor: fix missing directory in benchmarking workflow * refactor: fix triggering of second workflow * refactor: fix workflow finally? * docs: add comments to cut-offs and direct people to benchmarks PR --------- Co-authored-by: github-actions <github-actions@github.com>
525 lines
16 KiB
JavaScript
525 lines
16 KiB
JavaScript
'use strict';
|
|
|
|
$(document).ready(function() {
|
|
/* GLOBAL STATE */
|
|
/* The index.json content as returned from the server */
|
|
var main_timestamp = '';
|
|
var main_json = {};
|
|
/* Extra pages: {name: show_function} */
|
|
var loaded_pages = {};
|
|
/* Previous window scroll positions */
|
|
var window_scroll_positions = {};
|
|
/* Previous window hash location */
|
|
var window_last_location = null;
|
|
/* Graph data cache */
|
|
var graph_cache = {};
|
|
var graph_cache_max_size = 5;
|
|
|
|
var colors = [
|
|
'#247AAD',
|
|
'#E24A33',
|
|
'#988ED5',
|
|
'#777777',
|
|
'#FBC15E',
|
|
'#8EBA42',
|
|
'#FFB5B8'
|
|
];
|
|
|
|
var time_units = [
|
|
['ps', 'picoseconds', 0.000000000001],
|
|
['ns', 'nanoseconds', 0.000000001],
|
|
['μs', 'microseconds', 0.000001],
|
|
['ms', 'milliseconds', 0.001],
|
|
['s', 'seconds', 1],
|
|
['m', 'minutes', 60],
|
|
['h', 'hours', 60 * 60],
|
|
['d', 'days', 60 * 60 * 24],
|
|
['w', 'weeks', 60 * 60 * 24 * 7],
|
|
['y', 'years', 60 * 60 * 24 * 7 * 52],
|
|
['C', 'centuries', 60 * 60 * 24 * 7 * 52 * 100]
|
|
];
|
|
|
|
var mem_units = [
|
|
['', 'bytes', 1],
|
|
['k', 'kilobytes', 1000],
|
|
['M', 'megabytes', 1000000],
|
|
['G', 'gigabytes', 1000000000],
|
|
['T', 'terabytes', 1000000000000]
|
|
];
|
|
|
|
function pretty_second(x) {
|
|
for (var i = 0; i < time_units.length - 1; ++i) {
|
|
if (Math.abs(x) < time_units[i+1][2]) {
|
|
return (x / time_units[i][2]).toFixed(3) + time_units[i][0];
|
|
}
|
|
}
|
|
|
|
return 'inf';
|
|
}
|
|
|
|
function pretty_byte(x) {
|
|
for (var i = 0; i < mem_units.length - 1; ++i) {
|
|
if (Math.abs(x) < mem_units[i+1][2]) {
|
|
break;
|
|
}
|
|
}
|
|
if (i == 0) {
|
|
return x + '';
|
|
}
|
|
return (x / mem_units[i][2]).toFixed(3) + mem_units[i][0];
|
|
}
|
|
|
|
function pretty_unit(x, unit) {
|
|
if (unit == "seconds") {
|
|
return pretty_second(x);
|
|
}
|
|
else if (unit == "bytes") {
|
|
return pretty_byte(x);
|
|
}
|
|
else if (unit && unit != "unit") {
|
|
return '' + x.toPrecision(3) + ' ' + unit;
|
|
}
|
|
else {
|
|
return '' + x.toPrecision(3);
|
|
}
|
|
}
|
|
|
|
function pad_left(s, c, num) {
|
|
s = '' + s;
|
|
while (s.length < num) {
|
|
s = c + s;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
function format_date_yyyymmdd(date) {
|
|
return (pad_left(date.getFullYear(), '0', 4)
|
|
+ '-' + pad_left(date.getMonth() + 1, '0', 2)
|
|
+ '-' + pad_left(date.getDate(), '0', 2));
|
|
}
|
|
|
|
function format_date_yyyymmdd_hhmm(date) {
|
|
return (format_date_yyyymmdd(date) + ' '
|
|
+ pad_left(date.getHours(), '0', 2)
|
|
+ ':' + pad_left(date.getMinutes(), '0', 2));
|
|
}
|
|
|
|
/* Convert a flat index to permutation to the corresponding value */
|
|
function param_selection_from_flat_idx(params, idx) {
|
|
var selection = [];
|
|
if (idx < 0) {
|
|
idx = 0;
|
|
}
|
|
for (var k = params.length-1; k >= 0; --k) {
|
|
var j = idx % params[k].length;
|
|
selection.unshift([j]);
|
|
idx = (idx - j) / params[k].length;
|
|
}
|
|
selection.unshift([null]);
|
|
return selection;
|
|
}
|
|
|
|
/* Convert a benchmark parameter value from their native Python
|
|
repr format to a number or a string, ready for presentation */
|
|
function convert_benchmark_param_value(value_repr) {
|
|
var match = Number(value_repr);
|
|
if (!isNaN(match)) {
|
|
return match;
|
|
}
|
|
|
|
/* Python str */
|
|
match = value_repr.match(/^'(.+)'$/);
|
|
if (match) {
|
|
return match[1];
|
|
}
|
|
|
|
/* Python unicode */
|
|
match = value_repr.match(/^u'(.+)'$/);
|
|
if (match) {
|
|
return match[1];
|
|
}
|
|
|
|
/* Python class */
|
|
match = value_repr.match(/^<class '(.+)'>$/);
|
|
if (match) {
|
|
return match[1];
|
|
}
|
|
|
|
return value_repr;
|
|
}
|
|
|
|
/* Convert loaded graph data to a format flot understands, by
|
|
treating either time or one of the parameters as x-axis,
|
|
and selecting only one value of the remaining axes */
|
|
function filter_graph_data(raw_series, x_axis, other_indices, params) {
|
|
if (params.length == 0) {
|
|
/* Simple time series */
|
|
return raw_series;
|
|
}
|
|
|
|
/* Compute position of data entry in the results list,
|
|
and stride corresponding to plot x-axis parameter */
|
|
var stride = 1;
|
|
var param_stride = 0;
|
|
var param_idx = 0;
|
|
for (var k = params.length - 1; k >= 0; --k) {
|
|
if (k == x_axis - 1) {
|
|
param_stride = stride;
|
|
}
|
|
else {
|
|
param_idx += other_indices[k + 1] * stride;
|
|
}
|
|
stride *= params[k].length;
|
|
}
|
|
|
|
if (x_axis == 0) {
|
|
/* x-axis is time axis */
|
|
var series = new Array(raw_series.length);
|
|
for (var k = 0; k < raw_series.length; ++k) {
|
|
if (raw_series[k][1] === null) {
|
|
series[k] = [raw_series[k][0], null];
|
|
} else {
|
|
series[k] = [raw_series[k][0],
|
|
raw_series[k][1][param_idx]];
|
|
}
|
|
}
|
|
return series;
|
|
}
|
|
else {
|
|
/* x-axis is some parameter axis */
|
|
var time_idx = null;
|
|
if (other_indices[0] === null) {
|
|
time_idx = raw_series.length - 1;
|
|
}
|
|
else {
|
|
/* Need to search for the correct time value */
|
|
for (var k = 0; k < raw_series.length; ++k) {
|
|
if (raw_series[k][0] == other_indices[0]) {
|
|
time_idx = k;
|
|
break;
|
|
}
|
|
}
|
|
if (time_idx === null) {
|
|
/* No data points */
|
|
return [];
|
|
}
|
|
}
|
|
|
|
var x_values = params[x_axis - 1];
|
|
var series = new Array(x_values.length);
|
|
for (var k = 0; k < x_values.length; ++k) {
|
|
if (raw_series[time_idx][1] === null) {
|
|
series[k] = [convert_benchmark_param_value(x_values[k]),
|
|
null];
|
|
}
|
|
else {
|
|
series[k] = [convert_benchmark_param_value(x_values[k]),
|
|
raw_series[time_idx][1][param_idx]];
|
|
}
|
|
param_idx += param_stride;
|
|
}
|
|
return series;
|
|
}
|
|
}
|
|
|
|
function filter_graph_data_idx(raw_series, x_axis, flat_idx, params) {
|
|
var selection = param_selection_from_flat_idx(params, flat_idx);
|
|
var flat_selection = [];
|
|
$.each(selection, function(i, v) {
|
|
flat_selection.push(v[0]);
|
|
});
|
|
return filter_graph_data(raw_series, x_axis, flat_selection, params);
|
|
}
|
|
|
|
/* Escape special characters in graph item file names.
|
|
The implementation must match asv.util.sanitize_filename */
|
|
function sanitize_filename(name) {
|
|
var bad_re = /[<>:"\/\\^|?*\x00-\x1f]/g;
|
|
var bad_names = ["CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3",
|
|
"COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1",
|
|
"LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8",
|
|
"LPT9"];
|
|
name = name.replace(bad_re, "_");
|
|
if (bad_names.indexOf(name.toUpperCase()) != -1) {
|
|
name = name + "_";
|
|
}
|
|
return name;
|
|
}
|
|
|
|
/* Given a specific group of parameters, generate the URL to
|
|
use to load that graph.
|
|
The implementation must match asv.graph.Graph.get_file_path
|
|
*/
|
|
function graph_to_path(benchmark_name, state) {
|
|
var parts = [];
|
|
$.each(state, function(key, value) {
|
|
var part;
|
|
if (value === null) {
|
|
part = key + "-null";
|
|
} else if (value) {
|
|
part = key + "-" + value;
|
|
} else {
|
|
part = key;
|
|
}
|
|
parts.push(sanitize_filename('' + part));
|
|
});
|
|
parts.sort();
|
|
parts.splice(0, 0, "graphs");
|
|
parts.push(sanitize_filename(benchmark_name));
|
|
|
|
/* Escape URI components */
|
|
parts = $.map(parts, function (val) { return encodeURIComponent(val); });
|
|
return parts.join('/') + ".json";
|
|
}
|
|
|
|
/*
|
|
Load and cache graph data (on javascript side)
|
|
*/
|
|
function load_graph_data(url, success, failure) {
|
|
var dfd = $.Deferred();
|
|
if (graph_cache[url]) {
|
|
setTimeout(function() {
|
|
dfd.resolve(graph_cache[url]);
|
|
}, 1);
|
|
}
|
|
else {
|
|
$.ajax({
|
|
url: url + '?timestamp=' + $.asv.main_timestamp,
|
|
dataType: "json",
|
|
cache: true
|
|
}).done(function(data) {
|
|
if (Object.keys(graph_cache).length > graph_cache_max_size) {
|
|
$.each(Object.keys(graph_cache), function (i, key) {
|
|
delete graph_cache[key];
|
|
});
|
|
}
|
|
graph_cache[url] = data;
|
|
dfd.resolve(data);
|
|
}).fail(function() {
|
|
dfd.reject();
|
|
});
|
|
}
|
|
return dfd.promise();
|
|
}
|
|
|
|
/*
|
|
Parse hash string, assuming format similar to standard URL
|
|
query strings
|
|
*/
|
|
function parse_hash_string(str) {
|
|
var info = {location: [''], params: {}};
|
|
|
|
if (str && str[0] == '#') {
|
|
str = str.slice(1);
|
|
}
|
|
if (str && str[0] == '/') {
|
|
str = str.slice(1);
|
|
}
|
|
|
|
var match = str.match(/^([^?]*?)\?/);
|
|
if (match) {
|
|
info['location'] = decodeURIComponent(match[1]).replace(/\/+/, '/').split('/');
|
|
var rest = str.slice(match[1].length+1);
|
|
var parts = rest.split('&');
|
|
for (var i = 0; i < parts.length; ++i) {
|
|
var part = parts[i].split('=');
|
|
if (part.length != 2) {
|
|
continue;
|
|
}
|
|
var key = decodeURIComponent(part[0].replace(/\+/g, " "));
|
|
var value = decodeURIComponent(part[1].replace(/\+/g, " "));
|
|
if (value == '[none]') {
|
|
value = null;
|
|
}
|
|
if (info['params'][key] === undefined) {
|
|
info['params'][key] = [value];
|
|
}
|
|
else {
|
|
info['params'][key].push(value);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
info['location'] = decodeURIComponent(str).replace(/\/+/, '/').split('/');
|
|
}
|
|
return info;
|
|
}
|
|
|
|
/*
|
|
Generate a hash string, inverse of parse_hash_string
|
|
*/
|
|
function format_hash_string(info) {
|
|
var parts = info['params'];
|
|
var str = '#' + info['location'];
|
|
|
|
if (parts) {
|
|
str = str + '?';
|
|
var first = true;
|
|
$.each(parts, function (key, values) {
|
|
$.each(values, function (idx, value) {
|
|
if (!first) {
|
|
str = str + '&';
|
|
}
|
|
if (value === null) {
|
|
value = '[none]';
|
|
}
|
|
str = str + encodeURIComponent(key) + '=' + encodeURIComponent(value);
|
|
first = false;
|
|
});
|
|
});
|
|
}
|
|
return str;
|
|
}
|
|
|
|
/*
|
|
Dealing with sub-pages
|
|
*/
|
|
|
|
function show_page(name, params) {
|
|
if (loaded_pages[name] !== undefined) {
|
|
$("#nav ul li.active").removeClass('active');
|
|
$("#nav-li-" + name).addClass('active');
|
|
$("#graph-display").hide();
|
|
$("#summarygrid-display").hide();
|
|
$("#summarylist-display").hide();
|
|
$('#regressions-display').hide();
|
|
$('.tooltip').remove();
|
|
loaded_pages[name](params);
|
|
return true;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function hashchange() {
|
|
var info = parse_hash_string(window.location.hash);
|
|
|
|
/* Keep track of window scroll position; makes the back-button work */
|
|
var old_scroll_pos = window_scroll_positions[info.location.join('/')];
|
|
window_scroll_positions[window_last_location] = $(window).scrollTop();
|
|
window_last_location = info.location.join('/');
|
|
|
|
/* Redirect to correct handler */
|
|
if (show_page(info.location, info.params)) {
|
|
/* show_page does the work */
|
|
}
|
|
else {
|
|
/* Display benchmark page */
|
|
info.params['benchmark'] = info.location[0];
|
|
show_page('graphdisplay', info.params);
|
|
}
|
|
|
|
/* Scroll back to previous position, if any */
|
|
if (old_scroll_pos !== undefined) {
|
|
$(window).scrollTop(old_scroll_pos);
|
|
}
|
|
}
|
|
|
|
function get_commit_hash(revision) {
|
|
var commit_hash = main_json.revision_to_hash[revision];
|
|
if (commit_hash) {
|
|
// Return printable commit hash
|
|
commit_hash = commit_hash.slice(0, main_json.hash_length);
|
|
}
|
|
return commit_hash;
|
|
}
|
|
|
|
function get_revision(commit_hash) {
|
|
var rev = null;
|
|
$.each(main_json.revision_to_hash, function(revision, full_commit_hash) {
|
|
if (full_commit_hash.startsWith(commit_hash)) {
|
|
rev = revision;
|
|
// break the $.each loop
|
|
return false;
|
|
}
|
|
});
|
|
return rev;
|
|
}
|
|
|
|
function init_index() {
|
|
/* Fetch the main index.json and then set up the page elements
|
|
based on it. */
|
|
$.ajax({
|
|
url: "index.json" + '?timestamp=' + $.asv.main_timestamp,
|
|
dataType: "json",
|
|
cache: true
|
|
}).done(function (index) {
|
|
main_json = index;
|
|
$.asv.main_json = index;
|
|
|
|
/* Page title */
|
|
var project_name = $("#project-name")[0];
|
|
project_name.textContent = index.project;
|
|
project_name.setAttribute("href", index.project_url);
|
|
$("#project-name").textContent = index.project;
|
|
document.title = "airspeed velocity of an unladen " + index.project;
|
|
|
|
$(window).on('hashchange', hashchange);
|
|
|
|
$('#graph-display').hide();
|
|
$('#regressions-display').hide();
|
|
$('#summarygrid-display').hide();
|
|
$('#summarylist-display').hide();
|
|
|
|
hashchange();
|
|
}).fail(function () {
|
|
$.asv.ui.network_error();
|
|
});
|
|
}
|
|
|
|
function init() {
|
|
/* Fetch the info.json */
|
|
$.ajax({
|
|
url: "info.json",
|
|
dataType: "json",
|
|
cache: false
|
|
}).done(function (info) {
|
|
main_timestamp = info['timestamp'];
|
|
$.asv.main_timestamp = main_timestamp;
|
|
init_index();
|
|
}).fail(function () {
|
|
$.asv.ui.network_error();
|
|
});
|
|
}
|
|
|
|
|
|
/*
|
|
Set up $.asv
|
|
*/
|
|
|
|
this.register_page = function(name, show_function) {
|
|
loaded_pages[name] = show_function;
|
|
}
|
|
this.parse_hash_string = parse_hash_string;
|
|
this.format_hash_string = format_hash_string;
|
|
|
|
this.filter_graph_data = filter_graph_data;
|
|
this.filter_graph_data_idx = filter_graph_data_idx;
|
|
this.convert_benchmark_param_value = convert_benchmark_param_value;
|
|
this.param_selection_from_flat_idx = param_selection_from_flat_idx;
|
|
this.graph_to_path = graph_to_path;
|
|
this.load_graph_data = load_graph_data;
|
|
this.get_commit_hash = get_commit_hash;
|
|
this.get_revision = get_revision;
|
|
|
|
this.main_timestamp = main_timestamp; /* Updated after info.json loads */
|
|
this.main_json = main_json; /* Updated after index.json loads */
|
|
|
|
this.format_date_yyyymmdd = format_date_yyyymmdd;
|
|
this.format_date_yyyymmdd_hhmm = format_date_yyyymmdd_hhmm;
|
|
this.pretty_unit = pretty_unit;
|
|
this.time_units = time_units;
|
|
this.mem_units = mem_units;
|
|
|
|
this.colors = colors;
|
|
|
|
$.asv = this;
|
|
|
|
|
|
/*
|
|
Launch it
|
|
*/
|
|
|
|
init();
|
|
});
|