@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
194 lines • 21.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.StateMachineLogger = void 0;
const LoggerHelper_1 = require("../LoggerHelper");
class StateMachineLogger {
static logState(depth, cpuNode, currentState) {
var _a;
/*
[STATE] moduleFunction_fileA_0 (./fileA.js)
├─ Depth : 1
├─ CPU Node : 001
├─ ReportID : 1
├─ SourceNodeID : 3
├─ Scope : module
├─ Type : intern
├─ Headless : false
├─ Profiler Hits : 2
├─ CPU Time : self=20 µs | total=30 µs
├─ CPU Energy : self=0 mJ | total=0 mJ
├─ RAM Energy : self=0 mJ | total=0 mJ
*/
if (currentState.callIdentifier.sourceNode === null) {
LoggerHelper_1.LoggerHelper.log(LoggerHelper_1.LoggerHelper.successString('[STATE]'), '(root)');
return;
}
const sourceNodeIndex = (_a = currentState.callIdentifier.sourceNode) === null || _a === void 0 ? void 0 : _a.getIndex();
if (sourceNodeIndex === undefined) {
throw new Error('InsertCPUProfileStateMachine.logState: sourceNode has no index');
}
const sensorValues = currentState.callIdentifier.sourceNode.sensorValues;
LoggerHelper_1.LoggerHelper.log(LoggerHelper_1.LoggerHelper.successString('[STATE]'), `${sourceNodeIndex.functionName}`, `(${sourceNodeIndex.pathIndex.identifier})`, '\n' +
StateMachineLogger.formatState({
Depth: depth.toString(),
'CPU Node': String(cpuNode.index).padStart(3, '0'),
ReportID: currentState.callIdentifier.report.internID.toString(),
SourceNodeID: currentState.callIdentifier.sourceNode.id.toString(),
Scope: currentState.scope,
Type: currentState.type,
Headless: currentState.headless.toString(),
'Profiler Hits': `${sensorValues.profilerHits}`,
'CPU Time': `self=${sensorValues.selfCPUTime} µs | total=${sensorValues.aggregatedCPUTime} µs | l=${sensorValues.langInternalCPUTime} µs | i=${sensorValues.internCPUTime} µs | e=${sensorValues.externCPUTime} µs`,
'CPU Energy': `self=${sensorValues.selfCPUEnergyConsumption} mJ | total=${sensorValues.aggregatedCPUEnergyConsumption} mJ | l=${sensorValues.langInternalCPUEnergyConsumption} mJ | i=${sensorValues.internCPUEnergyConsumption} mJ | e=${sensorValues.externCPUEnergyConsumption} mJ `,
'RAM Energy': `self=${sensorValues.selfRAMEnergyConsumption} mJ | total=${sensorValues.aggregatedRAMEnergyConsumption} mJ | l=${sensorValues.langInternalRAMEnergyConsumption} mJ | i=${sensorValues.internRAMEnergyConsumption} mJ | e=${sensorValues.externRAMEnergyConsumption} mJ`
}));
const iterators = {
LANG_INTERNAL: currentState.callIdentifier.sourceNode.lang_internal.values(),
INTERN: currentState.callIdentifier.sourceNode.intern.values(),
EXTERN: currentState.callIdentifier.sourceNode.extern.values()
};
for (const [type, iterator] of Object.entries(iterators)) {
let hasEntries = false;
for (const referenceSourceNode of iterator) {
if (hasEntries === false) {
LoggerHelper_1.LoggerHelper.log(LoggerHelper_1.LoggerHelper.warnString(`${type} REFERENCES`));
hasEntries = true;
}
StateMachineLogger.logSourceNodeReference(referenceSourceNode);
}
}
}
static logSourceNodeReference(referenceSourceNode) {
LoggerHelper_1.LoggerHelper.log(`SourceNodeID: ${referenceSourceNode.id.toString()}\n` +
StateMachineLogger.formatReference({
'CPU Time': `self=${referenceSourceNode.sensorValues.selfCPUTime} µs | total=${referenceSourceNode.sensorValues.aggregatedCPUTime} µs`,
'CPU Energy': `self=${referenceSourceNode.sensorValues.selfCPUEnergyConsumption} mJ | total=${referenceSourceNode.sensorValues.aggregatedCPUEnergyConsumption} mJ`,
'RAM Energy': `self=${referenceSourceNode.sensorValues.selfRAMEnergyConsumption} mJ | total=${referenceSourceNode.sensorValues.aggregatedRAMEnergyConsumption} mJ`
}));
}
static logLeaveTransition(currentState, nextState) {
var _a, _b;
const currentSourceNodeIndex = (_a = currentState.callIdentifier.sourceNode) === null || _a === void 0 ? void 0 : _a.getIndex();
const currentSourceNodeName = currentSourceNodeIndex !== undefined
? currentSourceNodeIndex.functionName
: '(root)';
const nextSourceNodeIndex = (_b = nextState.callIdentifier.sourceNode) === null || _b === void 0 ? void 0 : _b.getIndex();
const nextSourceNodeName = nextSourceNodeIndex !== undefined
? nextSourceNodeIndex.functionName
: '(root)';
LoggerHelper_1.LoggerHelper.log(LoggerHelper_1.LoggerHelper.errorString('[LEAVE TRANSITION]'), `${currentSourceNodeName}`, `-> ${nextSourceNodeName}`);
}
static logTransition(cpuNode, transition, accountingInfo, currentState, nextState) {
var _a, _b;
/*
[TRANSITION] (root) -> moduleFunction_fileA_0
├─ CPU Node : 000
├─ Transition : toModule
├─ AccountingType : accountToExtern
├─ FirstTimeVisited : true
├─ Accounted Hits : 2
├─ Accounted CPU Time : self=20 µs | total=30 µs
├─ Accounted CPU Energy : self=0 mJ | total=0 mJ
├─ Accounted RAM Energy : self=0 mJ | total=0 mJ
*/
const currentSourceNodeIndex = (_a = currentState.callIdentifier.sourceNode) === null || _a === void 0 ? void 0 : _a.getIndex();
const currentSourceNodeName = currentSourceNodeIndex !== undefined
? currentSourceNodeIndex.functionName
: '(root)';
const nextSourceNodeIndex = (_b = nextState.callIdentifier.sourceNode) === null || _b === void 0 ? void 0 : _b.getIndex();
const nextSourceNodeName = nextSourceNodeIndex !== undefined
? nextSourceNodeIndex.functionName
: '(root)';
LoggerHelper_1.LoggerHelper.log(LoggerHelper_1.LoggerHelper.warnString('[TRANSITION]'), `${currentSourceNodeName} -> ${nextSourceNodeName}`, '\n' +
StateMachineLogger.formatTransition({
'CPU Node': String(cpuNode.index).padStart(3, '0'),
Transition: transition.transition,
'Create Link': transition.options.createLink.toString(),
AccountingType: accountingInfo.type,
FirstTimeVisited: accountingInfo.accountedSourceNode.firstTimeVisited.toString(),
'Accounted Hits': `${cpuNode.profilerHits}`,
'Accounted CPU Time': `self=${(accountingInfo === null || accountingInfo === void 0 ? void 0 : accountingInfo.accountedSensorValues.selfCPUTime) || 0} µs | total=${(accountingInfo === null || accountingInfo === void 0 ? void 0 : accountingInfo.accountedSensorValues.aggregatedCPUTime) || 0} µs`,
'Accounted CPU Energy': `self=${(accountingInfo === null || accountingInfo === void 0 ? void 0 : accountingInfo.accountedSensorValues.selfCPUEnergyConsumption) || 0} mJ | total=${(accountingInfo === null || accountingInfo === void 0 ? void 0 : accountingInfo.accountedSensorValues.aggregatedCPUEnergyConsumption) || 0} mJ`,
'Accounted RAM Energy': `self=${(accountingInfo === null || accountingInfo === void 0 ? void 0 : accountingInfo.accountedSensorValues.selfRAMEnergyConsumption) || 0} mJ | total=${(accountingInfo === null || accountingInfo === void 0 ? void 0 : accountingInfo.accountedSensorValues.aggregatedRAMEnergyConsumption) || 0} mJ`
}));
}
static logCompensation(depth, cpuNode, currentState, compensation, title) {
/*
[CREATE COMPENSATION | APPLY COMPENSATION] 2 moduleFunction_fileA_0 (./fileA.js)
├─ Depth : 2
├─ CPU Node : 002
├─ ReportID : 1
├─ SourceNodeID : 5
├─ Scope : module
├─ Type : intern
├─ Headless : false
├─ Compensated CPU Time : self=30 µs | total=0 µs
├─ Compensated CPU Energy : self=0 mJ | total=0 mJ
├─ Compensated RAM Energy : self=0 mJ | total=0 mJ
*/
if (currentState.callIdentifier.sourceNode === null) {
LoggerHelper_1.LoggerHelper.log(LoggerHelper_1.LoggerHelper.errorString(`[${title}]`), compensation.id.toString(), `(${cpuNode.sourceLocation.rawFunctionName})`, '~', '(root)');
return;
}
const sourceNodeIndex = currentState.callIdentifier.sourceNode.getIndex();
if (sourceNodeIndex === undefined) {
throw new Error('InsertCPUProfileStateMachine.logCompensation: sourceNode has no index');
}
const createdComp = compensation.createdComp;
const carriedComp = compensation.carriedComp;
LoggerHelper_1.LoggerHelper.log(LoggerHelper_1.LoggerHelper.errorString(`[${title}]`), compensation.id.toString(), `(${cpuNode.sourceLocation.rawFunctionName})`, '~', `${sourceNodeIndex.functionName}`, `(${sourceNodeIndex.pathIndex.identifier})`, '\n' +
StateMachineLogger.formatCompensation({
'Compensation ID': compensation.id.toString(),
Depth: depth.toString(),
'CPU Node': String(cpuNode.index).padStart(3, '0'),
ReportID: currentState.callIdentifier.report.internID.toString(),
SourceNodeID: currentState.callIdentifier.sourceNode.id.toString(),
Scope: currentState.scope,
Type: currentState.type,
Headless: currentState.headless.toString(),
'Compensated CPU Time': `created=${createdComp === null || createdComp === void 0 ? void 0 : createdComp.aggregatedCPUTime} µs | carried=${carriedComp === null || carriedComp === void 0 ? void 0 : carriedComp.aggregatedCPUTime} µs`,
'Compensated CPU Energy': `created=${createdComp === null || createdComp === void 0 ? void 0 : createdComp.aggregatedCPUEnergyConsumption} mJ | carried=${carriedComp === null || carriedComp === void 0 ? void 0 : carriedComp.aggregatedCPUEnergyConsumption} mJ`,
'Compensated RAM Energy': `created=${createdComp === null || createdComp === void 0 ? void 0 : createdComp.aggregatedRAMEnergyConsumption} mJ | carried=${carriedComp === null || carriedComp === void 0 ? void 0 : carriedComp.aggregatedRAMEnergyConsumption} mJ`
}));
}
}
exports.StateMachineLogger = StateMachineLogger;
StateMachineLogger.formatReference = LoggerHelper_1.LoggerHelper.treeStyleKeyValues(['CPU Time', 'CPU Energy', 'RAM Energy'], 29);
StateMachineLogger.formatState = LoggerHelper_1.LoggerHelper.treeStyleKeyValues([
'Depth',
'CPU Node',
'ReportID',
'SourceNodeID',
'Scope',
'Type',
'Headless',
'Profiler Hits',
'CPU Time',
'CPU Energy',
'RAM Energy'
], 29);
StateMachineLogger.formatTransition = LoggerHelper_1.LoggerHelper.treeStyleKeyValues([
'CPU Node',
'Transition',
'Create Link',
'AccountingType',
'FirstTimeVisited',
'Accounted Hits',
'Accounted CPU Time',
'Accounted CPU Energy',
'Accounted RAM Energy'
], 29);
StateMachineLogger.formatCompensation = LoggerHelper_1.LoggerHelper.treeStyleKeyValues([
'Compensation ID',
'Depth',
'CPU Node',
'ReportID',
'SourceNodeID',
'Scope',
'Type',
'Headless',
'Compensated CPU Time',
'Compensated CPU Energy',
'Compensated RAM Energy'
], 29);
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU3RhdGVNYWNoaW5lTG9nZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2hlbHBlci9JbnNlcnRDUFVQcm9maWxlSGVscGVyL1N0YXRlTWFjaGluZUxvZ2dlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFJQSxrREFBOEM7QUFLOUMsTUFBYSxrQkFBa0I7SUF1QjlCLE1BQU0sQ0FBQyxRQUFRLENBQUMsS0FBYSxFQUFFLE9BQWdCLEVBQUUsWUFBbUI7O1FBQ25FOzs7Ozs7Ozs7Ozs7O1VBYUU7UUFDRixJQUFJLFlBQVksQ0FBQyxjQUFjLENBQUMsVUFBVSxLQUFLLElBQUksRUFBRSxDQUFDO1lBQ3JELDJCQUFZLENBQUMsR0FBRyxDQUFDLDJCQUFZLENBQUMsYUFBYSxDQUFDLFNBQVMsQ0FBQyxFQUFFLFFBQVEsQ0FBQyxDQUFBO1lBQ2pFLE9BQU07UUFDUCxDQUFDO1FBRUQsTUFBTSxlQUFlLEdBQUcsTUFBQSxZQUFZLENBQUMsY0FBYyxDQUFDLFVBQVUsMENBQUUsUUFBUSxFQUFFLENBQUE7UUFDMUUsSUFBSSxlQUFlLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDbkMsTUFBTSxJQUFJLEtBQUssQ0FDZCxnRUFBZ0UsQ0FDaEUsQ0FBQTtRQUNGLENBQUM7UUFFRCxNQUFNLFlBQVksR0FBRyxZQUFZLENBQUMsY0FBYyxDQUFDLFVBQVUsQ0FBQyxZQUFZLENBQUE7UUFFeEUsMkJBQVksQ0FBQyxHQUFHLENBQ2YsMkJBQVksQ0FBQyxhQUFhLENBQUMsU0FBUyxDQUFDLEVBQ3JDLEdBQUcsZUFBZSxDQUFDLFlBQVksRUFBRSxFQUNqQyxJQUFJLGVBQWUsQ0FBQyxTQUFTLENBQUMsVUFBVSxHQUFHLEVBQzNDLElBQUk7WUFDSCxrQkFBa0IsQ0FBQyxXQUFXLENBQUM7Z0JBQzlCLEtBQUssRUFBRSxLQUFLLENBQUMsUUFBUSxFQUFFO2dCQUN2QixVQUFVLEVBQUUsTUFBTSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENB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