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"><h3>Compare</h3>'; 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-outline-primary'; } else if (system_kinds[i] == 'desktop' || system_kinds[i] == 'laptop') { button_class = 'btn-outline-secondary'; }; html += '<button type="button" class="btn btn-sm mr-2 mb-2 ' + 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"><h3>Dataset size</h3>'; for (var i = 0; i < data_sizes.length; i++) { html += '<button type="button" class="btn btn-sm btn-outline-dark mr-2 mb-2' + (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"><h3>Run</h3>'; for (var i = 0; i < runs.length; i++) { html += '<button type="button" class="btn btn-sm btn-outline-dark mr-2 mb-2' + (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 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-primary'; } 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();