blob: ac0cfcb793366e27aa949aa20e99e8e588c4cb9c [file] [log] [blame] [edit]
/**
* @brief GPU telemetry client command line tool
*
* SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES.
* All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#include "gpu-telemetry/client.h"
#include "libnsm/base.h"
#include <iostream>
#include <iomanip>
#include <vector>
#include <string>
#include <cstring>
#include <csignal>
#include <chrono>
#include <thread>
namespace {
volatile sig_atomic_t running = 1;
void signal_handler(int) {
running = 0;
}
void print_usage(const char* program) {
std::cerr << "Usage: " << program << " [options] <hex-message>\n"
<< "Options:\n"
<< " -s <socket> Socket path (default: /tmp/gpu-telemetry.sock)\n"
<< " -i <interval> Repeat interval in ms (default: 0 = once)\n"
<< " -t Temperature request mode\n"
<< " -x Print responses in hex\n"
<< " -h Show this help message\n"
<< "\nExamples:\n"
<< " " << program << " -t # Get temperature\n"
<< " " << program << " -t -i 1000 # Monitor temperature\n"
<< " " << program << " -x 0102030405 # Send custom message\n";
}
// Callback to handle responses
void message_callback(void* user_data,
const uint8_t* response,
size_t response_len) {
bool hex_mode = *static_cast<bool*>(user_data);
if (hex_mode) {
// Print raw hex response
std::cout << "Response: ";
for (size_t i = 0; i < response_len; i++) {
std::cout << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<int>(response[i]) << " ";
}
std::cout << std::dec << std::endl;
}
else {
// Try to parse as NSM response
const nsm_msg* msg = reinterpret_cast<const nsm_msg*>(response);
if (response_len >= sizeof(nsm_msg)) {
uint8_t cc = msg->header[0];
uint16_t data_size = *reinterpret_cast<const uint16_t*>(&msg->header[1]);
uint16_t reason = *reinterpret_cast<const uint16_t*>(&msg->header[3]);
if (cc == NSM_SUCCESS && data_size == sizeof(float)) {
// Parse temperature response
float temp = *reinterpret_cast<const float*>(msg->payload);
std::cout << "Temperature: " << temp << "°C" << std::endl;
}
else {
std::cout << "NSM Response: cc=0x" << std::hex << (int)cc
<< " reason=0x" << reason << std::dec << std::endl;
}
}
}
}
// Convert hex string to bytes
std::vector<uint8_t> hex_to_bytes(const std::string& hex) {
std::vector<uint8_t> bytes;
for (size_t i = 0; i < hex.length(); i += 2) {
bytes.push_back(std::stoul(hex.substr(i, 2), nullptr, 16));
}
return bytes;
}
}
int main(int argc, char* argv[]) {
std::string socket_path = "/tmp/gpu-telemetry.sock";
int interval_ms = 0;
bool temp_mode = false;
bool hex_mode = false;
// Parse command line options
int opt;
while ((opt = getopt(argc, argv, "s:i:txh")) != -1) {
switch (opt) {
case 's':
socket_path = optarg;
break;
case 'i':
interval_ms = std::atoi(optarg);
break;
case 't':
temp_mode = true;
break;
case 'x':
hex_mode = true;
break;
case 'h':
print_usage(argv[0]);
return 0;
default:
print_usage(argv[0]);
return 1;
}
}
// Check arguments
if (!temp_mode && optind >= argc) {
std::cerr << "Error: Message required in hex mode\n";
print_usage(argv[0]);
return 1;
}
try {
// Initialize client
gpu_telemetry_ctx* ctx;
if (gpu_telemetry_init(&ctx) < 0) {
throw std::runtime_error("Failed to initialize client");
}
// Set up signal handling
struct sigaction sa = {};
sa.sa_handler = signal_handler;
sigaction(SIGINT, &sa, nullptr);
sigaction(SIGTERM, &sa, nullptr);
// Prepare message
std::vector<uint8_t> message;
if (temp_mode) {
// Create temperature request
nsm_msg req = {};
encode_common_req(0x01, NSM_TYPE_TEMPERATURE,
NSM_GET_TEMPERATURE_READING, &req);
message.assign(reinterpret_cast<uint8_t*>(&req),
reinterpret_cast<uint8_t*>(&req) + sizeof(req));
}
else {
// Parse hex message
message = hex_to_bytes(argv[optind]);
}
// Send message(s)
do {
if (gpu_telemetry_send_message(ctx, message.data(), message.size(),
message_callback, &hex_mode) < 0) {
throw std::runtime_error("Failed to send message");
}
if (interval_ms > 0) {
std::this_thread::sleep_for(
std::chrono::milliseconds(interval_ms));
}
} while (running && interval_ms > 0);
gpu_telemetry_free(ctx);
return 0;
}
catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
}