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:
parent
1cc72b2aef
commit
948f780915
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue