<!--
Tracing template
----------------
Test_shell has an optional tracing feature. It can be enabled by running
with the --enable-tracing option. Tracing causes events to be dropped into
a trace file during runtime.
This HTML file can be used to render the output from the trace. You'll need
to rename your trace data to "trace_data.js" in the same directory with this
HTML file, and then you can visualize the trace.
Lots of work remains on this tracing tool; currently development is on hold.
-->
<html>
<head>
<title>
Trace Events
</title>
<style>
body {
font-family: "Courier New";
font-size: 9pt;
}
#header {
position: absolute;
top: 0px;
left: 0px;
border-bottom: 1px dashed black;
background-color: #F0F0F0;
z-index: 3;
}
#outer {
position: relative;
height: 200px;
}
#time_scale {
height: 15px;
width: 100%;
}
#tooltip {
position: absolute;
background-color: #FFFFCC;
display: none;
font-family: "Courier New";
font-size: 9pt;
padding: 5px;
border: 1px solid #CCCC88;
z-index: 3;
}
#legend {
position: fixed;
left: 10px;
bottom: 10px;
padding: 5px;
border: 1px solid silver;
z-index: 10;
background-color: #f0f0f0;
}
h2 {
margin: 5px;
}
#instructions {
position: absolute;
top:
float: right;
display: none;
}
li.time_tick {
background-color: #FFFFCC;
height: 15px;
}
li {
background: pink;
position: absolute;
height: 10px;
list-style: none;
margin: 0px;
padding: 0px;
z-index: 2;
}
li:hover {
border: 1px solid red;
}
.url {
background-color: green;
}
.http {
background-color: blue;
}
.socket {
background-color: black;
}
.v8 {
background-color: orange;
}
.loop {
background-color: gray;
}
.io {
background-color: blue;
}
</style>
<script src='trace_data.js'></script>
<script>
var scale = 100000;
var row_height = 15;
var trace_initial_time = 0;
var trace_threads = {};
var heartbeats = [];
var trace_total_time = 0;
function process_raw_events() {
trace_initial_time = raw_trace_events[0].usec_begin;
var stack = [];
var e;
for (var i in raw_trace_events) {
e = raw_trace_events[i];
var trace_events = trace_threads["e.tid"];
if (!trace_events) {
trace_events = [];
trace_threads["e.tid"] = trace_events;
}
if (e.name.indexOf("heartbeat.") == 0) {
heartbeats.push(e);
} else if (e.type == "BEGIN") {
trace_events.push(e);
stack.unshift(e);
} else if (e.type == "END") {
for (var s in stack) {
var begin = stack[s];
if ((begin.id == e.id) && (begin.name == e.name) &&
(begin.pid == e.pid) && (begin.tid == e.tid)) {
begin.usec_end = e.usec_begin;
begin.duration = begin.usec_end - begin.usec_begin;
begin.extra += " " + e.extra;
stack.splice(s, 1);
break;
}
}
} else if (e.type == "INSTANT") {
trace_events.push(e);
e.duration = 0;
}
}
if (e.usec_end)
trace_total_time = e.usec_end - trace_initial_time;
else
trace_total_time = e.usec_begin - trace_initial_time;
}
function compute_scale() {
var outer = document.getElementById("outer");
scale = Math.floor(trace_total_time / (outer.offsetWidth - (row_height * 2)));
};
function show_details(tid, i, event) {
var trace_events = trace_threads["e.tid"];
var inner = trace_events[i].name + " " +
trace_events[i].duration / 1000 + "ms<br />" +
trace_events[i].id + "<br />" +
trace_events[i].extra + "<br />";
var tooltip = document.getElementById("tooltip");
tooltip.innerHTML = inner;
if (window.event)
event = window.event;
tooltip.style.top = event.pageY + 3;
tooltip.style.left = event.pageX + 3;
tooltip.style.display = "block";
};
function generate_time_scale() {
var view_size = window.clientWidth;
var body_size = document.body.scrollWidth;
var inner = "";
var step_ms = Math.floor(scale / 10); // ms per 100px
var pow10 = Math.pow(10, Math.floor(Math.log(step_ms) / Math.log(10)));
var round = .5 * pow10;
step_ms = round * (Math.floor(step_ms / round)); // round to a multiple of round
for (var i = step_ms; i < trace_total_time / 1000; i += step_ms) {
var x = Math.floor(i * 1000 / scale);
inner += "<li class='time_tick' style='left: " + x + "px'>" + i + "</li>";
}
var time_scale = document.getElementById("time_scale");
time_scale.innerHTML = inner;
time_scale.style.width = document.body.scrollWidth;
}
function generate_io_graph(trace_events, top) {
var max_height = 200;
var bucket_size = 50000; // millisecs
var inner = "";
var buckets = new Array();
var value = 0;
var max_bucket = 0;
// Go through events and find all read samples.
// Aggregate data into buckets.
for (var i in trace_events) {
var e = trace_events[i];
if (e.name != "socket.read") {
continue;
}
var bytes = parseInt(e.extra);
// bytes = 400;
var start_time = e.usec_begin - trace_initial_time;
var mybucket = Math.floor(start_time / bucket_size);
if (buckets[mybucket] == undefined) {
buckets[mybucket] = 0;
}
buckets[mybucket] += bytes;
if (buckets[max_bucket] == undefined ||
buckets[max_bucket] < buckets[mybucket]) {
max_bucket = mybucket;
}
}
for (var index = 0; index < buckets.length; index++) {
var left = index * Math.floor(bucket_size / scale);
var width = Math.floor(bucket_size / scale);
if (width == 0)
width = 1;
var height;
if (buckets[index] == undefined) {
height = 0;
} else {
height = (buckets[index] / buckets[max_bucket]) * max_height;
}
var my_top = max_height - height;
var style = "top: " + my_top + "px; left: " + left + "px; width: " + width + "px; height:" + height + "px;";
var cls = "io";
inner += "<li title='" + buckets[index] + " bytes' class='" + cls + "' id='li-" + i + "' style='" + style + "'></li>\n";
}
var subchart = document.createElement('div');
subchart.setAttribute("class", "iograph");
subchart.setAttribute("id", trace_events[0].tid);
subchart.innerHTML = inner;
subchart.style.height = max_height;
subchart.style.top = top;
subchart.style.left = 0;
subchart.style.position = "absolute";
// subchart.style.width = row_height + last_max_x;
var chart = document.getElementById("chart");
chart.appendChild(subchart);
return top + max_height;
}
function generate_subchart(trace_events, top) {
var start_top = top;
var heights = new Array();
var max_row = 0;
var inner = "";
var last_max_time = 0;
var last_max_x = 0;
for (var i in trace_events) {
var e = trace_events[i];
var start_time = e.usec_begin - trace_initial_time;
var left = row_height + Math.floor(start_time / scale);
var width = Math.floor(e.duration / scale);
if (width == 0)
width = 1;
if (heights[e.id]) {
top = heights[e.id];
} else {
max_row += row_height;
heights[e.id] = max_row;
top = heights[e.id];
}
//if (start_time < last_max_time)
// top += row_height;
var style = "top: " + top + "px; left: " + left + "px; width: " + width + "px;";
var js = 'javascript:show_details("' + e.tid + '", ' + i + ', event);';
var cls = e.name.split('.')[0];
inner += "<li class='" + cls + "' onmouseover='" + js + "' id='li-" + i + "' style='" + style + "'></li>\n";
last_max_time = start_time + e.duration;
last_max_x = left + width;
}
var subchart = document.createElement('div');
subchart.setAttribute("class", "subchart");
subchart.setAttribute("id", trace_events[0].tid);
subchart.innerHTML = inner;
subchart.style.top = start_top + "px";
subchart.style.height = top + row_height;
subchart.style.width = row_height + last_max_x;
subchart.style.position = "absolute";
var chart = document.getElementById("chart");
chart.appendChild(subchart);
return top;
};
function generate_chart() {
var chart = document.getElementById("chart");
chart.innerHTML = "";
var top = 60;
for (var t in trace_threads) {
top = generate_io_graph(trace_threads[t], top);
top = generate_subchart(trace_threads[t], top);
}
generate_time_scale();
}
function change_scale(event) {
if (!event)
event = window.event;
if (!event.shiftKey)
return;
var delta = 0;
if (event.wheelDelta) {
delta = event.wheelDelta / 120;
} else if (event.detail) {
delta = - event.detail / 3;
}
if (delta) {
var tooltip = document.getElementById("tooltip");
tooltip.style.display = "none";
var factor = 1.1;
if (delta < 0)
scale = Math.floor(scale * factor);
else
scale = Math.floor(scale / factor);
if (scale > 300000)
scale = 300000;
generate_chart();
if (event.preventDefault)
event.preventDefault();
}
event.returnValue = false;
};
function initial_load() {
if (window.addEventListener)
window.addEventListener('DOMMouseScroll', change_scale, false);
window.onmousewheel = document.onmousewheel = change_scale;
process_raw_events();
compute_scale();
generate_chart();
};
</script>
</head>
<body onload='initial_load();'>
<div id="header">
<h2>Trace Events</h2>
<div id="instructions">
Use shift+mouse-wheel to zoom in and out.
</div>
<div id="time_scale"></div>
</div>
<div id="legend">
<span class="url"> </span> URL<br />
<span class="http"> </span> HTTP<br />
<span class="socket"> </span> Socket<br />
<span class="v8"> </span> V8<br />
<span class="loop"> </span> TASKS<br />
</div>
<div id="chart">
<div id="outer">
</div>
</div>
<div id="tooltip" ondblclick="this.style.display = 'none';"></div>
</body>
</html>