| // Copyright 2024 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 zx; |
| |
| /// The act of taking a sample takes on the order of single digit microseconds. |
| /// A period close to or shorter than that doesn't make sense. |
| const SAMPLER_MIN_PERIOD Duration = 10000; |
| const SAMPLER_MAX_BUFFER_SIZE usize64 = 1073741824; // 1 GiB |
| |
| type SamplerConfig = struct { |
| period Duration; |
| buffer_size usize64; |
| discipline uint64; |
| }; |
| |
| @transport("Syscall") |
| closed protocol Sampler { |
| /// ## Summary |
| /// |
| /// Create a sampler session, returning an IOBuffer containing a buffer allocated for each |
| /// active cpu. |
| /// |
| /// ## Declaration |
| /// |
| /// ```c |
| /// #include <zircon/syscalls.h> |
| /// |
| /// zx_status_t zx_sampler_create(zx_resource_t rsrc |
| /// uint64_t options, |
| /// zx_sampler_config_t* config, |
| /// size_t config_size; |
| /// zx_handle_t* iob_out); |
| /// ``` |
| /// |
| /// ## Description |
| /// |
| /// `zx_sampler_create()` initializes a global singleton thread sampler which |
| /// writes samples to the returned IOBuffer. The returned iobuffer will have |
| /// a number of regions equal to the active number of cpus on the system |
| /// when called. Each buffer is of the size declared in *config*. |
| /// |
| /// |
| /// The parameter *options* must be 0. |
| /// |
| /// The parameter *config* must be a zx_sampler_config_t. |
| /// ### Config {#zx_sampler_config_t} |
| /// ``` |
| /// typedef struct { |
| /// // How long an individual cpu core will wait in nanoseconds between |
| /// // taking each sample. The minimum period is ZX_SAMPLER_MIN_PERIOD (10000ns). |
| /// zx_duration_t period; |
| /// |
| /// // The requested size of the region in bytes. The size will be |
| /// // rounded up to the next system page size boundary, as reported by |
| /// // zx_system_get_page_size(). Use `zx_object_get_info` with topic |
| /// // `ZX_INFO_IOB_REGIONS` on the returned handle to determine the |
| /// // actual size of each region. |
| /// size_t buffer_size; |
| /// |
| /// // The requested discipline of the returned iobuffer. See below for |
| /// // valid disciplines. |
| /// uint64_t iobuffer_discipline; |
| /// } zx_sampler_config_t; |
| /// ``` |
| /// |
| /// The caller may request the samples be written to the returned IOBuffer |
| /// using an agreed upon iobuffer discipline. Currently, there is a single |
| /// supported discipline `ZX_IOB_DISCIPLINE_NONE (0)` which works as |
| /// follows: |
| /// |
| /// After threads are attached and sampling is started, each cpu will write |
| /// samples to the dedicated region. Samples will continue to be written to |
| /// the buffer until either sampling stops or the buffer becomes full. |
| /// |
| /// Samples are read by reading a thread's PC and attempting to walk the |
| /// thread's backtrace by following frame pointers. |
| /// |
| /// Samples are written as 8 bytes aligned [FXT Large Blob with Metadata] |
| /// records where the payload contains the PCs sampled from the thread's |
| /// stack. An FXT Header of `0` indicates that there is no additional data. |
| /// |
| /// To safely read the data from the buffer, a read should first call |
| /// zx_sampler_stop which will stop the session and return when no |
| /// additional samples will be written. A reader may then map each region of |
| /// the IOBuffer with `zx_vmar_map_iob` and access the samples. |
| /// |
| /// ## Controlling the Session |
| /// |
| /// The sampler is a global singleton and there is at most one session |
| /// active at a time. The session can be controlled by passing the returned |
| /// IOBuffer to the start/stop/attach calls. When the returned IOBuffer's |
| /// last handle is closed the session will stop and be destroyed. |
| /// |
| /// ## Rights |
| /// |
| /// *debug_resource* must have resource kind `ZX_RSRC_KIND_SYSTEM` with base |
| /// `ZX_RSRC_SYSTEM_DEBUG_BASE`. |
| /// |
| /// ## Errors |
| /// |
| /// `ZX_ERR_NOT_SUPPORTED` `kernel.enable-debugging-syscalls` is not set to `true` |
| /// on the kernel command line or the experimental_thread_sampler_enabled |
| /// build param is not set to true. |
| /// |
| /// `ZX_ERR_PERMISION_DENIED` *rsrc* is not resource kind |
| /// `ZX_RSRC_KIND_SYSTEM` with base `ZX_RSRC_SYSTEM_DEBUG_BASE`. |
| /// |
| /// `ZX_ERR_INVALID_ARGS` |
| /// - *options* is not 0 |
| /// - The provided *config* is invalid. See |
| /// [zx_sampler_config_t](sampler_create.md#zx_sampler_config_t) for the expected config. |
| /// |
| /// ## See also |
| /// |
| /// - [`zx_sampler_attach()`] |
| /// - [`zx_sampler_start()`] |
| /// - [`zx_sampler_stop()`] |
| /// - [FXT Format] |
| /// - [`zx_vmar_map_iob()`] |
| /// |
| /// [FXT Large Blob with Metadata]: docs/reference/tracing/trace-format.md#large-blob-record |
| /// [`zx_sampler_attach()`]: sampler_attach.md |
| /// [`zx_sampler_start()`]: sampler_start.md |
| /// [`zx_sampler_stop()`]: sampler_stop.md |
| /// [FXT Format]: docs/reference/tracing/trace-format.md |
| /// [`zx_vmar_map_iob()`]: vmar_map_iob.md |
| @next |
| strict Create(resource struct { |
| rsrc Handle:RESOURCE; |
| options uint64; |
| config SamplerConfig; |
| }) -> (resource struct { |
| per_cpu_buffers Handle; |
| }) error Status; |
| |
| /// ## Summary |
| /// |
| /// Configure a thread to have its stack periodically sampled and written to |
| /// the provided IOBuffer. The provided IOBuffer must be one previously |
| /// returned by zx_sampler_create. |
| /// |
| /// ## Declaration |
| /// |
| /// ```c |
| /// #include <zircon/syscalls.h> |
| /// |
| /// zx_status_t zx_sampler_attach(zx_handle_t iobuffer, |
| /// zx_handle_t thread); |
| /// ``` |
| /// |
| /// ## Description |
| /// |
| /// Configure a thread to have its stack periodically sampled and written to |
| /// the provided IOBuffer. The provided IOBuffer must be one previously |
| /// returned by zx_sampler_create. The frequency and write strategy of |
| /// sampling is determined by the zx_sampler_config_t used when calling |
| /// zx_sampler_create. |
| /// |
| /// If a thread is attached to before a session starts, in which it will be |
| /// sampled when the session starts. Alternatively, if a thread is attached |
| /// to during a session, it will start to be sampled immediately. |
| /// |
| /// ## Errors |
| /// |
| /// `ZX_ERR_NOT_SUPPORTED` `kernel.enable-debugging-syscalls` is not set to `true` |
| /// on the kernel command line or the experimental_thread_sampler_enabled |
| /// build param is not set to true. |
| /// |
| /// `ZX_ERR_PERMISION_DENIED` |
| /// - *iobuffer* is not an IOBuffer returned by zx_sampler_create. |
| /// - *thread* does not have ZX_RIGHT_READ. |
| /// |
| /// ## See also |
| /// |
| /// - [`zx_sampler_create()`] |
| /// - [`zx_sampler_destroy()`] |
| /// |
| /// [`zx_sampler_create()`]: sampler_create.md |
| /// [`zx_sampler_destroy()`]: sampler_destroy.md |
| @next |
| strict Attach(resource struct { |
| iobuffer Handle; |
| thread Handle:THREAD; |
| }) -> () error Status; |
| |
| /// ## Summary |
| /// |
| /// Begin sampling to the provided IOBuffer. |
| /// |
| /// ## Declaration |
| /// |
| /// ```c |
| /// #include <zircon/syscalls.h> |
| /// |
| /// zx_status_t zx_sampler_start(zx_handle_t iobuffer); |
| /// ``` |
| /// |
| /// ## Description |
| /// |
| /// Begin sampling each attached thread and writing each sample to the |
| /// provided IOBuffer. The provided IOBuffer must be one previously returned |
| /// by zx_sampler_create. |
| /// |
| /// Attempting to start a session which has already been started will return |
| /// an error, but will not stop or otherwise modify the session. |
| /// |
| /// Restarting a previously started/stopped session will continue writing to |
| /// the buffers where the previous session left off. |
| /// |
| /// ## Errors |
| /// |
| /// `ZX_ERR_NOT_SUPPORTED` `kernel.enable-debugging-syscalls` is not set to `true` |
| /// on the kernel command line or the experimental_thread_sampler_enabled |
| /// build param is not set to true. |
| /// |
| /// `ZX_ERR_PERMISION_DENIED` *iobuffer* is not an IOBuffer returned by zx_sampler_create. |
| /// |
| /// `ZX_ERR_BAD_STATE` the sampler has already been started. |
| /// |
| /// ## See also |
| /// |
| /// - [`zx_sampler_attach()`] |
| /// - [`zx_sampler_create()`] |
| /// - [`zx_sampler_stop()`] |
| /// |
| /// [`zx_sampler_attach()`]: sampler_attach.md |
| /// [`zx_sampler_create()`]: sampler_create.md |
| /// [`zx_sampler_stop()`]: sampler_stop.md |
| @next |
| strict Start(resource struct { |
| iobuffer Handle; |
| }) -> () error Status; |
| |
| /// ## Summary |
| /// |
| /// Stop writing samples to the provided IOBuffer. |
| /// |
| /// ## Declaration |
| /// |
| /// ```c |
| /// #include <zircon/syscalls.h> |
| /// |
| /// zx_status_t zx_sampler_stop(zx_handle_t iobuffer); |
| /// ``` |
| /// |
| /// ## Description |
| /// |
| /// Stop sampling each attached thread and finish writing any in flight |
| /// samples to the iobuffer. This call will return after no additional |
| /// samples will be written. The provided IOBuffer must be one previously |
| /// returned by zx_sampler_create. |
| /// |
| /// Attempting to stop a session which has already been stopped will return |
| /// an error, but will not modify the session. |
| /// |
| /// ## Errors |
| /// |
| /// `ZX_ERR_NOT_SUPPORTED` `kernel.enable-debugging-syscalls` is not set to `true` |
| /// on the kernel command line or the experimental_thread_sampler_enabled |
| /// build param is not set to true. |
| /// |
| /// `ZX_ERR_PERMISION_DENIED` *iobuffer* is not an IOBuffer returned by zx_sampler_create. |
| /// |
| /// `ZX_ERR_BAD_STATE` the sampler has not started or has already been |
| /// stopped |
| /// |
| /// ## See also |
| /// |
| /// - [`zx_sampler_attach()`] |
| /// - [`zx_sampler_create()`] |
| /// - [`zx_sampler_start()`] |
| /// |
| /// [`zx_sampler_attach()`]: sampler_attach.md |
| /// [`zx_sampler_create()`]: sampler_create.md |
| /// [`zx_sampler_start()`]: sampler_stop.md |
| @next |
| strict Stop(resource struct { |
| iobuffer Handle; |
| }) -> () error Status; |
| }; |