blob: 3427ae7f7b956faa886fe4de13c6c96250f37051 [file] [log] [blame]
<!DOCTYPE HTML>
<html>
<body>
<canvas width="1000" height="50" id="c" style="border:1px solid black"></canvas>
<table style="margin:1em; border:1px solid black; width:90%">
<thead style="font-weight:bold"><tr><td>Checkpoint<td>Time<td>Time to next</thead>
<tbody id="t"></tbody>
</table>
<script>
/* This script simulates the algorithm of ReplayTimeline::update_reverse_exec_checkpoints
and visualizes the results.
In this script, the ideal inter-checkpoint interval is normalized to 1.
*/
var checkpoint_interval_exponent = 2;
var checkpoints = [];
function countCheckpointsAtOrAfter(start) {
var count = 0;
for (var i = 0; i < checkpoints.length; ++i) {
if (checkpoints[i] >= start) {
++count;
}
}
return count;
}
function removeLastCheckpointInRange(x1, x2) {
var lastIndex = -1;
for (var i = 0; i < checkpoints.length; ++i) {
if (checkpoints[i] >= x1 && checkpoints[i] < x2) {
lastIndex = i;
}
}
if (lastIndex >= 0) {
checkpoints.splice(lastIndex, 1);
}
}
function discard_excess_checkpoints(now) {
var checkpoints_allowed = 0;
var checkpoints_in_range = 0;
var it = checkpoints.length - 1;
var checkpoints_to_delete = [];
for (var len = 1; ; len = checkpoint_interval_exponent*len) {
var start = now - len;
var tmp_it = it;
while (tmp_it >= 0 && checkpoints[tmp_it] >= start) {
++checkpoints_in_range;
--tmp_it;
}
while (checkpoints_in_range > checkpoints_allowed) {
checkpoints_to_delete.push(it);
--checkpoints_in_range;
--it;
}
++checkpoints_allowed;
it = tmp_it;
if (it < 0) {
break;
}
}
for (var i = 0; i < checkpoints_to_delete.length; ++i) {
checkpoints.splice(checkpoints_to_delete[i], 1);
}
}
function renderCheckpoints() {
var ctx = c.getContext('2d');
ctx.clearRect(0, 0, c.width, c.height);
ctx.fillStyle = "lime";
for (var i = 0; i < checkpoints.length; ++i) {
var x = Math.floor(checkpoints[i]);
ctx.fillRect(x, 0, 1, c.height);
}
}
var next = 0;
// Choose a random stopping point in the second half
// of the canvas.
var stopAt = (1 + Math.random())*c.width/2;
function step() {
if (next >= stopAt) {
var s = [];
for (var i = 0; i < checkpoints.length; ++i) {
s.push("<tr><td>" + i + "<td>" + checkpoints[i] + "<td>" +
((i < checkpoints.length - 1) ? checkpoints[i + 1] - checkpoints[i] : 0));
}
t.innerHTML = s.join('\n');
return;
}
discard_excess_checkpoints(next);
checkpoints.push(next);
renderCheckpoints();
// Add some jitter to reflect the fact that during replay
// we'll usually stop a bit later than the inter-checkpoint
// threshold.
next += 1 + Math.random()*0.1;
setTimeout(step, 0);
}
step();
</script>