Skip to content

Commit

Permalink
Add Deep JS stacks example
Browse files Browse the repository at this point in the history
  • Loading branch information
paulirish committed Jan 7, 2025
1 parent 43093b2 commit fde7582
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 0 deletions.
8 changes: 8 additions & 0 deletions deep-js-stacks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# deep-js-stacks

This test case exists to show what happens to JS callstacks at around 256 frames tall.

The known bug: the v8 sampling profiler only emits the "top-most" 256 callframes on the stack. (Visually in the flamechart it's the bottom-most).

<img width="1224" alt="top of flamechart" src="https://github.com/user-attachments/assets/fee1615d-1d78-4e11-be5d-c3fd39e6348f" />
<img width="1090" alt="bottom of flamechart" src="https://github.com/user-attachments/assets/f606a1a8-caa9-4af4-9036-74314308d2b1" />
44 changes: 44 additions & 0 deletions deep-js-stacks/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// The problem manifests at a stack depth of 256, but startDemo and onclick count as well.
const lowBound = 248;
const highBound = 256;

const output = document.getElementById('output');
let currentMaxDepth = 0;

function stall() {
const start = Date.now();
while (Date.now() - start < 0.5) {}
}

function startDemo() {
const start = performance.now();

for (let maxDepth = lowBound; maxDepth <= highBound; maxDepth++) {
currentMaxDepth = maxDepth;
call0();
}
for (let maxDepth = highBound; maxDepth >= lowBound; maxDepth--) {
currentMaxDepth = maxDepth;
call0();
}

const measure = performance.measure(`stack-calling ${lowBound}-${highBound}`, {start, end: performance.now()});

output.textContent += `Total execution time: ${measure.duration.toFixed(2)}ms\n`;
}

// Generate all the call functions
for (let i = highBound; i >= 0; i--) {
let fnBody = `if (${i} > currentMaxDepth) return;
if (${i} === currentMaxDepth) stall();
else call${i + 1}();`;

fnBody += `//# sourceURL=call${i}.js \n`; // Just added for coloring.

window[`call${i}`] = new Function('return function call' + i + '() {' + fnBody + '}')();
}

startDemo();
document.querySelector('button').addEventListener('click', function onclick() {
startDemo();
});
11 changes: 11 additions & 0 deletions deep-js-stacks/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<title>Generate icicles ~256 entries high</title>
</head>
<body>
<button>Start Demo</button>
<pre id="output"></pre>
<script src="app.js"></script>
</body>
</html>

0 comments on commit fde7582

Please sign in to comment.