UNPKG

@oaklean/profiler-core

Version:

Part of the @oaklean suite. It provides all basic functions to work with the `.oak` file format. It allows parsing the `.oak` file format as well as tools for analyzing the measurement values. It also provides all necessary capabilities required for prec

580 lines 64.7 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; 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 }); exports.InsertCPUProfileHelper = void 0; const fs = __importStar(require("fs")); const path_1 = __importDefault(require("path")); const CPUModel_1 = require("./CPUModel"); const memoize_1 = require("./memoize"); const TypescriptParser_1 = require("./TypescriptParser"); const TypescriptHelper_1 = require("./TypescriptHelper"); const LoggerHelper_1 = require("./LoggerHelper"); const ModuleReport_1 = require("../model/ModuleReport"); const UnifiedPath_1 = require("../system/UnifiedPath"); const TypeScriptAdapter_1 = require("../adapters/transformer/TypeScriptAdapter"); const ModelMap_1 = require("../model/ModelMap"); const SourceMap_1 = require("../model/SourceMap"); const GlobalIdentifier_1 = require("../system/GlobalIdentifier"); class InsertCPUProfileHelper { static callIdentifierToString(identifier) { return `${identifier.reportID}:${identifier.sourceNodeID}`; } static initAccountedIfNecessary(accounted, callIdentifierString, kind) { if (!accounted.map.has(callIdentifierString)) { accounted.map.set(callIdentifierString, []); switch (kind) { case 'intern': accounted.internMap.set(callIdentifierString, true); break; case 'extern': accounted.externMap.set(callIdentifierString, true); break; case 'langInternal': accounted.langInternalMap.set(callIdentifierString, true); break; } return true; } return false; } static removeFromAccounted(accounted, callIdentifier) { const callIdentifierString = InsertCPUProfileHelper.callIdentifierToString(callIdentifier); accounted.internMap.delete(callIdentifierString); accounted.externMap.delete(callIdentifierString); accounted.langInternalMap.delete(callIdentifierString); accounted.map.delete(callIdentifierString); } static markAsAccounted(accounted, self, parent) { const selfCallIdentifierString = InsertCPUProfileHelper.callIdentifierToString(self); const parentCallIdentifierString = InsertCPUProfileHelper.callIdentifierToString(parent); let previousChildCalls = accounted.map.get(parentCallIdentifierString); let alreadyAccounted = false; if (previousChildCalls === undefined) { previousChildCalls = []; accounted.map.set(parentCallIdentifierString, previousChildCalls); } else { alreadyAccounted = previousChildCalls.includes(selfCallIdentifierString); } previousChildCalls.push(selfCallIdentifierString); return alreadyAccounted; } // IMPORTANT to change when new measurement type gets added static sensorValuesForVisitedNode(cpuTime, cpuEnergyConsumption, ramEnergyConsumption, visited) { const cpuTimeResult = { selfCPUTime: cpuTime.selfCPUTime, aggregatedCPUTime: cpuTime.aggregatedCPUTime }; const cpuEnergyConsumptionResult = { selfCPUEnergyConsumption: cpuEnergyConsumption.selfCPUEnergyConsumption, aggregatedCPUEnergyConsumption: cpuEnergyConsumption.aggregatedCPUEnergyConsumption }; const ramEnergyConsumptionResult = { selfRAMEnergyConsumption: ramEnergyConsumption.selfRAMEnergyConsumption, aggregatedRAMEnergyConsumption: ramEnergyConsumption.aggregatedRAMEnergyConsumption }; if (visited) { cpuTimeResult.aggregatedCPUTime = 0; cpuEnergyConsumptionResult.aggregatedCPUEnergyConsumption = 0; ramEnergyConsumptionResult.aggregatedRAMEnergyConsumption = 0; } return { cpuTime: cpuTimeResult, cpuEnergyConsumption: cpuEnergyConsumptionResult, ramEnergyConsumption: ramEnergyConsumptionResult }; } static accountToLangInternal(cpuNode, reportToCredit, lastNodeCallInfo, accounted) { return __awaiter(this, void 0, void 0, function* () { const cpuTime = cpuNode.cpuTime; const cpuEnergyConsumption = cpuNode.cpuEnergyConsumption; const ramEnergyConsumption = cpuNode.ramEnergyConsumption; let firstTimeVisitedSourceNode_CallIdentifier = undefined; let parentSourceNode_CallIdentifier = undefined; const sourceNodeIdentifier = cpuNode.sourceNodeIdentifier; const langInternalPath = cpuNode.rawUrl; const sourceNode = reportToCredit.addToLangInternal(langInternalPath, sourceNodeIdentifier); const currentCallIdentifier = { reportID: reportToCredit.internID, sourceNodeID: sourceNode.id }; const currentCallIdentifierString = InsertCPUProfileHelper.callIdentifierToString(currentCallIdentifier); sourceNode.sensorValues.profilerHits += cpuNode.profilerHits; if (accounted.internMap.size === 0 && accounted.externMap.size === 0) { // if no extern or intern calls were accounted yet, add the time to the total of headless cpu time // IMPORTANT to change when new measurement type gets added reportToCredit.lang_internalHeadlessSensorValues.selfCPUTime = reportToCredit.lang_internalHeadlessSensorValues.selfCPUTime + (cpuTime.selfCPUTime || 0); reportToCredit.lang_internalHeadlessSensorValues.selfCPUEnergyConsumption = reportToCredit.lang_internalHeadlessSensorValues.selfCPUEnergyConsumption + (cpuEnergyConsumption.selfCPUEnergyConsumption || 0); reportToCredit.lang_internalHeadlessSensorValues.selfRAMEnergyConsumption = reportToCredit.lang_internalHeadlessSensorValues.selfRAMEnergyConsumption + (ramEnergyConsumption.selfRAMEnergyConsumption || 0); } sourceNode.addToSensorValues(InsertCPUProfileHelper.sensorValuesForVisitedNode(cpuTime, cpuEnergyConsumption, ramEnergyConsumption, accounted.map.has(currentCallIdentifierString))); if (InsertCPUProfileHelper.initAccountedIfNecessary(accounted, currentCallIdentifierString, 'langInternal')) { firstTimeVisitedSourceNode_CallIdentifier = currentCallIdentifier; } if (lastNodeCallInfo) { parentSourceNode_CallIdentifier = { reportID: lastNodeCallInfo.report.internID, sourceNodeID: lastNodeCallInfo.sourceNode.id }; const alreadyAccounted = InsertCPUProfileHelper.markAsAccounted(accounted, { reportID: reportToCredit.internID, sourceNodeID: sourceNode.id }, parentSourceNode_CallIdentifier); const langInternalSourceNodeReference = lastNodeCallInfo.sourceNode.addSensorValuesToLangInternal(sourceNode.globalIdentifier(), InsertCPUProfileHelper.sensorValuesForVisitedNode(cpuTime, cpuEnergyConsumption, ramEnergyConsumption, alreadyAccounted)); langInternalSourceNodeReference.sensorValues.profilerHits += cpuNode.profilerHits; } return { firstTimeVisitedSourceNode_CallIdentifier, parentSourceNode_CallIdentifier }; }); } static accountOwnCodeGetsExecutedByExternal(cpuNode, originalReport, functionIdentifier, relativeOriginalSourcePath, lastNodeCallInfo, accounted) { return __awaiter(this, void 0, void 0, function* () { const cpuTime = cpuNode.cpuTime; const cpuEnergyConsumption = cpuNode.cpuEnergyConsumption; const ramEnergyConsumption = cpuNode.ramEnergyConsumption; let newReportToCredit = undefined; let firstTimeVisitedSourceNode_CallIdentifier = undefined; let parentSourceNode_CallIdentifier = undefined; const newLastInternSourceNode = originalReport.addToIntern(cpuNode.relativeSourceFilePath.toString(), functionIdentifier); const currentCallIdentifier = { reportID: originalReport.internID, sourceNodeID: newLastInternSourceNode.id }; const currentCallIdentifierString = InsertCPUProfileHelper.callIdentifierToString(currentCallIdentifier); newLastInternSourceNode.sensorValues.profilerHits += cpuNode.profilerHits; // add measurements to original source code newLastInternSourceNode.addToSensorValues(InsertCPUProfileHelper.sensorValuesForVisitedNode(cpuTime, cpuEnergyConsumption, ramEnergyConsumption, accounted.map.has(currentCallIdentifierString))); if (InsertCPUProfileHelper.initAccountedIfNecessary(accounted, currentCallIdentifierString, 'intern')) { firstTimeVisitedSourceNode_CallIdentifier = currentCallIdentifier; } // remove aggregated time from last intern source node parentSourceNode_CallIdentifier = { reportID: lastNodeCallInfo.report.internID, sourceNodeID: lastNodeCallInfo.sourceNode.id }; // parent caller was already accounted once, so don't subtract the cpu time from it again const sensorValuesCorrected = InsertCPUProfileHelper.sensorValuesForVisitedNode(cpuTime, cpuEnergyConsumption, ramEnergyConsumption, accounted.map.has(InsertCPUProfileHelper.callIdentifierToString(parentSourceNode_CallIdentifier)) && accounted.map.get(InsertCPUProfileHelper.callIdentifierToString(parentSourceNode_CallIdentifier)).length > 0); // IMPORTANT to change when new measurement type gets added lastNodeCallInfo.sourceNode.sensorValues.aggregatedCPUTime = lastNodeCallInfo.sourceNode.sensorValues.aggregatedCPUTime - (sensorValuesCorrected.cpuTime.aggregatedCPUTime || 0); lastNodeCallInfo.sourceNode.sensorValues.aggregatedCPUEnergyConsumption = lastNodeCallInfo.sourceNode.sensorValues.aggregatedCPUEnergyConsumption - (sensorValuesCorrected. cpuEnergyConsumption. aggregatedCPUEnergyConsumption || 0); lastNodeCallInfo.sourceNode.sensorValues.aggregatedRAMEnergyConsumption = lastNodeCallInfo.sourceNode.sensorValues.aggregatedRAMEnergyConsumption - (sensorValuesCorrected. ramEnergyConsumption. aggregatedRAMEnergyConsumption || 0); // set call as accounted InsertCPUProfileHelper.markAsAccounted(accounted, currentCallIdentifier, parentSourceNode_CallIdentifier); if (relativeOriginalSourcePath) { originalReport.addSourceFileMapLink(cpuNode.relativeSourceFilePath, relativeOriginalSourcePath); } newReportToCredit = originalReport; // reset report back to the orignal report return { newReportToCredit, newLastInternSourceNode, firstTimeVisitedSourceNode_CallIdentifier, parentSourceNode_CallIdentifier }; }); } static accountToIntern(reportToCredit, cpuNode, functionIdentifier, relativeOriginalSourcePath, lastNodeCallInfo, awaiterStack, accounted) { var _a; return __awaiter(this, void 0, void 0, function* () { const cpuTime = cpuNode.cpuTime; const cpuEnergyConsumption = cpuNode.cpuEnergyConsumption; const ramEnergyConsumption = cpuNode.ramEnergyConsumption; let isAwaiterSourceNode = false; let firstTimeVisitedSourceNode_CallIdentifier = undefined; let parentSourceNode_CallIdentifier = undefined; // intern const newLastInternSourceNode = reportToCredit.addToIntern(cpuNode.relativeSourceFilePath.toString(), functionIdentifier); const currentCallIdentifier = { reportID: reportToCredit.internID, sourceNodeID: newLastInternSourceNode.id }; const currentCallIdentifierString = InsertCPUProfileHelper.callIdentifierToString(currentCallIdentifier); newLastInternSourceNode.sensorValues.profilerHits += cpuNode.profilerHits; newLastInternSourceNode.addToSensorValues(InsertCPUProfileHelper.sensorValuesForVisitedNode(cpuTime, cpuEnergyConsumption, ramEnergyConsumption, accounted.map.has(currentCallIdentifierString))); if (InsertCPUProfileHelper.initAccountedIfNecessary(accounted, currentCallIdentifierString, 'intern')) { firstTimeVisitedSourceNode_CallIdentifier = currentCallIdentifier; } if (functionIdentifier === TypescriptHelper_1.TypeScriptHelper.awaiterSourceNodeIdentifier()) { isAwaiterSourceNode = true; awaiterStack.push(newLastInternSourceNode); } const awaiterSourceNodeIndex = (_a = newLastInternSourceNode.getIndex()) === null || _a === void 0 ? void 0 : _a.pathIndex.getSourceNodeIndex('get', '{root}.{functionExpression:__awaiter}'); if (!isAwaiterSourceNode && awaiterSourceNodeIndex && accounted.map.has(InsertCPUProfileHelper.callIdentifierToString({ reportID: reportToCredit.internID, sourceNodeID: awaiterSourceNodeIndex.id }))) { /* The current source node is not an awaiter but there is an awaiter in the source file and the current source node was called by it. If the current source node was already using the awaiter (as an intern call) in the call tree, subtract the current aggregated measurements, since they are already accounted */ const lastAwaiterNode = awaiterStack[awaiterStack.length - 1]; if (lastAwaiterNode === undefined) { throw new Error('InsertCPUProfileHelper.accountToIntern: expected an awaiter in awaiterStack'); } if (lastAwaiterNode !== (lastNodeCallInfo === null || lastNodeCallInfo === void 0 ? void 0 : lastNodeCallInfo.sourceNode)) { const awaiterInternChild = newLastInternSourceNode.intern.get(awaiterSourceNodeIndex.id); if (awaiterInternChild !== undefined) { // IMPORTANT to change when new measurement type gets added awaiterInternChild. sensorValues. aggregatedCPUTime = awaiterInternChild.sensorValues.aggregatedCPUTime - (cpuTime.aggregatedCPUTime || 0); awaiterInternChild. sensorValues. aggregatedCPUEnergyConsumption = awaiterInternChild. sensorValues. aggregatedCPUEnergyConsumption - (cpuEnergyConsumption.aggregatedCPUEnergyConsumption || 0); awaiterInternChild. sensorValues. aggregatedRAMEnergyConsumption = awaiterInternChild. sensorValues. aggregatedRAMEnergyConsumption - (ramEnergyConsumption.aggregatedRAMEnergyConsumption || 0); // IMPORTANT to change when new measurement type gets added newLastInternSourceNode.sensorValues.internCPUTime = newLastInternSourceNode.sensorValues.internCPUTime - (cpuTime.aggregatedCPUTime || 0); newLastInternSourceNode.sensorValues.internCPUEnergyConsumption = newLastInternSourceNode.sensorValues.internCPUEnergyConsumption - (cpuEnergyConsumption.aggregatedCPUEnergyConsumption || 0); newLastInternSourceNode.sensorValues.internRAMEnergyConsumption = newLastInternSourceNode.sensorValues.internRAMEnergyConsumption - (ramEnergyConsumption.aggregatedRAMEnergyConsumption || 0); } } } if (relativeOriginalSourcePath) { reportToCredit.addSourceFileMapLink(cpuNode.relativeSourceFilePath, relativeOriginalSourcePath); } if (lastNodeCallInfo && lastNodeCallInfo.sourceNode !== newLastInternSourceNode) { parentSourceNode_CallIdentifier = { reportID: lastNodeCallInfo.report.internID, sourceNodeID: lastNodeCallInfo.sourceNode.id }; const alreadyAccounted = InsertCPUProfileHelper.markAsAccounted(accounted, currentCallIdentifier, parentSourceNode_CallIdentifier); const internSourceNodeReference = lastNodeCallInfo.sourceNode.addSensorValuesToIntern(newLastInternSourceNode.globalIdentifier(), InsertCPUProfileHelper.sensorValuesForVisitedNode(cpuTime, cpuEnergyConsumption, ramEnergyConsumption, alreadyAccounted)); internSourceNodeReference.sensorValues.profilerHits += cpuNode.profilerHits; } return { isAwaiterSourceNode, firstTimeVisitedSourceNode_CallIdentifier, parentSourceNode_CallIdentifier, newLastInternSourceNode }; }); } static accountToExtern(reportToCredit, cpuNode, nodeModule, functionIdentifier, relativeOriginalSourcePath, lastNodeCallInfo, accounted) { return __awaiter(this, void 0, void 0, function* () { const cpuTime = cpuNode.cpuTime; const cpuEnergyConsumption = cpuNode.cpuEnergyConsumption; const ramEnergyConsumption = cpuNode.ramEnergyConsumption; let firstTimeVisitedSourceNode_CallIdentifier = undefined; let parentSourceNode_CallIdentifier = undefined; const globalIdentifier = new GlobalIdentifier_1.GlobalIdentifier(cpuNode.relativeSourceFilePath.toString(), functionIdentifier, nodeModule); // extern const { report, sourceNodeMetaData } = reportToCredit.addToExtern(cpuNode.relativeSourceFilePath, nodeModule, functionIdentifier); const newReportToCredit = report; const newLastInternSourceNode = sourceNodeMetaData; const currentCallIdentifier = { reportID: report.internID, sourceNodeID: sourceNodeMetaData.id }; const currentCallIdentifierString = InsertCPUProfileHelper.callIdentifierToString(currentCallIdentifier); sourceNodeMetaData.sensorValues.profilerHits += cpuNode.profilerHits; sourceNodeMetaData.addToSensorValues(InsertCPUProfileHelper.sensorValuesForVisitedNode(cpuTime, cpuEnergyConsumption, ramEnergyConsumption, accounted.map.has(currentCallIdentifierString))); if (InsertCPUProfileHelper.initAccountedIfNecessary(accounted, currentCallIdentifierString, 'extern')) { firstTimeVisitedSourceNode_CallIdentifier = currentCallIdentifier; } if (lastNodeCallInfo) { parentSourceNode_CallIdentifier = { reportID: lastNodeCallInfo.report.internID, sourceNodeID: lastNodeCallInfo.sourceNode.id }; const alreadyAccounted = InsertCPUProfileHelper.markAsAccounted(accounted, currentCallIdentifier, parentSourceNode_CallIdentifier); // add to this source node as well const externSourceNodeReference = lastNodeCallInfo.sourceNode.addSensorValuesToExtern(globalIdentifier, InsertCPUProfileHelper.sensorValuesForVisitedNode(cpuTime, cpuEnergyConsumption, ramEnergyConsumption, alreadyAccounted)); externSourceNodeReference.sensorValues.profilerHits += cpuNode.profilerHits; } if (relativeOriginalSourcePath) { newReportToCredit.addSourceFileMapLink(cpuNode.relativeSourceFilePath, relativeOriginalSourcePath); } return { parentSourceNode_CallIdentifier, firstTimeVisitedSourceNode_CallIdentifier, newLastInternSourceNode, newReportToCredit }; }); } static resolveFunctionIdentifier(rootDir, cpuNode, programStructureTreePerFile, programStructureTreePerOriginalFile, transformerAdapterToUse, getSourceMapOfFile, getSourceMapFromSourceCode) { return __awaiter(this, void 0, void 0, function* () { /** * Resolve procedure: * * if file "dir/dir/file.ext" is transformable * - store transformed source code at programStructureTreePerFile["dir/dir/file.ext"] * - store original source code at * programStructureTreePerOriginalFile["_ORIGINAL_dir/dir/file.ext"] * else: (file is already transformed) * - store transformed source code at * programStructureTreePerFile["dir/dir/file.ext"] * - get source map of transformed file * - store original source code at * programStructureTreePerOriginalFile[path.resolve("dir/dir/" + sourcemap.source)] */ let sourceMap = undefined; let programStructureTree = undefined; let programStructureTreeOriginal = undefined; programStructureTree = programStructureTreePerFile.get(cpuNode.relativeUrl.toString()); const shouldBeTransformed = yield transformerAdapterToUse.shouldProcess(cpuNode.url); const { lineNumber, columnNumber } = cpuNode.sourceLocation; let relativeOriginalSourcePath = undefined; if (shouldBeTransformed) { relativeOriginalSourcePath = cpuNode.relativeUrl; const originalFilePath = '_ORIGINAL_' + cpuNode.relativeUrl.toString(); programStructureTreeOriginal = programStructureTreePerOriginalFile.get(originalFilePath); if (programStructureTree === undefined) { const transformedSourceCode = yield transformerAdapterToUse.process(cpuNode.url); if (!transformedSourceCode) { throw new Error('InsertCPUProfileHelper.resolveFunctionIdentifier Could not transform source code from: ' + cpuNode.url.toString()); } programStructureTree = TypescriptParser_1.TypescriptParser.parseSource(cpuNode.javascriptUrl, transformedSourceCode); programStructureTreePerFile.set(cpuNode.relativeUrl.toString(), programStructureTree); sourceMap = getSourceMapFromSourceCode(cpuNode.javascriptUrl, transformedSourceCode); } if (programStructureTreeOriginal === undefined) { programStructureTreeOriginal = TypescriptParser_1.TypescriptParser.parseFile(cpuNode.url); programStructureTreePerOriginalFile.set(originalFilePath, programStructureTreeOriginal); } } else { if (programStructureTree === undefined) { programStructureTree = TypescriptParser_1.TypescriptParser.parseFile(cpuNode.url); programStructureTreePerFile.set(cpuNode.relativeUrl.toString(), programStructureTree); } sourceMap = getSourceMapOfFile(cpuNode.url); const originalPosition = sourceMap === null || sourceMap === void 0 ? void 0 : sourceMap.getOriginalSourceLocation(lineNumber, columnNumber); if (originalPosition && originalPosition.source) { const absoluteOriginalSourcePath = new UnifiedPath_1.UnifiedPath(path_1.default.resolve(path_1.default.join(path_1.default.dirname(cpuNode.url.toString()), originalPosition.source))); if (fs.existsSync(absoluteOriginalSourcePath.toPlatformString())) { const pureRelativeOriginalSourcePath = rootDir.pathTo(absoluteOriginalSourcePath); relativeOriginalSourcePath = (cpuNode.nodeModulePath && cpuNode.nodeModule) ? cpuNode.nodeModulePath.pathTo(pureRelativeOriginalSourcePath) : pureRelativeOriginalSourcePath; programStructureTreeOriginal = programStructureTreePerOriginalFile.get(pureRelativeOriginalSourcePath.toString()); if (programStructureTreeOriginal === undefined) { programStructureTreeOriginal = TypescriptParser_1.TypescriptParser.parseFile(absoluteOriginalSourcePath); programStructureTreePerOriginalFile.set(pureRelativeOriginalSourcePath.toString(), programStructureTreeOriginal); } } } if (programStructureTreeOriginal === undefined) { programStructureTreeOriginal = programStructureTree; } } const functionIdentifier = programStructureTree.identifierBySourceLocation({ line: lineNumber, column: columnNumber }); const functionIdentifierPresentInOriginalFile = programStructureTree === programStructureTreeOriginal ? true : (programStructureTreeOriginal.sourceLocationOfIdentifier(functionIdentifier) !== undefined); if (functionIdentifier === '') { LoggerHelper_1.LoggerHelper.error('InsertCPUProfileHelper.resolveFunctionIdentifier: functionIdentifier should not be empty', { url: cpuNode.url.toString(), lineNumber, columnNumber }); throw new Error('InsertCPUProfileHelper.resolveFunctionIdentifier: functionIdentifier should not be empty'); } return { functionIdentifier, relativeOriginalSourcePath, functionIdentifierPresentInOriginalFile }; }); } static insertCPUProfile(reportToApply, rootDir, profile, transformerAdapter, metricsDataCollection) { return __awaiter(this, void 0, void 0, function* () { if (reportToApply.executionDetails.highResolutionBeginTime === undefined) { throw new Error('InsertCPUProfileHelper.insertCPUProfile: executionDetails.highResolutionBeginTime is undefined'); } const cpuModel = new CPUModel_1.CPUModel(rootDir, profile, BigInt(reportToApply.executionDetails.highResolutionBeginTime)); let transformerAdapterToUse; if (transformerAdapter) { transformerAdapterToUse = transformerAdapter; } else { transformerAdapterToUse = new TypeScriptAdapter_1.TypeScriptAdapter(); } const getSourceMapOfFile = (0, memoize_1.memoize)(SourceMap_1.SourceMap.fromCompiledJSFile); const getSourceMapFromSourceCode = (0, memoize_1.memoize)(SourceMap_1.SourceMap.fromCompiledJSString); const programStructureTreePerFile = new ModelMap_1.ModelMap('string'); const programStructureTreePerOriginalFile = new ModelMap_1.ModelMap('string'); if (metricsDataCollection && metricsDataCollection.items.length > 0) { // fill the cpu model with energy values cpuModel.energyValuesPerNode = cpuModel.energyValuesPerNodeByMetricsData(metricsDataCollection); } const awaiterStack = []; function afterTraverse(parentSourceNode_CallIdentifier, firstTimeVisitedSourceNode_CallIdentifier, isAwaiterSourceNode, accounted) { // equivalent to leave node since after child traverse if (parentSourceNode_CallIdentifier) { const childCalls = accounted.map.get(InsertCPUProfileHelper.callIdentifierToString(parentSourceNode_CallIdentifier)); if (childCalls === undefined) { throw new Error('InsertCPUProfileHelper.insertCPUProfile.traverse: expected childCalls to be present'); } childCalls.pop(); // remove self from parent } if (firstTimeVisitedSourceNode_CallIdentifier !== undefined) { InsertCPUProfileHelper.removeFromAccounted(accounted, firstTimeVisitedSourceNode_CallIdentifier); } if (isAwaiterSourceNode) { awaiterStack.pop(); } } function beforeTraverse(cpuNode, originalReport, reportToCreditArg, lastNodeCallInfo, accounted) { return __awaiter(this, void 0, void 0, function* () { let reportToCredit = reportToCreditArg; if (!cpuNode.isExtern && !cpuNode.isLangInternal) { reportToCredit = originalReport; } const sourceFileExists = fs.existsSync(cpuNode.url.toString()) && fs.statSync(cpuNode.url.toString()).isFile(); if (!cpuNode.isEmpty && !cpuNode.isLangInternal && !sourceFileExists) { throw new Error('InsertCPUProfileHelper.insertCPUProfile.traverse: Sourcefile does not exist: ' + cpuNode.url); } let firstTimeVisitedSourceNode_CallIdentifier = undefined; let parentSourceNode_CallIdentifier = undefined; let isAwaiterSourceNode = false; let newLastInternSourceNode = undefined; let newReportToCredit = undefined; if (cpuNode.isLangInternal) { const result = yield InsertCPUProfileHelper.accountToLangInternal(cpuNode, reportToCredit, lastNodeCallInfo, accounted); firstTimeVisitedSourceNode_CallIdentifier = result.firstTimeVisitedSourceNode_CallIdentifier; parentSourceNode_CallIdentifier = result.parentSourceNode_CallIdentifier; } else if (!cpuNode.isEmpty) { const { functionIdentifier, relativeOriginalSourcePath, functionIdentifierPresentInOriginalFile } = yield InsertCPUProfileHelper.resolveFunctionIdentifier(rootDir, cpuNode, programStructureTreePerFile, programStructureTreePerOriginalFile, transformerAdapterToUse, getSourceMapOfFile, getSourceMapFromSourceCode); // add to intern if the source file is not part of a node module // or the reportToCredit is the node module that source file belongs to const addToIntern = !((cpuNode.nodeModulePath && cpuNode.nodeModule)) || (reportToCredit instanceof ModuleReport_1.ModuleReport && reportToCredit.nodeModule.identifier === cpuNode.nodeModule.identifier); // this happens for node modules like the jest-runner, that executes the own code // the measurements will be credited to the original code rather than the node module that executes it const ownCodeGetsExecutedByExternal = cpuNode.nodeModulePath === null && lastNodeCallInfo && lastNodeCallInfo.sourceNode.sourceNodeIndex.pathIndex.moduleIndex.identifier !== '{self}'; if (ownCodeGetsExecutedByExternal) { const result = yield InsertCPUProfileHelper.accountOwnCodeGetsExecutedByExternal(cpuNode, originalReport, functionIdentifier, relativeOriginalSourcePath, lastNodeCallInfo, accounted); newReportToCredit = result.newReportToCredit; newLastInternSourceNode = result.newLastInternSourceNode; firstTimeVisitedSourceNode_CallIdentifier = result.firstTimeVisitedSourceNode_CallIdentifier; parentSourceNode_CallIdentifier = result.parentSourceNode_CallIdentifier; } else { if (addToIntern) { const result = yield InsertCPUProfileHelper.accountToIntern(reportToCredit, cpuNode, functionIdentifier, relativeOriginalSourcePath, lastNodeCallInfo, awaiterStack, accounted); isAwaiterSourceNode = result.isAwaiterSourceNode; firstTimeVisitedSourceNode_CallIdentifier = result.firstTimeVisitedSourceNode_CallIdentifier; parentSourceNode_CallIdentifier = result.parentSourceNode_CallIdentifier; newLastInternSourceNode = result.newLastInternSourceNode; } else { const result = yield InsertCPUProfileHelper.accountToExtern(reportToCredit, cpuNode, cpuNode.nodeModule, functionIdentifier, relativeOriginalSourcePath, lastNodeCallInfo, accounted); parentSourceNode_CallIdentifier = result.parentSourceNode_CallIdentifier; firstTimeVisitedSourceNode_CallIdentifier = result.firstTimeVisitedSourceNode_CallIdentifier; newLastInternSourceNode = result.newLastInternSourceNode; newReportToCredit = result.newReportToCredit; } } newLastInternSourceNode.presentInOriginalSourceCode = functionIdentifierPresentInOriginalFile; } return { originalReport, reportToCredit, newReportToCredit, newLastInternSourceNode, parentSourceNode_CallIdentifier, firstTimeVisitedSourceNode_CallIdentifier, isAwaiterSourceNode, accounted }; }); } function traverse(originalReport, reportToCredit, cpuNode, lastNodeCallInfo, accounted) { return __awaiter(this, void 0, void 0, function* () { const { newReportToCredit, newLastInternSourceNode, parentSourceNode_CallIdentifier, firstTimeVisitedSourceNode_CallIdentifier, isAwaiterSourceNode, } = yield beforeTraverse(cpuNode, originalReport, reportToCredit, lastNodeCallInfo, accounted); for (const child of cpuNode.children()) { yield traverse(originalReport, newReportToCredit ? newReportToCredit : reportToCredit, child, newLastInternSourceNode !== undefined ? { report: reportToCredit, sourceNode: newLastInternSourceNode } : undefined, accounted); } afterTraverse(parentSourceNode_CallIdentifier, firstTimeVisitedSourceNode_CallIdentifier, isAwaiterSourceNode, accounted); }); } yield traverse(reportToApply, reportToApply, cpuModel.getNode(0), undefined, { map: new Map, internMap: new Map(), externMap: new Map(), langInternalMap: new Map() }); }); } } exports.InsertCPUProfileHelper = InsertCPUProfileHelper; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSW5zZXJ0Q1BVUHJvZmlsZUhlbHBlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9oZWxwZXIvSW5zZXJ0Q1BVUHJvZmlsZUhlbHBlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLHVDQUF3QjtBQUN4QixnREFBdUI7QUFFdkIseUNBQXFDO0FBRXJDLHVDQUFtQztBQUNuQyx5REFBcUQ7QUFDckQseURBQXFEO0FBQ3JELGlEQUE2QztBQUk3Qyx3REFBb0Q7QUFDcEQsdURBQW1EO0FBSW5ELGlGQUE2RTtBQUM3RSxnREFBNEM7QUFFNUMsa0RBQThDO0FBSTlDLGlFQUE2RDtBQW1DN0QsTUFBYSxzQkFBc0I7SUFDbEMsTUFBTSxDQUFDLHNCQUFzQixDQUFDLFVBQTBCO1FBQ3ZELE9BQU8sR0FBRyxVQUFVLENBQUMsUUFBUSxJQUFJLFVBQVUsQ0FBQyxZQUFZLEVBQUUsQ0FBQTtJQUMzRCxDQUFDO0lBRUQsTUFBTSxDQUFDLHdCQUF3QixDQUM5QixTQUEyQixFQUMzQixvQkFBNEIsRUFDNUIsSUFBMEM7UUFFMUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLG9CQUFvQixDQUFDLEVBQUUsQ0FBQztZQUM5QyxTQUFTLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxvQkFBb0IsRUFBRSxFQUFFLENBQUMsQ0FBQTtZQUMzQyxRQUFRLElBQUksRUFBRSxDQUFDO2dCQUNkLEtBQUssUUFBUTtvQkFDWixTQUFTLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxvQkFBb0IsRUFBRSxJQUFJLENBQUMsQ0FBQTtvQkFDbkQsTUFBSztnQkFDTixLQUFLLFFBQVE7b0JBQ1osU0FBUyxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsb0JBQW9CLEVBQUUsSUFBSSxDQUFDLENBQUE7b0JBQ25ELE1BQUs7Z0JBQ04sS0FBSyxjQUFjO29CQUNsQixT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