[tools] Remove tools/profviz
The tool has been outdated for a while and replaced by profview for most use-cases. The last version is still hosted under https://v8.github.io/tools/v8.4/profviz/profviz.html Bug: v8:9260, v8:10667 Change-Id: I54888640a627ee8e4d8ad2ab63bd91e04e6fb98f Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2434335 Reviewed-by: Leszek Swirski <leszeks@chromium.org> Reviewed-by: Yang Guo <yangguo@chromium.org> Commit-Queue: Camillo Bruni <cbruni@chromium.org> Cr-Commit-Position: refs/heads/master@{#70159}
This commit is contained in:
parent
4f015e85fa
commit
1e80ad69b3
@ -22,7 +22,6 @@ group("v8_mjsunit") {
|
||||
"../../tools/arguments.js",
|
||||
"../../tools/profile.js",
|
||||
"../../tools/profile_view.js",
|
||||
"../../tools/profviz/composer.js",
|
||||
"../../tools/splaytree.js",
|
||||
"../../tools/tickprocessor.js",
|
||||
"../../tools/dumpcpp.js",
|
||||
|
@ -60,9 +60,6 @@
|
||||
# BUG(v8:8169)
|
||||
'external-backing-store-gc': [SKIP],
|
||||
|
||||
# BUG(v8:9260)
|
||||
'tools/profviz': [SKIP],
|
||||
|
||||
# Issue 9380: Memory leaks of shared WebAssembly.Memory objects
|
||||
'wasm/shared-memory-worker-gc': [SKIP],
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,84 +0,0 @@
|
||||
// Copyright 2009 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Load implementations from <project root>/tools.
|
||||
// Files: tools/csvparser.js tools/splaytree.js tools/codemap.js
|
||||
// Files: tools/consarray.js tools/profile.js tools/profile_view.js
|
||||
// Files: tools/logreader.js tools/arguments.js tools/tickprocessor.js
|
||||
// Files: tools/profviz/composer.js
|
||||
// Resources: test/mjsunit/tools/profviz-test.log
|
||||
// Resources: test/mjsunit/tools/profviz-test.default
|
||||
// Env: TEST_FILE_NAME
|
||||
|
||||
assertEquals('string', typeof TEST_FILE_NAME);
|
||||
var path_length = TEST_FILE_NAME.lastIndexOf('/');
|
||||
if (path_length == -1) {
|
||||
path_length = TEST_FILE_NAME.lastIndexOf('\\');
|
||||
}
|
||||
assertTrue(path_length != -1);
|
||||
|
||||
var path = TEST_FILE_NAME.substr(0, path_length + 1);
|
||||
var input_file = path + "profviz-test.log";
|
||||
var reference_file = path + "profviz-test.default";
|
||||
|
||||
var content_lines = read(input_file).split("\n");
|
||||
var line_cursor = 0;
|
||||
var output_lines = [];
|
||||
|
||||
function input() {
|
||||
return content_lines[line_cursor++];
|
||||
}
|
||||
|
||||
function output(line) {
|
||||
output_lines.push(line);
|
||||
}
|
||||
|
||||
function set_range(start, end) {
|
||||
range_start = start;
|
||||
range_end = end;
|
||||
}
|
||||
|
||||
var distortion = 4500 / 1000000;
|
||||
var resx = 1600;
|
||||
var resy = 600;
|
||||
|
||||
var psc = new PlotScriptComposer(resx, resy);
|
||||
psc.collectData(input, distortion);
|
||||
psc.findPlotRange(undefined, undefined, set_range);
|
||||
var objects = psc.assembleOutput(output);
|
||||
|
||||
output("# start: " + range_start);
|
||||
output("# end: " + range_end);
|
||||
output("# objects: " + objects);
|
||||
|
||||
var create_baseline = false;
|
||||
|
||||
if (create_baseline) {
|
||||
print(JSON.stringify(output_lines, null, 2));
|
||||
} else {
|
||||
assertArrayEquals(JSON.parse(read(reference_file)), output_lines);
|
||||
}
|
@ -102,7 +102,6 @@ sync_file tools/logreader.js
|
||||
sync_file tools/arguments.js
|
||||
sync_file tools/tickprocessor.js
|
||||
echo ""
|
||||
sync_dir tools/profviz
|
||||
sync_dir test/intl
|
||||
sync_dir test/message
|
||||
sync_dir test/mjsunit
|
||||
|
@ -1,93 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# find the name of the log file to process, it must not start with a dash.
|
||||
log_file="v8.log"
|
||||
for arg in "$@"
|
||||
do
|
||||
if ! expr "X${arg}" : "^X-" > /dev/null; then
|
||||
log_file=${arg}
|
||||
fi
|
||||
done
|
||||
|
||||
tools_path=`cd $(dirname "$0");pwd`
|
||||
if test ! "$D8_PATH"; then
|
||||
d8_public=`which d8`
|
||||
if test -x "$d8_public"; then D8_PATH=$(dirname "$d8_public"); fi
|
||||
fi
|
||||
|
||||
if test ! -n "$D8_PATH"; then
|
||||
D8_PATH=$tools_path/..
|
||||
fi
|
||||
|
||||
d8_exec=$D8_PATH/d8
|
||||
|
||||
if test ! -x "$d8_exec"; then
|
||||
D8_PATH=`pwd`/out/native
|
||||
d8_exec=$D8_PATH/d8
|
||||
fi
|
||||
|
||||
if test ! -x "$d8_exec"; then
|
||||
d8_exec=`grep -m 1 -o '".*/d8"' $log_file | sed 's/"//g'`
|
||||
fi
|
||||
|
||||
if test ! -x "$d8_exec"; then
|
||||
echo "d8 shell not found in $D8_PATH"
|
||||
echo "Please provide path to d8 as env var in D8_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
contains=0;
|
||||
for arg in "$@"; do
|
||||
`echo "$arg" | grep -q "^--distortion"`
|
||||
if test $? -eq 0; then
|
||||
contains=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if test "$contains" -eq 0; then
|
||||
# Try to find out how much the instrumentation overhead is.
|
||||
calibration_log=calibration.log
|
||||
calibration_script="for (var i = 0; i < 1000000; i++) print();"
|
||||
|
||||
$d8_exec --noopt --prof --logfile $calibration_log \
|
||||
--log-timer-events -e "$calibration_script" > /dev/null
|
||||
t_1_start=`grep "timer-event-start,\"V8.Execute\"" $calibration_log \
|
||||
| tail -n1 | awk -F, '{print $3}'`
|
||||
t_1_end=`grep "timer-event-end,\"V8.Execute\"" $calibration_log \
|
||||
| tail -n1 | awk -F, '{print $3}'`
|
||||
n_1=`grep "timer-event\|tick" $calibration_log | wc -l`
|
||||
|
||||
$d8_exec --noopt --prof --logfile $calibration_log \
|
||||
--log-internal-timer-events -e "$calibration_script" > /dev/null
|
||||
t_2_start=`grep "timer-event-start,\"V8.Execute\"" $calibration_log \
|
||||
| tail -n1 | awk -F, '{print $3}'`
|
||||
t_2_end=`grep "timer-event-end,\"V8.Execute\"" $calibration_log \
|
||||
| tail -n1 | awk -F, '{print $3}'`
|
||||
n_2=`grep "timer-event\|tick" $calibration_log | wc -l`
|
||||
|
||||
rm $calibration_log
|
||||
|
||||
# Overhead in picoseconds.
|
||||
distortion=`echo "1000*(($t_1_end - $t_1_start) - ($t_2_end - $t_2_start)) \
|
||||
/ ($n_1 - $n_2)" | bc`
|
||||
options="--distortion=$distortion"
|
||||
fi
|
||||
|
||||
cat $log_file |
|
||||
$d8_exec $tools_path/csvparser.js $tools_path/splaytree.js \
|
||||
$tools_path/codemap.js $tools_path/profile.js $tools_path/profile_view.js \
|
||||
$tools_path/logreader.js $tools_path/arguments.js \
|
||||
$tools_path/tickprocessor.js$tools_path/profviz/composer.js \
|
||||
$tools_path/profviz/stdio.js \
|
||||
-- $@ $options 2>/dev/null > timer-events.plot
|
||||
|
||||
success=$?
|
||||
if test $success -ne 0; then
|
||||
cat timer-events.plot
|
||||
else
|
||||
cat timer-events.plot | gnuplot > timer-events.png
|
||||
fi
|
||||
|
||||
rm -f timer-events.plot
|
@ -1,557 +0,0 @@
|
||||
// Copyright 2013 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Array.prototype.top = function() {
|
||||
if (this.length == 0) return undefined;
|
||||
return this[this.length - 1];
|
||||
}
|
||||
|
||||
|
||||
function PlotScriptComposer(kResX, kResY, error_output) {
|
||||
// Constants.
|
||||
var kV8BinarySuffixes = ["/d8", "/libv8.so"];
|
||||
var kStackFrames = 8; // Stack frames to display in the plot.
|
||||
|
||||
var kTimerEventWidth = 0.33; // Width of each timeline.
|
||||
var kExecutionFrameWidth = 0.2; // Width of the top stack frame line.
|
||||
var kStackFrameWidth = 0.1; // Width of the lower stack frame lines.
|
||||
var kGapWidth = 0.05; // Gap between stack frame lines.
|
||||
|
||||
var kY1Offset = 11; // Offset for stack frame vs. event lines.
|
||||
var kDeoptRow = 7; // Row displaying deopts.
|
||||
var kGetTimeHeight = 0.5; // Height of marker displaying timed part.
|
||||
var kMaxDeoptLength = 4; // Draw size of the largest deopt.
|
||||
var kPauseLabelPadding = 5; // Padding for pause time labels.
|
||||
var kNumPauseLabels = 7; // Number of biggest pauses to label.
|
||||
var kCodeKindLabelPadding = 100; // Padding for code kind labels.
|
||||
|
||||
var kTickHalfDuration = 0.5; // Duration of half a tick in ms.
|
||||
var kMinRangeLength = 0.0005; // Minimum length for an event in ms.
|
||||
|
||||
var kNumThreads = 2; // Number of threads.
|
||||
var kExecutionThreadId = 0; // ID of main thread.
|
||||
|
||||
// Init values.
|
||||
var num_timer_event = kY1Offset + 0.5;
|
||||
|
||||
// Data structures.
|
||||
function TimerEvent(label, color, pause, thread_id) {
|
||||
assert(thread_id >= 0 && thread_id < kNumThreads, "invalid thread id");
|
||||
this.label = label;
|
||||
this.color = color;
|
||||
this.pause = pause;
|
||||
this.ranges = [];
|
||||
this.thread_id = thread_id;
|
||||
this.index = ++num_timer_event;
|
||||
}
|
||||
|
||||
function CodeKind(color, kinds) {
|
||||
this.color = color;
|
||||
this.in_execution = [];
|
||||
this.stack_frames = [];
|
||||
for (var i = 0; i < kStackFrames; i++) this.stack_frames.push([]);
|
||||
this.kinds = kinds;
|
||||
}
|
||||
|
||||
function Range(start, end) {
|
||||
this.start = start; // In milliseconds.
|
||||
this.end = end; // In milliseconds.
|
||||
}
|
||||
|
||||
function Deopt(time, size) {
|
||||
this.time = time; // In milliseconds.
|
||||
this.size = size; // In bytes.
|
||||
}
|
||||
|
||||
Range.prototype.duration = function() { return this.end - this.start; }
|
||||
|
||||
function Tick(tick) {
|
||||
this.tick = tick;
|
||||
}
|
||||
|
||||
var TimerEvents = {
|
||||
'V8.Execute':
|
||||
new TimerEvent("execution", "#000000", false, 0),
|
||||
'V8.External':
|
||||
new TimerEvent("external", "#3399FF", false, 0),
|
||||
'V8.CompileFullCode':
|
||||
new TimerEvent("compile unopt", "#CC0000", true, 0),
|
||||
'V8.RecompileSynchronous':
|
||||
new TimerEvent("recompile sync", "#CC0044", true, 0),
|
||||
'V8.RecompileConcurrent':
|
||||
new TimerEvent("recompile async", "#CC4499", false, 1),
|
||||
'V8.CompileEvalMicroSeconds':
|
||||
new TimerEvent("compile eval", "#CC4400", true, 0),
|
||||
'V8.ParseMicroSeconds':
|
||||
new TimerEvent("parse", "#00CC00", true, 0),
|
||||
'V8.PreParseMicroSeconds':
|
||||
new TimerEvent("preparse", "#44CC00", true, 0),
|
||||
'V8.ParseLazyMicroSeconds':
|
||||
new TimerEvent("lazy parse", "#00CC44", true, 0),
|
||||
'V8.GCScavenger':
|
||||
new TimerEvent("gc scavenge", "#0044CC", true, 0),
|
||||
'V8.GCCompactor':
|
||||
new TimerEvent("gc compaction", "#4444CC", true, 0),
|
||||
'V8.GCContext':
|
||||
new TimerEvent("gc context", "#4400CC", true, 0),
|
||||
};
|
||||
|
||||
var CodeKinds = {
|
||||
'external ': new CodeKind("#3399FF", [-2]),
|
||||
'runtime ': new CodeKind("#000000", [-1]),
|
||||
'full code': new CodeKind("#DD0000", [0]),
|
||||
'opt code ': new CodeKind("#00EE00", [1]),
|
||||
'code stub': new CodeKind("#FF00FF", [2]),
|
||||
'built-in ': new CodeKind("#AA00AA", [3]),
|
||||
'inl.cache': new CodeKind("#4444AA",
|
||||
[4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]),
|
||||
'reg.exp. ': new CodeKind("#0000FF", [15]),
|
||||
};
|
||||
|
||||
var code_map = new CodeMap();
|
||||
var execution_pauses = [];
|
||||
var deopts = [];
|
||||
var gettime = [];
|
||||
var event_stack = [];
|
||||
var last_time_stamp = [];
|
||||
for (var i = 0; i < kNumThreads; i++) {
|
||||
event_stack[i] = [];
|
||||
last_time_stamp[i] = -1;
|
||||
}
|
||||
|
||||
var range_start = undefined;
|
||||
var range_end = undefined;
|
||||
var obj_index = 0;
|
||||
var pause_tolerance = 0.005; // Milliseconds.
|
||||
var distortion = 0;
|
||||
|
||||
// Utility functions.
|
||||
function assert(something, message) {
|
||||
if (!something) {
|
||||
var error = new Error(message);
|
||||
error_output(error.stack);
|
||||
}
|
||||
}
|
||||
|
||||
function FindCodeKind(kind) {
|
||||
for (name in CodeKinds) {
|
||||
if (CodeKinds[name].kinds.indexOf(kind) >= 0) {
|
||||
return CodeKinds[name];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function TicksToRanges(ticks) {
|
||||
var ranges = [];
|
||||
for (var i = 0; i < ticks.length; i++) {
|
||||
var tick = ticks[i].tick;
|
||||
ranges.push(
|
||||
new Range(tick - kTickHalfDuration, tick + kTickHalfDuration));
|
||||
}
|
||||
return ranges;
|
||||
}
|
||||
|
||||
function MergeRanges(ranges) {
|
||||
ranges.sort(function(a, b) {
|
||||
return (a.start == b.start) ? a.end - b.end : a.start - b.start;
|
||||
});
|
||||
var result = [];
|
||||
var j = 0;
|
||||
for (var i = 0; i < ranges.length; i = j) {
|
||||
var merge_start = ranges[i].start;
|
||||
if (merge_start > range_end) break; // Out of plot range.
|
||||
var merge_end = ranges[i].end;
|
||||
for (j = i + 1; j < ranges.length; j++) {
|
||||
var next_range = ranges[j];
|
||||
// Don't merge ranges if there is no overlap (incl. merge tolerance).
|
||||
if (next_range.start > merge_end + pause_tolerance) break;
|
||||
// Merge ranges.
|
||||
if (next_range.end > merge_end) { // Extend range end.
|
||||
merge_end = next_range.end;
|
||||
}
|
||||
}
|
||||
if (merge_end < range_start) continue; // Out of plot range.
|
||||
if (merge_end < merge_start) continue; // Not an actual range.
|
||||
result.push(new Range(merge_start, merge_end));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function RestrictRangesTo(ranges, start, end) {
|
||||
var result = [];
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
if (ranges[i].start <= end && ranges[i].end >= start) {
|
||||
result.push(new Range(Math.max(ranges[i].start, start),
|
||||
Math.min(ranges[i].end, end)));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Public methods.
|
||||
this.collectData = function(input, distortion_per_entry) {
|
||||
|
||||
var last_timestamp = 0;
|
||||
|
||||
// Parse functions.
|
||||
var parseTimeStamp = function(timestamp) {
|
||||
int_timestamp = parseInt(timestamp);
|
||||
assert(int_timestamp >= last_timestamp, "Inconsistent timestamps.");
|
||||
last_timestamp = int_timestamp;
|
||||
distortion += distortion_per_entry;
|
||||
return int_timestamp / 1000 - distortion;
|
||||
}
|
||||
|
||||
var processTimerEventStart = function(name, start) {
|
||||
// Find out the thread id.
|
||||
var new_event = TimerEvents[name];
|
||||
if (new_event === undefined) return;
|
||||
var thread_id = new_event.thread_id;
|
||||
|
||||
start = Math.max(last_time_stamp[thread_id] + kMinRangeLength, start);
|
||||
|
||||
// Last event on this thread is done with the start of this event.
|
||||
var last_event = event_stack[thread_id].top();
|
||||
if (last_event !== undefined) {
|
||||
var new_range = new Range(last_time_stamp[thread_id], start);
|
||||
last_event.ranges.push(new_range);
|
||||
}
|
||||
event_stack[thread_id].push(new_event);
|
||||
last_time_stamp[thread_id] = start;
|
||||
};
|
||||
|
||||
var processTimerEventEnd = function(name, end) {
|
||||
// Find out about the thread_id.
|
||||
var finished_event = TimerEvents[name];
|
||||
var thread_id = finished_event.thread_id;
|
||||
assert(finished_event === event_stack[thread_id].pop(),
|
||||
"inconsistent event stack");
|
||||
|
||||
end = Math.max(last_time_stamp[thread_id] + kMinRangeLength, end);
|
||||
|
||||
var new_range = new Range(last_time_stamp[thread_id], end);
|
||||
finished_event.ranges.push(new_range);
|
||||
last_time_stamp[thread_id] = end;
|
||||
};
|
||||
|
||||
var processCodeCreateEvent = function(type, kind, address, size, name) {
|
||||
var code_entry = new CodeMap.CodeEntry(size, name);
|
||||
code_entry.kind = kind;
|
||||
code_map.addCode(address, code_entry);
|
||||
};
|
||||
|
||||
var processCodeMoveEvent = function(from, to) {
|
||||
code_map.moveCode(from, to);
|
||||
};
|
||||
|
||||
var processCodeDeleteEvent = function(address) {
|
||||
code_map.deleteCode(address);
|
||||
};
|
||||
|
||||
var processCodeDeoptEvent = function(time, size) {
|
||||
deopts.push(new Deopt(time, size));
|
||||
}
|
||||
|
||||
var processCurrentTimeEvent = function(time) {
|
||||
gettime.push(time);
|
||||
}
|
||||
|
||||
var processSharedLibrary = function(name, start, end) {
|
||||
var code_entry = new CodeMap.CodeEntry(end - start, name);
|
||||
code_entry.kind = -3; // External code kind.
|
||||
for (var i = 0; i < kV8BinarySuffixes.length; i++) {
|
||||
var suffix = kV8BinarySuffixes[i];
|
||||
if (name.indexOf(suffix, name.length - suffix.length) >= 0) {
|
||||
code_entry.kind = -1; // V8 runtime code kind.
|
||||
break;
|
||||
}
|
||||
}
|
||||
code_map.addLibrary(start, code_entry);
|
||||
};
|
||||
|
||||
var processTickEvent = function(
|
||||
pc, timer, unused_x, unused_y, vmstate, stack) {
|
||||
var tick = new Tick(timer);
|
||||
|
||||
var entry = code_map.findEntry(pc);
|
||||
if (entry) FindCodeKind(entry.kind).in_execution.push(tick);
|
||||
|
||||
for (var i = 0; i < kStackFrames; i++) {
|
||||
if (!stack[i]) break;
|
||||
var entry = code_map.findEntry(stack[i]);
|
||||
if (entry) FindCodeKind(entry.kind).stack_frames[i].push(tick);
|
||||
}
|
||||
};
|
||||
// Collect data from log.
|
||||
var logreader = new LogReader(
|
||||
{ 'timer-event-start': { parsers: [parseString, parseTimeStamp],
|
||||
processor: processTimerEventStart },
|
||||
'timer-event-end': { parsers: [parseString, parseTimeStamp],
|
||||
processor: processTimerEventEnd },
|
||||
'shared-library': { parsers: [parseString, parseInt, parseInt],
|
||||
processor: processSharedLibrary },
|
||||
'code-creation': { parsers: [parseString, parseInt, parseInt,
|
||||
parseInt, parseString],
|
||||
processor: processCodeCreateEvent },
|
||||
'code-move': { parsers: [parseInt, parseInt],
|
||||
processor: processCodeMoveEvent },
|
||||
'code-delete': { parsers: [parseInt],
|
||||
processor: processCodeDeleteEvent },
|
||||
'code-deopt': { parsers: [parseTimeStamp, parseInt],
|
||||
processor: processCodeDeoptEvent },
|
||||
'current-time': { parsers: [parseTimeStamp],
|
||||
processor: processCurrentTimeEvent },
|
||||
'tick': { parsers: [parseInt, parseTimeStamp, parseString,
|
||||
parseString, parseInt, parseVarArgs],
|
||||
processor: processTickEvent }
|
||||
});
|
||||
|
||||
var line;
|
||||
while (line = input()) {
|
||||
for (var s of line.split("\n")) logreader.processLogLine(s);
|
||||
}
|
||||
|
||||
// Collect execution pauses.
|
||||
for (name in TimerEvents) {
|
||||
var event = TimerEvents[name];
|
||||
if (!event.pause) continue;
|
||||
var ranges = event.ranges;
|
||||
for (var j = 0; j < ranges.length; j++) execution_pauses.push(ranges[j]);
|
||||
}
|
||||
execution_pauses = MergeRanges(execution_pauses);
|
||||
};
|
||||
|
||||
|
||||
this.findPlotRange = function(
|
||||
range_start_override, range_end_override, result_callback) {
|
||||
var start_found = (range_start_override || range_start_override == 0);
|
||||
var end_found = (range_end_override || range_end_override == 0);
|
||||
range_start = start_found ? range_start_override : Infinity;
|
||||
range_end = end_found ? range_end_override : -Infinity;
|
||||
|
||||
if (!start_found || !end_found) {
|
||||
for (name in TimerEvents) {
|
||||
var ranges = TimerEvents[name].ranges;
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
if (ranges[i].start < range_start && !start_found) {
|
||||
range_start = ranges[i].start;
|
||||
}
|
||||
if (ranges[i].end > range_end && !end_found) {
|
||||
range_end = ranges[i].end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (codekind in CodeKinds) {
|
||||
var ticks = CodeKinds[codekind].in_execution;
|
||||
for (var i = 0; i < ticks.length; i++) {
|
||||
if (ticks[i].tick < range_start && !start_found) {
|
||||
range_start = ticks[i].tick;
|
||||
}
|
||||
if (ticks[i].tick > range_end && !end_found) {
|
||||
range_end = ticks[i].tick;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Set pause tolerance to something appropriate for the plot resolution
|
||||
// to make it easier for gnuplot.
|
||||
pause_tolerance = (range_end - range_start) / kResX / 10;
|
||||
|
||||
if (typeof result_callback === 'function') {
|
||||
result_callback(range_start, range_end);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.assembleOutput = function(output) {
|
||||
output("set yrange [0:" + (num_timer_event + 1) + "]");
|
||||
output("set xlabel \"execution time in ms\"");
|
||||
output("set xrange [" + range_start + ":" + range_end + "]");
|
||||
output("set style fill pattern 2 bo 1");
|
||||
output("set style rect fs solid 1 noborder");
|
||||
output("set style line 1 lt 1 lw 1 lc rgb \"#000000\"");
|
||||
output("set border 15 lw 0.2"); // Draw thin border box.
|
||||
output("set style line 2 lt 1 lw 1 lc rgb \"#9944CC\"");
|
||||
output("set xtics out nomirror");
|
||||
output("unset key");
|
||||
|
||||
function DrawBarBase(color, start, end, top, bottom, transparency) {
|
||||
obj_index++;
|
||||
command = "set object " + obj_index + " rect";
|
||||
command += " from " + start + ", " + top;
|
||||
command += " to " + end + ", " + bottom;
|
||||
command += " fc rgb \"" + color + "\"";
|
||||
if (transparency) {
|
||||
command += " fs transparent solid " + transparency;
|
||||
}
|
||||
output(command);
|
||||
}
|
||||
|
||||
function DrawBar(row, color, start, end, width) {
|
||||
DrawBarBase(color, start, end, row + width, row - width);
|
||||
}
|
||||
|
||||
function DrawHalfBar(row, color, start, end, width) {
|
||||
DrawBarBase(color, start, end, row, row - width);
|
||||
}
|
||||
|
||||
var percentages = {};
|
||||
var total = 0;
|
||||
for (var name in TimerEvents) {
|
||||
var event = TimerEvents[name];
|
||||
var ranges = RestrictRangesTo(event.ranges, range_start, range_end);
|
||||
var sum =
|
||||
ranges.map(function(range) { return range.duration(); })
|
||||
.reduce(function(a, b) { return a + b; }, 0);
|
||||
percentages[name] = (sum / (range_end - range_start) * 100).toFixed(1);
|
||||
}
|
||||
|
||||
// Plot deopts.
|
||||
deopts.sort(function(a, b) { return b.size - a.size; });
|
||||
var max_deopt_size = deopts.length > 0 ? deopts[0].size : Infinity;
|
||||
|
||||
for (var i = 0; i < deopts.length; i++) {
|
||||
var deopt = deopts[i];
|
||||
DrawHalfBar(kDeoptRow, "#9944CC", deopt.time,
|
||||
deopt.time + 10 * pause_tolerance,
|
||||
deopt.size / max_deopt_size * kMaxDeoptLength);
|
||||
}
|
||||
|
||||
// Plot current time polls.
|
||||
if (gettime.length > 1) {
|
||||
var start = gettime[0];
|
||||
var end = gettime.pop();
|
||||
DrawBarBase("#0000BB", start, end, kGetTimeHeight, 0, 0.2);
|
||||
}
|
||||
|
||||
// Name Y-axis.
|
||||
var ytics = [];
|
||||
for (name in TimerEvents) {
|
||||
var index = TimerEvents[name].index;
|
||||
var label = TimerEvents[name].label;
|
||||
ytics.push('"' + label + ' (' + percentages[name] + '%%)" ' + index);
|
||||
}
|
||||
ytics.push('"code kind color coding" ' + kY1Offset);
|
||||
ytics.push('"code kind in execution" ' + (kY1Offset - 1));
|
||||
ytics.push('"top ' + kStackFrames + ' js stack frames"' + ' ' +
|
||||
(kY1Offset - 2));
|
||||
ytics.push('"pause times" 0');
|
||||
ytics.push('"max deopt size: ' + (max_deopt_size / 1024).toFixed(1) +
|
||||
' kB" ' + kDeoptRow);
|
||||
output("set ytics out nomirror (" + ytics.join(', ') + ")");
|
||||
|
||||
// Plot timeline.
|
||||
for (var name in TimerEvents) {
|
||||
var event = TimerEvents[name];
|
||||
var ranges = MergeRanges(event.ranges);
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
DrawBar(event.index, event.color,
|
||||
ranges[i].start, ranges[i].end,
|
||||
kTimerEventWidth);
|
||||
}
|
||||
}
|
||||
|
||||
// Plot code kind gathered from ticks.
|
||||
for (var name in CodeKinds) {
|
||||
var code_kind = CodeKinds[name];
|
||||
var offset = kY1Offset - 1;
|
||||
// Top most frame.
|
||||
var row = MergeRanges(TicksToRanges(code_kind.in_execution));
|
||||
for (var j = 0; j < row.length; j++) {
|
||||
DrawBar(offset, code_kind.color,
|
||||
row[j].start, row[j].end, kExecutionFrameWidth);
|
||||
}
|
||||
offset = offset - 2 * kExecutionFrameWidth - kGapWidth;
|
||||
// Javascript frames.
|
||||
for (var i = 0; i < kStackFrames; i++) {
|
||||
offset = offset - 2 * kStackFrameWidth - kGapWidth;
|
||||
row = MergeRanges(TicksToRanges(code_kind.stack_frames[i]));
|
||||
for (var j = 0; j < row.length; j++) {
|
||||
DrawBar(offset, code_kind.color,
|
||||
row[j].start, row[j].end, kStackFrameWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add labels as legend for code kind colors.
|
||||
var padding = kCodeKindLabelPadding * (range_end - range_start) / kResX;
|
||||
var label_x = range_start;
|
||||
var label_y = kY1Offset;
|
||||
for (var name in CodeKinds) {
|
||||
label_x += padding;
|
||||
output("set label \"" + name + "\" at " + label_x + "," + label_y +
|
||||
" textcolor rgb \"" + CodeKinds[name].color + "\"" +
|
||||
" font \"Helvetica,9'\"");
|
||||
obj_index++;
|
||||
}
|
||||
|
||||
if (execution_pauses.length == 0) {
|
||||
// Force plot and return without plotting execution pause impulses.
|
||||
output("plot 1/0");
|
||||
return;
|
||||
}
|
||||
|
||||
// Label the longest pauses.
|
||||
execution_pauses =
|
||||
RestrictRangesTo(execution_pauses, range_start, range_end);
|
||||
execution_pauses.sort(function(a, b) {
|
||||
if (a.duration() == b.duration() && b.end == a.end)
|
||||
return b.start - a.start;
|
||||
|
||||
return (a.duration() == b.duration())
|
||||
? b.end - a.end : b.duration() - a.duration();
|
||||
});
|
||||
|
||||
var max_pause_time = execution_pauses.length > 0
|
||||
? execution_pauses[0].duration() : 0;
|
||||
padding = kPauseLabelPadding * (range_end - range_start) / kResX;
|
||||
var y_scale = kY1Offset / max_pause_time / 2;
|
||||
for (var i = 0; i < execution_pauses.length && i < kNumPauseLabels; i++) {
|
||||
var pause = execution_pauses[i];
|
||||
var label_content = (pause.duration() | 0) + " ms";
|
||||
var label_x = pause.end + padding;
|
||||
var label_y = Math.max(1, (pause.duration() * y_scale));
|
||||
output("set label \"" + label_content + "\" at " +
|
||||
label_x + "," + label_y + " font \"Helvetica,7'\"");
|
||||
obj_index++;
|
||||
}
|
||||
|
||||
// Scale second Y-axis appropriately.
|
||||
var y2range = max_pause_time * num_timer_event / kY1Offset * 2;
|
||||
output("set y2range [0:" + y2range + "]");
|
||||
// Plot graph with impulses as data set.
|
||||
output("plot '-' using 1:2 axes x1y2 with impulses ls 1");
|
||||
for (var i = 0; i < execution_pauses.length; i++) {
|
||||
var pause = execution_pauses[i];
|
||||
output(pause.end + " " + pause.duration());
|
||||
obj_index++;
|
||||
}
|
||||
output("e");
|
||||
return obj_index;
|
||||
};
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -1,138 +0,0 @@
|
||||
/*
|
||||
Copyright 2013 the V8 project authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
body {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
#content {
|
||||
background-color: #fff;
|
||||
width: 1200px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding: 25px;
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 1200px;
|
||||
resize: none;
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
color: #000;
|
||||
border: 1px dotted #aaa;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
textarea.log {
|
||||
background-color: #ffe;
|
||||
}
|
||||
|
||||
.display {
|
||||
width: 1200px;
|
||||
height: 600px;
|
||||
background-color: #fff;
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 1200px;
|
||||
}
|
||||
|
||||
button {
|
||||
width: 100px;
|
||||
height: 20px;
|
||||
border: 1px solid #000;
|
||||
border-color: #aaa;
|
||||
font-family: Verdana;
|
||||
font-size: 12px;
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
#file {
|
||||
width: 200px;
|
||||
height: 20px;
|
||||
border: none;
|
||||
font-family: Verdana;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
input.range {
|
||||
width: 70px;
|
||||
height: 16px;
|
||||
text-align: right;
|
||||
padding-right: 5px;
|
||||
border: 0px;
|
||||
background-color: #eee;
|
||||
font-family: Verdana;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
label {
|
||||
height: 20px;
|
||||
font-family: Verdana;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
border-bottom: 1px dotted #000;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: Verdana;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.text {
|
||||
font-family: Verdana;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.tt {
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
color: #822;
|
||||
}
|
||||
|
||||
a {
|
||||
font-family: Verdana;
|
||||
font-size: 12px;
|
||||
text-decoration: none;
|
||||
color: #282;
|
||||
}
|
||||
|
||||
a.unroll {
|
||||
border-bottom: 1px dotted #000;
|
||||
color: #222;
|
||||
}
|
@ -1,158 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- Copyright 2013 the V8 project authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -->
|
||||
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<title>V8 profile log plotter</title>
|
||||
<link rel="stylesheet" type="text/css" href="profviz.css">
|
||||
<script src="profviz.js"></script>
|
||||
</head>
|
||||
|
||||
<body onload="onload()">
|
||||
<div id="content">
|
||||
|
||||
<img src="" id="plot" type="image/svg+xml" class="display"
|
||||
width="1200" height="600" class="float-right"/>
|
||||
|
||||
<textarea id="prof" class="display" disabled=true></textarea>
|
||||
<br/>
|
||||
|
||||
<table width="1200">
|
||||
<tr>
|
||||
<td width="330">
|
||||
<button id="start" onclick="start()">
|
||||
Start
|
||||
</button>
|
||||
<button id="reset" onclick="ui.reset(); worker.reset();">
|
||||
Reset
|
||||
</button>
|
||||
<button id="toggledisplay" onclick="ui.toggle();">
|
||||
Show profile
|
||||
</button>
|
||||
</td>
|
||||
<td width="220">
|
||||
<input type="file" id="file" onchange="ui.reset();"/>
|
||||
</td>
|
||||
<td width="300">
|
||||
<label title="You can manually choose the range
|
||||
to plot only part of the log file.">
|
||||
<span class="tooltip">Range</span>:
|
||||
</label>
|
||||
<input type="text" id="range_start" class="range"/>
|
||||
<label>to</label>
|
||||
<input type="text" id="range_end" class="range"/>
|
||||
</td>
|
||||
<td width="350">
|
||||
<label title="We model profiling overhead by accounting a constant
|
||||
execution delay to each log entry. Adjust to better suit
|
||||
your computer's performance.">
|
||||
<span class="tooltip">Delay per log entry</span>:
|
||||
</label>
|
||||
<input type="text" id="distortion" class="range" value="4500"/>
|
||||
<label>picoseconds</label>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br/>
|
||||
<textarea class="log" id="log" rows="8" disabled=true></textarea>
|
||||
|
||||
<div class="text">
|
||||
<h1>
|
||||
<a href="javascript:ui.info('instructions');" class="unroll">
|
||||
Instructions
|
||||
</a>
|
||||
</h1>
|
||||
<div id="instructions">
|
||||
<ol>
|
||||
<li>
|
||||
Run V8 with
|
||||
<span class="tt">--prof --log-timer-events</span>,
|
||||
or alternatively,<br/>
|
||||
Chrome with
|
||||
<span class="tt">
|
||||
--no-sandbox --js-flags="--prof --log-timer-events"
|
||||
</span> to produce <span class="tt">v8.log</span>.
|
||||
</li>
|
||||
<li>
|
||||
Open
|
||||
<span class="tt">v8.log</span>
|
||||
on this page. Don't worry, it won't be uploaded anywhere.
|
||||
</li>
|
||||
<li>
|
||||
Click "Start" to start number crunching. This will take a while.
|
||||
</li>
|
||||
<li>
|
||||
Click "Show plot/profile" to switch between the statistical profile and
|
||||
the timeline plot.<br/>
|
||||
C++ items are missing in the statistical profile because symbol
|
||||
information is not available.<br>
|
||||
Consider using the
|
||||
<a href="https://code.google.com/p/v8/wiki/V8Profiler">
|
||||
command-line utility
|
||||
</a> instead.
|
||||
</li>
|
||||
</ol>
|
||||
If you expect multiple V8 instances to run concurrently, for example
|
||||
with several tabs in Chrome,<br/>
|
||||
add the V8 flag <span class="tt">--logfile=v8.%p.log</span>
|
||||
so that each instance writes to its own log file.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text">
|
||||
<h1>
|
||||
<a href="javascript:ui.info('credits');" class="unroll">
|
||||
Credits
|
||||
</a>
|
||||
</h1>
|
||||
<div id="credits">
|
||||
<ul>
|
||||
<li>
|
||||
Christian Huettig for the
|
||||
<a href="http://gnuplot.respawned.com/">Javascript port</a>
|
||||
of Gnuplot 4.6.3.
|
||||
</li>
|
||||
<li>
|
||||
The
|
||||
<a href="https://github.com/kripken/emscripten">Emscripten compiler</a>
|
||||
that made the port possible.
|
||||
</li>
|
||||
<li>
|
||||
The <a href="http://www.gnuplot.info/">Gnuplot project</a>.
|
||||
</li>
|
||||
<li>
|
||||
The <a href="https://developers.google.com/v8/">V8 project</a>.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,286 +0,0 @@
|
||||
// Copyright 2013 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
var worker_scripts = [
|
||||
"../csvparser.js",
|
||||
"../splaytree.js",
|
||||
"../codemap.js",
|
||||
"../consarray.js",
|
||||
"../profile.js",
|
||||
"../profile_view.js",
|
||||
"../logreader.js",
|
||||
"../arguments.js",
|
||||
"../tickprocessor.js",
|
||||
"composer.js",
|
||||
"gnuplot-4.6.3-emscripten.js"
|
||||
];
|
||||
|
||||
|
||||
function plotWorker() {
|
||||
var worker = null;
|
||||
|
||||
function initialize() {
|
||||
ui.freeze();
|
||||
worker = new Worker("worker.js");
|
||||
running = false;
|
||||
|
||||
worker.postMessage({ "call" : "load scripts",
|
||||
"args" : worker_scripts });
|
||||
|
||||
worker.addEventListener("message", function(event) {
|
||||
var call = delegateList[event.data["call"]];
|
||||
call(event.data["args"]);
|
||||
});
|
||||
}
|
||||
|
||||
function scriptLoaded() {
|
||||
ui.thaw();
|
||||
}
|
||||
|
||||
// Public methods.
|
||||
this.run = function(filename,
|
||||
resx, resy,
|
||||
distortion,
|
||||
range_start, range_end) {
|
||||
var args = {
|
||||
'file' : filename,
|
||||
'resx' : resx,
|
||||
'resy' : resy,
|
||||
'distortion' : distortion,
|
||||
'range_start' : range_start,
|
||||
'range_end' : range_end
|
||||
}
|
||||
worker.postMessage({ 'call' : 'run', 'args' : args });
|
||||
}
|
||||
|
||||
this.reset = function() {
|
||||
if (worker) worker.terminate();
|
||||
initialize();
|
||||
}
|
||||
|
||||
var delegateList = {
|
||||
"log" : log,
|
||||
"error" : logError,
|
||||
"displayplot" : displayplot,
|
||||
"displayprof" : displayprof,
|
||||
"range" : setRange,
|
||||
"script" : scriptLoaded,
|
||||
"reset" : this.reset
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function UIWrapper() {
|
||||
var input_elements = ["range_start",
|
||||
"range_end",
|
||||
"distortion",
|
||||
"start",
|
||||
"file"];
|
||||
|
||||
var other_elements = ["log",
|
||||
"plot",
|
||||
"prof",
|
||||
"instructions",
|
||||
"credits",
|
||||
"toggledisplay"];
|
||||
|
||||
for (var i in input_elements) {
|
||||
var id = input_elements[i];
|
||||
this[id] = document.getElementById(id);
|
||||
}
|
||||
|
||||
for (var i in other_elements) {
|
||||
var id = other_elements[i];
|
||||
this[id] = document.getElementById(id);
|
||||
}
|
||||
|
||||
this.freeze = function() {
|
||||
this.plot.style.webkitFilter = "grayscale(1)";
|
||||
this.prof.style.color = "#bbb";
|
||||
for (var i in input_elements) {
|
||||
this[input_elements[i]].disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
this.thaw = function() {
|
||||
this.plot.style.webkitFilter = "";
|
||||
this.prof.style.color = "#000";
|
||||
for (var i in input_elements) {
|
||||
this[input_elements[i]].disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
this.reset = function() {
|
||||
this.thaw();
|
||||
this.log.value = "";
|
||||
this.range_start.value = "automatic";
|
||||
this.range_end.value = "automatic";
|
||||
this.toggle("plot");
|
||||
this.plot.src = "";
|
||||
this.prof.value = "";
|
||||
}
|
||||
|
||||
this.toggle = function(mode) {
|
||||
if (mode) this.toggledisplay.next_mode = mode;
|
||||
if (this.toggledisplay.next_mode == "plot") {
|
||||
this.toggledisplay.next_mode = "prof";
|
||||
this.plot.style.display = "block";
|
||||
this.prof.style.display = "none";
|
||||
this.toggledisplay.innerHTML = "Show profile";
|
||||
} else {
|
||||
this.toggledisplay.next_mode = "plot";
|
||||
this.plot.style.display = "none";
|
||||
this.prof.style.display = "block";
|
||||
this.toggledisplay.innerHTML = "Show plot";
|
||||
}
|
||||
}
|
||||
|
||||
this.info = function(field) {
|
||||
var down_arrow = "\u25bc";
|
||||
var right_arrow = "\u25b6";
|
||||
if (field && this[field].style.display != "none") field = null; // Toggle.
|
||||
this.credits.style.display = "none";
|
||||
this.instructions.style.display = "none";
|
||||
if (!field) return;
|
||||
this[field].style.display = "block";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function log(text) {
|
||||
ui.log.value += text;
|
||||
ui.log.scrollTop = ui.log.scrollHeight;
|
||||
}
|
||||
|
||||
|
||||
function logError(text) {
|
||||
if (ui.log.value.length > 0 &&
|
||||
ui.log.value[ui.log.value.length-1] != "\n") {
|
||||
ui.log.value += "\n";
|
||||
}
|
||||
ui.log.value += "ERROR: " + text + "\n";
|
||||
ui.log.scrollTop = ui.log.scrollHeight;
|
||||
error_logged = true;
|
||||
}
|
||||
|
||||
|
||||
function displayplot(args) {
|
||||
if (error_logged) {
|
||||
log("Plot failed.\n\n");
|
||||
} else {
|
||||
log("Displaying plot. Total time: " +
|
||||
(Date.now() - timer) / 1000 + "ms.\n\n");
|
||||
var blob = new Blob([new Uint8Array(args.contents).buffer],
|
||||
{ "type" : "image\/svg+xml" });
|
||||
window.URL = window.URL || window.webkitURL;
|
||||
ui.plot.src = window.URL.createObjectURL(blob);
|
||||
}
|
||||
|
||||
ui.thaw();
|
||||
ui.toggle("plot");
|
||||
}
|
||||
|
||||
|
||||
function displayprof(args) {
|
||||
if (error_logged) return;
|
||||
ui.prof.value = args;
|
||||
this.prof.style.color = "";
|
||||
ui.toggle("prof");
|
||||
}
|
||||
|
||||
|
||||
function start(event) {
|
||||
error_logged = false;
|
||||
ui.freeze();
|
||||
|
||||
try {
|
||||
var file = getSelectedFile();
|
||||
var distortion = getDistortion();
|
||||
var range = getRange();
|
||||
} catch (e) {
|
||||
logError(e.message);
|
||||
display();
|
||||
return;
|
||||
}
|
||||
|
||||
timer = Date.now();
|
||||
worker.run(file, kResX, kResY, distortion, range[0], range[1]);
|
||||
}
|
||||
|
||||
|
||||
function getSelectedFile() {
|
||||
var file = ui.file.files[0];
|
||||
if (!file) throw Error("No valid file selected.");
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
function getDistortion() {
|
||||
var input_distortion =
|
||||
parseInt(ui.distortion.value, 10);
|
||||
if (isNaN(input_distortion)) {
|
||||
input_distortion = ui.distortion.value = 4500;
|
||||
}
|
||||
return input_distortion / 1000000;
|
||||
}
|
||||
|
||||
|
||||
function getRange() {
|
||||
var input_start =
|
||||
parseInt(ui.range_start.value, 10);
|
||||
if (isNaN(input_start)) input_start = undefined;
|
||||
var input_end =
|
||||
parseInt(ui.range_end.value, 10);
|
||||
if (isNaN(input_end)) input_end = undefined;
|
||||
return [input_start, input_end];
|
||||
}
|
||||
|
||||
|
||||
function setRange(args) {
|
||||
ui.range_start.value = args.start.toFixed(1);
|
||||
ui.range_end.value = args.end.toFixed(1);
|
||||
}
|
||||
|
||||
|
||||
function onload() {
|
||||
kResX = 1200;
|
||||
kResY = 600;
|
||||
error_logged = false;
|
||||
ui = new UIWrapper();
|
||||
ui.reset();
|
||||
ui.info(null);
|
||||
worker = new plotWorker();
|
||||
worker.reset();
|
||||
}
|
||||
|
||||
|
||||
var kResX;
|
||||
var kResY;
|
||||
var error_logged;
|
||||
var ui;
|
||||
var worker;
|
||||
var timer;
|
@ -1,56 +0,0 @@
|
||||
// Copyright 2013 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
var processor = new ArgumentsProcessor(arguments);
|
||||
var distortion_per_entry = 0;
|
||||
var range_start_override = undefined;
|
||||
var range_end_override = undefined;
|
||||
|
||||
if (!processor.parse()) processor.printUsageAndExit();
|
||||
var result = processor.result();
|
||||
var distortion = parseInt(result.distortion);
|
||||
if (isNaN(distortion)) processor.printUsageAndExit();
|
||||
// Convert picoseconds to milliseconds.
|
||||
distortion_per_entry = distortion / 1000000;
|
||||
var rangelimits = result.range.split(",");
|
||||
var range_start = parseInt(rangelimits[0]);
|
||||
var range_end = parseInt(rangelimits[1]);
|
||||
if (!isNaN(range_start)) range_start_override = range_start;
|
||||
if (!isNaN(range_end)) range_end_override = range_end;
|
||||
|
||||
var kResX = 1600;
|
||||
var kResY = 600;
|
||||
function log_error(text) {
|
||||
print(text);
|
||||
quit(1);
|
||||
}
|
||||
var psc = new PlotScriptComposer(kResX, kResY, log_error);
|
||||
psc.collectData(readline, distortion_per_entry);
|
||||
psc.findPlotRange(range_start_override, range_end_override);
|
||||
print("set terminal pngcairo size " + kResX + "," + kResY +
|
||||
" enhanced font 'Helvetica,10'");
|
||||
psc.assembleOutput(print);
|
@ -1,171 +0,0 @@
|
||||
// Copyright 2013 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
var delegateList = {
|
||||
"load scripts" : load_scripts,
|
||||
"run" : run,
|
||||
}
|
||||
|
||||
self.addEventListener("message", function(event) {
|
||||
var call = delegateList[event.data["call"]];
|
||||
var result = call(event.data["args"]);
|
||||
}, false);
|
||||
|
||||
|
||||
function log(text) {
|
||||
self.postMessage({ "call" : "log", "args" : text });
|
||||
}
|
||||
|
||||
|
||||
function displayplot(content) {
|
||||
self.postMessage({ "call" : "displayplot", "args" : content});
|
||||
}
|
||||
|
||||
|
||||
function displayprof(content) {
|
||||
self.postMessage({ "call" : "displayprof", "args" : content});
|
||||
}
|
||||
|
||||
|
||||
function setRange(start, end) {
|
||||
self.postMessage({ "call" : "range",
|
||||
"args" : { "start" : start, "end" : end } });
|
||||
}
|
||||
|
||||
|
||||
function time(name, fun) {
|
||||
log(name + "...");
|
||||
var start = Date.now();
|
||||
fun();
|
||||
log(" took " + (Date.now() - start) / 1000 + "s.\n");
|
||||
}
|
||||
|
||||
|
||||
function load_scripts(scripts) {
|
||||
time("Loading scripts",
|
||||
function() { for (var i in scripts) importScripts(scripts[i]); });
|
||||
self.postMessage({ "call" : "script" });
|
||||
}
|
||||
|
||||
|
||||
function log_error(text) {
|
||||
self.postMessage({"call": "error", "args": text});
|
||||
self.postMessage({"call": "reset"});
|
||||
}
|
||||
|
||||
|
||||
function run(args) {
|
||||
var file = args["file"];
|
||||
var resx = args["resx"];
|
||||
var resy = args["resy"];
|
||||
var distortion = args["distortion"];
|
||||
var range_start_override = args["range_start"];
|
||||
var range_end_override = args["range_end"];
|
||||
|
||||
var reader = new FileReaderSync();
|
||||
var content_lines;
|
||||
|
||||
time("Reading log file (" + (file.size / 1024).toFixed(1) + " kB)",
|
||||
function() {
|
||||
var content = reader.readAsText(file);
|
||||
content_lines = content.split("\n");
|
||||
});
|
||||
|
||||
time("Producing statistical profile",
|
||||
function() {
|
||||
var profile = "";
|
||||
print = function(text) { profile += text + "\n"; };
|
||||
// Dummy entries provider, as we cannot call nm.
|
||||
var entriesProvider = new UnixCppEntriesProvider("", "", "");
|
||||
var targetRootFS = "";
|
||||
var separateIc = false;
|
||||
var callGraphSize = 5;
|
||||
var ignoreUnknown = true;
|
||||
var stateFilter = null;
|
||||
var range = range_start_override + "," + range_end_override;
|
||||
|
||||
var tickProcessor = new TickProcessor(entriesProvider,
|
||||
separateIc,
|
||||
callGraphSize,
|
||||
ignoreUnknown,
|
||||
stateFilter,
|
||||
distortion,
|
||||
range);
|
||||
for (var i = 0; i < content_lines.length; i++) {
|
||||
tickProcessor.processLogLine(content_lines[i]);
|
||||
}
|
||||
tickProcessor.printStatistics();
|
||||
displayprof(profile);
|
||||
});
|
||||
|
||||
var input_file_name = "input_temp";
|
||||
var output_file_name = "output.svg";
|
||||
|
||||
var psc = new PlotScriptComposer(resx, resy, log_error);
|
||||
var objects = 0;
|
||||
|
||||
time("Collecting events (" + content_lines.length + " entries)",
|
||||
function() {
|
||||
var line_cursor = 0;
|
||||
var input = function() { return content_lines[line_cursor++]; };
|
||||
psc.collectData(input, distortion);
|
||||
psc.findPlotRange(range_start_override,
|
||||
range_end_override,
|
||||
setRange);
|
||||
});
|
||||
|
||||
time("Assembling plot script",
|
||||
function() {
|
||||
var plot_script = "";
|
||||
var output = function(text) { plot_script += text + "\n"; };
|
||||
output("set terminal svg size " + resx + "," + resy +
|
||||
" enhanced font \"Helvetica,10\"");
|
||||
output("set output \""+ output_file_name + "\"");
|
||||
objects = psc.assembleOutput(output);
|
||||
if (FS.findObject(input_file_name)) {
|
||||
FS.deleteFile(input_file_name);
|
||||
}
|
||||
var arrc = Module["intArrayFromString"](plot_script, true);
|
||||
FS.createDataFile("/", input_file_name, arrc);
|
||||
});
|
||||
|
||||
time("Running gnuplot (" + objects + " objects)",
|
||||
function() { Module.run([input_file_name]); });
|
||||
|
||||
displayplot(FS.findObject(output_file_name));
|
||||
}
|
||||
|
||||
|
||||
var Module = {
|
||||
"noInitialRun": true,
|
||||
print: function(text) {
|
||||
self.postMessage({"call": "error", "args": text});
|
||||
},
|
||||
printErr: function(text) {
|
||||
self.postMessage({"call": "error", "args": text});
|
||||
},
|
||||
};
|
Loading…
Reference in New Issue
Block a user