@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
JavaScript
;
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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