jsSelfProfiling.tsx 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. import {stackMarkerToHumanReadable} from './formatters/stackMarkerToHumanReadable';
  2. import {Frame} from './frame';
  3. function createMarkerFrame(marker: JSSelfProfiling.Marker): JSSelfProfiling.Frame {
  4. return {
  5. name: stackMarkerToHumanReadable(marker),
  6. resourceId: undefined,
  7. line: undefined,
  8. column: undefined,
  9. };
  10. }
  11. /**
  12. * Utility fn to resolve stack frames starting from the top most frame.
  13. * Each frame points to it's parent, with the initial stackId pointer pointing to the top of the frame.
  14. * We walk down the stack until no more frames are found, appending the parent frame to the list.
  15. * As a result we end up with a list of frames starting from the root most frame.
  16. *
  17. * There is a caching opportunity here, as stackId's point to the same parts of the stack, resolving it once is sufficient
  18. * and all subsequent calls could be cached. Some instrumentation and testing would be required, leaving as is for now.
  19. */
  20. export function resolveJSSelfProfilingStack(
  21. trace: JSSelfProfiling.Trace,
  22. stackId: JSSelfProfiling.Sample['stackId'],
  23. frameIndex: Record<number, Frame>,
  24. marker?: JSSelfProfiling.Marker
  25. ): Frame[] {
  26. // If there is no stack associated with a sample, it means the thread was idle
  27. const callStack: Frame[] = [];
  28. // There can only be one marker per callStack, so prepend it to the start of the stack
  29. if (marker && marker !== 'script') {
  30. callStack.unshift(new Frame({...createMarkerFrame(marker), key: marker}));
  31. }
  32. if (stackId === undefined) {
  33. return callStack;
  34. }
  35. let stack: JSSelfProfiling.Stack | undefined = trace.stacks[stackId];
  36. // If the stackId cannot be resolved from the stacks dict, it means the format is corrupt or partial (possibly due to termination reasons).
  37. // This should never happen, but in the offchance that it somehow does, it should be handled.
  38. if (!stack) {
  39. throw new Error(`Missing stackId ${stackId} in trace, cannot resolve stack`);
  40. }
  41. while (stack !== undefined) {
  42. // If the frameId pointer cannot be resolved, it means the format is corrupt or partial (possibly due to termination reasons).
  43. // This should never happen, but in the offchance that it somehow does, it should be handled.
  44. if (trace.frames[stack.frameId] === undefined) {
  45. return callStack;
  46. }
  47. callStack.unshift(frameIndex[stack.frameId]);
  48. if (stack.parentId !== undefined) {
  49. stack = trace.stacks[stack.parentId];
  50. } else {
  51. stack = undefined;
  52. }
  53. }
  54. return callStack;
  55. }