Flamegraphs are wonderful.

Me: looks at my code. "sure, ok, looks alright."

Me: looks at the resulting flamegraph. "what the hell is this?!?!?"

I've found all kinds of crazy stuff in codebases this way. Static initializers that aren't static, one-line logger calls that trigger expensive serialization, heavy string-parsing calls that don't memoize patterns, etc. Unfortunately some of those are my fault.

I also like icicle graphs for this. They're flamegraphs, but aggregated in the reverse order. (I.e. if you have calls A->B->C and D->E->C, then both calls to C are aggregated together, rather than being stacked on top of B and E respectively. It can make it easier to see what's wrong when you have a bunch of distinct codepaths that all invoke a common library where you're spending too much time.)

Regular flamegraphs are good too, icicle graphs are just another tool in the toolbox.

So someone else linked the original flamegraph site [0] and it describes icicle graphs as "inverting the y axis" but that's not only what's happening, right? You bucket top-down the stack opposed to bottom-up, correct?

[0] https://www.brendangregg.com/flamegraphs.html

It's certainly possible that what I encountered, labeled as an 'icicle graph', is a nonstandard usage of the term. But if so, that's a shame. I don't think inverting the y-axis is useful by itself, the different bucketing is what makes for an actually useful change.

Right, what is needed is something trie-like, with the root being the most fine-grained call.

Also cool that when you open it in a new tab, the svg [0] is interactive! You can zoom in by clicking on sections, and there's a button to reset the zoom level.

[0]: https://questdb.com/images/blog/2026-01-13/before.svg

Yes, they are made with: http://www.brendangregg.com/flamegraphs.html and

https://github.com/brendangregg/FlameGraph

Useful site if you are on to perf/eBPF/performance things with many examples and descriptions even for other uses as e.g. memory usage, disk usage (prefer heatmaps here but they are nice if you want to send someone a interactive view of their directory tree ...).

I always found profiling performance critical code and experimenting with optimisations to be one of the most enjoyable parts of development - probably because of the number of surprises that I encountered ("Why on Earth is that so slow?").

I might be very wrong in every way but, string parsing and or manipulating and memoiziation... sound like a super strange combo? For the first you know you're already doing expensive allocations, but the 2nd is also not a pattern I really see apart from in JS codebases. Could you provide more context on how this actually bit you in the behind? memoizing strings seems like a complicated and error prone "welp it feels better now" territory in my mind so I'm genuinely curious.

In Java it can be a bad toString() implementation hiding behind a + used for string assembly.

Or another great one: new instances of ObjectMapper created inside a method for a single call and then thrown away.

To be clear this is often sloppy code that shouldn’t have been written. But in a legacy codebase this stuff can easily happen.

A huge chunk of a "legacy codebase" is "sloppy code that shouldn’t have been written"

Unless you're inheriting code written by Bill Atkinson or something.

> but the 2nd is also not a pattern I really see apart from in JS codebases.

If you're referring to "one-line logger calls that trigger expensive serialization", it's also common in java.

I've never used flamegraphs but would like to know about them. Can you explain more? Or where should I start?

Flame graphs have an official web site, maintained by Brendan Gregg, who invented them: https://www.brendangregg.com/flamegraphs.html. It's a useful starting point.

I would also try hotspot, it is a interactive viewer for perf graphs.

I use them all the time on Perl code.

https://metacpan.org/pod/Devel::NYTProf