-
Notifications
You must be signed in to change notification settings - Fork 5.5k
docs: added developer docs for pprof/tcmalloc testing #4194
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
Changes from 4 commits
1cbcfe1
5c0a04f
a94412d
0d63507
94e4ff4
02df9b3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| # Memory consumption testing with `pprof` | ||
|
|
||
| To use `pprof` to analyze performance and memory consumption in Envoy, you can | ||
| use the built-in statically linked profiler, or dynamically link it in to a | ||
| specific place yourself. | ||
|
|
||
| # Linking | ||
|
|
||
| ## Static Linking | ||
|
|
||
| Static linking is already available (because of a `HeapProfilerDump()` call | ||
| inside | ||
| [`Envoy::Profiler::Heap::forceLink()`](https://github.com/envoyproxy/envoy/blob/master/source/common/profiler/profiler.cc#L21-L26)). | ||
|
|
||
| ### Compiling a statically-linked Envoy | ||
|
|
||
| Just compile Envoy as normal: | ||
|
|
||
| $ bazel build //source/exe:envoy-static --copt='-ltcmalloc' | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The copt isn't needed. We compile against tcmalloc by default. |
||
|
|
||
| ### Running a statically-linked Envoy with `pprof` | ||
|
|
||
| And run the binary with a `HEAPPROFILE` env var, like so: | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: remove Also, can you add a brief explanation of what the |
||
|
|
||
| $ HEAPPROFILE=/tmp/mybin.hprof bazel-bin/source/exe/envoy-static <args> | ||
|
|
||
| ## Dynamic Linking | ||
|
|
||
| ### Adding `tcmalloc_dep` to Envoy | ||
|
|
||
| To add a `HeapProfiler` breakpoint yourself, add `tcmalloc` as a dependency | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: maybe add a one sentence explanation (or link) explaining what a heap profiler break point does? Or, you could add a section (or link) at the top that explains the ways you can use the heap profiler. Also, do heap profiler break points only work/apply in the dynamic linking setup?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe the statically linked Envoy profiles everything by default. |
||
| under the `envoy_cc_library` rule: `source/exe/BUILD` | ||
|
|
||
| ```c++ | ||
| envoy_cc_library( | ||
| name = "envoy_common_lib", | ||
| + tcmalloc_dep = 1, | ||
| deps = [ | ||
| ... | ||
| ) | ||
| ``` | ||
|
|
||
| It is then necessary to add `HeapProfilerStart()` and `HeapProfilerDump()` | ||
| breakpoints somewhere in Envoy. One place to start profiling is at the | ||
| instantiation of `MainCommonBase::MainCommonBase`: | ||
|
|
||
| `source/exe/main_common.cc` | ||
|
|
||
| ```c++ | ||
| // includes | ||
| #include "gperftools/heap-profiler.h" | ||
| ... | ||
| MainCommonBase::MainCommonBase(...) : ... { | ||
| + HeapProfilerStart("main_common_base"); // first line | ||
| ... | ||
| } | ||
| ``` | ||
|
|
||
| `source/server/server.cc` | ||
|
|
||
| ```c++ | ||
| // includes | ||
| #include "gperftools/heap-profiler.h" | ||
| ... | ||
| void InstanceImpl::Initialize(...) : ... { | ||
| ... | ||
| + HeapProfilerDump("main_common_base"); // last line | ||
| } | ||
| ``` | ||
|
|
||
| Once these changes have been implemented against head, it might make sense to | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The usage of "head" here seems a little weird. For example, I bet lots of people would want to use this to test a branch where they are developing a PR, not actually "head". Instead, maybe something like "Once these changes have been made in your working directory"?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oops, you're right. This was a holdover from when I was enabling profiling against both upstream/master and my branch. |
||
| save the diff as a patch (`git diff > file`), which can then be quickly | ||
| applied/unapplied for testing and commiting. (`git apply`, `git apply -R`) | ||
|
|
||
| ### Compiling a dynamically-linked Envoy with `pprof` | ||
|
|
||
| The binary must be explicitly built with `tcmalloc` like so: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did you mean to write
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (Also, are you sure this is needed even for the dynamic case?)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch -- the inclusion of |
||
|
|
||
| $ bazel build //source/exe:envoy --copt='-ltcmalloc' | ||
|
|
||
| ### Running a dynamically-linked Envoy with `pprof` | ||
|
|
||
| You can then run the binary without any env vars: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just say "Run the binary without any env vars:" |
||
|
|
||
| $ bazel-bin/source/exe/envoy <args> | ||
|
|
||
| This will output your `.heap` files to the working directory. | ||
|
|
||
| # Methodology | ||
|
|
||
| For consistent testing, it makes sense to run Envoy for a constant amount of | ||
| time across trials: | ||
|
|
||
| $ timeout <num_seconds> bazel-bin/source/exe/envoy <options> | ||
|
|
||
| During a run, the binary should print something like: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To stdout? stderr?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To stdout by default. |
||
|
|
||
| Starting tracking the heap | ||
|
|
||
| And then a series of stdouts like: | ||
|
|
||
| Dumping heap profile to <heap file 0001> (100 MB currently in use) | ||
| Dumping heap profile to <heap file 0002> (200 MB currently in use) | ||
| ... | ||
|
|
||
| This will generate a series of files; if you statically-linked, these are | ||
| wherever `HEAPPROFILE` points to. Otherwise, they are in the current directory | ||
| by default. They'll be named something like `main_common_base.0001.heap`, | ||
| `main_common_base.0002.heap`, etc. | ||
|
|
||
| *NB:* There is no reason this needs to be titled `main_common_base`: whatever | ||
| flag you supply `HeapProfilerStart` / `HeapProfilerDump` will become the | ||
| filename. Multiple ranges could be tested at the same time with this method. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does "range" refer to here? The time interval between
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be more explicit about profiling a section of code, not a range of time. I'll fix. |
||
|
|
||
| # Analyzing with `pprof` | ||
|
|
||
| [pprof](https://github.com/google/pprof) can then read these heap files in a | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: drop "then" |
||
| number of ways. Most convenient for first-order inspection might be `pprof -top` | ||
| or `pprof -text`: | ||
|
|
||
| $ pprof -text bazel-bin/source/exe/envoy main_common_base* | head -n5 | ||
| File: envoy | ||
| Build ID: ... | ||
| Type: inuse_space | ||
| Showing nodes accounting for 6402800.62kB, 98.59% of 6494044.58kB total | ||
| Dropped ... nodes (cum <= ...kB) | ||
|
|
||
| More complex flame/graph charts can be generated and viewed in a browser, which | ||
| is often more helpful than text-based output: | ||
|
|
||
| $ pprof -http=localhost:9999 bazel-bin/source/exe/envoy main_common_base* | ||
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.
nit: phrasing - I would prefer something like:
Build the static binary using bazel: