blob: cc3d7ab08b7b440d7858575249456a5717a8f37e [file] [log] [blame]
// Copyright 2020 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.
#ifndef SRC_DEVICES_BIN_DRIVER_HOST_INSPECT_H_
#define SRC_DEVICES_BIN_DRIVER_HOST_INSPECT_H_
#include <fuchsia/device/llcpp/fidl.h>
#include <fuchsia/device/manager/llcpp/fidl.h>
#include <lib/inspect/cpp/inspect.h>
#include <lib/zx/clock.h>
#include <ddk/driver.h>
#include <fbl/ref_ptr.h>
#include <fs/pseudo_dir.h>
#include <fs/synchronous_vfs.h>
#include "defaults.h"
class InspectCallStats {
public:
InspectCallStats(inspect::Node& parent, std::string name) {
node_ = parent.CreateChild(name);
count_ = node_.CreateUint("count", 0);
time_taken_ns_ = node_.CreateExponentialUintHistogram(
"time_taken(ns)", 0 /* floor */, 1000 /* step size: 1 us */, 10 /* step multiplier */,
7 /* buckets (upto 1s) */);
}
class InspectCallStatsUpdate {
public:
InspectCallStatsUpdate(InspectCallStats& stats) : stats_(stats) { stats_.count().Add(1); }
~InspectCallStatsUpdate() {
stats_.time_taken_ns().Insert((zx::clock::get_monotonic() - start_).get());
}
// disallow copy and assign
InspectCallStatsUpdate(const InspectCallStatsUpdate&) = delete;
InspectCallStatsUpdate& operator=(const InspectCallStatsUpdate&) = delete;
private:
zx::time start_ = zx::clock::get_monotonic();
InspectCallStats& stats_;
};
// Call this method to measure time taken for a function. When the Update object goes out of
// scope, the measurements are recorded.
// Eg: void ProcessRequest() {
// inspect_stat.Update();
// // Do something useful.
// } // Measurements are recorded here.
//
// Note: `InspectCallStatsUpdate` object returned by this method should not outlive
// `InspectCallStats` i.e. this object
InspectCallStatsUpdate Update() { return InspectCallStatsUpdate(*this); }
inspect::ExponentialUintHistogram& time_taken_ns() { return time_taken_ns_; }
inspect::UintProperty& count() { return count_; }
private:
inspect::Node node_;
inspect::UintProperty count_;
inspect::ExponentialUintHistogram time_taken_ns_;
};
struct InspectNodeCollection {
inspect::Node nodes;
inspect::UintProperty count;
};
// Helper class for device inspect
struct DeviceSystemPowerStateMapping {
explicit DeviceSystemPowerStateMapping(inspect::Node& parent, uint32_t state_id) {
system_power_state = parent.CreateChild(std::to_string(state_id));
power_state = system_power_state.CreateUint("power_state", 0);
performance_state = system_power_state.CreateUint("performance_state", 0);
suspend_flag = system_power_state.CreateUint("suspend_flag", 0);
wakeup_enable = system_power_state.CreateBool("wakeup_enable", false);
}
inspect::Node system_power_state;
inspect::UintProperty power_state;
inspect::UintProperty performance_state;
inspect::UintProperty suspend_flag;
inspect::BoolProperty wakeup_enable;
};
// Helper class for device inspect
struct DevicePowerStates {
explicit DevicePowerStates(inspect::Node& parent, uint32_t state_id) {
power_state = parent.CreateChild(std::to_string(state_id));
restore_latency = power_state.CreateInt("restore_latency", 0);
wakeup_capable = power_state.CreateBool("wakeup_capable", false);
system_wake_state = power_state.CreateInt("system_wake_state", 0);
}
inspect::Node power_state;
inspect::IntProperty restore_latency;
inspect::BoolProperty wakeup_capable;
inspect::IntProperty system_wake_state;
};
// Helper class for device inspect
struct DevicePerformanceStates {
explicit DevicePerformanceStates(inspect::Node& parent, uint32_t state_id) {
performance_state = parent.CreateChild(std::to_string(state_id));
restore_latency = performance_state.CreateInt("restore_latency", 0);
}
inspect::Node performance_state;
inspect::IntProperty restore_latency;
};
class DriverHostInspect {
public:
DriverHostInspect();
inspect::Node& root_node() { return inspect_.GetRoot(); }
fs::PseudoDir& diagnostics_dir() { return *diagnostics_dir_; }
InspectNodeCollection& drivers() { return drivers_; }
zx_status_t Serve(zx::channel remote, async_dispatcher_t* dispatcher);
// Public method for test purpose.
inspect::Inspector& inspector() { return inspect_; }
InspectCallStats& DeviceCreateStats();
InspectCallStats& DeviceDestroyStats();
InspectCallStats& DeviceInitStats();
InspectCallStats& DeviceOpenStats();
InspectCallStats& DeviceCloseStats();
InspectCallStats& DeviceAddStats();
InspectCallStats& DeviceRemoveStats();
InspectCallStats& DeviceSuspendStats();
InspectCallStats& DeviceResumeStats();
InspectCallStats& DeviceUnbindStats();
private:
inspect::Inspector inspect_;
zx::vmo inspect_vmo_;
fbl::RefPtr<fs::PseudoDir> diagnostics_dir_;
std::unique_ptr<fs::SynchronousVfs> diagnostics_vfs_;
// Data for nodes stored in static_values_.
std::array<std::optional<DevicePowerStates>, std::size(internal::kDeviceDefaultPowerStates)>
power_states_;
std::array<std::optional<DevicePerformanceStates>, std::size(internal::kDeviceDefaultPerfStates)>
performance_states_;
std::array<std::optional<DeviceSystemPowerStateMapping>,
std::size(internal::kDeviceDefaultStateMapping)>
state_mappings_;
// Reference to nodes with static properties
inspect::ValueList static_values_;
InspectNodeCollection drivers_;
// Driver host call stats.
inspect::Node call_stats_;
std::optional<InspectCallStats> device_create_stats_;
std::optional<InspectCallStats> device_destroy_stats_;
std::optional<InspectCallStats> device_init_stats_;
std::optional<InspectCallStats> device_open_stats_;
std::optional<InspectCallStats> device_close_stats_;
std::optional<InspectCallStats> device_add_stats_;
std::optional<InspectCallStats> device_remove_stats_;
std::optional<InspectCallStats> device_suspend_stats_;
std::optional<InspectCallStats> device_resume_stats_;
std::optional<InspectCallStats> device_unbind_stats_;
inspect::Node& GetCallStatsNode();
void SetDeviceDefaultPowerStates(inspect::Node& parent);
void SetDeviceDefaultPerfStates(inspect::Node& parent);
void SetDeviceDefaultStateMapping(inspect::Node& parent);
};
class DriverInspect {
public:
// |drivers| should outlive DriverInspect class
DriverInspect(InspectNodeCollection& drivers, std::string name);
~DriverInspect();
inspect::Node& driver_node() { return driver_node_; }
InspectNodeCollection& devices() { return devices_; }
void set_name(std::string name) { driver_node_.CreateString("name", name, &static_values_); }
void set_ops(const zx_driver_ops_t* ops);
void set_status(zx_status_t status);
void set_driver_rec(zx_driver_rec_t* driver_rec) {
driver_node_.CreateUint("log_flags", driver_rec->log_flags, &static_values_);
}
private:
inspect::Node driver_node_;
InspectNodeCollection& drivers_;
InspectNodeCollection devices_;
// Reference to nodes with static properties
inspect::ValueList static_values_;
inspect::IntProperty status_;
};
class DeviceInspect {
public:
// |devices| should outlive DeviceInspect class
DeviceInspect(InspectNodeCollection& devices, std::string name);
~DeviceInspect();
inspect::Node& device_node() { return device_node_; }
void set_local_id(uint64_t local_id);
void set_performance_states(const device_performance_state_info_t* performance_states,
uint8_t count);
void set_current_performance_state(uint32_t state);
void set_auto_suspend(bool value);
void set_power_states(const device_power_state_info_t* power_states, uint8_t count);
using SystemPowerStateMapping =
std::array<::llcpp::fuchsia::device::SystemPowerStateInfo,
::llcpp::fuchsia::hardware::power::statecontrol::MAX_SYSTEM_POWER_STATES>;
void set_system_power_state_mapping(const SystemPowerStateMapping& mapping);
void set_composite() { device_node_.CreateBool("composite", true, &static_values_); }
void set_flags(uint32_t flags);
void set_ops(const zx_protocol_device_t* ops);
void set_protocol_id(uint32_t protocol_id);
void increment_instance_count();
void decrement_instance_count();
void increment_child_count();
void decrement_child_count();
void increment_open_count();
void increment_close_count();
void set_parent(fbl::RefPtr<zx_device> parent);
InspectCallStats& ReadOpStats();
InspectCallStats& WriteOpStats();
InspectCallStats& MessageOpStats();
private:
inspect::Node device_node_;
InspectNodeCollection& devices_;
// Reference to nodes with static properties
inspect::ValueList static_values_;
inspect::UintProperty local_id_;
inspect::StringProperty flags_;
inspect::StringProperty ops_;
inspect::StringProperty parent_;
inspect::BoolProperty auto_suspend_;
inspect::UintProperty child_count_;
inspect::UintProperty instance_count_;
inspect::UintProperty open_count_;
inspect::UintProperty close_count_;
inspect::Node call_stats_;
std::optional<InspectCallStats> read_stats_;
std::optional<InspectCallStats> write_stats_;
std::optional<InspectCallStats> message_stats_;
inspect::Node& GetCallStatsNode();
std::array<std::optional<DevicePowerStates>, ::llcpp::fuchsia::device::MAX_DEVICE_POWER_STATES>
power_states_{};
inspect::Node power_states_node_;
std::array<std::optional<DevicePerformanceStates>,
::llcpp::fuchsia::device::MAX_DEVICE_PERFORMANCE_STATES>
performance_states_{};
inspect::Node performance_states_node_;
inspect::UintProperty current_performance_state_;
std::array<std::optional<DeviceSystemPowerStateMapping>,
::llcpp::fuchsia::hardware::power::statecontrol::MAX_SYSTEM_POWER_STATES>
system_power_states_mapping_{};
inspect::Node system_power_states_node_;
};
#endif // SRC_DEVICES_BIN_DRIVER_HOST_INSPECT_H_