@oaklean/cli
Version:
A command-line interface that provides utilities for parsing, inspecting, and converting the .oak file format, as well as interfaces used in the @oaklean suite.
293 lines • 29.3 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const cli_color_1 = __importDefault(require("cli-color"));
const profiler_core_1 = require("@oaklean/profiler-core");
const commander_1 = require("commander");
var TraceColors;
(function (TraceColors) {
TraceColors[TraceColors["LangInternal"] = 9] = "LangInternal";
TraceColors[TraceColors["External"] = 11] = "External";
TraceColors[TraceColors["WebAssembly"] = 57] = "WebAssembly";
TraceColors[TraceColors["Webpack"] = 39] = "Webpack";
})(TraceColors || (TraceColors = {}));
class CPUProfileCommands {
constructor() {
const baseCommand = commander_1.program
.command('profile')
.description("commands to convert or inspect the cpu profile's format");
baseCommand
.command('toCPUModel')
.description('Converts a cpu profile format that is given to a cpu model format')
.argument('<input>', 'input file path')
.argument('<output>', 'output file path')
.action(this.convertToCPUModel.bind(this));
baseCommand
.command('inspect')
.description('Displays an overview of the cpu profile stats')
.argument('<input>', 'input file path')
.action(this.inspect.bind(this));
baseCommand
.command('trace')
.description('Displays the trace of the cpu profile')
.argument('<input>', 'input file path')
.option('-r, --root-dir <rootdir>', 'specify which root dir should be used, if not set it will be determined by the config file', undefined)
.option('-e, --external-resources [external-resources]', 'external resources file path - When provided, this improves file resolution accuracy and ensures source maps are taken into account.', undefined)
.action(this.trace.bind(this));
baseCommand
.command('anonymize')
.description('Converts all paths in the cpu profile to relative paths ' +
`(relative to the rootDir mentioned in the ${profiler_core_1.STATIC_CONFIG_FILENAME} config)` +
' to remove all user related paths')
.argument('<input>', 'input file path')
.option('-o, --output <output>', 'output file path (default: input file path)')
.action(this.anonymize.bind(this));
}
static init() {
return new CPUProfileCommands();
}
convertToCPUModel(input, output) {
return __awaiter(this, void 0, void 0, function* () {
let inputPath = new profiler_core_1.UnifiedPath(input);
if (inputPath.isRelative()) {
inputPath = new profiler_core_1.UnifiedPath(process.cwd()).join(inputPath);
}
let outputPath = new profiler_core_1.UnifiedPath(output);
if (outputPath.isRelative()) {
outputPath = new profiler_core_1.UnifiedPath(process.cwd()).join(outputPath);
}
const cpuProfile = yield profiler_core_1.CPUProfileHelper.loadFromFile(inputPath);
if (cpuProfile === undefined) {
profiler_core_1.LoggerHelper.error(`CPU profile could not be loaded from ${inputPath.toPlatformString()}. ` +
'Please make sure the file exists and is a valid CPU profile.');
return;
}
const cpuModel = new profiler_core_1.CPUModel(new profiler_core_1.UnifiedPath(__dirname).join('..'), cpuProfile, BigInt(0));
yield cpuModel.storeToFile(outputPath);
});
}
inspect(input) {
return __awaiter(this, void 0, void 0, function* () {
let inputPath = new profiler_core_1.UnifiedPath(input);
if (inputPath.isRelative()) {
inputPath = new profiler_core_1.UnifiedPath(process.cwd()).join(inputPath);
}
const cpuProfile = yield profiler_core_1.CPUProfileHelper.loadFromFile(inputPath);
if (cpuProfile === undefined) {
profiler_core_1.LoggerHelper.error(`CPU profile could not be loaded from ${inputPath.toPlatformString()}. ` +
'Please make sure the file exists and is a valid CPU profile.');
return;
}
const cpuModel = new profiler_core_1.CPUModel(new profiler_core_1.UnifiedPath(__dirname).join('..'), cpuProfile, BigInt(0));
const nodeCount = cpuModel.INodes.length;
const sourceNodeLocationCount = cpuModel.CPUProfileSourceLocations.length;
const sampleCount = cpuModel.samples.length;
let totalHits = 0;
let totalCPUTime = 0;
function traverse(cpuNode) {
for (const child of cpuNode.children()) {
totalCPUTime += child.cpuTime.selfCPUTime || 0;
totalHits += child.profilerHits;
traverse(child);
}
}
traverse(cpuModel.getNode(0));
profiler_core_1.LoggerHelper.table([
{
type: 'Node Count',
value: nodeCount
},
{
type: 'Source Node Location Count',
value: sourceNodeLocationCount
},
{
type: 'Sample Count',
value: sampleCount
},
{
type: 'Total Hits',
value: totalHits
},
{
type: 'Total CPU Time',
value: totalCPUTime,
unit: 'µs'
}
], ['type', 'value', 'unit']);
});
}
trace(input, options) {
return __awaiter(this, void 0, void 0, function* () {
let inputPath = new profiler_core_1.UnifiedPath(input);
if (inputPath.isRelative()) {
inputPath = new profiler_core_1.UnifiedPath(process.cwd()).join(inputPath);
}
let externalResourcesInput = options.externalResources;
if (externalResourcesInput === true) {
externalResourcesInput = new profiler_core_1.ExportAssetHelper(inputPath.dirName())
.outputExternalResourceHelperPath(inputPath.filename())
.toPlatformString();
profiler_core_1.LoggerHelper.log('No external resources file provided, attempting to determine one automatically.', `Using: ${externalResourcesInput}`);
}
const cpuProfile = yield profiler_core_1.CPUProfileHelper.loadFromFile(inputPath);
if (cpuProfile === undefined) {
profiler_core_1.LoggerHelper.error(`CPU profile could not be loaded from ${inputPath.toPlatformString()}. ` +
'Please make sure the file exists and is a valid CPU profile.');
return;
}
let rootDir;
if (options.rootDir !== undefined) {
rootDir = new profiler_core_1.UnifiedPath(options.rootDir);
}
else {
const profilerConfig = profiler_core_1.ProfilerConfig.autoResolveFromPath(inputPath.dirName());
rootDir = profilerConfig.getRootDir();
}
let resolveFunctionIdentifierHelper;
let externalResourceHelper;
if (externalResourcesInput !== undefined) {
let resourcesHelperPath = new profiler_core_1.UnifiedPath(externalResourcesInput);
if (resourcesHelperPath.isRelative()) {
resourcesHelperPath = new profiler_core_1.UnifiedPath(process.cwd()).join(resourcesHelperPath);
}
externalResourceHelper = profiler_core_1.ExternalResourceHelper.loadFromFile(rootDir, resourcesHelperPath);
if (externalResourceHelper === undefined) {
profiler_core_1.LoggerHelper.warn('Failed to load external resources file. Check if the file exists and is valid.');
}
else {
resolveFunctionIdentifierHelper = new profiler_core_1.ResolveFunctionIdentifierHelper(rootDir, externalResourceHelper);
}
}
function colorByType(cpuNode, resolvedAsExternal) {
if (cpuNode.sourceLocation.isLangInternal) {
return cli_color_1.default.xterm(TraceColors.LangInternal);
}
else if (cpuNode.sourceLocation.isWASM) {
return cli_color_1.default.xterm(TraceColors.WebAssembly);
}
else if (cpuNode.sourceLocation.isWebpack) {
return cli_color_1.default.xterm(TraceColors.Webpack);
}
else if (resolvedAsExternal ||
cpuNode.sourceLocation.relativeUrl.toString().includes('/node_modules/')) {
return cli_color_1.default.xterm(TraceColors.External);
}
return (arg) => arg;
}
const cpuModel = new profiler_core_1.CPUModel(rootDir, cpuProfile, BigInt(0));
function traverse(cpuNode_1) {
return __awaiter(this, arguments, void 0, function* (cpuNode, parentsPaint = [], last = [] // specifies wether the parents are the last children
) {
let selfPaint = colorByType(cpuNode, false);
if (cpuNode.index === 0) {
const resolvedPrefix = resolveFunctionIdentifierHelper !== undefined
? cli_color_1.default.xterm(TraceColors.LangInternal)('■ ')
: '';
profiler_core_1.LoggerHelper.log(resolvedPrefix +
cli_color_1.default.xterm(TraceColors.LangInternal)('■ ') +
cli_color_1.default.green('({root})'));
}
else {
let indent = '';
for (let i = 0; i < last.length - 1; i++) {
if (last[i]) {
indent += ' ';
}
else {
indent += parentsPaint[i]('│ ');
}
}
const originalPrefix = selfPaint('■ ');
let resolvedPrefix = '';
let relativeFilePath = cpuNode.sourceLocation.relativeUrl.toString();
let resolvedFunctionName = '';
if (resolveFunctionIdentifierHelper !== undefined) {
if (!cpuNode.sourceLocation.isLangInternal &&
!cpuNode.sourceLocation.isWASM) {
const { sourceNodeLocation, nodeModule, relativeNodeModulePath } = yield resolveFunctionIdentifierHelper.resolveFunctionIdentifier(cpuNode.sourceLocation);
relativeFilePath = sourceNodeLocation.relativeFilePath.toString();
const functionIdentifierParts = sourceNodeLocation.functionIdentifier.split('.');
resolvedFunctionName =
functionIdentifierParts[functionIdentifierParts.length - 1];
if (relativeNodeModulePath !== null && nodeModule !== null) {
// change color to node module
selfPaint = colorByType(cpuNode, true);
}
}
resolvedPrefix = selfPaint('■ ');
}
const lastIndent = parentsPaint[parentsPaint.length - 1](last[last.length - 1] ? '└' : '├') + selfPaint('─ ');
console.log(originalPrefix +
resolvedPrefix +
indent +
lastIndent +
relativeFilePath +
(resolvedFunctionName !== ''
? cli_color_1.default.green(` ${resolvedFunctionName}`)
: '') +
cli_color_1.default.green(` (${cpuNode.sourceLocation.rawFunctionName})`) +
`[CM_ID: ${cpuNode.index}]`, `[LOC_ID: ${cpuNode.sourceLocation.index}]`, `[SCRIPT_ID: ${cpuNode.sourceLocation.scriptID} | ${cpuNode.sourceLocation.isLangInternal}]`, `- ${cpuNode.cpuTime.selfCPUTime} µs | ${cpuNode.cpuTime.aggregatedCPUTime} µs`);
}
const nodes = Array.from(cpuNode.children());
for (let i = 0; i < nodes.length; i++) {
yield traverse(nodes[i], [...parentsPaint, selfPaint], [...last, i === nodes.length - 1]);
}
});
}
// vertical legend
profiler_core_1.LoggerHelper.log('\nLegend:\n' +
' ■ ' +
' Node (own code)\n' +
cli_color_1.default.xterm(TraceColors.LangInternal)(' ■ ') +
' Node (node internal)\n' +
cli_color_1.default.xterm(TraceColors.External)(' ■ ') +
' Node (node module)\n' +
cli_color_1.default.xterm(TraceColors.WebAssembly)(' ■ ') +
' Node (WebAssembly)\n' +
cli_color_1.default.xterm(TraceColors.Webpack)(' ■ ') +
' Node (Webpack)\n');
if (resolveFunctionIdentifierHelper !== undefined) {
profiler_core_1.LoggerHelper.log('┌───' +
' originally from the cpu profile\n' +
'│ ┌─' +
' resolved via the external resource (using sourcemaps)\n' +
'│ │ ');
}
yield traverse(cpuModel.getNode(0));
});
}
anonymize(input, options) {
return __awaiter(this, void 0, void 0, function* () {
let inputPath = new profiler_core_1.UnifiedPath(input);
if (inputPath.isRelative()) {
inputPath = new profiler_core_1.UnifiedPath(process.cwd()).join(inputPath);
}
let outputPath;
if (options.output === undefined) {
outputPath = inputPath.copy();
}
else {
outputPath = new profiler_core_1.UnifiedPath(options.output);
if (outputPath.isRelative()) {
outputPath = new profiler_core_1.UnifiedPath(process.cwd()).join(outputPath);
}
}
const profilerConfig = profiler_core_1.ProfilerConfig.autoResolveFromPath(inputPath.dirName());
yield profiler_core_1.CPUProfileHelper.anonymize(profilerConfig.getRootDir(), inputPath, outputPath);
});
}
}
exports.default = CPUProfileCommands;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ1BVUHJvZmlsZUNvbW1hbmRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbW1hbmRzL0NQVVByb2ZpbGVDb21tYW5kcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7OztBQUFBLDBEQUEyQjtBQUMzQiwwREFZK0I7QUFDL0IseUNBQW1DO0FBR25DLElBQUssV0FLSjtBQUxELFdBQUssV0FBVztJQUNmLDZEQUFnQixDQUFBO0lBQ2hCLHNEQUFhLENBQUE7SUFDYiw0REFBZ0IsQ0FBQTtJQUNoQixvREFBWSxDQUFBO0FBQ2IsQ0FBQyxFQUxJLFdBQVcsS0FBWCxXQUFXLFFBS2Y7QUFFRCxNQUFxQixrQkFBa0I7SUFDdEM7UUFDQyxNQUFNLFdBQVcsR0FBRyxtQkFBTzthQUN6QixPQUFPLENBQUMsU0FBUyxDQUFDO2FBQ2xCLFdBQVcsQ0FBQyx5REFBeUQsQ0FBQyxDQUFBO1FBRXhFLFdBQVc7YUFDVCxPQUFPLENBQUMsWUFBWSxDQUFDO2FBQ3JCLFdBQVcsQ0FDWCxtRUFBbUUsQ0FDbkU7YUFDQSxRQUFRLENBQUMsU0FBUyxFQUFFLGlCQUFpQixDQUFDO2FBQ3RDLFFBQVEsQ0FBQyxVQUFVLEVBQUUsa0JBQWtCLENBQUM7YUFDeEMsTUFBTSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQTtRQUUzQyxXQUFXO2FBQ1QsT0FBTyxDQUFDLFNBQVMsQ0FBQzthQUNsQixXQUFXLENBQUMsK0NBQStDLENBQUM7YUFDNUQsUUFBUSxDQUFDLFNBQVMsRUFBRSxpQkFBaUIsQ0FBQzthQUN0QyxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQTtRQUVqQyxXQUFXO2FBQ1QsT0FBTyxDQUFDLE9BQU8sQ0FBQzthQUNoQixXQUFXLENBQUMsdUNBQXVDLENBQUM7YUFDcEQsUUFBUSxDQUFDLFNBQVMsRUFBRSxp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