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

348 lines 28.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SourceFileMetaData = exports.AggregatedSourceNodeMetaData = void 0; const BaseModel_1 = require("./BaseModel"); const ModelMap_1 = require("./ModelMap"); const SourceNodeMetaData_1 = require("./SourceNodeMetaData"); const NodeModule_1 = require("./NodeModule"); const SensorValues_1 = require("./SensorValues"); const env_1 = require("../constants/env"); const SourceNodeRegex_1 = require("../constants/SourceNodeRegex"); const BufferHelper_1 = require("../helper/BufferHelper"); // Types const types_1 = require("../types"); class AggregatedSourceNodeMetaData extends BaseModel_1.BaseModel { constructor(total, max) { super(); this.total = total; this.max = max; } toBuffer() { throw new Error('ModelMap.toBuffer: not yet implemented'); } toJSON() { return { total: this.total.toJSON(), max: this.max.toJSON() }; } static join(...args) { return new AggregatedSourceNodeMetaData(SourceNodeMetaData_1.SourceNodeMetaData.sum(...args.map((x) => x.total)), SourceNodeMetaData_1.SourceNodeMetaData.max(...args.map((x) => x.max))); } static fromJSON(json) { let data; if (typeof json === 'string') { data = JSON.parse(json); } else { data = json; } return new AggregatedSourceNodeMetaData(SourceNodeMetaData_1.SourceNodeMetaData.fromJSON(data.total, undefined), SourceNodeMetaData_1.SourceNodeMetaData.fromJSON(data.max, undefined)); } } exports.AggregatedSourceNodeMetaData = AggregatedSourceNodeMetaData; class SourceFileMetaData extends BaseModel_1.BaseModel { constructor(path, pathIndex) { super(); this.path = path; this.pathIndex = pathIndex; } get containsUncommittedChanges() { if (this.pathIndex === undefined) { return false; } return this.pathIndex.containsUncommittedChanges; } set containsUncommittedChanges(v) { if (this.pathIndex !== undefined) { this.pathIndex.containsUncommittedChanges = v; } } normalize(newGlobalIndex) { function sortIDsByIdentifier(input) { return Array.from(input.values()) .map((value) => ({ identifier: value.sourceNodeIndex.identifier, id: value.id })) // Pair identifier with id .sort((a, b) => a.identifier.localeCompare(b.identifier)) // Sort by identifier .map((pair) => pair.id); // Extract sorted ids } const newPathIndex = this.pathIndex.insertToOtherIndex(newGlobalIndex); const newFunctions = new ModelMap_1.ModelMap('number'); for (const sourceNodeID of sortIDsByIdentifier(this.functions)) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const sourceNodeMetaData = this.functions.get(sourceNodeID); sourceNodeMetaData.normalize(newGlobalIndex); newFunctions.set(sourceNodeMetaData.id, sourceNodeMetaData); } this.pathIndex = newPathIndex; this._functions = newFunctions; } static merge(pathIndex, ...args) { if (args.length === 0) { throw new Error('SourceFileMetaData.merge: no SourceFileMetaDatas were given'); } const path = args[0].path; const containsUncommittedChanges = args .map((x) => x.containsUncommittedChanges) .reduce((prevValue, currValue) => prevValue || currValue); const valuesToMerge = { functions: {} }; for (const currentSourceFileMetaData of args) { if (path !== currentSourceFileMetaData.path) { throw new Error('SourceFileMetaData.merge: all SourceFileMetaDatas should be from the same file.'); } for (const [sourceNodeID, sourceNodeMetaData] of currentSourceFileMetaData.functions) { const sourceNodeIndex = currentSourceFileMetaData.getSourceNodeIndexByID(sourceNodeID); if (sourceNodeIndex === undefined) { throw new Error('SourceFileMetaData.merge: could not resolve sourceNode from id'); } const identifier = sourceNodeIndex.identifier; if (!valuesToMerge.functions[identifier]) { valuesToMerge.functions[identifier] = []; } valuesToMerge.functions[identifier].push(sourceNodeMetaData); } } const result = new SourceFileMetaData(path, pathIndex); for (const [identifier, sourceNodeMetaDatas] of Object.entries(valuesToMerge.functions)) { const sourceNodeIndex = result.getSourceNodeIndex('upsert', identifier); const sourceNodeID = sourceNodeIndex.id; result.functions.set(sourceNodeID, SourceNodeMetaData_1.SourceNodeMetaData.merge(sourceNodeID, sourceNodeIndex, ...sourceNodeMetaDatas)); } result.containsUncommittedChanges = containsUncommittedChanges; return result; } get functions() { if (!this._functions) { this._functions = new ModelMap_1.ModelMap('number'); } return this._functions; } getSourceNodeIndexByID(id) { return this.pathIndex.moduleIndex.globalIndex.getSourceNodeIndexByID(id); } getSourceNodeIndex(indexRequestType, sourceNodeIdentifier) { return this.pathIndex.getSourceNodeIndex(indexRequestType, sourceNodeIdentifier); } validate() { for (const [sourceNodeID, sourceNodeMetaData] of this.functions.entries()) { const sourceNodeIndex = this.getSourceNodeIndexByID(sourceNodeID); if (sourceNodeIndex === undefined) { throw new Error('SourceFileMetaData.validate: could not resolve source node index'); } const identifier = sourceNodeIndex === null || sourceNodeIndex === void 0 ? void 0 : sourceNodeIndex.identifier; if (!(sourceNodeIndex.pathIndex.moduleIndex.identifier === NodeModule_1.WASM_NODE_MODULE.identifier)) { if (sourceNodeMetaData.type === types_1.SourceNodeMetaDataType.LangInternalSourceNode) { if (!SourceNodeRegex_1.LangInternalSourceNodeIdentifierRegex.test(identifier)) { throw new Error('SourceFileMetaData.validate: invalid LangInternalSourceNodeIdentifier_string:' + identifier + '\n' + SourceNodeRegex_1.LangInternalSourceNodeIdentifierRegexString); } } else { if (!SourceNodeRegex_1.SourceNodeIdentifierRegex.test(identifier)) { throw new Error(`SourceFileMetaData.validate: invalid sourceNodeIdentifier: ${identifier}\n` + SourceNodeRegex_1.SourceNodeIdentifierRegexString); } } } sourceNodeMetaData.validate(this.path, identifier); } } toJSON() { if (env_1.NODE_ENV === 'test') { this.validate(); } return { path: this.path, functions: this.functions.toJSON() }; } static fromJSON(json, pathIndex) { let data; if (typeof json === 'string') { data = JSON.parse(json); } else { data = json; } const result = new SourceFileMetaData(data.path, pathIndex); if (data.functions) { for (const [sourceNodeID_string, nodeMetaData] of Object.entries(data.functions)) { const sourceNodeID = parseInt(sourceNodeID_string); result.functions.set(sourceNodeID, SourceNodeMetaData_1.SourceNodeMetaData.fromJSON(nodeMetaData, pathIndex.moduleIndex.globalIndex)); } } return result; } createOrGetSourceNodeMetaData(identifier, type) { const sourceNodeIndex = this.getSourceNodeIndex('upsert', identifier); const sourceNodeID = sourceNodeIndex.id; let node = this.functions.get(sourceNodeID); if (!node) { node = new SourceNodeMetaData_1.SourceNodeMetaData(type, sourceNodeID, new SensorValues_1.SensorValues({}), sourceNodeIndex); this.functions.set(sourceNodeID, node); } return node; } /** * Calculates the total SourceNodeMetaData of the SourceFile (the sum of all functions) * as well as the intern, extern and langInternal references. * * TLDR: * Returns the total sum of the measurements of the file and each external reference (not included in that file) * with their own sum of measurements. * * * Example: * * // File: FileA * ClassA: * functionA: * selfTime: 1 * aggregatedTime: 6 * intern: * ClassA.functionB: * aggregatedTime: 5 * functionB: * selfTime: 2 * aggregatedTime: 5 * intern: * ClassA.functionC: * aggregatedTime: 3 * functionC: * selfTime: 2 * aggregatedTime: 3 * intern: * ClassB.functionD: * aggregatedTime: 1 * * // File: FileB * ClassB: * functionD: * selfTime: 1 * aggregatedTime: 1 * * * Would return: * * sum: { selfTime: 5, aggregatedTime: 6, internCPUTime: 1 } * intern: * ClassB.functionD: * aggregatedCPUTime: 1 * extern: empty * langInternal: empty * * For each function in the file the sum is calculated by adding up: * hits, selfTime, aggregatedTime, langInternalTime, externTime and internTime * * Then intern self references within the same file are removed from the sum * * @returns { * sum // the sum of all functions in the file * intern // the sum of all intern references of each function in the file * extern // the sum of all extern references of each function in the file * langInternal // the sum of all langInternal references of each function in the file * } */ totalSourceNodeMetaData( // eslint-disable-next-line @typescript-eslint/no-unused-vars graph) { const listToSum = []; const intern = new ModelMap_1.ModelMap('number'); const extern = new ModelMap_1.ModelMap('number'); const langInternal = new ModelMap_1.ModelMap('number'); for (const sourceNodeMetaData of this.functions.values()) { listToSum.push(sourceNodeMetaData); for (const sourceNodeMetaDataReferences of [ sourceNodeMetaData.lang_internal, sourceNodeMetaData.intern, sourceNodeMetaData.extern ]) { for (const sourceNodeMetaDataReference of sourceNodeMetaDataReferences.values()) { const pathID = sourceNodeMetaDataReference.sourceNodeIndex.pathIndex.id; if (pathID === undefined) { throw new Error('totalSourceNodeMetaData: expected pathID'); } switch (sourceNodeMetaDataReferences) { case sourceNodeMetaData.lang_internal: { const sensorValuesOfFile = langInternal.get(pathID); langInternal.set(pathID, SensorValues_1.SensorValues.sum(sourceNodeMetaDataReference.sensorValues, ...(sensorValuesOfFile ? [sensorValuesOfFile] : []))); } break; case sourceNodeMetaData.intern: { const sensorValuesOfFile = intern.get(pathID); intern.set(pathID, SensorValues_1.SensorValues.sum(sourceNodeMetaDataReference.sensorValues, ...(sensorValuesOfFile ? [sensorValuesOfFile] : []))); } break; case sourceNodeMetaData.extern: { const sensorValuesOfFile = extern.get(pathID); extern.set(pathID, SensorValues_1.SensorValues.sum(sourceNodeMetaDataReference.sensorValues, ...(sensorValuesOfFile ? [sensorValuesOfFile] : []))); } break; } } } } if (this.pathIndex.id === undefined) { throw new Error('totalSourceNodeMetaData: expected pathIndex.id'); } const selfReference = intern.get(this.pathIndex.id); const result = SourceNodeMetaData_1.SourceNodeMetaData.sum(...listToSum); if (selfReference !== undefined) { // remove self references result.sensorValues.addToIntern(selfReference, -1); result.sensorValues.addToAggregated(selfReference, -1); // remove self references intern.delete(this.pathIndex.id); } return { sum: result, intern, extern, langInternal }; } maxSourceNodeMetaData() { return SourceNodeMetaData_1.SourceNodeMetaData.max(...this.functions.values()); } toBuffer() { const id = this.pathIndex.id; if (id === undefined) { throw new Error('SourceFileMetaData.toBuffer: expected id'); } const buffers = [BufferHelper_1.BufferHelper.UIntToBuffer(id), this.functions.toBuffer()]; return Buffer.concat(buffers); } static consumeFromBuffer(buffer, globalIndex) { let remainingBuffer = buffer; const { instance: pathID, remainingBuffer: newRemainingBuffer1 } = BufferHelper_1.BufferHelper.UIntFromBuffer(remainingBuffer); remainingBuffer = newRemainingBuffer1; const pathIndex = globalIndex.getPathIndexByID(pathID); if (pathIndex === undefined) { throw new Error('SourceFileMetaData.consumeFromBuffer: could not resolve pathIndex'); } const instance = new SourceFileMetaData(pathIndex.identifier, pathIndex); const consumeFromBufferWithModuleIndex = (buffer) => { return SourceNodeMetaData_1.SourceNodeMetaData.consumeFromBuffer(buffer, globalIndex); }; const { instance: functions, remainingBuffer: newRemainingBuffer2 } = ModelMap_1.ModelMap.consumeFromBuffer(remainingBuffer, 'number', consumeFromBufferWithModuleIndex); instance._functions = functions; remainingBuffer = newRemainingBuffer2; return { instance, remainingBuffer }; } } exports.SourceFileMetaData = SourceFileMetaData; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU291cmNlRmlsZU1ldGFEYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL21vZGVsL1NvdXJjZUZpbGVNZXRhRGF0YS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSwyQ0FBdUM7QUFDdkMseUNBQXFDO0FBQ3JDLDZEQUc2QjtBQUM3Qiw2Q0FBK0M7QUFDL0MsaURBQTZDO0FBTTdDLDBDQUEyQztBQUMzQyxrRUFLcUM7QUFDckMseURBQXFEO0FBQ3JELFFBQVE7QUFDUixvQ0FXaUI7QUFFakIsTUFBYSw0QkFBNkIsU0FBUSxxQkFBUztJQUkxRCxZQUNDLEtBQTJELEVBQzNELEdBQXlEO1FBRXpELEtBQUssRUFBRSxDQUFBO1FBQ1AsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUE7UUFDbEIsSUFBSSxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUE7SUFDZixDQUFDO0lBRUQsUUFBUTtRQUNQLE1BQU0sSUFBSSxLQUFLLENBQUMsd0NBQXdDLENBQUMsQ0FBQTtJQUMxRCxDQUFDO0lBRUQsTUFBTTtRQUNMLE9BQU87WUFDTixLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUU7WUFDMUIsR0FBRyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFO1NBQ3RCLENBQUE7SUFDRixDQUFDO0lBRUQsTUFBTSxDQUFDLElBQUksQ0FDVixHQUFHLElBQW9DO1FBRXZDLE9BQU8sSUFBSSw0QkFBNEIsQ0FDdEMsdUNBQWtCLENBQUMsR0FBRyxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQ25ELHVDQUFrQixDQUFDLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUNqRCxDQUFBO0lB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