<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; } </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; 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_subchart(trace_events, top) { 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 (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.height = top + row_height; subchart.style.width = row_height + last_max_x; 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_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 /> </div> <div id="chart"> <div id="outer"> </div> </div> <div id="tooltip" ondblclick="this.style.display = 'none';"></div> </body> </html>