Restructure the folder

Move rocm_smi related function to rocm_smi folder. Move amd_smi to
top level include/ and src/ folder. Remove obsolte oam folder.
Change the CMakeLists.txt to update folder locations.

Change-Id: I52e6be739e49f3b0545865f25364787f5985e9c3
This commit is contained in:
Bill(Shuzhou) Liu
2022-09-20 14:57:30 -04:00
parent 1ec3a2182e
commit 0c91ef919d
98 changed files with 177 additions and 1715 deletions
File diff suppressed because it is too large Load Diff
+52
View File
@@ -0,0 +1,52 @@
/*
* =============================================================================
* The University of Illinois/NCSA
* Open Source License (NCSA)
*
* Copyright (c) 2022, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Developed by:
*
* AMD Research and AMD ROC Software Development
*
* Advanced Micro Devices, Inc.
*
* www.amd.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal with 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:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimers.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimers in
* the documentation and/or other materials provided with the distribution.
* - Neither the names of <Name of Development Group, Name of Institution>,
* nor the names of its contributors may be used to endorse or promote
* products derived from this Software without specific prior written
* permission.
*
* 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 CONTRIBUTORS 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 WITH THE SOFTWARE.
*
*/
#include <functional>
#include "amd_smi/impl/amd_smi_common.h"
namespace amd {
namespace smi {
} // namespace smi
} // namespace amd
+200
View File
@@ -0,0 +1,200 @@
/*
* =============================================================================
* The University of Illinois/NCSA
* Open Source License (NCSA)
*
* Copyright (c) 2022, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Developed by:
*
* AMD Research and AMD ROC Software Development
*
* Advanced Micro Devices, Inc.
*
* www.amd.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal with 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:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimers.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimers in
* the documentation and/or other materials provided with the distribution.
* - Neither the names of <Name of Development Group, Name of Institution>,
* nor the names of its contributors may be used to endorse or promote
* products derived from this Software without specific prior written
* permission.
*
* 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 CONTRIBUTORS 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 WITH THE SOFTWARE.
*
*/
#include <sys/types.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <xf86drm.h>
#include <string.h>
#include <memory>
#include "amd_smi/impl/amd_smi_drm.h"
#include "amd_smi/impl/amdgpu_drm.h"
namespace amd {
namespace smi {
amdsmi_status_t AMDSmiDrm::init() {
// A few RAII handler
using dir_ptr = std::unique_ptr<DIR, decltype(&closedir)>;
using drm_version_ptr = std::unique_ptr<drmVersion,
decltype(&drmFreeVersion)>;
struct dirent *dir = nullptr;
int fd = -1;
amdsmi_status_t status = lib_loader_.load("libdrm.so");
if (status != AMDSMI_STATUS_SUCCESS) {
return status;
}
// load symbol from libdrm
drm_cmd_write_ = nullptr;
status = lib_loader_.load_symbol(&drm_cmd_write_, "drmCommandWrite");
if (status != AMDSMI_STATUS_SUCCESS) {
return status;
}
using drmGetVersionType = drmVersionPtr (*)(int); // drmGetVersion
using drmFreeVersionType = void (*)(drmVersionPtr); // drmFreeVersion
drmGetVersionType drm_get_version = nullptr;
drmFreeVersionType drm_free_version = nullptr;
status = lib_loader_.load_symbol(&drm_get_version, "drmGetVersion");
if (status != AMDSMI_STATUS_SUCCESS) {
return status;
}
status = lib_loader_.load_symbol(&drm_free_version, "drmFreeVersion");
if (status != AMDSMI_STATUS_SUCCESS) {
return status;
}
auto d = dir_ptr(opendir("/dev/dri/"), &closedir);
if (d == nullptr) return AMDSMI_STATUS_NOT_INIT;
while ((dir = readdir(d.get())) != NULL) {
char* name_cstr = new char[sizeof(dir->d_name) + 10];
auto name = std::unique_ptr<char[]>(name_cstr);
snprintf(name.get(), sizeof(dir->d_name) + 10,
"/dev/dri/%s", dir->d_name);
fd = open(name.get(), O_RDWR | O_CLOEXEC);
if (fd < 0) continue;
auto version = drm_version_ptr(drm_get_version(fd), drm_free_version);
if (strcmp("amdgpu", version->name) ||
strstr(name.get(), "render") == nullptr) {
close(fd);
continue;
}
drm_fds_.push_back(fd);
}
return AMDSMI_STATUS_SUCCESS;
}
amdsmi_status_t AMDSmiDrm::cleanup() {
for (unsigned int i=0; i < drm_fds_.size(); i++) {
close(drm_fds_[i]);
}
drm_fds_.clear();
lib_loader_.unload();
return AMDSMI_STATUS_SUCCESS;
}
amdsmi_status_t AMDSmiDrm::amdgpu_query_info(int fd, unsigned info_id,
unsigned size, void *value) {
if (drm_cmd_write_ == nullptr) return AMDSMI_STATUS_NOT_SUPPORTED;
std::lock_guard<std::mutex> guard(drm_mutex_);
struct drm_amdgpu_info request;
memset(&request, 0, sizeof(request));
request.return_pointer = (uintptr_t)value;
request.return_size = size;
request.query = info_id;
int status = drm_cmd_write_(fd, DRM_AMDGPU_INFO,
&request, sizeof(struct drm_amdgpu_info));
if (status == 0) return AMDSMI_STATUS_SUCCESS;
return AMDSMI_STATUS_DRM_ERROR;
}
amdsmi_status_t AMDSmiDrm::amdgpu_query_fw(int fd, unsigned info_id,
unsigned fw_type, unsigned size, void *value) {
if (drm_cmd_write_ == nullptr) return AMDSMI_STATUS_NOT_SUPPORTED;
std::lock_guard<std::mutex> guard(drm_mutex_);
struct drm_amdgpu_info request;
memset(&request, 0, sizeof(request));
request.return_pointer = (uintptr_t)value;
request.return_size = size;
request.query = info_id;
request.query_fw.fw_type = fw_type;
int status = drm_cmd_write_(fd, DRM_AMDGPU_INFO, &request,
sizeof(struct drm_amdgpu_info));
if (status == 0) return AMDSMI_STATUS_SUCCESS;
return AMDSMI_STATUS_DRM_ERROR;
}
amdsmi_status_t AMDSmiDrm::amdgpu_query_hw_ip(int fd, unsigned info_id,
unsigned hw_ip_type, unsigned size, void *value) {
if (drm_cmd_write_ == nullptr) return AMDSMI_STATUS_NOT_SUPPORTED;
std::lock_guard<std::mutex> guard(drm_mutex_);
struct drm_amdgpu_info request;
memset(&request, 0, sizeof(request));
request.return_pointer = (uintptr_t)value;
request.return_size = size;
request.query = info_id;
request.query_hw_ip.type = hw_ip_type;
int status = drm_cmd_write_(fd, DRM_AMDGPU_INFO, &request,
sizeof(struct drm_amdgpu_info));
if (status == 0) return AMDSMI_STATUS_SUCCESS;
return AMDSMI_STATUS_DRM_ERROR;
}
amdsmi_status_t AMDSmiDrm::amdgpu_query_vbios(int fd, void *info) {
if (drm_cmd_write_ == nullptr) return AMDSMI_STATUS_NOT_SUPPORTED;
std::lock_guard<std::mutex> guard(drm_mutex_);
struct drm_amdgpu_info request;
memset(&request, 0, sizeof request);
request.return_pointer = (uint64_t) info;
request.return_size = sizeof(drm_amdgpu_info_vbios);
request.query = AMDGPU_INFO_VBIOS;
request.vbios_info.type = AMDGPU_INFO_VBIOS_INFO;
int status = drm_cmd_write_(fd, DRM_AMDGPU_INFO, &request,
sizeof(struct drm_amdgpu_info));
if (status == 0) return AMDSMI_STATUS_SUCCESS;
return AMDSMI_STATUS_DRM_ERROR;
}
int AMDSmiDrm::get_drm_fd_by_index(uint32_t gpu_index) const {
if (gpu_index + 1 > drm_fds_.size()) return -1;
return drm_fds_[gpu_index];
}
} // namespace smi
} // namespace amd
+88
View File
@@ -0,0 +1,88 @@
/*
* =============================================================================
* The University of Illinois/NCSA
* Open Source License (NCSA)
*
* Copyright (c) 2022, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Developed by:
*
* AMD Research and AMD ROC Software Development
*
* Advanced Micro Devices, Inc.
*
* www.amd.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal with 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:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimers.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimers in
* the documentation and/or other materials provided with the distribution.
* - Neither the names of <Name of Development Group, Name of Institution>,
* nor the names of its contributors may be used to endorse or promote
* products derived from this Software without specific prior written
* permission.
*
* 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 CONTRIBUTORS 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 WITH THE SOFTWARE.
*
*/
#include <functional>
#include "amd_smi/impl/amd_smi_gpu_device.h"
namespace amd {
namespace smi {
uint32_t AMDSmiGPUDevice::get_gpu_id() const {
return gpu_id_;
}
amdsmi_status_t AMDSmiGPUDevice::amdgpu_query_info(unsigned info_id,
unsigned size, void *value) const {
int fd = drm_.get_drm_fd_by_index(gpu_id_);
if (fd == -1) return AMDSMI_STATUS_NOT_SUPPORTED;
return drm_.amdgpu_query_info(fd, info_id, size, value);
}
amdsmi_status_t AMDSmiGPUDevice::amdgpu_query_hw_ip(unsigned info_id,
unsigned hw_ip_type, unsigned size, void *value) const {
int fd = drm_.get_drm_fd_by_index(gpu_id_);
if (fd == -1) return AMDSMI_STATUS_NOT_SUPPORTED;
return drm_.amdgpu_query_hw_ip(fd, info_id, hw_ip_type, size, value);
}
amdsmi_status_t AMDSmiGPUDevice::amdgpu_query_fw(unsigned info_id,
unsigned fw_type, unsigned size, void *value) const {
int fd = drm_.get_drm_fd_by_index(gpu_id_);
if (fd == -1) return AMDSMI_STATUS_NOT_SUPPORTED;
return drm_.amdgpu_query_fw(fd, info_id, fw_type, size, value);
}
amdsmi_status_t AMDSmiGPUDevice::amdgpu_query_vbios(void *info) const {
int fd = drm_.get_drm_fd_by_index(gpu_id_);
if (fd == -1) return AMDSMI_STATUS_NOT_SUPPORTED;
return drm_.amdgpu_query_vbios(fd, info);
}
} // namespace smi
} // namespace amd
+87
View File
@@ -0,0 +1,87 @@
/*
* =============================================================================
* The University of Illinois/NCSA
* Open Source License (NCSA)
*
* Copyright (c) 2022, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Developed by:
*
* AMD Research and AMD ROC Software Development
*
* Advanced Micro Devices, Inc.
*
* www.amd.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal with 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:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimers.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimers in
* the documentation and/or other materials provided with the distribution.
* - Neither the names of <Name of Development Group, Name of Institution>,
* nor the names of its contributors may be used to endorse or promote
* products derived from this Software without specific prior written
* permission.
*
* 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 CONTRIBUTORS 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 WITH THE SOFTWARE.
*
*/
#include "amd_smi/impl/amd_smi_lib_loader.h"
#include <iostream>
namespace amd {
namespace smi {
AMDSmiLibraryLoader::AMDSmiLibraryLoader(): libHandler_(nullptr) {
}
amdsmi_status_t AMDSmiLibraryLoader::load(const char* filename) {
if (filename == nullptr) {
return AMDSMI_STATUS_FAIL_LOAD_MODULE;
}
if (libHandler_) {
unload();
}
std::lock_guard<std::mutex> guard(library_mutex_);
libHandler_ = dlopen(filename, RTLD_LAZY);
if (!libHandler_) {
char* error = dlerror();
std::cerr << "Fail to open " << filename <<": " << error
<< std::endl;
return AMDSMI_STATUS_FAIL_LOAD_MODULE;
}
return AMDSMI_STATUS_SUCCESS;
}
amdsmi_status_t AMDSmiLibraryLoader::unload() {
std::lock_guard<std::mutex> guard(library_mutex_);
if (libHandler_) {
dlclose(libHandler_);
libHandler_ = nullptr;
}
return AMDSMI_STATUS_SUCCESS;
}
AMDSmiLibraryLoader::~AMDSmiLibraryLoader() {
unload();
}
} // namespace rdc
} // namespace amd
+60
View File
@@ -0,0 +1,60 @@
/*
* =============================================================================
* The University of Illinois/NCSA
* Open Source License (NCSA)
*
* Copyright (c) 2022, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Developed by:
*
* AMD Research and AMD ROC Software Development
*
* Advanced Micro Devices, Inc.
*
* www.amd.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal with 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:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimers.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimers in
* the documentation and/or other materials provided with the distribution.
* - Neither the names of <Name of Development Group, Name of Institution>,
* nor the names of its contributors may be used to endorse or promote
* products derived from this Software without specific prior written
* permission.
*
* 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 CONTRIBUTORS 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 WITH THE SOFTWARE.
*
*/
#include <functional>
#include "amd_smi/impl/amd_smi_socket.h"
namespace amd {
namespace smi {
AMDSmiSocket::~AMDSmiSocket() {
for (uint32_t i = 0; i < devices_.size(); i++) {
delete devices_[i];
}
devices_.clear();
}
} // namespace smi
} // namespace amd
+185
View File
@@ -0,0 +1,185 @@
/*
* =============================================================================
* The University of Illinois/NCSA
* Open Source License (NCSA)
*
* Copyright (c) 2022, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Developed by:
*
* AMD Research and AMD ROC Software Development
*
* Advanced Micro Devices, Inc.
*
* www.amd.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal with 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:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimers.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimers in
* the documentation and/or other materials provided with the distribution.
* - Neither the names of <Name of Development Group, Name of Institution>,
* nor the names of its contributors may be used to endorse or promote
* products derived from this Software without specific prior written
* permission.
*
* 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 CONTRIBUTORS 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 WITH THE SOFTWARE.
*
*/
#include <sstream>
#include <iomanip>
#include "amd_smi/impl/amd_smi_system.h"
#include "amd_smi/impl/amd_smi_gpu_device.h"
#include "rocm_smi/rocm_smi.h"
namespace amd {
namespace smi {
#define AMD_SMI_INIT_FLAG_RESRV_TEST1 0x800000000000000 //!< Reserved for test
amdsmi_status_t AMDSmiSystem::init(uint64_t flags) {
init_flag_ = flags;
// populate sockets and devices
if (flags & AMDSMI_INIT_AMD_GPUS) {
drm_.init();
// init rsmi
rsmi_status_t ret = rsmi_init(flags);
if (ret != RSMI_STATUS_SUCCESS) {
return static_cast<amdsmi_status_t>(ret);
}
uint32_t device_count = 0;
ret = rsmi_num_monitor_devices(&device_count);
if (ret != RSMI_STATUS_SUCCESS) {
return static_cast<amdsmi_status_t>(ret);
}
for (uint32_t i=0; i < device_count; i++) {
uint64_t bdfid = 0;
ret = rsmi_dev_pci_id_get(i, &bdfid);
if (ret != RSMI_STATUS_SUCCESS) {
return static_cast<amdsmi_status_t>(ret);
}
uint64_t domain = (bdfid >> 32) & 0xffffffff;
uint64_t bus = (bdfid >> 8) & 0xff;
uint64_t device_id = (bdfid >> 3) & 0x1f;
uint64_t function = bdfid & 0x7;
std::stringstream ss;
ss << std::setfill('0') << std::uppercase << std::hex
<< std::setw(4) << domain << ":" << std::setw(2) << bus << ":"
<< std::setw(2) << device_id << "." << std::setw(2) << function;
// Multiple devices may share the same socket
auto socket_id = ss.str();
AMDSmiSocket* socket = nullptr;
for (unsigned int j=0; j < sockets_.size(); j++) {
if (sockets_[j]->get_socket_id() == socket_id) {
socket = sockets_[j];
break;
}
}
if (socket == nullptr) {
socket = new AMDSmiSocket(ss.str());
sockets_.push_back(socket);
}
AMDSmiDevice* device = new AMDSmiGPUDevice(i, drm_);
socket->add_device(device);
devices_.insert(device);
}
} else {
return AMDSMI_STATUS_NOT_SUPPORTED;
}
return AMDSMI_STATUS_SUCCESS;
}
amdsmi_status_t AMDSmiSystem::cleanup() {
for (uint32_t i = 0; i < sockets_.size(); i++) {
delete sockets_[i];
}
devices_.clear();
sockets_.clear();
init_flag_ = AMDSMI_INIT_ALL_DEVICES;
rsmi_status_t ret = rsmi_shut_down();
if (ret != RSMI_STATUS_SUCCESS) {
return static_cast<amdsmi_status_t>(ret);
}
drm_.cleanup();
return AMDSMI_STATUS_SUCCESS;
}
amdsmi_status_t AMDSmiSystem::handle_to_socket(
amdsmi_socket_handle socket_handle,
AMDSmiSocket** socket) {
if (socket_handle == nullptr || socket == nullptr) {
return AMDSMI_STATUS_INVAL;
}
*socket = static_cast<AMDSmiSocket*>(socket_handle);
// double check handlers is here
if (std::find(sockets_.begin(), sockets_.end(), *socket)
!= sockets_.end()) {
return AMDSMI_STATUS_SUCCESS;
}
return AMDSMI_STATUS_INVAL;
}
amdsmi_status_t AMDSmiSystem::handle_to_device(
amdsmi_device_handle device_handle,
AMDSmiDevice** device) {
if (device_handle == nullptr || device == nullptr) {
return AMDSMI_STATUS_INVAL;
}
*device = static_cast<AMDSmiDevice*>(device_handle);
// double check handlers is here
if (std::find(devices_.begin(), devices_.end(), *device)
!= devices_.end()) {
return AMDSMI_STATUS_SUCCESS;
}
return AMDSMI_STATUS_INVAL;
}
amdsmi_status_t AMDSmiSystem::gpu_index_to_handle(uint32_t gpu_index,
amdsmi_device_handle* device_handle) {
if (device_handle == nullptr)
return AMDSMI_STATUS_INVAL;
auto iter = devices_.begin();
for (; iter != devices_.end(); iter++) {
auto cur_device = (*iter);
if (cur_device->get_device_type() != AMD_GPU)
continue;
amd::smi::AMDSmiGPUDevice* gpu_device =
static_cast<amd::smi::AMDSmiGPUDevice*>(cur_device);
uint32_t cur_gpu_index = gpu_device->get_gpu_id();
if (gpu_index == cur_gpu_index) {
*device_handle = cur_device;
return AMDSMI_STATUS_SUCCESS;
}
}
return AMDSMI_STATUS_INVAL;
}
} // namespace smi
} // namespace amd
@@ -5,7 +5,7 @@
* The University of Illinois/NCSA
* Open Source License (NCSA)
*
* Copyright (c) 2017, Advanced Micro Devices, Inc.
* Copyright (c) 2022, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Developed by:
@@ -43,14 +43,14 @@
*
*/
#ifndef INCLUDE_ROCM_SMI_ROCM_SMI64CONFIG_H_
#define INCLUDE_ROCM_SMI_ROCM_SMI64CONFIG_H_
#ifndef INCLUDE_AMD_SMI_AMD_SMI64CONFIG_H_
#define INCLUDE_AMD_SMI_AMD_SMI64CONFIG_H_
// This file is generated on build.
#define rocm_smi_VERSION_MAJOR @rocm_smi_VERSION_MAJOR@
#define rocm_smi_VERSION_MINOR @rocm_smi_VERSION_MINOR@
#define rocm_smi_VERSION_PATCH @rocm_smi_VERSION_PATCH@
#define rocm_smi_VERSION_BUILD "@rocm_smi_VERSION_BUILD@"
#define amd_smi_VERSION_MAJOR @amd_smi_VERSION_MAJOR@
#define amd_smi_VERSION_MINOR @amd_smi_VERSION_MINOR@
#define amd_smi_VERSION_PATCH @amd_smi_VERSION_PATCH@
#define amd_smi_VERSION_BUILD "@amd_smi_VERSION_BUILD@"
#endif // INCLUDE_ROCM_SMI_ROCM_SMI64CONFIG_H_
#endif // INCLUDE_AMD_SMI_AMD_SMI64CONFIG_H_
-4161
View File
File diff suppressed because it is too large Load Diff
-438
View File
@@ -1,438 +0,0 @@
/*
* =============================================================================
* The University of Illinois/NCSA
* Open Source License (NCSA)
*
* Copyright (c) 2019, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Developed by:
*
* AMD Research and AMD ROC Software Development
*
* Advanced Micro Devices, Inc.
*
* www.amd.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal with 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:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimers.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimers in
* the documentation and/or other materials provided with the distribution.
* - Neither the names of <Name of Development Group, Name of Institution>,
* nor the names of its contributors may be used to endorse or promote
* products derived from this Software without specific prior written
* permission.
*
* 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 CONTRIBUTORS 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 WITH THE SOFTWARE.
*
*/
#include <assert.h>
#include <string.h>
#include <linux/perf_event.h>
#include <unistd.h>
#include <asm/unistd.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <stdio.h>
#include <map>
#include <sstream>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <unordered_set>
#include "rocm_smi/rocm_smi.h"
#include "rocm_smi/rocm_smi_counters.h"
#include "rocm_smi/rocm_smi_utils.h"
#include "rocm_smi/rocm_smi_exception.h"
#include "rocm_smi/rocm_smi_main.h"
#include "rocm_smi/rocm_smi_device.h"
namespace amd {
namespace smi {
namespace evt {
static const char *kPathDeviceEventRoot = "/sys/bus/event_source/devices";
// Event group names
static const char *kEvGrpDataFabricFName = "amdgpu_df_#";
static const char *kEvGrpAmdGpuFName = "amdgpu_#";
// Data Fabric event file names
static const char *kDFEvtCake0FtiReqAllocFName = "cake0_ftiinstat_reqalloc";
static const char *kDFEvtCake0FtiRspAllocFName = "cake0_ftiinstat_rspalloc";
static const char *kDFEvtCake0PcsOutTxDataFName = "cake0_pcsout_txdata";
static const char *kDFEvtCake0PcsOutTxMetaFName = "cake0_pcsout_txmeta";
static const char *kDFEvtCake1FtiReqAllocFName = "cake1_ftiinstat_reqalloc";
static const char *kDFEvtCake1FtiRspAllocFName = "cake1_ftiinstat_rspalloc";
static const char *kDFEvtCake1PcsOutTxDataFName = "cake1_pcsout_txdata";
static const char *kDFEvtCake1PcsOutTxMetaFName = "cake1_pcsout_txmeta";
// XGMI Data Outbound event file names
static const char *kXGMIDOutBound0FName = "xgmi_link0_data_outbound";
static const char *kXGMIDOutBound1FName = "xgmi_link1_data_outbound";
static const char *kXGMIDOutBound2FName = "xgmi_link2_data_outbound";
static const char *kXGMIDOutBound3FName = "xgmi_link3_data_outbound";
static const char *kXGMIDOutBound4FName = "xgmi_link4_data_outbound";
static const char *kXGMIDOutBound5FName = "xgmi_link5_data_outbound";
static const std::map<rsmi_event_type_t, const char *> kEventFNameMap = {
{RSMI_EVNT_XGMI_0_NOP_TX, kDFEvtCake0PcsOutTxMetaFName},
{RSMI_EVNT_XGMI_0_REQUEST_TX, kDFEvtCake0FtiReqAllocFName},
{RSMI_EVNT_XGMI_0_RESPONSE_TX, kDFEvtCake0FtiRspAllocFName},
{RSMI_EVNT_XGMI_0_BEATS_TX, kDFEvtCake0PcsOutTxDataFName},
{RSMI_EVNT_XGMI_1_NOP_TX, kDFEvtCake1PcsOutTxMetaFName},
{RSMI_EVNT_XGMI_1_REQUEST_TX, kDFEvtCake1FtiReqAllocFName},
{RSMI_EVNT_XGMI_1_RESPONSE_TX, kDFEvtCake1FtiRspAllocFName},
{RSMI_EVNT_XGMI_1_BEATS_TX, kDFEvtCake1PcsOutTxDataFName},
{RSMI_EVNT_XGMI_DATA_OUT_0, kXGMIDOutBound0FName},
{RSMI_EVNT_XGMI_DATA_OUT_1, kXGMIDOutBound1FName},
{RSMI_EVNT_XGMI_DATA_OUT_2, kXGMIDOutBound2FName},
{RSMI_EVNT_XGMI_DATA_OUT_3, kXGMIDOutBound3FName},
{RSMI_EVNT_XGMI_DATA_OUT_4, kXGMIDOutBound4FName},
{RSMI_EVNT_XGMI_DATA_OUT_5, kXGMIDOutBound5FName},
};
static const std::map<rsmi_event_group_t, const char *> kEvtGrpFNameMap = {
{RSMI_EVNT_GRP_XGMI, kEvGrpDataFabricFName},
{RSMI_EVNT_GRP_XGMI_DATA_OUT, kEvGrpAmdGpuFName},
{RSMI_EVNT_GRP_INVALID, "bogus"},
};
static rsmi_event_group_t EvtGrpFromEvtID(rsmi_event_type_t evnt) {
#define EVNT_GRP_RANGE_CHK(EVGRP_SHORT, EVGRP_ENUM) \
if (evnt >= RSMI_EVNT_##EVGRP_SHORT##_FIRST && \
evnt <= RSMI_EVNT_##EVGRP_SHORT##_LAST) { \
return EVGRP_ENUM; \
}
EVNT_GRP_RANGE_CHK(XGMI, RSMI_EVNT_GRP_XGMI);
EVNT_GRP_RANGE_CHK(XGMI_DATA_OUT, RSMI_EVNT_GRP_XGMI_DATA_OUT);
return RSMI_EVNT_GRP_INVALID;
}
// Note below that dev_num is not the same as the usual dv_ind.
// dev_num is the number of the device (e.g., 1 for card1) whereas dv_ind
// is usually the index into the vector of devices
void
GetSupportedEventGroups(uint32_t dev_num, dev_evt_grp_set_t *supported_grps) {
assert(supported_grps != nullptr);
std::string grp_path_base;
std::string grp_path;
int32_t ret;
grp_path_base = kPathDeviceEventRoot;
grp_path_base += '/';
struct stat file_stat;
for (auto g : kEvtGrpFNameMap) {
grp_path = grp_path_base;
grp_path += g.second;
std::replace(grp_path.begin(), grp_path.end(), '#',
static_cast<char>('0' + dev_num));
ret = stat(grp_path.c_str(), &file_stat);
if (ret) {
assert(errno == ENOENT);
continue;
}
if (S_ISDIR(file_stat.st_mode)) {
supported_grps->insert(g.first);
}
}
}
// /sys/bus/event_source/devices/<hw block>_<instance>/type
Event::Event(rsmi_event_type_t event, uint32_t dev_ind) :
event_type_(event), prev_cntr_val_(0) {
fd_ = -1;
rsmi_event_group_t grp = EvtGrpFromEvtID(event);
assert(grp != RSMI_EVNT_GRP_INVALID); // This should have failed before now
evt_path_root_ = kPathDeviceEventRoot;
evt_path_root_ += '/';
evt_path_root_ += kEvtGrpFNameMap.at(grp);
amd::smi::RocmSMI& smi = amd::smi::RocmSMI::getInstance();
assert(dev_ind < smi.devices().size());
std::shared_ptr<amd::smi::Device> dev = smi.devices()[dev_ind];
assert(dev != nullptr);
dev_ind_ = dev_ind;
dev_file_ind_ = dev->index();
std::replace(evt_path_root_.begin(), evt_path_root_.end(), '#',
static_cast<char>('0' + dev_file_ind_));
}
Event::~Event(void) {
int ret;
if (fd_ != -1) {
ret = close(fd_);
if (ret == -1) {
perror("Failed to close file descriptor.");
}
}
}
static void
parse_field_config(std::string fstr, evnt_info_t *val) {
std::stringstream ss(fstr);
std::stringstream fs;
std::string config_ln;
std::string field_name;
uint32_t start_bit;
uint32_t end_bit;
char jnk;
assert(val != nullptr);
getline(ss, config_ln, ':');
ss >> start_bit;
ss >> jnk;
assert(jnk == '-');
ss >> end_bit;
if (start_bit > end_bit ||
start_bit > 0xFF ||
end_bit > 0xFF ||
((end_bit - start_bit + 1) > 0xFF)) {
throw amd::smi::rsmi_exception(RSMI_STATUS_UNEXPECTED_SIZE, __FUNCTION__);
}
val->start_bit = static_cast<uint8_t>(start_bit);
val->field_size = static_cast<uint8_t>(end_bit - start_bit + 1);
}
static int32_t
get_event_bitfield_info(std::string *config_path, evnt_info_t *val) {
int32_t err;
std::string fstr;
err = ReadSysfsStr(*config_path, &fstr);
if (err) {
return err;
}
parse_field_config(fstr, val);
return 0;
}
int32_t
Event::get_event_file_info(void) {
int32_t err;
std::string fn = evt_path_root_;
std::string fstr;
fn += "/events/";
fn += kEventFNameMap.at(event_type_);
err = ReadSysfsStr(fn, &fstr);
if (err) {
return err;
}
// parse_perf_attr(fstr, &event_id_.event_field_vals);
std::stringstream ss(fstr);
std::stringstream fs;
std::string field_assgn;
std::string field_name;
evnt_info_t ev_info;
while (ss.rdbuf()->in_avail() != 0) {
ev_info = {};
getline(ss, field_assgn, ',');
fs.clear();
fs << field_assgn;
getline(fs, field_name, '=');
fs >> std::hex >> ev_info.value;
assert(fs.rdbuf()->in_avail() == 0);
// Now, get the corresponding bitfield
std::string config_path = evt_path_root_;
config_path += "/format/";
config_path += field_name;
err = get_event_bitfield_info(&config_path, &ev_info);
if (err) {
return err;
}
event_info_.push_back(ev_info);
}
return 0;
}
int32_t
Event::get_event_type(uint32_t *ev_type) {
assert(ev_type != nullptr);
if (ev_type == nullptr) {
return EINVAL;
}
std::string fn = evt_path_root_;
std::string fstr;
fn += "/type";
std::ifstream fs;
fs.open(fn);
if (!fs.is_open()) {
return errno;
}
fs >> *ev_type;
fs.close();
return 0;
}
static uint64_t
get_perf_attr_config(std::vector<evnt_info_t> *ev_info) {
uint64_t ret_val = 0;
assert(ev_info != nullptr);
for (const evnt_info_t& ev : *ev_info) {
ret_val |= ev.value << ev.start_bit;
}
return ret_val;
}
int32_t
amd::smi::evt::Event::openPerfHandle(void) {
int32_t ret;
memset(&attr_, 0, sizeof(struct perf_event_attr));
ret = get_event_file_info();
if (ret) {
return ret;
}
ret = get_event_type(&attr_.type);
if (ret) {
return ret;
}
attr_.size = sizeof(struct perf_event_attr);
attr_.config = get_perf_attr_config(&event_info_);
attr_.sample_type = PERF_SAMPLE_IDENTIFIER;
attr_.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
PERF_FORMAT_TOTAL_TIME_RUNNING;
attr_.disabled = 1;
attr_.inherit = 1;
int64_t p_ret = syscall(__NR_perf_event_open, &attr_,
-1, 0, -1, PERF_FLAG_FD_NO_GROUP);
if (p_ret < 0) {
return errno;
}
fd_ = static_cast<int>(p_ret);
return 0;
}
int32_t
amd::smi::evt::Event::startCounter(void) {
int32_t ret;
if (fd_ == -1) {
ret = openPerfHandle();
if (ret != 0) {
return ret;
}
}
ret = ioctl(fd_, PERF_EVENT_IOC_ENABLE, NULL);
if (ret == -1) {
return errno;
}
assert(ret == 0); // We're expecting the ioctl call to return -1 or 0
return 0;
}
int32_t
amd::smi::evt::Event::stopCounter(void) {
int32_t ret;
if (fd_ == -1) {
return EBADF;
}
ret = ioctl(fd_, PERF_EVENT_IOC_DISABLE, NULL);
if (ret == -1) {
return errno;
}
assert(ret == 0); // We're expecting the ioctl call to return -1 or 0
return 0;
}
static ssize_t
readn(int fd, void *buf, size_t n) {
size_t left = n;
ssize_t bytes;
while (left) {
bytes = read(fd, buf, left);
if (!bytes) { /* reach EOF */
return static_cast<ssize_t>(n - left);
}
if (bytes < 0) {
if (errno == EINTR) /* read got interrupted */
continue;
else
return -errno;
}
left -= static_cast<size_t>(bytes);
buf = reinterpret_cast<void *>((reinterpret_cast<uint8_t *>(buf) + bytes));
}
return static_cast<ssize_t>(n);
}
uint32_t
amd::smi::evt::Event::getValue(rsmi_counter_value_t *val) {
assert(val != nullptr);
ssize_t ret;
perf_read_format_t pvalue;
ret = readn(fd_, &pvalue, sizeof(perf_read_format_t));
if (ret < 0) {
return static_cast<uint32_t>(-ret);
}
if (ret != sizeof(perf_read_format_t)) {
return EIO;
}
val->value = pvalue.value - prev_cntr_val_;
prev_cntr_val_ = pvalue.value;
val->time_enabled = pvalue.enabled_time;
val->time_running = pvalue.run_time;
return 0;
}
} // namespace evt
} // namespace smi
} // namespace amd
File diff suppressed because it is too large Load Diff
-312
View File
@@ -1,312 +0,0 @@
/*
* =============================================================================
* The University of Illinois/NCSA
* Open Source License (NCSA)
*
* Copyright (c) 2021, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Developed by:
*
* AMD Research and AMD ROC Software Development
*
* Advanced Micro Devices, Inc.
*
* www.amd.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal with 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:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimers.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimers in
* the documentation and/or other materials provided with the distribution.
* - Neither the names of <Name of Development Group, Name of Institution>,
* nor the names of its contributors may be used to endorse or promote
* products derived from this Software without specific prior written
* permission.
*
* 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 CONTRIBUTORS 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 WITH THE SOFTWARE.
*
*/
#include <assert.h>
#include <dirent.h>
#include <fstream>
#include <string>
#include <cstdint>
#include <map>
#include <iostream>
#include <algorithm>
#include <regex> // NOLINT
#include <vector>
#include <pthread.h>
#include "rocm_smi/rocm_smi_common.h" // Should go before rocm_smi.h
#include "rocm_smi/rocm_smi_main.h"
#include "rocm_smi/rocm_smi_monitor.h"
#include "rocm_smi/rocm_smi_utils.h"
#include "rocm_smi/rocm_smi_exception.h"
#define TRY try {
#define CATCH } catch (...) {return amd::smi::handleException();}
// Put definitions of old gpu_metrics formats here
typedef struct {
struct metrics_table_header_t common_header;
/* Driver attached timestamp (in ns) */
uint64_t system_clock_counter;
/* Temperature */
uint16_t temperature_edge;
uint16_t temperature_hotspot;
uint16_t temperature_mem;
uint16_t temperature_vrgfx;
uint16_t temperature_vrsoc;
uint16_t temperature_vrmem;
/* Utilization */
uint16_t average_gfx_activity;
uint16_t average_umc_activity; // memory controller
uint16_t average_mm_activity; // UVD or VCN
/* Power/Energy */
uint16_t average_socket_power;
uint32_t energy_accumulator;
/* Average clocks */
uint16_t average_gfxclk_frequency;
uint16_t average_socclk_frequency;
uint16_t average_uclk_frequency;
uint16_t average_vclk0_frequency;
uint16_t average_dclk0_frequency;
uint16_t average_vclk1_frequency;
uint16_t average_dclk1_frequency;
/* Current clocks */
uint16_t current_gfxclk;
uint16_t current_socclk;
uint16_t current_uclk;
uint16_t current_vclk0;
uint16_t current_dclk0;
uint16_t current_vclk1;
uint16_t current_dclk1;
/* Throttle status */
uint32_t throttle_status;
/* Fans */
uint16_t current_fan_speed;
/* Link width/speed */
uint8_t pcie_link_width;
uint8_t pcie_link_speed; // in 0.1 GT/s
} rsmi_gpu_metrics_v_1_0_t;
typedef struct {
rsmi_gpu_metrics_t base;
uint64_t firmware_timestamp;
} rsmi_gpu_metrics_v_1_2;
typedef struct {
rsmi_gpu_metrics_t base;
/* PMFW attached timestamp (10ns resolution) */
uint64_t firmware_timestamp;
/* Voltage (mV) */
uint16_t voltage_soc;
uint16_t voltage_gfx;
uint16_t voltage_mem;
uint16_t padding1;
/* Throttle status (ASIC independent) */
uint64_t indep_throttle_status;
} rsmi_gpu_metrics_v_1_3;
static rsmi_status_t GetGPUMetricsFormat1(uint32_t dv_ind,
rsmi_gpu_metrics_t *data, uint8_t content_v) {
assert(content_v != RSMI_GPU_METRICS_API_CONTENT_VER_1 &&
content_v != RSMI_GPU_METRICS_API_CONTENT_VER_2 &&
content_v != RSMI_GPU_METRICS_API_CONTENT_VER_3 );
if (content_v == RSMI_GPU_METRICS_API_CONTENT_VER_1 ||
content_v == RSMI_GPU_METRICS_API_CONTENT_VER_2 ||
content_v == RSMI_GPU_METRICS_API_CONTENT_VER_3 ) {
// This function shouldn't be called if content version is
// RSMI_GPU_METRICS_API_CONTENT_VER_1 or RSMI_GPU_METRICS_API_CONTENT_VER_2
// or RSMI_GPU_METRICS_API_CONTENT_VER_3
return RSMI_STATUS_INVALID_ARGS;
}
void *metric_data = nullptr;
size_t data_size;
rsmi_status_t ret;
rsmi_gpu_metrics_v_1_0_t metric_data_v_1_0;
if (content_v == 0) {
metric_data = &metric_data_v_1_0;
data_size = sizeof(rsmi_gpu_metrics_v_1_0_t);
} // else { ... handle other conversions to v1
assert(metric_data != nullptr && "Unexpected conversion attempted.");
ret = GetDevBinaryBlob(amd::smi::kDevGpuMetrics, dv_ind, data_size,
metric_data);
if (ret != RSMI_STATUS_SUCCESS) {
return ret;
}
#define ASSIGN_DATA_FIELD(FIELD, SRC) \
data->FIELD = SRC->FIELD;
#define ASSIGN_COMMON_FORMATS(SRC) \
ASSIGN_DATA_FIELD(common_header, (SRC)) \
ASSIGN_DATA_FIELD(temperature_edge, (SRC)) \
ASSIGN_DATA_FIELD(temperature_hotspot, (SRC)) \
ASSIGN_DATA_FIELD(temperature_mem, (SRC)) \
ASSIGN_DATA_FIELD(temperature_vrgfx, (SRC)) \
ASSIGN_DATA_FIELD(temperature_vrsoc, (SRC)) \
ASSIGN_DATA_FIELD(temperature_vrmem, (SRC)) \
ASSIGN_DATA_FIELD(average_gfx_activity, (SRC)) \
ASSIGN_DATA_FIELD(average_umc_activity, (SRC)) \
ASSIGN_DATA_FIELD(average_mm_activity, (SRC)) \
ASSIGN_DATA_FIELD(average_socket_power, (SRC)) \
ASSIGN_DATA_FIELD(system_clock_counter, (SRC)) \
ASSIGN_DATA_FIELD(average_gfxclk_frequency, (SRC)) \
ASSIGN_DATA_FIELD(average_socclk_frequency, (SRC)) \
ASSIGN_DATA_FIELD(average_uclk_frequency, (SRC)) \
ASSIGN_DATA_FIELD(average_vclk0_frequency, (SRC)) \
ASSIGN_DATA_FIELD(average_dclk0_frequency, (SRC)) \
ASSIGN_DATA_FIELD(average_vclk1_frequency, (SRC)) \
ASSIGN_DATA_FIELD(average_dclk1_frequency, (SRC)) \
ASSIGN_DATA_FIELD(current_gfxclk, (SRC)) \
ASSIGN_DATA_FIELD(current_socclk, (SRC)) \
ASSIGN_DATA_FIELD(current_uclk, (SRC)) \
ASSIGN_DATA_FIELD(current_vclk0, (SRC)) \
ASSIGN_DATA_FIELD(current_dclk0, (SRC)) \
ASSIGN_DATA_FIELD(current_vclk1, (SRC)) \
ASSIGN_DATA_FIELD(current_dclk1, (SRC)) \
ASSIGN_DATA_FIELD(throttle_status, (SRC)) \
ASSIGN_DATA_FIELD(current_fan_speed, (SRC))
// Now handle differences from format 1
if (content_v == 0) {
// First handle all data that is common to Format1 and other formats
ASSIGN_COMMON_FORMATS(
reinterpret_cast<rsmi_gpu_metrics_v_1_0_t *>(metric_data))
// Then, the differences:
data->energy_accumulator = static_cast<uint64_t>(
reinterpret_cast<rsmi_gpu_metrics_v_1_0_t *>(
metric_data)->energy_accumulator);
data->pcie_link_width = static_cast<uint16_t>(
reinterpret_cast<rsmi_gpu_metrics_v_1_0_t *>(
metric_data)->pcie_link_width);
data->pcie_link_speed = static_cast<uint16_t>(
reinterpret_cast<rsmi_gpu_metrics_v_1_0_t *>(
metric_data)->pcie_link_speed);
// These fields didn't exist in v0
data->gfx_activity_acc = 0;
data->mem_actvity_acc = 0;
(void)memset(data->temperature_hbm, 0,
RSMI_NUM_HBM_INSTANCES * sizeof(uint16_t));
} // else handle other conversions to format 1
#undef ASSIGN_DATA_FIELD
#undef ASSIGN_COMMON_FORMATS
return RSMI_STATUS_SUCCESS;
}
// Translate gpu_metrics version 1.2 to rsmi_gpu_metrics_t. gpu_metrics
// version 1.2 provides timestamp provided by the firmware. This timestamp
// is sampled atomically along when gpu_metric information. Use this
// timestamp instead of system_clock_counter
static void map_gpu_metrics_1_2_to_rsmi_gpu_metrics_t(
const rsmi_gpu_metrics_v_1_2 *gpu_metrics_v_1_2,
rsmi_gpu_metrics_t *rsmi_gpu_metrics)
{
memcpy(rsmi_gpu_metrics, &gpu_metrics_v_1_2->base,
sizeof(rsmi_gpu_metrics_t));
// firmware_timestamp is at 10ns resolution
rsmi_gpu_metrics->system_clock_counter =
gpu_metrics_v_1_2->firmware_timestamp * 10;
}
static void map_gpu_metrics_1_3_to_rsmi_gpu_metrics_t(
const rsmi_gpu_metrics_v_1_3 *gpu_metrics_v_1_3,
rsmi_gpu_metrics_t *rsmi_gpu_metrics)
{
memcpy(rsmi_gpu_metrics, &gpu_metrics_v_1_3->base,
sizeof(rsmi_gpu_metrics_t));
// firmware_timestamp is at 10ns resolution
rsmi_gpu_metrics->system_clock_counter =
gpu_metrics_v_1_3->firmware_timestamp * 10;
}
rsmi_status_t
rsmi_dev_gpu_metrics_info_get(uint32_t dv_ind, rsmi_gpu_metrics_t *smu) {
TRY
DEVICE_MUTEX
CHK_SUPPORT_NAME_ONLY(smu)
rsmi_gpu_metrics_v_1_2 smu_v_1_2;
rsmi_gpu_metrics_v_1_3 smu_v_1_3;
rsmi_status_t ret;
if (!dev->gpu_metrics_ver().structure_size) {
ret = GetDevBinaryBlob(amd::smi::kDevGpuMetrics, dv_ind,
sizeof(struct metrics_table_header_t), &dev->gpu_metrics_ver());
if (ret != RSMI_STATUS_SUCCESS) {
return ret;
}
}
// only supports gpu_metrics_v1_x version
if (dev->gpu_metrics_ver().format_revision != 1) {
return RSMI_STATUS_NOT_SUPPORTED;
}
// Initialize the smu fiedls to zero as some of them only valid in
// a specific version.
*smu = {};
if (dev->gpu_metrics_ver().content_revision ==
RSMI_GPU_METRICS_API_CONTENT_VER_1) {
ret = GetDevBinaryBlob(amd::smi::kDevGpuMetrics, dv_ind,
sizeof(rsmi_gpu_metrics_t), smu);
} else if (dev->gpu_metrics_ver().content_revision ==
RSMI_GPU_METRICS_API_CONTENT_VER_2) {
ret = GetDevBinaryBlob(amd::smi::kDevGpuMetrics, dv_ind,
sizeof(rsmi_gpu_metrics_v_1_2), &smu_v_1_2);
map_gpu_metrics_1_2_to_rsmi_gpu_metrics_t(&smu_v_1_2, smu);
} else if (dev->gpu_metrics_ver().content_revision ==
RSMI_GPU_METRICS_API_CONTENT_VER_3) {
ret = GetDevBinaryBlob(amd::smi::kDevGpuMetrics, dv_ind,
sizeof(rsmi_gpu_metrics_v_1_3), &smu_v_1_3);
map_gpu_metrics_1_3_to_rsmi_gpu_metrics_t(&smu_v_1_3, smu);
} else {
ret = GetGPUMetricsFormat1(dv_ind, smu,
dev->gpu_metrics_ver().content_revision);
}
if (ret != RSMI_STATUS_SUCCESS) {
return ret;
}
return ret;
CATCH
}
-407
View File
@@ -1,407 +0,0 @@
/*
* =============================================================================
* The University of Illinois/NCSA
* Open Source License (NCSA)
*
* Copyright (c) 2020, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Developed by:
*
* AMD Research and AMD ROC Software Development
*
* Advanced Micro Devices, Inc.
*
* www.amd.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal with 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:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimers.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimers in
* the documentation and/or other materials provided with the distribution.
* - Neither the names of <Name of Development Group, Name of Institution>,
* nor the names of its contributors may be used to endorse or promote
* products derived from this Software without specific prior written
* permission.
*
* 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 CONTRIBUTORS 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 WITH THE SOFTWARE.
*
*/
#include <assert.h>
#include <sys/stat.h>
#include <dirent.h>
#include <algorithm>
#include <string>
#include <unordered_set>
#include <fstream>
#include <cstdint>
#include <iostream>
#include <sstream>
#include "rocm_smi/rocm_smi.h"
#include "rocm_smi/rocm_smi_exception.h"
#include "rocm_smi/rocm_smi_utils.h"
#include "rocm_smi/rocm_smi_io_link.h"
namespace amd {
namespace smi {
static const char *kKFDNodesPathRoot = "/sys/class/kfd/kfd/topology/nodes";
static const char *kKFDLinkPath[] = {"io_links", "p2p_links"};
// IO Link Property strings
static const char *kIOLinkPropTYPEStr = "type";
// static const char *kIOLinkPropVERSION_MAJORStr = "version_major";
// static const char *kIOLinkPropVERSION_MINORStr = "version_minor";
static const char *kIOLinkPropNODE_FROMStr = "node_from";
static const char *kIOLinkPropNODE_TOStr = "node_to";
static const char *kIOLinkPropWEIGHTStr = "weight";
// static const char *kIOLinkPropMIN_LATENCYStr = "min_latency";
// static const char *kIOLinkPropMAX_LATENCYStr = "max_latency";
static const char *kIOLinkPropMIN_BANDWIDTHStr = "min_bandwidth";
static const char *kIOLinkPropMAX_BANDWIDTHStr = "max_bandwidth";
// static const char *kIOLinkPropRECOMMENDED_TRANSFER_SIZEStr =
// "recommended_transfer_size";
// static const char *kIOLinkPropFLAGSStr = "flags";
static bool is_number(const std::string &s) {
return !s.empty() && std::all_of(s.begin(), s.end(), ::isdigit);
}
static std::string LinkPathRoot(uint32_t node_indx,
LINK_DIRECTORY_TYPE directory) {
std::string link_path_root = kKFDNodesPathRoot;
link_path_root += '/';
link_path_root += std::to_string(node_indx);
link_path_root += '/';
if (directory < sizeof(kKFDLinkPath)/sizeof(kKFDLinkPath[0])) {
link_path_root += kKFDLinkPath[directory];
} else {
link_path_root = "";
}
return link_path_root;
}
static std::string LinkPath(uint32_t node_indx, uint32_t link_indx,
LINK_DIRECTORY_TYPE directory) {
std::string link_path = LinkPathRoot(node_indx, directory);
link_path += '/';
link_path += std::to_string(link_indx);
return link_path;
}
static int OpenLinkProperties(uint32_t node_indx, uint32_t link_indx,
std::ifstream *fs,
LINK_DIRECTORY_TYPE directory) {
int ret;
std::string f_path;
bool reg_file;
assert(fs != nullptr);
if (fs == nullptr) {
return EINVAL;
}
f_path = LinkPath(node_indx, link_indx, directory);
f_path += "/";
f_path += "properties";
ret = isRegularFile(f_path, &reg_file);
if (ret != 0) {
return ret;
}
if (!reg_file) {
return ENOENT;
}
fs->open(f_path);
if (!fs->is_open()) {
return errno;
}
return 0;
}
static int ReadLinkProperties(uint32_t node_indx, uint32_t link_indx,
std::vector<std::string> *retVec,
LINK_DIRECTORY_TYPE directory) {
std::string line;
int ret;
std::ifstream fs;
assert(retVec != nullptr);
if (retVec == nullptr) {
return EINVAL;
}
ret = OpenLinkProperties(node_indx, link_indx, &fs, directory);
if (ret) {
return ret;
}
while (std::getline(fs, line)) {
retVec->push_back(line);
}
if (retVec->size() == 0) {
fs.close();
return 0;
}
// Remove any *trailing* empty (whitespace) lines
while (retVec->back().find_first_not_of(" \t\n\v\f\r") == std::string::npos) {
retVec->pop_back();
}
fs.close();
return 0;
}
static int DiscoverLinks(std::map<std::pair<uint32_t, uint32_t>,
std::shared_ptr<IOLink>> *links,
LINK_DIRECTORY_TYPE directory) {
assert(links != nullptr);
if (links == nullptr) {
return EINVAL;
}
assert(links->size() == 0);
links->clear();
auto kfd_node_dir = opendir(kKFDNodesPathRoot);
if (kfd_node_dir == nullptr) {
std::string err_msg = "Failed to open KFD nodes directory ";
err_msg += kKFDNodesPathRoot;
err_msg += ".";
perror(err_msg.c_str());
return 1;
}
auto dentry_kfd = readdir(kfd_node_dir);
while (dentry_kfd != nullptr) {
if (dentry_kfd->d_name[0] == '.') {
dentry_kfd = readdir(kfd_node_dir);
continue;
}
if (!is_number(dentry_kfd->d_name)) {
dentry_kfd = readdir(kfd_node_dir);
continue;
}
uint32_t node_indx = static_cast<uint32_t>(std::stoi(dentry_kfd->d_name));
std::shared_ptr<IOLink> link;
uint32_t link_indx;
std::string link_path_root = LinkPathRoot(node_indx, directory);
auto io_link_dir = opendir(link_path_root.c_str());
assert(io_link_dir != nullptr);
auto dentry_io_link = readdir(io_link_dir);
while (dentry_io_link != nullptr) {
if (dentry_io_link->d_name[0] == '.') {
dentry_io_link = readdir(io_link_dir);
continue;
}
if (!is_number(dentry_io_link->d_name)) {
dentry_io_link = readdir(io_link_dir);
continue;
}
link_indx = static_cast<uint32_t>(std::stoi(dentry_io_link->d_name));
link = std::shared_ptr<IOLink>(new IOLink(node_indx, link_indx,
directory));
link->Initialize();
(*links)[std::make_pair(link->node_from(), link->node_to())] = link;
dentry_io_link = readdir(io_link_dir);
}
if (closedir(io_link_dir)) {
std::string err_msg = "Failed to close KFD nodes directory ";
err_msg += kKFDNodesPathRoot;
err_msg += ".";
perror(err_msg.c_str());
return 1;
}
dentry_kfd = readdir(kfd_node_dir);
}
if (closedir(kfd_node_dir)) {
return 1;
}
return 0;
}
int DiscoverIOLinks(std::map<std::pair<uint32_t, uint32_t>,
std::shared_ptr<IOLink>> *links) {
return DiscoverLinks(links, IO_LINK_DIRECTORY);
}
int DiscoverP2PLinks(std::map<std::pair<uint32_t, uint32_t>,
std::shared_ptr<IOLink>> *links) {
return DiscoverLinks(links, P2P_LINK_DIRECTORY);
}
static int DiscoverLinksPerNode(uint32_t node_indx, std::map<uint32_t,
std::shared_ptr<IOLink>> *links,
LINK_DIRECTORY_TYPE directory) {
assert(links != nullptr);
if (links == nullptr) {
return EINVAL;
}
assert(links->size() == 0);
links->clear();
std::shared_ptr<IOLink> link;
uint32_t link_indx;
std::string link_path_root = LinkPathRoot(node_indx, directory);
auto io_link_dir = opendir(link_path_root.c_str());
assert(io_link_dir != nullptr);
auto dentry = readdir(io_link_dir);
while (dentry != nullptr) {
if (dentry->d_name[0] == '.') {
dentry = readdir(io_link_dir);
continue;
}
if (!is_number(dentry->d_name)) {
dentry = readdir(io_link_dir);
continue;
}
link_indx = static_cast<uint32_t>(std::stoi(dentry->d_name));
link = std::shared_ptr<IOLink>(new IOLink(node_indx, link_indx,
directory));
link->Initialize();
(*links)[link->node_to()] = link;
dentry = readdir(io_link_dir);
}
if (closedir(io_link_dir)) {
return 1;
}
return 0;
}
int DiscoverIOLinksPerNode(uint32_t node_indx, std::map<uint32_t,
std::shared_ptr<IOLink>> *links) {
return DiscoverLinksPerNode(node_indx, links, IO_LINK_DIRECTORY);
}
int DiscoverP2PLinksPerNode(uint32_t node_indx, std::map<uint32_t,
std::shared_ptr<IOLink>> *links) {
return DiscoverLinksPerNode(node_indx, links, P2P_LINK_DIRECTORY);
}
IOLink::~IOLink() {
}
int IOLink::ReadProperties(void) {
int ret;
std::vector<std::string> propVec;
assert(properties_.size() == 0);
if (properties_.size() > 0) {
return 0;
}
ret = ReadLinkProperties(node_indx_, link_indx_, &propVec,
link_dir_type_);
if (ret) {
return ret;
}
std::string key_str;
uint64_t val_int; // Assume all properties are unsigned integers for now
std::istringstream fs;
for (uint32_t i = 0; i < propVec.size(); ++i) {
fs.str(propVec[i]);
fs >> key_str;
fs >> val_int;
properties_[key_str] = val_int;
fs.str("");
fs.clear();
}
return 0;
}
int
IOLink::Initialize(void) {
int ret = 0;
ret = ReadProperties();
if (ret) {return ret;}
ret = get_property_value(kIOLinkPropTYPEStr,
reinterpret_cast<uint64_t *>(&type_));
if (ret) {return ret;}
ret = get_property_value(kIOLinkPropNODE_FROMStr,
reinterpret_cast<uint64_t *>(&node_from_));
if (ret) {return ret;}
ret = get_property_value(kIOLinkPropNODE_TOStr,
reinterpret_cast<uint64_t *>(&node_to_));
if (ret) {return ret;}
ret = get_property_value(kIOLinkPropWEIGHTStr, &weight_);
if (ret) {return ret;}
ret = get_property_value(kIOLinkPropMIN_BANDWIDTHStr, &min_bandwidth_);
if (ret) {return ret;}
ret = get_property_value(kIOLinkPropMAX_BANDWIDTHStr, &max_bandwidth_);
return ret;
}
int
IOLink::get_property_value(std::string property, uint64_t *value) {
assert(value != nullptr);
if (value == nullptr) {
return EINVAL;
}
if (properties_.find(property) == properties_.end()) {
return EINVAL;
}
*value = properties_[property];
return 0;
}
} // namespace smi
} // namespace amd
-772
View File
@@ -1,772 +0,0 @@
/*
* =============================================================================
* The University of Illinois/NCSA
* Open Source License (NCSA)
*
* Copyright (c) 2019, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Developed by:
*
* AMD Research and AMD ROC Software Development
*
* Advanced Micro Devices, Inc.
*
* www.amd.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal with 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:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimers.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimers in
* the documentation and/or other materials provided with the distribution.
* - Neither the names of <Name of Development Group, Name of Institution>,
* nor the names of its contributors may be used to endorse or promote
* products derived from this Software without specific prior written
* permission.
*
* 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 CONTRIBUTORS 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 WITH THE SOFTWARE.
*
*/
#include <assert.h>
#include <sys/stat.h>
#include <dirent.h>
#include <algorithm>
#include <string>
#include <unordered_set>
#include <fstream>
#include <cstdint>
#include <iostream>
#include <sstream>
#include "rocm_smi/rocm_smi_io_link.h"
#include "rocm_smi/rocm_smi_kfd.h"
#include "rocm_smi/rocm_smi.h"
#include "rocm_smi/rocm_smi_exception.h"
#include "rocm_smi/rocm_smi_utils.h"
#include "rocm_smi/rocm_smi_device.h"
#include "rocm_smi/rocm_smi_main.h"
namespace amd {
namespace smi {
static const char *kKFDProcPathRoot = "/sys/class/kfd/kfd/proc";
static const char *kKFDNodesPathRoot = "/sys/class/kfd/kfd/topology/nodes";
// Sysfs file names
static const char *kKFDPasidFName = "pasid";
// KFD Node Property strings
// static const char *kKFDNodePropCPU_CORES_COUNTStr = "cpu_cores_count";
// static const char *kKFDNodePropSIMD_COUNTStr = "simd_count";
// static const char *kKFDNodePropMEM_BANKS_COUNTStr = "mem_banks_count";
// static const char *kKFDNodePropCACHES_COUNTStr = "caches_count";
// static const char *kKFDNodePropIO_LINKS_COUNTStr = "io_links_count";
// static const char *kKFDNodePropCPU_CORE_ID_BASEStr = "cpu_core_id_base";
// static const char *kKFDNodePropSIMD_ID_BASEStr = "simd_id_base";
// static const char *kKFDNodePropMAX_WAVES_PER_SIMDStr = "max_waves_per_simd";
// static const char *kKFDNodePropLDS_SIZE_IN_KBStr = "lds_size_in_kb";
// static const char *kKFDNodePropGDS_SIZE_IN_KBStr = "gds_size_in_kb";
// static const char *kKFDNodePropNUM_GWSStr = "num_gws";
// static const char *kKFDNodePropWAVE_FRONT_SIZEStr = "wave_front_size";
static const char *kKFDNodePropARRAY_COUNTStr = "array_count";
static const char *kKFDNodePropSIMD_ARRAYS_PER_ENGINEStr =
"simd_arrays_per_engine";
static const char *kKFDNodePropCU_PER_SIMD_ARRAYStr = "cu_per_simd_array";
// static const char *kKFDNodePropSIMD_PER_CUStr = "simd_per_cu";
// static const char *kKFDNodePropMAX_SLOTS_SCRATCH_CUStr =
// "max_slots_scratch_cu";
// static const char *kKFDNodePropVENDOR_IDStr = "vendor_id";
// static const char *kKFDNodePropDEVICE_IDStr = "device_id";
static const char *kKFDNodePropLOCATION_IDStr = "location_id";
static const char *kKFDNodePropDOMAINStr = "domain";
// static const char *kKFDNodePropDRM_RENDER_MINORStr = "drm_render_minor";
static const char *kKFDNodePropHIVE_IDStr = "hive_id";
// static const char *kKFDNodePropNUM_SDMA_ENGINESStr = "num_sdma_engines";
// static const char *kKFDNodePropNUM_SDMA_XGMI_ENGINESStr =
// "num_sdma_xgmi_engines";
// static const char *kKFDNodePropNUM_SDMA_QUEUES_PER_ENGINEStr =
// "num_sdma_queues_per_engine";
// static const char *kKFDNodePropNUM_CP_QUEUESStr = "num_cp_queues";
// static const char *kKFDNodePropMAX_ENGINE_CLK_FCOMPUTEStr =
// "max_engine_clk_fcompute";
// static const char *kKFDNodePropLOCAL_MEM_SIZEStr = "local_mem_size";
// static const char *kKFDNodePropFW_VERSIONStr = "fw_version";
// static const char *kKFDNodePropCAPABILITYStr = "capability";
// static const char *kKFDNodePropDEBUG_PROPStr = "debug_prop";
// static const char *kKFDNodePropSDMA_FW_VERSIOStr = "sdma_fw_versio";
// static const char *kKFDNodePropMAX_ENGINE_CLK_CCOMPUTEStr =
// "max_engine_clk_ccompute";
static bool is_number(const std::string &s) {
return !s.empty() && std::all_of(s.begin(), s.end(), ::isdigit);
}
static std::string KFDDevicePath(uint32_t dev_id) {
std::string node_path = kKFDNodesPathRoot;
node_path += '/';
node_path += std::to_string(dev_id);
return node_path;
}
static int OpenKFDNodeFile(uint32_t dev_id, std::string node_file,
std::ifstream *fs) {
std::string line;
int ret;
std::string f_path;
bool reg_file;
assert(fs != nullptr);
f_path = KFDDevicePath(dev_id);
f_path += "/";
f_path += node_file;
ret = isRegularFile(f_path, &reg_file);
if (ret != 0) {
return ret;
}
if (!reg_file) {
return ENOENT;
}
fs->open(f_path);
if (!fs->is_open()) {
return errno;
}
return 0;
}
bool KFDNodeSupported(uint32_t node_indx) {
std::ifstream fs;
bool ret = true;
int err;
err = OpenKFDNodeFile(node_indx, "properties", &fs);
if (err == ENOENT) {
return false;
}
if (fs.peek() == std::ifstream::traits_type::eof()) {
ret = false;
}
fs.close();
return ret;
}
int ReadKFDDeviceProperties(uint32_t kfd_node_id,
std::vector<std::string> *retVec) {
std::string line;
int ret;
std::ifstream fs;
std::string properties_path;
assert(retVec != nullptr);
ret = OpenKFDNodeFile(kfd_node_id, "properties", &fs);
if (ret) {
return ret;
}
while (std::getline(fs, line)) {
retVec->push_back(line);
}
if (retVec->size() == 0) {
fs.close();
return ENOENT;
}
// Remove any *trailing* empty (whitespace) lines
while (retVec->back().find_first_not_of(" \t\n\v\f\r") == std::string::npos) {
retVec->pop_back();
}
fs.close();
return 0;
}
static int ReadKFDGpuId(uint32_t kfd_node_id, uint64_t *gpu_id) {
std::string line;
int ret;
std::ifstream fs;
std::string gpu_id_str;
assert(gpu_id != nullptr);
ret = OpenKFDNodeFile(kfd_node_id, "gpu_id", &fs);
if (ret) {
fs.close();
return ret;
}
std::stringstream ss;
ss << fs.rdbuf();
fs.close();
gpu_id_str = ss.str();
gpu_id_str.erase(std::remove(gpu_id_str.begin(), gpu_id_str.end(), '\n'),
gpu_id_str.end());
if (!is_number(gpu_id_str)) {
return ENXIO;
}
*gpu_id = static_cast<uint64_t>(std::stoi(gpu_id_str));
return 0;
}
static int ReadKFDGpuName(uint32_t kfd_node_id, std::string *gpu_name) {
std::string line;
int ret;
std::ifstream fs;
assert(gpu_name != nullptr);
ret = OpenKFDNodeFile(kfd_node_id, "name", &fs);
if (ret) {
fs.close();
return ret;
}
std::stringstream ss;
ss << fs.rdbuf();
fs.close();
*gpu_name = ss.str();
gpu_name->erase(std::remove(gpu_name->begin(), gpu_name->end(), '\n'),
gpu_name->end());
return 0;
}
int GetProcessInfo(rsmi_process_info_t *procs, uint32_t num_allocated,
uint32_t *num_procs_found) {
assert(num_procs_found != nullptr);
*num_procs_found = 0;
errno = 0;
auto proc_dir = opendir(kKFDProcPathRoot);
if (proc_dir == nullptr) {
perror("Unable to open process directory");
return errno;
}
auto dentry = readdir(proc_dir);
std::string proc_id_str;
std::string tmp;
while (dentry != nullptr) {
if (dentry->d_name[0] == '.') {
dentry = readdir(proc_dir);
continue;
}
proc_id_str = dentry->d_name;
assert(is_number(proc_id_str) && "Unexpected file name in kfd/proc dir");
if (!is_number(proc_id_str)) {
dentry = readdir(proc_dir);
continue;
}
if (procs && *num_procs_found < num_allocated) {
int err;
std::string tmp;
procs[*num_procs_found].process_id =
static_cast<uint32_t>(std::stoi(proc_id_str));
std::string pasid_str_path = kKFDProcPathRoot;
pasid_str_path += "/";
pasid_str_path += proc_id_str;
pasid_str_path += "/";
pasid_str_path += kKFDPasidFName;
err = ReadSysfsStr(pasid_str_path, &tmp);
if (err) {
dentry = readdir(proc_dir);
continue;
}
assert(is_number(tmp) && "Unexpected value in pasid file");
if (!is_number(tmp)) {
closedir(proc_dir);
return EINVAL;
}
procs[*num_procs_found].pasid = static_cast<uint32_t>(std::stoi(tmp));
}
++(*num_procs_found);
dentry = readdir(proc_dir);
}
errno = 0;
if (closedir(proc_dir)) {
return errno;
}
return 0;
}
// Read the gpuid files found in all the <queue id> dirs and put them in
// gpus_found.
// Directory structure:
// /sys/class/kfd/kfd/proc/<pid>/queues/<queue id>/gpuid
int GetProcessGPUs(uint32_t pid, std::unordered_set<uint64_t> *gpu_set) {
int err;
assert(gpu_set != nullptr);
if (gpu_set == nullptr) {
return RSMI_STATUS_INVALID_ARGS;
}
errno = 0;
std::string queues_dir = kKFDProcPathRoot;
queues_dir += "/";
queues_dir += std::to_string(pid);
queues_dir += "/queues";
auto queues_dir_hd = opendir(queues_dir.c_str());
if (queues_dir_hd == nullptr) {
std::string err_str = "Unable to open queues directory for process ";
err_str += std::to_string(pid);
perror(err_str.c_str());
return ESRCH;
}
auto q_dentry = readdir(queues_dir_hd);
std::string q_gpu_id_str;
std::string q_dir;
std::string tmp;
while (q_dentry != nullptr) {
if (q_dentry->d_name[0] == '.') {
q_dentry = readdir(queues_dir_hd);
continue;
}
if (!is_number(q_dentry->d_name)) {
q_dentry = readdir(queues_dir_hd);
continue;
}
q_gpu_id_str = queues_dir + '/' + q_dentry->d_name + "/gpuid";
err = ReadSysfsStr(q_gpu_id_str, &tmp);
if (err) {
q_dentry = readdir(queues_dir_hd);
continue;
}
uint64_t val;
try {
val = static_cast<uint64_t>(std::stoi(tmp));
} catch (...) {
std::cerr << "Error; read invalid data: " << tmp << " from " <<
q_gpu_id_str << std::endl;
closedir(queues_dir_hd);
return ENXIO; // Return "no such device" if we read an invalid gpu id
}
gpu_set->insert(val);
q_dentry = readdir(queues_dir_hd);
}
errno = 0;
if (closedir(queues_dir_hd)) {
return errno;
}
return 0;
}
int GetProcessInfoForPID(uint32_t pid, rsmi_process_info_t *proc,
std::unordered_set<uint64_t> *gpu_set) {
assert(proc != nullptr);
assert(gpu_set != nullptr);
int err;
std::string tmp;
std::unordered_set<uint64_t>::iterator itr;
std::string proc_str_path = kKFDProcPathRoot;
proc_str_path += "/";
proc_str_path += std::to_string(pid);
if (!FileExists(proc_str_path.c_str())) {
return ESRCH;
}
proc->process_id = pid;
std::string pasid_str_path = proc_str_path;
pasid_str_path += "/";
pasid_str_path += kKFDPasidFName;
err = ReadSysfsStr(pasid_str_path, &tmp);
if (err) {
return err;
}
assert(is_number(tmp) && "Unexpected value in pasid file");
if (!is_number(tmp)) {
return EINVAL;
}
proc->pasid = static_cast<uint32_t>(std::stoi(tmp));
proc->vram_usage = 0;
proc->sdma_usage = 0;
proc->cu_occupancy = 0;
uint32_t cu_count = 0;
static amd::smi::RocmSMI& smi = amd::smi::RocmSMI::getInstance();
static std::map<uint64_t, std::shared_ptr<KFDNode>>& kfd_node_map =
smi.kfd_node_map();
for (itr = gpu_set->begin(); itr != gpu_set->end(); itr++) {
uint64_t gpu_id = (*itr);
std::string vram_str_path = proc_str_path;
vram_str_path += "/vram_";
vram_str_path += std::to_string(gpu_id);
err = ReadSysfsStr(vram_str_path, &tmp);
if (err) {
return err;
}
if (!is_number(tmp)) {
return EINVAL;
}
proc->vram_usage += std::stoull(tmp);
std::string sdma_str_path = proc_str_path;
sdma_str_path += "/sdma_";
sdma_str_path += std::to_string(gpu_id);
err = ReadSysfsStr(sdma_str_path, &tmp);
if (err) {
return err;
}
if (!is_number(tmp)) {
return EINVAL;
}
proc->sdma_usage += std::stoull(tmp);
// Build the path and read from Sysfs file, info that
// encodes Compute Unit usage by a process of interest
std::string cu_occupancy_path = proc_str_path;
cu_occupancy_path += "/stats_";
cu_occupancy_path += std::to_string(gpu_id);
cu_occupancy_path += "/cu_occupancy";
err = ReadSysfsStr(cu_occupancy_path, &tmp);
if (err == 0) {
if (!is_number(tmp)) {
return EINVAL;
}
// Update CU usage by the process
proc->cu_occupancy += std::stoi(tmp);
// Collect count of compute units
cu_count += kfd_node_map[gpu_id]->cu_count();
}
}
// Adjust CU occupancy to percent.
if (cu_count > 0) {
proc->cu_occupancy = ((proc->cu_occupancy * 100) / cu_count);
}
return 0;
}
int DiscoverKFDNodes(std::map<uint64_t, std::shared_ptr<KFDNode>> *nodes) {
assert(nodes != nullptr);
if (nodes == nullptr) {
return EINVAL;
}
assert(nodes->size() == 0);
nodes->clear();
std::shared_ptr<KFDNode> node;
uint32_t node_indx;
auto kfd_node_dir = opendir(kKFDNodesPathRoot);
if (kfd_node_dir == nullptr) {
return errno;
}
auto dentry = readdir(kfd_node_dir);
while (dentry != nullptr) {
if (dentry->d_name[0] == '.') {
dentry = readdir(kfd_node_dir);
continue;
}
if (!is_number(dentry->d_name)) {
dentry = readdir(kfd_node_dir);
continue;
}
node_indx = static_cast<uint32_t>(std::stoi(dentry->d_name));
if (!KFDNodeSupported(node_indx)) {
dentry = readdir(kfd_node_dir);
continue;
}
node = std::shared_ptr<KFDNode>(new KFDNode(node_indx));
node->Initialize();
if (node->gpu_id() == 0) {
// Don't add; this is a cpu node.
dentry = readdir(kfd_node_dir);
continue;
}
uint64_t kfd_gpu_node_bus_fn;
uint64_t kfd_gpu_node_domain;
int ret;
ret =
node->get_property_value(kKFDNodePropLOCATION_IDStr,
&kfd_gpu_node_bus_fn);
if (ret != 0) {
std:: cerr << "Failed to open properties file for kfd node " <<
node->node_index() << "." << std::endl;
closedir(kfd_node_dir);
return ret;
}
ret =
node->get_property_value(kKFDNodePropDOMAINStr, &kfd_gpu_node_domain);
if (ret != 0) {
std::cerr << "Failed to get \"domain\" properity from properties "
"files for kfd node " << node->node_index() << "." << std::endl;
closedir(kfd_node_dir);
return ret;
}
uint64_t kfd_bdfid =
(kfd_gpu_node_domain << 32) | (kfd_gpu_node_bus_fn);
(*nodes)[kfd_bdfid] = node;
dentry = readdir(kfd_node_dir);
}
if (closedir(kfd_node_dir)) {
std::string err_str = "Failed to close KFD node directory ";
err_str += kKFDNodesPathRoot;
err_str += ".";
perror(err_str.c_str());
return 1;
}
return 0;
}
KFDNode::~KFDNode() {
}
int KFDNode::ReadProperties(void) {
int ret;
std::vector<std::string> propVec;
assert(properties_.size() == 0);
if (properties_.size() > 0) {
return 0;
}
ret = ReadKFDDeviceProperties(node_indx_, &propVec);
if (ret) {
return ret;
}
std::string key_str;
// std::string val_str;
uint64_t val_int; // Assume all properties are unsigned integers for now
std::istringstream fs;
for (uint32_t i = 0; i < propVec.size(); ++i) {
fs.str(propVec[i]);
fs >> key_str;
fs >> val_int;
properties_[key_str] = val_int;
fs.str("");
fs.clear();
}
return 0;
}
int
KFDNode::Initialize(void) {
int ret = 0;
ret = ReadProperties();
if (ret) {return ret;}
ret = ReadKFDGpuId(node_indx_, &gpu_id_);
if (ret || (gpu_id_ == 0)) {return ret;}
ret = ReadKFDGpuName(node_indx_, &name_);
ret = get_property_value(kKFDNodePropHIVE_IDStr, &xgmi_hive_id_);
if (ret != 0) {
throw amd::smi::rsmi_exception(RSMI_INITIALIZATION_ERROR,
"Failed to initialize rocm_smi library (get xgmi hive id).");
}
std::map<uint32_t, std::shared_ptr<IOLink>> io_link_map_tmp;
ret = DiscoverIOLinksPerNode(node_indx_, &io_link_map_tmp);
if (ret != 0) {
throw amd::smi::rsmi_exception(RSMI_INITIALIZATION_ERROR,
"Failed to initialize rocm_smi library (IO Links discovery per node).");
}
std::map<uint32_t, std::shared_ptr<IOLink>>::iterator it;
uint32_t node_to;
uint64_t node_to_gpu_id;
std::shared_ptr<IOLink> link;
bool numa_node_found = false;
for (it = io_link_map_tmp.begin(); it != io_link_map_tmp.end(); it++) {
io_link_map_[it->first] = it->second;
node_to = it->first;
link = it->second;
ret = ReadKFDGpuId(node_to, &node_to_gpu_id);
if (ret) {return ret;}
if (node_to_gpu_id == 0) { // CPU node
if (numa_node_found) {
if (numa_node_weight_ > link->weight()) {
numa_node_number_ = node_to;
numa_node_weight_ = link->weight();
numa_node_type_ = link->type();
}
} else {
numa_node_number_ = node_to;
numa_node_weight_ = link->weight();
numa_node_type_ = link->type();
numa_node_found = true;
}
} else {
io_link_type_[node_to] = link->type();
io_link_weight_[node_to] = link->weight();
io_link_max_bandwidth_[node_to] = link->max_bandwidth();
io_link_min_bandwidth_[node_to] = link->min_bandwidth();
}
}
// Pre-compute the total number of compute units a device has
uint64_t tmp_val;
ret = get_property_value(kKFDNodePropSIMD_ARRAYS_PER_ENGINEStr, &tmp_val);
if (ret != 0) {
throw amd::smi::rsmi_exception(RSMI_INITIALIZATION_ERROR,
"Failed to initialize rocm_smi library "
"(get number of shader arrays per engine).");
}
cu_count_ = uint32_t(tmp_val);
ret = get_property_value(kKFDNodePropARRAY_COUNTStr, &tmp_val);
if (ret != 0) {
throw amd::smi::rsmi_exception(RSMI_INITIALIZATION_ERROR,
"Failed to initialize rocm_smi library (get number of shader arrays).");
}
cu_count_ = cu_count_ * uint32_t(tmp_val);
ret = get_property_value(kKFDNodePropCU_PER_SIMD_ARRAYStr, &tmp_val);
if (ret != 0) {
throw amd::smi::rsmi_exception(RSMI_INITIALIZATION_ERROR,
"Failed to initialize rocm_smi library (get number of CU's per array).");
}
cu_count_ = cu_count_ * uint32_t(tmp_val);
return ret;
}
int
KFDNode::get_property_value(std::string property, uint64_t *value) {
assert(value != nullptr);
if (value == nullptr) {
return EINVAL;
}
if (properties_.find(property) == properties_.end()) {
return EINVAL;
}
*value = properties_[property];
return 0;
}
int
KFDNode::get_io_link_type(uint32_t node_to, IO_LINK_TYPE *type) {
assert(type != nullptr);
if (type == nullptr) {
return EINVAL;
}
if (io_link_type_.find(node_to) == io_link_type_.end()) {
return EINVAL;
}
*type = io_link_type_[node_to];
return 0;
}
int
KFDNode::get_io_link_weight(uint32_t node_to, uint64_t *weight) {
assert(weight != nullptr);
if (weight == nullptr) {
return EINVAL;
}
if (io_link_weight_.find(node_to) == io_link_weight_.end()) {
return EINVAL;
}
*weight = io_link_weight_[node_to];
return 0;
}
int
KFDNode::get_io_link_bandwidth(uint32_t node_to, uint64_t *max_bandwidth,
uint64_t *min_bandwidth){
assert (max_bandwidth != nullptr && min_bandwidth != nullptr);
if (max_bandwidth == nullptr || min_bandwidth == nullptr ){
return EINVAL;
}
if (io_link_max_bandwidth_.find(node_to) == io_link_max_bandwidth_.end() ||
io_link_min_bandwidth_.find(node_to) == io_link_min_bandwidth_.end()){
return EINVAL;
}
*max_bandwidth = io_link_max_bandwidth_[node_to];
*min_bandwidth = io_link_min_bandwidth_[node_to];
return 0;
}
} // namespace smi
} // namespace amd
-659
View File
@@ -1,659 +0,0 @@
/*
* The University of Illinois/NCSA
* Open Source License (NCSA)
*
* Copyright (c) 2017, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Developed by:
*
* AMD Research and AMD ROC Software Development
*
* Advanced Micro Devices, Inc.
*
* www.amd.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal with 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:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimers.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimers in
* the documentation and/or other materials provided with the distribution.
* - Neither the names of <Name of Development Group, Name of Institution>,
* nor the names of its contributors may be used to endorse or promote
* products derived from this Software without specific prior written
* permission.
*
* 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 CONTRIBUTORS 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 WITH THE SOFTWARE.
*
*/
#include <dirent.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string>
#include <cstdint>
#include <memory>
#include <fstream>
#include <vector>
#include <set>
#include <utility>
#include <functional>
#include <cerrno>
#include <unordered_map>
#include <iostream>
#include "rocm_smi/rocm_smi.h"
#include "rocm_smi/rocm_smi_device.h"
#include "rocm_smi/rocm_smi_main.h"
#include "rocm_smi/rocm_smi_exception.h"
#include "rocm_smi/rocm_smi_utils.h"
#include "rocm_smi/rocm_smi_kfd.h"
static const char *kPathDRMRoot = "/sys/class/drm";
static const char *kPathHWMonRoot = "/sys/class/hwmon";
static const char *kPathPowerRoot = "/sys/kernel/debug/dri";
static const char *kDeviceNamePrefix = "card";
static const char *kAMDMonitorTypes[] = {"radeon", "amdgpu", ""};
namespace amd {
namespace smi {
static uint32_t GetDeviceIndex(const std::string s) {
std::string t = s;
size_t tmp = t.find_last_not_of("0123456789");
t.erase(0, tmp+1);
assert(stoi(t) >= 0);
return static_cast<uint32_t>(stoi(t));
}
// Find the drm minor from from sysfs path "/sys/class/drm/cardX/device/drm".
// From the directory renderDN in that sysfs path, the drm minor can be
// computed for cardX.
// On success, return drm_minor which is >= 128 otherwise return 0
static uint32_t GetDrmRenderMinor(const std::string s) {
std::string drm_path = s;
int drm_minor = 0;
const std::string render_file_prefix = "renderD";
const uint64_t prefix_size = render_file_prefix.size();
drm_path += "/device/drm";
auto drm_dir = opendir(drm_path.c_str());
if (drm_dir == nullptr)
return 0;
auto dentry = readdir(drm_dir);
while (dentry != nullptr) {
std::string render_file = dentry->d_name;
if (!render_file.compare(0, prefix_size, render_file_prefix)) {
drm_minor = stoi(render_file.substr(prefix_size));
if (drm_minor)
break;
}
dentry = readdir(drm_dir);
}
if (closedir(drm_dir)) {
return 0;
}
return static_cast<uint32_t>(drm_minor);
}
// Determine if provided string is a bdfid pci path directory of the form
// XXXX:XX:XX.X,
// domain:bus:device.function
//
// where X is a hex integer (lower case is expected). If so, write the value
// to bdfid
static bool bdfid_from_path(const std::string in_name, uint64_t *bdfid) {
char *p = nullptr;
char *name_start;
char name[13] = {'\0'};
uint64_t tmp;
assert(bdfid != nullptr);
if (in_name.size() != 12) {
return false;
}
tmp = in_name.copy(name, 12);
assert(tmp == 12);
// BDFID = ((<DOMAIN> & 0xffff) << 32) | ((<BUS> & 0xff) << 8) |
// ((device& 0x1f) <<3 ) | (function & 0x7)
*bdfid = 0;
name_start = name;
p = name_start;
// Match this: XXXX:xx:xx.x
tmp = std::strtoul(p, &p, 16);
if (*p != ':' || p - name_start != 4) {
return false;
}
*bdfid |= tmp << 32;
// Match this: xxxx:XX:xx.x
p++; // Skip past ':'
tmp = std::strtoul(p, &p, 16);
if (*p != ':' || p - name_start != 7) {
return false;
}
*bdfid |= tmp << 8;
// Match this: xxxx:xx:XX.x
p++; // Skip past ':'
tmp = std::strtoul(p, &p, 16);
if (*p != '.' || p - name_start != 10) {
return false;
}
*bdfid |= tmp << 3;
// Match this: xxxx:xx:xx.X
p++; // Skip past '.'
tmp = std::strtoul(p, &p, 16);
if (*p != '\0' || p - name_start != 12) {
return false;
}
*bdfid |= tmp;
return true;
}
static uint32_t ConstructBDFID(std::string path, uint64_t *bdfid) {
assert(bdfid != nullptr);
char tpath[256] = {'\0'};
ssize_t ret;
memset(tpath,0,256);
ret = readlink(path.c_str(), tpath, 256);
assert(ret > 0);
assert(ret < 256);
if (ret <= 0 || ret >= 256) {
return 1;
}
// We are looking for the last element in the path that has the form
// XXXX:XX:XX.X, where X is a hex integer (lower case is expected)
std::size_t slash_i, end_i;
std::string tmp;
std::string tpath_str(tpath);
end_i = tpath_str.size() - 1;
while (end_i > 0) {
slash_i = tpath_str.find_last_of('/', end_i);
tmp = tpath_str.substr(slash_i + 1, end_i - slash_i);
if (bdfid_from_path(tmp, bdfid)) {
return 0;
}
end_i = slash_i - 1;
}
return 1;
}
void
RocmSMI::Initialize(uint64_t flags) {
auto i = 0;
uint32_t ret;
int i_ret;
assert(ref_count_ == 1);
if (ref_count_ != 1) {
throw amd::smi::rsmi_exception(RSMI_INITIALIZATION_ERROR,
"Unexpected: RocmSMI ref_count_ != 1");
}
init_options_ = flags;
euid_ = geteuid();
GetEnvVariables();
while (env_vars_.debug_inf_loop) {}
while (std::string(kAMDMonitorTypes[i]) != "") {
amd_monitor_types_.insert(kAMDMonitorTypes[i]);
++i;
}
// DiscoverAmdgpuDevices() will search for devices and monitors and update
// internal data structures.
ret = DiscoverAmdgpuDevices();
if (ret != 0) {
throw amd::smi::rsmi_exception(RSMI_INITIALIZATION_ERROR,
"DiscoverAmdgpuDevices() failed.");
}
uint64_t bdfid;
for (uint32_t i = 0; i < devices_.size(); ++i) {
if (ConstructBDFID(devices_[i]->path(), &bdfid) != 0) {
std::cerr << "Failed to construct BDFID." << std::endl;
ret = 1;
}
devices_[i]->set_bdfid(bdfid);
}
if (ret != 0) {
throw amd::smi::rsmi_exception(RSMI_INITIALIZATION_ERROR,
"Failed to initialize rocm_smi library (amdgpu node discovery).");
}
std::map<uint64_t, std::shared_ptr<KFDNode>> tmp_map;
i_ret = DiscoverKFDNodes(&tmp_map);
if (i_ret != 0) {
throw amd::smi::rsmi_exception(RSMI_INITIALIZATION_ERROR,
"Failed to initialize rocm_smi library (KFD node discovery).");
}
std::map<std::pair<uint32_t, uint32_t>, std::shared_ptr<IOLink>>
io_link_map_tmp;
i_ret = DiscoverIOLinks(&io_link_map_tmp);
if (i_ret != 0) {
throw amd::smi::rsmi_exception(RSMI_INITIALIZATION_ERROR,
"Failed to initialize rocm_smi library (IO Links discovery).");
}
std::map<std::pair<uint32_t, uint32_t>, std::shared_ptr<IOLink>>::iterator it;
for (it = io_link_map_tmp.begin(); it != io_link_map_tmp.end(); it++)
io_link_map_[it->first] = it->second;
std::shared_ptr<amd::smi::Device> dev;
// Remove any drm nodes that don't have a corresponding readable kfd node.
// kfd nodes will not be added if their properties file is not readable.
auto dev_iter = devices_.begin();
while (dev_iter != devices_.end()) {
uint64_t bdfid = (*dev_iter)->bdfid();
if (tmp_map.find(bdfid) == tmp_map.end()) {
dev_iter = devices_.erase(dev_iter);
continue;
}
dev_iter++;
}
// 1. construct kfd_node_map_ with gpu_id as key and *Device as value
// 2. for each kfd node, write the corresponding dv_ind
// 3. for each amdgpu device, write the corresponding gpu_id
for (uint32_t dv_ind = 0; dv_ind < devices_.size(); ++dv_ind) {
dev = devices_[dv_ind];
uint64_t bdfid = dev->bdfid();
assert(tmp_map.find(bdfid) != tmp_map.end());
if (tmp_map.find(bdfid) == tmp_map.end()) {
throw amd::smi::rsmi_exception(RSMI_INITIALIZATION_ERROR,
"amdgpu device bdfid has no KFD matching node");
}
tmp_map[bdfid]->set_amdgpu_dev_index(dv_ind);
dev_ind_to_node_ind_map_[dv_ind] = tmp_map[bdfid]->node_index();
uint64_t gpu_id = tmp_map[bdfid]->gpu_id();
dev->set_kfd_gpu_id(gpu_id);
kfd_node_map_[gpu_id] = tmp_map[bdfid];
}
}
void
RocmSMI::Cleanup() {
devices_.clear();
monitors_.clear();
if (kfd_notif_evt_fh() >= 0) {
int ret = close(kfd_notif_evt_fh());
if (ret < 0) {
throw amd::smi::rsmi_exception(RSMI_STATUS_FILE_ERROR,
"Failed to close kfd file handle on shutdown.");
}
}
}
RocmSMI::RocmSMI(uint64_t flags) : init_options_(flags),
kfd_notif_evt_fh_(-1), kfd_notif_evt_fh_refcnt_(0) {
}
RocmSMI::~RocmSMI() {
}
RocmSMI& RocmSMI::getInstance(uint64_t flags) {
// Assume c++11 or greater. static objects will be created by only 1 thread
// and creation will be thread-safe.
static RocmSMI singleton(flags);
return singleton;
}
static uint32_t GetEnvVarUInteger(const char *ev_str) {
#ifndef DEBUG
(void)ev_str;
#else
ev_str = getenv(ev_str);
if (ev_str) {
int ret = atoi(ev_str);
assert(ret >= 0);
return static_cast<uint32_t>(ret);
}
#endif
return 0;
}
// Get and store env. variables in this method
void RocmSMI::GetEnvVariables(void) {
#ifndef DEBUG
(void)GetEnvVarUInteger(nullptr); // This is to quiet release build warning.
env_vars_.debug_output_bitfield = 0;
env_vars_.path_DRM_root_override = nullptr;
env_vars_.path_HWMon_root_override = nullptr;
env_vars_.path_power_root_override = nullptr;
env_vars_.enum_override = 0;
env_vars_.debug_inf_loop = 0;
#else
env_vars_.debug_output_bitfield = GetEnvVarUInteger("RSMI_DEBUG_BITFIELD");
env_vars_.path_DRM_root_override = getenv("RSMI_DEBUG_DRM_ROOT_OVERRIDE");
env_vars_.path_HWMon_root_override = getenv("RSMI_DEBUG_HWMON_ROOT_OVERRIDE");
env_vars_.path_power_root_override = getenv("RSMI_DEBUG_PP_ROOT_OVERRIDE");
env_vars_.enum_override = GetEnvVarUInteger("RSMI_DEBUG_ENUM_OVERRIDE");
env_vars_.debug_inf_loop = GetEnvVarUInteger("RSMI_DEBUG_INFINITE_LOOP");
#endif
}
const RocmSMI_env_vars& RocmSMI::getEnv(void) {
return env_vars_;
}
std::shared_ptr<Monitor>
RocmSMI::FindMonitor(std::string monitor_path) {
std::string tmp;
std::string err_msg;
std::string mon_name;
std::shared_ptr<Monitor> m;
if (!FileExists(monitor_path.c_str())) {
return nullptr;
}
auto mon_dir = opendir(monitor_path.c_str());
if (mon_dir == nullptr) {
return nullptr;
}
auto dentry = readdir(mon_dir);
while (dentry != nullptr) {
if (dentry->d_name[0] == '.') {
dentry = readdir(mon_dir);
continue;
}
mon_name = monitor_path;
mon_name += "/";
mon_name += dentry->d_name;
tmp = mon_name + "/name";
if (FileExists(tmp.c_str())) {
std::ifstream fs;
fs.open(tmp);
if (!fs.is_open()) {
err_msg = "Failed to open monitor file ";
err_msg += tmp;
err_msg += ".";
perror(err_msg.c_str());
return nullptr;
}
std::string mon_type;
fs >> mon_type;
fs.close();
if (amd_monitor_types_.find(mon_type) != amd_monitor_types_.end()) {
m = std::shared_ptr<Monitor>(new Monitor(mon_name, &env_vars_));
m->setTempSensorLabelMap();
m->setVoltSensorLabelMap();
break;
}
}
dentry = readdir(mon_dir);
}
if (closedir(mon_dir)) {
err_msg = "Failed to close monitor directory ";
err_msg += kPathHWMonRoot;
err_msg += ".";
perror(err_msg.c_str());
return nullptr;
}
return m;
}
void
RocmSMI::AddToDeviceList(std::string dev_name) {
auto dev_path = std::string(kPathDRMRoot);
dev_path += "/";
dev_path += dev_name;
auto dev = std::shared_ptr<Device>(new Device(dev_path, &env_vars_));
std::shared_ptr<Monitor> m = FindMonitor(dev_path + "/device/hwmon");
dev->set_monitor(m);
std::string d_name = dev_name;
uint32_t card_indx = GetDeviceIndex(d_name);
dev->set_drm_render_minor(GetDrmRenderMinor(dev_path));
dev->set_card_index(card_indx);
GetSupportedEventGroups(card_indx, dev->supported_event_groups());
devices_.push_back(dev);
return;
}
static const uint32_t kAmdGpuId = 0x1002;
static bool isAMDGPU(std::string dev_path) {
std::string vend_path = dev_path + "/device/vendor";
std::string vbios_v_path = dev_path + "/device/vbios_version";
if (!FileExists(vend_path.c_str())) {
return false;
}
if (!FileExists(vbios_v_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;
}
uint32_t RocmSMI::DiscoverAmdgpuDevices(void) {
std::string err_msg;
uint32_t count = 0;
// If this gets called more than once, clear previous findings.
devices_.clear();
monitors_.clear();
auto drm_dir = opendir(kPathDRMRoot);
if (drm_dir == nullptr) {
err_msg = "Failed to open drm root directory ";
err_msg += kPathDRMRoot;
err_msg += ".";
perror(err_msg.c_str());
return 1;
}
auto dentry = readdir(drm_dir);
while (dentry != nullptr) {
if (memcmp(dentry->d_name, kDeviceNamePrefix, strlen(kDeviceNamePrefix))
== 0) {
if ((strcmp(dentry->d_name, ".") == 0) ||
(strcmp(dentry->d_name, "..") == 0))
continue;
count++;
}
dentry = readdir(drm_dir);
}
for (uint32_t node_id = 0; node_id < count; node_id++) {
std::string path = kPathDRMRoot;
path += "/card";
path += std::to_string(node_id);
if (isAMDGPU(path) ||
(init_options_ & RSMI_INIT_FLAG_ALL_GPUS)) {
std::string d_name = "card";
d_name += std::to_string(node_id);
AddToDeviceList(d_name);
}
}
if (closedir(drm_dir)) {
err_msg = "Failed to close drm root directory ";
err_msg += kPathDRMRoot;
err_msg += ".";
perror(err_msg.c_str());
return 1;
}
return 0;
}
// Since these sysfs files require sudo access, we won't discover them
// with rsmi_init() (and thus always require the user to use "sudo".
// Instead, we will discover() all the power monitors the first time
// they are needed and then check for previous discovery on each subsequent
// call.
int RocmSMI::DiscoverAMDPowerMonitors(bool force_update) {
if (force_update) {
power_mons_.clear();
}
if (power_mons_.size() != 0) {
return 0;
}
errno = 0;
auto dri_dir = opendir(kPathPowerRoot);
if (dri_dir == nullptr) {
return errno;
}
auto dentry = readdir(dri_dir);
std::string mon_name;
std::string tmp;
while (dentry != nullptr) {
if (dentry->d_name[0] == '.') {
dentry = readdir(dri_dir);
continue;
}
mon_name = kPathPowerRoot;
mon_name += "/";
mon_name += dentry->d_name;
tmp = mon_name + "/amdgpu_pm_info";
if (FileExists(tmp.c_str())) {
std::shared_ptr<PowerMon> mon =
std::shared_ptr<PowerMon>(new PowerMon(mon_name, &env_vars_));
power_mons_.push_back(mon);
mon->set_dev_index(GetDeviceIndex(dentry->d_name));
}
dentry = readdir(dri_dir);
}
errno = 0;
if (closedir(dri_dir)) {
power_mons_.clear();
return errno;
}
for (auto m : power_mons_) {
for (auto d : devices_) {
if (m->dev_index() == d->index()) {
d->set_power_monitor(m);
break;
}
}
}
return 0;
}
uint32_t RocmSMI::IterateSMIDevices(
std::function<uint32_t(std::shared_ptr<Device>&, void *)> func, void *p) {
if (func == nullptr) {
return 1;
}
auto d = devices_.begin();
uint32_t ret;
while (d != devices_.end()) {
ret = func(*d, p);
if (ret != 0) {
return ret;
}
++d;
}
return 0;
}
int RocmSMI::get_node_index(uint32_t dv_ind, uint32_t *node_ind) {
if (dev_ind_to_node_ind_map_.find(dv_ind) == dev_ind_to_node_ind_map_.end()) {
return EINVAL;
}
*node_ind = dev_ind_to_node_ind_map_[dv_ind];
return 0;
}
int RocmSMI::get_io_link_weight(uint32_t node_from, uint32_t node_to,
uint64_t *weight) {
assert(weight != nullptr);
if (weight == nullptr) {
return EINVAL;
}
if (io_link_map_.find(std::make_pair(node_from, node_to)) ==
io_link_map_.end()) {
return EINVAL;
}
*weight = io_link_map_[std::make_pair(node_from, node_to)]->weight();
return 0;
}
} // namespace smi
} // namespace amd
-639
View File
@@ -1,639 +0,0 @@
/*
* =============================================================================
* The University of Illinois/NCSA
* Open Source License (NCSA)
*
* Copyright (c) 2017, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Developed by:
*
* AMD Research and AMD ROC Software Development
*
* Advanced Micro Devices, Inc.
*
* www.amd.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal with 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:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimers.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimers in
* the documentation and/or other materials provided with the distribution.
* - Neither the names of <Name of Development Group, Name of Institution>,
* nor the names of its contributors may be used to endorse or promote
* products derived from this Software without specific prior written
* permission.
*
* 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 CONTRIBUTORS 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 WITH THE SOFTWARE.
*
*/
#include <assert.h>
#include <dirent.h>
#include <fstream>
#include <string>
#include <cstdint>
#include <map>
#include <iostream>
#include <algorithm>
#include <regex> // NOLINT
#include <vector>
#include "rocm_smi/rocm_smi_main.h"
#include "rocm_smi/rocm_smi_monitor.h"
#include "rocm_smi/rocm_smi_utils.h"
#include "rocm_smi/rocm_smi_exception.h"
namespace amd {
namespace smi {
struct MonitorNameEntry {
MonitorTypes type;
const char *name;
};
static const char *kMonTempFName = "temp#_input";
static const char *kMonFanSpeedFName = "pwm#";
static const char *kMonMaxFanSpeedFName = "pwm#_max";
static const char *kMonFanRPMsName = "fan#_input";
static const char *kMonFanControlEnableName = "pwm#_enable";
static const char *kMonNameFName = "name";
static const char *kMonPowerCapDefaultName = "power#_cap_default";
static const char *kMonPowerCapName = "power#_cap";
static const char *kMonPowerCapMaxName = "power#_cap_max";
static const char *kMonPowerCapMinName = "power#_cap_min";
static const char *kMonPowerAveName = "power#_average";
static const char *kMonTempMaxName = "temp#_max";
static const char *kMonTempMinName = "temp#_min";
static const char *kMonTempMaxHystName = "temp#_max_hyst";
static const char *kMonTempMinHystName = "temp#_min_hyst";
static const char *kMonTempCriticalName = "temp#_crit";
static const char *kMonTempCriticalHystName = "temp#_crit_hyst";
static const char *kMonTempEmergencyName = "temp#_emergency";
static const char *kMonTempEmergencyHystName = "temp#_emergency_hyst";
static const char *kMonTempCritMinName = "temp#_lcrit";
static const char *kMonTempCritMinHystName = "temp#_lcrit_hyst";
static const char *kMonTempOffsetName = "temp#_offset";
static const char *kMonTempLowestName = "temp#_lowest";
static const char *kMonTempHighestName = "temp#_highest";
static const char *kMonTempLabelName = "temp#_label";
static const char *kMonVoltFName = "in#_input";
static const char *kMonVoltMinName = "in#_min";
static const char *kMonVoltMinCritName = "in#_lcrit";
static const char *kMonVoltMaxName = "in#_max";
static const char *kMonVoltMaxCritName = "in#_crit";
static const char *kMonVoltAverageName = "in#_average";
static const char *kMonVoltLowestName = "in#_lowest";
static const char *kMonVoltHighestName = "in#_highest";
static const char *kMonVoltLabelName = "in#_label";
static const char *kTempSensorTypeMemoryName = "mem";
static const char *kTempSensorTypeJunctionName = "junction";
static const char *kTempSensorTypeEdgeName = "edge";
static const char *kTempSensorTypeVddgfxName = "vddgfx";
static const std::map<std::string, rsmi_temperature_type_t>
kTempSensorNameMap = {
{kTempSensorTypeMemoryName, RSMI_TEMP_TYPE_MEMORY},
{kTempSensorTypeJunctionName, RSMI_TEMP_TYPE_JUNCTION},
{kTempSensorTypeEdgeName, RSMI_TEMP_TYPE_EDGE},
};
static const std::map<std::string, rsmi_voltage_type_t>
kVoltSensorNameMap = {
{kTempSensorTypeVddgfxName, RSMI_VOLT_TYPE_VDDGFX},
};
static const std::map<MonitorTypes, const char *> kMonitorNameMap = {
{kMonName, kMonNameFName},
{kMonTemp, kMonTempFName},
{kMonFanSpeed, kMonFanSpeedFName},
{kMonFanCntrlEnable, kMonFanControlEnableName},
{kMonMaxFanSpeed, kMonMaxFanSpeedFName},
{kMonFanRPMs, kMonFanRPMsName},
{kMonPowerCap, kMonPowerCapName},
{kMonPowerCapDefault, kMonPowerCapDefaultName},
{kMonPowerCapMax, kMonPowerCapMaxName},
{kMonPowerCapMin, kMonPowerCapMinName},
{kMonPowerAve, kMonPowerAveName},
{kMonTempMax, kMonTempMaxName},
{kMonTempMin, kMonTempMinName},
{kMonTempMaxHyst, kMonTempMaxHystName},
{kMonTempMinHyst, kMonTempMinHystName},
{kMonTempCritical, kMonTempCriticalName},
{kMonTempCriticalHyst, kMonTempCriticalHystName},
{kMonTempEmergency, kMonTempEmergencyName},
{kMonTempEmergencyHyst, kMonTempEmergencyHystName},
{kMonTempCritMin, kMonTempCritMinName},
{kMonTempCritMinHyst, kMonTempCritMinHystName},
{kMonTempOffset, kMonTempOffsetName},
{kMonTempLowest, kMonTempLowestName},
{kMonTempHighest, kMonTempHighestName},
{kMonTempLabel, kMonTempLabelName},
{kMonVolt, kMonVoltFName},
{kMonVoltMin, kMonVoltMinName},
{kMonVoltMinCrit, kMonVoltMinCritName},
{kMonVoltMax, kMonVoltMaxName},
{kMonVoltMaxCrit, kMonVoltMaxCritName},
{kMonVoltAverage, kMonVoltAverageName},
{kMonVoltLowest, kMonVoltLowestName},
{kMonVoltHighest, kMonVoltHighestName},
{kMonVoltLabel, kMonVoltLabelName},
};
static std::map<MonitorTypes, uint64_t> kMonInfoVarTypeToRSMIVariant = {
// rsmi_temperature_metric_t
{kMonTemp, RSMI_TEMP_CURRENT},
{kMonTempMax, RSMI_TEMP_MAX},
{kMonTempMin, RSMI_TEMP_MIN},
{kMonTempMaxHyst, RSMI_TEMP_MAX_HYST},
{kMonTempMinHyst, RSMI_TEMP_MIN_HYST},
{kMonTempCritical, RSMI_TEMP_CRITICAL},
{kMonTempCriticalHyst, RSMI_TEMP_CRITICAL_HYST},
{kMonTempEmergency, RSMI_TEMP_EMERGENCY},
{kMonTempEmergencyHyst, RSMI_TEMP_EMERGENCY_HYST},
{kMonTempCritMin, RSMI_TEMP_CRIT_MIN},
{kMonTempCritMinHyst, RSMI_TEMP_CRIT_MIN_HYST},
{kMonTempOffset, RSMI_TEMP_OFFSET},
{kMonTempLowest, RSMI_TEMP_LOWEST},
{kMonTempHighest, RSMI_TEMP_HIGHEST},
{kMonInvalid, RSMI_DEFAULT_VARIANT},
// rsmi_voltage_metric_t
{kMonVolt, RSMI_VOLT_CURRENT},
{kMonVoltMin, RSMI_VOLT_MIN},
{kMonVoltMinCrit, RSMI_VOLT_MIN_CRIT},
{kMonVoltMax, RSMI_VOLT_MAX},
{kMonVoltMaxCrit, RSMI_VOLT_MAX_CRIT},
{kMonVoltAverage, RSMI_VOLT_AVERAGE},
{kMonVoltLowest, RSMI_VOLT_LOWEST},
{kMonVoltHighest, RSMI_VOLT_HIGHEST},
};
typedef struct {
std::vector<const char *> mandatory_depends;
std::vector<MonitorTypes> variants;
} monitor_depends_t;
static const std::map<const char *, monitor_depends_t> kMonFuncDependsMap = {
{"rsmi_dev_power_ave_get", { .mandatory_depends = {kMonPowerAveName},
.variants = {kMonInvalid},
}
},
{"rsmi_dev_power_cap_get", { .mandatory_depends = {kMonPowerCapName},
.variants = {kMonInvalid},
}
},
{"rsmi_dev_power_cap_default_get", { .mandatory_depends = {kMonPowerCapDefaultName},
.variants = {kMonInvalid},
}
},
{"rsmi_dev_power_cap_range_get", { .mandatory_depends =
{kMonPowerCapMaxName,
kMonPowerCapMinName},
.variants = {kMonInvalid},
}
},
{"rsmi_dev_power_cap_set", { .mandatory_depends =
{kMonPowerCapMaxName,
kMonPowerCapMinName,
kMonPowerCapName},
.variants = {kMonInvalid},
}
},
{"rsmi_dev_fan_rpms_get", { .mandatory_depends = {kMonFanRPMsName},
.variants = {kMonInvalid},
}
},
{"rsmi_dev_fan_speed_get", { .mandatory_depends = {kMonFanSpeedFName},
.variants = {kMonInvalid},
}
},
{"rsmi_dev_fan_speed_max_get", { .mandatory_depends =
{kMonMaxFanSpeedFName},
.variants = {kMonInvalid},
}
},
{"rsmi_dev_temp_metric_get", { .mandatory_depends =
{kMonTempLabelName},
.variants = {kMonTemp,
kMonTempMax,
kMonTempMin,
kMonTempMaxHyst,
kMonTempMinHyst,
kMonTempCritical,
kMonTempCriticalHyst,
kMonTempEmergency,
kMonTempEmergencyHyst,
kMonTempCritMin,
kMonTempCritMinHyst,
kMonTempOffset,
kMonTempLowest,
kMonTempHighest,
},
}
},
{"rsmi_dev_fan_reset", { .mandatory_depends =
{kMonFanControlEnableName},
.variants = {kMonInvalid},
}
},
{"rsmi_dev_fan_speed_set", { .mandatory_depends =
{kMonMaxFanSpeedFName,
kMonFanControlEnableName,
kMonFanSpeedFName},
.variants = {kMonInvalid},
}
},
{"rsmi_dev_volt_metric_get", { .mandatory_depends =
{kMonVoltLabelName},
.variants = {kMonVolt,
kMonVoltMin,
kMonVoltMinCrit,
kMonVoltMax,
kMonVoltMaxCrit,
kMonVoltAverage,
kMonVoltLowest,
kMonVoltHighest,
},
}
},
};
Monitor::Monitor(std::string path, RocmSMI_env_vars const *e) :
path_(path), env_(e) {
#ifndef DEBUG
env_ = nullptr;
#endif
}
Monitor::~Monitor(void) {
}
std::string
Monitor::MakeMonitorPath(MonitorTypes type, uint32_t sensor_id) {
std::string tempPath = path_;
std::string fn = kMonitorNameMap.at(type);
std::replace(fn.begin(), fn.end(), '#', static_cast<char>('0' + sensor_id));
tempPath += "/";
tempPath += fn;
return tempPath;
}
int Monitor::writeMonitor(MonitorTypes type, uint32_t sensor_id,
std::string val) {
std::string sysfs_path = MakeMonitorPath(type, sensor_id);
DBG_FILE_ERROR(sysfs_path, &val)
return WriteSysfsStr(sysfs_path, val);
}
// This string version should work for all valid monitor types
int Monitor::readMonitor(MonitorTypes type, uint32_t sensor_id,
std::string *val) {
assert(val != nullptr);
std::string temp_str;
std::string sysfs_path = MakeMonitorPath(type, sensor_id);
DBG_FILE_ERROR(sysfs_path, (std::string *)nullptr)
return ReadSysfsStr(sysfs_path, val);
}
int32_t
Monitor::setTempSensorLabelMap(void) {
std::string type_str;
int ret;
if (temp_type_index_map_.size() > 0) {
return 0; // We've already filled in the map
}
auto add_temp_sensor_entry = [&](uint32_t file_index) {
ret = readMonitor(kMonTempLabel, file_index, &type_str);
rsmi_temperature_type_t t_type;
// If readMonitor fails, there is no label file for the file_index.
// In that case, map the type to file index 0, which is not supported
// and will fail appropriately later when we check for support.
if (ret) {
index_temp_type_map_.insert({file_index, RSMI_TEMP_TYPE_INVALID});
} else {
t_type = kTempSensorNameMap.at(type_str);
temp_type_index_map_[t_type] = file_index;
index_temp_type_map_.insert({file_index, t_type});
}
return 0;
};
for (uint32_t t = RSMI_TEMP_TYPE_FIRST; t <= RSMI_TEMP_TYPE_LAST; ++t) {
temp_type_index_map_.insert(
{static_cast<rsmi_temperature_type_t>(t), RSMI_TEMP_TYPE_INVALID});
}
for (uint32_t i = 1; i <= RSMI_TEMP_TYPE_LAST + 1; ++i) {
ret = add_temp_sensor_entry(i);
if (ret) {
return ret;
}
}
return 0;
}
int32_t
Monitor::setVoltSensorLabelMap(void) {
std::string type_str;
int ret;
if (volt_type_index_map_.size() > 0) {
return 0; // We've already filled in the map
}
auto add_volt_sensor_entry = [&](uint32_t file_index) {
ret = readMonitor(kMonVoltLabel, file_index, &type_str);
rsmi_voltage_type_t t_type = kVoltSensorNameMap.at(type_str);
// If readMonitor fails, there is no label file for the file_index.
// In that case, map the type to file index 0, which is not supported
// and will fail appropriately later when we check for support.
if (ret) {
volt_type_index_map_.insert({t_type, 0});
index_volt_type_map_.insert({file_index, RSMI_VOLT_TYPE_INVALID});
} else {
volt_type_index_map_.insert({t_type, file_index});
index_volt_type_map_.insert({file_index, t_type});
}
return 0;
};
for (uint32_t i = 0; i < RSMI_VOLT_TYPE_LAST + 1; ++i) {
ret = add_volt_sensor_entry(i);
if (ret) {
return ret;
}
}
return 0;
}
static int get_supported_sensors(std::string dir_path, std::string fn_reg_ex,
std::vector<uint64_t> *sensors) {
auto hwmon_dir = opendir(dir_path.c_str());
assert(hwmon_dir != nullptr);
assert(sensors != nullptr);
sensors->clear();
std::string::size_type pos = fn_reg_ex.find('#');
if (pos == std::string::npos) {
closedir(hwmon_dir);
return -1;
}
fn_reg_ex.erase(pos, 1);
fn_reg_ex.insert(pos, "([0-9]+)");
fn_reg_ex = "\\b" + fn_reg_ex + "\\b";
auto dentry = readdir(hwmon_dir);
std::smatch match;
uint64_t mon_val;
char *endptr;
try {
std::regex re(fn_reg_ex);
std::string fn;
while (dentry != nullptr) {
fn = dentry->d_name;
if (std::regex_search(fn, match, re)) {
assert(match.size() == 2); // 1 for whole match + 1 for sub-match
errno = 0;
std::string val_str(match.str(1));
mon_val = strtoul(val_str.c_str(), &endptr, 10);
assert(errno == 0);
assert(*endptr == '\0');
if (errno) {
closedir(hwmon_dir);
return -2;
}
sensors->push_back(mon_val);
}
dentry = readdir(hwmon_dir);
}
if (closedir(hwmon_dir)) {
return errno;
}
} catch (std::regex_error& e) {
std::cout << "Regular expression error:" << std::endl;
std::cout << e.what() << std::endl;
std::cout << "Regex error code: " << e.code() << std::endl;
return -3;
}
return 0;
}
uint32_t
Monitor::getTempSensorIndex(rsmi_temperature_type_t type) {
return temp_type_index_map_.at(type);
}
rsmi_temperature_type_t
Monitor::getTempSensorEnum(uint64_t ind) {
return index_temp_type_map_.at(ind);
}
uint32_t
Monitor::getVoltSensorIndex(rsmi_voltage_type_t type) {
return volt_type_index_map_.at(type);
}
rsmi_voltage_type_t
Monitor::getVoltSensorEnum(uint64_t ind) {
return index_volt_type_map_.at(ind);
}
static std::vector<uint64_t> get_intersection(std::vector<uint64_t> *v1,
std::vector<uint64_t> *v2) {
assert(v1 != nullptr);
assert(v2 != nullptr);
std::vector<uint64_t> intersect;
std::sort(v1->begin(), v1->end());
std::sort(v2->begin(), v2->end());
std::set_intersection(v1->begin(), v1->end(), v2->begin(), v2->end(),
std::back_inserter(intersect));
return intersect;
}
// Use this enum to encode the monitor type into the monitor ID.
// We can later use this to convert to rsmi-api sensor types; for exampple,
// rsmi_temperature_type_t, which is what the caller will expect. Add
// new types as needed.
typedef enum {
eDefaultMonitor = 0,
eTempMonitor,
eVoltMonitor,
} monitor_types;
static monitor_types getFuncType(std::string f_name) {
monitor_types ret = eDefaultMonitor;
if (f_name.compare("rsmi_dev_temp_metric_get") == 0) {
ret = eTempMonitor;
}
if (f_name.compare("rsmi_dev_volt_metric_get") == 0) {
ret = eVoltMonitor;
}
return ret;
}
void Monitor::fillSupportedFuncs(SupportedFuncMap *supported_funcs) {
std::map<const char *, monitor_depends_t>::const_iterator it =
kMonFuncDependsMap.begin();
std::string mon_root = path_;
bool mand_depends_met;
std::shared_ptr<VariantMap> supported_variants;
std::vector<uint64_t> sensors_i;
std::vector<uint64_t> intersect;
int ret;
monitor_types m_type;
assert(supported_funcs != nullptr);
while (it != kMonFuncDependsMap.end()) {
// First, see if all the mandatory dependencies are there
std::vector<const char *>::const_iterator dep =
it->second.mandatory_depends.begin();
m_type = getFuncType(it->first);
mand_depends_met = true;
// Initialize "intersect". A monitor is considered supported if all of its
// dependency monitors with the same sensor index are present. So we
// initialize "intersect" with the set of sensors that exist for the first
// mandatory monitor, and take intersection of that with the subsequent
// dependency monitors. The main assumption here is that
// variant_<sensor_i>'s sensor-based dependencies have the same index i;
// in other words, variant_i is not dependent on a sensor j, j != i
// Initialize intersect with the available monitors for the first
// mandatory dependency.
ret = get_supported_sensors(mon_root + "/", *dep, &intersect);
std::string dep_path;
if (ret == -1) {
// In this case, the dependency is not sensor-specific, so just
// see if the file exists.
dep_path = mon_root + "/" + *dep;
if (!FileExists(dep_path.c_str())) {
mand_depends_met = false;
}
} else if (ret <= -2) {
throw amd::smi::rsmi_exception(RSMI_STATUS_INTERNAL_EXCEPTION,
"Failed to parse monitor file name: " + dep_path);
}
dep++;
while (mand_depends_met && dep != it->second.mandatory_depends.end()) {
ret = get_supported_sensors(mon_root + "/", *dep, &sensors_i);
if (ret == 0) {
intersect = get_intersection(&sensors_i, &intersect);
} else if (ret == -1) {
// In this case, the dependency is not sensor-specific, so just
// see if the file exists.
std::string dep_path = mon_root + "/" + *dep;
if (!FileExists(dep_path.c_str())) {
mand_depends_met = false;
break;
}
} else if (ret <= -2) {
throw amd::smi::rsmi_exception(RSMI_STATUS_INTERNAL_EXCEPTION,
"Failed to parse monitor file name: " + dep_path);
}
dep++;
}
if (!mand_depends_met) {
it++;
continue;
}
// "intersect" holds the set of sensors for the mandatory dependencies
// that exist.
std::vector<MonitorTypes>::const_iterator var =
it->second.variants.begin();
supported_variants = std::make_shared<VariantMap>();
std::vector<uint64_t> supported_monitors;
for (; var != it->second.variants.end(); var++) {
if (*var != kMonInvalid) {
ret = get_supported_sensors(mon_root + "/",
kMonitorNameMap.at(*var), &sensors_i);
if (ret == 0) {
supported_monitors = get_intersection(&sensors_i, &intersect);
} else if (ret <= -2) {
throw amd::smi::rsmi_exception(RSMI_STATUS_INTERNAL_EXCEPTION,
"Failed to parse monitor file name: " + dep_path);
}
} else {
supported_monitors = intersect;
}
if (supported_monitors.size() > 0) {
for (uint32_t i = 0; i < supported_monitors.size(); ++i) {
if (m_type == eDefaultMonitor) {
assert(supported_monitors[i] > 0);
supported_monitors[i] |=
(supported_monitors[i] - 1) << MONITOR_TYPE_BIT_POSITION;
} else if (m_type == eTempMonitor) {
// Temp sensor file names are 1-based
assert(supported_monitors[i] > 0);
supported_monitors[i] |=
static_cast<uint64_t>(getTempSensorEnum(supported_monitors[i]))
<< MONITOR_TYPE_BIT_POSITION;
} else if (m_type == eVoltMonitor) {
// Voltage sensor file names are 0-based
supported_monitors[i] |=
static_cast<uint64_t>(getVoltSensorEnum(supported_monitors[i]))
<< MONITOR_TYPE_BIT_POSITION;
} else {
assert(false); // Unexpected monitor type
}
}
(*supported_variants)[kMonInfoVarTypeToRSMIVariant.at(*var)] =
std::make_shared<SubVariant>(supported_monitors);
}
}
if (it->second.variants.size() == 0) {
(*supported_funcs)[it->first] = nullptr;
supported_variants = nullptr; // Invoke destructor
} else if ((*supported_variants).size() > 0) {
(*supported_funcs)[it->first] = supported_variants;
}
it++;
}
}
} // namespace smi
} // namespace amd
-158
View File
@@ -1,158 +0,0 @@
/*
* =============================================================================
* The University of Illinois/NCSA
* Open Source License (NCSA)
*
* Copyright (c) 2017, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Developed by:
*
* AMD Research and AMD ROC Software Development
*
* Advanced Micro Devices, Inc.
*
* www.amd.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal with 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:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimers.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimers in
* the documentation and/or other materials provided with the distribution.
* - Neither the names of <Name of Development Group, Name of Institution>,
* nor the names of its contributors may be used to endorse or promote
* products derived from this Software without specific prior written
* permission.
*
* 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 CONTRIBUTORS 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 WITH THE SOFTWARE.
*
*/
#include <assert.h>
#include <fstream>
#include <string>
#include <cstdint>
#include <map>
#include <iostream>
#include <sstream>
#include "rocm_smi/rocm_smi_main.h"
#include "rocm_smi/rocm_smi_monitor.h"
#include "rocm_smi/rocm_smi_utils.h"
#include "rocm_smi/rocm_smi_common.h"
#include "rocm_smi/rocm_smi_exception.h"
namespace amd {
namespace smi {
static const char *kPowerMonPMName = "amdgpu_pm_info";
// Using this map in case we add other files from dri directory to parse.
static const std::map<PowerMonTypes, const char *> kMonitorNameMap = {
{kPowerMaxGPUPower, kPowerMonPMName},
};
PowerMon::PowerMon(std::string path, RocmSMI_env_vars const *e) :
path_(path), env_(e) {
}
PowerMon::~PowerMon(void) {
}
static int parse_power_str(std::string s, PowerMonTypes type, uint64_t *val) {
std::stringstream ss(s);
std::string ln;
std::string search_str;
assert(val != nullptr);
switch (type) {
case kPowerMaxGPUPower:
search_str = "(max GPU)";
break;
default:
assert(false); // Invalid search Power type requested
return EINVAL;
}
bool found = false;
while (std::getline(ss, ln)) {
if (ln.rfind(search_str) != std::string::npos) {
found = true;
break;
}
}
if (!found) {
return EPERM;
}
ss.clear();
std::stringstream l_ss;
l_ss << ln;
double num_units;
std::string sz;
switch (type) {
case kPowerMaxGPUPower:
l_ss >> num_units;
l_ss >> sz;
assert(sz == "W"); // We only expect Watts at this time
if (sz != "W") {
throw amd::smi::rsmi_exception(RSMI_STATUS_UNEXPECTED_DATA,
__FUNCTION__);
}
if (num_units > static_cast<long double>(0xFFFFFFFFFFFFFFFF)/1000) {
throw amd::smi::rsmi_exception(RSMI_STATUS_UNEXPECTED_DATA,
__FUNCTION__);
}
*val = static_cast<uint64_t>(num_units * 1000); // Convert W to mW
break;
default:
assert(false); // Invalid search Power type requested
return EINVAL;
}
ss.clear();
return 0;
}
int PowerMon::readPowerValue(PowerMonTypes type, uint64_t *power) {
auto tempPath = path_;
std::string fstr;
assert(power != nullptr);
tempPath += "/";
tempPath += kMonitorNameMap.at(type);
DBG_FILE_ERROR(tempPath, (std::string *)nullptr)
int ret = ReadSysfsStr(tempPath, &fstr);
if (ret) {
return ret;
}
return parse_power_str(fstr, type, power);
}
} // namespace smi
} // namespace amd
-238
View File
@@ -1,238 +0,0 @@
/*
* =============================================================================
* The University of Illinois/NCSA
* Open Source License (NCSA)
*
* Copyright (c) 2018, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Developed by:
*
* AMD Research and AMD ROC Software Development
*
* Advanced Micro Devices, Inc.
*
* www.amd.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal with 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:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimers.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimers in
* the documentation and/or other materials provided with the distribution.
* - Neither the names of <Name of Development Group, Name of Institution>,
* nor the names of its contributors may be used to endorse or promote
* products derived from this Software without specific prior written
* permission.
*
* 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 CONTRIBUTORS 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 WITH THE SOFTWARE.
*
*/
#include <assert.h>
#include <errno.h>
#include <sys/stat.h>
#include <fstream>
#include <string>
#include <cstdint>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <vector>
#include "rocm_smi/rocm_smi.h"
#include "rocm_smi/rocm_smi_utils.h"
#include "rocm_smi/rocm_smi_exception.h"
#include "rocm_smi/rocm_smi_main.h"
#include "rocm_smi/rocm_smi_device.h"
namespace amd {
namespace smi {
// Return 0 if same file, 1 if not, and -1 for error
int SameFile(const std::string fileA, const std::string fileB) {
struct stat aStat;
struct stat bStat;
int ret;
ret = stat(fileA.c_str(), &aStat);
if (ret) {
return -1;
}
ret = stat(fileB.c_str(), &bStat);
if (ret) {
return -1;
}
if (aStat.st_dev != bStat.st_dev) {
return 1;
}
if (aStat.st_ino != bStat.st_ino) {
return 1;
}
return 0;
}
bool FileExists(char const *filename) {
struct stat buf;
return (stat(filename, &buf) == 0);
}
int isRegularFile(std::string fname, bool *is_reg) {
struct stat file_stat;
int ret;
assert(is_reg != nullptr);
ret = stat(fname.c_str(), &file_stat);
if (ret) {
return errno;
}
*is_reg = S_ISREG(file_stat.st_mode);
return 0;
}
int WriteSysfsStr(std::string path, std::string val) {
std::ofstream fs;
int ret = 0;
fs.open(path);
if (!fs.is_open()) {
ret = errno;
errno = 0;
return ret;
}
fs << val;
fs.close();
return ret;
}
int ReadSysfsStr(std::string path, std::string *retStr) {
std::stringstream ss;
int ret = 0;
assert(retStr != nullptr);
std::ifstream fs;
fs.open(path);
if (!fs.is_open()) {
ret = errno;
errno = 0;
return ret;
}
ss << fs.rdbuf();
fs.close();
*retStr = ss.str();
retStr->erase(std::remove(retStr->begin(), retStr->end(), '\n'),
retStr->end());
return ret;
}
bool IsInteger(const std::string & n_str) {
if (n_str.empty() || ((!isdigit(n_str[0])) && (n_str[0] != '-')
&& (n_str[0] != '+'))) {
return false;
}
char * tmp;
strtol(n_str.c_str(), &tmp, 10);
return (*tmp == 0);
}
rsmi_status_t handleException() {
try {
throw;
} catch (const std::bad_alloc& e) {
debug_print("RSMI exception: BadAlloc\n");
return RSMI_STATUS_OUT_OF_RESOURCES;
} catch (const amd::smi::rsmi_exception& e) {
debug_print("Exception caught: %s.\n", e.what());
return e.error_code();
} catch (const std::exception& e) {
debug_print("Exception caught: %s\n", e.what());
return RSMI_STATUS_INTERNAL_EXCEPTION;
} catch (const std::nested_exception& e) {
debug_print("Callback threw.\n");
return RSMI_STATUS_INTERNAL_EXCEPTION;
} catch (...) {
debug_print("Unknown exception caught.\n");
return RSMI_STATUS_INTERNAL_EXCEPTION;
}
}
pthread_mutex_t *GetMutex(uint32_t dv_ind) {
amd::smi::RocmSMI& smi = amd::smi::RocmSMI::getInstance();
if (dv_ind >= smi.devices().size()) {
return nullptr;
}
std::shared_ptr<amd::smi::Device> dev = smi.devices()[dv_ind];
assert(dev != nullptr);
return dev->mutex();
}
rsmi_status_t GetDevValueVec(amd::smi::DevInfoTypes type,
uint32_t dv_ind, std::vector<std::string> *val_vec) {
assert(val_vec != nullptr);
if (val_vec == nullptr) {
return RSMI_STATUS_INVALID_ARGS;
}
GET_DEV_FROM_INDX
int ret = dev->readDevInfo(type, val_vec);
return ErrnoToRsmiStatus(ret);
}
rsmi_status_t
GetDevBinaryBlob(amd::smi::DevInfoTypes type,
uint32_t dv_ind, std::size_t b_size, void* p_binary_data) {
assert(p_binary_data != nullptr);
if (p_binary_data == nullptr) {
return RSMI_STATUS_INVALID_ARGS;
}
GET_DEV_FROM_INDX
int ret = dev->readDevInfo(type, b_size, p_binary_data);
return ErrnoToRsmiStatus(ret);
}
rsmi_status_t ErrnoToRsmiStatus(int err) {
switch (err) {
case 0: return RSMI_STATUS_SUCCESS;
case ESRCH: return RSMI_STATUS_NOT_FOUND;
case EACCES: return RSMI_STATUS_PERMISSION;
case EPERM:
case ENOENT: return RSMI_STATUS_NOT_SUPPORTED;
case EBADF:
case EISDIR: return RSMI_STATUS_FILE_ERROR;
case EINTR: return RSMI_STATUS_INTERRUPT;
case EIO: return RSMI_STATUS_UNEXPECTED_SIZE;
case ENXIO: return RSMI_STATUS_UNEXPECTED_DATA;
case EBUSY: return RSMI_STATUS_BUSY;
default: return RSMI_STATUS_UNKNOWN_ERROR;
}
}
} // namespace smi
} // namespace amd