|  | // 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() -> (); | 
|  | }; |