-
Notifications
You must be signed in to change notification settings - Fork 38.7k
Add documentation about generating flame graphs. #12649
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Concept ACK 🔥, just some notes:
|
Sjors
left a comment
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.
Concept ACK, but having trouble getting this to work on macOS. That could be "fixed" with a note saying this doesn't work on macOS, but it would be nice if it did work.
greadelf returns:
Not an ELF file - it has the wrong magic bytes at the start
file src/bitcoind
src/bitcoind: Mach-O 64-bit executable x86_64
doc/flamegraphs.md
Outdated
| graph. You can learn more about flame graphs | ||
| [here](http://www.brendangregg.com/flamegraphs.html). | ||
|
|
||
| Example flame graph (click to zoom): |
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.
When I preview this page on Github, clicking on the image takes me to the image page, rather than zoom. An animated gif might be a better way to illustrate the behavior.
| # Install perf on Fedora. | ||
| sudo dnf install perf | ||
| ``` | ||
|
|
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.
# Install on macOS
brew install google-perftoolsThere 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.
This is a totally different project.
| ### Generating Flame Graphs On Linux Using Perf | ||
|
|
||
| To generate flame graphs with labeled function names you'll need a build of | ||
| Bitcoin that has debugging symbols enabled (this should be the case by default). |
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.
Are you sure? ./configure --enable-debug is off by default.
|
|
||
| ```bash | ||
| # If this produces output your binary has debugging symbols. | ||
| $ readelf -S src/bitcoind | grep .debug_str |
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.
For OSX, use greadelf instead of readelf, which can be installed using brew install binutils
doc/flamegraphs.md
Outdated
|
|
||
| ```bash | ||
| # Optional, enable kernel annotations | ||
| sudo sysctl kernel.perf_event_paranoid=-1 |
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.
On macOS this complains with:
sysctl: unknown oid 'kernel.perf_event_paranoid'
doc/flamegraphs.md
Outdated
|
|
||
| ```bash | ||
| # Profile bitcoind for 60 seconds | ||
| perf record -g --call-graph dwarf -F 101 -p $(pidof bitcoind) -- sleep 60 |
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.
pidof on macOS can be installed with brew install pidof. perf is gperf on macOS, although it doesn't recognize --call-graph.
|
Changes in my latest commit:
The other change is to link to a copy of the SVG file I am hosting on |
|
I opened this PR on bitcoincore.org to see if I can get the SVG file hosted here. |
|
Thanks for adding documentation on this! What about adding this to the maintainer tools or docs repository? This not bound to bitcoin core's release cycle, after all. |
|
|
||
| ```bash | ||
| # Install perf on Debian. | ||
| sudo apt-get install linux-perf |
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.
Seems on Ubuntu you need linux-tools-generic, linux-cloud-tools-generic, linux-tools-common.
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.
It seems that linux-tools is the old package name, I can update.
|
@laanwj I didn't know about those repositories until you pointed them out to me. I'm happy to move the docs if we can still keep a link to them in |
|
@eklitzke Yes, that sounds fine. |
|
Flamegraphs are awesome, but I have personally switched from using the flamegraph scripts to the KDAB/hotspot profiler, which basically is a flamegraph GUI for perf: https://github.com/KDAB/hotspot |
Yes, that'd be the way to do it. |
|
|
||
| Flame graphs are a way of visualizing software CPU and heap profiles. Any tool | ||
| that can create stack data in the correct format can be used to generate a flame | ||
| graph. The flame graphs themselves are SVG files that have a small have a small |
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.
s/have a small have a small/have a small/
|
Apologies for the delay on this, I was asked on IRC if I still plan to move this to the docs repo, and I do intend to. I will update this tomorrow. |
…ith perf 13782b8 docs: add perf section to developer docs (James O'Beirne) 58180b5 tests: add utility to easily profile node performance with perf (James O'Beirne) Pull request description: Adds a context manager to easily (and selectively) profile node performance during functional test execution using `perf`. While writing some tests, I encountered some odd bitcoind slowness. I wrote up a utility (`TestNode.profile_with_perf`) that generates performance diagnostics for a node by running `perf` during the execution of a particular region of test code. `perf` usage is detailed in the excellent (and sadly unmerged) #12649; all due props to @eklitzke. ### Example ```python with node.profile_with_perf("large-msgs"): for i in range(200): node.p2p.send_message(some_large_msg) node.p2p.sync_with_ping() ``` This generates a perf data file in the test node's datadir (`/tmp/testtxmpod0y/node0/node-0-TestName-large-msgs.perf.data`). Running `perf report` generates nice output about where the node spent most of its time while running that part of the test: ```bash $ perf report -i /tmp/testtxmpod0y/node0/node-0-TestName-large-msgs.perf.data --stdio \ | c++filt \ | less # To display the perf.data header info, please use --header/--header-only options. # # # Total Lost Samples: 0 # # Samples: 135 of event 'cycles:pp' # Event count (approx.): 1458205679493582 # # Children Self Command Shared Object Symbol # ........ ........ ............... ................... ........................................................................................................................................................................................................................................................................ # 70.14% 0.00% bitcoin-net bitcoind [.] CNode::ReceiveMsgBytes(char const*, unsigned int, bool&) | ---CNode::ReceiveMsgBytes(char const*, unsigned int, bool&) 70.14% 0.00% bitcoin-net bitcoind [.] CNetMessage::readData(char const*, unsigned int) | ---CNetMessage::readData(char const*, unsigned int) CNode::ReceiveMsgBytes(char const*, unsigned int, bool&) 35.52% 0.00% bitcoin-net bitcoind [.] std::vector<char, zero_after_free_allocator<char> >::_M_fill_insert(__gnu_cxx::__normal_iterator<char*, std::vector<char, zero_after_free_allocator<char> > >, unsigned long, char const&) | ---std::vector<char, zero_after_free_allocator<char> >::_M_fill_insert(__gnu_cxx::__normal_iterator<char*, std::vector<char, zero_after_free_allocator<char> > >, unsigned long, char const&) CNetMessage::readData(char const*, unsigned int) CNode::ReceiveMsgBytes(char const*, unsigned int, bool&) ... ``` Tree-SHA512: 9ac4ceaa88818d5eca00994e8e3c8ad42ae019550d6583972a0a4f7b0c4f61032e3d0c476b4ae58756bc5eb8f8015a19a7fc26c095bd588f31d49a37ed0c6b3e
|
@eklitzke the links you posted at doc/flamegraphs are dead - can you generate/upload the pic and svg file again? |
|
@GChuf You can generate them yourself. If you are looking for an illustrative example, there are plenty: https://duckduckgo.com/?q=flamegraph&t=ffab&iax=images&ia=images |
|
Just wanted to point out the broken links. Anyone can find examples on the internet - if I had found a bitcoin example i'd already propose to replace the picture. |
|
Here's a flame graph I generated for doing some of my wallet load time stuff: https://achow101.com/bitcoin-master-flame.svg |
…e with perf Summary: docs: add perf section to developer docs (James O'Beirne) add utility to easily profile node performance with perf (James O'Beirne) Pull request description: Adds a context manager to easily (and selectively) profile node performance during functional test execution using `perf`. While writing some tests, I encountered some odd bitcoind slowness. I wrote up a utility (`TestNode.profile_with_perf`) that generates performance diagnostics for a node by running `perf` during the execution of a particular region of test code. `perf` usage is detailed in the excellent (and sadly unmerged) bitcoin/bitcoin#12649; all due props to @eklitzke. ### Example ```python with node.profile_with_perf("large-msgs"): for i in range(200): node.p2p.send_message(some_large_msg) node.p2p.sync_with_ping() ``` This generates a perf data file in the test node's datadir (`/tmp/testtxmpod0y/node0/node-0-TestName-large-msgs.perf.data`). Running `perf report` generates nice output about where the node spent most of its time while running that part of the test: ```bash $ perf report -i /tmp/testtxmpod0y/node0/node-0-TestName-large-msgs.perf.data --stdio \ | c++filt \ | less https://github.com/bitcoin/bitcoin/pull/14519/files --- Backport of Core PR14519 Test Plan: ninja cd test ../../test/functional/abc-cmdline.py --perf --config=config.ini run command to see test report in the output log Reviewers: #bitcoin_abc, Fabien Reviewed By: #bitcoin_abc, Fabien Differential Revision: https://reviews.bitcoinabc.org/D7080
…mance with perf 13782b8 docs: add perf section to developer docs (James O'Beirne) 58180b5 tests: add utility to easily profile node performance with perf (James O'Beirne) Pull request description: Adds a context manager to easily (and selectively) profile node performance during functional test execution using `perf`. While writing some tests, I encountered some odd bitcoind slowness. I wrote up a utility (`TestNode.profile_with_perf`) that generates performance diagnostics for a node by running `perf` during the execution of a particular region of test code. `perf` usage is detailed in the excellent (and sadly unmerged) bitcoin#12649; all due props to @eklitzke. ### Example ```python with node.profile_with_perf("large-msgs"): for i in range(200): node.p2p.send_message(some_large_msg) node.p2p.sync_with_ping() ``` This generates a perf data file in the test node's datadir (`/tmp/testtxmpod0y/node0/node-0-TestName-large-msgs.perf.data`). Running `perf report` generates nice output about where the node spent most of its time while running that part of the test: ```bash $ perf report -i /tmp/testtxmpod0y/node0/node-0-TestName-large-msgs.perf.data --stdio \ | c++filt \ | less # To display the perf.data header info, please use --header/--header-only options. # # # Total Lost Samples: 0 # # Samples: 135 of event 'cycles:pp' # Event count (approx.): 1458205679493582 # # Children Self Command Shared Object Symbol # ........ ........ ............... ................... ........................................................................................................................................................................................................................................................................ # 70.14% 0.00% bitcoin-net bitcoind [.] CNode::ReceiveMsgBytes(char const*, unsigned int, bool&) | ---CNode::ReceiveMsgBytes(char const*, unsigned int, bool&) 70.14% 0.00% bitcoin-net bitcoind [.] CNetMessage::readData(char const*, unsigned int) | ---CNetMessage::readData(char const*, unsigned int) CNode::ReceiveMsgBytes(char const*, unsigned int, bool&) 35.52% 0.00% bitcoin-net bitcoind [.] std::vector<char, zero_after_free_allocator<char> >::_M_fill_insert(__gnu_cxx::__normal_iterator<char*, std::vector<char, zero_after_free_allocator<char> > >, unsigned long, char const&) | ---std::vector<char, zero_after_free_allocator<char> >::_M_fill_insert(__gnu_cxx::__normal_iterator<char*, std::vector<char, zero_after_free_allocator<char> > >, unsigned long, char const&) CNetMessage::readData(char const*, unsigned int) CNode::ReceiveMsgBytes(char const*, unsigned int, bool&) ... ``` Tree-SHA512: 9ac4ceaa88818d5eca00994e8e3c8ad42ae019550d6583972a0a4f7b0c4f61032e3d0c476b4ae58756bc5eb8f8015a19a7fc26c095bd588f31d49a37ed0c6b3e
This adds documentation for generating flame graphs (a profiling format I've found to be very useful). It's pretty straightforward: I've added a new file in
doc/, updateddoc/developer-notes.md, and checked in a patch and example flame graph to contrib.You can see how it looks when rendered on GitHub here: https://github.com/eklitzke/bitcoin/blob/flamegraphs/doc/flamegraphs.md
The one thing that's kind of weird is that when you look at an actual flame graph file you get hover events and can interact with the graph (for example, here's the same example.svg file I checked in on an actual web page). The way GitHub renders the markdown file (which refers to the
example.svgI added to contrib) prevent this from happening, it just gets rendered as a static image. It would be kind of cool if we could host the example file on bitcoincore.org or something.