Author here, kinda sorta. I should've been a bit more specific than that.
You can have a profile showing a function taking up 99% of the time, but when you dive into it, there's no clear bottleneck. But just because there's no bottleneck, that doesn't mean it's optimized; vice versa-a well-optimized program can have a bottleneck that's already been cycle-squeezed to hell and back.
What I wanted to say was that a spiky profile provides a clear path to optimizing a piece of code, whereas a flat profile usually means there are more fundamental issues (inefficient memory management, pointer chasing all over the place, convoluted object system, etc.).
It sounds like a flat profile essentially is a local optimum, compared to cases where there's a path "upwards" along a hill to some place more optimal that doesn't require completely changing your strategy.
I've seen a few of these in my career, if I understand the author correctly. You have a big ball of mud that can theoretically be 10x or 100x faster, but the costs are diffuse and can't be solved by just finding a hotspot and optimizing it.
It often happens for good reasons. Features get added over time, there are some scars from a mocking framework, simpler (faster) solutions don't quite work because they're supporting X which supports Y which supports Z (dead code, but nobody noticed), people use full datetime handling when they mean to access performance counters, the complexity of the thing means that you blow your branch prediction cache size budget, etc....
The solution is to deeply understand the problem (lots of techniques, but this comment isn't a blog post) and come up with a solution, like a ground-up rewrite of some or all of the offending section.
bofersen|3 months ago
What I wanted to say was that a spiky profile provides a clear path to optimizing a piece of code, whereas a flat profile usually means there are more fundamental issues (inefficient memory management, pointer chasing all over the place, convoluted object system, etc.).
saghm|3 months ago
hansvm|3 months ago
It often happens for good reasons. Features get added over time, there are some scars from a mocking framework, simpler (faster) solutions don't quite work because they're supporting X which supports Y which supports Z (dead code, but nobody noticed), people use full datetime handling when they mean to access performance counters, the complexity of the thing means that you blow your branch prediction cache size budget, etc....
The solution is to deeply understand the problem (lots of techniques, but this comment isn't a blog post) and come up with a solution, like a ground-up rewrite of some or all of the offending section.
Narishma|3 months ago
lmm|3 months ago