Profiling Go Applications with Flamegraphs
brendanjryan.com
brendanjryan.com
- Linux perf can profile unmodified Go programs. This is handy when your application doesn't expose the /debug/pprof endpoint. (http://brendangregg.com/FlameGraphs/cpuflamegraphs.html#perf has detailed instructions)
- Recent versions of https://github.com/google/pprof include a flamegraph viewer in the web UI. This is handy when you want a line-level flamegraph instead of a function-level flamegraph.
func (sc *SimpleClient) Timing(s string, d time.Duration, sampleRate float64,
tags map[string]string) error {
return sc.send([...]
The wrapped parameter list is indented to the same level as the function body. Is this how it's supposed to be done?Another thing that is omitted is what type of buffer was used. I'm assuming it was a `[]string` slice but why not use a `sync.Pool`?
[1] https://github.com/golang/go/wiki/CodeReviewComments#variabl...
Small variable names for iteration variables and the `this` equivalent in struct methods are fine.
As for other situations... I guess it's an art?
I don't think that assigning terse names (such as the variable "ra" from the OP) to variables that might be declared anywhere in a function is helpful.
I think the problem comes when people take that advice without nuance and think it gives them carte blanche to make everything as obscure as possible.
And really, it’s not about whether or not we can understand our own code, but can the future developers who have to maintain it after we leave.
I kinda worry that the Go community is creating a lot of unmaintainable code right now.
I work on Java code where variables name look like 'reconnectDelayToInitiallyEstablishJMSConnection" Even though very clear name it really exhaust me while reading code like this. Java explicitness things like spreading code over dozens of files and directories for a functionality that could ideally be in 1-2 reasonably sized files. And methods that actually do something instead of calling another methods. So I guess code I deal with is understandable at a method level which finally does something. But overall it is too sprawling to fit everything in mind while looking at a functionality.
rd := 1000
How is anyone supposed to understand at a glance what this value is for? Why not just:
reconnectionDelay := 1000
Intent is clear.
And now, I have strayed way too far off topic (I’ve done some flamegraph style debugging in .Net, super useful!), and should probably apologize to the OP.
Some natural limits might be: (1) single letters for extremely local terms whose structural meaning is more salient than denotation (canonical example: loop counter); (2) fully spelled-out terms for globally-significant terms (not necessarily in global scope) whose denotation is crucial (canonical example: an app configuration value).
Even two short camel-cased words often seem unnecessarily verbose for a loop counter to me. Whereas an important global config variable might justify the full THIS_IS_WHAT_I_AM_FOR treatment.
This is survivable, if they're motivated to fix the glaring omissions in Go.
n = copy(p, b.buf[b.r:b.w])
Oh better go to the top and see what those are again...
https://github.com/golang/go/blob/master/src/bufio/bufio.go#...
Once I know what they all are, I find it's easier for me to track them through the function if they have short names.
Something java style like
numBytesWritten = copy(destinationBuffer, reader.buffer[reader.readPosition:reader.writePosition]
is much harder for me to follow.Maybe it's a cultural thing - lots of C code looks like this from Lion's UNIX book onwards. I still find this style easier on the eyes when it's clear from context what is going on.
For i/o code this is about as obscure as using "i" for a loop index.
There's no reason to use any more than a single character for a loop variable. Who cares how old the convention is?
As for short variable names -- I think they're a readability boon where they are essentially placeholders into common structures that you can read as a whole unit at a glance (counters in loops, readers/writers/buffers in input/output idioms etc), but detrimental elsewhere.
[1] http://www.vi-hps.org/upload/material/tw-score-p/vi-hps-tw-s... [2] http://www.vi-hps.org/upload/material/tw-score-p/vi-hps-tw-s...
But do they help to debug issues related to CPU spikes? I have my reservations because they are generated using sampling, and flamegraphs won't give a clear insight into who is causing the spikes.
And then "diff" them to get stack causing spikes.
Is this the correct way?
In general, how do people solve CPU spikes issue?
Personally I want something like this for py.
In searching for the vid I see netflix also have a medium post(2014)[1] about it.
[0]: https://www.youtube.com/watch?v=O1YP8QP9gLA
[1]: https://medium.com/netflix-techblog/node-js-in-flames-ddd073...