v8/tools/system-analyzer/lws-middleware.js
Camillo Bruni 7a90c32032 [tools][system-analyzer] Add profiler-panel
Add basic profiler support
- Moved profiling-related helpers to profiling.mjs
- Added bottom-up profiler table
- Added mini-timeline overview wit opt/deopt events and usage graph
- Added flame-graph, pivoted on the currently selected function

Drive-by-fixes:
- Added/updated jsdoc type information
- Fixed static symbols (builtins, bytecodehandlers) that were both
  added by the CppEntriesProvider and from code-events in the v8.log
- Support platform-specific (linux/macos) dynamic symbol loader by
  adding a query path ('/v8/info/platform') to lws-middleware.js
- added css var --selection-color

Bug: v8:10644
Change-Id: I6412bec63eac13140d6d425e7d9cc33316824c73
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3585453
Reviewed-by: Patrick Thier <pthier@chromium.org>
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80192}
2022-04-26 17:57:03 +00:00

102 lines
2.9 KiB
JavaScript

// Copyright 2021 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.
const util = require('util');
const execFile = util.promisify(require('child_process').execFile);
const fs = require('fs')
async function sh(cmd, ...params) {
console.log(cmd, params.join(' '));
const options = {maxBuffer: 256 * 1024 * 1024};
const {stdout} = await execFile(cmd, params, options);
return stdout;
}
class Symbolizer {
constructor() {
this.nmExec = 'nm';
this.objdumpExec = 'objdump';
}
middleware(config) {
return async (ctx, next) => {
if (ctx.path == '/v8/loadVMSymbols') {
await this.parseVMSymbols(ctx)
} else if (ctx.path == '/v8/info/platform') {
ctx.response.type = 'text';
ctx.response.body = process.platform;
}
await next();
}
}
async parseVMSymbols(ctx) {
const query = ctx.request.query;
const result = {
libName: query.libName,
symbols: ['', ''],
error: undefined,
fileOffsetMinusVma: 0,
};
switch (query.platform) {
case 'macos':
await this.loadVMSymbolsMacOS(query, result);
break;
case 'linux':
await this.loadVMSymbolsLinux(query, result);
break;
default:
ctx.response.status = '500';
return;
}
ctx.response.type = 'json';
ctx.response.body = JSON.stringify(result);
}
async loadVMSymbolsMacOS(query, result) {
let libName =
(query.targetRootFS ? query.targetRootFS : '') + query.libName;
try {
// Fast skip files that don't exist.
if (libName.indexOf('/') === -1 || !fs.existsSync(libName)) return;
result.symbols = [await sh(this.nmExec, '--demangle', '-n', libName), ''];
} catch (e) {
result.error = e.message;
}
}
async loadVMSymbolsLinux(query, result) {
let libName = query.libName;
if (query.apkEmbeddedLibrary && libName.endsWith('.apk')) {
libName = query.apkEmbeddedLibrary;
}
if (query.targetRootFS) {
libName = libName.substring(libName.lastIndexOf('/') + 1);
libName = query.targetRootFS + libName;
}
try {
// Fast skip files that don't exist.
if (libName.indexOf('/') === -1 || !fs.existsSync(libName)) return;
result.symbols = [
await sh(this.nmExec, '-C', '-n', '-S', libName),
await sh(this.nmExec, '-C', '-n', '-S', '-D', libName)
];
const objdumpOutput = await sh(this.objdumpExec, '-h', libName);
for (const line of objdumpOutput.split('\n')) {
const [, sectionName, , vma, , fileOffset] = line.trim().split(/\s+/);
if (sectionName === '.text') {
result.fileOffsetMinusVma =
parseInt(fileOffset, 16) - parseInt(vma, 16);
}
}
} catch (e) {
console.log(e);
result.error = e.message;
}
}
}
module.exports = Symbolizer