mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-09-29 22:34:33 +00:00
65 lines
2.4 KiB
TypeScript
65 lines
2.4 KiB
TypeScript
import {stackMarkerToHumanReadable} from './formatters/stackMarkerToHumanReadable';
|
|
import {Frame} from './frame';
|
|
|
|
function createMarkerFrame(marker: JSSelfProfiling.Marker): JSSelfProfiling.Frame {
|
|
return {
|
|
name: stackMarkerToHumanReadable(marker),
|
|
resourceId: undefined,
|
|
line: undefined,
|
|
column: undefined,
|
|
};
|
|
}
|
|
/**
|
|
* Utility fn to resolve stack frames starting from the top most frame.
|
|
* Each frame points to it's parent, with the initial stackId pointer pointing to the top of the frame.
|
|
* We walk down the stack until no more frames are found, appending the parent frame to the list.
|
|
* As a result we end up with a list of frames starting from the root most frame.
|
|
*
|
|
* There is a caching opportunity here, as stackId's point to the same parts of the stack, resolving it once is sufficient
|
|
* and all subsequent calls could be cached. Some instrumentation and testing would be required, leaving as is for now.
|
|
*/
|
|
export function resolveJSSelfProfilingStack(
|
|
trace: JSSelfProfiling.Trace,
|
|
stackId: JSSelfProfiling.Sample['stackId'],
|
|
frameIndex: Record<number, Frame>,
|
|
marker?: JSSelfProfiling.Marker
|
|
): Frame[] {
|
|
// If there is no stack associated with a sample, it means the thread was idle
|
|
const callStack: Frame[] = [];
|
|
|
|
// There can only be one marker per callStack, so prepend it to the start of the stack
|
|
if (marker && marker !== 'script') {
|
|
callStack.unshift(new Frame({...createMarkerFrame(marker), key: marker}));
|
|
}
|
|
|
|
if (stackId === undefined) {
|
|
return callStack;
|
|
}
|
|
|
|
let stack: JSSelfProfiling.Stack | undefined = trace.stacks[stackId];
|
|
|
|
// If the stackId cannot be resolved from the stacks dict, it means the format is corrupt or partial (possibly due to termination reasons).
|
|
// This should never happen, but in the offchance that it somehow does, it should be handled.
|
|
if (!stack) {
|
|
throw new Error(`Missing stackId ${stackId} in trace, cannot resolve stack`);
|
|
}
|
|
|
|
while (stack !== undefined) {
|
|
// If the frameId pointer cannot be resolved, it means the format is corrupt or partial (possibly due to termination reasons).
|
|
// This should never happen, but in the offchance that it somehow does, it should be handled.
|
|
if (trace.frames[stack.frameId] === undefined) {
|
|
return callStack;
|
|
}
|
|
|
|
callStack.unshift(frameIndex[stack.frameId]);
|
|
|
|
if (stack.parentId !== undefined) {
|
|
stack = trace.stacks[stack.parentId];
|
|
} else {
|
|
stack = undefined;
|
|
}
|
|
}
|
|
|
|
return callStack;
|
|
}
|