tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_HeapAnalyses_takeCensus_04.js (3530B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 "use strict";
      4 
      5 // Test that the HeapAnalyses{Client,Worker} can send SavedFrame stacks from
      6 // by-allocation-stack reports from the worker.
      7 
      8 add_task(async function test() {
      9  const client = new HeapAnalysesClient();
     10 
     11  // Track some allocation stacks.
     12 
     13  const g = newGlobal();
     14  const dbg = new Debugger(g);
     15  g.eval(`                                                   // 1
     16         this.log = [];                                      // 2
     17         function f() { this.log.push(allocationMarker()); } // 3
     18         function g() { this.log.push(allocationMarker()); } // 4
     19         function h() { this.log.push(allocationMarker()); } // 5
     20         `);
     21 
     22  // Create one allocationMarker with tracking turned off,
     23  // so it will have no associated stack.
     24  g.f();
     25 
     26  dbg.memory.allocationSamplingProbability = 1;
     27 
     28  for (const [func, n] of [
     29    [g.f, 20],
     30    [g.g, 10],
     31    [g.h, 5],
     32  ]) {
     33    for (let i = 0; i < n; i++) {
     34      dbg.memory.trackingAllocationSites = true;
     35      // All allocations of allocationMarker occur with this line as the oldest
     36      // stack frame.
     37      func();
     38      dbg.memory.trackingAllocationSites = false;
     39    }
     40  }
     41 
     42  // Take a heap snapshot.
     43 
     44  const snapshotFilePath = saveNewHeapSnapshot({ debugger: dbg });
     45  await client.readHeapSnapshot(snapshotFilePath);
     46  ok(true, "Should have read the heap snapshot");
     47 
     48  // Run a census broken down by class name -> allocation stack so we can grab
     49  // only the AllocationMarker objects we have complete control over.
     50 
     51  const { report } = await client.takeCensus(snapshotFilePath, {
     52    breakdown: {
     53      by: "objectClass",
     54      then: {
     55        by: "allocationStack",
     56        then: {
     57          by: "count",
     58          bytes: true,
     59          count: true,
     60        },
     61        noStack: {
     62          by: "count",
     63          bytes: true,
     64          count: true,
     65        },
     66      },
     67    },
     68  });
     69 
     70  // Test the generated report.
     71 
     72  ok(report, "Should get a report");
     73 
     74  const map = report.AllocationMarker;
     75  ok(map, "Should get AllocationMarkers in the report.");
     76  // From a module with a different global, and therefore a different Map
     77  // constructor, so we can't use instanceof.
     78  equal(Object.getPrototypeOf(map).constructor.name, "Map");
     79 
     80  equal(
     81    map.size,
     82    4,
     83    "Should have 4 allocation stacks (including the lack of a stack)"
     84  );
     85 
     86  // Gather the stacks we are expecting to appear as keys, and
     87  // check that there are no unexpected keys.
     88  const stacks = {};
     89 
     90  map.forEach((v, k) => {
     91    if (k === "noStack") {
     92      // No need to save this key.
     93    } else if (
     94      k.functionDisplayName === "f" &&
     95      k.parent.functionDisplayName === "test"
     96    ) {
     97      stacks.f = k;
     98    } else if (
     99      k.functionDisplayName === "g" &&
    100      k.parent.functionDisplayName === "test"
    101    ) {
    102      stacks.g = k;
    103    } else if (
    104      k.functionDisplayName === "h" &&
    105      k.parent.functionDisplayName === "test"
    106    ) {
    107      stacks.h = k;
    108    } else {
    109      dumpn("Unexpected allocation stack:");
    110      k.toString()
    111        .split(/\n/g)
    112        .forEach(s => dumpn(s));
    113      ok(false);
    114    }
    115  });
    116 
    117  ok(map.get("noStack"));
    118  equal(map.get("noStack").count, 1);
    119 
    120  ok(stacks.f);
    121  ok(map.get(stacks.f));
    122  equal(map.get(stacks.f).count, 20);
    123 
    124  ok(stacks.g);
    125  ok(map.get(stacks.g));
    126  equal(map.get(stacks.g).count, 10);
    127 
    128  ok(stacks.h);
    129  ok(map.get(stacks.h));
    130  equal(map.get(stacks.h).count, 5);
    131 
    132  client.destroy();
    133 });