Home | History | Annotate | Download | only in tracing
      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">&nbsp;</span> URL<br />
    384 <span class="http">&nbsp;</span> HTTP<br />
    385 <span class="socket">&nbsp;</span> Socket<br />
    386 <span class="v8">&nbsp;</span> V8<br />
    387 <span class="loop">&nbsp;</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