github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/packages/pyroscope-flamegraph/src/convert/flamebearersToTree.ts (about)

     1  import type { Profile } from '@pyroscope/models/src';
     2  
     3  export interface TreeNode {
     4    name: string;
     5    key: string;
     6    self: number[];
     7    total: number[];
     8    offset?: number;
     9    children: TreeNode[];
    10  }
    11  
    12  export function flamebearersToTree(
    13    f1: Profile['flamebearer'],
    14    f2?: Profile['flamebearer']
    15  ): TreeNode {
    16    const globalLookup: { [key: string]: TreeNode } = {};
    17    const treeSpecificLookup: { [key: string]: TreeNode } = {};
    18    let root: TreeNode = {
    19      name: 'total',
    20      children: [],
    21      self: [],
    22      total: [],
    23      key: '/total',
    24    };
    25  
    26    (f2 ? [f1, f2] : [f1]).forEach((f, fi) => {
    27      for (let i = 0; i < f.levels.length; i += 1) {
    28        for (let j = 0; j < f.levels[i].length; j += 4) {
    29          const treeSpecificKey: string = [fi, i, j].join('/');
    30          const name: string = f.names[f.levels[i][j + 3]];
    31          const offset: number = f.levels[i][j + 0];
    32          const total: number = f.levels[i][j + 1];
    33          const self: number = f.levels[i][j + 2];
    34          let parentGlobalKey = '';
    35          // searching for parent node
    36          if (i !== 0) {
    37            const pi = i - 1;
    38            const parentLevel = f.levels[pi];
    39            for (let k = 0; k < parentLevel.length; k += 4) {
    40              const parentOffset = parentLevel[k + 0];
    41              const total = parentLevel[k + 1];
    42              if (offset >= parentOffset && offset < parentOffset + total) {
    43                const parentTreeSpecificKey = [fi, pi, k].join('/');
    44                const parentObj = treeSpecificLookup[parentTreeSpecificKey];
    45                parentGlobalKey = parentObj.key;
    46                break;
    47              }
    48            }
    49          }
    50  
    51          const globalKey = [parentGlobalKey || '', name].join('/');
    52          const isNewObject = !globalLookup[globalKey];
    53          globalLookup[globalKey] ||= {
    54            name,
    55            children: [],
    56            self: [],
    57            total: [],
    58            key: globalKey,
    59          } as TreeNode;
    60          const obj: TreeNode = globalLookup[globalKey];
    61          obj.total[fi] ||= 0;
    62          obj.total[fi] += total;
    63          obj.self[fi] ||= 0;
    64          obj.self[fi] += self;
    65          treeSpecificLookup[treeSpecificKey] = obj;
    66  
    67          if (parentGlobalKey && isNewObject) {
    68            globalLookup[parentGlobalKey].children.push(obj);
    69          }
    70          if (i === 0) {
    71            root = obj;
    72          }
    73        }
    74      }
    75    });
    76  
    77    return root;
    78  }