[tools] Convert JS-tools to ES6 modules
This changes all tools to use ES6 modules and proper imports. Step 1: Add converted .mjs files (*this CL*) Step 2: Update node-ci build to use new .mjs files Step 3: Remove outdated .js files Bug: v8:10667, v8:10933 Change-Id: I3e92e66f896d8a9cacaf6d421f8d2c86fb3bc444 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2431045 Commit-Queue: Camillo Bruni <cbruni@chromium.org> Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org> Cr-Commit-Position: refs/heads/master@{#70163}
This commit is contained in:
parent
630fbf672a
commit
94bce1dcac
@ -15,15 +15,15 @@ group("v8_mjsunit") {
|
|||||||
"../../tools/clusterfuzz/v8_mock.js",
|
"../../tools/clusterfuzz/v8_mock.js",
|
||||||
"../../tools/clusterfuzz/v8_mock_archs.js",
|
"../../tools/clusterfuzz/v8_mock_archs.js",
|
||||||
"../../tools/clusterfuzz/v8_mock_webassembly.js",
|
"../../tools/clusterfuzz/v8_mock_webassembly.js",
|
||||||
"../../tools/codemap.js",
|
"../../tools/codemap.mjs",
|
||||||
"../../tools/consarray.js",
|
"../../tools/consarray.mjs",
|
||||||
"../../tools/csvparser.js",
|
"../../tools/csvparser.mjs",
|
||||||
"../../tools/logreader.js",
|
"../../tools/logreader.mjs",
|
||||||
"../../tools/arguments.js",
|
"../../tools/arguments.mjs",
|
||||||
"../../tools/profile.js",
|
"../../tools/profile.mjs",
|
||||||
"../../tools/profile_view.js",
|
"../../tools/profile_view.mjs",
|
||||||
"../../tools/splaytree.js",
|
"../../tools/splaytree.mjs",
|
||||||
"../../tools/tickprocessor.js",
|
"../../tools/tickprocessor.mjs",
|
||||||
"../../tools/dumpcpp.js",
|
"../../tools/dumpcpp.mjs",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,7 @@
|
|||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// Load Splay tree and CodeMap implementations from <project root>/tools.
|
import { CodeMap } from "../../../tools/codemap.mjs";
|
||||||
// Files: tools/splaytree.js tools/codemap.js
|
|
||||||
|
|
||||||
|
|
||||||
function newCodeEntry(size, name) {
|
function newCodeEntry(size, name) {
|
||||||
return new CodeMap.CodeEntry(size, name);
|
return new CodeMap.CodeEntry(size, name);
|
@ -25,9 +25,7 @@
|
|||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// Load ConsArray implementation from <project root>/tools.
|
import { ConsArray } from "../../../tools/consarray.mjs";
|
||||||
// Files: tools/consarray.js
|
|
||||||
|
|
||||||
|
|
||||||
var arr1 = new ConsArray();
|
var arr1 = new ConsArray();
|
||||||
assertTrue(arr1.atEnd());
|
assertTrue(arr1.atEnd());
|
@ -25,8 +25,7 @@
|
|||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// Load CSV parser implementation from <project root>/tools.
|
import { CsvParser } from "../../../tools/csvparser.mjs";
|
||||||
// Files: tools/csvparser.js
|
|
||||||
|
|
||||||
var parser = new CsvParser();
|
var parser = new CsvParser();
|
||||||
|
|
@ -2,12 +2,9 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
// Load implementations from <project root>/tools.
|
import {
|
||||||
// Files: tools/splaytree.js tools/codemap.js tools/csvparser.js
|
CppProcessor, UnixCppEntriesProvider
|
||||||
// Files: tools/consarray.js tools/profile.js tools/profile_view.js
|
} from "../../../tools/dumpcpp.mjs" ;
|
||||||
// Files: tools/logreader.js tools/arguments.js tools/tickprocessor.js
|
|
||||||
// Files: tools/dumpcpp.js
|
|
||||||
// Env: TEST_FILE_NAME
|
|
||||||
|
|
||||||
(function testProcessSharedLibrary() {
|
(function testProcessSharedLibrary() {
|
||||||
var oldLoadSymbols = UnixCppEntriesProvider.prototype.loadSymbols;
|
var oldLoadSymbols = UnixCppEntriesProvider.prototype.loadSymbols;
|
@ -25,9 +25,7 @@
|
|||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// Load source code files from <project root>/tools.
|
import { Profile } from "../../../tools/profile.mjs";
|
||||||
// Files: tools/splaytree.js tools/codemap.js tools/consarray.js tools/profile.js
|
|
||||||
|
|
||||||
|
|
||||||
function stackToString(stack) {
|
function stackToString(stack) {
|
||||||
return stack.join(' -> ');
|
return stack.join(' -> ');
|
@ -25,9 +25,7 @@
|
|||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// Load source code files from <project root>/tools.
|
import { ProfileView } from "../../../tools/profile_view.mjs";
|
||||||
// Files: tools/codemap.js tools/consarray.js tools/profile.js
|
|
||||||
// Files: tools/profile_view.js
|
|
||||||
|
|
||||||
|
|
||||||
function createNode(name, time, opt_parent) {
|
function createNode(name, time, opt_parent) {
|
@ -25,8 +25,7 @@
|
|||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// Load the Splay tree implementation from <project root>/tools.
|
import { SplayTree } from "../../../tools/splaytree.mjs";
|
||||||
// Files: tools/splaytree.js
|
|
||||||
|
|
||||||
|
|
||||||
(function testIsEmpty() {
|
(function testIsEmpty() {
|
@ -25,10 +25,6 @@
|
|||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// Load implementations from <project root>/tools.
|
|
||||||
// Files: tools/splaytree.js tools/codemap.js tools/csvparser.js
|
|
||||||
// Files: tools/consarray.js tools/profile.js tools/profile_view.js
|
|
||||||
// Files: tools/logreader.js tools/arguments.js tools/tickprocessor.js
|
|
||||||
// Resources: test/mjsunit/tools/tickprocessor-test-func-info.log
|
// Resources: test/mjsunit/tools/tickprocessor-test-func-info.log
|
||||||
// Resources: test/mjsunit/tools/tickprocessor-test.default
|
// Resources: test/mjsunit/tools/tickprocessor-test.default
|
||||||
// Resources: test/mjsunit/tools/tickprocessor-test.func-info
|
// Resources: test/mjsunit/tools/tickprocessor-test.func-info
|
||||||
@ -39,6 +35,11 @@
|
|||||||
// Resources: test/mjsunit/tools/tickprocessor-test.separate-ic
|
// Resources: test/mjsunit/tools/tickprocessor-test.separate-ic
|
||||||
// Env: TEST_FILE_NAME
|
// Env: TEST_FILE_NAME
|
||||||
|
|
||||||
|
import {
|
||||||
|
TickProcessor, ArgumentsProcessor, UnixCppEntriesProvider,
|
||||||
|
MacCppEntriesProvider, WindowsCppEntriesProvider, readFile
|
||||||
|
} from "../../../tools/tickprocessor.mjs";
|
||||||
|
|
||||||
|
|
||||||
(function testArgumentsProcessor() {
|
(function testArgumentsProcessor() {
|
||||||
var p_default = new ArgumentsProcessor([]);
|
var p_default = new ArgumentsProcessor([]);
|
382
tools/SourceMap.mjs
Normal file
382
tools/SourceMap.mjs
Normal file
@ -0,0 +1,382 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// This is a copy from blink dev tools, see:
|
||||||
|
// http://src.chromium.org/viewvc/blink/trunk/Source/devtools/front_end/SourceMap.js
|
||||||
|
// revision: 153407
|
||||||
|
|
||||||
|
// Added to make the file work without dev tools
|
||||||
|
export const WebInspector = {};
|
||||||
|
WebInspector.ParsedURL = {};
|
||||||
|
WebInspector.ParsedURL.completeURL = function(){};
|
||||||
|
// start of original file content
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 Google Inc. 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements Source Map V3 model. See http://code.google.com/p/closure-compiler/wiki/SourceMaps
|
||||||
|
* for format description.
|
||||||
|
* @constructor
|
||||||
|
* @param {string} sourceMappingURL
|
||||||
|
* @param {SourceMapV3} payload
|
||||||
|
*/
|
||||||
|
WebInspector.SourceMap = function(sourceMappingURL, payload)
|
||||||
|
{
|
||||||
|
if (!WebInspector.SourceMap.prototype._base64Map) {
|
||||||
|
const base64Digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
|
WebInspector.SourceMap.prototype._base64Map = {};
|
||||||
|
for (var i = 0; i < base64Digits.length; ++i)
|
||||||
|
WebInspector.SourceMap.prototype._base64Map[base64Digits.charAt(i)] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._sourceMappingURL = sourceMappingURL;
|
||||||
|
this._reverseMappingsBySourceURL = {};
|
||||||
|
this._mappings = [];
|
||||||
|
this._sources = {};
|
||||||
|
this._sourceContentByURL = {};
|
||||||
|
this._parseMappingPayload(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sourceMapURL
|
||||||
|
* @param {string} compiledURL
|
||||||
|
* @param {function(WebInspector.SourceMap)} callback
|
||||||
|
*/
|
||||||
|
WebInspector.SourceMap.load = function(sourceMapURL, compiledURL, callback)
|
||||||
|
{
|
||||||
|
NetworkAgent.loadResourceForFrontend(WebInspector.resourceTreeModel.mainFrame.id, sourceMapURL, undefined, contentLoaded.bind(this));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Protocol.Error} error
|
||||||
|
* @param {number} statusCode
|
||||||
|
* @param {NetworkAgent.Headers} headers
|
||||||
|
* @param {string} content
|
||||||
|
*/
|
||||||
|
function contentLoaded(error, statusCode, headers, content)
|
||||||
|
{
|
||||||
|
if (error || !content || statusCode >= 400) {
|
||||||
|
console.error("Could not load content for " + sourceMapURL + " : " + (error || ("HTTP status code: " + statusCode)));
|
||||||
|
callback(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (content.slice(0, 3) === ")]}")
|
||||||
|
content = content.substring(content.indexOf('\n'));
|
||||||
|
try {
|
||||||
|
var payload = /** @type {SourceMapV3} */ (JSON.parse(content));
|
||||||
|
var baseURL = sourceMapURL.startsWith("data:") ? compiledURL : sourceMapURL;
|
||||||
|
callback(new WebInspector.SourceMap(baseURL, payload));
|
||||||
|
} catch(e) {
|
||||||
|
console.error(e.message);
|
||||||
|
callback(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WebInspector.SourceMap.prototype = {
|
||||||
|
/**
|
||||||
|
* @return {Array.<string>}
|
||||||
|
*/
|
||||||
|
sources: function()
|
||||||
|
{
|
||||||
|
return Object.keys(this._sources);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sourceURL
|
||||||
|
* @return {string|undefined}
|
||||||
|
*/
|
||||||
|
sourceContent: function(sourceURL)
|
||||||
|
{
|
||||||
|
return this._sourceContentByURL[sourceURL];
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sourceURL
|
||||||
|
* @param {WebInspector.ResourceType} contentType
|
||||||
|
* @return {WebInspector.ContentProvider}
|
||||||
|
*/
|
||||||
|
sourceContentProvider: function(sourceURL, contentType)
|
||||||
|
{
|
||||||
|
var lastIndexOfDot = sourceURL.lastIndexOf(".");
|
||||||
|
var extension = lastIndexOfDot !== -1 ? sourceURL.substr(lastIndexOfDot + 1) : "";
|
||||||
|
var mimeType = WebInspector.ResourceType.mimeTypesForExtensions[extension.toLowerCase()];
|
||||||
|
var sourceContent = this.sourceContent(sourceURL);
|
||||||
|
if (sourceContent)
|
||||||
|
return new WebInspector.StaticContentProvider(contentType, sourceContent, mimeType);
|
||||||
|
return new WebInspector.CompilerSourceMappingContentProvider(sourceURL, contentType, mimeType);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {SourceMapV3} mappingPayload
|
||||||
|
*/
|
||||||
|
_parseMappingPayload: function(mappingPayload)
|
||||||
|
{
|
||||||
|
if (mappingPayload.sections)
|
||||||
|
this._parseSections(mappingPayload.sections);
|
||||||
|
else
|
||||||
|
this._parseMap(mappingPayload, 0, 0);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array.<SourceMapV3.Section>} sections
|
||||||
|
*/
|
||||||
|
_parseSections: function(sections)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < sections.length; ++i) {
|
||||||
|
var section = sections[i];
|
||||||
|
this._parseMap(section.map, section.offset.line, section.offset.column);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} lineNumber in compiled resource
|
||||||
|
* @param {number} columnNumber in compiled resource
|
||||||
|
* @return {?Array}
|
||||||
|
*/
|
||||||
|
findEntry: function(lineNumber, columnNumber)
|
||||||
|
{
|
||||||
|
var first = 0;
|
||||||
|
var count = this._mappings.length;
|
||||||
|
while (count > 1) {
|
||||||
|
var step = count >> 1;
|
||||||
|
var middle = first + step;
|
||||||
|
var mapping = this._mappings[middle];
|
||||||
|
if (lineNumber < mapping[0] || (lineNumber === mapping[0] && columnNumber < mapping[1]))
|
||||||
|
count = step;
|
||||||
|
else {
|
||||||
|
first = middle;
|
||||||
|
count -= step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var entry = this._mappings[first];
|
||||||
|
if (!first && entry && (lineNumber < entry[0] || (lineNumber === entry[0] && columnNumber < entry[1])))
|
||||||
|
return null;
|
||||||
|
return entry;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sourceURL of the originating resource
|
||||||
|
* @param {number} lineNumber in the originating resource
|
||||||
|
* @return {Array}
|
||||||
|
*/
|
||||||
|
findEntryReversed: function(sourceURL, lineNumber)
|
||||||
|
{
|
||||||
|
var mappings = this._reverseMappingsBySourceURL[sourceURL];
|
||||||
|
for ( ; lineNumber < mappings.length; ++lineNumber) {
|
||||||
|
var mapping = mappings[lineNumber];
|
||||||
|
if (mapping)
|
||||||
|
return mapping;
|
||||||
|
}
|
||||||
|
return this._mappings[0];
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
_parseMap: function(map, lineNumber, columnNumber)
|
||||||
|
{
|
||||||
|
var sourceIndex = 0;
|
||||||
|
var sourceLineNumber = 0;
|
||||||
|
var sourceColumnNumber = 0;
|
||||||
|
var nameIndex = 0;
|
||||||
|
|
||||||
|
var sources = [];
|
||||||
|
var originalToCanonicalURLMap = {};
|
||||||
|
for (var i = 0; i < map.sources.length; ++i) {
|
||||||
|
var originalSourceURL = map.sources[i];
|
||||||
|
var sourceRoot = map.sourceRoot || "";
|
||||||
|
if (sourceRoot && !sourceRoot.endsWith("/"))
|
||||||
|
sourceRoot += "/";
|
||||||
|
var href = sourceRoot + originalSourceURL;
|
||||||
|
var url = WebInspector.ParsedURL.completeURL(this._sourceMappingURL, href) || href;
|
||||||
|
originalToCanonicalURLMap[originalSourceURL] = url;
|
||||||
|
sources.push(url);
|
||||||
|
this._sources[url] = true;
|
||||||
|
|
||||||
|
if (map.sourcesContent && map.sourcesContent[i])
|
||||||
|
this._sourceContentByURL[url] = map.sourcesContent[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
var stringCharIterator = new WebInspector.SourceMap.StringCharIterator(map.mappings);
|
||||||
|
var sourceURL = sources[sourceIndex];
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (stringCharIterator.peek() === ",")
|
||||||
|
stringCharIterator.next();
|
||||||
|
else {
|
||||||
|
while (stringCharIterator.peek() === ";") {
|
||||||
|
lineNumber += 1;
|
||||||
|
columnNumber = 0;
|
||||||
|
stringCharIterator.next();
|
||||||
|
}
|
||||||
|
if (!stringCharIterator.hasNext())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
columnNumber += this._decodeVLQ(stringCharIterator);
|
||||||
|
if (this._isSeparator(stringCharIterator.peek())) {
|
||||||
|
this._mappings.push([lineNumber, columnNumber]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sourceIndexDelta = this._decodeVLQ(stringCharIterator);
|
||||||
|
if (sourceIndexDelta) {
|
||||||
|
sourceIndex += sourceIndexDelta;
|
||||||
|
sourceURL = sources[sourceIndex];
|
||||||
|
}
|
||||||
|
sourceLineNumber += this._decodeVLQ(stringCharIterator);
|
||||||
|
sourceColumnNumber += this._decodeVLQ(stringCharIterator);
|
||||||
|
if (!this._isSeparator(stringCharIterator.peek()))
|
||||||
|
nameIndex += this._decodeVLQ(stringCharIterator);
|
||||||
|
|
||||||
|
this._mappings.push([lineNumber, columnNumber, sourceURL, sourceLineNumber, sourceColumnNumber]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < this._mappings.length; ++i) {
|
||||||
|
var mapping = this._mappings[i];
|
||||||
|
var url = mapping[2];
|
||||||
|
if (!url)
|
||||||
|
continue;
|
||||||
|
if (!this._reverseMappingsBySourceURL[url])
|
||||||
|
this._reverseMappingsBySourceURL[url] = [];
|
||||||
|
var reverseMappings = this._reverseMappingsBySourceURL[url];
|
||||||
|
var sourceLine = mapping[3];
|
||||||
|
if (!reverseMappings[sourceLine])
|
||||||
|
reverseMappings[sourceLine] = [mapping[0], mapping[1]];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} char
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
_isSeparator: function(char)
|
||||||
|
{
|
||||||
|
return char === "," || char === ";";
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {WebInspector.SourceMap.StringCharIterator} stringCharIterator
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
_decodeVLQ: function(stringCharIterator)
|
||||||
|
{
|
||||||
|
// Read unsigned value.
|
||||||
|
var result = 0;
|
||||||
|
var shift = 0;
|
||||||
|
do {
|
||||||
|
var digit = this._base64Map[stringCharIterator.next()];
|
||||||
|
result += (digit & this._VLQ_BASE_MASK) << shift;
|
||||||
|
shift += this._VLQ_BASE_SHIFT;
|
||||||
|
} while (digit & this._VLQ_CONTINUATION_MASK);
|
||||||
|
|
||||||
|
// Fix the sign.
|
||||||
|
var negative = result & 1;
|
||||||
|
// Use unsigned right shift, so that the 32nd bit is properly shifted
|
||||||
|
// to the 31st, and the 32nd becomes unset.
|
||||||
|
result >>>= 1;
|
||||||
|
if (negate) {
|
||||||
|
// We need to OR 0x80000000 here to ensure the 32nd bit (the sign bit
|
||||||
|
// in a 32bit int) is always set for negative numbers. If `result`
|
||||||
|
// were 1, (meaning `negate` is true and all other bits were zeros),
|
||||||
|
// `result` would now be 0. But -0 doesn't flip the 32nd bit as
|
||||||
|
// intended. All other numbers will successfully set the 32nd bit
|
||||||
|
// without issue, so doing this is a noop for them.
|
||||||
|
return -result | 0x80000000;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
_VLQ_BASE_SHIFT: 5,
|
||||||
|
_VLQ_BASE_MASK: (1 << 5) - 1,
|
||||||
|
_VLQ_CONTINUATION_MASK: 1 << 5
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @param {string} string
|
||||||
|
*/
|
||||||
|
WebInspector.SourceMap.StringCharIterator = function(string)
|
||||||
|
{
|
||||||
|
this._string = string;
|
||||||
|
this._position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
WebInspector.SourceMap.StringCharIterator.prototype = {
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
next: function()
|
||||||
|
{
|
||||||
|
return this._string.charAt(this._position++);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
peek: function()
|
||||||
|
{
|
||||||
|
return this._string.charAt(this._position);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
hasNext: function()
|
||||||
|
{
|
||||||
|
return this._position < this._string.length;
|
||||||
|
}
|
||||||
|
}
|
78
tools/arguments.mjs
Normal file
78
tools/arguments.mjs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
// Copyright 2017 the V8 project authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
export class BaseArgumentsProcessor {
|
||||||
|
constructor(args) {
|
||||||
|
this.args_ = args;
|
||||||
|
this.result_ = this.getDefaultResults();
|
||||||
|
console.assert(this.result_ !== undefined)
|
||||||
|
console.assert(this.result_.logFileName !== undefined);
|
||||||
|
this.argsDispatch_ = this.getArgsDispatch();
|
||||||
|
console.assert(this.argsDispatch_ !== undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
getDefaultResults() {
|
||||||
|
throw "Implement in getDefaultResults in subclass";
|
||||||
|
}
|
||||||
|
|
||||||
|
getArgsDispatch() {
|
||||||
|
throw "Implement getArgsDispatch in subclass";
|
||||||
|
}
|
||||||
|
|
||||||
|
result() { return this.result_ }
|
||||||
|
|
||||||
|
printUsageAndExit() {
|
||||||
|
print('Cmdline args: [options] [log-file-name]\n' +
|
||||||
|
'Default log file name is "' +
|
||||||
|
this.result_.logFileName + '".\n');
|
||||||
|
print('Options:');
|
||||||
|
for (var arg in this.argsDispatch_) {
|
||||||
|
var synonyms = [arg];
|
||||||
|
var dispatch = this.argsDispatch_[arg];
|
||||||
|
for (var synArg in this.argsDispatch_) {
|
||||||
|
if (arg !== synArg && dispatch === this.argsDispatch_[synArg]) {
|
||||||
|
synonyms.push(synArg);
|
||||||
|
delete this.argsDispatch_[synArg];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print(' ' + synonyms.join(', ').padEnd(20) + " " + dispatch[2]);
|
||||||
|
}
|
||||||
|
quit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
parse() {
|
||||||
|
while (this.args_.length) {
|
||||||
|
var arg = this.args_.shift();
|
||||||
|
if (arg.charAt(0) != '-') {
|
||||||
|
this.result_.logFileName = arg;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var userValue = null;
|
||||||
|
var eqPos = arg.indexOf('=');
|
||||||
|
if (eqPos != -1) {
|
||||||
|
userValue = arg.substr(eqPos + 1);
|
||||||
|
arg = arg.substr(0, eqPos);
|
||||||
|
}
|
||||||
|
if (arg in this.argsDispatch_) {
|
||||||
|
var dispatch = this.argsDispatch_[arg];
|
||||||
|
var property = dispatch[0];
|
||||||
|
var defaultValue = dispatch[1];
|
||||||
|
if (typeof defaultValue == "function") {
|
||||||
|
userValue = defaultValue(userValue);
|
||||||
|
} else if (userValue == null) {
|
||||||
|
userValue = defaultValue;
|
||||||
|
}
|
||||||
|
this.result_[property] = userValue;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseBool(str) {
|
||||||
|
if (str == "true" || str == "1") return true;
|
||||||
|
return false;
|
||||||
|
}
|
321
tools/codemap.mjs
Normal file
321
tools/codemap.mjs
Normal file
@ -0,0 +1,321 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
import { SplayTree } from "./splaytree.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a mapper that maps addresses into code entries.
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
export function CodeMap() {
|
||||||
|
/**
|
||||||
|
* Dynamic code entries. Used for JIT compiled code.
|
||||||
|
*/
|
||||||
|
this.dynamics_ = new SplayTree();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name generator for entries having duplicate names.
|
||||||
|
*/
|
||||||
|
this.dynamicsNameGen_ = new CodeMap.NameGenerator();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static code entries. Used for statically compiled code.
|
||||||
|
*/
|
||||||
|
this.statics_ = new SplayTree();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Libraries entries. Used for the whole static code libraries.
|
||||||
|
*/
|
||||||
|
this.libraries_ = new SplayTree();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map of memory pages occupied with static code.
|
||||||
|
*/
|
||||||
|
this.pages_ = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of alignment bits in a page address.
|
||||||
|
*/
|
||||||
|
CodeMap.PAGE_ALIGNMENT = 12;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Page size in bytes.
|
||||||
|
*/
|
||||||
|
CodeMap.PAGE_SIZE =
|
||||||
|
1 << CodeMap.PAGE_ALIGNMENT;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a dynamic (i.e. moveable and discardable) code entry.
|
||||||
|
*
|
||||||
|
* @param {number} start The starting address.
|
||||||
|
* @param {CodeMap.CodeEntry} codeEntry Code entry object.
|
||||||
|
*/
|
||||||
|
CodeMap.prototype.addCode = function(start, codeEntry) {
|
||||||
|
this.deleteAllCoveredNodes_(this.dynamics_, start, start + codeEntry.size);
|
||||||
|
this.dynamics_.insert(start, codeEntry);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves a dynamic code entry. Throws an exception if there is no dynamic
|
||||||
|
* code entry with the specified starting address.
|
||||||
|
*
|
||||||
|
* @param {number} from The starting address of the entry being moved.
|
||||||
|
* @param {number} to The destination address.
|
||||||
|
*/
|
||||||
|
CodeMap.prototype.moveCode = function(from, to) {
|
||||||
|
var removedNode = this.dynamics_.remove(from);
|
||||||
|
this.deleteAllCoveredNodes_(this.dynamics_, to, to + removedNode.value.size);
|
||||||
|
this.dynamics_.insert(to, removedNode.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discards a dynamic code entry. Throws an exception if there is no dynamic
|
||||||
|
* code entry with the specified starting address.
|
||||||
|
*
|
||||||
|
* @param {number} start The starting address of the entry being deleted.
|
||||||
|
*/
|
||||||
|
CodeMap.prototype.deleteCode = function(start) {
|
||||||
|
var removedNode = this.dynamics_.remove(start);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a library entry.
|
||||||
|
*
|
||||||
|
* @param {number} start The starting address.
|
||||||
|
* @param {CodeMap.CodeEntry} codeEntry Code entry object.
|
||||||
|
*/
|
||||||
|
CodeMap.prototype.addLibrary = function(
|
||||||
|
start, codeEntry) {
|
||||||
|
this.markPages_(start, start + codeEntry.size);
|
||||||
|
this.libraries_.insert(start, codeEntry);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a static code entry.
|
||||||
|
*
|
||||||
|
* @param {number} start The starting address.
|
||||||
|
* @param {CodeMap.CodeEntry} codeEntry Code entry object.
|
||||||
|
*/
|
||||||
|
CodeMap.prototype.addStaticCode = function(
|
||||||
|
start, codeEntry) {
|
||||||
|
this.statics_.insert(start, codeEntry);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
CodeMap.prototype.markPages_ = function(start, end) {
|
||||||
|
for (var addr = start; addr <= end;
|
||||||
|
addr += CodeMap.PAGE_SIZE) {
|
||||||
|
this.pages_[(addr / CodeMap.PAGE_SIZE)|0] = 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
CodeMap.prototype.deleteAllCoveredNodes_ = function(tree, start, end) {
|
||||||
|
var to_delete = [];
|
||||||
|
var addr = end - 1;
|
||||||
|
while (addr >= start) {
|
||||||
|
var node = tree.findGreatestLessThan(addr);
|
||||||
|
if (!node) break;
|
||||||
|
var start2 = node.key, end2 = start2 + node.value.size;
|
||||||
|
if (start2 < end && start < end2) to_delete.push(start2);
|
||||||
|
addr = start2 - 1;
|
||||||
|
}
|
||||||
|
for (var i = 0, l = to_delete.length; i < l; ++i) tree.remove(to_delete[i]);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
CodeMap.prototype.isAddressBelongsTo_ = function(addr, node) {
|
||||||
|
return addr >= node.key && addr < (node.key + node.value.size);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
CodeMap.prototype.findInTree_ = function(tree, addr) {
|
||||||
|
var node = tree.findGreatestLessThan(addr);
|
||||||
|
return node && this.isAddressBelongsTo_(addr, node) ? node : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a code entry that contains the specified address. Both static and
|
||||||
|
* dynamic code entries are considered. Returns the code entry and the offset
|
||||||
|
* within the entry.
|
||||||
|
*
|
||||||
|
* @param {number} addr Address.
|
||||||
|
*/
|
||||||
|
CodeMap.prototype.findAddress = function(addr) {
|
||||||
|
var pageAddr = (addr / CodeMap.PAGE_SIZE)|0;
|
||||||
|
if (pageAddr in this.pages_) {
|
||||||
|
// Static code entries can contain "holes" of unnamed code.
|
||||||
|
// In this case, the whole library is assigned to this address.
|
||||||
|
var result = this.findInTree_(this.statics_, addr);
|
||||||
|
if (!result) {
|
||||||
|
result = this.findInTree_(this.libraries_, addr);
|
||||||
|
if (!result) return null;
|
||||||
|
}
|
||||||
|
return { entry : result.value, offset : addr - result.key };
|
||||||
|
}
|
||||||
|
var min = this.dynamics_.findMin();
|
||||||
|
var max = this.dynamics_.findMax();
|
||||||
|
if (max != null && addr < (max.key + max.value.size) && addr >= min.key) {
|
||||||
|
var dynaEntry = this.findInTree_(this.dynamics_, addr);
|
||||||
|
if (dynaEntry == null) return null;
|
||||||
|
// Dedupe entry name.
|
||||||
|
var entry = dynaEntry.value;
|
||||||
|
if (!entry.nameUpdated_) {
|
||||||
|
entry.name = this.dynamicsNameGen_.getName(entry.name);
|
||||||
|
entry.nameUpdated_ = true;
|
||||||
|
}
|
||||||
|
return { entry : entry, offset : addr - dynaEntry.key };
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a code entry that contains the specified address. Both static and
|
||||||
|
* dynamic code entries are considered.
|
||||||
|
*
|
||||||
|
* @param {number} addr Address.
|
||||||
|
*/
|
||||||
|
CodeMap.prototype.findEntry = function(addr) {
|
||||||
|
var result = this.findAddress(addr);
|
||||||
|
return result ? result.entry : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a dynamic code entry using its starting address.
|
||||||
|
*
|
||||||
|
* @param {number} addr Address.
|
||||||
|
*/
|
||||||
|
CodeMap.prototype.findDynamicEntryByStartAddress =
|
||||||
|
function(addr) {
|
||||||
|
var node = this.dynamics_.find(addr);
|
||||||
|
return node ? node.value : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of all dynamic code entries.
|
||||||
|
*/
|
||||||
|
CodeMap.prototype.getAllDynamicEntries = function() {
|
||||||
|
return this.dynamics_.exportValues();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of pairs of all dynamic code entries and their addresses.
|
||||||
|
*/
|
||||||
|
CodeMap.prototype.getAllDynamicEntriesWithAddresses = function() {
|
||||||
|
return this.dynamics_.exportKeysAndValues();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of all static code entries.
|
||||||
|
*/
|
||||||
|
CodeMap.prototype.getAllStaticEntries = function() {
|
||||||
|
return this.statics_.exportValues();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of pairs of all static code entries and their addresses.
|
||||||
|
*/
|
||||||
|
CodeMap.prototype.getAllStaticEntriesWithAddresses = function() {
|
||||||
|
return this.statics_.exportKeysAndValues();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of all libraries entries.
|
||||||
|
*/
|
||||||
|
CodeMap.prototype.getAllLibrariesEntries = function() {
|
||||||
|
return this.libraries_.exportValues();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a code entry object.
|
||||||
|
*
|
||||||
|
* @param {number} size Code entry size in bytes.
|
||||||
|
* @param {string} opt_name Code entry name.
|
||||||
|
* @param {string} opt_type Code entry type, e.g. SHARED_LIB, CPP.
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
CodeMap.CodeEntry = function(size, opt_name, opt_type) {
|
||||||
|
this.size = size;
|
||||||
|
this.name = opt_name || '';
|
||||||
|
this.type = opt_type || '';
|
||||||
|
this.nameUpdated_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
CodeMap.CodeEntry.prototype.getName = function() {
|
||||||
|
return this.name;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
CodeMap.CodeEntry.prototype.toString = function() {
|
||||||
|
return this.name + ': ' + this.size.toString(16);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
CodeMap.NameGenerator = function() {
|
||||||
|
this.knownNames_ = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
CodeMap.NameGenerator.prototype.getName = function(name) {
|
||||||
|
if (!(name in this.knownNames_)) {
|
||||||
|
this.knownNames_[name] = 0;
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
var count = ++this.knownNames_[name];
|
||||||
|
return name + ' {' + count + '}';
|
||||||
|
};
|
92
tools/consarray.mjs
Normal file
92
tools/consarray.mjs
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a ConsArray object. It is used mainly for tree traversal.
|
||||||
|
* In this use case we have lots of arrays that we need to iterate
|
||||||
|
* sequentally. The internal Array implementation is horribly slow
|
||||||
|
* when concatenating on large (10K items) arrays due to memory copying.
|
||||||
|
* That's why we avoid copying memory and insead build a linked list
|
||||||
|
* of arrays to iterate through.
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
export function ConsArray() {
|
||||||
|
this.tail_ = new ConsArray.Cell(null, null);
|
||||||
|
this.currCell_ = this.tail_;
|
||||||
|
this.currCellPos_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Concatenates another array for iterating. Empty arrays are ignored.
|
||||||
|
* This operation can be safely performed during ongoing ConsArray
|
||||||
|
* iteration.
|
||||||
|
*
|
||||||
|
* @param {Array} arr Array to concatenate.
|
||||||
|
*/
|
||||||
|
ConsArray.prototype.concat = function(arr) {
|
||||||
|
if (arr.length > 0) {
|
||||||
|
this.tail_.data = arr;
|
||||||
|
this.tail_ = this.tail_.next = new ConsArray.Cell(null, null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the end of iteration is reached.
|
||||||
|
*/
|
||||||
|
ConsArray.prototype.atEnd = function() {
|
||||||
|
return this.currCell_ === null ||
|
||||||
|
this.currCell_.data === null ||
|
||||||
|
this.currCellPos_ >= this.currCell_.data.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current item, moves to the next one.
|
||||||
|
*/
|
||||||
|
ConsArray.prototype.next = function() {
|
||||||
|
var result = this.currCell_.data[this.currCellPos_++];
|
||||||
|
if (this.currCellPos_ >= this.currCell_.data.length) {
|
||||||
|
this.currCell_ = this.currCell_.next;
|
||||||
|
this.currCellPos_ = 0;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A cell object used for constructing a list in ConsArray.
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
ConsArray.Cell = function(data, next) {
|
||||||
|
this.data = data;
|
||||||
|
this.next = next;
|
||||||
|
};
|
105
tools/csvparser.mjs
Normal file
105
tools/csvparser.mjs
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a CSV lines parser.
|
||||||
|
*/
|
||||||
|
export class CsvParser {
|
||||||
|
/**
|
||||||
|
* Converts \x00 and \u0000 escape sequences in the given string.
|
||||||
|
*
|
||||||
|
* @param {string} input field.
|
||||||
|
**/
|
||||||
|
escapeField(string) {
|
||||||
|
let nextPos = string.indexOf("\\");
|
||||||
|
if (nextPos === -1) return string;
|
||||||
|
|
||||||
|
let result = string.substring(0, nextPos);
|
||||||
|
// Escape sequences of the form \x00 and \u0000;
|
||||||
|
let endPos = string.length;
|
||||||
|
let pos = 0;
|
||||||
|
while (nextPos !== -1) {
|
||||||
|
let escapeIdentifier = string.charAt(nextPos + 1);
|
||||||
|
pos = nextPos + 2;
|
||||||
|
if (escapeIdentifier === 'n') {
|
||||||
|
result += '\n';
|
||||||
|
nextPos = pos;
|
||||||
|
} else if (escapeIdentifier === '\\') {
|
||||||
|
result += '\\';
|
||||||
|
nextPos = pos;
|
||||||
|
} else {
|
||||||
|
if (escapeIdentifier === 'x') {
|
||||||
|
// \x00 ascii range escapes consume 2 chars.
|
||||||
|
nextPos = pos + 2;
|
||||||
|
} else {
|
||||||
|
// \u0000 unicode range escapes consume 4 chars.
|
||||||
|
nextPos = pos + 4;
|
||||||
|
}
|
||||||
|
// Convert the selected escape sequence to a single character.
|
||||||
|
let escapeChars = string.substring(pos, nextPos);
|
||||||
|
result += String.fromCharCode(parseInt(escapeChars, 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue looking for the next escape sequence.
|
||||||
|
pos = nextPos;
|
||||||
|
nextPos = string.indexOf("\\", pos);
|
||||||
|
// If there are no more escape sequences consume the rest of the string.
|
||||||
|
if (nextPos === -1) {
|
||||||
|
result += string.substr(pos);
|
||||||
|
} else if (pos !== nextPos) {
|
||||||
|
result += string.substring(pos, nextPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a line of CSV-encoded values. Returns an array of fields.
|
||||||
|
*
|
||||||
|
* @param {string} line Input line.
|
||||||
|
*/
|
||||||
|
parseLine(line) {
|
||||||
|
var pos = 0;
|
||||||
|
var endPos = line.length;
|
||||||
|
var fields = [];
|
||||||
|
if (endPos == 0) return fields;
|
||||||
|
let nextPos = 0;
|
||||||
|
while(nextPos !== -1) {
|
||||||
|
nextPos = line.indexOf(',', pos);
|
||||||
|
let field;
|
||||||
|
if (nextPos === -1) {
|
||||||
|
field = line.substr(pos);
|
||||||
|
} else {
|
||||||
|
field = line.substring(pos, nextPos);
|
||||||
|
}
|
||||||
|
fields.push(this.escapeField(field));
|
||||||
|
pos = nextPos + 1;
|
||||||
|
};
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
}
|
@ -19,9 +19,7 @@ def is_file_executable(fPath):
|
|||||||
return os.path.isfile(fPath) and os.access(fPath, os.X_OK)
|
return os.path.isfile(fPath) and os.access(fPath, os.X_OK)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
JS_FILES = ['splaytree.js', 'codemap.js', 'csvparser.js', 'consarray.js',
|
JS_FILES = ['dumpcpp-driver.mjs']
|
||||||
'profile.js', 'logreader.js', 'arguments.js', 'tickprocessor.js',
|
|
||||||
'SourceMap.js', 'dumpcpp.js', 'dumpcpp-driver.js']
|
|
||||||
tools_path = os.path.dirname(os.path.realpath(__file__))
|
tools_path = os.path.dirname(os.path.realpath(__file__))
|
||||||
on_windows = platform.system() == 'Windows'
|
on_windows = platform.system() == 'Windows'
|
||||||
JS_FILES = [os.path.join(tools_path, f) for f in JS_FILES]
|
JS_FILES = [os.path.join(tools_path, f) for f in JS_FILES]
|
||||||
@ -53,7 +51,7 @@ if __name__ == '__main__':
|
|||||||
print('No d8 binary path found in {}.'.format(log_file))
|
print('No d8 binary path found in {}.'.format(log_file))
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
||||||
args = [d8_exec] + JS_FILES + ['--'] + args
|
args = [d8_exec] + ['--module'] + JS_FILES + ['--'] + args
|
||||||
|
|
||||||
with open(log_file) as f:
|
with open(log_file) as f:
|
||||||
sp = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
sp = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||||
|
@ -2,6 +2,12 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import "./sourcemap.mjs";
|
||||||
|
import {
|
||||||
|
CppProcessor, ArgumentsProcessor, UnixCppEntriesProvider,
|
||||||
|
WindowsCppEntriesProvider, MacCppEntriesProvider
|
||||||
|
} from "./dumpcpp.mjs";
|
||||||
|
|
||||||
// Dump C++ symbols of shared library if possible
|
// Dump C++ symbols of shared library if possible
|
||||||
|
|
||||||
function processArguments(args) {
|
function processArguments(args) {
|
@ -2,7 +2,16 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
function CppProcessor(cppEntriesProvider, timedRange, pairwiseTimedRange) {
|
import { LogReader, parseString } from "./logreader.mjs";
|
||||||
|
import { CodeMap } from "./codemap.mjs";
|
||||||
|
export {
|
||||||
|
ArgumentsProcessor, UnixCppEntriesProvider,
|
||||||
|
WindowsCppEntriesProvider, MacCppEntriesProvider,
|
||||||
|
} from "./tickprocessor.mjs";
|
||||||
|
import { inherits } from "./tickprocessor.mjs";
|
||||||
|
|
||||||
|
|
||||||
|
export function CppProcessor(cppEntriesProvider, timedRange, pairwiseTimedRange) {
|
||||||
LogReader.call(this, {
|
LogReader.call(this, {
|
||||||
'shared-library': { parsers: [parseString, parseInt, parseInt, parseInt],
|
'shared-library': { parsers: [parseString, parseInt, parseInt, parseInt],
|
||||||
processor: this.processSharedLibrary }
|
processor: this.processSharedLibrary }
|
@ -49,16 +49,7 @@ code is governed by a BSD-style license that can be found in the LICENSE file.
|
|||||||
padding: 0.5em 0 0.2em 0;
|
padding: 0.5em 0 0.2em 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script src="./splaytree.js"></script>
|
<script type="module" src="./ic-processor.js"></script>
|
||||||
<script src="./codemap.js"></script>
|
|
||||||
<script src="./csvparser.js"></script>
|
|
||||||
<script src="./consarray.js"></script>
|
|
||||||
<script src="./profile.js"></script>
|
|
||||||
<script src="./profile_view.js"></script>
|
|
||||||
<script src="./logreader.js"></script>
|
|
||||||
<script src="./arguments.js"></script>
|
|
||||||
<script src="./ic-processor.js"></script>
|
|
||||||
<script src="./SourceMap.js"></script>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
"use strict"
|
"use strict"
|
||||||
|
@ -33,9 +33,5 @@ if [ ! -x "$d8_exec" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# nm spits out 'no symbols found' messages to stderr.
|
# nm spits out 'no symbols found' messages to stderr.
|
||||||
cat $log_file | $d8_exec $tools_path/splaytree.js $tools_path/codemap.js \
|
cat $log_file | $d8_exec \
|
||||||
$tools_path/csvparser.js $tools_path/consarray.js \
|
--module $tools_path/ic-processor-driver.mjs -- $@ 2>/dev/null
|
||||||
$tools_path/profile.js $tools_path/profile_view.js \
|
|
||||||
$tools_path/logreader.js $tools_path/arguments.js \
|
|
||||||
$tools_path/ic-processor.js $tools_path/SourceMap.js \
|
|
||||||
$tools_path/ic-processor-driver.js -- $@ 2>/dev/null
|
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import { IcProcessor, ArgumentsProcessor, readFile } from "./ic-processor.mjs";
|
||||||
|
import "./SourceMap.mjs";
|
||||||
|
|
||||||
function processArguments(args) {
|
function processArguments(args) {
|
||||||
var processor = new ArgumentsProcessor(args);
|
var processor = new ArgumentsProcessor(args);
|
||||||
if (processor.parse()) {
|
if (processor.parse()) {
|
@ -2,6 +2,10 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import { LogReader, parseString, parseVarArgs } from "./logreader.mjs";
|
||||||
|
import { BaseArgumentsProcessor } from "./arguments.mjs";
|
||||||
|
import { Profile } from "./profile.mjs";
|
||||||
|
|
||||||
function inherits(childCtor, parentCtor) {
|
function inherits(childCtor, parentCtor) {
|
||||||
childCtor.prototype.__proto__ = parentCtor.prototype;
|
childCtor.prototype.__proto__ = parentCtor.prototype;
|
||||||
};
|
};
|
||||||
@ -9,7 +13,7 @@ function inherits(childCtor, parentCtor) {
|
|||||||
/**
|
/**
|
||||||
* A thin wrapper around shell's 'read' function showing a file name on error.
|
* A thin wrapper around shell's 'read' function showing a file name on error.
|
||||||
*/
|
*/
|
||||||
function readFile(fileName) {
|
export function readFile(fileName) {
|
||||||
try {
|
try {
|
||||||
return read(fileName);
|
return read(fileName);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -31,7 +35,7 @@ function parseState(s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function IcProcessor() {
|
export function IcProcessor() {
|
||||||
var propertyICParser = [
|
var propertyICParser = [
|
||||||
parseInt, parseInt, parseInt, parseInt, parseString, parseString,
|
parseInt, parseInt, parseInt, parseInt, parseString, parseString,
|
||||||
parseInt, parseString, parseString, parseString];
|
parseInt, parseString, parseString, parseString];
|
||||||
@ -175,7 +179,7 @@ print(
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ArgumentsProcessor extends BaseArgumentsProcessor {
|
export class ArgumentsProcessor extends BaseArgumentsProcessor {
|
||||||
getArgsDispatch() {
|
getArgsDispatch() {
|
||||||
return {
|
return {
|
||||||
'--range': ['range', 'auto,auto',
|
'--range': ['range', 'auto,auto',
|
@ -34,9 +34,4 @@ fi
|
|||||||
|
|
||||||
# nm spits out 'no symbols found' messages to stderr.
|
# nm spits out 'no symbols found' messages to stderr.
|
||||||
cat $log_file | $d8_exec --enable-os-system \
|
cat $log_file | $d8_exec --enable-os-system \
|
||||||
$tools_path/splaytree.js $tools_path/codemap.js \
|
--module $tools_path/tickprocessor-driver.mjs -- $@ 2>/dev/null
|
||||||
$tools_path/csvparser.js $tools_path/consarray.js \
|
|
||||||
$tools_path/profile.js $tools_path/profile_view.js \
|
|
||||||
$tools_path/logreader.js $tools_path/arguments.js \
|
|
||||||
$tools_path/tickprocessor.js $tools_path/SourceMap.js \
|
|
||||||
$tools_path/tickprocessor-driver.js -- $@ 2>/dev/null
|
|
||||||
|
248
tools/logreader.mjs
Normal file
248
tools/logreader.mjs
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
// Copyright 2011 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.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fileoverview Log Reader is used to process log file produced by V8.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { CsvParser } from "./csvparser.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for processing log files.
|
||||||
|
*
|
||||||
|
* @param {Array.<Object>} dispatchTable A table used for parsing and processing
|
||||||
|
* log records.
|
||||||
|
* @param {boolean} timedRange Ignore ticks outside timed range.
|
||||||
|
* @param {boolean} pairwiseTimedRange Ignore ticks outside pairs of timer
|
||||||
|
* markers.
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
export function LogReader(dispatchTable, timedRange, pairwiseTimedRange) {
|
||||||
|
/**
|
||||||
|
* @type {Array.<Object>}
|
||||||
|
*/
|
||||||
|
this.dispatchTable_ = dispatchTable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
this.timedRange_ = timedRange;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
this.pairwiseTimedRange_ = pairwiseTimedRange;
|
||||||
|
if (pairwiseTimedRange) {
|
||||||
|
this.timedRange_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current line.
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
this.lineNum_ = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CSV lines parser.
|
||||||
|
* @type {CsvParser}
|
||||||
|
*/
|
||||||
|
this.csvParser_ = new CsvParser();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keeps track of whether we've seen a "current-time" tick yet.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
this.hasSeenTimerMarker_ = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of log lines seen since last "current-time" tick.
|
||||||
|
* @type {Array.<String>}
|
||||||
|
*/
|
||||||
|
this.logLinesSinceLastTimerMarker_ = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for printing error messages.
|
||||||
|
*
|
||||||
|
* @param {string} str Error message.
|
||||||
|
*/
|
||||||
|
LogReader.prototype.printError = function(str) {
|
||||||
|
// Do nothing.
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes a portion of V8 profiler event log.
|
||||||
|
*
|
||||||
|
* @param {string} chunk A portion of log.
|
||||||
|
*/
|
||||||
|
LogReader.prototype.processLogChunk = function(chunk) {
|
||||||
|
this.processLog_(chunk.split('\n'));
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes a line of V8 profiler event log.
|
||||||
|
*
|
||||||
|
* @param {string} line A line of log.
|
||||||
|
*/
|
||||||
|
LogReader.prototype.processLogLine = function(line) {
|
||||||
|
if (!this.timedRange_) {
|
||||||
|
this.processLogLine_(line);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (line.startsWith("current-time")) {
|
||||||
|
if (this.hasSeenTimerMarker_) {
|
||||||
|
this.processLog_(this.logLinesSinceLastTimerMarker_);
|
||||||
|
this.logLinesSinceLastTimerMarker_ = [];
|
||||||
|
// In pairwise mode, a "current-time" line ends the timed range.
|
||||||
|
if (this.pairwiseTimedRange_) {
|
||||||
|
this.hasSeenTimerMarker_ = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.hasSeenTimerMarker_ = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.hasSeenTimerMarker_) {
|
||||||
|
this.logLinesSinceLastTimerMarker_.push(line);
|
||||||
|
} else if (!line.startsWith("tick")) {
|
||||||
|
this.processLogLine_(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes stack record.
|
||||||
|
*
|
||||||
|
* @param {number} pc Program counter.
|
||||||
|
* @param {number} func JS Function.
|
||||||
|
* @param {Array.<string>} stack String representation of a stack.
|
||||||
|
* @return {Array.<number>} Processed stack.
|
||||||
|
*/
|
||||||
|
LogReader.prototype.processStack = function(pc, func, stack) {
|
||||||
|
var fullStack = func ? [pc, func] : [pc];
|
||||||
|
var prevFrame = pc;
|
||||||
|
for (var i = 0, n = stack.length; i < n; ++i) {
|
||||||
|
var frame = stack[i];
|
||||||
|
var firstChar = frame.charAt(0);
|
||||||
|
if (firstChar == '+' || firstChar == '-') {
|
||||||
|
// An offset from the previous frame.
|
||||||
|
prevFrame += parseInt(frame, 16);
|
||||||
|
fullStack.push(prevFrame);
|
||||||
|
// Filter out possible 'overflow' string.
|
||||||
|
} else if (firstChar != 'o') {
|
||||||
|
fullStack.push(parseInt(frame, 16));
|
||||||
|
} else {
|
||||||
|
this.printError("dropping: " + frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fullStack;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether a particular dispatch must be skipped.
|
||||||
|
*
|
||||||
|
* @param {!Object} dispatch Dispatch record.
|
||||||
|
* @return {boolean} True if dispatch must be skipped.
|
||||||
|
*/
|
||||||
|
LogReader.prototype.skipDispatch = function(dispatch) {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parses dummy variable for readability;
|
||||||
|
export const parseString = 'parse-string';
|
||||||
|
export const parseVarArgs = 'parse-var-args';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does a dispatch of a log record.
|
||||||
|
*
|
||||||
|
* @param {Array.<string>} fields Log record.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
LogReader.prototype.dispatchLogRow_ = function(fields) {
|
||||||
|
// Obtain the dispatch.
|
||||||
|
var command = fields[0];
|
||||||
|
var dispatch = this.dispatchTable_[command];
|
||||||
|
if (dispatch === undefined) return;
|
||||||
|
if (dispatch === null || this.skipDispatch(dispatch)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse fields.
|
||||||
|
var parsedFields = [];
|
||||||
|
for (var i = 0; i < dispatch.parsers.length; ++i) {
|
||||||
|
var parser = dispatch.parsers[i];
|
||||||
|
if (parser === parseString) {
|
||||||
|
parsedFields.push(fields[1 + i]);
|
||||||
|
} else if (typeof parser == 'function') {
|
||||||
|
parsedFields.push(parser(fields[1 + i]));
|
||||||
|
} else if (parser === parseVarArgs) {
|
||||||
|
// var-args
|
||||||
|
parsedFields.push(fields.slice(1 + i));
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
throw new Error("Invalid log field parser: " + parser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the processor.
|
||||||
|
dispatch.processor.apply(this, parsedFields);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes log lines.
|
||||||
|
*
|
||||||
|
* @param {Array.<string>} lines Log lines.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
LogReader.prototype.processLog_ = function(lines) {
|
||||||
|
for (var i = 0, n = lines.length; i < n; ++i) {
|
||||||
|
this.processLogLine_(lines[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes a single log line.
|
||||||
|
*
|
||||||
|
* @param {String} a log line
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
LogReader.prototype.processLogLine_ = function(line) {
|
||||||
|
if (line.length > 0) {
|
||||||
|
try {
|
||||||
|
var fields = this.csvParser_.parseLine(line);
|
||||||
|
this.dispatchLogRow_(fields);
|
||||||
|
} catch (e) {
|
||||||
|
this.printError('line ' + (this.lineNum_ + 1) + ': ' + (e.message || e) + '\n' + e.stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.lineNum_++;
|
||||||
|
};
|
@ -33,9 +33,5 @@ if [ ! -x "$d8_exec" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# nm spits out 'no symbols found' messages to stderr.
|
# nm spits out 'no symbols found' messages to stderr.
|
||||||
cat $log_file | $d8_exec $tools_path/splaytree.js $tools_path/codemap.js \
|
cat $log_file | $d8_exec \
|
||||||
$tools_path/csvparser.js $tools_path/consarray.js \
|
--module $tools_path/map-processor-driver.mjs -- $@ 2>/dev/null
|
||||||
$tools_path/profile.js $tools_path/profile_view.js \
|
|
||||||
$tools_path/logreader.js $tools_path/arguments.js \
|
|
||||||
$tools_path/map-processor.js $tools_path/SourceMap.js \
|
|
||||||
$tools_path/map-processor-driver.js -- $@ 2>/dev/null
|
|
||||||
|
@ -2,6 +2,11 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import "./SourceMap.mjs";
|
||||||
|
import {
|
||||||
|
MapProcessor, ArgumentsProcessor, readFile
|
||||||
|
} from "./map-processor.mjs";
|
||||||
|
|
||||||
function processArguments(args) {
|
function processArguments(args) {
|
||||||
var processor = new ArgumentsProcessor(args);
|
var processor = new ArgumentsProcessor(args);
|
||||||
if (processor.parse()) {
|
if (processor.parse()) {
|
@ -374,16 +374,7 @@ dd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
<script src="./splaytree.js"></script>
|
<script type="module" src="./map-processor.js"></script>
|
||||||
<script src="./codemap.js"></script>
|
|
||||||
<script src="./csvparser.js"></script>
|
|
||||||
<script src="./consarray.js"></script>
|
|
||||||
<script src="./profile.js"></script>
|
|
||||||
<script src="./profile_view.js"></script>
|
|
||||||
<script src="./logreader.js"></script>
|
|
||||||
<script src="./SourceMap.js"></script>
|
|
||||||
<script src="./arguments.js"></script>
|
|
||||||
<script src="./map-processor.js"></script>
|
|
||||||
<script>
|
<script>
|
||||||
"use strict"
|
"use strict"
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
@ -2,6 +2,10 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import { LogReader, parseString, parseVarArgs } from "./logreader.mjs";
|
||||||
|
import { BaseArgumentsProcessor } from "./arguments.mjs";
|
||||||
|
import { Profile } from "./profile.mjs";
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
function define(prototype, name, fn) {
|
function define(prototype, name, fn) {
|
||||||
Object.defineProperty(prototype, name, {value:fn, enumerable:false});
|
Object.defineProperty(prototype, name, {value:fn, enumerable:false});
|
||||||
@ -18,9 +22,22 @@ define(Array.prototype, "max", function(fn) {
|
|||||||
})
|
})
|
||||||
define(Array.prototype, "first", function() { return this[0] });
|
define(Array.prototype, "first", function() { return this[0] });
|
||||||
define(Array.prototype, "last", function() { return this[this.length - 1] });
|
define(Array.prototype, "last", function() { return this[this.length - 1] });
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A thin wrapper around shell's 'read' function showing a file name on error.
|
||||||
|
*/
|
||||||
|
export function readFile(fileName) {
|
||||||
|
try {
|
||||||
|
return read(fileName);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(fileName + ': ' + (e.message || e));
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
|
|
||||||
class MapProcessor extends LogReader {
|
export class MapProcessor extends LogReader {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.dispatchTable_ = {
|
this.dispatchTable_ = {
|
||||||
@ -745,7 +762,7 @@ function BreakDown(list, map_fn) {
|
|||||||
|
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
class ArgumentsProcessor extends BaseArgumentsProcessor {
|
export class ArgumentsProcessor extends BaseArgumentsProcessor {
|
||||||
getArgsDispatch() {
|
getArgsDispatch() {
|
||||||
return {
|
return {
|
||||||
'--range': ['range', 'auto,auto',
|
'--range': ['range', 'auto,auto',
|
@ -34,9 +34,4 @@ fi
|
|||||||
|
|
||||||
# nm spits out 'no symbols found' messages to stderr.
|
# nm spits out 'no symbols found' messages to stderr.
|
||||||
cat $log_file | $d8_exec --allow-natives-syntax \
|
cat $log_file | $d8_exec --allow-natives-syntax \
|
||||||
$tools_path/splaytree.js $tools_path/codemap.js \
|
--module $tools_path/parse-processor-driver.mjs -- $@ 2>/dev/null
|
||||||
$tools_path/csvparser.js $tools_path/consarray.js \
|
|
||||||
$tools_path/profile.js $tools_path/profile_view.js \
|
|
||||||
$tools_path/logreader.js $tools_path/arguments.js \
|
|
||||||
$tools_path/parse-processor.js $tools_path/SourceMap.js \
|
|
||||||
$tools_path/parse-processor-driver.js -- $@ 2>/dev/null
|
|
||||||
|
@ -2,6 +2,11 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import { WebInspector } from "./SourceMap.mjs";
|
||||||
|
import {
|
||||||
|
ParseProcessor, ArgumentsProcessor, readFile,
|
||||||
|
} from "./parse-processor.mjs";
|
||||||
|
|
||||||
function processArguments(args) {
|
function processArguments(args) {
|
||||||
var processor = new ArgumentsProcessor(args);
|
var processor = new ArgumentsProcessor(args);
|
||||||
if (processor.parse()) {
|
if (processor.parse()) {
|
@ -103,26 +103,22 @@ code is governed by a BSD-style license that can be found in the LICENSE file.
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script src="./splaytree.js"></script>
|
|
||||||
<script src="./codemap.js"></script>
|
|
||||||
<script src="./csvparser.js"></script>
|
|
||||||
<script src="./consarray.js"></script>
|
|
||||||
<script src="./profile.js"></script>
|
|
||||||
<script src="./profile_view.js"></script>
|
|
||||||
<script src="./logreader.js"></script>
|
|
||||||
<script src="./arguments.js"></script>
|
|
||||||
<script src="./parse-processor.js"></script>
|
|
||||||
<script src="./SourceMap.js"></script>
|
|
||||||
<script src="https://www.gstatic.com/charts/loader.js"></script>
|
<script src="https://www.gstatic.com/charts/loader.js"></script>
|
||||||
<script>
|
<script type="module">
|
||||||
"use strict";
|
|
||||||
|
import { ParseProcessor, kSecondsToMillis } from "./parse-processor.mjs";
|
||||||
|
|
||||||
google.charts.load('current', {packages: ['corechart']});
|
google.charts.load('current', {packages: ['corechart']});
|
||||||
|
|
||||||
function $(query) {
|
function $(query) {
|
||||||
return document.querySelector(query);
|
return document.querySelector(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadFile() {
|
window.addEventListener('DOMContentLoaded', (event) => {
|
||||||
|
$("#uploadInput").focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.loadFile = function() {
|
||||||
let files = $('#uploadInput').files;
|
let files = $('#uploadInput').files;
|
||||||
|
|
||||||
let file = files[0];
|
let file = files[0];
|
||||||
@ -140,10 +136,6 @@ function loadFile() {
|
|||||||
reader.readAsText(file);
|
reader.readAsText(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleOnLoad() {
|
|
||||||
document.querySelector("#uploadInput").focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
function createNode(tag, classNames) {
|
function createNode(tag, classNames) {
|
||||||
let node = document.createElement(tag);
|
let node = document.createElement(tag);
|
||||||
if (classNames) {
|
if (classNames) {
|
||||||
@ -395,7 +387,7 @@ function createFunktionList(metric, description, time, funktions) {
|
|||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body onload="handleOnLoad()">
|
<body>
|
||||||
<h1>BEHOLD, THIS IS PARSEROR!</h1>
|
<h1>BEHOLD, THIS IS PARSEROR!</h1>
|
||||||
|
|
||||||
<h2>Usage</h2>
|
<h2>Usage</h2>
|
||||||
|
@ -3,11 +3,13 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
import { LogReader, parseString } from "./logreader.mjs";
|
||||||
|
import { BaseArgumentsProcessor } from "./arguments.mjs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A thin wrapper around shell's 'read' function showing a file name on error.
|
* A thin wrapper around shell's 'read' function showing a file name on error.
|
||||||
*/
|
*/
|
||||||
function readFile(fileName) {
|
export function readFile(fileName) {
|
||||||
try {
|
try {
|
||||||
return read(fileName);
|
return read(fileName);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -730,8 +732,8 @@ class Funktion extends CompilationUnit {
|
|||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
|
|
||||||
const kTimestampFactor = 1000;
|
export const kTimestampFactor = 1000;
|
||||||
const kSecondsToMillis = 1000;
|
export const kSecondsToMillis = 1000;
|
||||||
|
|
||||||
function toTimestamp(microseconds) {
|
function toTimestamp(microseconds) {
|
||||||
return microseconds / kTimestampFactor
|
return microseconds / kTimestampFactor
|
||||||
@ -744,7 +746,7 @@ function startOf(timestamp, time) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ParseProcessor extends LogReader {
|
export class ParseProcessor extends LogReader {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.dispatchTable_ = {
|
this.dispatchTable_ = {
|
||||||
@ -1130,7 +1132,7 @@ class ParseProcessor extends LogReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ArgumentsProcessor extends BaseArgumentsProcessor {
|
export class ArgumentsProcessor extends BaseArgumentsProcessor {
|
||||||
getArgsDispatch() {
|
getArgsDispatch() {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
1175
tools/profile.mjs
Normal file
1175
tools/profile.mjs
Normal file
File diff suppressed because it is too large
Load Diff
202
tools/profile_view.mjs
Normal file
202
tools/profile_view.mjs
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
import { ConsArray } from "./consarray.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Profile View builder object.
|
||||||
|
*
|
||||||
|
* @param {number} samplingRate Number of ms between profiler ticks.
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
export function ViewBuilder(samplingRate) {
|
||||||
|
this.samplingRate = samplingRate;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a profile view for the specified call tree.
|
||||||
|
*
|
||||||
|
* @param {CallTree} callTree A call tree.
|
||||||
|
* @param {boolean} opt_bottomUpViewWeights Whether remapping
|
||||||
|
* of self weights for a bottom up view is needed.
|
||||||
|
*/
|
||||||
|
ViewBuilder.prototype.buildView = function(
|
||||||
|
callTree, opt_bottomUpViewWeights) {
|
||||||
|
var head;
|
||||||
|
var samplingRate = this.samplingRate;
|
||||||
|
var createViewNode = this.createViewNode;
|
||||||
|
callTree.traverse(function(node, viewParent) {
|
||||||
|
var totalWeight = node.totalWeight * samplingRate;
|
||||||
|
var selfWeight = node.selfWeight * samplingRate;
|
||||||
|
if (opt_bottomUpViewWeights === true) {
|
||||||
|
if (viewParent === head) {
|
||||||
|
selfWeight = totalWeight;
|
||||||
|
} else {
|
||||||
|
selfWeight = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var viewNode = createViewNode(node.label, totalWeight, selfWeight, head);
|
||||||
|
if (viewParent) {
|
||||||
|
viewParent.addChild(viewNode);
|
||||||
|
} else {
|
||||||
|
head = viewNode;
|
||||||
|
}
|
||||||
|
return viewNode;
|
||||||
|
});
|
||||||
|
var view = this.createView(head);
|
||||||
|
return view;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory method for a profile view.
|
||||||
|
*
|
||||||
|
* @param {ProfileView.Node} head View head node.
|
||||||
|
* @return {ProfileView} Profile view.
|
||||||
|
*/
|
||||||
|
ViewBuilder.prototype.createView = function(head) {
|
||||||
|
return new ProfileView(head);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory method for a profile view node.
|
||||||
|
*
|
||||||
|
* @param {string} internalFuncName A fully qualified function name.
|
||||||
|
* @param {number} totalTime Amount of time that application spent in the
|
||||||
|
* corresponding function and its descendants (not that depending on
|
||||||
|
* profile they can be either callees or callers.)
|
||||||
|
* @param {number} selfTime Amount of time that application spent in the
|
||||||
|
* corresponding function only.
|
||||||
|
* @param {ProfileView.Node} head Profile view head.
|
||||||
|
* @return {ProfileView.Node} Profile view node.
|
||||||
|
*/
|
||||||
|
ViewBuilder.prototype.createViewNode = function(
|
||||||
|
funcName, totalTime, selfTime, head) {
|
||||||
|
return new ProfileView.Node(
|
||||||
|
funcName, totalTime, selfTime, head);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Profile View object. It allows to perform sorting
|
||||||
|
* and filtering actions on the profile.
|
||||||
|
*
|
||||||
|
* @param {ProfileView.Node} head Head (root) node.
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
export function ProfileView(head) {
|
||||||
|
this.head = head;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts the profile view using the specified sort function.
|
||||||
|
*
|
||||||
|
* @param {function(ProfileView.Node,
|
||||||
|
* ProfileView.Node):number} sortFunc A sorting
|
||||||
|
* functions. Must comply with Array.sort sorting function requirements.
|
||||||
|
*/
|
||||||
|
ProfileView.prototype.sort = function(sortFunc) {
|
||||||
|
this.traverse(function (node) {
|
||||||
|
node.sortChildren(sortFunc);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Traverses profile view nodes in preorder.
|
||||||
|
*
|
||||||
|
* @param {function(ProfileView.Node)} f Visitor function.
|
||||||
|
*/
|
||||||
|
ProfileView.prototype.traverse = function(f) {
|
||||||
|
var nodesToTraverse = new ConsArray();
|
||||||
|
nodesToTraverse.concat([this.head]);
|
||||||
|
while (!nodesToTraverse.atEnd()) {
|
||||||
|
var node = nodesToTraverse.next();
|
||||||
|
f(node);
|
||||||
|
nodesToTraverse.concat(node.children);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a Profile View node object. Each node object corresponds to
|
||||||
|
* a function call.
|
||||||
|
*
|
||||||
|
* @param {string} internalFuncName A fully qualified function name.
|
||||||
|
* @param {number} totalTime Amount of time that application spent in the
|
||||||
|
* corresponding function and its descendants (not that depending on
|
||||||
|
* profile they can be either callees or callers.)
|
||||||
|
* @param {number} selfTime Amount of time that application spent in the
|
||||||
|
* corresponding function only.
|
||||||
|
* @param {ProfileView.Node} head Profile view head.
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
ProfileView.Node = function(
|
||||||
|
internalFuncName, totalTime, selfTime, head) {
|
||||||
|
this.internalFuncName = internalFuncName;
|
||||||
|
this.totalTime = totalTime;
|
||||||
|
this.selfTime = selfTime;
|
||||||
|
this.head = head;
|
||||||
|
this.parent = null;
|
||||||
|
this.children = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a share of the function's total time in its parent's total time.
|
||||||
|
*/
|
||||||
|
ProfileView.Node.prototype.__defineGetter__(
|
||||||
|
'parentTotalPercent',
|
||||||
|
function() { return this.totalTime /
|
||||||
|
(this.parent ? this.parent.totalTime : this.totalTime) * 100.0; });
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a child to the node.
|
||||||
|
*
|
||||||
|
* @param {ProfileView.Node} node Child node.
|
||||||
|
*/
|
||||||
|
ProfileView.Node.prototype.addChild = function(node) {
|
||||||
|
node.parent = this;
|
||||||
|
this.children.push(node);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts all the node's children recursively.
|
||||||
|
*
|
||||||
|
* @param {function(ProfileView.Node,
|
||||||
|
* ProfileView.Node):number} sortFunc A sorting
|
||||||
|
* functions. Must comply with Array.sort sorting function requirements.
|
||||||
|
*/
|
||||||
|
ProfileView.Node.prototype.sortChildren = function(
|
||||||
|
sortFunc) {
|
||||||
|
this.children.sort(sortFunc);
|
||||||
|
};
|
327
tools/splaytree.mjs
Normal file
327
tools/splaytree.mjs
Normal file
@ -0,0 +1,327 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a Splay tree. A splay tree is a self-balancing binary
|
||||||
|
* search tree with the additional property that recently accessed
|
||||||
|
* elements are quick to access again. It performs basic operations
|
||||||
|
* such as insertion, look-up and removal in O(log(n)) amortized time.
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
export function SplayTree() {
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pointer to the root node of the tree.
|
||||||
|
*
|
||||||
|
* @type {SplayTree.Node}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
SplayTree.prototype.root_ = null;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {boolean} Whether the tree is empty.
|
||||||
|
*/
|
||||||
|
SplayTree.prototype.isEmpty = function() {
|
||||||
|
return !this.root_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts a node into the tree with the specified key and value if
|
||||||
|
* the tree does not already contain a node with the specified key. If
|
||||||
|
* the value is inserted, it becomes the root of the tree.
|
||||||
|
*
|
||||||
|
* @param {number} key Key to insert into the tree.
|
||||||
|
* @param {*} value Value to insert into the tree.
|
||||||
|
*/
|
||||||
|
SplayTree.prototype.insert = function(key, value) {
|
||||||
|
if (this.isEmpty()) {
|
||||||
|
this.root_ = new SplayTree.Node(key, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Splay on the key to move the last node on the search path for
|
||||||
|
// the key to the root of the tree.
|
||||||
|
this.splay_(key);
|
||||||
|
if (this.root_.key == key) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var node = new SplayTree.Node(key, value);
|
||||||
|
if (key > this.root_.key) {
|
||||||
|
node.left = this.root_;
|
||||||
|
node.right = this.root_.right;
|
||||||
|
this.root_.right = null;
|
||||||
|
} else {
|
||||||
|
node.right = this.root_;
|
||||||
|
node.left = this.root_.left;
|
||||||
|
this.root_.left = null;
|
||||||
|
}
|
||||||
|
this.root_ = node;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a node with the specified key from the tree if the tree
|
||||||
|
* contains a node with this key. The removed node is returned. If the
|
||||||
|
* key is not found, an exception is thrown.
|
||||||
|
*
|
||||||
|
* @param {number} key Key to find and remove from the tree.
|
||||||
|
* @return {SplayTree.Node} The removed node.
|
||||||
|
*/
|
||||||
|
SplayTree.prototype.remove = function(key) {
|
||||||
|
if (this.isEmpty()) {
|
||||||
|
throw Error('Key not found: ' + key);
|
||||||
|
}
|
||||||
|
this.splay_(key);
|
||||||
|
if (this.root_.key != key) {
|
||||||
|
throw Error('Key not found: ' + key);
|
||||||
|
}
|
||||||
|
var removed = this.root_;
|
||||||
|
if (!this.root_.left) {
|
||||||
|
this.root_ = this.root_.right;
|
||||||
|
} else {
|
||||||
|
var right = this.root_.right;
|
||||||
|
this.root_ = this.root_.left;
|
||||||
|
// Splay to make sure that the new root has an empty right child.
|
||||||
|
this.splay_(key);
|
||||||
|
// Insert the original right child as the right child of the new
|
||||||
|
// root.
|
||||||
|
this.root_.right = right;
|
||||||
|
}
|
||||||
|
return removed;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the node having the specified key or null if the tree doesn't contain
|
||||||
|
* a node with the specified key.
|
||||||
|
*
|
||||||
|
* @param {number} key Key to find in the tree.
|
||||||
|
* @return {SplayTree.Node} Node having the specified key.
|
||||||
|
*/
|
||||||
|
SplayTree.prototype.find = function(key) {
|
||||||
|
if (this.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
this.splay_(key);
|
||||||
|
return this.root_.key == key ? this.root_ : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {SplayTree.Node} Node having the minimum key value.
|
||||||
|
*/
|
||||||
|
SplayTree.prototype.findMin = function() {
|
||||||
|
if (this.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var current = this.root_;
|
||||||
|
while (current.left) {
|
||||||
|
current = current.left;
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {SplayTree.Node} Node having the maximum key value.
|
||||||
|
*/
|
||||||
|
SplayTree.prototype.findMax = function(opt_startNode) {
|
||||||
|
if (this.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var current = opt_startNode || this.root_;
|
||||||
|
while (current.right) {
|
||||||
|
current = current.right;
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {SplayTree.Node} Node having the maximum key value that
|
||||||
|
* is less or equal to the specified key value.
|
||||||
|
*/
|
||||||
|
SplayTree.prototype.findGreatestLessThan = function(key) {
|
||||||
|
if (this.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// Splay on the key to move the node with the given key or the last
|
||||||
|
// node on the search path to the top of the tree.
|
||||||
|
this.splay_(key);
|
||||||
|
// Now the result is either the root node or the greatest node in
|
||||||
|
// the left subtree.
|
||||||
|
if (this.root_.key <= key) {
|
||||||
|
return this.root_;
|
||||||
|
} else if (this.root_.left) {
|
||||||
|
return this.findMax(this.root_.left);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {Array<*>} An array containing all the values of tree's nodes paired
|
||||||
|
* with keys.
|
||||||
|
*/
|
||||||
|
SplayTree.prototype.exportKeysAndValues = function() {
|
||||||
|
var result = [];
|
||||||
|
this.traverse_(function(node) { result.push([node.key, node.value]); });
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {Array<*>} An array containing all the values of tree's nodes.
|
||||||
|
*/
|
||||||
|
SplayTree.prototype.exportValues = function() {
|
||||||
|
var result = [];
|
||||||
|
this.traverse_(function(node) { result.push(node.value); });
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform the splay operation for the given key. Moves the node with
|
||||||
|
* the given key to the top of the tree. If no node has the given
|
||||||
|
* key, the last node on the search path is moved to the top of the
|
||||||
|
* tree. This is the simplified top-down splaying algorithm from:
|
||||||
|
* "Self-adjusting Binary Search Trees" by Sleator and Tarjan
|
||||||
|
*
|
||||||
|
* @param {number} key Key to splay the tree on.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
SplayTree.prototype.splay_ = function(key) {
|
||||||
|
if (this.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Create a dummy node. The use of the dummy node is a bit
|
||||||
|
// counter-intuitive: The right child of the dummy node will hold
|
||||||
|
// the L tree of the algorithm. The left child of the dummy node
|
||||||
|
// will hold the R tree of the algorithm. Using a dummy node, left
|
||||||
|
// and right will always be nodes and we avoid special cases.
|
||||||
|
var dummy, left, right;
|
||||||
|
dummy = left = right = new SplayTree.Node(null, null);
|
||||||
|
var current = this.root_;
|
||||||
|
while (true) {
|
||||||
|
if (key < current.key) {
|
||||||
|
if (!current.left) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (key < current.left.key) {
|
||||||
|
// Rotate right.
|
||||||
|
var tmp = current.left;
|
||||||
|
current.left = tmp.right;
|
||||||
|
tmp.right = current;
|
||||||
|
current = tmp;
|
||||||
|
if (!current.left) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Link right.
|
||||||
|
right.left = current;
|
||||||
|
right = current;
|
||||||
|
current = current.left;
|
||||||
|
} else if (key > current.key) {
|
||||||
|
if (!current.right) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (key > current.right.key) {
|
||||||
|
// Rotate left.
|
||||||
|
var tmp = current.right;
|
||||||
|
current.right = tmp.left;
|
||||||
|
tmp.left = current;
|
||||||
|
current = tmp;
|
||||||
|
if (!current.right) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Link left.
|
||||||
|
left.right = current;
|
||||||
|
left = current;
|
||||||
|
current = current.right;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Assemble.
|
||||||
|
left.right = current.left;
|
||||||
|
right.left = current.right;
|
||||||
|
current.left = dummy.right;
|
||||||
|
current.right = dummy.left;
|
||||||
|
this.root_ = current;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a preorder traversal of the tree.
|
||||||
|
*
|
||||||
|
* @param {function(SplayTree.Node)} f Visitor function.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
SplayTree.prototype.traverse_ = function(f) {
|
||||||
|
var nodesToVisit = [this.root_];
|
||||||
|
while (nodesToVisit.length > 0) {
|
||||||
|
var node = nodesToVisit.shift();
|
||||||
|
if (node == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
f(node);
|
||||||
|
nodesToVisit.push(node.left);
|
||||||
|
nodesToVisit.push(node.right);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a Splay tree node.
|
||||||
|
*
|
||||||
|
* @param {number} key Key.
|
||||||
|
* @param {*} value Value.
|
||||||
|
*/
|
||||||
|
SplayTree.Node = function(key, value) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = value;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {SplayTree.Node}
|
||||||
|
*/
|
||||||
|
SplayTree.Node.prototype.left = null;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {SplayTree.Node}
|
||||||
|
*/
|
||||||
|
SplayTree.Node.prototype.right = null;
|
@ -12,17 +12,6 @@ found in the LICENSE file. -->
|
|||||||
<!-- <link rel="icon" type="image/png" href="/images/favicon.png"/> -->
|
<!-- <link rel="icon" type="image/png" href="/images/favicon.png"/> -->
|
||||||
<script type="module" src="index.mjs"></script>
|
<script type="module" src="index.mjs"></script>
|
||||||
<link rel="stylesheet" type="text/css" href="./index.css">
|
<link rel="stylesheet" type="text/css" href="./index.css">
|
||||||
<script type="module" src="helper.mjs"></script>
|
|
||||||
|
|
||||||
<script src="../splaytree.js"></script>
|
|
||||||
<script src="../codemap.js"></script>
|
|
||||||
<script src="../csvparser.js"></script>
|
|
||||||
<script src="../consarray.js"></script>
|
|
||||||
<script src="../profile.js"></script>
|
|
||||||
<script src="../profile_view.js"></script>
|
|
||||||
<script src="../logreader.js"></script>
|
|
||||||
<script src="../arguments.js"></script>
|
|
||||||
<script src="../SourceMap.js"></script>
|
|
||||||
<style>
|
<style>
|
||||||
#instructions {
|
#instructions {
|
||||||
padding: 10px 10px 60px 10px;
|
padding: 10px 10px 60px 10px;
|
||||||
|
@ -2,17 +2,21 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
|
||||||
import { SelectionEvent, FocusEvent, SelectTimeEvent } from "./events.mjs";
|
import { SelectionEvent, FocusEvent, SelectTimeEvent } from "./events.mjs";
|
||||||
import { State } from "./app-model.mjs";
|
import { State } from "./app-model.mjs";
|
||||||
import { MapLogEvent } from "./log/map.mjs";
|
import { MapLogEvent } from "./log/map.mjs";
|
||||||
import { IcLogEvent } from "./log/ic.mjs";
|
import { IcLogEvent } from "./log/ic.mjs";
|
||||||
import Processor from "./processor.mjs";
|
import Processor from "./processor.mjs";
|
||||||
|
import { SourcePosition } from "../profile.mjs";
|
||||||
import { $ } from "./helper.mjs";
|
import { $ } from "./helper.mjs";
|
||||||
import "./ic-panel.mjs";
|
import "./ic-panel.mjs";
|
||||||
import "./timeline-panel.mjs";
|
import "./timeline-panel.mjs";
|
||||||
import "./map-panel.mjs";
|
import "./map-panel.mjs";
|
||||||
import "./log-file-reader.mjs";
|
import "./log-file-reader.mjs";
|
||||||
import "./source-panel.mjs";
|
import "./source-panel.mjs";
|
||||||
|
|
||||||
|
|
||||||
class App {
|
class App {
|
||||||
#state;
|
#state;
|
||||||
#view;
|
#view;
|
||||||
|
@ -4,8 +4,9 @@
|
|||||||
|
|
||||||
import { MapLogEvent, Edge } from "./log/map.mjs";
|
import { MapLogEvent, Edge } from "./log/map.mjs";
|
||||||
import { IcLogEvent } from "./log/ic.mjs";
|
import { IcLogEvent } from "./log/ic.mjs";
|
||||||
import { Timeline } from './timeline.mjs';
|
import { Timeline } from "./timeline.mjs";
|
||||||
|
import { LogReader, parseString, parseVarArgs } from "../logreader.mjs";
|
||||||
|
import { Profile } from "../profile.mjs";
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
|
|
||||||
|
@ -42,24 +42,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -->
|
|||||||
margin-top: 0px;
|
margin-top: 0px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<script type="module">
|
||||||
<script src="splaytree.js"></script>
|
import {
|
||||||
<script src="codemap.js"></script>
|
TickProcessor, UnixCppEntriesProvider, MacCppEntriesProvider,
|
||||||
<script src="csvparser.js"></script>
|
WindowsCppEntriesProvider
|
||||||
<script src="consarray.js"></script>
|
} from "./tickprocessor.mjs";
|
||||||
<script src="profile.js"></script>
|
|
||||||
<script src="profile_view.js"></script>
|
|
||||||
<script src="logreader.js"></script>
|
|
||||||
<script src="arguments.js"></script>
|
|
||||||
<script src="tickprocessor.js"></script>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
|
|
||||||
var v8log_content;
|
var v8log_content;
|
||||||
var textout;
|
globalThis.textout;
|
||||||
|
|
||||||
function load_logfile(evt) {
|
globalThis.load_logfile = function(evt) {
|
||||||
textout.value = "";
|
globalThis.textout.value = "";
|
||||||
var f = evt.target.files[0];
|
var f = evt.target.files[0];
|
||||||
if (f) {
|
if (f) {
|
||||||
var reader = new FileReader();
|
var reader = new FileReader();
|
||||||
@ -77,7 +70,7 @@ function load_logfile(evt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function print(arg) {
|
function print(arg) {
|
||||||
textout.value+=arg+"\n";
|
globalThis.textout.value+=arg+"\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
function start_process() {
|
function start_process() {
|
||||||
@ -108,11 +101,12 @@ function start_process() {
|
|||||||
tickProcessor.processLogChunk(v8log_content);
|
tickProcessor.processLogChunk(v8log_content);
|
||||||
tickProcessor.printStatistics();
|
tickProcessor.printStatistics();
|
||||||
}
|
}
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
function Load() {
|
function Load() {
|
||||||
document.getElementById('fileinput').addEventListener(
|
document.getElementById('fileinput').addEventListener(
|
||||||
'change', load_logfile, false);
|
'change', globalThis.load_logfile, false);
|
||||||
textout = document.getElementById('textout');
|
globalThis.textout = document.getElementById('textout');
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
88
tools/tickprocessor-driver.mjs
Normal file
88
tools/tickprocessor-driver.mjs
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
// Copyright 2012 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.
|
||||||
|
|
||||||
|
import { WebInspector} from "./sourcemap.mjs";
|
||||||
|
import {
|
||||||
|
ArgumentsProcessor, TickProcessor, UnixCppEntriesProvider,
|
||||||
|
WindowsCppEntriesProvider, MacCppEntriesProvider, readFile,
|
||||||
|
} from "./tickprocessor.mjs";
|
||||||
|
|
||||||
|
// Tick Processor's code flow.
|
||||||
|
|
||||||
|
function processArguments(args) {
|
||||||
|
var processor = new ArgumentsProcessor(args);
|
||||||
|
if (processor.parse()) {
|
||||||
|
return processor.result();
|
||||||
|
} else {
|
||||||
|
processor.printUsageAndExit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initSourceMapSupport() {
|
||||||
|
// Pull dev tools source maps into our name space.
|
||||||
|
SourceMap = WebInspector.SourceMap;
|
||||||
|
|
||||||
|
// Overwrite the load function to load scripts synchronously.
|
||||||
|
SourceMap.load = function(sourceMapURL) {
|
||||||
|
var content = readFile(sourceMapURL);
|
||||||
|
var sourceMapObject = (JSON.parse(content));
|
||||||
|
return new SourceMap(sourceMapURL, sourceMapObject);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var entriesProviders = {
|
||||||
|
'unix': UnixCppEntriesProvider,
|
||||||
|
'windows': WindowsCppEntriesProvider,
|
||||||
|
'mac': MacCppEntriesProvider
|
||||||
|
};
|
||||||
|
|
||||||
|
var params = processArguments(arguments);
|
||||||
|
var sourceMap = null;
|
||||||
|
if (params.sourceMap) {
|
||||||
|
initSourceMapSupport();
|
||||||
|
sourceMap = SourceMap.load(params.sourceMap);
|
||||||
|
}
|
||||||
|
var tickProcessor = new TickProcessor(
|
||||||
|
new (entriesProviders[params.platform])(params.nm, params.objdump, params.targetRootFS,
|
||||||
|
params.apkEmbeddedLibrary),
|
||||||
|
params.separateIc,
|
||||||
|
params.separateBytecodes,
|
||||||
|
params.separateBuiltins,
|
||||||
|
params.separateStubs,
|
||||||
|
params.callGraphSize,
|
||||||
|
params.ignoreUnknown,
|
||||||
|
params.stateFilter,
|
||||||
|
params.distortion,
|
||||||
|
params.range,
|
||||||
|
sourceMap,
|
||||||
|
params.timedRange,
|
||||||
|
params.pairwiseTimedRange,
|
||||||
|
params.onlySummary,
|
||||||
|
params.runtimeTimerFilter,
|
||||||
|
params.preprocessJson);
|
||||||
|
tickProcessor.processLogFile(params.logFileName);
|
||||||
|
tickProcessor.printStatistics();
|
983
tools/tickprocessor.mjs
Normal file
983
tools/tickprocessor.mjs
Normal file
@ -0,0 +1,983 @@
|
|||||||
|
// Copyright 2012 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.
|
||||||
|
|
||||||
|
import { LogReader, parseString, parseVarArgs } from "./logreader.mjs";
|
||||||
|
import { BaseArgumentsProcessor, parseBool } from "./arguments.mjs";
|
||||||
|
import { Profile, JsonProfile } from "./profile.mjs";
|
||||||
|
import { ViewBuilder } from "./profile_view.mjs";
|
||||||
|
|
||||||
|
|
||||||
|
export function inherits(childCtor, parentCtor) {
|
||||||
|
childCtor.prototype.__proto__ = parentCtor.prototype;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function V8Profile(separateIc, separateBytecodes, separateBuiltins,
|
||||||
|
separateStubs) {
|
||||||
|
Profile.call(this);
|
||||||
|
var regexps = [];
|
||||||
|
if (!separateIc) regexps.push(V8Profile.IC_RE);
|
||||||
|
if (!separateBytecodes) regexps.push(V8Profile.BYTECODES_RE);
|
||||||
|
if (!separateBuiltins) regexps.push(V8Profile.BUILTINS_RE);
|
||||||
|
if (!separateStubs) regexps.push(V8Profile.STUBS_RE);
|
||||||
|
if (regexps.length > 0) {
|
||||||
|
this.skipThisFunction = function(name) {
|
||||||
|
for (var i=0; i<regexps.length; i++) {
|
||||||
|
if (regexps[i].test(name)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
inherits(V8Profile, Profile);
|
||||||
|
|
||||||
|
|
||||||
|
V8Profile.IC_RE =
|
||||||
|
/^(LoadGlobalIC: )|(Handler: )|(?:CallIC|LoadIC|StoreIC)|(?:Builtin: (?:Keyed)?(?:Load|Store)IC_)/;
|
||||||
|
V8Profile.BYTECODES_RE = /^(BytecodeHandler: )/
|
||||||
|
V8Profile.BUILTINS_RE = /^(Builtin: )/
|
||||||
|
V8Profile.STUBS_RE = /^(Stub: )/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A thin wrapper around shell's 'read' function showing a file name on error.
|
||||||
|
*/
|
||||||
|
export function readFile(fileName) {
|
||||||
|
try {
|
||||||
|
return read(fileName);
|
||||||
|
} catch (e) {
|
||||||
|
printErr(fileName + ': ' + (e.message || e));
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parser for dynamic code optimization state.
|
||||||
|
*/
|
||||||
|
function parseState(s) {
|
||||||
|
switch (s) {
|
||||||
|
case "": return Profile.CodeState.COMPILED;
|
||||||
|
case "~": return Profile.CodeState.OPTIMIZABLE;
|
||||||
|
case "*": return Profile.CodeState.OPTIMIZED;
|
||||||
|
}
|
||||||
|
throw new Error("unknown code state: " + s);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function TickProcessor(
|
||||||
|
cppEntriesProvider,
|
||||||
|
separateIc,
|
||||||
|
separateBytecodes,
|
||||||
|
separateBuiltins,
|
||||||
|
separateStubs,
|
||||||
|
callGraphSize,
|
||||||
|
ignoreUnknown,
|
||||||
|
stateFilter,
|
||||||
|
distortion,
|
||||||
|
range,
|
||||||
|
sourceMap,
|
||||||
|
timedRange,
|
||||||
|
pairwiseTimedRange,
|
||||||
|
onlySummary,
|
||||||
|
runtimeTimerFilter,
|
||||||
|
preprocessJson) {
|
||||||
|
this.preprocessJson = preprocessJson;
|
||||||
|
LogReader.call(this, {
|
||||||
|
'shared-library': { parsers: [parseString, parseInt, parseInt, parseInt],
|
||||||
|
processor: this.processSharedLibrary },
|
||||||
|
'code-creation': {
|
||||||
|
parsers: [parseString, parseInt, parseInt, parseInt, parseInt,
|
||||||
|
parseString, parseVarArgs],
|
||||||
|
processor: this.processCodeCreation },
|
||||||
|
'code-deopt': {
|
||||||
|
parsers: [parseInt, parseInt, parseInt, parseInt, parseInt,
|
||||||
|
parseString, parseString, parseString],
|
||||||
|
processor: this.processCodeDeopt },
|
||||||
|
'code-move': { parsers: [parseInt, parseInt, ],
|
||||||
|
processor: this.processCodeMove },
|
||||||
|
'code-delete': { parsers: [parseInt],
|
||||||
|
processor: this.processCodeDelete },
|
||||||
|
'code-source-info': {
|
||||||
|
parsers: [parseInt, parseInt, parseInt, parseInt, parseString,
|
||||||
|
parseString, parseString],
|
||||||
|
processor: this.processCodeSourceInfo },
|
||||||
|
'script-source': {
|
||||||
|
parsers: [parseInt, parseString, parseString],
|
||||||
|
processor: this.processScriptSource },
|
||||||
|
'sfi-move': { parsers: [parseInt, parseInt],
|
||||||
|
processor: this.processFunctionMove },
|
||||||
|
'active-runtime-timer': {
|
||||||
|
parsers: [parseString],
|
||||||
|
processor: this.processRuntimeTimerEvent },
|
||||||
|
'tick': {
|
||||||
|
parsers: [parseInt, parseInt, parseInt,
|
||||||
|
parseInt, parseInt, parseVarArgs],
|
||||||
|
processor: this.processTick },
|
||||||
|
'heap-sample-begin': { parsers: [parseString, parseString, parseInt],
|
||||||
|
processor: this.processHeapSampleBegin },
|
||||||
|
'heap-sample-end': { parsers: [parseString, parseString],
|
||||||
|
processor: this.processHeapSampleEnd },
|
||||||
|
'timer-event-start' : { parsers: [parseString, parseString, parseString],
|
||||||
|
processor: this.advanceDistortion },
|
||||||
|
'timer-event-end' : { parsers: [parseString, parseString, parseString],
|
||||||
|
processor: this.advanceDistortion },
|
||||||
|
// Ignored events.
|
||||||
|
'profiler': null,
|
||||||
|
'function-creation': null,
|
||||||
|
'function-move': null,
|
||||||
|
'function-delete': null,
|
||||||
|
'heap-sample-item': null,
|
||||||
|
'current-time': null, // Handled specially, not parsed.
|
||||||
|
// Obsolete row types.
|
||||||
|
'code-allocate': null,
|
||||||
|
'begin-code-region': null,
|
||||||
|
'end-code-region': null },
|
||||||
|
timedRange,
|
||||||
|
pairwiseTimedRange);
|
||||||
|
|
||||||
|
this.cppEntriesProvider_ = cppEntriesProvider;
|
||||||
|
this.callGraphSize_ = callGraphSize;
|
||||||
|
this.ignoreUnknown_ = ignoreUnknown;
|
||||||
|
this.stateFilter_ = stateFilter;
|
||||||
|
this.runtimeTimerFilter_ = runtimeTimerFilter;
|
||||||
|
this.sourceMap = sourceMap;
|
||||||
|
var ticks = this.ticks_ =
|
||||||
|
{ total: 0, unaccounted: 0, excluded: 0, gc: 0 };
|
||||||
|
|
||||||
|
distortion = parseInt(distortion);
|
||||||
|
// Convert picoseconds to nanoseconds.
|
||||||
|
this.distortion_per_entry = isNaN(distortion) ? 0 : (distortion / 1000);
|
||||||
|
this.distortion = 0;
|
||||||
|
var rangelimits = range ? range.split(",") : [];
|
||||||
|
var range_start = parseInt(rangelimits[0]);
|
||||||
|
var range_end = parseInt(rangelimits[1]);
|
||||||
|
// Convert milliseconds to nanoseconds.
|
||||||
|
this.range_start = isNaN(range_start) ? -Infinity : (range_start * 1000);
|
||||||
|
this.range_end = isNaN(range_end) ? Infinity : (range_end * 1000)
|
||||||
|
|
||||||
|
V8Profile.prototype.handleUnknownCode = function(
|
||||||
|
operation, addr, opt_stackPos) {
|
||||||
|
var op = Profile.Operation;
|
||||||
|
switch (operation) {
|
||||||
|
case op.MOVE:
|
||||||
|
printErr('Code move event for unknown code: 0x' + addr.toString(16));
|
||||||
|
break;
|
||||||
|
case op.DELETE:
|
||||||
|
printErr('Code delete event for unknown code: 0x' + addr.toString(16));
|
||||||
|
break;
|
||||||
|
case op.TICK:
|
||||||
|
// Only unknown PCs (the first frame) are reported as unaccounted,
|
||||||
|
// otherwise tick balance will be corrupted (this behavior is compatible
|
||||||
|
// with the original tickprocessor.py script.)
|
||||||
|
if (opt_stackPos == 0) {
|
||||||
|
ticks.unaccounted++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (preprocessJson) {
|
||||||
|
this.profile_ = new JsonProfile();
|
||||||
|
} else {
|
||||||
|
this.profile_ = new V8Profile(separateIc, separateBytecodes,
|
||||||
|
separateBuiltins, separateStubs);
|
||||||
|
}
|
||||||
|
this.codeTypes_ = {};
|
||||||
|
// Count each tick as a time unit.
|
||||||
|
this.viewBuilder_ = new ViewBuilder(1);
|
||||||
|
this.lastLogFileName_ = null;
|
||||||
|
|
||||||
|
this.generation_ = 1;
|
||||||
|
this.currentProducerProfile_ = null;
|
||||||
|
this.onlySummary_ = onlySummary;
|
||||||
|
};
|
||||||
|
inherits(TickProcessor, LogReader);
|
||||||
|
|
||||||
|
|
||||||
|
TickProcessor.VmStates = {
|
||||||
|
JS: 0,
|
||||||
|
GC: 1,
|
||||||
|
PARSER: 2,
|
||||||
|
BYTECODE_COMPILER: 3,
|
||||||
|
COMPILER: 4,
|
||||||
|
OTHER: 5,
|
||||||
|
EXTERNAL: 6,
|
||||||
|
IDLE: 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TickProcessor.CodeTypes = {
|
||||||
|
CPP: 0,
|
||||||
|
SHARED_LIB: 1
|
||||||
|
};
|
||||||
|
// Otherwise, this is JS-related code. We are not adding it to
|
||||||
|
// codeTypes_ map because there can be zillions of them.
|
||||||
|
|
||||||
|
|
||||||
|
TickProcessor.CALL_PROFILE_CUTOFF_PCT = 1.0;
|
||||||
|
|
||||||
|
TickProcessor.CALL_GRAPH_SIZE = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
TickProcessor.prototype.printError = function(str) {
|
||||||
|
printErr(str);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TickProcessor.prototype.setCodeType = function(name, type) {
|
||||||
|
this.codeTypes_[name] = TickProcessor.CodeTypes[type];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TickProcessor.prototype.isSharedLibrary = function(name) {
|
||||||
|
return this.codeTypes_[name] == TickProcessor.CodeTypes.SHARED_LIB;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TickProcessor.prototype.isCppCode = function(name) {
|
||||||
|
return this.codeTypes_[name] == TickProcessor.CodeTypes.CPP;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TickProcessor.prototype.isJsCode = function(name) {
|
||||||
|
return name !== "UNKNOWN" && !(name in this.codeTypes_);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TickProcessor.prototype.processLogFile = function(fileName) {
|
||||||
|
this.lastLogFileName_ = fileName;
|
||||||
|
var line;
|
||||||
|
while (line = readline()) {
|
||||||
|
this.processLogLine(line);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TickProcessor.prototype.processLogFileInTest = function(fileName) {
|
||||||
|
// Hack file name to avoid dealing with platform specifics.
|
||||||
|
this.lastLogFileName_ = 'v8.log';
|
||||||
|
var contents = readFile(fileName);
|
||||||
|
this.processLogChunk(contents);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TickProcessor.prototype.processSharedLibrary = function(
|
||||||
|
name, startAddr, endAddr, aslrSlide) {
|
||||||
|
var entry = this.profile_.addLibrary(name, startAddr, endAddr, aslrSlide);
|
||||||
|
this.setCodeType(entry.getName(), 'SHARED_LIB');
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
var libFuncs = this.cppEntriesProvider_.parseVmSymbols(
|
||||||
|
name, startAddr, endAddr, aslrSlide, function(fName, fStart, fEnd) {
|
||||||
|
self.profile_.addStaticCode(fName, fStart, fEnd);
|
||||||
|
self.setCodeType(fName, 'CPP');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TickProcessor.prototype.processCodeCreation = function(
|
||||||
|
type, kind, timestamp, start, size, name, maybe_func) {
|
||||||
|
if (maybe_func.length) {
|
||||||
|
var funcAddr = parseInt(maybe_func[0]);
|
||||||
|
var state = parseState(maybe_func[1]);
|
||||||
|
this.profile_.addFuncCode(type, name, timestamp, start, size, funcAddr, state);
|
||||||
|
} else {
|
||||||
|
this.profile_.addCode(type, name, timestamp, start, size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TickProcessor.prototype.processCodeDeopt = function(
|
||||||
|
timestamp, size, code, inliningId, scriptOffset, bailoutType,
|
||||||
|
sourcePositionText, deoptReasonText) {
|
||||||
|
this.profile_.deoptCode(timestamp, code, inliningId, scriptOffset,
|
||||||
|
bailoutType, sourcePositionText, deoptReasonText);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TickProcessor.prototype.processCodeMove = function(from, to) {
|
||||||
|
this.profile_.moveCode(from, to);
|
||||||
|
};
|
||||||
|
|
||||||
|
TickProcessor.prototype.processCodeDelete = function(start) {
|
||||||
|
this.profile_.deleteCode(start);
|
||||||
|
};
|
||||||
|
|
||||||
|
TickProcessor.prototype.processCodeSourceInfo = function(
|
||||||
|
start, script, startPos, endPos, sourcePositions, inliningPositions,
|
||||||
|
inlinedFunctions) {
|
||||||
|
this.profile_.addSourcePositions(start, script, startPos,
|
||||||
|
endPos, sourcePositions, inliningPositions, inlinedFunctions);
|
||||||
|
};
|
||||||
|
|
||||||
|
TickProcessor.prototype.processScriptSource = function(script, url, source) {
|
||||||
|
this.profile_.addScriptSource(script, url, source);
|
||||||
|
};
|
||||||
|
|
||||||
|
TickProcessor.prototype.processFunctionMove = function(from, to) {
|
||||||
|
this.profile_.moveFunc(from, to);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TickProcessor.prototype.includeTick = function(vmState) {
|
||||||
|
if (this.stateFilter_ !== null) {
|
||||||
|
return this.stateFilter_ == vmState;
|
||||||
|
} else if (this.runtimeTimerFilter_ !== null) {
|
||||||
|
return this.currentRuntimeTimer == this.runtimeTimerFilter_;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
TickProcessor.prototype.processRuntimeTimerEvent = function(name) {
|
||||||
|
this.currentRuntimeTimer = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
TickProcessor.prototype.processTick = function(pc,
|
||||||
|
ns_since_start,
|
||||||
|
is_external_callback,
|
||||||
|
tos_or_external_callback,
|
||||||
|
vmState,
|
||||||
|
stack) {
|
||||||
|
this.distortion += this.distortion_per_entry;
|
||||||
|
ns_since_start -= this.distortion;
|
||||||
|
if (ns_since_start < this.range_start || ns_since_start > this.range_end) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.ticks_.total++;
|
||||||
|
if (vmState == TickProcessor.VmStates.GC) this.ticks_.gc++;
|
||||||
|
if (!this.includeTick(vmState)) {
|
||||||
|
this.ticks_.excluded++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (is_external_callback) {
|
||||||
|
// Don't use PC when in external callback code, as it can point
|
||||||
|
// inside callback's code, and we will erroneously report
|
||||||
|
// that a callback calls itself. Instead we use tos_or_external_callback,
|
||||||
|
// as simply resetting PC will produce unaccounted ticks.
|
||||||
|
pc = tos_or_external_callback;
|
||||||
|
tos_or_external_callback = 0;
|
||||||
|
} else if (tos_or_external_callback) {
|
||||||
|
// Find out, if top of stack was pointing inside a JS function
|
||||||
|
// meaning that we have encountered a frameless invocation.
|
||||||
|
var funcEntry = this.profile_.findEntry(tos_or_external_callback);
|
||||||
|
if (!funcEntry || !funcEntry.isJSFunction || !funcEntry.isJSFunction()) {
|
||||||
|
tos_or_external_callback = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.profile_.recordTick(
|
||||||
|
ns_since_start, vmState,
|
||||||
|
this.processStack(pc, tos_or_external_callback, stack));
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TickProcessor.prototype.advanceDistortion = function() {
|
||||||
|
this.distortion += this.distortion_per_entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TickProcessor.prototype.processHeapSampleBegin = function(space, state, ticks) {
|
||||||
|
if (space != 'Heap') return;
|
||||||
|
this.currentProducerProfile_ = new CallTree();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TickProcessor.prototype.processHeapSampleEnd = function(space, state) {
|
||||||
|
if (space != 'Heap' || !this.currentProducerProfile_) return;
|
||||||
|
|
||||||
|
print('Generation ' + this.generation_ + ':');
|
||||||
|
var tree = this.currentProducerProfile_;
|
||||||
|
tree.computeTotalWeights();
|
||||||
|
var producersView = this.viewBuilder_.buildView(tree);
|
||||||
|
// Sort by total time, desc, then by name, desc.
|
||||||
|
producersView.sort(function(rec1, rec2) {
|
||||||
|
return rec2.totalTime - rec1.totalTime ||
|
||||||
|
(rec2.internalFuncName < rec1.internalFuncName ? -1 : 1); });
|
||||||
|
this.printHeavyProfile(producersView.head.children);
|
||||||
|
|
||||||
|
this.currentProducerProfile_ = null;
|
||||||
|
this.generation_++;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TickProcessor.prototype.printStatistics = function() {
|
||||||
|
if (this.preprocessJson) {
|
||||||
|
this.profile_.writeJson();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
print('Statistical profiling result from ' + this.lastLogFileName_ +
|
||||||
|
', (' + this.ticks_.total +
|
||||||
|
' ticks, ' + this.ticks_.unaccounted + ' unaccounted, ' +
|
||||||
|
this.ticks_.excluded + ' excluded).');
|
||||||
|
|
||||||
|
if (this.ticks_.total == 0) return;
|
||||||
|
|
||||||
|
var flatProfile = this.profile_.getFlatProfile();
|
||||||
|
var flatView = this.viewBuilder_.buildView(flatProfile);
|
||||||
|
// Sort by self time, desc, then by name, desc.
|
||||||
|
flatView.sort(function(rec1, rec2) {
|
||||||
|
return rec2.selfTime - rec1.selfTime ||
|
||||||
|
(rec2.internalFuncName < rec1.internalFuncName ? -1 : 1); });
|
||||||
|
var totalTicks = this.ticks_.total;
|
||||||
|
if (this.ignoreUnknown_) {
|
||||||
|
totalTicks -= this.ticks_.unaccounted;
|
||||||
|
}
|
||||||
|
var printAllTicks = !this.onlySummary_;
|
||||||
|
|
||||||
|
// Count library ticks
|
||||||
|
var flatViewNodes = flatView.head.children;
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
var libraryTicks = 0;
|
||||||
|
if(printAllTicks) this.printHeader('Shared libraries');
|
||||||
|
this.printEntries(flatViewNodes, totalTicks, null,
|
||||||
|
function(name) { return self.isSharedLibrary(name); },
|
||||||
|
function(rec) { libraryTicks += rec.selfTime; }, printAllTicks);
|
||||||
|
var nonLibraryTicks = totalTicks - libraryTicks;
|
||||||
|
|
||||||
|
var jsTicks = 0;
|
||||||
|
if(printAllTicks) this.printHeader('JavaScript');
|
||||||
|
this.printEntries(flatViewNodes, totalTicks, nonLibraryTicks,
|
||||||
|
function(name) { return self.isJsCode(name); },
|
||||||
|
function(rec) { jsTicks += rec.selfTime; }, printAllTicks);
|
||||||
|
|
||||||
|
var cppTicks = 0;
|
||||||
|
if(printAllTicks) this.printHeader('C++');
|
||||||
|
this.printEntries(flatViewNodes, totalTicks, nonLibraryTicks,
|
||||||
|
function(name) { return self.isCppCode(name); },
|
||||||
|
function(rec) { cppTicks += rec.selfTime; }, printAllTicks);
|
||||||
|
|
||||||
|
this.printHeader('Summary');
|
||||||
|
this.printLine('JavaScript', jsTicks, totalTicks, nonLibraryTicks);
|
||||||
|
this.printLine('C++', cppTicks, totalTicks, nonLibraryTicks);
|
||||||
|
this.printLine('GC', this.ticks_.gc, totalTicks, nonLibraryTicks);
|
||||||
|
this.printLine('Shared libraries', libraryTicks, totalTicks, null);
|
||||||
|
if (!this.ignoreUnknown_ && this.ticks_.unaccounted > 0) {
|
||||||
|
this.printLine('Unaccounted', this.ticks_.unaccounted,
|
||||||
|
this.ticks_.total, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(printAllTicks) {
|
||||||
|
print('\n [C++ entry points]:');
|
||||||
|
print(' ticks cpp total name');
|
||||||
|
var c_entry_functions = this.profile_.getCEntryProfile();
|
||||||
|
var total_c_entry = c_entry_functions[0].ticks;
|
||||||
|
for (var i = 1; i < c_entry_functions.length; i++) {
|
||||||
|
const c = c_entry_functions[i];
|
||||||
|
this.printLine(c.name, c.ticks, total_c_entry, totalTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.printHeavyProfHeader();
|
||||||
|
var heavyProfile = this.profile_.getBottomUpProfile();
|
||||||
|
var heavyView = this.viewBuilder_.buildView(heavyProfile);
|
||||||
|
// To show the same percentages as in the flat profile.
|
||||||
|
heavyView.head.totalTime = totalTicks;
|
||||||
|
// Sort by total time, desc, then by name, desc.
|
||||||
|
heavyView.sort(function(rec1, rec2) {
|
||||||
|
return rec2.totalTime - rec1.totalTime ||
|
||||||
|
(rec2.internalFuncName < rec1.internalFuncName ? -1 : 1); });
|
||||||
|
this.printHeavyProfile(heavyView.head.children);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function padLeft(s, len) {
|
||||||
|
s = s.toString();
|
||||||
|
if (s.length < len) {
|
||||||
|
var padLength = len - s.length;
|
||||||
|
if (!(padLength in padLeft)) {
|
||||||
|
padLeft[padLength] = new Array(padLength + 1).join(' ');
|
||||||
|
}
|
||||||
|
s = padLeft[padLength] + s;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TickProcessor.prototype.printHeader = function(headerTitle) {
|
||||||
|
print('\n [' + headerTitle + ']:');
|
||||||
|
print(' ticks total nonlib name');
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TickProcessor.prototype.printLine = function(
|
||||||
|
entry, ticks, totalTicks, nonLibTicks) {
|
||||||
|
var pct = ticks * 100 / totalTicks;
|
||||||
|
var nonLibPct = nonLibTicks != null
|
||||||
|
? padLeft((ticks * 100 / nonLibTicks).toFixed(1), 5) + '% '
|
||||||
|
: ' ';
|
||||||
|
print(' ' + padLeft(ticks, 5) + ' ' +
|
||||||
|
padLeft(pct.toFixed(1), 5) + '% ' +
|
||||||
|
nonLibPct +
|
||||||
|
entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
TickProcessor.prototype.printHeavyProfHeader = function() {
|
||||||
|
print('\n [Bottom up (heavy) profile]:');
|
||||||
|
print(' Note: percentage shows a share of a particular caller in the ' +
|
||||||
|
'total\n' +
|
||||||
|
' amount of its parent calls.');
|
||||||
|
print(' Callers occupying less than ' +
|
||||||
|
TickProcessor.CALL_PROFILE_CUTOFF_PCT.toFixed(1) +
|
||||||
|
'% are not shown.\n');
|
||||||
|
print(' ticks parent name');
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TickProcessor.prototype.processProfile = function(
|
||||||
|
profile, filterP, func) {
|
||||||
|
for (var i = 0, n = profile.length; i < n; ++i) {
|
||||||
|
var rec = profile[i];
|
||||||
|
if (!filterP(rec.internalFuncName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
func(rec);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TickProcessor.prototype.getLineAndColumn = function(name) {
|
||||||
|
var re = /:([0-9]+):([0-9]+)$/;
|
||||||
|
var array = re.exec(name);
|
||||||
|
if (!array) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {line: array[1], column: array[2]};
|
||||||
|
}
|
||||||
|
|
||||||
|
TickProcessor.prototype.hasSourceMap = function() {
|
||||||
|
return this.sourceMap != null;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TickProcessor.prototype.formatFunctionName = function(funcName) {
|
||||||
|
if (!this.hasSourceMap()) {
|
||||||
|
return funcName;
|
||||||
|
}
|
||||||
|
var lc = this.getLineAndColumn(funcName);
|
||||||
|
if (lc == null) {
|
||||||
|
return funcName;
|
||||||
|
}
|
||||||
|
// in source maps lines and columns are zero based
|
||||||
|
var lineNumber = lc.line - 1;
|
||||||
|
var column = lc.column - 1;
|
||||||
|
var entry = this.sourceMap.findEntry(lineNumber, column);
|
||||||
|
var sourceFile = entry[2];
|
||||||
|
var sourceLine = entry[3] + 1;
|
||||||
|
var sourceColumn = entry[4] + 1;
|
||||||
|
|
||||||
|
return sourceFile + ':' + sourceLine + ':' + sourceColumn + ' -> ' + funcName;
|
||||||
|
};
|
||||||
|
|
||||||
|
TickProcessor.prototype.printEntries = function(
|
||||||
|
profile, totalTicks, nonLibTicks, filterP, callback, printAllTicks) {
|
||||||
|
var that = this;
|
||||||
|
this.processProfile(profile, filterP, function (rec) {
|
||||||
|
if (rec.selfTime == 0) return;
|
||||||
|
callback(rec);
|
||||||
|
var funcName = that.formatFunctionName(rec.internalFuncName);
|
||||||
|
if(printAllTicks) {
|
||||||
|
that.printLine(funcName, rec.selfTime, totalTicks, nonLibTicks);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TickProcessor.prototype.printHeavyProfile = function(profile, opt_indent) {
|
||||||
|
var self = this;
|
||||||
|
var indent = opt_indent || 0;
|
||||||
|
var indentStr = padLeft('', indent);
|
||||||
|
this.processProfile(profile, function() { return true; }, function (rec) {
|
||||||
|
// Cut off too infrequent callers.
|
||||||
|
if (rec.parentTotalPercent < TickProcessor.CALL_PROFILE_CUTOFF_PCT) return;
|
||||||
|
var funcName = self.formatFunctionName(rec.internalFuncName);
|
||||||
|
print(' ' + padLeft(rec.totalTime, 5) + ' ' +
|
||||||
|
padLeft(rec.parentTotalPercent.toFixed(1), 5) + '% ' +
|
||||||
|
indentStr + funcName);
|
||||||
|
// Limit backtrace depth.
|
||||||
|
if (indent < 2 * self.callGraphSize_) {
|
||||||
|
self.printHeavyProfile(rec.children, indent + 2);
|
||||||
|
}
|
||||||
|
// Delimit top-level functions.
|
||||||
|
if (indent == 0) {
|
||||||
|
print('');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function CppEntriesProvider() {
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
CppEntriesProvider.prototype.parseVmSymbols = function(
|
||||||
|
libName, libStart, libEnd, libASLRSlide, processorFunc) {
|
||||||
|
this.loadSymbols(libName);
|
||||||
|
|
||||||
|
var lastUnknownSize;
|
||||||
|
var lastAdded;
|
||||||
|
|
||||||
|
function inRange(funcInfo, start, end) {
|
||||||
|
return funcInfo.start >= start && funcInfo.end <= end;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addEntry(funcInfo) {
|
||||||
|
// Several functions can be mapped onto the same address. To avoid
|
||||||
|
// creating zero-sized entries, skip such duplicates.
|
||||||
|
// Also double-check that function belongs to the library address space.
|
||||||
|
|
||||||
|
if (lastUnknownSize &&
|
||||||
|
lastUnknownSize.start < funcInfo.start) {
|
||||||
|
// Try to update lastUnknownSize based on new entries start position.
|
||||||
|
lastUnknownSize.end = funcInfo.start;
|
||||||
|
if ((!lastAdded || !inRange(lastUnknownSize, lastAdded.start,
|
||||||
|
lastAdded.end)) &&
|
||||||
|
inRange(lastUnknownSize, libStart, libEnd)) {
|
||||||
|
processorFunc(lastUnknownSize.name, lastUnknownSize.start,
|
||||||
|
lastUnknownSize.end);
|
||||||
|
lastAdded = lastUnknownSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastUnknownSize = undefined;
|
||||||
|
|
||||||
|
if (funcInfo.end) {
|
||||||
|
// Skip duplicates that have the same start address as the last added.
|
||||||
|
if ((!lastAdded || lastAdded.start != funcInfo.start) &&
|
||||||
|
inRange(funcInfo, libStart, libEnd)) {
|
||||||
|
processorFunc(funcInfo.name, funcInfo.start, funcInfo.end);
|
||||||
|
lastAdded = funcInfo;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If a funcInfo doesn't have an end, try to match it up with then next
|
||||||
|
// entry.
|
||||||
|
lastUnknownSize = funcInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
var funcInfo = this.parseNextLine();
|
||||||
|
if (funcInfo === null) {
|
||||||
|
continue;
|
||||||
|
} else if (funcInfo === false) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (funcInfo.start < libStart - libASLRSlide &&
|
||||||
|
funcInfo.start < libEnd - libStart) {
|
||||||
|
funcInfo.start += libStart;
|
||||||
|
} else {
|
||||||
|
funcInfo.start += libASLRSlide;
|
||||||
|
}
|
||||||
|
if (funcInfo.size) {
|
||||||
|
funcInfo.end = funcInfo.start + funcInfo.size;
|
||||||
|
}
|
||||||
|
addEntry(funcInfo);
|
||||||
|
}
|
||||||
|
addEntry({name: '', start: libEnd});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
CppEntriesProvider.prototype.loadSymbols = function(libName) {
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
CppEntriesProvider.prototype.parseNextLine = function() {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export function UnixCppEntriesProvider(nmExec, objdumpExec, targetRootFS, apkEmbeddedLibrary) {
|
||||||
|
this.symbols = [];
|
||||||
|
// File offset of a symbol minus the virtual address of a symbol found in
|
||||||
|
// the symbol table.
|
||||||
|
this.fileOffsetMinusVma = 0;
|
||||||
|
this.parsePos = 0;
|
||||||
|
this.nmExec = nmExec;
|
||||||
|
this.objdumpExec = objdumpExec;
|
||||||
|
this.targetRootFS = targetRootFS;
|
||||||
|
this.apkEmbeddedLibrary = apkEmbeddedLibrary;
|
||||||
|
this.FUNC_RE = /^([0-9a-fA-F]{8,16}) ([0-9a-fA-F]{8,16} )?[tTwW] (.*)$/;
|
||||||
|
};
|
||||||
|
inherits(UnixCppEntriesProvider, CppEntriesProvider);
|
||||||
|
|
||||||
|
|
||||||
|
UnixCppEntriesProvider.prototype.loadSymbols = function(libName) {
|
||||||
|
this.parsePos = 0;
|
||||||
|
if (this.apkEmbeddedLibrary && libName.endsWith('.apk')) {
|
||||||
|
libName = this.apkEmbeddedLibrary;
|
||||||
|
}
|
||||||
|
if (this.targetRootFS) {
|
||||||
|
libName = libName.substring(libName.lastIndexOf('/') + 1);
|
||||||
|
libName = this.targetRootFS + libName;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
this.symbols = [
|
||||||
|
os.system(this.nmExec, ['-C', '-n', '-S', libName], -1, -1),
|
||||||
|
os.system(this.nmExec, ['-C', '-n', '-S', '-D', libName], -1, -1)
|
||||||
|
];
|
||||||
|
|
||||||
|
const objdumpOutput = os.system(this.objdumpExec, ['-h', libName], -1, -1);
|
||||||
|
for (const line of objdumpOutput.split('\n')) {
|
||||||
|
const [,sectionName,,vma,,fileOffset] = line.trim().split(/\s+/);
|
||||||
|
if (sectionName === ".text") {
|
||||||
|
this.fileOffsetMinusVma = parseInt(fileOffset, 16) - parseInt(vma, 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// If the library cannot be found on this system let's not panic.
|
||||||
|
this.symbols = ['', ''];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
UnixCppEntriesProvider.prototype.parseNextLine = function() {
|
||||||
|
if (this.symbols.length == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var lineEndPos = this.symbols[0].indexOf('\n', this.parsePos);
|
||||||
|
if (lineEndPos == -1) {
|
||||||
|
this.symbols.shift();
|
||||||
|
this.parsePos = 0;
|
||||||
|
return this.parseNextLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
var line = this.symbols[0].substring(this.parsePos, lineEndPos);
|
||||||
|
this.parsePos = lineEndPos + 1;
|
||||||
|
var fields = line.match(this.FUNC_RE);
|
||||||
|
var funcInfo = null;
|
||||||
|
if (fields) {
|
||||||
|
funcInfo = { name: fields[3], start: parseInt(fields[1], 16) + this.fileOffsetMinusVma };
|
||||||
|
if (fields[2]) {
|
||||||
|
funcInfo.size = parseInt(fields[2], 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return funcInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export function MacCppEntriesProvider(nmExec, objdumpExec, targetRootFS, apkEmbeddedLibrary) {
|
||||||
|
UnixCppEntriesProvider.call(this, nmExec, objdumpExec, targetRootFS, apkEmbeddedLibrary);
|
||||||
|
// Note an empty group. It is required, as UnixCppEntriesProvider expects 3 groups.
|
||||||
|
this.FUNC_RE = /^([0-9a-fA-F]{8,16})() (.*)$/;
|
||||||
|
};
|
||||||
|
inherits(MacCppEntriesProvider, UnixCppEntriesProvider);
|
||||||
|
|
||||||
|
|
||||||
|
MacCppEntriesProvider.prototype.loadSymbols = function(libName) {
|
||||||
|
this.parsePos = 0;
|
||||||
|
libName = this.targetRootFS + libName;
|
||||||
|
|
||||||
|
// It seems that in OS X `nm` thinks that `-f` is a format option, not a
|
||||||
|
// "flat" display option flag.
|
||||||
|
try {
|
||||||
|
this.symbols = [os.system(this.nmExec, ['-n', libName], -1, -1), ''];
|
||||||
|
} catch (e) {
|
||||||
|
// If the library cannot be found on this system let's not panic.
|
||||||
|
this.symbols = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export function WindowsCppEntriesProvider(_ignored_nmExec, _ignored_objdumpExec, targetRootFS,
|
||||||
|
_ignored_apkEmbeddedLibrary) {
|
||||||
|
this.targetRootFS = targetRootFS;
|
||||||
|
this.symbols = '';
|
||||||
|
this.parsePos = 0;
|
||||||
|
};
|
||||||
|
inherits(WindowsCppEntriesProvider, CppEntriesProvider);
|
||||||
|
|
||||||
|
|
||||||
|
WindowsCppEntriesProvider.FILENAME_RE = /^(.*)\.([^.]+)$/;
|
||||||
|
|
||||||
|
|
||||||
|
WindowsCppEntriesProvider.FUNC_RE =
|
||||||
|
/^\s+0001:[0-9a-fA-F]{8}\s+([_\?@$0-9a-zA-Z]+)\s+([0-9a-fA-F]{8}).*$/;
|
||||||
|
|
||||||
|
|
||||||
|
WindowsCppEntriesProvider.IMAGE_BASE_RE =
|
||||||
|
/^\s+0000:00000000\s+___ImageBase\s+([0-9a-fA-F]{8}).*$/;
|
||||||
|
|
||||||
|
|
||||||
|
// This is almost a constant on Windows.
|
||||||
|
WindowsCppEntriesProvider.EXE_IMAGE_BASE = 0x00400000;
|
||||||
|
|
||||||
|
|
||||||
|
WindowsCppEntriesProvider.prototype.loadSymbols = function(libName) {
|
||||||
|
libName = this.targetRootFS + libName;
|
||||||
|
var fileNameFields = libName.match(WindowsCppEntriesProvider.FILENAME_RE);
|
||||||
|
if (!fileNameFields) return;
|
||||||
|
var mapFileName = fileNameFields[1] + '.map';
|
||||||
|
this.moduleType_ = fileNameFields[2].toLowerCase();
|
||||||
|
try {
|
||||||
|
this.symbols = read(mapFileName);
|
||||||
|
} catch (e) {
|
||||||
|
// If .map file cannot be found let's not panic.
|
||||||
|
this.symbols = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
WindowsCppEntriesProvider.prototype.parseNextLine = function() {
|
||||||
|
var lineEndPos = this.symbols.indexOf('\r\n', this.parsePos);
|
||||||
|
if (lineEndPos == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var line = this.symbols.substring(this.parsePos, lineEndPos);
|
||||||
|
this.parsePos = lineEndPos + 2;
|
||||||
|
|
||||||
|
// Image base entry is above all other symbols, so we can just
|
||||||
|
// terminate parsing.
|
||||||
|
var imageBaseFields = line.match(WindowsCppEntriesProvider.IMAGE_BASE_RE);
|
||||||
|
if (imageBaseFields) {
|
||||||
|
var imageBase = parseInt(imageBaseFields[1], 16);
|
||||||
|
if ((this.moduleType_ == 'exe') !=
|
||||||
|
(imageBase == WindowsCppEntriesProvider.EXE_IMAGE_BASE)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var fields = line.match(WindowsCppEntriesProvider.FUNC_RE);
|
||||||
|
return fields ?
|
||||||
|
{ name: this.unmangleName(fields[1]), start: parseInt(fields[2], 16) } :
|
||||||
|
null;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs very simple unmangling of C++ names.
|
||||||
|
*
|
||||||
|
* Does not handle arguments and template arguments. The mangled names have
|
||||||
|
* the form:
|
||||||
|
*
|
||||||
|
* ?LookupInDescriptor@JSObject@internal@v8@@...arguments info...
|
||||||
|
*/
|
||||||
|
WindowsCppEntriesProvider.prototype.unmangleName = function(name) {
|
||||||
|
// Empty or non-mangled name.
|
||||||
|
if (name.length < 1 || name.charAt(0) != '?') return name;
|
||||||
|
var nameEndPos = name.indexOf('@@');
|
||||||
|
var components = name.substring(1, nameEndPos).split('@');
|
||||||
|
components.reverse();
|
||||||
|
return components.join('::');
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export class ArgumentsProcessor extends BaseArgumentsProcessor {
|
||||||
|
getArgsDispatch() {
|
||||||
|
let dispatch = {
|
||||||
|
'-j': ['stateFilter', TickProcessor.VmStates.JS,
|
||||||
|
'Show only ticks from JS VM state'],
|
||||||
|
'-g': ['stateFilter', TickProcessor.VmStates.GC,
|
||||||
|
'Show only ticks from GC VM state'],
|
||||||
|
'-p': ['stateFilter', TickProcessor.VmStates.PARSER,
|
||||||
|
'Show only ticks from PARSER VM state'],
|
||||||
|
'-b': ['stateFilter', TickProcessor.VmStates.BYTECODE_COMPILER,
|
||||||
|
'Show only ticks from BYTECODE_COMPILER VM state'],
|
||||||
|
'-c': ['stateFilter', TickProcessor.VmStates.COMPILER,
|
||||||
|
'Show only ticks from COMPILER VM state'],
|
||||||
|
'-o': ['stateFilter', TickProcessor.VmStates.OTHER,
|
||||||
|
'Show only ticks from OTHER VM state'],
|
||||||
|
'-e': ['stateFilter', TickProcessor.VmStates.EXTERNAL,
|
||||||
|
'Show only ticks from EXTERNAL VM state'],
|
||||||
|
'--filter-runtime-timer': ['runtimeTimerFilter', null,
|
||||||
|
'Show only ticks matching the given runtime timer scope'],
|
||||||
|
'--call-graph-size': ['callGraphSize', TickProcessor.CALL_GRAPH_SIZE,
|
||||||
|
'Set the call graph size'],
|
||||||
|
'--ignore-unknown': ['ignoreUnknown', true,
|
||||||
|
'Exclude ticks of unknown code entries from processing'],
|
||||||
|
'--separate-ic': ['separateIc', parseBool,
|
||||||
|
'Separate IC entries'],
|
||||||
|
'--separate-bytecodes': ['separateBytecodes', parseBool,
|
||||||
|
'Separate Bytecode entries'],
|
||||||
|
'--separate-builtins': ['separateBuiltins', parseBool,
|
||||||
|
'Separate Builtin entries'],
|
||||||
|
'--separate-stubs': ['separateStubs', parseBool,
|
||||||
|
'Separate Stub entries'],
|
||||||
|
'--unix': ['platform', 'unix',
|
||||||
|
'Specify that we are running on *nix platform'],
|
||||||
|
'--windows': ['platform', 'windows',
|
||||||
|
'Specify that we are running on Windows platform'],
|
||||||
|
'--mac': ['platform', 'mac',
|
||||||
|
'Specify that we are running on Mac OS X platform'],
|
||||||
|
'--nm': ['nm', 'nm',
|
||||||
|
'Specify the \'nm\' executable to use (e.g. --nm=/my_dir/nm)'],
|
||||||
|
'--objdump': ['objdump', 'objdump',
|
||||||
|
'Specify the \'objdump\' executable to use (e.g. --objdump=/my_dir/objdump)'],
|
||||||
|
'--target': ['targetRootFS', '',
|
||||||
|
'Specify the target root directory for cross environment'],
|
||||||
|
'--apk-embedded-library': ['apkEmbeddedLibrary', '',
|
||||||
|
'Specify the path of the embedded library for Android traces'],
|
||||||
|
'--range': ['range', 'auto,auto',
|
||||||
|
'Specify the range limit as [start],[end]'],
|
||||||
|
'--distortion': ['distortion', 0,
|
||||||
|
'Specify the logging overhead in picoseconds'],
|
||||||
|
'--source-map': ['sourceMap', null,
|
||||||
|
'Specify the source map that should be used for output'],
|
||||||
|
'--timed-range': ['timedRange', true,
|
||||||
|
'Ignore ticks before first and after last Date.now() call'],
|
||||||
|
'--pairwise-timed-range': ['pairwiseTimedRange', true,
|
||||||
|
'Ignore ticks outside pairs of Date.now() calls'],
|
||||||
|
'--only-summary': ['onlySummary', true,
|
||||||
|
'Print only tick summary, exclude other information'],
|
||||||
|
'--preprocess': ['preprocessJson', true,
|
||||||
|
'Preprocess for consumption with web interface']
|
||||||
|
};
|
||||||
|
dispatch['--js'] = dispatch['-j'];
|
||||||
|
dispatch['--gc'] = dispatch['-g'];
|
||||||
|
dispatch['--compiler'] = dispatch['-c'];
|
||||||
|
dispatch['--other'] = dispatch['-o'];
|
||||||
|
dispatch['--external'] = dispatch['-e'];
|
||||||
|
dispatch['--ptr'] = dispatch['--pairwise-timed-range'];
|
||||||
|
return dispatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
getDefaultResults() {
|
||||||
|
return {
|
||||||
|
logFileName: 'v8.log',
|
||||||
|
platform: 'unix',
|
||||||
|
stateFilter: null,
|
||||||
|
callGraphSize: 5,
|
||||||
|
ignoreUnknown: false,
|
||||||
|
separateIc: true,
|
||||||
|
separateBytecodes: false,
|
||||||
|
separateBuiltins: true,
|
||||||
|
separateStubs: true,
|
||||||
|
preprocessJson: null,
|
||||||
|
targetRootFS: '',
|
||||||
|
nm: 'nm',
|
||||||
|
objdump: 'objdump',
|
||||||
|
range: 'auto,auto',
|
||||||
|
distortion: 0,
|
||||||
|
timedRange: false,
|
||||||
|
pairwiseTimedRange: false,
|
||||||
|
onlySummary: false,
|
||||||
|
runtimeTimerFilter: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -27,4 +27,4 @@ IF NOT %arg8:~0,2% == 8 (IF NOT %arg8:~0,2% == 8- SET log_file=%8)
|
|||||||
SET arg9=9%9
|
SET arg9=9%9
|
||||||
IF NOT %arg9:~0,2% == 9 (IF NOT %arg9:~0,2% == 9- SET log_file=%9)
|
IF NOT %arg9:~0,2% == 9 (IF NOT %arg9:~0,2% == 9- SET log_file=%9)
|
||||||
|
|
||||||
type %log_file% | %D8_PATH%\d8 %tools_dir%splaytree.js %tools_dir%codemap.js %tools_dir%csvparser.js %tools_dir%consarray.js %tools_dir%profile.js %tools_dir%profile_view.js %tools_dir%logreader.js %tools_dir%SourceMap.js %tools_dir%arguments.js %tools_dir%tickprocessor.js %tools_dir%tickprocessor-driver.js -- --windows %*
|
type %log_file% | %D8_PATH%\d8 --module %tools_dir%tickprocessor-driver.js -- --windows %*
|
||||||
|
Loading…
Reference in New Issue
Block a user