From d58bad93fcfc351ad496c397dec7b55584983786 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Fri, 22 May 2026 11:17:21 -0700 Subject: [PATCH 1/6] gh-150258: Show relative percentage on Tachyon flamegraph When running profiling, users rarely care about the global percentage of the runtime. Often, they want to select a function and measure child percentages relative to that. This PR updates the flamegraph tooltips to show both "Percentage" and "Relative Percentage" when the user clicks a specific function. Fixes #150258 --- .../sampling/_flamegraph_assets/flamegraph.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js b/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js index 1611bf754424c13..2e6dea8d59e91fb 100644 --- a/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js +++ b/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js @@ -7,6 +7,7 @@ let invertedData = null; let currentThreadFilter = 'all'; let isInverted = false; let useModuleNames = true; +let zoomedNodeValue = null; // Heat colors are now defined in CSS variables (--heat-1 through --heat-8) // and automatically switch with theme changes - no JS color arrays needed! @@ -316,6 +317,7 @@ function createPythonTooltip(data) { const selfSamples = d.data.self || 0; const selfMs = (selfSamples / 1000).toFixed(2); const percentage = ((d.data.value / data.value) * 100).toFixed(2); + const relativePercentage = Math.max(100, ((d.data.value / (zoomedNodeValue ?? data.value)) * 100)).toFixed(2); const calls = d.data.calls || 0; const childCount = d.children ? d.children.length : 0; const source = d.data.source; @@ -439,6 +441,11 @@ function createPythonTooltip(data) { Percentage: ${percentage}% + ${relativePercentage !== percentage && relativePercentage !== "100.00" ? ` + % of Selection: + ${relativePercentage}% + ` : ''} + ${calls > 0 ? ` Function Calls: ${calls.toLocaleString()} @@ -620,6 +627,9 @@ function createFlamegraph(tooltip, rootValue, data) { const percentage = d.data.value / rootValue; const level = getHeatLevel(percentage); return heatColors[level]; + }) + .onClick(function (d) { + zoomedNodeValue = d.data.value; }); return chart; @@ -1269,6 +1279,7 @@ function filterDataByThread(data, threadId) { function resetZoom() { if (window.flamegraphChart) { + zoomedNodeValue = null; window.flamegraphChart.resetZoom(); } } From 8389410e82ecf1baca430b6ec262a8ac0dd42632 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Fri, 22 May 2026 18:51:11 +0000 Subject: [PATCH 2/6] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Tools-Demos/2026-05-22-18-51-09.gh-issue-150258.dh8GVK.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Tools-Demos/2026-05-22-18-51-09.gh-issue-150258.dh8GVK.rst diff --git a/Misc/NEWS.d/next/Tools-Demos/2026-05-22-18-51-09.gh-issue-150258.dh8GVK.rst b/Misc/NEWS.d/next/Tools-Demos/2026-05-22-18-51-09.gh-issue-150258.dh8GVK.rst new file mode 100644 index 000000000000000..02cad6c4f53d928 --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2026-05-22-18-51-09.gh-issue-150258.dh8GVK.rst @@ -0,0 +1 @@ +Update the tooltip on the Tachyon flame graph to show both absolute and relative percentages. From 9c9477a905abe25ff3ce6941397f5e1f843fad96 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Fri, 22 May 2026 11:52:11 -0700 Subject: [PATCH 3/6] Fix strings and calculation --- Lib/profiling/sampling/_flamegraph_assets/flamegraph.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js b/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js index 2e6dea8d59e91fb..0d1023a9060177e 100644 --- a/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js +++ b/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js @@ -317,7 +317,8 @@ function createPythonTooltip(data) { const selfSamples = d.data.self || 0; const selfMs = (selfSamples / 1000).toFixed(2); const percentage = ((d.data.value / data.value) * 100).toFixed(2); - const relativePercentage = Math.max(100, ((d.data.value / (zoomedNodeValue ?? data.value)) * 100)).toFixed(2); + const relativePercentage = zoomedNodeValue && zoomedNodeValue !== data.value ? + (d.data.value / zoomedNodeValue * 100).toFixed(2) : undefined; const calls = d.data.calls || 0; const childCount = d.children ? d.children.length : 0; const source = d.data.source; @@ -441,8 +442,8 @@ function createPythonTooltip(data) { Percentage: ${percentage}% - ${relativePercentage !== percentage && relativePercentage !== "100.00" ? ` - % of Selection: + ${relativePercentage ? ` + Relative Percentage: ${relativePercentage}% ` : ''} From 0cd3c2da6265f4888039068c32a1da58bb9c34b5 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Fri, 22 May 2026 12:04:40 -0700 Subject: [PATCH 4/6] Reset zoomedNodeValue when re-rendering flamegraph --- Lib/profiling/sampling/_flamegraph_assets/flamegraph.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js b/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js index 0d1023a9060177e..c205c846e16e323 100644 --- a/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js +++ b/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js @@ -640,6 +640,7 @@ function renderFlamegraph(chart, data) { d3.select("#chart").datum(data).call(chart); window.flamegraphChart = chart; window.flamegraphData = data; + zoomedNodeValue = null; populateStats(data); } From a4b12296685aad8499a39754ed8b3523563100fe Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Fri, 22 May 2026 12:14:41 -0700 Subject: [PATCH 5/6] Update relativePercentage logic --- Lib/profiling/sampling/_flamegraph_assets/flamegraph.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js b/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js index c205c846e16e323..ad645d921c795b1 100644 --- a/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js +++ b/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js @@ -317,8 +317,7 @@ function createPythonTooltip(data) { const selfSamples = d.data.self || 0; const selfMs = (selfSamples / 1000).toFixed(2); const percentage = ((d.data.value / data.value) * 100).toFixed(2); - const relativePercentage = zoomedNodeValue && zoomedNodeValue !== data.value ? - (d.data.value / zoomedNodeValue * 100).toFixed(2) : undefined; + const relativePercentage = Math.min(100, ((d.data.value / (zoomedNodeValue ?? data.value)) * 100).toFixed(2)); const calls = d.data.calls || 0; const childCount = d.children ? d.children.length : 0; const source = d.data.source; @@ -442,7 +441,7 @@ function createPythonTooltip(data) { Percentage: ${percentage}% - ${relativePercentage ? ` + ${relativePercentage != percentage && relativePercentage != "100.00" ? ` Relative Percentage: ${relativePercentage}% ` : ''} From 5c9baa10c5e0ba52014178105fb9b16d4237cccc Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Fri, 22 May 2026 12:19:28 -0700 Subject: [PATCH 6/6] Fix bad typing --- Lib/profiling/sampling/_flamegraph_assets/flamegraph.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js b/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js index ad645d921c795b1..840acf2c27d1201 100644 --- a/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js +++ b/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js @@ -317,7 +317,7 @@ function createPythonTooltip(data) { const selfSamples = d.data.self || 0; const selfMs = (selfSamples / 1000).toFixed(2); const percentage = ((d.data.value / data.value) * 100).toFixed(2); - const relativePercentage = Math.min(100, ((d.data.value / (zoomedNodeValue ?? data.value)) * 100).toFixed(2)); + const relativePercentage = Math.min(100, ((d.data.value / (zoomedNodeValue ?? data.value)) * 100)).toFixed(2); const calls = d.data.calls || 0; const childCount = d.children ? d.children.length : 0; const source = d.data.source;