GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — gh-135953: Add flamegraph reporter to sampling profiler by lkollar · Pull Request #138304 · python/cpython

Conversation

@lkollar

@lkollar lkollar commented Aug 31, 2025 •
edited by bedevere-app Bot
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Add --flamegraph option to the sampling profiler to produce a self-contained HTML report.

  • Issue: Expose internal stack introspection APIs as a statistical runtime analysis tool #135953

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@bedevere-app bedevere-app Bot mentioned this pull request Aug 31, 2025
Expose internal stack introspection APIs as a statistical runtime analysis tool #135953
Open
@lkollar
lkollar force-pushed the profiling/flamegraph branch from 689b05c to 0803b28 Compare August 31, 2025 19:12
AA-Turner
AA-Turner reviewed Aug 31, 2025
View reviewed changes
Comment thread Lib/profiling/sampling/flamegraph_template.html Resolved

Uh oh!

There was an error while loading. Please reload this page.

@lkollar
lkollar marked this pull request as ready for review August 31, 2025 19:46
@bedevere-app bedevere-app Bot added the awaiting review label Aug 31, 2025
@lkollar
lkollar requested review from emmatyping and erlend-aasland as code owners September 7, 2025 17:45
emmatyping
emmatyping reviewed Sep 7, 2025
View reviewed changes
Comment thread Lib/profiling/sampling/_vendor/d3-flame-graph/4.1.3/LICENSE Resolved

Uh oh!

There was an error while loading. Please reload this page.

emmatyping
emmatyping reviewed Sep 7, 2025
View reviewed changes
Comment thread Makefile.pre.in Resolved

Uh oh!

There was an error while loading. Please reload this page.

AA-Turner
AA-Turner reviewed Sep 7, 2025
View reviewed changes
Comment thread Doc/license.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Doc/license.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

@pablogsal pablogsal added the skip news label Sep 8, 2025
AA-Turner
AA-Turner reviewed Sep 9, 2025
View reviewed changes

@AA-Turner AA-Turner left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Brief review of the JS code. Please disregard any feedback that is irrelevant due to use of the D3 framework -- I am primarily used to working with vanilla/framework-less JS.

On formatting, obviously PEP 8 doesn't apply as it's not Python code, but it would still be good to keep to the spirit of it, and wrap at 79 characters or thereabouts for readability.

I've had advice/reviews in the past that from a security perspective it's best to avoid constructing HTML in JS directly and instead use e.g. document.createElement(). I don't know enough about the D3/JS interactions to know if this applies here, though. There was one place that looked like it was performing HTML escaping in JavaScript, which seems like something we might consider doing in the Python layer before the data gets to JS?

A

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/profiling/sampling/_assets/python-logo-only.png

@AA-Turner AA-Turner Sep 9, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potentially use the SVG instead? https://github.com/python/devguide/blob/main/_static/python-logo.svg?short_path=f69d24a

The SVG is ~18x smaller, but it hasn't been minified.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/profiling/sampling/_vendor/d3-flame-graph/4.1.3/d3-flamegraph-tooltip.min.js

@AA-Turner AA-Turner Sep 9, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps add .min.js to the list of generated files in .gitattributes?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/profiling/sampling/flamegraph.js
Comment on lines +19 to +46
.style("position", "absolute")
.style("padding", "20px")
.style("background", "white")
.style("color", "#2e3338")
.style("border-radius", "8px")
.style("font-size", "14px")
.style("border", "1px solid #e9ecef")
.style("box-shadow", "0 8px 30px rgba(0, 0, 0, 0.15)")
.style("z-index", "1000")
.style("pointer-events", "none")
.style("font-weight", "400")
.style("line-height", "1.5")
.style("max-width", "500px")
.style("font-family", "'Source Sans Pro', sans-serif")
.style("opacity", 0);

@AA-Turner AA-Turner Sep 9, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to apply these styles via a class, instead of inline?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/profiling/sampling/flamegraph.js Outdated
}

const pythonTooltip = flamegraph.tooltip.defaultFlamegraphTooltip();

@AA-Turner AA-Turner Sep 9, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/profiling/sampling/flamegraph.js Outdated
const sourceLines = source
.map(
(line) =>
`<div style="font-family: 'SF Mono', 'Monaco', 'Consolas', monospace; font-size: 12px; color: ${line.startsWith("→") ? "#3776ab" : "#5a6c7d"}; white-space: pre; line-height: 1.4; padding: 2px 0;">${line.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")}</div>`,

@AA-Turner AA-Turner Sep 9, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise, is it possible to use a class instead of inline styles?

Should we escape the HTML (line.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")) whilst we're still in Python?

For the color codes, could we use CSS variables so that if we change them in the future, we only need to change it in one place?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/profiling/sampling/flamegraph.js Outdated
Comment on lines +87 to +94
${
calls > 0
? `
<span style="color: #5a6c7d; font-weight: 500;">Function Calls:</span>
<strong style="color: #2e3338;">${calls.toLocaleString()}</strong>
`
: ""
}

@AA-Turner AA-Turner Sep 9, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps extract to local variables instead of nested substitutions?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/profiling/sampling/flamegraph.js Outdated
}

// Wait for libraries to load
document.addEventListener("DOMContentLoaded", function () {

@AA-Turner AA-Turner Sep 9, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding is that DOMContentLoaded may fire before the script loads, so the suggested pattern is to check for document.readyState. I don't know if this applies here or not, though.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/profiling/sampling/flamegraph.js Outdated
Comment on lines +240 to +241
// Add search functionality - wait for chart to be ready
if (searchInput) {

@AA-Turner AA-Turner Sep 9, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this block be extracted to a helper function?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/profiling/sampling/stack_collector.py Outdated
def _create_flamegraph_html(self, data):
data_json = json.dumps(data)

template_dir = pathlib.Path(__file__).parent

@AA-Turner AA-Turner Sep 9, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we use importlib.resources here? I believe e.g. for the Windows embedable builds, the stdlib is distributed as a zip file so modules might not have a __file__ attribute.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/test/test_profiling/test_sampling_profiler.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@pablogsal

pablogsal commented Sep 9, 2025

Copy link
Copy Markdown
Member

I've had advice/reviews in the past that from a security perspective it's best to avoid constructing HTML in JS directly and instead use e.g. document.createElement(). I don't know enough about the D3/JS interactions to know if this applies here, though. There was one place that looked like it was performing HTML escaping in JavaScript, which seems like something we might consider doing in the Python layer before the data gets to JS?

Since this is a static template there are no advantages of doing this and having the web parts in Python is a bit messy specially since we cannot use something like Jinja. Having all the web parts in JS or the template itself is a common practice for this case and keeps the Python code focused just on the data part and not in creating HTML. Also since this is just a static file served with no dependencies so there are no concerns aboutsecurity or injection so I prefer to maximize maintainability.

I will give it a pass with prettier to format it as you indicate :)

AA-Turner reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@lkollar

lkollar commented Sep 9, 2025

Copy link
Copy Markdown
Contributor Author

Thanks for the review @AA-Turner. I think I addressed everything except for the comments around constructing HTML in JS. I also ended up breaking up the JS functions a bit in 7c4d792 as it was getting really unwieldy and I think this will make maintenance easier.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@lkollar
lkollar requested review from AlexWaygood, FFY00, JelleZijlstra, ambv, barneygale, berkerpeksag, ethanfurman, giampaolo, gpshead, jaraco, lysnikolaou, rhettinger, terryjreedy, tomasr8, vsajip and warsaw as code owners September 9, 2025 20:48
lkollar and others added 11 commits September 9, 2025 21:50
@lkollar @AA-Turner
Update license.rst
3799731
Co-authored-by: Adam Turner <[email protected]>
@pablogsal @lkollar
fixup! Update license.rst
4f10915
@pablogsal @lkollar
fixup! fixup! Update license.rst
fb48a88
@pablogsal @lkollar
fixup! fixup! fixup! Update license.rst
8882b27
@lkollar @AA-Turner
Update Lib/test/test_profiling/test_sampling_profiler.py
738bd0a
Co-authored-by: Adam Turner <[email protected]>
@lkollar
Shorten lines in flamegraph.js
4e63501
@lkollar
Watch for readystate before initialising flamegraph UI
eef995d
@lkollar
Add .min.js to .gitattributes
97474d6
@lkollar
Break up large functions in flamegraph.js
8291df0
@lkollar
Use importlib.resources to locate flamegraph assets
a780144
@lkollar
fixup! Update Lib/test/test_profiling/test_sampling_profiler.py
9d3956d
@lkollar
lkollar force-pushed the profiling/flamegraph branch from ff7c603 to 9d3956d Compare September 9, 2025 20:50
@pablogsal
pablogsal removed request for AlexWaygood, FFY00, JelleZijlstra, berkerpeksag, erlend-aasland, ethanfurman, giampaolo, gpshead, lysnikolaou, rhettinger and vsajip September 9, 2025 20:53
@lkollar

lkollar commented Sep 9, 2025

Copy link
Copy Markdown
Contributor Author

Apologies, I messed up the rebase. I'll open a new PR to keep a clean slate.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@lkollar lkollar closed this Sep 9, 2025
@pablogsal
pablogsal removed request for ambv, barneygale, jaraco, terryjreedy and warsaw September 9, 2025 20:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@AA-Turner AA-Turner AA-Turner left review comments
@emmatyping emmatyping emmatyping left review comments
@pablogsal pablogsal pablogsal left review comments

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

awaiting review skip news

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

4 participants

@lkollar @pablogsal @AA-Turner @emmatyping
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.