Simulation replay profiling graph overhaul.
Support multiple graphs with different scales, units, rounding and descriptions and use it for memory allocation and number of garbage collections. Have the X axis in number of turns (instead of that divided by 20). Don't have the legend hide part of the graph. Add references to that hardcoded 20. Move graph JS to a separate JS file. Use JSON instead of JS. Add legal html structure. Comments By: Vladislav in irc yesterday This was SVN commit r21602.
This commit is contained in:
parent
fcceffb3dd
commit
ee9e677084
@ -42,6 +42,12 @@
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
|
||||
/**
|
||||
* Number of turns between two saved profiler snapshots.
|
||||
* Keep in sync with source/tools/replayprofile/graph.js
|
||||
*/
|
||||
static const int PROFILE_TURN_INTERVAL = 20;
|
||||
|
||||
CReplayLogger::CReplayLogger(const ScriptInterface& scriptInterface) :
|
||||
m_ScriptInterface(scriptInterface), m_Stream(NULL)
|
||||
{
|
||||
@ -234,13 +240,11 @@ void CReplayPlayer::Replay(bool serializationtest, int rejointestturn, bool oosl
|
||||
|
||||
g_Profiler.Frame();
|
||||
|
||||
if (turn % 20 == 0)
|
||||
if (turn % PROFILE_TURN_INTERVAL == 0)
|
||||
g_ProfileViewer.SaveToFile();
|
||||
}
|
||||
else
|
||||
{
|
||||
debug_printf("Unrecognised replay token %s\n", type.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ while (<$f>) {
|
||||
}
|
||||
}
|
||||
|
||||
print "var graphData = [\n";
|
||||
print "[\n";
|
||||
my $n = 0;
|
||||
for my $k (sort keys %s) {
|
||||
print ",\n" if $n++;
|
||||
@ -44,4 +44,4 @@ for my $k (sort keys %s) {
|
||||
}
|
||||
print "]}";
|
||||
}
|
||||
print "\n];\n";
|
||||
print "\n]\n";
|
||||
|
@ -1,61 +1,28 @@
|
||||
<!DOCTYPE html>
|
||||
<script src="jquery.js"></script>
|
||||
<script src="jquery.flot.js"></script>
|
||||
<script src="jquery.flot.navigate.js"></script>
|
||||
<script src="data.js"></script>
|
||||
<script>
|
||||
var newGraphData = [];
|
||||
for (var i = 0; i < graphData.length; ++i) {
|
||||
var d = graphData[i];
|
||||
|
||||
if (d.label == "allocated bytes" || d.label == "max nominal heap bytes" || d.label == "max JS_malloc bytes")
|
||||
d.yaxis = 2;
|
||||
|
||||
// Uninteresting:
|
||||
if (d.label == "max nominal heap bytes" || d.label == "max JS_malloc bytes" || d.label == "number of GCs" || d.label == "allocated bytes")
|
||||
continue;
|
||||
|
||||
// Bogus data:
|
||||
if (d.label == "unlogged")
|
||||
continue;
|
||||
|
||||
newGraphData.push(d);
|
||||
}
|
||||
|
||||
function showTooltip(x, y, contents) {
|
||||
$('<div id="tooltip">' + contents + '</div>').css( {
|
||||
position: 'absolute',
|
||||
top: y + 5,
|
||||
left: x + 5,
|
||||
border: '1px solid #fdd',
|
||||
padding: '2px',
|
||||
'background-color': '#fee',
|
||||
opacity: 0.80
|
||||
}).appendTo("body");
|
||||
}
|
||||
|
||||
$(function () {
|
||||
$.plot($("#placeholder"), newGraphData, {
|
||||
grid: { hoverable: true },
|
||||
zoom: { interactive: true },
|
||||
pan: { interactive: true },
|
||||
legend: { position: "nw" }
|
||||
});
|
||||
|
||||
$("#placeholder").bind("plothover", function (event, pos, item) {
|
||||
$("#tooltip").remove();
|
||||
if (item) {
|
||||
var x = item.datapoint[0].toFixed(2);
|
||||
var y = item.datapoint[1].toFixed(2);
|
||||
showTooltip(item.pageX, item.pageY, item.series.label + " at " + Math.round(x) + ": " + y);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="placeholder" style="width:1100px; height:600px;"></div>
|
||||
<p>x axis: turn number / 20
|
||||
<p>y axis (left): time per frame / msecs
|
||||
<p>y axis (right): bytes
|
||||
<p>Drag to pan, mouse-wheel to zoom
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<title>0 A.D. Simulation Profiling</title>
|
||||
<link rel="stylesheet" type="text/css" href="graph.css">
|
||||
<script src="jquery.js"></script>
|
||||
<script src="jquery.flot.js"></script>
|
||||
<script src="jquery.flot.navigate.js"></script>
|
||||
<script src="graph.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<label>Graph:
|
||||
<select id="replayGraphSelection" size="1" onchange="showReplayData()">
|
||||
<option value="time" selected="selected">Performance</option>
|
||||
<option value="bytes">Memory</option>
|
||||
<option value="garbageCollection">Garbage Collections</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div id="replayGraphLegend" style="width:300px;float:left"></div>
|
||||
<div>
|
||||
<div id="replayGraph" style="width:1100px; height:600px; float:left"></div>
|
||||
<div id="replayGraphDescription" style="float:top"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
141
source/tools/replayprofile/graph.js
Normal file
141
source/tools/replayprofile/graph.js
Normal file
@ -0,0 +1,141 @@
|
||||
/**
|
||||
* Contents of data.json
|
||||
*/
|
||||
var replayData;
|
||||
|
||||
/**
|
||||
* Number of turns between two saved profiler snapshots.
|
||||
* Keep in sync with Replay.cpp.
|
||||
*/
|
||||
var PROFILE_TURN_INTERVAL = 20;
|
||||
|
||||
/**
|
||||
* These columns are never displayed.
|
||||
*/
|
||||
var filteredColumns = [
|
||||
"sim update", // indistringuishable from Total
|
||||
"unlogged" // Bogus
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Determines how the the different graphs are formatted.
|
||||
*/
|
||||
var graphFormat = {
|
||||
"time": {
|
||||
"axisTitle": "Time per frame",
|
||||
"unit": "milliseconds",
|
||||
"digits": 2,
|
||||
"scale": 1,
|
||||
},
|
||||
"bytes": {
|
||||
"axisTitle": "Memory",
|
||||
"unit": "Megabytes",
|
||||
"digits": 2,
|
||||
"scale": 1 / 1024 / 1024,
|
||||
"isColumn": function(label) {
|
||||
return label.indexOf("bytes") != -1;
|
||||
}
|
||||
},
|
||||
"garbageCollection": {
|
||||
"axisTitle": "Number of Garbace Collections",
|
||||
"unit": "",
|
||||
"scale": 1,
|
||||
"digits": 0,
|
||||
"isColumn": function(label) {
|
||||
return label == "number of GCs";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function showReplayData()
|
||||
{
|
||||
var displayedColumn = $("#replayGraphSelection").val();
|
||||
|
||||
$.plot($("#replayGraph"), getReplayGraphData(displayedColumn), {
|
||||
"grid": {
|
||||
"hoverable": true
|
||||
},
|
||||
"zoom": {
|
||||
"interactive": true
|
||||
},
|
||||
"pan": {
|
||||
"interactive": true
|
||||
},
|
||||
"legend": {
|
||||
"container": $("#replayGraphLegend")
|
||||
}
|
||||
});
|
||||
|
||||
$("#replayGraph").bind("plothover", function (event, pos, item) {
|
||||
$("#tooltip").remove();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
showTooltip(
|
||||
item.pageX,
|
||||
item.pageY,
|
||||
displayedColumn,
|
||||
item.series.label,
|
||||
item.datapoint[0],
|
||||
item.datapoint[1].toFixed(graphFormat[displayedColumn].digits));
|
||||
});
|
||||
|
||||
$("#replayGraphDescription").html(
|
||||
"<p>X axis: Turn Number</p>" +
|
||||
"<p>Y axis: " + graphFormat[displayedColumn].axisTitle +
|
||||
(graphFormat[displayedColumn].unit ? " [" + graphFormat[displayedColumn].unit + "]" : "") + "</p>" +
|
||||
"<p>Drag to pan, mouse-wheel to zoom</p>"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the affected columns and apply the scaling and rounding.
|
||||
*/
|
||||
function getReplayGraphData(displayedColumn)
|
||||
{
|
||||
var replayGraphData = [];
|
||||
|
||||
for (var i = 0; i < replayData.length; ++i)
|
||||
{
|
||||
var label = replayData[i].label;
|
||||
|
||||
if (filteredColumns.indexOf(label) != -1 ||
|
||||
(displayedColumn == "bytes") != graphFormat.bytes.isColumn(label) ||
|
||||
(displayedColumn == "garbageCollection") != (graphFormat.garbageCollection.isColumn(label)))
|
||||
continue
|
||||
|
||||
var data = [];
|
||||
for (var j = 0; j < replayData[i].data.length; ++j)
|
||||
data.push([
|
||||
replayData[i].data[j][0] * PROFILE_TURN_INTERVAL,
|
||||
replayData[i].data[j][1] * graphFormat[displayedColumn].scale
|
||||
]);
|
||||
|
||||
replayGraphData.push({
|
||||
"label": label,
|
||||
"data": data
|
||||
});
|
||||
}
|
||||
|
||||
return replayGraphData;
|
||||
}
|
||||
|
||||
function showTooltip(x, y, displayedColumn, label, turn, value)
|
||||
{
|
||||
$("body").append(
|
||||
$('<div id="tooltip">' + label + " at turn " + turn + ": " + value + " " + graphFormat[displayedColumn].unit + "</div>").css({
|
||||
"position": "absolute",
|
||||
"top": y + 5,
|
||||
"left": x + 5,
|
||||
"border": "1px solid #fdd",
|
||||
"padding": "2px",
|
||||
"background-color": "#fee",
|
||||
"opacity": 0.8
|
||||
}));
|
||||
}
|
||||
|
||||
$.getJSON("data.json", function(data) {
|
||||
replayData = data;
|
||||
showReplayData();
|
||||
});
|
Loading…
Reference in New Issue
Block a user