From 513d1baaea5eeef3d9bcfdf9f6e2180db8924236 Mon Sep 17 00:00:00 2001 From: Antonio Caggiano Date: Thu, 18 Mar 2021 19:29:33 +0100 Subject: [PATCH] pps: Panfrost pps driver Add the Panfrost pps driver. v2: Human readable names for counter blocks and use `unreachable`. v3: Use libpanfrost_perf to collect counter values. Signed-off-by: Antonio Caggiano Part-of: --- src/panfrost/ds/.clang-format | 21 ++++ src/panfrost/ds/meson.build | 31 ++++++ src/panfrost/ds/pan_pps_driver.cc | 160 ++++++++++++++++++++++++++++++ src/panfrost/ds/pan_pps_driver.h | 61 ++++++++++++ src/panfrost/ds/pan_pps_perf.cc | 89 +++++++++++++++++ src/panfrost/ds/pan_pps_perf.h | 50 ++++++++++ src/panfrost/meson.build | 4 + src/tool/pps/pps_driver.cc | 8 ++ 8 files changed, 424 insertions(+) create mode 100644 src/panfrost/ds/.clang-format create mode 100644 src/panfrost/ds/meson.build create mode 100644 src/panfrost/ds/pan_pps_driver.cc create mode 100644 src/panfrost/ds/pan_pps_driver.h create mode 100644 src/panfrost/ds/pan_pps_perf.cc create mode 100644 src/panfrost/ds/pan_pps_perf.h diff --git a/src/panfrost/ds/.clang-format b/src/panfrost/ds/.clang-format new file mode 100644 index 00000000000..41203078b2b --- /dev/null +++ b/src/panfrost/ds/.clang-format @@ -0,0 +1,21 @@ +BasedOnStyle: WebKit +AlignTrailingComments: 'true' +AllowAllParametersOfDeclarationOnNextLine: 'false' +AllowShortFunctionsOnASingleLine: None +AlwaysBreakBeforeMultilineStrings: 'true' +BinPackArguments: 'false' +BinPackParameters: 'false' +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Linux +ColumnLimit: '100' +Cpp11BracedListStyle: 'true' +KeepEmptyLinesAtTheStartOfBlocks: 'false' +NamespaceIndentation: None +PointerAlignment: Right +SortIncludes: 'true' +SpaceAfterTemplateKeyword: 'false' +Standard: Cpp11 +TabWidth: '3' +IndentWidth: '3' +ConstructorInitializerIndentWidth: '3' +ContinuationIndentWidth: '3' diff --git a/src/panfrost/ds/meson.build b/src/panfrost/ds/meson.build new file mode 100644 index 00000000000..a31a71561f2 --- /dev/null +++ b/src/panfrost/ds/meson.build @@ -0,0 +1,31 @@ +# Copyright © 2020 Collabora, Ltd. +# Author: Antonio Caggiano +# Author: Robert Beckett +# +# SPDX-License-Identifier: MIT + +pps_panfrost_sources = [ + 'pan_pps_perf.cc', + 'pan_pps_driver.cc' +] + +pps_panfrost_includes = [inc_include, inc_src, inc_tool] + +pps_panfrost_lib = static_library( + 'pps-panfrost', + sources: pps_panfrost_sources, + include_directories: pps_panfrost_includes, + dependencies: [dep_libdrm, dep_perfetto, libpanfrost_dep, dep_panfrost_perf], + cpp_args: '-std=c++17' +) + +compile_args_pps_panfrost = ['-DPPS_PANFROST'] + +pps_panfrost_dep = declare_dependency( + link_with: pps_panfrost_lib, + include_directories: pps_panfrost_includes, + compile_args: compile_args_pps_panfrost +) + +pps_datasources += pps_panfrost_dep +with_datasources += 'panfrost' diff --git a/src/panfrost/ds/pan_pps_driver.cc b/src/panfrost/ds/pan_pps_driver.cc new file mode 100644 index 00000000000..fbe9263748d --- /dev/null +++ b/src/panfrost/ds/pan_pps_driver.cc @@ -0,0 +1,160 @@ +/* + * Copyright © 2019-2021 Collabora, Ltd. + * Author: Antonio Caggiano + * Author: Rohan Garg + * Author: Robert Beckett + * + * SPDX-License-Identifier: MIT + */ + +#include "pan_pps_driver.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace pps +{ +PanfrostDriver::PanfrostDriver() +{ +} + +PanfrostDriver::~PanfrostDriver() +{ +} + +uint64_t PanfrostDriver::get_min_sampling_period_ns() +{ + return 1000000; +} + +uint32_t find_id_within_group(uint32_t counter_id, const struct panfrost_perf_config *cfg) +{ + for (uint32_t cat_id = 0; cat_id < cfg->n_categories; ++cat_id) { + const struct panfrost_perf_category *cat = &cfg->categories[cat_id]; + if (counter_id < cat->n_counters) { + break; + } + counter_id -= cat->n_counters; + } + + return counter_id; +} + +std::pair, std::vector> +PanfrostDriver::create_available_counters(const PanfrostPerf &perf) +{ + std::pair, std::vector> ret; + auto &[groups, counters] = ret; + + size_t cid = 0; + + for (uint32_t gid = 0; gid < perf.perf->cfg->n_categories; ++gid) { + const auto &category = perf.perf->cfg->categories[gid]; + CounterGroup group = {}; + group.id = gid; + group.name = category.name; + + for (; cid < category.n_counters; ++cid) { + Counter counter = {}; + counter.id = cid; + counter.group = gid; + + uint32_t id_within_group = find_id_within_group(cid, perf.perf->cfg); + counter.name = category.counters[id_within_group].name; + + counter.set_getter([](const Counter &c, const Driver &d) { + auto &pan_driver = PanfrostDriver::into(d); + struct panfrost_perf *perf = pan_driver.perf->perf; + uint32_t id_within_group = find_id_within_group(c.id, perf->cfg); + const auto counter = &perf->cfg->categories[c.group].counters[id_within_group]; + return int64_t(panfrost_perf_counter_read(counter, perf)); + }); + + group.counters.push_back(cid); + + counters.emplace_back(counter); + } + + groups.push_back(group); + } + + return ret; +} + +bool PanfrostDriver::init_perfcnt() +{ + if (!dev) { + dev = std::make_unique(drm_device.fd); + } + if (!perf) { + perf = std::make_unique(*dev); + } + if (groups.empty() && counters.empty()) { + std::tie(groups, counters) = create_available_counters(*perf); + } + return true; +} + +void PanfrostDriver::enable_counter(const uint32_t counter_id) +{ + enabled_counters.push_back(counters[counter_id]); +} + +void PanfrostDriver::enable_all_counters() +{ + enabled_counters.resize(counters.size()); + for (size_t i = 0; i < counters.size(); ++i) { + enabled_counters[i] = counters[i]; + } +} + +void PanfrostDriver::enable_perfcnt(const uint64_t /* sampling_period_ns */) +{ + auto res = perf->enable(); + if (!check(res, "Failed to enable performance counters")) { + if (res == -ENOSYS) { + PERFETTO_FATAL("Please enable unstable ioctls with: modprobe panfrost unstable_ioctls=1"); + } + PERFETTO_FATAL("Please verify graphics card"); + } +} + +bool PanfrostDriver::dump_perfcnt() +{ + last_dump_ts = perfetto::base::GetBootTimeNs().count(); + + // Dump performance counters to buffer + if (!check(perf->dump(), "Failed to dump performance counters")) { + PERFETTO_ELOG("Skipping sample"); + return false; + } + + return true; +} + +uint64_t PanfrostDriver::next() +{ + auto ret = last_dump_ts; + last_dump_ts = 0; + return ret; +} + +void PanfrostDriver::disable_perfcnt() +{ + perf->disable(); + perf.reset(); + dev.reset(); + groups.clear(); + counters.clear(); + enabled_counters.clear(); +} + +} // namespace pps diff --git a/src/panfrost/ds/pan_pps_driver.h b/src/panfrost/ds/pan_pps_driver.h new file mode 100644 index 00000000000..de764b18aae --- /dev/null +++ b/src/panfrost/ds/pan_pps_driver.h @@ -0,0 +1,61 @@ +/* + * Copyright © 2020-2021 Collabora, Ltd. + * Author: Antonio Caggiano + * Author: Rohan Garg + * Author: Robert Beckett + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include + +#include "pan_pps_perf.h" + +namespace pps +{ +/// @brief Panfrost implementation of PPS driver. +/// This driver queries the GPU through `drm/panfrost_drm.h`, using performance counters ioctls, +/// which can be enabled by setting a kernel parameter: `modprobe panfrost unstable_ioctls=1`. +/// The ioctl needs a buffer to copy data from kernel to user space. +class PanfrostDriver : public Driver +{ + public: + static inline PanfrostDriver &into(Driver &dri); + static inline const PanfrostDriver &into(const Driver &dri); + + /// @param A list of mali counter names + /// @return A pair with two lists: counter groups and available counters + static std::pair, std::vector> create_available_counters( + const PanfrostPerf& perf); + + PanfrostDriver(); + ~PanfrostDriver(); + + 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; + + uint64_t last_dump_ts = 0; + + std::unique_ptr dev = nullptr; + std::unique_ptr perf = nullptr; +}; + +PanfrostDriver &PanfrostDriver::into(Driver &dri) +{ + return reinterpret_cast(dri); +} + +const PanfrostDriver &PanfrostDriver::into(const Driver &dri) +{ + return reinterpret_cast(dri); +} + +} // namespace pps diff --git a/src/panfrost/ds/pan_pps_perf.cc b/src/panfrost/ds/pan_pps_perf.cc new file mode 100644 index 00000000000..e8d4a85cf60 --- /dev/null +++ b/src/panfrost/ds/pan_pps_perf.cc @@ -0,0 +1,89 @@ +#include "pan_pps_perf.h" + +#include +#include +#include +#include + +namespace pps +{ +PanfrostDevice::PanfrostDevice(int fd) + : ctx {ralloc_context(nullptr)} + , dev {reinterpret_cast(new struct panfrost_device())} +{ + assert(fd >= 0); + panfrost_open_device(ctx, fd, dev); +} + +PanfrostDevice::~PanfrostDevice() +{ + if (ctx) { + panfrost_close_device(dev); + } + if (dev) { + delete dev; + } +} + +PanfrostDevice::PanfrostDevice(PanfrostDevice &&o) + : ctx {o.ctx} + , dev {o.dev} +{ + o.ctx = nullptr; + o.dev = nullptr; +} + +PanfrostDevice &PanfrostDevice::operator=(PanfrostDevice &&o) +{ + std::swap(ctx, o.ctx); + std::swap(dev, o.dev); + return *this; +} + +PanfrostPerf::PanfrostPerf(const PanfrostDevice& dev) + : perf {reinterpret_cast(rzalloc(nullptr, struct panfrost_perf))} +{ + assert(perf); + assert(dev.dev); + panfrost_perf_init(perf, dev.dev); +} + +PanfrostPerf::~PanfrostPerf() +{ + if (perf) { + panfrost_perf_disable(perf); + ralloc_free(perf); + } +} + +PanfrostPerf::PanfrostPerf(PanfrostPerf &&o) + : perf {o.perf} +{ + o.perf = nullptr; +} + +PanfrostPerf &PanfrostPerf::operator=(PanfrostPerf &&o) +{ + std::swap(perf, o.perf); + return *this; +} + +int PanfrostPerf::enable() const +{ + assert(perf); + return panfrost_perf_enable(perf); +} + +void PanfrostPerf::disable() const +{ + assert(perf); + panfrost_perf_disable(perf); +} + +int PanfrostPerf::dump() const +{ + assert(perf); + return panfrost_perf_dump(perf); +} + +} // namespace pps diff --git a/src/panfrost/ds/pan_pps_perf.h b/src/panfrost/ds/pan_pps_perf.h new file mode 100644 index 00000000000..48ae2f58e53 --- /dev/null +++ b/src/panfrost/ds/pan_pps_perf.h @@ -0,0 +1,50 @@ +/* + * Copyright © 2021 Collabora, Ltd. + * Author: Antonio Caggiano + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +struct panfrost_device; +struct panfrost_perf; + +namespace pps +{ +class PanfrostDevice +{ + public: + PanfrostDevice(int fd); + ~PanfrostDevice(); + + PanfrostDevice(const PanfrostDevice &) = delete; + PanfrostDevice &operator=(const PanfrostDevice &) = delete; + + PanfrostDevice(PanfrostDevice&&); + PanfrostDevice& operator=(PanfrostDevice&&); + + void *ctx = nullptr; + struct panfrost_device* dev = nullptr; +}; + +class PanfrostPerf +{ + public: + PanfrostPerf(const PanfrostDevice& dev); + ~PanfrostPerf(); + + PanfrostPerf(const PanfrostPerf &) = delete; + PanfrostPerf &operator=(const PanfrostPerf &) = delete; + + PanfrostPerf(PanfrostPerf&&); + PanfrostPerf& operator=(PanfrostPerf&&); + + int enable() const; + void disable() const; + int dump() const; + + struct panfrost_perf *perf = nullptr; +}; + +} // namespace pps diff --git a/src/panfrost/meson.build b/src/panfrost/meson.build index cd6febe7877..ae4ea71b77c 100644 --- a/src/panfrost/meson.build +++ b/src/panfrost/meson.build @@ -70,3 +70,7 @@ bifrost_compiler = executable( if with_panfrost_vk subdir('vulkan') endif + +if with_perfetto and (with_datasources.contains('panfrost') or with_datasources.contains('auto')) + subdir('ds') +endif diff --git a/src/tool/pps/pps_driver.cc b/src/tool/pps/pps_driver.cc index 239c9666dba..e04c36e6520 100644 --- a/src/tool/pps/pps_driver.cc +++ b/src/tool/pps/pps_driver.cc @@ -21,6 +21,10 @@ #include "intel/ds/intel_pps_driver.h" #endif // PPS_INTEL +#ifdef PPS_PANFROST +#include "panfrost/ds/pan_pps_driver.h" +#endif // PPS_PANFROST + #include "pps.h" #include "pps_algorithm.h" @@ -38,6 +42,10 @@ std::unordered_map> create_supported_driver map.emplace("i915", std::make_unique()); #endif // PPS_INTEL +#ifdef PPS_PANFROST + map.emplace("panfrost", std::make_unique()); +#endif // PPS_PANFROST + return map; }