Skip to content

Commit ee68f5f

Browse files
authored
gh-154059: Fix Tachyon flame graph time units (#154036)
1 parent 3444ef9 commit ee68f5f

4 files changed

Lines changed: 19 additions & 10 deletions

File tree

Lib/profiling/sampling/_flamegraph_assets/flamegraph.js

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ function getDisplayName(moduleName, filename) {
9999
return filename;
100100
}
101101

102+
function samplesToMilliseconds(samples, data) {
103+
return (samples * data.stats.sample_interval_usec / 1000).toFixed(2);
104+
}
105+
102106
function selectFlamegraphData(selectedThreadId = null) {
103107
let baseData = isShowingElided ? elidedFlamegraphData : normalData;
104108

@@ -255,12 +259,12 @@ function setupLogos() {
255259
// Status Bar
256260
// ============================================================================
257261

258-
function updateStatusBar(nodeData, rootValue) {
262+
function updateStatusBar(nodeData, rootValue, data) {
259263
const funcname = resolveString(nodeData.funcname) || resolveString(nodeData.name) || "--";
260264
const filename = resolveString(nodeData.filename) || "";
261265
const moduleName = resolveString(nodeData.module) || "";
262266
const lineno = nodeData.lineno;
263-
const timeMs = (nodeData.value / 1000).toFixed(2);
267+
const timeMs = samplesToMilliseconds(nodeData.value, data);
264268
const percent = rootValue > 0 ? ((nodeData.value / rootValue) * 100).toFixed(1) : "0.0";
265269

266270
const brandEl = document.getElementById('status-brand');
@@ -322,9 +326,9 @@ function createPythonTooltip(data) {
322326
.style("opacity", 0);
323327
}
324328

325-
const timeMs = (d.data.value / 1000).toFixed(2);
329+
const timeMs = samplesToMilliseconds(d.data.value, data);
326330
const selfSamples = d.data.self || 0;
327-
const selfMs = (selfSamples / 1000).toFixed(2);
331+
const selfMs = samplesToMilliseconds(selfSamples, data);
328332
const percentage = ((d.data.value / data.value) * 100).toFixed(2);
329333
const relativePercentage = Math.min(100, ((d.data.value / (zoomedNodeValue ?? data.value)) * 100)).toFixed(2);
330334
const calls = d.data.calls || 0;
@@ -408,9 +412,9 @@ function createPythonTooltip(data) {
408412
// Differential stats section
409413
let diffSection = "";
410414
if (d.data.diff !== undefined && d.data.baseline !== undefined) {
411-
const baselineSelf = (d.data.baseline / 1000).toFixed(2);
412-
const currentSelf = ((d.data.self_time || 0) / 1000).toFixed(2);
413-
const diffMs = (d.data.diff / 1000).toFixed(2);
415+
const baselineSelf = samplesToMilliseconds(d.data.baseline, data);
416+
const currentSelf = samplesToMilliseconds(d.data.self_time || 0, data);
417+
const diffMs = samplesToMilliseconds(d.data.diff, data);
414418
const diffPct = d.data.diff_pct;
415419
const sign = d.data.diff >= 0 ? "+" : "";
416420
const diffClass = d.data.diff > 0 ? "regression" : (d.data.diff < 0 ? "improvement" : "neutral");
@@ -508,7 +512,7 @@ function createPythonTooltip(data) {
508512
.style("opacity", 1);
509513

510514
// Update status bar
511-
updateStatusBar(d.data, data.value);
515+
updateStatusBar(d.data, data.value, data);
512516
};
513517

514518
pythonTooltip.hide = function () {

Lib/profiling/sampling/stack_collector.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def export(self, filename):
7070
class FlamegraphCollector(StackTraceCollector):
7171
def __init__(self, *args, **kwargs):
7272
super().__init__(*args, **kwargs)
73-
self.stats = {}
73+
self.stats = {"sample_interval_usec": self.sample_interval_usec}
7474
self._root = {
7575
"samples": 0,
7676
"children": {},

Lib/test/test_profiling/test_sampling_profiler/test_collectors.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,7 @@ def test_flamegraph_collector_basic(self):
505505
self.assertIn("func1 (file.py:10)", resolve_name(child, strings))
506506
self.assertEqual(child["value"], 1)
507507
self.assertEqual(child["self"], 1) # leaf: all time is self
508+
self.assertEqual(data["stats"]["sample_interval_usec"], 1000)
508509

509510
def test_flamegraph_collector_export(self):
510511
"""Test flamegraph HTML export functionality."""
@@ -513,7 +514,7 @@ def test_flamegraph_collector_export(self):
513514
)
514515
self.addCleanup(close_and_unlink, flamegraph_out)
515516

516-
collector = FlamegraphCollector(1000)
517+
collector = FlamegraphCollector(10000)
517518

518519
# Create some test data (use Interpreter/Thread objects like runtime)
519520
test_frames1 = [
@@ -569,6 +570,8 @@ def test_flamegraph_collector_export(self):
569570
self.assertIn('"name":', content)
570571
self.assertIn('"value":', content)
571572
self.assertIn('"children":', content)
573+
self.assertIn('"sample_interval_usec": 10000', content)
574+
self.assertIn("samples * data.stats.sample_interval_usec / 1000", content)
572575

573576
def test_flamegraph_collector_empty_export_fails(self):
574577
"""Test empty flamegraph export reports no output."""
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix the time units in Tachyon flame graph tooltips by accounting for the
2+
sampling interval when converting samples to milliseconds.

0 commit comments

Comments
 (0)