blob: 8c0cd4ba2af24069a8ff0221d5911b31664cdf96 [file] [log] [blame]
// Copyright 2017 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.
// TODO(dje): The "category" mechanism is limiting but it's what we have
// at the moment.
#include <stddef.h>
#include <stdint.h>
#include <functional>
#include <string>
#include <unordered_set>
#include <lib/zircon-internal/device/cpu-trace/perf-mon.h>
#include "garnet/lib/perfmon/config.h"
#include "garnet/lib/perfmon/events.h"
namespace cpuperf_provider {
enum class TraceOption {
// Collect data from the o/s.
// Collect data from userspace.
// Collect the PC value for each event that is its own timebase.
// Collect the set of last branch entries for each event that is its
// own timebase.
enum class CategoryGroup {
// Options like os vs user.
// The sampling mode and frequency.
// Collection of architecturally defined fixed-purpose events.
// Collection of architecturally defined programmable events.
// Collection of model-specific fixed-purpose events.
// Collection of model-specific programmable events.
using CategoryValue = uint32_t;
struct CategorySpec {
const char* name;
CategoryGroup group;
// This is only used by kOption and kSample.
CategoryValue value;
size_t count;
const perfmon::EventId* events;
struct TimebaseSpec {
const char* name;
const perfmon::EventId event;
extern const CategorySpec kCommonCategories[];
extern const size_t kNumCommonCategories;
extern const CategorySpec kTargetCategories[];
extern const size_t kNumTargetCategories;
extern const TimebaseSpec kTimebaseCategories[];
extern const size_t kNumTimebaseCategories;
// A data collection run is called a "trace".
// This records the user-specified configuration of the trace.
class TraceConfig final {
using IsCategoryEnabledFunc = std::function<bool(const char* name)>;
static std::unique_ptr<TraceConfig> Create(
perfmon::ModelEventManager* model_event_manager,
IsCategoryEnabledFunc category_is_enabled);
perfmon::ModelEventManager* model_event_manager() const {
return model_event_manager_;
bool is_enabled() const { return is_enabled_; }
bool trace_os() const { return trace_os_; }
bool trace_user() const { return trace_user_; }
bool trace_pc() const { return trace_pc_; }
bool trace_last_branch() const { return trace_last_branch_; }
uint32_t sample_rate() const { return sample_rate_; }
perfmon::EventId timebase_event() const { return timebase_event_; }
// Return true if the configuration has changed.
bool Changed(const TraceConfig& old) const;
// Translate our representation of the configuration to the device's.
bool TranslateToDeviceConfig(perfmon::Config* out_config) const;
// Return a string representation of the config for error reporting.
std::string ToString() const;
// Keeps track of category data for ProcessCategories.
struct CategoryData {
bool have_data_to_collect = false;
bool have_sample_rate = false;
bool have_programmable_category = false;
TraceConfig(perfmon::ModelEventManager* model_event_manager,
IsCategoryEnabledFunc category_is_enabled);
bool ProcessAllCategories();
bool ProcessCategories(const CategorySpec categories[],
size_t num_categories,
CategoryData* data);
bool ProcessTimebase();
// Non-owning.
perfmon::ModelEventManager* const model_event_manager_;
const IsCategoryEnabledFunc is_category_enabled_;
bool is_enabled_ = false;
bool trace_os_ = false;
bool trace_user_ = false;
bool trace_pc_ = false;
bool trace_last_branch_ = false;
uint32_t sample_rate_ = 0;
perfmon::EventId timebase_event_ = perfmon::kEventIdNone;
// Set of selected fixed + programmable categories.
std::unordered_set<const CategorySpec*> selected_categories_;
} // namespace cpuperf_provider