This way it's possible to see side-by-side results of CPU and GPU time on "fast" scenes, without having Victor scene making bars for bmw really tiny.
257 lines
8.2 KiB
JavaScript
257 lines
8.2 KiB
JavaScript
// Generate unique looking color for a given bar index.
|
|
function generateBarColor(index) {
|
|
var builtin_colors = [[255, 99, 132],
|
|
[255, 159, 64],
|
|
[255, 205, 86],
|
|
[75, 192, 192],
|
|
[54, 162, 235],
|
|
[153, 102, 255],
|
|
[201, 203, 207],
|
|
[48, 103, 204],
|
|
[220, 56, 18],
|
|
[254, 155, 0],
|
|
[15, 147, 25]];
|
|
var color = [0, 0, 0];
|
|
if (index >= 0 && index < builtin_colors.length) {
|
|
color = builtin_colors[index];
|
|
}
|
|
return "rgb(" + color[0].toString() + ", " +
|
|
color[1].toString() + ", " +
|
|
color[2].toString() + ")";
|
|
}
|
|
|
|
function clone(object) {
|
|
return jQuery.extend(true, {}, object);
|
|
}
|
|
|
|
function padValue(value, size) {
|
|
var s = String(value);
|
|
while (s.length < (size || 2)) {
|
|
s = "0" + s;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
function secondsToHumanReadable(seconds) {
|
|
var h = Math.floor((seconds %= 86400) / 3600);
|
|
var m = Math.floor((seconds %= 3600) / 60);
|
|
var s = Math.floor(seconds % 60);
|
|
var msec = Math.floor((seconds % 60) % 1 * 100);
|
|
var result = "";
|
|
if (h != 0) {
|
|
result += h + ":";
|
|
}
|
|
result += padValue(m, 2) + ":";
|
|
result += padValue(s, 2) + ".";
|
|
result += padValue(msec, 2);
|
|
return result;
|
|
}
|
|
|
|
function setDatasetColor(data, is_bar) {
|
|
var index = 0;
|
|
for (dataset of data.datasets) {
|
|
var color = Chart.helpers.color(generateBarColor(index));
|
|
dataset.backgroundColor = color.alpha(0.5).rgbString();
|
|
dataset.borderColor = color.alpha(1.0).rgbString();
|
|
if (is_bar) {
|
|
dataset.borderWidth = 1;
|
|
} else {
|
|
dataset.fill = false;
|
|
}
|
|
index++;
|
|
}
|
|
}
|
|
|
|
function findDatasetMaxValue(data) {
|
|
var max_value = 0;
|
|
for (dataset of data.datasets) {
|
|
for (value of dataset.data) {
|
|
if (value === null) {
|
|
continue;
|
|
}
|
|
if (typeof value !== "number") {
|
|
value = value.y;
|
|
}
|
|
max_value = Math.max(max_value, value);
|
|
}
|
|
}
|
|
return max_value;
|
|
}
|
|
|
|
function buildChart(ctx, bare_data) {
|
|
var data = clone(bare_data);
|
|
setDatasetColor(data, true);
|
|
var my_chart = new Chart(
|
|
ctx,
|
|
{
|
|
type: 'bar',
|
|
data: data,
|
|
options: { responsive: true,
|
|
legend: {position: 'top'},
|
|
title: {display: true,
|
|
text: 'Benchmark Results'},
|
|
scales: {xAxes: [{display: true,
|
|
scaleLabel: {display: true,
|
|
labelString: 'Scene'}}],
|
|
yAxes: [{display: true,
|
|
scaleLabel: {display: true,
|
|
labelString: 'Render time (sec)'},
|
|
ticks: {min: 0}}]},
|
|
tooltips: {// mode: 'index',
|
|
callbacks: {
|
|
footer: function(tooltipItems, data) {
|
|
var human_time = "";
|
|
tooltipItems.forEach(
|
|
function(tooltipItem) {
|
|
var render_time = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
|
|
human_time = secondsToHumanReadable(render_time);
|
|
}
|
|
);
|
|
if (human_time != "") {
|
|
return "Render Time: " + human_time;
|
|
}
|
|
return "";
|
|
},
|
|
},
|
|
filter: function(item, data) {
|
|
var data = data.datasets[item.datasetIndex].data[item.index];
|
|
return !isNaN(data) && data !== null;
|
|
},
|
|
footerFontStyle: 'normal'},
|
|
}
|
|
});
|
|
// TODO(sergey): How can we avoid storing chart in some obscure global variable?
|
|
window.my_chart = my_chart;
|
|
}
|
|
|
|
function updateEnabledScenesCallback(bare_data) {
|
|
/* Collect list of enabled scenes. */
|
|
var enabled_scenes = [];
|
|
var disabled_scenes = [];
|
|
var scene_index = 0;
|
|
for (scene_name of bare_data.labels) {
|
|
var id = "scene_" + scene_name + "_id";
|
|
var checkbox = document.getElementById(id);
|
|
if (checkbox.checked) {
|
|
enabled_scenes.push({"index": scene_index, "name": scene_name});
|
|
} else {
|
|
disabled_scenes.push({"index": scene_index, "name": scene_name});
|
|
}
|
|
++scene_index;
|
|
}
|
|
/* Construct new data by making a copy of original one and removing
|
|
* disabeld scenes.
|
|
*
|
|
* Note: we reverse te list so indices for removal are alweays staying
|
|
* the same.
|
|
*/
|
|
disabled_scenes.reverse();
|
|
var updated_data = clone(bare_data);
|
|
setDatasetColor(updated_data, true);
|
|
for (scene of disabled_scenes) {
|
|
// Remove label first.
|
|
updated_data.labels.splice(scene.index, 1);
|
|
updated_data.datasets.forEach(function(dataset, dataset_index) {
|
|
dataset.data.splice(scene.index, 1);
|
|
});
|
|
}
|
|
/* Update the actual chart. */
|
|
var my_chart = window.my_chart;
|
|
my_chart.data = updated_data;
|
|
my_chart.update();
|
|
}
|
|
|
|
function buildScenesSelector(ctx, bare_data) {
|
|
var div = document.createElement("div");
|
|
div.className = "scene_selector_container";
|
|
for (scene_name of data.labels) {
|
|
var span = document.createElement("span");
|
|
|
|
var checkbox = document.createElement('input');
|
|
checkbox.type = "checkbox";
|
|
checkbox.name = "scene_" + scene_name;
|
|
checkbox.checked = true;
|
|
checkbox.id = "scene_" + scene_name + "_id";
|
|
checkbox.onclick = function() { updateEnabledScenesCallback(bare_data); };
|
|
span.appendChild(checkbox);
|
|
|
|
var label = document.createElement('label');
|
|
label.htmlFor = "scene_" + scene_name + "_id";
|
|
label.appendChild(document.createTextNode(scene_name));
|
|
span.appendChild(label);
|
|
|
|
div.appendChild(span);
|
|
}
|
|
ctx.appendChild(div);
|
|
}
|
|
|
|
function historyChartGetSceneStats(bare_data, scene_name) {
|
|
var datasets = [];
|
|
for (dataset of bare_data.datasets) {
|
|
if (dataset.scene_name != scene_name) {
|
|
continue;
|
|
}
|
|
datasets.push({"data": dataset.data,
|
|
"label": dataset.device_name});
|
|
}
|
|
return {"datasets": datasets};
|
|
}
|
|
|
|
function buildHistoryChart(ctx, bare_data, scene_name) {
|
|
var data = historyChartGetSceneStats(bare_data, scene_name);
|
|
setDatasetColor(data, false);
|
|
new Chart(
|
|
ctx,
|
|
{
|
|
type: 'line',
|
|
data: data,
|
|
options: { responsive: true,
|
|
legend: {position: 'top'},
|
|
title: {display: true,
|
|
text: scene_name + ' benchmark results'},
|
|
scales: {xAxes: [{type: "time",
|
|
time: {format: 'DD/MM/YYYY HH:mm',
|
|
tooltipFormat: 'll HH:mm'},
|
|
scaleLabel: {display: true,
|
|
labelString: 'Date'}},],
|
|
yAxes: [{display: true,
|
|
scaleLabel: {display: true,
|
|
labelString: 'Render time (sec)'},
|
|
ticks: {min: 0}}]},
|
|
|
|
elements: { line: { tension: 0.000001 } },
|
|
}
|
|
});
|
|
}
|
|
|
|
function buildSpreadsheet(ctx, data) {
|
|
// Generate columns for header.
|
|
var columns = [{label: "", name: "", width: 300}];
|
|
for (label of data.labels) {
|
|
columns.push({label: label, name: label});
|
|
}
|
|
// Generate actual data.
|
|
var rows = [];
|
|
for (dataset of data.datasets) {
|
|
var row = [dataset.label];
|
|
for (value of dataset.data) {
|
|
if (value == null) {
|
|
row.push("");
|
|
} else {
|
|
row.push(secondsToHumanReadable(value));
|
|
}
|
|
}
|
|
rows.push(row);
|
|
}
|
|
// Create actual table.
|
|
$(ctx).jqGrid({
|
|
data: rows,
|
|
localReader: {repeatitems: true},
|
|
datatype: "local",
|
|
styleUI : 'Bootstrap',
|
|
colModel: columns,
|
|
caption: "Spreadsheet",
|
|
height: 300,
|
|
});
|
|
}
|