pps: Gfx-pps config tool

Add helpful tool to query pps capabilites such as supported devices,
counters and counter groups, and to dump counter values to stdout.

Signed-off-by: Antonio Caggiano <antonio.caggiano@collabora.com>
Acked-by: Emma Anholt <emma@anholt.net>
Reviewed-by: Rob Clark <robdclark@chromium.org>
Reviewed-by: John Bates <jbates@chromium.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/9652>
This commit is contained in:
Antonio Caggiano 2021-03-30 18:03:33 +02:00 committed by Marge Bot
parent 1cc72b2aef
commit 948f780915
2 changed files with 244 additions and 0 deletions

View File

@ -42,3 +42,20 @@ executable(
cpp_args: '-std=c++17',
install: true
)
config_sources = [
'pps_config.cc'
]
dep_docopt = dependency('docopt', required: false)
if dep_docopt.found()
executable(
'pps-config',
sources: config_sources,
include_directories: [include_pps, inc_src],
dependencies: [dep_pps, dep_docopt],
cpp_args: '-std=c++17',
install: true
)
endif

227
src/tool/pps/pps_config.cc Normal file
View File

@ -0,0 +1,227 @@
/*
* Copyright © 2020-2021 Collabora, Ltd.
* Author: Antonio Caggiano <antonio.caggiano@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include <pps/pps_driver.h>
#include <charconv>
#include <cstdlib>
#include <cstring>
#include <optional>
#include <thread>
#include <docopt/docopt.h>
static const char *USAGE =
R"(pps-config
Usage:
pps-config info
pps-config dump [--gpu=<n>] [--ids=<n>] [--sec=<n>]
pps-config groups [--gpu=<n>]
pps-config counters [--gpu=<n>]
pps-config (-h | --help)
pps-config --version
Options:
-h --help Show this screen.
--version Show version.
--gpu=<n> GPU number to query [default: 0].
--ids=<n> Comma separated list of numbers.
--sec=<n> Seconds to wait before dumping performance counters [default: 1].
)";
// Tool running mode
enum class Mode {
// Show help message
Help,
// Show system information
Info,
// Show list of available counters
Counters,
// Groups
Groups,
// Dump performance counters
Dump,
};
std::vector<std::string_view> split(const std::string &list, const std::string &separator)
{
std::vector<std::string_view> ret;
std::string_view list_view = list;
while (!list_view.empty()) {
size_t pos = list_view.find(separator);
if (pos == std::string::npos) {
ret.push_back(list_view);
break;
}
ret.push_back(list_view.substr(0, pos));
list_view = list_view.substr(pos + separator.length(), list_view.length());
}
return ret;
}
std::optional<uint32_t> to_counter_id(const std::string_view &view)
{
uint32_t counter_id = 0;
auto res = std::from_chars(view.data(), view.data() + view.size(), counter_id);
if (res.ec == std::errc::invalid_argument) {
return std::nullopt;
}
return counter_id;
}
int main(int argc, const char **argv)
{
using namespace pps;
Mode mode = Mode::Help;
auto secs = std::chrono::seconds(1);
uint32_t gpu_num = 0;
std::vector<uint32_t> counter_ids;
auto args =
docopt::docopt(USAGE, {std::next(argv), std::next(argv, argc)}, true, "pps-config 0.3");
if (args["info"].asBool()) {
mode = Mode::Info;
}
if (args["dump"].asBool()) {
mode = Mode::Dump;
}
if (args["--gpu"]) {
gpu_num = static_cast<uint32_t>(args["--gpu"].asLong());
}
if (args["--ids"]) {
auto comma_separated_list = args["--ids"].asString();
std::vector<std::string_view> ids_list = split(comma_separated_list, ",");
for (auto &id : ids_list) {
if (auto counter_id = to_counter_id(id)) {
counter_ids.push_back(*counter_id);
} else {
fprintf(stderr, "Failed to parse counter ids: %s\n", comma_separated_list.c_str());
return EXIT_FAILURE;
}
}
}
if (args["--sec"]) {
secs = std::chrono::seconds(args["--sec"].asLong());
}
if (args["groups"].asBool()) {
mode = Mode::Groups;
}
if (args["counters"].asBool()) {
mode = Mode::Counters;
}
// Docopt shows the help message for us
if (mode == Mode::Help) {
return EXIT_SUCCESS;
}
switch (mode) {
default:
break;
case Mode::Info: {
// Header: device name, and whether it is supported or not
printf("#%4s %16s %16s\n", "num", "device", "support");
auto devices = DrmDevice::create_all();
for (auto &device : devices) {
auto gpu_num = device.gpu_num;
auto name = device.name;
auto driver = Driver::get_driver(std::move(device));
printf(" %4u %16s %16s\n", gpu_num, name.c_str(), driver ? "yes" : "no");
}
break;
}
case Mode::Dump: {
if (auto device = DrmDevice::create(gpu_num)) {
if (auto driver = Driver::get_driver(std::move(device.value()))) {
driver->init_perfcnt();
// Enable counters
if (counter_ids.empty()) {
driver->enable_all_counters();
} else {
for (auto id : counter_ids) {
driver->enable_counter(id);
}
}
driver->enable_perfcnt(std::chrono::nanoseconds(secs).count());
std::this_thread::sleep_for(std::chrono::seconds(secs));
// Try dumping until it succeeds
while (!driver->dump_perfcnt())
;
// Try collecting samples until it succeeds
while (!driver->next())
;
printf("#%32s %32s\n", "counter", "value");
for (auto &counter : driver->enabled_counters) {
printf(" %32s ", counter.name.c_str());
auto value = counter.get_value(*driver);
if (auto d_val = std::get_if<double>(&value)) {
printf("%32f\n", *d_val);
} else if (auto i_val = std::get_if<int64_t>(&value))
printf("%32li\n", *i_val);
else {
printf("%32s\n", "error");
}
}
}
}
break;
}
case Mode::Groups: {
if (auto device = DrmDevice::create(gpu_num)) {
if (auto driver = Driver::get_driver(std::move(device.value()))) {
driver->init_perfcnt();
printf("#%4s %32s\n", "id", "name");
for (auto &group : driver->groups) {
printf(" %4u %32s\n", group.id, group.name.c_str());
}
}
}
break;
}
case Mode::Counters: {
if (auto device = DrmDevice::create(gpu_num)) {
if (auto driver = Driver::get_driver(std::move(device.value()))) {
driver->init_perfcnt();
printf("#%4s %32s\n", "id", "name");
for (uint32_t i = 0; i < driver->counters.size(); ++i) {
auto &counter = driver->counters[i];
printf(" %4u %32s\n", counter.id, counter.name.c_str());
}
}
}
break;
}
} // switch
return EXIT_SUCCESS;
}