OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 23 matching lines...) Expand all Loading... |
34 function PlotScriptComposer(kResX, kResY) { | 34 function PlotScriptComposer(kResX, kResY) { |
35 // Constants. | 35 // Constants. |
36 var kV8BinarySuffixes = ["/d8", "/libv8.so"]; | 36 var kV8BinarySuffixes = ["/d8", "/libv8.so"]; |
37 var kStackFrames = 8; // Stack frames to display in the plot. | 37 var kStackFrames = 8; // Stack frames to display in the plot. |
38 | 38 |
39 var kTimerEventWidth = 0.33; // Width of each timeline. | 39 var kTimerEventWidth = 0.33; // Width of each timeline. |
40 var kExecutionFrameWidth = 0.2; // Width of the top stack frame line. | 40 var kExecutionFrameWidth = 0.2; // Width of the top stack frame line. |
41 var kStackFrameWidth = 0.1; // Width of the lower stack frame lines. | 41 var kStackFrameWidth = 0.1; // Width of the lower stack frame lines. |
42 var kGapWidth = 0.05; // Gap between stack frame lines. | 42 var kGapWidth = 0.05; // Gap between stack frame lines. |
43 | 43 |
44 var kY1Offset = 10; // Offset for stack frame vs. event lines. | 44 var kY1Offset = 11; // Offset for stack frame vs. event lines. |
| 45 var kDeoptRow = 7; // Row displaying deopts. |
| 46 var kMaxDeoptLength = 4; // Draw size of the largest deopt. |
45 var kPauseLabelPadding = 5; // Padding for pause time labels. | 47 var kPauseLabelPadding = 5; // Padding for pause time labels. |
46 var kNumPauseLabels = 7; // Number of biggest pauses to label. | 48 var kNumPauseLabels = 7; // Number of biggest pauses to label. |
47 var kCodeKindLabelPadding = 100; // Padding for code kind labels. | 49 var kCodeKindLabelPadding = 100; // Padding for code kind labels. |
48 | 50 |
49 var kTickHalfDuration = 0.5; // Duration of half a tick in ms. | 51 var kTickHalfDuration = 0.5; // Duration of half a tick in ms. |
50 var kMinRangeLength = 0.0005; // Minimum length for an event in ms. | 52 var kMinRangeLength = 0.0005; // Minimum length for an event in ms. |
51 | 53 |
52 var kNumThreads = 2; // Number of threads. | 54 var kNumThreads = 2; // Number of threads. |
53 var kExecutionThreadId = 0; // ID of main thread. | 55 var kExecutionThreadId = 0; // ID of main thread. |
54 | 56 |
| 57 // Init values. |
| 58 var num_timer_event = kY1Offset + 0.5; |
| 59 |
55 // Data structures. | 60 // Data structures. |
56 function TimerEvent(label, color, pause, thread_id) { | 61 function TimerEvent(label, color, pause, thread_id) { |
57 assert(thread_id >= 0 && thread_id < kNumThreads, "invalid thread id"); | 62 assert(thread_id >= 0 && thread_id < kNumThreads, "invalid thread id"); |
58 this.label = label; | 63 this.label = label; |
59 this.color = color; | 64 this.color = color; |
60 this.pause = pause; | 65 this.pause = pause; |
61 this.ranges = []; | 66 this.ranges = []; |
62 this.thread_id = thread_id; | 67 this.thread_id = thread_id; |
63 this.index = ++num_timer_event; | 68 this.index = ++num_timer_event; |
64 } | 69 } |
65 | 70 |
66 function CodeKind(color, kinds) { | 71 function CodeKind(color, kinds) { |
67 this.color = color; | 72 this.color = color; |
68 this.in_execution = []; | 73 this.in_execution = []; |
69 this.stack_frames = []; | 74 this.stack_frames = []; |
70 for (var i = 0; i < kStackFrames; i++) this.stack_frames.push([]); | 75 for (var i = 0; i < kStackFrames; i++) this.stack_frames.push([]); |
71 this.kinds = kinds; | 76 this.kinds = kinds; |
72 } | 77 } |
73 | 78 |
74 function Range(start, end) { | 79 function Range(start, end) { |
75 // Everthing here are in milliseconds. | 80 this.start = start; // In milliseconds. |
76 this.start = start; | 81 this.end = end; // In milliseconds. |
77 this.end = end; | 82 } |
| 83 |
| 84 function Deopt(time, size) { |
| 85 this.time = time; // In milliseconds. |
| 86 this.size = size; // In bytes. |
78 } | 87 } |
79 | 88 |
80 Range.prototype.duration = function() { return this.end - this.start; } | 89 Range.prototype.duration = function() { return this.end - this.start; } |
81 | 90 |
82 function Tick(tick) { | 91 function Tick(tick) { |
83 this.tick = tick; | 92 this.tick = tick; |
84 } | 93 } |
85 | 94 |
86 // Init values. | |
87 var num_timer_event = kY1Offset + 0.5; | |
88 | |
89 var TimerEvents = { | 95 var TimerEvents = { |
90 'V8.Execute': | 96 'V8.Execute': |
91 new TimerEvent("execution", "#000000", false, 0), | 97 new TimerEvent("execution", "#000000", false, 0), |
92 'V8.External': | 98 'V8.External': |
93 new TimerEvent("external", "#3399FF", false, 0), | 99 new TimerEvent("external", "#3399FF", false, 0), |
94 'V8.CompileFullCode': | 100 'V8.CompileFullCode': |
95 new TimerEvent("compile unopt", "#CC0000", true, 0), | 101 new TimerEvent("compile unopt", "#CC0000", true, 0), |
96 'V8.RecompileSynchronous': | 102 'V8.RecompileSynchronous': |
97 new TimerEvent("recompile sync", "#CC0044", true, 0), | 103 new TimerEvent("recompile sync", "#CC0044", true, 0), |
98 'V8.RecompileParallel': | 104 'V8.RecompileParallel': |
(...skipping 21 matching lines...) Expand all Loading... |
120 'opt code ': new CodeKind("#00EE00", [1]), | 126 'opt code ': new CodeKind("#00EE00", [1]), |
121 'code stub': new CodeKind("#FF00FF", [2]), | 127 'code stub': new CodeKind("#FF00FF", [2]), |
122 'built-in ': new CodeKind("#AA00AA", [3]), | 128 'built-in ': new CodeKind("#AA00AA", [3]), |
123 'inl.cache': new CodeKind("#4444AA", | 129 'inl.cache': new CodeKind("#4444AA", |
124 [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]), | 130 [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]), |
125 'reg.exp. ': new CodeKind("#0000FF", [15]), | 131 'reg.exp. ': new CodeKind("#0000FF", [15]), |
126 }; | 132 }; |
127 | 133 |
128 var code_map = new CodeMap(); | 134 var code_map = new CodeMap(); |
129 var execution_pauses = []; | 135 var execution_pauses = []; |
| 136 var deopts = []; |
130 var event_stack = []; | 137 var event_stack = []; |
131 var last_time_stamp = []; | 138 var last_time_stamp = []; |
132 for (var i = 0; i < kNumThreads; i++) { | 139 for (var i = 0; i < kNumThreads; i++) { |
133 event_stack[i] = []; | 140 event_stack[i] = []; |
134 last_time_stamp[i] = -1; | 141 last_time_stamp[i] = -1; |
135 } | 142 } |
136 | 143 |
137 var range_start = undefined; | 144 var range_start = undefined; |
138 var range_end = undefined; | 145 var range_end = undefined; |
139 var obj_index = 0; | 146 var obj_index = 0; |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
305 }; | 312 }; |
306 | 313 |
307 var processCodeMoveEvent = function(from, to) { | 314 var processCodeMoveEvent = function(from, to) { |
308 code_map.moveCode(from, to); | 315 code_map.moveCode(from, to); |
309 }; | 316 }; |
310 | 317 |
311 var processCodeDeleteEvent = function(address) { | 318 var processCodeDeleteEvent = function(address) { |
312 code_map.deleteCode(address); | 319 code_map.deleteCode(address); |
313 }; | 320 }; |
314 | 321 |
| 322 var processCodeDeoptEvent = function(time, size) { |
| 323 deopts.push(new Deopt(time, size)); |
| 324 } |
| 325 |
315 var processSharedLibrary = function(name, start, end) { | 326 var processSharedLibrary = function(name, start, end) { |
316 var code_entry = new CodeMap.CodeEntry(end - start, name); | 327 var code_entry = new CodeMap.CodeEntry(end - start, name); |
317 code_entry.kind = -3; // External code kind. | 328 code_entry.kind = -3; // External code kind. |
318 for (var i = 0; i < kV8BinarySuffixes.length; i++) { | 329 for (var i = 0; i < kV8BinarySuffixes.length; i++) { |
319 var suffix = kV8BinarySuffixes[i]; | 330 var suffix = kV8BinarySuffixes[i]; |
320 if (name.indexOf(suffix, name.length - suffix.length) >= 0) { | 331 if (name.indexOf(suffix, name.length - suffix.length) >= 0) { |
321 code_entry.kind = -1; // V8 runtime code kind. | 332 code_entry.kind = -1; // V8 runtime code kind. |
322 break; | 333 break; |
323 } | 334 } |
324 } | 335 } |
(...skipping 20 matching lines...) Expand all Loading... |
345 'timer-event-end': { parsers: [null, parseTimeStamp], | 356 'timer-event-end': { parsers: [null, parseTimeStamp], |
346 processor: processTimerEventEnd }, | 357 processor: processTimerEventEnd }, |
347 'shared-library': { parsers: [null, parseInt, parseInt], | 358 'shared-library': { parsers: [null, parseInt, parseInt], |
348 processor: processSharedLibrary }, | 359 processor: processSharedLibrary }, |
349 'code-creation': { parsers: [null, parseInt, parseInt, parseInt, null], | 360 'code-creation': { parsers: [null, parseInt, parseInt, parseInt, null], |
350 processor: processCodeCreateEvent }, | 361 processor: processCodeCreateEvent }, |
351 'code-move': { parsers: [parseInt, parseInt], | 362 'code-move': { parsers: [parseInt, parseInt], |
352 processor: processCodeMoveEvent }, | 363 processor: processCodeMoveEvent }, |
353 'code-delete': { parsers: [parseInt], | 364 'code-delete': { parsers: [parseInt], |
354 processor: processCodeDeleteEvent }, | 365 processor: processCodeDeleteEvent }, |
| 366 'code-deopt': { parsers: [parseTimeStamp, parseInt], |
| 367 processor: processCodeDeoptEvent }, |
355 'tick': { parsers: [parseInt, parseInt, parseTimeStamp, | 368 'tick': { parsers: [parseInt, parseInt, parseTimeStamp, |
356 null, null, parseInt, 'var-args'], | 369 null, null, parseInt, 'var-args'], |
357 processor: processTickEvent } | 370 processor: processTickEvent } |
358 }); | 371 }); |
359 | 372 |
360 var line; | 373 var line; |
361 while (line = input()) { | 374 while (line = input()) { |
362 logreader.processLogLine(line); | 375 logreader.processLogLine(line); |
363 } | 376 } |
364 | 377 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
415 }; | 428 }; |
416 | 429 |
417 | 430 |
418 this.assembleOutput = function(output) { | 431 this.assembleOutput = function(output) { |
419 output("set yrange [0:" + (num_timer_event + 1) + "]"); | 432 output("set yrange [0:" + (num_timer_event + 1) + "]"); |
420 output("set xlabel \"execution time in ms\""); | 433 output("set xlabel \"execution time in ms\""); |
421 output("set xrange [" + range_start + ":" + range_end + "]"); | 434 output("set xrange [" + range_start + ":" + range_end + "]"); |
422 output("set style fill pattern 2 bo 1"); | 435 output("set style fill pattern 2 bo 1"); |
423 output("set style rect fs solid 1 noborder"); | 436 output("set style rect fs solid 1 noborder"); |
424 output("set style line 1 lt 1 lw 1 lc rgb \"#000000\""); | 437 output("set style line 1 lt 1 lw 1 lc rgb \"#000000\""); |
| 438 output("set style line 2 lt 1 lw 1 lc rgb \"#9944CC\""); |
425 output("set xtics out nomirror"); | 439 output("set xtics out nomirror"); |
426 output("unset key"); | 440 output("unset key"); |
427 | 441 |
428 function DrawBar(row, color, start, end, width) { | 442 function DrawBarBase(color, start, end, top, bottom) { |
429 obj_index++; | 443 obj_index++; |
430 command = "set object " + obj_index + " rect"; | 444 command = "set object " + obj_index + " rect"; |
431 command += " from " + start + ", " + (row - width); | 445 command += " from " + start + ", " + top; |
432 command += " to " + end + ", " + (row + width); | 446 command += " to " + end + ", " + bottom; |
433 command += " fc rgb \"" + color + "\""; | 447 command += " fc rgb \"" + color + "\""; |
434 output(command); | 448 output(command); |
435 } | 449 } |
436 | 450 |
| 451 function DrawBar(row, color, start, end, width) { |
| 452 DrawBarBase(color, start, end, row + width, row - width); |
| 453 } |
| 454 |
| 455 function DrawHalfBar(row, color, start, end, width) { |
| 456 DrawBarBase(color, start, end, row, row - width); |
| 457 } |
| 458 |
437 var percentages = {}; | 459 var percentages = {}; |
438 var total = 0; | 460 var total = 0; |
439 for (var name in TimerEvents) { | 461 for (var name in TimerEvents) { |
440 var event = TimerEvents[name]; | 462 var event = TimerEvents[name]; |
441 var ranges = RestrictRangesTo(event.ranges, range_start, range_end); | 463 var ranges = RestrictRangesTo(event.ranges, range_start, range_end); |
442 ranges = MergeRanges(ranges); | 464 ranges = MergeRanges(ranges); |
443 var sum = | 465 var sum = |
444 ranges.map(function(range) { return range.duration(); }) | 466 ranges.map(function(range) { return range.duration(); }) |
445 .reduce(function(a, b) { return a + b; }, 0); | 467 .reduce(function(a, b) { return a + b; }, 0); |
446 percentages[name] = (sum / (range_end - range_start) * 100).toFixed(1); | 468 percentages[name] = (sum / (range_end - range_start) * 100).toFixed(1); |
447 } | 469 } |
448 | 470 |
| 471 // Plot deopts. |
| 472 deopts.sort(function(a, b) { return b.size - a.size; }); |
| 473 var max_deopt_size = deopts.length > 0 ? deopts[0].size : Infinity; |
| 474 |
| 475 for (var i = 0; i < deopts.length; i++) { |
| 476 var deopt = deopts[i]; |
| 477 DrawHalfBar(kDeoptRow, "#9944CC", deopt.time, |
| 478 deopt.time + 10 * pause_tolerance, |
| 479 deopt.size / max_deopt_size * kMaxDeoptLength); |
| 480 } |
| 481 |
449 // Name Y-axis. | 482 // Name Y-axis. |
450 var ytics = []; | 483 var ytics = []; |
451 for (name in TimerEvents) { | 484 for (name in TimerEvents) { |
452 var index = TimerEvents[name].index; | 485 var index = TimerEvents[name].index; |
453 var label = TimerEvents[name].label; | 486 var label = TimerEvents[name].label; |
454 ytics.push('"' + label + ' (' + percentages[name] + '%%)" ' + index); | 487 ytics.push('"' + label + ' (' + percentages[name] + '%%)" ' + index); |
455 } | 488 } |
456 ytics.push('"code kind color coding" ' + kY1Offset); | 489 ytics.push('"code kind color coding" ' + kY1Offset); |
457 ytics.push('"code kind in execution" ' + (kY1Offset - 1)); | 490 ytics.push('"code kind in execution" ' + (kY1Offset - 1)); |
458 ytics.push('"top ' + kStackFrames + ' js stack frames"' + ' ' + | 491 ytics.push('"top ' + kStackFrames + ' js stack frames"' + ' ' + |
459 (kY1Offset - 2)); | 492 (kY1Offset - 2)); |
460 ytics.push('"pause times" 0'); | 493 ytics.push('"pause times" 0'); |
| 494 ytics.push('"max deopt size: ' + (max_deopt_size / 1024).toFixed(1) + |
| 495 ' kB" ' + kDeoptRow); |
461 output("set ytics out nomirror (" + ytics.join(', ') + ")"); | 496 output("set ytics out nomirror (" + ytics.join(', ') + ")"); |
462 | 497 |
463 // Plot timeline. | 498 // Plot timeline. |
464 for (var name in TimerEvents) { | 499 for (var name in TimerEvents) { |
465 var event = TimerEvents[name]; | 500 var event = TimerEvents[name]; |
466 var ranges = MergeRanges(event.ranges); | 501 var ranges = MergeRanges(event.ranges); |
467 for (var i = 0; i < ranges.length; i++) { | 502 for (var i = 0; i < ranges.length; i++) { |
468 DrawBar(event.index, event.color, | 503 DrawBar(event.index, event.color, |
469 ranges[i].start, ranges[i].end, | 504 ranges[i].start, ranges[i].end, |
470 kTimerEventWidth); | 505 kTimerEventWidth); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
535 output("plot '-' using 1:2 axes x1y2 with impulses ls 1"); | 570 output("plot '-' using 1:2 axes x1y2 with impulses ls 1"); |
536 for (var i = 0; i < execution_pauses.length; i++) { | 571 for (var i = 0; i < execution_pauses.length; i++) { |
537 var pause = execution_pauses[i]; | 572 var pause = execution_pauses[i]; |
538 output(pause.end + " " + pause.duration()); | 573 output(pause.end + " " + pause.duration()); |
539 obj_index++; | 574 obj_index++; |
540 } | 575 } |
541 output("e"); | 576 output("e"); |
542 return obj_index; | 577 return obj_index; |
543 }; | 578 }; |
544 } | 579 } |
OLD | NEW |