1<!-- 2Tracing template 3---------------- 4Test_shell has an optional tracing feature. It can be enabled by running 5with the --enable-tracing option. Tracing causes events to be dropped into 6a trace file during runtime. 7 8This HTML file can be used to render the output from the trace. You'll need 9to rename your trace data to "trace_data.js" in the same directory with this 10HTML file, and then you can visualize the trace. 11 12Lots of work remains on this tracing tool; currently development is on hold. 13 14--> 15 16<html> 17<head> 18<title> 19Trace Events 20</title> 21<style> 22body { 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 67h2 { 68 margin: 5px; 69} 70 71#instructions { 72 position: absolute; 73 top: 74 float: right; 75 display: none; 76} 77 78li.time_tick { 79 background-color: #FFFFCC; 80 height: 15px; 81} 82 83li { 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 93li: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> 125var scale = 100000; 126var row_height = 15; 127var trace_initial_time = 0; 128var trace_threads = {}; 129var heartbeats = []; 130var trace_total_time = 0; 131 132function 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 171function compute_scale() { 172 var outer = document.getElementById("outer"); 173 scale = Math.floor(trace_total_time / (outer.offsetWidth - (row_height * 2))); 174}; 175 176function 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 191function 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 209function 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 278function 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 323function 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 334function 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 362function 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"> 378Use 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