| // Copyright 2019 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.perfmon.cpu; |
| |
| using zx; |
| |
| // The type of the `rate` field of EventConfig. |
| alias EventRate = uint32; |
| |
| // Trace buffer space is expensive, we want to keep records small. |
| // Having more than 64K different events for any one arch is unlikely |
| // so we use 16 bits for the event id. |
| // To help each arch manage the plethora of different events, the event id |
| // is split it two parts: 5 bit event group, and 11 bit event within that |
| // group. |
| // An event id of zero is defined to be unused. |
| alias EventId = uint16; |
| |
| const API_VERSION uint16 = 0; |
| |
| /// The maximum number of events we support simultaneously. |
| /// Typically the h/w supports less than this, e.g., 7 or so. |
| const MAX_NUM_EVENTS uint16 = 32; |
| |
| /// Bits for Properties.flags field. |
| type PropertyFlags = strict bits : uint64 { |
| /// The architecture supports LBR records (Last Branch Records). |
| HAS_LAST_BRANCH = 0x1; |
| }; |
| |
| /// The properties of this system. |
| type Properties = struct { |
| /// S/W API version = `API_VERSION`. |
| api_version uint16; |
| |
| /// The H/W Performance Monitor version. |
| /// This is the version defined by the architecture. |
| pm_version uint16; |
| |
| /// The maximum number of events that can be simultaneously supported. |
| /// The combination of events that can be simultaneously supported is |
| /// architecture/model specific. |
| max_num_events uint16; |
| |
| /// The maximum number of fixed events that can be simultaneously |
| /// supported, and their maximum width. |
| /// These values are for informational/display purposes. |
| max_num_fixed_events uint16; |
| max_fixed_counter_width uint16; |
| |
| /// The maximum number of programmable events that can be simultaneously |
| /// supported, and their maximum width. |
| /// These values are for informational/display purposes. |
| max_num_programmable_events uint16; |
| max_programmable_counter_width uint16; |
| |
| /// The maximum number of misc events that can be simultaneously |
| /// supported, and their maximum width. |
| /// These values are for informational/display purposes. |
| max_num_misc_events uint16; |
| max_misc_counter_width uint16; |
| |
| /// Various flags. |
| flags PropertyFlags; |
| }; |
| |
| /// Bits for EventConfig.flags field. |
| // TODO(dje): hypervisor, host/guest os/user |
| type EventConfigFlags = strict bits : uint32 { |
| /// Collect data when running in kernel mode. |
| COLLECT_OS = 0x1; |
| |
| /// Collect data when running in userspace mode. |
| COLLECT_USER = 0x2; |
| |
| /// Collect aspace+pc values. |
| COLLECT_PC = 0x4; |
| |
| /// If set for an event then the event is used as the "timebase": data |
| /// for events with a zero rate is collected when data for the timebase |
| /// event is collected. |
| /// It is an error to have this set and have the event's rate be zero. |
| /// At most one event may be the timebase event. |
| IS_TIMEBASE = 0x8; |
| |
| /// Collect the available set of last branches. |
| /// Branch data is emitted as LastBranch records. |
| /// This is only available when the underlying system supports it. |
| // TODO(dje): Provide knob to specify how many branches. |
| COLLECT_LAST_BRANCH = 0x10; |
| }; |
| |
| type EventConfig = struct { |
| /// Event to collect data for. |
| /// The values are architecture specific ids. |
| /// Each event may appear at most once. |
| event EventId; |
| |
| /// Sampling rate. |
| /// - If rate is non-zero then when the event gets this many hits data is |
| /// collected (e.g., pc, time). |
| /// The rate can be non-zero for counting based events only. |
| /// - If rate is zero then: |
| /// If there is a timebase event then data for this event is collected |
| /// when data for the timebase event is collected. |
| /// Otherwise data for the event is collected once, when tracing stops. |
| rate EventRate; |
| |
| /// Flags for the event. |
| flags EventConfigFlags; |
| }; |
| |
| /// Passed to `StageConfig()` to select the data to be collected. |
| type Config = struct { |
| /// Events to collect data for. |
| events array<EventConfig, MAX_NUM_EVENTS>; |
| }; |
| |
| /// The allocation configuration for a data collection run. |
| /// This is generally the first call to allocate resources for a trace, |
| /// "trace" is used generically here: == "data collection run". |
| type Allocation = struct { |
| /// The number of buffers to allocate for trace data. |
| /// This must be #cpus for now. |
| num_buffers uint32; |
| |
| /// The size of each buffer in 4K pages. |
| /// Each cpu gets same buffer size. |
| buffer_size_in_pages uint32; |
| }; |
| |
| protocol Controller { |
| /// Fetch the performance monitor properties of the system. |
| GetProperties() -> (struct { |
| properties Properties; |
| }); |
| |
| /// Create a trace, allocating the needed trace buffers and other resources. |
| /// "other resources" is basically a catch-all for other things that will |
| /// be needed. This does not include reserving the events, that is done |
| /// later by `StageConfig()`. |
| Initialize(struct { |
| allocation Allocation; |
| }) -> (struct {}) error zx.status; |
| |
| /// Free all trace buffers and any other resources allocated for the trace. |
| /// This is also done when the connection is closed. |
| /// Tracing is first stopped if not already stopped. |
| /// May be called multiple times. |
| Terminate() -> (); |
| |
| /// Return the trace allocation configuration, if there is one. |
| GetAllocation() -> (struct { |
| allocation box<Allocation>; |
| }); |
| |
| /// Stage performance monitor specification for a cpu. |
| /// Must be called with data collection off and after `Initialize()`. |
| /// Note: This doesn't actually configure the h/w, this just stages |
| /// the values for subsequent use by `Start()`. |
| StageConfig(struct { |
| config Config; |
| }) -> (struct {}) error zx.status; |
| |
| /// Fetch performance monitor specification for a cpu, if it exists. |
| /// Must be called with data collection off and after `StageConfig()`. |
| GetConfig() -> (struct { |
| config box<Config>; |
| }); |
| |
| /// Return a handle of a trace buffer, if it exists, and if `descriptor` |
| /// is valid. |
| /// `descriptor` is (0, 1, 2, ..., `num_buffers`-1) |
| GetBufferHandle(struct { |
| descriptor uint32; |
| }) -> (resource struct { |
| vmo zx.handle:<VMO, optional>; |
| }); |
| |
| /// Turn on data collection. |
| /// Must be called after `Initialize()` + `StageConfig()` and with data |
| /// collection off. |
| Start() -> (struct {}) error zx.status; |
| |
| /// Turn off data collection. |
| /// May be called any time after `Initialize()` has been called and before |
| /// `Terminate()`. If called at other times the call is ignored. |
| /// May be called multiple times. |
| Stop() -> (); |
| }; |