From 3d2d3b2c10f33993b3e314fdac8f51948fd06983 Mon Sep 17 00:00:00 2001 From: Christian Gmeiner Date: Tue, 15 Oct 2024 11:31:49 +0200 Subject: [PATCH] broadcom: Add perfetto data source Signed-off-by: Christian Gmeiner Reviewed-by: Iago Toral Quiroga Part-of: --- src/broadcom/ds/meson.build | 42 +++++++ src/broadcom/ds/v3d_pps_driver.cc | 181 ++++++++++++++++++++++++++++++ src/broadcom/ds/v3d_pps_driver.h | 41 +++++++ src/broadcom/meson.build | 4 + 4 files changed, 268 insertions(+) create mode 100644 src/broadcom/ds/meson.build create mode 100644 src/broadcom/ds/v3d_pps_driver.cc create mode 100644 src/broadcom/ds/v3d_pps_driver.h diff --git a/src/broadcom/ds/meson.build b/src/broadcom/ds/meson.build new file mode 100644 index 00000000000..5f003869164 --- /dev/null +++ b/src/broadcom/ds/meson.build @@ -0,0 +1,42 @@ +# Copyright © 2024 Raspberry Pi Ltd +# Copyright © 2021 Collabora, Ltd. +# Copyright © 2021 Google, Inc +# SPDX-License-Identifier: MIT + +pps_broadcom_lib = static_library( + 'broadcom-dds', + sources: [ + 'v3d_pps_driver.cc', + 'v3d_pps_driver.h', + ], + include_directories: [ + inc_tool, + inc_broadcom, + inc_include, + ], + dependencies: [ + dep_libdrm, + dep_perfetto, + idep_broadcom_perfcntrs, + ], + c_args: [no_override_init_args], +) + +pps_broadcom_dep = declare_dependency( + link_with: [ + pps_broadcom_lib, + libbroadcom_v3d, + ], + include_directories: [ + inc_tool, + ], + compile_args: [ + '-DPPS_V3D', + ], +) + +pps_datasources += pps_broadcom_dep +pps_includes += [ + inc_include, + inc_broadcom, +] diff --git a/src/broadcom/ds/v3d_pps_driver.cc b/src/broadcom/ds/v3d_pps_driver.cc new file mode 100644 index 00000000000..563c8e5af99 --- /dev/null +++ b/src/broadcom/ds/v3d_pps_driver.cc @@ -0,0 +1,181 @@ +/* + * Copyright © 2024 Raspberry Pi Ltd + * SPDX-License-Identifier: MIT + */ + +#include "v3d_pps_driver.h" + +#include +#include +#include + +#include "perfcntrs/v3d_perfcntrs.h" +#include + +namespace pps +{ + +uint64_t +V3DDriver::get_min_sampling_period_ns() +{ + return 100000; +} + +bool +V3DDriver::init_perfcnt() +{ + const char *v3d_ds_counter_env = getenv("V3D_DS_COUNTER"); + if (!v3d_ds_counter_env || v3d_ds_counter_env[0] == '\0') + return false; + + bool success = v3d_get_device_info(drm_device.fd, &devinfo, &drmIoctl); + if (!success) + return false; + + perfcntrs = v3d_perfcntrs_init(&devinfo, drm_device.fd); + if (!perfcntrs) + return false; + + groups.clear(); + counters.clear(); + enabled_counters.clear(); + + struct drm_v3d_perfmon_create createreq = { 0 }; + CounterGroup group = {}; + + char *dup = strdup(v3d_ds_counter_env); + char *name = strtok(dup, ","); + while (name != NULL && createreq.ncounters < DRM_V3D_MAX_PERF_COUNTERS) { + const struct v3d_perfcntr_desc *desc = v3d_perfcntrs_get_by_name(perfcntrs, name); + if (desc) { + Counter counter_desc = {}; + + counter_desc.units = Counter::Units::None; + counter_desc.id = createreq.ncounters; + counter_desc.name = desc->name; + counter_desc.group = group.id; + counter_desc.getter = [this]( + const Counter &c, const Driver &dri) -> Counter::Value { + return static_cast(values[c.id]); + }; + + counters.emplace_back(std::move(counter_desc)); + createreq.counters[createreq.ncounters++] = desc->index; + } else { + PERFETTO_ELOG("Unkown performance counter name: %s", name); + } + + name = strtok(NULL, ","); + } + + free(dup); + + if (createreq.ncounters == 0) + return false; + + int ret = drmIoctl(drm_device.fd, DRM_IOCTL_V3D_PERFMON_CREATE, &createreq); + if (ret != 0) + PERFETTO_FATAL("Failed to create perfmon %s", strerror(errno)); + + perfmon_id = createreq.id; + + return true; +} + +void +V3DDriver::enable_counter(uint32_t counter_id) +{ + enabled_counters.push_back(counters[counter_id]); +} + +void +V3DDriver::enable_all_counters() +{ + enabled_counters.reserve(counters.size()); + enabled_counters.insert(enabled_counters.end(), counters.begin(), counters.end()); +} + +void +V3DDriver::enable_perfcnt(uint64_t sampling_period_ns) +{ + struct drm_v3d_perfmon_set_global globalreq = { + .id = perfmon_id, + }; + + int ret = drmIoctl(drm_device.fd, DRM_IOCTL_V3D_PERFMON_SET_GLOBAL, &globalreq); + if (ret != 0) { + if (errno == ENOTTY) + PERFETTO_FATAL("Failed to set global perfmon. Feature not available - update your kernel"); + else + PERFETTO_FATAL("Failed to set global perfmon %s", strerror(errno)); + } +} + +void +V3DDriver::disable_perfcnt() +{ + struct drm_v3d_perfmon_set_global globalreq = { + .flags = DRM_V3D_PERFMON_CLEAR_GLOBAL, + .id = perfmon_id, + }; + + int ret = drmIoctl(drm_device.fd, DRM_IOCTL_V3D_PERFMON_SET_GLOBAL, &globalreq); + if (ret != 0) + PERFETTO_FATAL("Failed to clear global perfmon %s", strerror(errno)); + + struct drm_v3d_perfmon_destroy destroyreq = { + .id = perfmon_id, + }; + + ret = drmIoctl(drm_device.fd, DRM_IOCTL_V3D_PERFMON_DESTROY, &destroyreq); + if (ret != 0) + PERFETTO_FATAL("Failed to destroy perfmon %s", strerror(errno)); +} + +bool +V3DDriver::dump_perfcnt() +{ + last_dump_ts = perfetto::base::GetBootTimeNs().count(); + + struct drm_v3d_perfmon_get_values req = { + .id = perfmon_id, + .values_ptr = (uintptr_t)values, + }; + + int ret = drmIoctl(drm_device.fd, DRM_IOCTL_V3D_PERFMON_GET_VALUES, &req); + if (ret != 0) { + PERFETTO_FATAL("Can't request perfmon counters values\n"); + return false; + } + + return true; +} + +uint64_t +V3DDriver::next() +{ + auto ret = last_dump_ts; + last_dump_ts = 0; + return ret; +} + +uint32_t +V3DDriver::gpu_clock_id() const +{ + return perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME; +} + +uint64_t +V3DDriver::gpu_timestamp() const +{ + return perfetto::base::GetBootTimeNs().count(); +} + +bool +V3DDriver::cpu_gpu_timestamp(uint64_t &, uint64_t &) const +{ + /* Not supported */ + return false; +} + +} // namespace pps diff --git a/src/broadcom/ds/v3d_pps_driver.h b/src/broadcom/ds/v3d_pps_driver.h new file mode 100644 index 00000000000..b37cd43d7da --- /dev/null +++ b/src/broadcom/ds/v3d_pps_driver.h @@ -0,0 +1,41 @@ +/* + * Copyright © 2024 Raspberry Pi Ltd + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include "common/v3d_device_info.h" +#include "drm-uapi/v3d_drm.h" +#include "perfcntrs/v3d_perfcntrs.h" +#include "pps/pps_driver.h" + +namespace pps +{ + +class V3DDriver : public Driver +{ +public: + uint64_t get_min_sampling_period_ns() override; + bool init_perfcnt() override; + void enable_counter(uint32_t counter_id) override; + void enable_all_counters() override; + void enable_perfcnt(uint64_t sampling_period_ns) override; + void disable_perfcnt() override; + bool dump_perfcnt() override; + uint64_t next() override; + uint32_t gpu_clock_id() const override; + uint64_t gpu_timestamp() const override; + bool cpu_gpu_timestamp(uint64_t &cpu_timestamp, + uint64_t &gpu_timestamp) const override; + +private: + struct v3d_device_info devinfo; + struct v3d_perfcntrs *perfcntrs; + uint64_t last_dump_ts = 0; + + unsigned int perfmon_id; + uint64_t values[DRM_V3D_MAX_PERF_COUNTERS]; +}; + +} // namespace pps diff --git a/src/broadcom/meson.build b/src/broadcom/meson.build index d92c6f9f69a..be6f6d2d5b8 100644 --- a/src/broadcom/meson.build +++ b/src/broadcom/meson.build @@ -75,6 +75,10 @@ libbroadcom_v3d = static_library( subdir('perfcntrs') +if with_perfetto and (with_datasources.contains('v3d') or with_datasources.contains('auto')) + subdir('ds') +endif + if with_broadcom_vk subdir('vulkan') endif