| # Stacktrack |
| |
| Stacktrack is a profiling tool that records the peak stack usage observed for |
| each thread in a process. |
| |
| The Stacktrack library runs within the profiled process and wraps the Zircon |
| VDSO symbols. Therefore, whenever the process makes a syscall, its current stack |
| usage will be analyzed before passing control to the real syscall handler. |
| |
| Conversely, stacks that do not bottom-out in a syscall (e.g. pure calculations |
| or recursive calls performed entirely in user-space) will **not** be seen or |
| recorded by this tool. |
| |
| ## Profiling individual components |
| |
| * Add `//src/performance/memory/stacktrack/instrumentation/collector.shard.cml` |
| to the `include` list in your component's manifest. |
| * Add `//src/performance/memory/stacktrack/collector` to the `subpackages` of |
| your package. |
| * C++: |
| * Add `//src/performance/memory/stacktrack/instrumentation` to the `deps` of |
| the `executable` target that you want to profile. |
| * Add `#include <stacktrack/bind.h>` and call `stacktrack_bind_with_fdio()` at |
| the beginning of `main` in your program. |
| * Rust: |
| * Add `//src/performance/memory/stacktrack/instrumentation:rust` to the `deps` |
| of the `rustc_binary` target that you want to profile. |
| * Call `stacktrack::bind_with_fdio()` at the beginning of `main` in your |
| program. |
| |
| * Run your program as usual. |
| * The `ffx profile stacktrack` tool, to dump the results, is not yet available. |
| |
| ### Quickstart: Running the example |
| |
| ``` |
| # Include stacktrack's example component in the build. |
| fx set ... --with src/performance/memory/stacktrack/example |
| |
| # Build and run Fuchsia as usual, then start the example component. |
| ffx component run /core/ffx-laboratory:example fuchsia-pkg://fuchsia.com/stacktrack-example#meta/stacktrack-example.cm |
| ``` |
| |
| ## Design |
| |
| The Stacktrack library interposes calls to the Zircon VDSO and tracks the |
| deepest stack trace observed for each thread. It maintains a list of active |
| threads in a shared VMO, allowing external tools to inspect the state of the |
| process at any time without requiring cooperation from the process itself (i.e. |
| without taking locks or pausing execution). |
| |
| Each instrumented process shares a read-only handle to its VMOs to a centralized |
| component called "stacktrack-collector". The collector can then easily take a |
| snapshot, at any time and without any further cooperation from the instrumented |
| process, by simply creating a `ZX_VMO_CHILD_SNAPSHOT` of the threads VMO. |
| |
| In order to guarantee that the resulting snapshot is always consistent, the |
| instrumentation updates the VMO using atomic operations. Specifically, when a |
| thread's stack trace needs to be updated (because a deeper stack is observed), a |
| new node is inserted into the list, and then the old node is removed. This |
| insert-then-remove pattern ensures that the thread remains visible from the |
| reader's perspective at all times. |
| |
| ### VMO format |
| |
| The Stacktrack VMO consists of a header followed by an array of nodes, indexed |
| by zero-based integers. A linked list is built on top of this array, allowing a |
| list of active threads to be maintained without requiring contiguous storage. |
| |
| Each node represents a thread, storing the deepest stack trace observed so far. |
| This structure allows a reader to reconstruct the state of all active threads |
| simply by traversing the linked list from the header. |