Fichiers
rocm-systems/projects/amdsmi/src/amd_smi/amd_smi_utils.cc
T
Charis Poag 4f502e5dab Add vcn and jpeg activity
Changes:
    - Add new engine field vcn_activity (from 1.4/1.5
      gpu_metrics
    - Updated log output to enhance view of gpu_metric
      data as json pretty print
    - Added new fields provided in 1.5
    - Added unit overview in python API, CLI is WIP

Signed-off-by: Charis Poag <Charis.Poag@amd.com>
Change-Id: I7d9f29e7ecc35dcd0697814c222cdd02b0d5518e


[ROCm/amdsmi commit: 8f3861e1d9]
2023-12-15 22:18:46 -05:00

572 lignes
16 KiB
C++

/* * Copyright (C) 2023 Advanced Micro Devices. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <dirent.h>
#include <sys/types.h>
#include <memory>
#include <random>
#include <fstream>
#include <iostream>
#include <regex>
#include <sstream>
#include <sys/ioctl.h>
#include <algorithm>
#include <limits.h>
#include "amd_smi/impl/amd_smi_utils.h"
#include "shared_mutex.h" // NOLINT
#include "rocm_smi/rocm_smi_logger.h"
static const uint32_t kAmdGpuId = 0x1002;
static bool isAMDGPU(std::string dev_path) {
std::string vend_path = dev_path + "/device/vendor";
if (!amd::smi::FileExists(vend_path.c_str())) {
return false;
}
std::ifstream fs;
fs.open(vend_path);
if (!fs.is_open()) {
return false;
}
uint32_t vendor_id;
fs >> std::hex >> vendor_id;
fs.close();
if (vendor_id == kAmdGpuId) {
return true;
}
return false;
}
amdsmi_status_t smi_amdgpu_find_hwmon_dir(amd::smi::AMDSmiGPUDevice *device, std::string* full_path)
{
if (!device->check_if_drm_is_supported()) {
return AMDSMI_STATUS_NOT_SUPPORTED;
}
if (full_path == nullptr) {
return AMDSMI_STATUS_API_FAILED;
}
SMIGPUDEVICE_MUTEX(device->get_mutex())
DIR *dh;
struct dirent * contents;
std::string device_path = "/sys/class/drm/" + device->get_gpu_path();
std::string directory_path = device_path + "/device/hwmon/";
if (!isAMDGPU(device_path)) {
return AMDSMI_STATUS_NOT_SUPPORTED;
}
dh = opendir(directory_path.c_str());
if (!dh) {
return AMDSMI_STATUS_NOT_SUPPORTED;
}
/*
First directory is '.', second directory is '..' and third directory is
valid directory for reading sysfs node
*/
while ((contents = readdir(dh)) != NULL) {
std::string name = contents->d_name;
if (name.find("hwmon", 0) != std::string::npos)
*full_path = directory_path + name;
}
closedir(dh);
return AMDSMI_STATUS_SUCCESS;
}
amdsmi_status_t smi_amdgpu_get_board_info(amd::smi::AMDSmiGPUDevice* device, amdsmi_board_info_t *info) {
if (!device->check_if_drm_is_supported()) {
return AMDSMI_STATUS_NOT_SUPPORTED;
}
SMIGPUDEVICE_MUTEX(device->get_mutex())
std::string model_number_path = "/sys/class/drm/" + device->get_gpu_path() + std::string("/device/product_number");
std::string product_serial_path = "/sys/class/drm/" + device->get_gpu_path() + std::string("/device/serial_number");
std::string fru_id_path = "/sys/class/drm/" + device->get_gpu_path() + std::string("/device/fru_id");
std::string manufacturer_name_path = "/sys/class/drm/" + device->get_gpu_path() + std::string("/device/manufacturer");
std::string product_name_path = "/sys/class/drm/" + device->get_gpu_path() + std::string("/device/product_name");
FILE *fp;
fp = fopen(model_number_path.c_str(), "rb");
if (fp) {
fgets(info->model_number, sizeof(info->model_number), fp);
fclose(fp);
}
fp = fopen(product_serial_path.c_str(), "rb");
if (fp) {
fgets(info->product_serial, sizeof(info->product_serial), fp);
fclose(fp);
}
fp = fopen(fru_id_path.c_str(), "rb");
if (fp) {
fgets(info->fru_id, sizeof(info->fru_id), fp);
fclose(fp);
}
fp = fopen(manufacturer_name_path.c_str(), "rb");
if (fp) {
fgets(info->manufacturer_name, sizeof(info->manufacturer_name), fp);
fclose(fp);
}
fp = fopen(product_name_path.c_str(), "rb");
if (fp) {
fgets(info->product_name, sizeof(info->product_name), fp);
fclose(fp);
}
std::ostringstream ss;
ss << __PRETTY_FUNCTION__
<< "Returning status = AMDSMI_STATUS_SUCCESS"
<< " | model_number_path = " << model_number_path
<< "; info->model_number: " << info->model_number
<< "\n product_serial_path = " << product_serial_path
<< "; info->product_serial: " << info->product_serial
<< "\n fru_id_path = " << fru_id_path
<< "; info->fru_id: " << info->fru_id
<< "\n manufacturer_name_path = " << manufacturer_name_path
<< "; info->manufacturer_name: " << info->manufacturer_name
<< "\n product_name_path = " << product_name_path
<< "; info->product_name: " << info->product_name;
LOG_INFO(ss);
return AMDSMI_STATUS_SUCCESS;
}
amdsmi_status_t smi_amdgpu_get_power_cap(amd::smi::AMDSmiGPUDevice* device, int *cap)
{
if (!device->check_if_drm_is_supported()) {
return AMDSMI_STATUS_NOT_SUPPORTED;
}
constexpr int DATA_SIZE = 10;
char val[DATA_SIZE];
std::string fullpath;
amdsmi_status_t ret = AMDSMI_STATUS_SUCCESS;
ret = smi_amdgpu_find_hwmon_dir(device, &fullpath);
SMIGPUDEVICE_MUTEX(device->get_mutex())
if (ret)
return ret;
fullpath += "/power1_cap";
std::ifstream file(fullpath.c_str(), std::ifstream::in);
if (!file.is_open()) {
return AMDSMI_STATUS_API_FAILED;
}
file.getline(val, DATA_SIZE);
if (sscanf(val, "%d", cap) < 0) {
return AMDSMI_STATUS_API_FAILED;
}
// Dividing by 1000000 to get measurement in Watts
*cap /= 1000000;
return AMDSMI_STATUS_SUCCESS;
}
amdsmi_status_t smi_amdgpu_get_ranges(amd::smi::AMDSmiGPUDevice* device, amdsmi_clk_type_t domain,
int *max_freq, int *min_freq, int *num_dpm, int *sleep_state_freq)
{
if (!device->check_if_drm_is_supported()) {
return AMDSMI_STATUS_NOT_SUPPORTED;
}
SMIGPUDEVICE_MUTEX(device->get_mutex())
std::string fullpath = "/sys/class/drm/" + device->get_gpu_path() + "/device";
switch (domain) {
case CLK_TYPE_GFX:
fullpath += "/pp_dpm_sclk";
break;
case CLK_TYPE_MEM:
fullpath += "/pp_dpm_mclk";
break;
case CLK_TYPE_VCLK0:
fullpath += "/pp_dpm_vclk";
break;
case CLK_TYPE_VCLK1:
fullpath += "/pp_dpm_vclk1";
break;
default:
return AMDSMI_STATUS_INVAL;
}
std::ifstream ranges(fullpath.c_str());
if (ranges.fail()) {
return AMDSMI_STATUS_API_FAILED;
}
unsigned int max, min, dpm, sleep_freq;
char str[10];
char single_char;
max = 0;
min = UINT_MAX;
dpm = 0;
sleep_freq = UINT_MAX;
for (std::string line; getline(ranges, line);) {
unsigned int dpm_level, freq;
char firstChar = line[0];
if (firstChar == 'S') {
if (sscanf(line.c_str(), "%c: %d%s", &single_char, &sleep_freq, str) <= 2) {
ranges.close();
return AMDSMI_STATUS_NO_DATA;
}
} else {
if (sscanf(line.c_str(), "%u: %d%c", &dpm_level, &freq, str) <= 2){
ranges.close();
return AMDSMI_STATUS_IO;
}
max = freq > max ? freq : max;
min = freq < min ? freq: min;
dpm = dpm_level > dpm ? dpm_level : dpm;
}
}
if (num_dpm)
*num_dpm = dpm;
if (max_freq)
*max_freq = max;
if (min_freq)
*min_freq = min;
if (sleep_state_freq)
*sleep_state_freq = sleep_freq;
ranges.close();
return AMDSMI_STATUS_SUCCESS;
}
amdsmi_status_t smi_amdgpu_get_enabled_blocks(amd::smi::AMDSmiGPUDevice* device, uint64_t *enabled_blocks) {
if (!device->check_if_drm_is_supported()) {
return AMDSMI_STATUS_NOT_SUPPORTED;
}
SMIGPUDEVICE_MUTEX(device->get_mutex())
std::string fullpath = "/sys/class/drm/" + device->get_gpu_path() + "/device/ras/features";
std::ifstream f(fullpath.c_str());
std::string tmp_str;
if (f.fail()) {
return AMDSMI_STATUS_API_FAILED;
}
std::string line;
getline(f, line);
std::istringstream f1(line);
f1 >> tmp_str; // ignore
f1 >> tmp_str; // ignore
f1 >> tmp_str;
*enabled_blocks = strtoul(tmp_str.c_str(), nullptr, 16);
f.close();
if (*enabled_blocks == 0 || *enabled_blocks == ULONG_MAX) {
return AMDSMI_STATUS_API_FAILED;
}
return AMDSMI_STATUS_SUCCESS;
}
amdsmi_status_t smi_amdgpu_get_bad_page_info(amd::smi::AMDSmiGPUDevice* device,
uint32_t *num_pages, amdsmi_retired_page_record_t *info) {
if (!device->check_if_drm_is_supported()) {
return AMDSMI_STATUS_NOT_SUPPORTED;
}
SMIGPUDEVICE_MUTEX(device->get_mutex())
std::string line;
std::vector<std::string> badPagesVec;
std::string fullpath = "/sys/class/drm/" + device->get_gpu_path() + std::string("/device/ras/gpu_vram_bad_pages");
std::ifstream fs(fullpath.c_str());
if (fs.fail()) {
return AMDSMI_STATUS_NOT_SUPPORTED;
}
while (std::getline(fs, line)) {
badPagesVec.push_back(line);
}
if (badPagesVec.size() == 0) {
num_pages = 0;
return AMDSMI_STATUS_SUCCESS;
}
// Remove any *trailing* empty (whitespace) lines
while (badPagesVec.size() != 0 &&
badPagesVec.back().find_first_not_of(" \t\n\v\f\r") == std::string::npos) {
badPagesVec.pop_back();
}
*num_pages = static_cast<uint32_t>(badPagesVec.size());
if (info == nullptr) {
return AMDSMI_STATUS_SUCCESS;
}
char status_code;
amdsmi_memory_page_status_t tmp_stat;
std::string junk;
for (uint32_t i = 0; i < *num_pages; ++i) {
std::istringstream fs1(badPagesVec[i]);
fs1 >> std::hex >> info[i].page_address;
fs1 >> junk;
fs1 >> std::hex >> info[i].page_size;
fs1 >> junk;
fs1 >> status_code;
switch (status_code) {
case 'P':
tmp_stat = AMDSMI_MEM_PAGE_STATUS_PENDING;
break;
case 'F':
tmp_stat = AMDSMI_MEM_PAGE_STATUS_UNRESERVABLE;
break;
case 'R':
tmp_stat = AMDSMI_MEM_PAGE_STATUS_RESERVED;
break;
default:
return AMDSMI_STATUS_API_FAILED;
}
info[i].status = tmp_stat;
}
return AMDSMI_STATUS_SUCCESS;
}
amdsmi_status_t smi_amdgpu_get_ecc_error_count(amd::smi::AMDSmiGPUDevice* device, amdsmi_error_count_t *err_cnt) {
if (!device->check_if_drm_is_supported()) {
return AMDSMI_STATUS_NOT_SUPPORTED;
}
SMIGPUDEVICE_MUTEX(device->get_mutex())
char str[10];
std::string fullpath = "/sys/class/drm/" + device->get_gpu_path() + std::string("/device/ras/umc_err_count");
std::ifstream f(fullpath.c_str());
if (f.fail()) {
return AMDSMI_STATUS_NOT_SUPPORTED;
}
std::string line;
getline(f, line);
sscanf(line.c_str(), "%s%ld", str, &(err_cnt->uncorrectable_count));
getline(f, line);
sscanf(line.c_str(), "%s%ld", str, &(err_cnt->correctable_count));
f.close();
return AMDSMI_STATUS_SUCCESS;
}
amdsmi_status_t smi_amdgpu_get_driver_version(amd::smi::AMDSmiGPUDevice* device, int *length, char *version) {
if (!device->check_if_drm_is_supported()) {
return AMDSMI_STATUS_NOT_SUPPORTED;
}
SMIGPUDEVICE_MUTEX(device->get_mutex())
amdsmi_status_t status = AMDSMI_STATUS_SUCCESS;
FILE *fp;
char *tmp, *ptr, *token;
char *ver = NULL;
int i = 0;
size_t len;
if (length)
len = *length < AMDSMI_MAX_DRIVER_VERSION_LENGTH ? *length : AMDSMI_MAX_DRIVER_VERSION_LENGTH;
else
len = AMDSMI_MAX_DRIVER_VERSION_LENGTH;
std::string path = "/sys/module/amdgpu/version";
fp = fopen(path.c_str(), "r");
if (fp == nullptr){
fp = fopen("/proc/version", "r");
if (fp == nullptr) {
status = AMDSMI_STATUS_IO;
return status;
}
len = 0;
if (getline(&ver, &len, fp) <= 0) {
status = AMDSMI_STATUS_IO;
fclose(fp);
free(ver);
return status;
}
fclose(fp);
ptr = ver;
token = strtok_r(ptr, " ", &tmp);
if (!token) {
free(ver);
status = AMDSMI_STATUS_IO;
return status;
}
for (i = 0; i < 2; i++) {
ptr = strtok_r(NULL, " ", &tmp);
if (!ptr)
break;
}
if (i != 2 || !ptr) {
free(ver);
status = AMDSMI_STATUS_IO;
return status;
}
if (length)
len = *length < AMDSMI_MAX_DRIVER_VERSION_LENGTH ? *length :
AMDSMI_MAX_DRIVER_VERSION_LENGTH;
else
len = AMDSMI_MAX_DRIVER_VERSION_LENGTH;
strncpy(version, ptr, len);
free(ver);
} else {
if ((len = getline(&version, &len, fp)) <= 0)
status = AMDSMI_STATUS_IO;
fclose(fp);
if (length) {
*length = version[len-1] == '\n' ? len - 1 : len;
}
version[len-1] = version[len-1] == '\n' ? '\0' : version[len-1];
}
return status;
}
amdsmi_status_t smi_amdgpu_get_pcie_speed_from_pcie_type(uint16_t pcie_type, uint32_t *pcie_speed)
{
switch (pcie_type) {
case 1:
*pcie_speed = 2500;
break;
case 2:
*pcie_speed = 5000;
break;
case 3:
*pcie_speed = 8000;
break;
case 4:
*pcie_speed = 16000;
break;
case 5:
*pcie_speed = 32000;
break;
case 6:
*pcie_speed = 64000;
break;
default:
return AMDSMI_STATUS_API_FAILED;
}
return AMDSMI_STATUS_SUCCESS;
}
amdsmi_status_t smi_amdgpu_get_market_name_from_dev_id(uint32_t device_id, char *market_name)
{
switch (device_id) {
case 0x73c8:
case 0x73c4:
case 0x73c5:
case 0x7460:
case 0x7461:
strcpy(market_name, "NAVI32");
break;
case 0x73a1:
case 0x73ae:
strcpy(market_name, "NAVI21");
break;
case 0x74b4:
case 0x74a0:
strcpy(market_name, "MI300A");
break;
case 0x74a1:
case 0x74b5:
strcpy(market_name, "MI300X-O");
break;
default:
return AMDSMI_STATUS_API_FAILED;
}
return AMDSMI_STATUS_SUCCESS;
}
amdsmi_status_t smi_amdgpu_is_gpu_power_management_enabled(amd::smi::AMDSmiGPUDevice *device,
bool *enabled) {
if (!device->check_if_drm_is_supported()) {
return AMDSMI_STATUS_NOT_SUPPORTED;
}
if (enabled == nullptr) {
return AMDSMI_STATUS_API_FAILED;
}
SMIGPUDEVICE_MUTEX(device->get_mutex())
std::string fullpath = "/sys/class/drm/" + device->get_gpu_path() + std::string("/device/pp_features");
std::ifstream fs(fullpath.c_str());
if (fs.fail()) {
return AMDSMI_STATUS_NOT_SUPPORTED;
}
// ANY line must end with "enabled" and have space before it
const std::regex regex(R"(.*\senabled$)");
std::string line;
while (std::getline(fs, line)) {
// match the whole line against regex, not just substrings
if (std::regex_match(line, regex)) {
*enabled = true;
return AMDSMI_STATUS_SUCCESS;
}
}
*enabled = false;
return AMDSMI_STATUS_SUCCESS;
}