| // Copyright 2023 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| library fuchsia.cpu.profiler; |
| using zx; |
| using fuchsia.component; |
| using fuchsia.url; |
| |
| /// Curated set of platform independent IDs |
| type CounterId = flexible enum : uint8 { |
| /// A counter increments each nanosecond |
| NANOSECONDS = 0; |
| /// A counter increments each cpu cycle |
| CYCLES = 1; |
| /// A counter increments on each instruction retired |
| INSTRUCTIONS_RETIRED = 2; |
| /// A counter increments on each branch correctly predicted |
| BRANCHES_PREDICTED = 3; |
| /// A counter increments on each branch mispredicted |
| BRANCHES_MISPREDIDCTED = 4; |
| }; |
| |
| type Counter = flexible union { |
| /// Curated set of platform independent ids that get converted into the |
| /// appropriate hardware specific counter id. |
| 1: platform_independent CounterId; |
| |
| /// In the case a counter is not widely supported across |
| /// platform or not included in the curated set, one can |
| /// specify a platform dependent id that will not get |
| /// converted. |
| 2: platform_dependent uint32; |
| }; |
| |
| /// Various approaches to obtaining |
| type CallgraphStrategy = flexible enum : uint8 { |
| /// Don't try to get a callgraph |
| NONE = 0; |
| /// Copy out stack memory and attempt to parse the DWARF info. |
| /// This is the slowest and most memory intensive of the approaches, but |
| /// gives the most accurate callgraphs. Parsing dwarf allows the callgraph |
| /// to trace inlined and leaf functions which other approaches do not |
| /// support. |
| DWARF = 1; |
| /// Intel CPUs support a hardware feature called Last Branch Records (LBR)s |
| /// which record up to the last 32 calls made depending on hardware version. |
| /// On supported CPUs, this is a low overhead approach to finding the |
| /// callgraph with the caveat that stacks that exceed 32 calls in depth will |
| /// overflow the hardware buffer. |
| LAST_BRANCH_RECORD = 2; |
| /// arm and riscv support shadow call stacks which are an efficient way for us |
| /// to find and copy out the call stack. However, leaf functions and code |
| /// compiled without shadow callstack support, such as the vdso will not |
| /// appear in the returned callgraph. |
| SHADOW_CALL_STACK = 3; |
| /// A general approach of parsing the frame pointers of the callstack. Frame |
| /// pointers are supported across architectures and are slightly more |
| /// expensive than the lbrs or shadow call stacks, but much cheaper than |
| /// parsing dwarf. Code compiled with omitted frame pointers and inlined |
| /// functions will not appear in the resulting stacks. |
| FRAME_POINTER = 4; |
| }; |
| |
| type CallgraphConfig = table { |
| 1: strategy CallgraphStrategy; |
| }; |
| |
| type Sample = table { |
| /// Whether the profiler should include callgraph information and if so, |
| /// what strategy it should use. |
| 1: callgraph CallgraphConfig; |
| /// The value of a counter since the last sample |
| 2: counters vector<Counter>:64; |
| }; |
| |
| /// An adhoc set of running tasks to attach to. |
| type Task = flexible union { |
| /// Profile a process and all threads associated with it |
| 1: process zx.Koid; |
| /// Profile a single thread |
| 2: thread zx.Koid; |
| /// Profile a job and all processes and threads associated with it |
| 3: job zx.Koid; |
| }; |
| |
| /// A test to launch and attach to |
| type TestConfig = table { |
| /// The url of the test to launch |
| 1: url fuchsia.url.Url; |
| /// Test case filters to limit the test run to |
| 2: filters vector<string:MAX>:MAX; |
| /// Optional realm in which the test will be run |
| 3: realm string:fuchsia.component.MAX_MONIKER_LENGTH; |
| }; |
| |
| /// A component to optionally launch and attach to |
| type ComponentConfig = table { |
| /// The url of the component to launch |
| 1: url fuchsia.url.Url; |
| |
| /// If a component exists with the given moniker, attach to it, else launch |
| /// the component specified by the given url at the moniker |
| 2: moniker string:fuchsia.component.MAX_MONIKER_LENGTH; |
| }; |
| |
| /// A target may be an adhoc set of tasks, or one defined by a component/test |
| type TargetConfig = flexible union { |
| /// An adhoc set of threads/processes/jobs |
| 1: tasks vector<Task>:64; |
| /// Profile a component and all tasks it launches |
| 2: component ComponentConfig; |
| /// Profile a test and all tasks it launches |
| 3: test TestConfig; |
| }; |
| |
| /// Profiling information about the profile itself |
| type SamplingConfig = table { |
| /// How many ticks of the counter should occur between each sample |
| 1: period uint64; |
| /// The counter to the rate on |
| 2: timebase Counter; |
| /// What information the profiler will write when it takes |
| /// a sample. |
| 3: sample Sample; |
| }; |
| |
| /// When a config has multiple SamplingConfigs, the session applies each |
| /// SamplingConfig to the TargetConfig. |
| type Config = table { |
| 1: configs vector<SamplingConfig>:64; |
| 2: target TargetConfig; |
| }; |
| |
| @discoverable |
| closed protocol Session { |
| /// Set up and prepare to profile |
| strict Configure(resource table { |
| 1: output zx.Handle:SOCKET; |
| 2: config Config; |
| }) -> () error flexible enum : uint32 { |
| BAD_SOCKET = 1; |
| BAD_STATE = 2; |
| INVALID_CONFIGURATION = 3; |
| }; |
| |
| /// Begin profiling and optionally begin writing data to the configured |
| /// socket |
| strict Start(table { |
| /// If true, delays writing data to the output socket until the profiling |
| /// session ends. This reduces overhead, but also caps the maximum output |
| /// size to the requested buffer size. |
| 1: buffer_size_mb uint64; |
| 2: buffer_results bool; |
| }) -> () error flexible enum : uint32 { |
| BAD_STATE = 1; |
| }; |
| |
| /// End the profiling session and write out data to the earlier |
| /// configured socket if not already writing. |
| strict Stop() -> (table { |
| 1: samples_collected uint64; |
| 2: mean_sample_time uint64; |
| 3: median_sample_time uint64; |
| 4: min_sample_time uint64; |
| 5: max_sample_time uint64; |
| }); |
| |
| /// Clean up and unconfigure the profiler. Flushes the remaining data and |
| /// closes the provided socket. Doesn't return until all data has been |
| /// successfully written. |
| strict Reset() -> (); |
| }; |