| <!-- |
| 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> |