Other approaches taken have been the more Erlang style "let it fail" methodology which is fine for newer projects but represents a rewrite for most systems in practice and is thus far, far beyond profiling discussions.
gdb -p $PID
ctrl-c bt c ctrl-c bt c crl-c bt c ...
While your code may look all nice and sane, not have any glaring performance issues - what you may not realise is that you're using a framework that does things in unexpected ways.
The devs I work with are running into the reality of this at the moment - they blame the servers/network/database/whatever as being slow/shit/etc.
I go take a look and see that network traffic is at capacity. They've got some 'magic' caching framework that promises to speed things up by storing data in Redis. What's happening in the background though is that this caching framework is doing dumb things like asking for the same key over and over again - so we've got a multi-Gbit stream of the same handful of keys being asked for thousands of times a second.
These are the sorts of things profiling can tell you just by looking at the amount of calls to Redis.
Eventually we got them online to do a screen share, and sure enough it took over a minute to render the page (it was a map). They were using an 8 year old CPU.
Switching them from IE6 to Firefox fixed the issue.
Having production quality hardware for the dev cycle is extremely valuable for these uses.
There’s been many times I’ve been bitten by this, including the one time we found that a small portion of users would set the number of results returned to the max and scroll through hundreds of pages of results, blowing the cache for everyone.
I tend to hear “we run performance tests so we don’t get regressions” a lot more than “we monitor the performance of releases to canaries and rollback”. It shouldn’t be one or the other, both are invaluable.
Yup, that sounds like me. I do exactly that whenever the pages are slow to load. Rather wait longer, once.