1 <!-- 2 Tracing template 3 ---------------- 4 Test_shell has an optional tracing feature. It can be enabled by running 5 with the --enable-tracing option. Tracing causes events to be dropped into 6 a trace file during runtime. 7 8 This HTML file can be used to render the output from the trace. You'll need 9 to rename your trace data to "trace_data.js" in the same directory with this 10 HTML file, and then you can visualize the trace. 11 12 Lots of work remains on this tracing tool; currently development is on hold. 13 14 --> 15 16 <html> 17 <head> 18 <title> 19 Trace Events 20 </title> 21 <style> 22 body { 23 font-family: "Courier New"; 24 font-size: 9pt; 25 } 26 27 #header { 28 position: absolute; 29 top: 0px; 30 left: 0px; 31 border-bottom: 1px dashed black; 32 background-color: #F0F0F0; 33 z-index: 3; 34 } 35 36 #outer { 37 position: relative; 38 height: 200px; 39 } 40 41 #time_scale { 42 height: 15px; 43 width: 100%; 44 } 45 46 #tooltip { 47 position: absolute; 48 background-color: #FFFFCC; 49 display: none; 50 font-family: "Courier New"; 51 font-size: 9pt; 52 padding: 5px; 53 border: 1px solid #CCCC88; 54 z-index: 3; 55 } 56 57 #legend { 58 position: fixed; 59 left: 10px; 60 bottom: 10px; 61 padding: 5px; 62 border: 1px solid silver; 63 z-index: 10; 64 background-color: #f0f0f0; 65 } 66 67 h2 { 68 margin: 5px; 69 } 70 71 #instructions { 72 position: absolute; 73 top: 74 float: right; 75 display: none; 76 } 77 78 li.time_tick { 79 background-color: #FFFFCC; 80 height: 15px; 81 } 82 83 li { 84 background: pink; 85 position: absolute; 86 height: 10px; 87 list-style: none; 88 margin: 0px; 89 padding: 0px; 90 z-index: 2; 91 } 92 93 li:hover { 94 border: 1px solid red; 95 } 96 97 .url { 98 background-color: green; 99 } 100 101 .http { 102 background-color: blue; 103 } 104 105 .socket { 106 background-color: black; 107 } 108 109 .v8 { 110 background-color: orange; 111 } 112 113 .loop { 114 background-color: gray; 115 } 116 117 .io { 118 background-color: blue; 119 } 120 121 </style> 122 123 <script src='trace_data.js'></script> 124 <script> 125 var scale = 100000; 126 var row_height = 15; 127 var trace_initial_time = 0; 128 var trace_threads = {}; 129 var heartbeats = []; 130 var trace_total_time = 0; 131 132 function process_raw_events() { 133 trace_initial_time = raw_trace_events[0].usec_begin; 134 var stack = []; 135 var e; 136 for (var i in raw_trace_events) { 137 e = raw_trace_events[i]; 138 var trace_events = trace_threads["e.tid"]; 139 if (!trace_events) { 140 trace_events = []; 141 trace_threads["e.tid"] = trace_events; 142 } 143 if (e.name.indexOf("heartbeat.") == 0) { 144 heartbeats.push(e); 145 } else if (e.type == "BEGIN") { 146 trace_events.push(e); 147 stack.unshift(e); 148 } else if (e.type == "END") { 149 for (var s in stack) { 150 var begin = stack[s]; 151 if ((begin.id == e.id) && (begin.name == e.name) && 152 (begin.pid == e.pid) && (begin.tid == e.tid)) { 153 begin.usec_end = e.usec_begin; 154 begin.duration = begin.usec_end - begin.usec_begin; 155 begin.extra += " " + e.extra; 156 stack.splice(s, 1); 157 break; 158 } 159 } 160 } else if (e.type == "INSTANT") { 161 trace_events.push(e); 162 e.duration = 0; 163 } 164 } 165 if (e.usec_end) 166 trace_total_time = e.usec_end - trace_initial_time; 167 else 168 trace_total_time = e.usec_begin - trace_initial_time; 169 } 170 171 function compute_scale() { 172 var outer = document.getElementById("outer"); 173 scale = Math.floor(trace_total_time / (outer.offsetWidth - (row_height * 2))); 174 }; 175 176 function show_details(tid, i, event) { 177 var trace_events = trace_threads["e.tid"]; 178 var inner = trace_events[i].name + " " + 179 trace_events[i].duration / 1000 + "ms<br />" + 180 trace_events[i].id + "<br />" + 181 trace_events[i].extra + "<br />"; 182 var tooltip = document.getElementById("tooltip"); 183 tooltip.innerHTML = inner; 184 if (window.event) 185 event = window.event; 186 tooltip.style.top = event.pageY + 3; 187 tooltip.style.left = event.pageX + 3; 188 tooltip.style.display = "block"; 189 }; 190 191 function generate_time_scale() { 192 var view_size = window.clientWidth; 193 var body_size = document.body.scrollWidth; 194 var inner = ""; 195 196 var step_ms = Math.floor(scale / 10); // ms per 100px 197 var pow10 = Math.pow(10, Math.floor(Math.log(step_ms) / Math.log(10))); 198 var round = .5 * pow10; 199 step_ms = round * (Math.floor(step_ms / round)); // round to a multiple of round 200 for (var i = step_ms; i < trace_total_time / 1000; i += step_ms) { 201 var x = Math.floor(i * 1000 / scale); 202 inner += "<li class='time_tick' style='left: " + x + "px'>" + i + "</li>"; 203 } 204 var time_scale = document.getElementById("time_scale"); 205 time_scale.innerHTML = inner; 206 time_scale.style.width = document.body.scrollWidth; 207 } 208 209 function generate_io_graph(trace_events, top) { 210 var max_height = 200; 211 var bucket_size = 50000; // millisecs 212 213 var inner = ""; 214 var buckets = new Array(); 215 var value = 0; 216 var max_bucket = 0; 217 218 // Go through events and find all read samples. 219 // Aggregate data into buckets. 220 for (var i in trace_events) { 221 var e = trace_events[i]; 222 if (e.name != "socket.read") { 223 continue; 224 } 225 226 var bytes = parseInt(e.extra); 227 // bytes = 400; 228 229 var start_time = e.usec_begin - trace_initial_time; 230 var mybucket = Math.floor(start_time / bucket_size); 231 232 if (buckets[mybucket] == undefined) { 233 buckets[mybucket] = 0; 234 } 235 buckets[mybucket] += bytes; 236 237 if (buckets[max_bucket] == undefined || 238 buckets[max_bucket] < buckets[mybucket]) { 239 max_bucket = mybucket; 240 } 241 } 242 243 for (var index = 0; index < buckets.length; index++) { 244 var left = index * Math.floor(bucket_size / scale); 245 var width = Math.floor(bucket_size / scale); 246 if (width == 0) 247 width = 1; 248 249 var height; 250 if (buckets[index] == undefined) { 251 height = 0; 252 } else { 253 height = (buckets[index] / buckets[max_bucket]) * max_height; 254 } 255 256 var my_top = max_height - height; 257 258 var style = "top: " + my_top + "px; left: " + left + "px; width: " + width + "px; height:" + height + "px;"; 259 var cls = "io"; 260 inner += "<li title='" + buckets[index] + " bytes' class='" + cls + "' id='li-" + i + "' style='" + style + "'></li>\n"; 261 } 262 263 var subchart = document.createElement('div'); 264 subchart.setAttribute("class", "iograph"); 265 subchart.setAttribute("id", trace_events[0].tid); 266 subchart.innerHTML = inner; 267 subchart.style.height = max_height; 268 subchart.style.top = top; 269 subchart.style.left = 0; 270 subchart.style.position = "absolute"; 271 // subchart.style.width = row_height + last_max_x; 272 var chart = document.getElementById("chart"); 273 chart.appendChild(subchart); 274 275 return top + max_height; 276 } 277 278 function generate_subchart(trace_events, top) { 279 var start_top = top; 280 var heights = new Array(); 281 var max_row = 0; 282 var inner = ""; 283 var last_max_time = 0; 284 var last_max_x = 0; 285 for (var i in trace_events) { 286 var e = trace_events[i]; 287 var start_time = e.usec_begin - trace_initial_time; 288 var left = row_height + Math.floor(start_time / scale); 289 var width = Math.floor(e.duration / scale); 290 if (width == 0) 291 width = 1; 292 293 if (heights[e.id]) { 294 top = heights[e.id]; 295 } else { 296 max_row += row_height; 297 heights[e.id] = max_row; 298 top = heights[e.id]; 299 } 300 //if (start_time < last_max_time) 301 // top += row_height; 302 var style = "top: " + top + "px; left: " + left + "px; width: " + width + "px;"; 303 var js = 'javascript:show_details("' + e.tid + '", ' + i + ', event);'; 304 var cls = e.name.split('.')[0]; 305 inner += "<li class='" + cls + "' onmouseover='" + js + "' id='li-" + i + "' style='" + style + "'></li>\n"; 306 last_max_time = start_time + e.duration; 307 last_max_x = left + width; 308 } 309 var subchart = document.createElement('div'); 310 subchart.setAttribute("class", "subchart"); 311 subchart.setAttribute("id", trace_events[0].tid); 312 subchart.innerHTML = inner; 313 subchart.style.top = start_top + "px"; 314 subchart.style.height = top + row_height; 315 subchart.style.width = row_height + last_max_x; 316 subchart.style.position = "absolute"; 317 var chart = document.getElementById("chart"); 318 chart.appendChild(subchart); 319 320 return top; 321 }; 322 323 function generate_chart() { 324 var chart = document.getElementById("chart"); 325 chart.innerHTML = ""; 326 var top = 60; 327 for (var t in trace_threads) { 328 top = generate_io_graph(trace_threads[t], top); 329 top = generate_subchart(trace_threads[t], top); 330 } 331 generate_time_scale(); 332 } 333 334 function change_scale(event) { 335 if (!event) 336 event = window.event; 337 if (!event.shiftKey) 338 return; 339 var delta = 0; 340 if (event.wheelDelta) { 341 delta = event.wheelDelta / 120; 342 } else if (event.detail) { 343 delta = - event.detail / 3; 344 } 345 if (delta) { 346 var tooltip = document.getElementById("tooltip"); 347 tooltip.style.display = "none"; 348 var factor = 1.1; 349 if (delta < 0) 350 scale = Math.floor(scale * factor); 351 else 352 scale = Math.floor(scale / factor); 353 if (scale > 300000) 354 scale = 300000; 355 generate_chart(); 356 if (event.preventDefault) 357 event.preventDefault(); 358 } 359 event.returnValue = false; 360 }; 361 362 function initial_load() { 363 if (window.addEventListener) 364 window.addEventListener('DOMMouseScroll', change_scale, false); 365 window.onmousewheel = document.onmousewheel = change_scale; 366 367 process_raw_events(); 368 compute_scale(); 369 generate_chart(); 370 }; 371 372 </script> 373 </head> 374 <body onload='initial_load();'> 375 <div id="header"> 376 <h2>Trace Events</h2> 377 <div id="instructions"> 378 Use shift+mouse-wheel to zoom in and out. 379 </div> 380 <div id="time_scale"></div> 381 </div> 382 <div id="legend"> 383 <span class="url"> </span> URL<br /> 384 <span class="http"> </span> HTTP<br /> 385 <span class="socket"> </span> Socket<br /> 386 <span class="v8"> </span> V8<br /> 387 <span class="loop"> </span> TASKS<br /> 388 </div> 389 <div id="chart"> 390 <div id="outer"> 391 </div> 392 </div> 393 <div id="tooltip" ondblclick="this.style.display = 'none';"></div> 394 </body> 395 </html> 396