228 lines
5.8 KiB
C++
228 lines
5.8 KiB
C++
/*
|
|
* 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;
|
|
}
|