mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-27 18:12:02 +00:00
465 lines
15 KiB
JavaScript
465 lines
15 KiB
JavaScript
var data_sizes =
|
||
[
|
||
{id: "10000000", name: "10 mln."},
|
||
{id: "100000000", name: "100 mln."},
|
||
{id: "1000000000", name: "1 bn."}
|
||
];
|
||
|
||
|
||
var systems = [];
|
||
var systems_full = [];
|
||
var system_kinds = [];
|
||
var systems_uniq = {};
|
||
for (r in results) {
|
||
if (systems_uniq[results[r].system])
|
||
continue;
|
||
systems_uniq[results[r].system] = 1;
|
||
systems.push(results[r].system);
|
||
systems_full.push(results[r].system_full);
|
||
system_kinds.push(results[r].kind);
|
||
}
|
||
|
||
var runs = ["first (cold cache)", "second", "third"];
|
||
var current_runs = ['1', '2'];
|
||
|
||
try {
|
||
var state = JSON.parse(decodeURIComponent(window.location.hash.substring(1)));
|
||
current_data_size = state[0];
|
||
current_systems = state[1];
|
||
current_runs = state[2];
|
||
} catch (e) {
|
||
}
|
||
|
||
if (!current_systems.length) {
|
||
current_systems = systems;
|
||
}
|
||
|
||
function update_hash() {
|
||
window.location.hash = JSON.stringify([current_data_size, current_systems, current_runs]);
|
||
}
|
||
|
||
|
||
function generate_selectors(elem) {
|
||
var html = '<div id="systems_selector" class="mb-3"><h2 class="h4">Compare</h2>';
|
||
|
||
var available_results = results;
|
||
|
||
if (current_data_size) {
|
||
available_results = results.filter(function (run) {
|
||
return run.data_size == current_data_size;
|
||
});
|
||
}
|
||
var available_systems_for_current_data_size = available_results.map(function (run) {
|
||
return run.system;
|
||
});
|
||
|
||
for (var i = 0; i < systems.length; i++) {
|
||
var selected = current_systems.indexOf(systems[i]) != -1;
|
||
var available = available_systems_for_current_data_size.indexOf(systems[i]) != -1;
|
||
var button_class = 'btn-outline-dark';
|
||
if (system_kinds[i] == 'cloud' || system_kinds[i] == 'vps') {
|
||
button_class = 'btn-light';
|
||
} else if (system_kinds[i] == 'desktop' || system_kinds[i] == 'laptop') {
|
||
button_class = 'btn-outline-secondary';
|
||
};
|
||
|
||
html += '<button type="button" class="btn btn-sm mr-1 mb-1 ' + button_class +
|
||
(selected && available ? ' active' : '') +
|
||
(available ? '' : ' disabled') + '"';
|
||
if (systems_full[i]) {
|
||
html += ' data-toggle="tooltip" data-placement="bottom" title="' + systems_full[i] + '"';
|
||
}
|
||
html += '>' + systems[i] + '</button>';
|
||
}
|
||
|
||
if (current_data_size) {
|
||
html += '</div><div id="data_size_selector"><h2 class="h4">Dataset size</h2>';
|
||
|
||
for (var i = 0; i < data_sizes.length; i++) {
|
||
html += '<button type="button" class="btn btn-sm btn-outline-dark mr-1 mb-1' + (data_sizes[i].id == current_data_size ? ' active' : '') + '" data-size-id="' + data_sizes[i].id + '">' + data_sizes[i].name + '</button>';
|
||
}
|
||
}
|
||
|
||
html += '</div><div id="runs_selector"><h2 class="h4">Run</h2>';
|
||
|
||
for (var i = 0; i < runs.length; i++) {
|
||
html += '<button type="button" class="btn btn-sm btn-outline-dark mr-1 mb-1' + (current_runs.indexOf(String(i)) != -1 ? ' active' : '') + '" data-run-id="' + i + '">' + runs[i] + '</button>';
|
||
}
|
||
|
||
html += '</div>';
|
||
|
||
elem.html(html);
|
||
|
||
$('button').focus(function() {
|
||
$('[data-toggle="tooltip"]').tooltip('hide');
|
||
});
|
||
|
||
$('#systems_selector button:not(.disabled)').click(function (event) {
|
||
event.preventDefault();
|
||
var target = $(event.target || event.srcElement);
|
||
|
||
if (target.hasClass("active") && current_systems.length == 1) {
|
||
return;
|
||
}
|
||
|
||
target.toggleClass("active");
|
||
|
||
current_systems = $.map($('#systems_selector button'), function (elem) {
|
||
return $(elem).hasClass("active") ? $(elem).html() : null
|
||
}).filter(function (x) {
|
||
return x;
|
||
});
|
||
|
||
update_hash();
|
||
generate_selectors(elem);
|
||
generate_comparison_table();
|
||
generate_diagram();
|
||
});
|
||
|
||
if (current_data_size) {
|
||
$('#data_size_selector button').click(function (event) {
|
||
event.preventDefault();
|
||
var target = $(event.target || event.srcElement);
|
||
|
||
current_data_size = target.attr("data-size-id");
|
||
|
||
update_hash();
|
||
generate_selectors(elem);
|
||
generate_comparison_table();
|
||
generate_diagram();
|
||
});
|
||
}
|
||
|
||
$('#runs_selector button').click(function (event) {
|
||
event.preventDefault();
|
||
var target = $(event.target || event.srcElement);
|
||
|
||
if (target.hasClass("active") && current_runs.length == 1) {
|
||
return;
|
||
}
|
||
|
||
target.toggleClass("active");
|
||
|
||
current_runs = $.map($('#runs_selector button'), function (elem) {
|
||
return $(elem).hasClass("active") ? $(elem).attr("data-run-id") : null
|
||
}).filter(function (x) {
|
||
return x;
|
||
});
|
||
|
||
update_hash();
|
||
generate_selectors(elem);
|
||
generate_comparison_table();
|
||
generate_diagram();
|
||
});
|
||
}
|
||
|
||
function format_number_cell(value, ratio) {
|
||
var html = "";
|
||
|
||
var redness = (ratio - 1) / ratio;
|
||
var blackness = ratio < 10 ? 0 : ((ratio - 10) / ratio / 2);
|
||
|
||
var color = !value ? "#FFF" :
|
||
ratio == 1 ?
|
||
("rgba(0, 255, 0, 1)") :
|
||
("rgba(" + ~~(255 * (1 - blackness)) + ", 0, 0, " + redness + ")");
|
||
|
||
html += "<td style='background-color: " + color + "'>";
|
||
html += value ?
|
||
(ratio == 1 ? "" : ("×" + ratio.toFixed(2))) + " <span style='color: #888;'>(" + value.toFixed(3) + " s.)</span>" :
|
||
"—";
|
||
html += "</td>";
|
||
|
||
return html;
|
||
}
|
||
|
||
/* Ratio of execution time to best execution time:
|
||
* system index -> run index -> query index -> ratio.
|
||
*/
|
||
var ratios = [];
|
||
|
||
|
||
function generate_comparison_table() {
|
||
ratios = [];
|
||
|
||
var filtered_results = results;
|
||
if (current_data_size) {
|
||
filtered_results = filtered_results.filter(function (x) {
|
||
return x.data_size == current_data_size;
|
||
});
|
||
}
|
||
filtered_results = filtered_results.filter(function (x) {
|
||
return current_systems.indexOf(x.system) != -1;
|
||
});
|
||
|
||
var html = "";
|
||
|
||
html += "<table class='table table-bordered table-sm'>";
|
||
html += "<tr>";
|
||
html += "<th><input id='query_checkbox_toggler' type='checkbox' checked /></th>";
|
||
html += "<th>Query</th>";
|
||
for (var j = 0; j < filtered_results.length; j++) {
|
||
html += "<th colspan='" + current_runs.length + "'";
|
||
if (filtered_results[j].system_full) {
|
||
html += ' data-toggle="tooltip" title="' + filtered_results[j].system_full + '"';
|
||
}
|
||
html += " class='text-center'>" + filtered_results[j].system.replace(/ /g, ' ') +
|
||
(filtered_results[j].version ? " (" + filtered_results[j].version + ")" : "") + "</th>";
|
||
}
|
||
html += "</tr>";
|
||
|
||
for (var i = 0; i < queries.length; i++) {
|
||
html += "<tr>";
|
||
html += "<td><input id='query_checkbox" + i + "' type='checkbox' " +
|
||
($('#query_checkbox' + i).length == 0 || $('#query_checkbox' + i).is(':checked') ? "checked" : "") + " /></td>";
|
||
|
||
html += "<td class='benchmark-query-cell-wrapper'><div class='benchmark-query-cell'>" + queries[i].query + "</div></td>";
|
||
|
||
// Max and min execution time per system, for each of three runs
|
||
var minimums = [0, 0, 0], maximums = [0, 0, 0];
|
||
|
||
for (var j = 0; j < filtered_results.length; j++) {
|
||
for (var current_run_idx = 0; current_run_idx < current_runs.length; current_run_idx++) {
|
||
var k = current_runs[current_run_idx];
|
||
var value = filtered_results[j].result[i][k];
|
||
|
||
if (value && (!minimums[k] || value < minimums[k])) {
|
||
minimums[k] = value;
|
||
|
||
// Ignore below 10ms
|
||
if (minimums[k] < 0.01) {
|
||
minimums[k] = 0.01;
|
||
}
|
||
}
|
||
|
||
if (value > maximums[k]) {
|
||
maximums[k] = value;
|
||
}
|
||
}
|
||
}
|
||
|
||
for (var j = 0; j < filtered_results.length; j++) {
|
||
if (!ratios[j]) {
|
||
ratios[j] = [];
|
||
}
|
||
|
||
for (var current_run_idx = 0; current_run_idx < current_runs.length; current_run_idx++) {
|
||
var k = current_runs[current_run_idx];
|
||
var value = filtered_results[j].result[i][k];
|
||
|
||
var ratio = value / minimums[k];
|
||
|
||
ratios[j][k] = ratios[j][k] || [];
|
||
|
||
if (ratio && ratio <= 1) {
|
||
ratio = 1;
|
||
}
|
||
|
||
ratios[j][k].push(ratio);
|
||
|
||
html += format_number_cell(value, ratio);
|
||
}
|
||
}
|
||
html += "</tr>";
|
||
}
|
||
|
||
if (current_systems.length) {
|
||
html += "<tr>";
|
||
html += "<td rowspan='2'></td>";
|
||
html += "<td rowspan='2'>Geometric mean of ratios</td>";
|
||
|
||
for (var j = 0; j < filtered_results.length; j++) {
|
||
for (var k = 0; k < current_runs.length; k++) {
|
||
html += "<th id='totals" + j + "_" + current_runs[k] + "' class='number_cell text-center'></th>";
|
||
}
|
||
}
|
||
|
||
html += "</tr>";
|
||
html += "<tr>";
|
||
|
||
for (var j = 0; j < filtered_results.length; j++) {
|
||
html += "<th id='absolute_totals" + j + "' colspan='" + current_runs.length + "' class='number_cell text-center'></th>";
|
||
}
|
||
|
||
html += "</tr>";
|
||
}
|
||
|
||
html += "</table>";
|
||
|
||
$('#comparison_table').html(html);
|
||
|
||
for (var i = 0; i < queries.length; i++) {
|
||
$('#query_checkbox' + i).click(function () {
|
||
calculate_totals();
|
||
generate_diagram();
|
||
});
|
||
}
|
||
$('#query_checkbox_toggler').click(function () {
|
||
for (var i = 0; i < queries.length; i++) {
|
||
var item = $('#query_checkbox' + i);
|
||
item.prop("checked", !item.prop("checked"));
|
||
}
|
||
});
|
||
|
||
calculate_totals();
|
||
}
|
||
|
||
|
||
function calculate_totals() {
|
||
if (!current_systems.length) return;
|
||
var filtered_results = results;
|
||
if (current_data_size) {
|
||
filtered_results = filtered_results.filter(function (x) {
|
||
return x.data_size == current_data_size;
|
||
});
|
||
}
|
||
|
||
filtered_results = filtered_results.filter(function (x) {
|
||
return current_systems.indexOf(x.system) != -1;
|
||
});
|
||
|
||
var total_ratios = [];
|
||
|
||
for (var j = 0; j < filtered_results.length; j++) {
|
||
for (var current_run_idx = 0; current_run_idx < current_runs.length; current_run_idx++) {
|
||
var k = current_runs[current_run_idx];
|
||
|
||
var current_ratios = ratios[j][k].filter(
|
||
function (x, i) {
|
||
return x && $("#query_checkbox" + i).is(':checked');
|
||
}
|
||
);
|
||
|
||
var ratio = Math.pow(
|
||
current_ratios.reduce(
|
||
function (acc, cur) {
|
||
return acc * cur;
|
||
},
|
||
1),
|
||
1 / current_ratios.length);
|
||
|
||
total_ratios[j] = total_ratios[j] || 1;
|
||
total_ratios[j] *= ratio;
|
||
|
||
$("#totals" + j + "_" + k).attr("data-ratio", ratio).html("x" + ratio.toFixed(2));
|
||
}
|
||
}
|
||
|
||
for (var j = 0; j < filtered_results.length; j++) {
|
||
var total_ratio = Math.pow(total_ratios[j], 1 / current_runs.length);
|
||
$("#absolute_totals" + j).attr("data-ratio", total_ratio).html("x" + total_ratio.toFixed(2));
|
||
}
|
||
}
|
||
|
||
|
||
function generate_diagram() {
|
||
var html = "";
|
||
var filtered_results = results;
|
||
if (current_data_size) {
|
||
filtered_results = filtered_results.filter(function (x) {
|
||
return x.data_size == current_data_size && current_systems.indexOf(x.system) != -1;
|
||
});
|
||
}
|
||
filtered_results = filtered_results.filter(function (x) {
|
||
return current_systems.indexOf(x.system) != -1;
|
||
});
|
||
|
||
var max_ratio = 1;
|
||
var min_ratio = 0;
|
||
|
||
var max_total_ratio = 1;
|
||
var min_total_ratio = 0;
|
||
|
||
for (var j = 0; j < filtered_results.length; j++) {
|
||
for (var current_run_idx = 0; current_run_idx < current_runs.length; current_run_idx++) {
|
||
var k = current_runs[current_run_idx];
|
||
var ratio = +$("#totals" + j + "_" + k).attr("data-ratio");
|
||
|
||
if (ratio > max_ratio) {
|
||
max_ratio = ratio;
|
||
}
|
||
|
||
if (!min_ratio || ratio < min_ratio) {
|
||
min_ratio = ratio;
|
||
}
|
||
}
|
||
|
||
var total_ratio = +$("#absolute_totals" + j).attr("data-ratio");
|
||
|
||
if (total_ratio > max_total_ratio) {
|
||
max_total_ratio = total_ratio;
|
||
}
|
||
|
||
if (!min_total_ratio || total_ratio < min_total_ratio) {
|
||
min_total_ratio = total_ratio;
|
||
}
|
||
}
|
||
|
||
html += "<table class='table table-borderless table-sm'>";
|
||
var table_rows = [];
|
||
|
||
for (var j = 0; j < filtered_results.length; j++) {
|
||
var total_ratio = +$("#absolute_totals" + j).attr("data-ratio");
|
||
var table_row = "";
|
||
|
||
table_row += "<tr>";
|
||
table_row += "<td class='text-right text-nowrap w-15 align-middle'";
|
||
if (filtered_results[j].system_full) {
|
||
table_row += ' data-toggle="tooltip" data-placement="right" title="' + filtered_results[j].system_full + '"';
|
||
}
|
||
table_row += ">" + filtered_results[j].system + "" +
|
||
(filtered_results[j].version ? "<br /><span class='text-muted'(" + filtered_results[j].version.replace(/ /g, ' ') + ")</span>" : "") + "</td>";
|
||
|
||
table_row += "<td class='w-75'>";
|
||
|
||
for (var current_run_idx = 0; current_run_idx < current_runs.length; current_run_idx++) {
|
||
var k = current_runs[current_run_idx];
|
||
|
||
var ratio = +$("#totals" + j + "_" + k).attr("data-ratio");
|
||
var percents = (ratio * 100 / max_ratio).toFixed(2);
|
||
|
||
if (!ratio) {
|
||
ratio = +$("#absolute_totals" + j).attr("data-ratio");
|
||
percents = (ratio * 100 / max_total_ratio).toFixed(2);
|
||
}
|
||
|
||
|
||
table_row += '<div class="progress bg-light ml-2 my-2" style="height:1rem;"><div class="progress-bar ';
|
||
|
||
var bg = 'bg-dark';
|
||
if (filtered_results[j].kind == 'cloud' || filtered_results[j].kind == 'vps') {
|
||
bg = 'bg-medium';
|
||
} else if (filtered_results[j].kind == 'desktop' || filtered_results[j].kind == 'laptop' || filtered_results[j].kind == 'phone') {
|
||
bg = 'bg-secondary';
|
||
}
|
||
|
||
table_row += bg + '" style="width: ' + percents + '%;"> </div></div>';
|
||
|
||
}
|
||
|
||
|
||
table_row += "</td>";
|
||
|
||
table_row += "<td class='align-middle'><strong>" + (total_ratio / min_total_ratio).toFixed(2) + "</strong></td>";
|
||
table_row += "</tr>";
|
||
table_rows.push({ data: table_row, value: total_ratio / min_total_ratio });
|
||
}
|
||
table_rows.sort(function(a, b) { return a.value - b.value; });
|
||
|
||
for (var j = 0; j < table_rows.length; j++) {
|
||
html += table_rows[j].data;
|
||
}
|
||
|
||
html += "</table>";
|
||
|
||
$('#diagram').html(html);
|
||
$('[data-toggle="tooltip"]').tooltip({
|
||
trigger: 'hover',
|
||
delay: { "show": 300, "hide": 100 }
|
||
});
|
||
}
|
||
|
||
generate_selectors($('#selectors'));
|
||
generate_comparison_table();
|
||
generate_diagram();
|