Add 'projects/rdc/' from commit '5ae7eeb3550d4cb14cbc31d3022e545b054f1ad1'
git-subtree-dir: projects/rdc git-subtree-mainline:a68afa42a1git-subtree-split:5ae7eeb355
This commit is contained in:
Executable
+148
@@ -0,0 +1,148 @@
|
||||
# Copyright (c) 2020 - present Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
# WARN: This is a standalone CMake project! Do not include as a subdirectory!
|
||||
|
||||
# This project is meant to demo RDC library
|
||||
# See README.md for more information
|
||||
|
||||
#
|
||||
# Minimum version of cmake required
|
||||
#
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
option(CMAKE_VERBOSE_MAKEFILE "Enable verbose output" ON)
|
||||
option(CMAKE_EXPORT_COMPILE_COMMANDS "Export compile commands for linters and autocompleters" ON)
|
||||
|
||||
# Set compile flags
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -m64 -msse -msse2")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG
|
||||
"${CMAKE_CXX_FLAGS_DEBUG} -O0 -ggdb -DDEBUG"
|
||||
CACHE STRING
|
||||
"Flags for Debug builds"
|
||||
)
|
||||
# note: no '-s' here unlike other CMakeLists.txt
|
||||
set(CMAKE_CXX_FLAGS_RELEASE
|
||||
"${CMAKE_CXX_FLAGS_RELEASE} -O2 -DNDEBUG"
|
||||
CACHE STRING
|
||||
"Flags for Release builds"
|
||||
)
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO
|
||||
"${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O2 -g -DNDEBUG"
|
||||
CACHE STRING
|
||||
"Flags for RelWithDebInfo builds"
|
||||
)
|
||||
set(CMAKE_CXX_FLAGS_MINSIZEREL
|
||||
"${CMAKE_CXX_FLAGS_MINSIZEREL} -Os -DNDEBUG"
|
||||
CACHE STRING
|
||||
"Flags for MinSizeRel builds"
|
||||
)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17 CACHE STRING "The C++ standard to use")
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.4.0)
|
||||
message("Compiler version is " ${CMAKE_CXX_COMPILER_VERSION})
|
||||
message(FATAL_ERROR "Require at least gcc-5.4.0")
|
||||
endif()
|
||||
|
||||
project(RDC_example)
|
||||
|
||||
# provides cmake_print_variables(VAR)
|
||||
include(CMakePrintHelpers)
|
||||
|
||||
# required variables
|
||||
if(DEFINED ENV{ROCM_PATH})
|
||||
set(ROCM_DIR "$ENV{ROCM_PATH}" CACHE STRING "ROCm directory.")
|
||||
else()
|
||||
set(ROCM_DIR "/opt/rocm" CACHE STRING "ROCm directory.")
|
||||
endif()
|
||||
|
||||
# add package search paths
|
||||
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${ROCM_DIR})
|
||||
set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} ${ROCM_DIR}/lib ${ROCM_DIR}/lib64)
|
||||
|
||||
# RDC provides librdc_bootstrap
|
||||
find_package(rdc CONFIG REQUIRED)
|
||||
|
||||
message("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&")
|
||||
message(" Cmake Example ")
|
||||
message("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&")
|
||||
|
||||
message("")
|
||||
message("Build Configuration:")
|
||||
message("-----------BuildType: " ${CMAKE_BUILD_TYPE})
|
||||
message("------------Compiler: " ${CMAKE_CXX_COMPILER})
|
||||
message("-------------Version: " ${CMAKE_CXX_COMPILER_VERSION})
|
||||
message("------------ROCM_DIR: " ${ROCM_DIR})
|
||||
message("")
|
||||
|
||||
set(JOBSTATS_EXAMPLE_SRC_LIST "job_stats_example.cc")
|
||||
cmake_print_variables(JOBSTATS_EXAMPLE_SRC_LIST)
|
||||
set(JOBSTATS_EXAMPLE_EXE "jobstats")
|
||||
add_executable(${JOBSTATS_EXAMPLE_EXE} "${JOBSTATS_EXAMPLE_SRC_LIST}")
|
||||
target_link_libraries(${JOBSTATS_EXAMPLE_EXE} pthread dl rdc_bootstrap)
|
||||
|
||||
set(FIELDVALUE_EXAMPLE_SRC_LIST "field_value_example.cc")
|
||||
cmake_print_variables(FIELDVALUE_EXAMPLE_SRC_LIST)
|
||||
set(FIELDVALUE_EXAMPLE_EXE "fieldvalue")
|
||||
add_executable(${FIELDVALUE_EXAMPLE_EXE} "${FIELDVALUE_EXAMPLE_SRC_LIST}")
|
||||
target_link_libraries(${FIELDVALUE_EXAMPLE_EXE} pthread dl rdc_bootstrap)
|
||||
|
||||
set(DIAGNOSTIC_EXAMPLE_SRC_LIST "diagnostic_example.cc")
|
||||
cmake_print_variables(DIAGNOSTIC_EXAMPLE_SRC_LIST)
|
||||
set(DIAGNOSTIC_EXAMPLE_EXE "diagnostic")
|
||||
add_executable(${DIAGNOSTIC_EXAMPLE_EXE} "${DIAGNOSTIC_EXAMPLE_SRC_LIST}")
|
||||
target_link_libraries(${DIAGNOSTIC_EXAMPLE_EXE} pthread dl rdc_bootstrap)
|
||||
|
||||
set(ROCPROFILER_EXAMPLE_SRC_LIST "rocprofiler_example.cc")
|
||||
cmake_print_variables(ROCPROFILER_EXAMPLE_SRC_LIST)
|
||||
set(ROCPROFILER_EXAMPLE_EXE "rocprofiler")
|
||||
add_executable(${ROCPROFILER_EXAMPLE_EXE} "${ROCPROFILER_EXAMPLE_SRC_LIST}")
|
||||
target_link_libraries(${ROCPROFILER_EXAMPLE_EXE} pthread dl rdc_bootstrap)
|
||||
|
||||
set(POLICY_EXAMPLE_SRC_LIST "policy_example.cc")
|
||||
cmake_print_variables(POLICY_EXAMPLE_SRC_LIST)
|
||||
set(POLICY_EXAMPLE_EXE "policy")
|
||||
add_executable(${POLICY_EXAMPLE_EXE} "${POLICY_EXAMPLE_SRC_LIST}")
|
||||
target_link_libraries(${POLICY_EXAMPLE_EXE} pthread dl rdc_bootstrap)
|
||||
|
||||
set(HEALTH_EXAMPLE_SRC_LIST "health_example.cc")
|
||||
cmake_print_variables(HEALTH_EXAMPLE_SRC_LIST)
|
||||
set(HEALTH_EXAMPLE_EXE "health")
|
||||
add_executable(${HEALTH_EXAMPLE_EXE} "${HEALTH_EXAMPLE_SRC_LIST}")
|
||||
target_link_libraries(${HEALTH_EXAMPLE_EXE} pthread dl rdc_bootstrap)
|
||||
|
||||
set(CONFIG_EXAMPLE_SRC_LIST "config_example.cc")
|
||||
cmake_print_variables(CONFIG_EXAMPLE_SRC_LIST)
|
||||
set(CONFIG_EXAMPLE_EXE "config")
|
||||
add_executable(${CONFIG_EXAMPLE_EXE} "${CONFIG_EXAMPLE_SRC_LIST}")
|
||||
target_link_libraries(${CONFIG_EXAMPLE_EXE} pthread dl rdc_bootstrap)
|
||||
|
||||
set(TOPOLOGYLINK_EXAMPLE_SRC_LIST "topologylink_example.cc")
|
||||
cmake_print_variables(TOPOLOGYLINK_EXAMPLE_SRC_LIST)
|
||||
set(TOPOLOGYLINK_EXAMPLE_EXE "topologylink")
|
||||
add_executable(${TOPOLOGYLINK_EXAMPLE_EXE} "${TOPOLOGYLINK_EXAMPLE_SRC_LIST}")
|
||||
target_link_libraries(${TOPOLOGYLINK_EXAMPLE_EXE} pthread dl rdc_bootstrap)
|
||||
|
||||
message("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&")
|
||||
message(" Finished Cmake Example ")
|
||||
message("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&")
|
||||
@@ -0,0 +1,57 @@
|
||||
# Examples
|
||||
|
||||
|
||||
### How to compile examples?
|
||||
|
||||
***NOTE: You have to have RDC installed somewhere.***
|
||||
|
||||
If you have rocm (and RDC) installed under `/opt/rocm` - then you can simply do:
|
||||
|
||||
```bash
|
||||
# same as 'mkdir -p build; cd build; cmake ../; cd ../'
|
||||
cmake -B build
|
||||
# same as 'cd build; make; cd ../'
|
||||
make -C build
|
||||
```
|
||||
|
||||
If you have rocm installed under a different directory, then you will have to
|
||||
add that path with one of the following ways:
|
||||
|
||||
- `cmake -DROCM_DIR=/custom/rocm/path -B build`
|
||||
- `ROCM_PATH=/custom/rocm/path cmake -B build`
|
||||
|
||||
followed by `make -C build`
|
||||
|
||||
You can also set ROCM\_PATH environment variable.
|
||||
|
||||
|
||||
### I can't find rdc!
|
||||
|
||||
- Is RDC installed?
|
||||
- Is RDC installed under `/opt/rocm`?
|
||||
- Can you find `/opt/rocm/lib/cmake/rdc/rdcTargets.cmake`?
|
||||
|
||||
|
||||
### Where is rdc?
|
||||
|
||||
```bash
|
||||
ldd build/diagnostic
|
||||
```
|
||||
|
||||
Look for `librdc_bootstrap.so`
|
||||
|
||||
|
||||
### `diagnostic` is halted, but other examples work
|
||||
|
||||
Did you wait long enough?
|
||||
|
||||
It takes a while to run. 46 seconds on my machine with 2 GPUs.
|
||||
|
||||
|
||||
### `Couldn't find the platform configure..`
|
||||
|
||||
### `Couldn't find the config for the Device...`
|
||||
|
||||
That's probably ok. The examples will still run.
|
||||
|
||||
Try to `cd` into the config directory and call these examples from there.
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
Copyright (C) Advanced Micro Devices. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
#include "rdc/rdc.h"
|
||||
|
||||
int main() {
|
||||
rdc_gpu_group_t group_id;
|
||||
rdc_status_t result;
|
||||
bool standalone = false;
|
||||
rdc_handle_t rdc_handle;
|
||||
uint32_t count = 0;
|
||||
rdc_config_setting_list_t settings_list;
|
||||
rdc_config_setting_t setting;
|
||||
uint64_t watts;
|
||||
|
||||
char hostIpAddress[] = {"localhost:50051"};
|
||||
char group_name[] = {"group1"};
|
||||
|
||||
// Select the embedded mode and standalone mode dynamically.
|
||||
std::cout << "Start rdci in: \n";
|
||||
std::cout << "0 - Embedded mode \n";
|
||||
std::cout << "1 - Standalone mode \n";
|
||||
while (!(std::cin >> standalone)) {
|
||||
std::cout << "Invalid input.\n";
|
||||
std::cin.clear();
|
||||
std::cin.ignore();
|
||||
}
|
||||
std::cout << std::endl;
|
||||
std::cout << (standalone ? "Standalone mode selected.\n" : "Embedded mode selected.\n");
|
||||
|
||||
// Init the rdc
|
||||
result = rdc_init(0);
|
||||
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error initializing RDC. Return: " << rdc_status_string(result) << std::endl;
|
||||
goto cleanup;
|
||||
} else {
|
||||
std::cout << "RDC Initialized.\n";
|
||||
}
|
||||
|
||||
if (standalone) { // standalone
|
||||
result = rdc_connect(hostIpAddress, &rdc_handle, nullptr, nullptr, nullptr);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error connecting to remote rdcd. Return: " << rdc_status_string(result)
|
||||
<< std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
} else { // embedded
|
||||
result = rdc_start_embedded(RDC_OPERATION_MODE_AUTO, &rdc_handle);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error starting embedded RDC engine. Return: " << rdc_status_string(result)
|
||||
<< std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
// Now we can use the same API for both standalone and embedded
|
||||
// Get the list of devices in the system
|
||||
uint32_t gpu_index_list[RDC_MAX_NUM_DEVICES];
|
||||
result = rdc_device_get_all(rdc_handle, gpu_index_list, &count);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error to find devices on the system. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
if (count == 0) {
|
||||
std::cout << "No GPUs find on the sytem ";
|
||||
goto cleanup;
|
||||
} else {
|
||||
std::cout << count << " GPUs found in the system.\n";
|
||||
}
|
||||
|
||||
// Create the group
|
||||
result = rdc_group_gpu_create(rdc_handle, RDC_GROUP_EMPTY, group_name, &group_id);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error creating group. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
std::cout << "Created the GPU group " << group_id << std::endl;
|
||||
|
||||
// Add all GPUs to the group
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
result = rdc_group_gpu_add(rdc_handle, group_id, gpu_index_list[i]); // Add GPU 0
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error adding group. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
rdc_device_attributes_t attribute;
|
||||
result = rdc_device_get_attributes(rdc_handle, gpu_index_list[i], &attribute);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error get GPU attribute. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
std::cout << "Add GPU " << gpu_index_list[i] << ":" << attribute.device_name << " to group "
|
||||
<< group_id << std::endl;
|
||||
}
|
||||
|
||||
setting.type = RDC_CFG_POWER_LIMIT;
|
||||
// Our targeted value is 195 Watts, which will be converted into Microwatts inside of
|
||||
// rdc_config_set
|
||||
setting.target_value = 195;
|
||||
result = rdc_config_set(rdc_handle, group_id, setting);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error set config RDC_CFG_POWER_LIMIT, Return: " << rdc_status_string(result)
|
||||
<< std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
result = rdc_config_get(rdc_handle, group_id, &settings_list);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error get config, Return: " << rdc_status_string(result) << std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Prompt user to change amd-smi to other value, and watch rdc config change it back
|
||||
|
||||
std::cout << "Config before wait:" << std::endl;
|
||||
|
||||
result = rdc_config_get(rdc_handle, group_id, &settings_list);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error get config, Return: " << rdc_status_string(result) << std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
std::cout << "The config will keep the power limit to 195 Watts" << std::endl;
|
||||
std::cout << "You can change the power limit using amd-smi, the RDC config module should be able "
|
||||
"to detect it and set it back"
|
||||
<< std::endl;
|
||||
std::cout << "Waiting 3 minutes before exit ..." << std::endl;
|
||||
std::this_thread::sleep_for(std::chrono::minutes(3));
|
||||
|
||||
result = rdc_config_clear(rdc_handle, group_id);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error clear config, Return: " << rdc_status_string(result) << std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
//... clean up
|
||||
cleanup:
|
||||
std::cout << "Cleaning up.\n";
|
||||
|
||||
result = rdc_group_gpu_destroy(rdc_handle, group_id);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error delete GPU group. Return: " << rdc_status_string(result);
|
||||
}
|
||||
std::cout << "Deleted the GPU group " << group_id << std::endl;
|
||||
|
||||
if (standalone)
|
||||
rdc_disconnect(rdc_handle);
|
||||
else
|
||||
rdc_stop_embedded(rdc_handle);
|
||||
rdc_shutdown();
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
Copyright (c) 2021 - present Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "rdc/rdc.h"
|
||||
|
||||
static std::string get_test_name(rdc_diag_test_cases_t test_case) {
|
||||
const std::map<rdc_diag_test_cases_t, std::string> test_desc = {
|
||||
{RDC_DIAG_COMPUTE_PROCESS, "No compute process"},
|
||||
{RDC_DIAG_COMPUTE_QUEUE, "Compute Queue ready"},
|
||||
{RDC_DIAG_SYS_MEM_CHECK, "System memory check"},
|
||||
{RDC_DIAG_NODE_TOPOLOGY, "Node topology check"},
|
||||
{RDC_DIAG_RVS_GST_TEST, "RVS check"},
|
||||
{RDC_DIAG_GPU_PARAMETERS, "GPU parameters check"},
|
||||
{RDC_DIAG_TEST_LAST, "Unknown"}};
|
||||
|
||||
auto test_name = test_desc.find(test_case);
|
||||
if (test_name == test_desc.end()) {
|
||||
return "Unknown Test";
|
||||
}
|
||||
return test_name->second;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
rdc_status_t result;
|
||||
rdc_handle_t rdc_handle;
|
||||
bool standalone = false;
|
||||
char hostIpAddress[] = {"127.0.0.1:50051"};
|
||||
char group_name[] = {"diag_group"};
|
||||
|
||||
// Select the embedded mode and standalone mode dynamically.
|
||||
std::cout << "Start rdci in: \n";
|
||||
std::cout << "0 - Embedded mode \n";
|
||||
std::cout << "1 - Standalone mode \n";
|
||||
while (!(std::cin >> standalone)) {
|
||||
std::cout << "Invalid input.\n";
|
||||
std::cin.clear();
|
||||
std::cin.ignore();
|
||||
}
|
||||
std::cout << std::endl;
|
||||
std::cout << (standalone ? "Standalone mode selected.\n" : "Embedded mode selected.\n");
|
||||
|
||||
// Init the rdc
|
||||
result = rdc_init(0);
|
||||
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error initializing RDC. Return: " << rdc_status_string(result) << std::endl;
|
||||
goto cleanup;
|
||||
} else {
|
||||
std::cout << "RDC Initialized.\n";
|
||||
}
|
||||
|
||||
if (standalone) { // standalone
|
||||
result = rdc_connect(hostIpAddress, &rdc_handle, nullptr, nullptr, nullptr);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error connecting to remote rdcd. Return: " << rdc_status_string(result)
|
||||
<< std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
} else { // embedded
|
||||
result = rdc_start_embedded(RDC_OPERATION_MODE_AUTO, &rdc_handle);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error starting embedded RDC engine. Return: " << rdc_status_string(result)
|
||||
<< std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
// Now we can use the same API for both standalone and embedded
|
||||
// (1) create group for all GPUs
|
||||
rdc_gpu_group_t group_id;
|
||||
result = rdc_group_gpu_create(rdc_handle, RDC_GROUP_DEFAULT, group_name, &group_id);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error creating group. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// (2) start to run short diagnostic.
|
||||
rdc_diag_response_t response;
|
||||
result = rdc_diagnostic_run(rdc_handle, group_id, RDC_DIAG_LVL_SHORT, nullptr, 0, &response, nullptr);
|
||||
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error run RDC_DIAG_LVL_SHORT diagnostic. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// (3) Check diagnostic results
|
||||
for (uint32_t i = 0; i < response.results_count; i++) {
|
||||
const rdc_diag_test_result_t& test_result = response.diag_info[i];
|
||||
std::cout << std::setw(22) << std::left << get_test_name(test_result.test_case) + ":"
|
||||
<< rdc_diagnostic_result_string(test_result.status) << "\n";
|
||||
}
|
||||
|
||||
// (4) diagnostic detail information
|
||||
std::cout << " =============== Diagnostic Details ==================\n";
|
||||
for (uint32_t i = 0; i < response.results_count; i++) {
|
||||
const rdc_diag_test_result_t& test_result = response.diag_info[i];
|
||||
if (test_result.info[0] != '\0') {
|
||||
std::cout << std::setw(22) << std::left << get_test_name(test_result.test_case) + ":"
|
||||
<< test_result.info << "\n";
|
||||
}
|
||||
for (uint32_t j = 0; j < test_result.per_gpu_result_count; j++) {
|
||||
const rdc_diag_per_gpu_result_t& gpu_result = test_result.gpu_results[j];
|
||||
if (strlen(gpu_result.gpu_result.msg) > 0) {
|
||||
std::cout << " GPU " << gpu_result.gpu_index << " " << gpu_result.gpu_result.msg << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// (5) run one test case
|
||||
std::cout << " ============== Run individual diagnostic test ===========\n";
|
||||
rdc_diag_test_result_t test_result;
|
||||
result =
|
||||
rdc_test_case_run(rdc_handle, group_id, RDC_DIAG_COMPUTE_PROCESS, nullptr, 0, &test_result, nullptr);
|
||||
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error run RDC_DIAG_COMPUTE_PROCESS diagnostic. Return: "
|
||||
<< rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
std::cout << std::setw(22) << std::left << get_test_name(RDC_DIAG_COMPUTE_PROCESS) + ":"
|
||||
<< test_result.info << "\n";
|
||||
|
||||
// Cleanup consists of shutting down RDC.
|
||||
cleanup:
|
||||
std::cout << "Cleaning up.\n";
|
||||
if (standalone)
|
||||
rdc_disconnect(rdc_handle);
|
||||
else
|
||||
rdc_stop_embedded(rdc_handle);
|
||||
rdc_shutdown();
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
Copyright (c) 2020 - present Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
#include "rdc/rdc.h"
|
||||
|
||||
int main(int, char**) {
|
||||
rdc_status_t result;
|
||||
rdc_handle_t rdc_handle;
|
||||
bool standalone = false;
|
||||
char hostIpAddress[] = {"127.0.0.1:50051"};
|
||||
char group_name[] = {"group1"};
|
||||
char field_group_name[] = {"fieldgroup1"};
|
||||
uint64_t since_timestamp = 0;
|
||||
uint64_t next_timestamp = 0;
|
||||
uint64_t start_timestamp = 0;
|
||||
uint32_t count = 0;
|
||||
|
||||
// Select the embedded mode and standalone mode dynamically.
|
||||
std::cout << "Start rdci in: \n";
|
||||
std::cout << "0 - Embedded mode \n";
|
||||
std::cout << "1 - Standalone mode \n";
|
||||
while (!(std::cin >> standalone)) {
|
||||
std::cout << "Invalid input.\n";
|
||||
std::cin.clear();
|
||||
std::cin.ignore();
|
||||
}
|
||||
std::cout << std::endl;
|
||||
std::cout << (standalone ? "Standalone mode selected.\n" : "Embedded mode selected.\n");
|
||||
|
||||
// Init the rdc
|
||||
result = rdc_init(0);
|
||||
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error initializing RDC. Return: " << rdc_status_string(result) << std::endl;
|
||||
goto cleanup;
|
||||
} else {
|
||||
std::cout << "RDC Initialized.\n";
|
||||
}
|
||||
|
||||
if (standalone) { // standalone
|
||||
result = rdc_connect(hostIpAddress, &rdc_handle, nullptr, nullptr, nullptr);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error connecting to remote rdcd. Return: " << rdc_status_string(result)
|
||||
<< std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
} else { // embedded
|
||||
result = rdc_start_embedded(RDC_OPERATION_MODE_AUTO, &rdc_handle);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error starting embedded RDC engine. Return: " << rdc_status_string(result)
|
||||
<< std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
// Now we can use the same API for both standalone and embedded
|
||||
// Get the list of devices in the system
|
||||
uint32_t gpu_index_list[RDC_MAX_NUM_DEVICES];
|
||||
result = rdc_device_get_all(rdc_handle, gpu_index_list, &count);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error to find devices on the system. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
if (count == 0) {
|
||||
std::cout << "No GPUs find on the sytem ";
|
||||
goto cleanup;
|
||||
} else {
|
||||
std::cout << count << " GPUs found in the system.\n";
|
||||
}
|
||||
|
||||
// Create the group
|
||||
rdc_gpu_group_t group_id;
|
||||
result = rdc_group_gpu_create(rdc_handle, RDC_GROUP_EMPTY, group_name, &group_id);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error creating group. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
std::cout << "Created the GPU group " << group_id << std::endl;
|
||||
|
||||
// Add all GPUs to the group
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
result = rdc_group_gpu_add(rdc_handle, group_id, gpu_index_list[i]); // Add GPU 0
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error adding group. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
rdc_device_attributes_t attribute;
|
||||
result = rdc_device_get_attributes(rdc_handle, gpu_index_list[i], &attribute);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error get GPU attribute. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
std::cout << "Add GPU " << gpu_index_list[i] << ":" << attribute.device_name << " to group "
|
||||
<< group_id << std::endl;
|
||||
}
|
||||
|
||||
// Create the field groups to monitor POWER and TEMP
|
||||
rdc_field_grp_t field_group_id;
|
||||
rdc_field_t field_ids[2];
|
||||
field_ids[0] = RDC_FI_GPU_MEMORY_USAGE;
|
||||
field_ids[1] = RDC_FI_POWER_USAGE;
|
||||
result = rdc_group_field_create(rdc_handle, 2, &field_ids[0], field_group_name, &field_group_id);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error create field group, Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
std::cout << "Created the field group " << field_group_id << ": "
|
||||
<< field_id_string(RDC_FI_GPU_MEMORY_USAGE) << ", "
|
||||
<< field_id_string(RDC_FI_POWER_USAGE) << std::endl;
|
||||
|
||||
// Let the RDC to watch the fields and groups. The fields will be updated
|
||||
// once per second, the max keep age is 1 minutes and only keep 10 samples.
|
||||
result = rdc_field_watch(rdc_handle, group_id, field_group_id, 1000000, 60, 10);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error watch group fields. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
std::cout << "Start to watch group:" << group_id << ", field_group:" << field_group_id
|
||||
<< std::endl;
|
||||
std::cout << "Sleep a few seconds before retreive the data ...\n";
|
||||
|
||||
// Since we are running the RDC_OPERATION_MODE_AUTO mode, the rdc_update_
|
||||
// all_fields() will be called periodically at background. If running as
|
||||
// RDC_OPERATION_MODE_MANUAL mode, we must call rdc_field_update_all()
|
||||
// periodically to take samples.
|
||||
usleep(5000000); // sleep 5 seconds before fetch the stats
|
||||
|
||||
// Retreive the field and group information from RDC
|
||||
rdc_group_info_t group_info;
|
||||
rdc_field_group_info_t field_info;
|
||||
result = rdc_group_gpu_get_info(rdc_handle, group_id, &group_info);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error get gpu group info. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
result = rdc_group_field_get_info(rdc_handle, field_group_id, &field_info);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error get field group info. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Get the latest metrics
|
||||
std::cout << "Get the latest metrics for group:" << group_id << " field_group:" << field_group_id
|
||||
<< std::endl;
|
||||
std::cout << "time_stamp\t"
|
||||
<< "GPU_index\t"
|
||||
<< "field_name\t\t"
|
||||
<< "field_value\n";
|
||||
for (uint32_t gindex = 0; gindex < group_info.count; gindex++) {
|
||||
for (uint32_t findex = 0; findex < field_info.count; findex++) {
|
||||
rdc_field_value value;
|
||||
result = rdc_field_get_latest_value(rdc_handle, group_info.entity_ids[gindex],
|
||||
field_info.field_ids[findex], &value);
|
||||
if (result == RDC_ST_NOT_FOUND) {
|
||||
continue;
|
||||
}
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error get least value. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
// We only support the integer metrics so far
|
||||
std::cout << value.ts << "\t" << group_info.entity_ids[gindex] << "\t\t" << std::left
|
||||
<< std::setw(16) << field_id_string(value.field_id) << "\t" << value.value.l_int
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Stop watching the field group
|
||||
result = rdc_field_unwatch(rdc_handle, group_id, field_group_id);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error stop watch fields. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
std::cout << "Stop watch group:" << group_id << ", field_group:" << field_group_id << std::endl;
|
||||
|
||||
// Get the history data last 10 seconds
|
||||
std::cout << "Get last 10 seconds metrics for group:" << group_id
|
||||
<< " field_group:" << field_group_id << std::endl;
|
||||
std::cout << "time_stamp\t"
|
||||
<< "GPU_index\t"
|
||||
<< "field_name\t\t"
|
||||
<< "field_value\n";
|
||||
start_timestamp = static_cast<uint64_t>(time(nullptr) - 10) * 1000;
|
||||
for (uint32_t gindex = 0; gindex < group_info.count; gindex++) {
|
||||
for (uint32_t findex = 0; findex < field_info.count; findex++) {
|
||||
since_timestamp = start_timestamp;
|
||||
while (true) {
|
||||
rdc_field_value value;
|
||||
result = rdc_field_get_value_since(rdc_handle, group_info.entity_ids[gindex],
|
||||
field_info.field_ids[findex], since_timestamp,
|
||||
&next_timestamp, &value);
|
||||
if (result == RDC_ST_NOT_FOUND) {
|
||||
break;
|
||||
}
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error get history data. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
std::cout << value.ts << "\t" << group_info.entity_ids[gindex] << "\t\t" << std::left
|
||||
<< std::setw(16) << field_id_string(value.field_id) << "\t" << value.value.l_int
|
||||
<< std::endl;
|
||||
since_timestamp = next_timestamp;
|
||||
} // while
|
||||
} // for findex
|
||||
} // for gindex
|
||||
|
||||
// Delete the field group and GPU group
|
||||
result = rdc_group_field_destroy(rdc_handle, field_group_id);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error delete field group. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
std::cout << "Deleted the field group " << field_group_id << std::endl;
|
||||
|
||||
result = rdc_group_gpu_destroy(rdc_handle, group_id);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error delete GPU group. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
std::cout << "Deleted the GPU group " << group_id << std::endl;
|
||||
|
||||
// Cleanup consists of shutting down RDC.
|
||||
cleanup:
|
||||
std::cout << "Cleaning up.\n";
|
||||
if (standalone)
|
||||
rdc_disconnect(rdc_handle);
|
||||
else
|
||||
rdc_stop_embedded(rdc_handle);
|
||||
rdc_shutdown();
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,367 @@
|
||||
/*
|
||||
Copyright (c) 2024 - present Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "rdc/rdc.h"
|
||||
|
||||
rdc_status_t get_watches(rdc_handle_t rdc_handle, rdc_gpu_group_t group_id) {
|
||||
unsigned int components;
|
||||
rdc_status_t result = rdc_health_get(rdc_handle, group_id, &components);
|
||||
if (result == RDC_ST_OK) {
|
||||
std::string on = "On";
|
||||
std::string off = "Off";
|
||||
|
||||
std::cout << "Health monitor systems status:" << std::endl;
|
||||
std::cout << "+--------------------+" //"-" width :20
|
||||
<< "---------------------------------------------------+\n"; //-" width :51
|
||||
std::cout << "|" << std::setw(20) << std::left << " PCIe" << "| "
|
||||
<< std::setw(50) << std::left << ((components & RDC_HEALTH_WATCH_PCIE) ? on : off).c_str() << "|\n";
|
||||
std::cout << "|" << std::setw(20) << std::left << " XGMI" << "| "
|
||||
<< std::setw(50) << std::left << ((components & RDC_HEALTH_WATCH_XGMI) ? on : off).c_str() << "|\n";
|
||||
std::cout << "|" << std::setw(20) << std::left << " Memory" << "| "
|
||||
<< std::setw(50) << std::left << ((components & RDC_HEALTH_WATCH_MEM) ? on : off).c_str() << "|\n";
|
||||
std::cout << "|" << std::setw(20) << std::left << " EEPROM" << "| "
|
||||
<< std::setw(50) << std::left << ((components & RDC_HEALTH_WATCH_EEPROM) ? on : off).c_str() << "|\n";
|
||||
std::cout << "|" << std::setw(20) << std::left << " Thermal" << "| "
|
||||
<< std::setw(50) << std::left << ((components & RDC_HEALTH_WATCH_THERMAL) ? on : off).c_str() << "|\n";
|
||||
std::cout << "|" << std::setw(20) << std::left << " Power" << "| "
|
||||
<< std::setw(50) << std::left << ((components & RDC_HEALTH_WATCH_POWER) ? on : off).c_str() << "|\n";
|
||||
std::cout << "+--------------------+" //"-" width :20
|
||||
<< "---------------------------------------------------+\n"; //-" width :51
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string health_string(rdc_health_result_t health) {
|
||||
switch (health) {
|
||||
case RDC_HEALTH_RESULT_PASS:
|
||||
return "Pass";
|
||||
|
||||
case RDC_HEALTH_RESULT_WARN:
|
||||
return "Warning";
|
||||
|
||||
case RDC_HEALTH_RESULT_FAIL:
|
||||
return "Fail";
|
||||
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
std::string component_string(rdc_health_system_t component) {
|
||||
switch (component) {
|
||||
case RDC_HEALTH_WATCH_PCIE:
|
||||
return "PCIe system: ";
|
||||
|
||||
case RDC_HEALTH_WATCH_XGMI:
|
||||
return"XGMI system: ";
|
||||
|
||||
case RDC_HEALTH_WATCH_MEM:
|
||||
return "Memory system: ";
|
||||
|
||||
case RDC_HEALTH_WATCH_EEPROM:
|
||||
return "EEPROM system: ";
|
||||
|
||||
case RDC_HEALTH_WATCH_THERMAL:
|
||||
return "Thermal system:";
|
||||
|
||||
case RDC_HEALTH_WATCH_POWER:
|
||||
return "Power system: ";
|
||||
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void output_errstr(const std::string& input) {
|
||||
std::string word, line_str;
|
||||
unsigned int width = 60, line_size = 0;
|
||||
std::istringstream iss(input);
|
||||
|
||||
while (iss >> word) {
|
||||
if (line_size + word.size() >= width) {
|
||||
std::cout << "|" << std::setw(20) << " " << "| "
|
||||
<< std::setw(width) << std::left << line_str << "|\n";
|
||||
|
||||
//add new line string
|
||||
line_str = word;
|
||||
line_size = word.size();
|
||||
} else {
|
||||
if (line_size > 0) {
|
||||
line_str += " ";
|
||||
line_str += word;
|
||||
line_size += word.size() + 1;
|
||||
} else {
|
||||
line_str += word;
|
||||
line_size += word.size();
|
||||
}
|
||||
}
|
||||
} //end while
|
||||
|
||||
if (0 < line_size)
|
||||
std::cout << "|" << std::setw(20) << " " << "| "
|
||||
<< std::setw(width) << std::left << line_str << "|\n";
|
||||
}
|
||||
|
||||
unsigned int handle_one_component(rdc_health_response_t &response,
|
||||
unsigned int start_index,
|
||||
uint32_t gpu_index,
|
||||
rdc_health_system_t component,
|
||||
rdc_health_result_t &component_health,
|
||||
std::vector<std::string> &err_str) {
|
||||
unsigned int count = 0;
|
||||
rdc_health_incidents_t *incident;
|
||||
std::string all_err_str;
|
||||
|
||||
for (unsigned int i = start_index; i < response.incidents_count; i++) {
|
||||
incident = &response.incidents[i];
|
||||
|
||||
//same GPU Index, same component
|
||||
if ((incident->gpu_index != gpu_index) ||
|
||||
(incident->component != component))
|
||||
break;
|
||||
|
||||
//set component health
|
||||
if (incident->health > component_health)
|
||||
component_health = incident->health;
|
||||
|
||||
all_err_str = " - ";
|
||||
all_err_str += incident->error.msg;
|
||||
err_str.push_back(all_err_str);
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
unsigned int handle_one_gpu(rdc_health_response_t &response,
|
||||
unsigned int start_index,
|
||||
uint32_t gpu_index) {
|
||||
unsigned int count = 0, comp_count = 0;
|
||||
rdc_health_incidents_t *incident;
|
||||
rdc_health_result_t gpu_health = RDC_HEALTH_RESULT_PASS;
|
||||
std::string component_str, health_str, gpu_health_str;
|
||||
typedef struct {
|
||||
rdc_health_result_t component_health;
|
||||
std::vector<std::string> err_str;
|
||||
} component_detail_t;
|
||||
std::map<rdc_health_system_t, component_detail_t> component_detail_map;
|
||||
|
||||
for (unsigned int i = start_index; i < response.incidents_count; i++) {
|
||||
incident = &response.incidents[i];
|
||||
|
||||
//same GPU Index
|
||||
if (incident->gpu_index != gpu_index)
|
||||
break;
|
||||
|
||||
//set gpu health
|
||||
if (incident->health > gpu_health)
|
||||
gpu_health = incident->health;
|
||||
|
||||
//handle smae component
|
||||
component_detail_t detail;
|
||||
detail.component_health = RDC_HEALTH_RESULT_PASS;
|
||||
detail.err_str.clear();
|
||||
|
||||
comp_count = handle_one_component(response, i, gpu_index, incident->component, detail.component_health, detail.err_str);
|
||||
i += comp_count - 1;
|
||||
count += comp_count;
|
||||
|
||||
// Add to the component detail map
|
||||
component_detail_map.insert({incident->component, detail});
|
||||
}
|
||||
|
||||
//output gpu_index health result
|
||||
gpu_health_str = health_string(gpu_health);
|
||||
|
||||
std::cout << "|" << std::setw(20) << " GPU ID: " + std::to_string(gpu_index) << "| "
|
||||
<< std::setw(60) << std::left << gpu_health_str << "|\n";
|
||||
std::cout << "|" << std::setw(20) << " " << "| "
|
||||
<< std::setw(60) << " " << "|\n";
|
||||
|
||||
for (auto ite : component_detail_map) {
|
||||
component_str = component_string(ite.first);
|
||||
health_str = health_string(ite.second.component_health);
|
||||
std::cout << "|" << std::setw(20) << " " << "| "
|
||||
<< std::setw(60) << std::left << component_str + health_str << "|\n";
|
||||
|
||||
for (auto msg : ite.second.err_str)
|
||||
output_errstr(msg);
|
||||
|
||||
std::cout << "|" << std::setw(20) << " " << "| "
|
||||
<< std::setw(60) << " " << "|\n";
|
||||
}
|
||||
std::cout << "+--------------------+-" //"-" width :20
|
||||
<< "------------------------------------------------------------+\n"; //-" width :60
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
rdc_status_t result;
|
||||
rdc_handle_t rdc_handle;
|
||||
char hostIpAddress[] = {"127.0.0.1:50051"};
|
||||
char group_name[] = {"healthgroup1"};
|
||||
|
||||
std::cout << "Start rdci in Standalone mode\n";
|
||||
|
||||
// Init the rdc
|
||||
result = rdc_init(0);
|
||||
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error initializing RDC. Return: " << rdc_status_string(result) << std::endl;
|
||||
goto cleanup;
|
||||
} else {
|
||||
std::cout << "RDC Initialized.\n";
|
||||
}
|
||||
|
||||
result = rdc_connect(hostIpAddress, &rdc_handle, nullptr, nullptr, nullptr);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error connecting to remote rdcd. Return: " << rdc_status_string(result)
|
||||
<< std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Now we can use the same API for standalone
|
||||
// (1) create group and add GPUs
|
||||
rdc_gpu_group_t group_id;
|
||||
result = rdc_group_gpu_create(rdc_handle, RDC_GROUP_EMPTY, group_name, &group_id);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error creating group. Return: " << rdc_status_string(result)
|
||||
<< std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
std::cout << "Created the GPU group " << group_id << std::endl;
|
||||
|
||||
result = rdc_group_gpu_add(rdc_handle, group_id, 0); // Add GPU 0
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error adding group. Return: " << rdc_status_string(result)
|
||||
<< std::endl;
|
||||
goto destroygroup;
|
||||
}
|
||||
|
||||
rdc_device_attributes_t attribute;
|
||||
result = rdc_device_get_attributes(rdc_handle, 0, &attribute);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error get GPU attribute. Return: " << rdc_status_string(result);
|
||||
goto destroygroup;
|
||||
}
|
||||
std::cout << "Add GPU 0: " << attribute.device_name << " to group "
|
||||
<< group_id << std::endl;
|
||||
|
||||
// (2) get heath current watches before setting
|
||||
result = get_watches(rdc_handle, group_id);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error getting health watches. Return: " << rdc_status_string(result)
|
||||
<< std::endl;
|
||||
goto destroygroup;
|
||||
}
|
||||
|
||||
// (3) set health watches.
|
||||
unsigned int components;
|
||||
components = RDC_HEALTH_WATCH_PCIE | RDC_HEALTH_WATCH_XGMI | RDC_HEALTH_WATCH_MEM
|
||||
| RDC_HEALTH_WATCH_EEPROM | RDC_HEALTH_WATCH_THERMAL
|
||||
| RDC_HEALTH_WATCH_POWER;
|
||||
result = rdc_health_set(rdc_handle, group_id, components);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error setting health watches. Return: " << rdc_status_string(result)
|
||||
<< std::endl;
|
||||
goto destroygroup;
|
||||
}
|
||||
std::cout << "Set health watches to all." << std::endl;
|
||||
|
||||
// (4) get heath current watches after setting
|
||||
result = get_watches(rdc_handle, group_id);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error getting health watches. Return: " << rdc_status_string(result)
|
||||
<< std::endl;
|
||||
goto destroygroup;
|
||||
}
|
||||
|
||||
std::cout << "Start to health monitor group:" << group_id
|
||||
<< std::endl;
|
||||
std::cout << "Sleep a few seconds before retreive the data ...\n";
|
||||
// For standalone mode, the daemon will update and cache the samples
|
||||
// take samples, standalone mode, do nothing
|
||||
usleep(5000000); // sleep 5 seconds before fetch the stats
|
||||
|
||||
// (5) Get the health stats
|
||||
rdc_health_response_t response;
|
||||
result = rdc_health_check(rdc_handle, group_id, &response);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error health check. Return: " << rdc_status_string(result)
|
||||
<< std::endl;
|
||||
goto destroygroup;
|
||||
} else {
|
||||
//output headline
|
||||
std::string overall_str = health_string(response.overall_health);
|
||||
std::cout << "Health monitor report:" << std::endl;
|
||||
std::cout << "+--------------------+-" //"-" width :20
|
||||
<< "------------------------------------------------------------+\n"; //-" width :60
|
||||
std::cout << "|" << std::setw(20) << std::left << " Group " + std::to_string(group_id) << "| "
|
||||
<< std::setw(60) << std::left << "Overall Health: " + overall_str << "|\n";
|
||||
std::cout << "+====================+=" //"=" width :20
|
||||
<< "============================================================+\n"; //"=" width :60
|
||||
|
||||
//output health of per GPU
|
||||
unsigned int index = 0;
|
||||
while (index < response.incidents_count) {
|
||||
uint32_t gpu_index = response.incidents[index].gpu_index;
|
||||
|
||||
unsigned int count = handle_one_gpu(response, index, gpu_index);
|
||||
index += count;
|
||||
}
|
||||
}
|
||||
|
||||
// (6) Clear the health
|
||||
result = rdc_health_clear(rdc_handle, group_id);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error clear health. Return: " << rdc_status_string(result)
|
||||
<< std::endl;
|
||||
goto destroygroup;
|
||||
}
|
||||
std::cout << "Clear Group " << group_id << " all health monitor systems." << std::endl;
|
||||
|
||||
destroygroup:
|
||||
// Delete the GPU group
|
||||
result = rdc_group_gpu_destroy(rdc_handle, group_id);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error delete GPU group. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
std::cout << "Deleted the GPU group " << group_id << std::endl;
|
||||
|
||||
// Cleanup consists of shutting down RDC.
|
||||
cleanup:
|
||||
std::cout << "Cleaning up.\n";
|
||||
rdc_disconnect(rdc_handle);
|
||||
rdc_shutdown();
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
Copyright (c) 2020 - present Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "rdc/rdc.h"
|
||||
|
||||
int main(int, char**) {
|
||||
rdc_status_t result;
|
||||
rdc_handle_t rdc_handle;
|
||||
bool standalone = false;
|
||||
char hostIpAddress[] = {"127.0.0.1:50051"};
|
||||
char group_name[] = {"group1"};
|
||||
char job_id[] = {"123"};
|
||||
|
||||
// Select the embedded mode and standalone mode dynamically.
|
||||
std::cout << "Start rdci in: \n";
|
||||
std::cout << "0 - Embedded mode \n";
|
||||
std::cout << "1 - Standalone mode \n";
|
||||
while (!(std::cin >> standalone)) {
|
||||
std::cout << "Invalid input.\n";
|
||||
std::cin.clear();
|
||||
std::cin.ignore();
|
||||
}
|
||||
std::cout << std::endl;
|
||||
std::cout << (standalone ? "Standalone mode selected.\n" : "Embedded mode selected.\n");
|
||||
|
||||
// Init the rdc
|
||||
result = rdc_init(0);
|
||||
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error initializing RDC. Return: " << rdc_status_string(result) << std::endl;
|
||||
goto cleanup;
|
||||
} else {
|
||||
std::cout << "RDC Initialized.\n";
|
||||
}
|
||||
|
||||
if (standalone) { // standalone
|
||||
result = rdc_connect(hostIpAddress, &rdc_handle, nullptr, nullptr, nullptr);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error connecting to remote rdcd. Return: " << rdc_status_string(result)
|
||||
<< std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
} else { // embedded
|
||||
result = rdc_start_embedded(RDC_OPERATION_MODE_MANUAL, &rdc_handle);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error starting embedded RDC engine. Return: " << rdc_status_string(result)
|
||||
<< std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
// Now we can use the same API for both standalone and embedded
|
||||
// (1) create group and add GPUs
|
||||
rdc_gpu_group_t group_id;
|
||||
result = rdc_group_gpu_create(rdc_handle, RDC_GROUP_EMPTY, group_name, &group_id);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error creating group. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
result = rdc_group_gpu_add(rdc_handle, group_id, 0); // Add GPU 0
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error adding group. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// (2) start the recording. Set the sample frequency to once per second.
|
||||
result = rdc_job_start_stats(rdc_handle, group_id, job_id, 1000000);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error start job stats. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// For standalone mode, the daemon will update and cache the samples
|
||||
// In manual mode, we must call rdc_field_update_all periodically to
|
||||
// take samples.
|
||||
if (!standalone) { // embedded manual mode
|
||||
for (int i = 5; i > 0; i--) { // As an example, we will take 5 samples
|
||||
result = rdc_field_update_all(rdc_handle, 0);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error update all fields. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
usleep(1000000);
|
||||
}
|
||||
} else { // standalone mode, do nothing
|
||||
usleep(5000000); // sleep 5 seconds before fetch the stats
|
||||
}
|
||||
|
||||
// (3) stop the Slurm job, which will stop the watch
|
||||
// We do not have to stop the job to get stats. The rdc_job_get_stats can be
|
||||
// called at any time before stop
|
||||
result = rdc_job_stop_stats(rdc_handle, job_id);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error stop job stats. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// (4) Get the stats
|
||||
rdc_job_info_t job_info;
|
||||
result = rdc_job_get_stats(rdc_handle, job_id, &job_info);
|
||||
|
||||
if (result == RDC_ST_OK) {
|
||||
std::cout << "|------- Execution Stats ----------+"
|
||||
<< "------------------------------------\n";
|
||||
std::cout << "| Start Time * | " << job_info.summary.start_time << "\n";
|
||||
std::cout << "| End Time * | " << job_info.summary.end_time << "\n";
|
||||
std::cout << "| Total Execution Time (sec) * | "
|
||||
<< (job_info.summary.end_time - job_info.summary.start_time) << "\n";
|
||||
std::cout << "+------- Performance Stats --------+"
|
||||
<< "------------------------------------\n";
|
||||
std::cout << "| Energy Consumed (Joules) | " << job_info.summary.energy_consumed
|
||||
<< "\n";
|
||||
std::cout << "| Power Usage (Watts) | "
|
||||
<< "Max: " << job_info.summary.power_usage.max_value
|
||||
<< " Min: " << job_info.summary.power_usage.min_value
|
||||
<< " Avg: " << job_info.summary.power_usage.average << "\n";
|
||||
std::cout << "| GPU Clock (MHz) | "
|
||||
<< "Max: " << job_info.summary.gpu_clock.max_value
|
||||
<< " Min: " << job_info.summary.gpu_clock.min_value
|
||||
<< " Avg: " << job_info.summary.gpu_clock.average << "\n";
|
||||
std::cout << "| GPU Utilization (%) | "
|
||||
<< "Max: " << job_info.summary.gpu_utilization.max_value
|
||||
<< " Min: " << job_info.summary.gpu_utilization.min_value
|
||||
<< " Avg: " << job_info.summary.gpu_utilization.average << "\n";
|
||||
std::cout << "| Max GPU Memory Used (bytes) * | " << job_info.summary.max_gpu_memory_used
|
||||
<< "\n";
|
||||
std::cout << "| Memory Utilization (%) | "
|
||||
<< "Max: " << job_info.summary.memory_utilization.max_value
|
||||
<< " Min: " << job_info.summary.memory_utilization.min_value
|
||||
<< " Avg: " << job_info.summary.memory_utilization.average << "\n";
|
||||
std::cout << "+----------------------------------+"
|
||||
<< "------------------------------------\n";
|
||||
} else {
|
||||
std::cout << "No data for job stats found." << std::endl;
|
||||
}
|
||||
|
||||
// Cleanup consists of shutting down RDC.
|
||||
cleanup:
|
||||
std::cout << "Cleaning up.\n";
|
||||
if (standalone)
|
||||
rdc_disconnect(rdc_handle);
|
||||
else
|
||||
rdc_stop_embedded(rdc_handle);
|
||||
rdc_shutdown();
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
Copyright (C) Advanced Micro Devices. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "rdc/rdc.h"
|
||||
|
||||
static const char* condition_type_to_str(rdc_policy_condition_type_t type) {
|
||||
if (type == RDC_POLICY_COND_MAX_PAGE_RETRIED) return "Retried Page Limit";
|
||||
if (type == RDC_POLICY_COND_THERMAL) return "Temperature Limit";
|
||||
if (type == RDC_POLICY_COND_POWER) return "Power Limit";
|
||||
return "Unknown_Type";
|
||||
}
|
||||
|
||||
static time_t last_time = 0; // last time to print message
|
||||
int rdc_policy_callback(rdc_policy_callback_response_t* userData) {
|
||||
if (userData == nullptr) {
|
||||
std::cerr << "The rdc_policy_callback returns null data\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
// To avoid flooding too many messages, only print message every 5 seconds
|
||||
time_t now = time(NULL);
|
||||
if (difftime(now, last_time) < 5) {
|
||||
return 0;
|
||||
}
|
||||
std::cout << "The " << condition_type_to_str(userData->condition.type)
|
||||
<< " exceeds the threshold " << userData->condition.value << " with the value "
|
||||
<< userData->value << std::endl;
|
||||
last_time = now; // update the last time
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
rdc_gpu_group_t group_id;
|
||||
rdc_status_t result;
|
||||
bool standalone = false;
|
||||
rdc_handle_t rdc_handle;
|
||||
uint32_t count = 0;
|
||||
|
||||
char hostIpAddress[] = {"localhost:50051"};
|
||||
char group_name[] = {"group1"};
|
||||
|
||||
// Select the embedded mode and standalone mode dynamically.
|
||||
std::cout << "Start rdci in: \n";
|
||||
std::cout << "0 - Embedded mode \n";
|
||||
std::cout << "1 - Standalone mode \n";
|
||||
while (!(std::cin >> standalone)) {
|
||||
std::cout << "Invalid input.\n";
|
||||
std::cin.clear();
|
||||
std::cin.ignore();
|
||||
}
|
||||
std::cout << std::endl;
|
||||
std::cout << (standalone ? "Standalone mode selected.\n" : "Embedded mode selected.\n");
|
||||
|
||||
// Init the rdc
|
||||
result = rdc_init(0);
|
||||
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error initializing RDC. Return: " << rdc_status_string(result) << std::endl;
|
||||
goto cleanup;
|
||||
} else {
|
||||
std::cout << "RDC Initialized.\n";
|
||||
}
|
||||
|
||||
if (standalone) { // standalone
|
||||
result = rdc_connect(hostIpAddress, &rdc_handle, nullptr, nullptr, nullptr);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error connecting to remote rdcd. Return: " << rdc_status_string(result)
|
||||
<< std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
} else { // embedded
|
||||
result = rdc_start_embedded(RDC_OPERATION_MODE_AUTO, &rdc_handle);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error starting embedded RDC engine. Return: " << rdc_status_string(result)
|
||||
<< std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
// Now we can use the same API for both standalone and embedded
|
||||
// Get the list of devices in the system
|
||||
uint32_t gpu_index_list[RDC_MAX_NUM_DEVICES];
|
||||
result = rdc_device_get_all(rdc_handle, gpu_index_list, &count);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error to find devices on the system. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
if (count == 0) {
|
||||
std::cout << "No GPUs find on the sytem ";
|
||||
goto cleanup;
|
||||
} else {
|
||||
std::cout << count << " GPUs found in the system.\n";
|
||||
}
|
||||
|
||||
// Create the group
|
||||
result = rdc_group_gpu_create(rdc_handle, RDC_GROUP_EMPTY, group_name, &group_id);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error creating group. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
std::cout << "Created the GPU group " << group_id << std::endl;
|
||||
|
||||
// Add all GPUs to the group
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
result = rdc_group_gpu_add(rdc_handle, group_id, gpu_index_list[i]); // Add GPU 0
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error adding group. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
rdc_device_attributes_t attribute;
|
||||
result = rdc_device_get_attributes(rdc_handle, gpu_index_list[i], &attribute);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error get GPU attribute. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
std::cout << "Add GPU " << gpu_index_list[i] << ":" << attribute.device_name << " to group "
|
||||
<< group_id << std::endl;
|
||||
}
|
||||
|
||||
// Define a policy to print out message when temperature is above 30 degree
|
||||
// or power usage is more than 150W
|
||||
rdc_policy_t policy;
|
||||
policy.condition = {RDC_POLICY_COND_THERMAL, 30 * 1000}; // convert to milli degree
|
||||
policy.action = RDC_POLICY_ACTION_NONE; // Notify only
|
||||
result = rdc_policy_set(rdc_handle, group_id, policy);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error set policy RDC_POLICY_COND_THERMAL, Return: " << rdc_status_string(result)
|
||||
<< std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
policy.condition = {RDC_POLICY_COND_POWER, 150000}; // convert to milli degree
|
||||
policy.action = RDC_POLICY_ACTION_NONE; // Notify only
|
||||
result = rdc_policy_set(rdc_handle, group_id, policy);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error set policy RDC_POLICY_COND_POWER, Return: " << rdc_status_string(result)
|
||||
<< std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
policy.condition = {RDC_POLICY_COND_MAX_PAGE_RETRIED, 100}; // convert to milli degree
|
||||
policy.action = RDC_POLICY_ACTION_NONE; // Notify only
|
||||
result = rdc_policy_set(rdc_handle, group_id, policy);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error set policy RDC_POLICY_COND_MAX_PAGE_RETRIED, Return: " << rdc_status_string(result)
|
||||
<< std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rdc_policy_t policy_get[RDC_MAX_POLICY_SETTINGS];
|
||||
result = rdc_policy_get(rdc_handle, group_id, &count, policy_get);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error get policy, Return: " << rdc_status_string(result) << std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Register a function to listen to the events
|
||||
result = rdc_policy_register(rdc_handle, group_id, rdc_policy_callback);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error register policy, Return: " << rdc_status_string(result) << std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
std::cout << "Wait 30 seconds for the events happening ...\n" << std::endl;
|
||||
|
||||
// If the events happening, the callback rdc_policy_register_callback will be called.
|
||||
usleep(30 * 1000000); // sleep 30 seconds
|
||||
|
||||
// Un-register the events
|
||||
result = rdc_policy_unregister(rdc_handle, group_id);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error unregister policy, Return: " << rdc_status_string(result) << std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// clear the events
|
||||
rdc_policy_condition_type_t condition_type;
|
||||
condition_type = RDC_POLICY_COND_THERMAL;
|
||||
result = rdc_policy_delete(rdc_handle, group_id, condition_type);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error clear policy, Return: " << rdc_status_string(result) << std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
//... clean up
|
||||
cleanup:
|
||||
std::cout << "Cleaning up.\n";
|
||||
if (standalone)
|
||||
rdc_disconnect(rdc_handle);
|
||||
else
|
||||
rdc_stop_embedded(rdc_handle);
|
||||
rdc_shutdown();
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
Copyright (c) 2024 - present Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "rdc/rdc.h"
|
||||
|
||||
rdc_handle_t rdc_handle;
|
||||
rdc_status_t result;
|
||||
|
||||
const std::string value_to_string(rdc_field_value value) {
|
||||
switch (value.type) {
|
||||
case INTEGER:
|
||||
return std::to_string(value.value.l_int);
|
||||
case DOUBLE:
|
||||
return std::to_string(value.value.dbl);
|
||||
case STRING:
|
||||
return value.value.str;
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup consists of shutting down RDC.
|
||||
rdc_status_t cleanup() {
|
||||
std::cout << "Cleaning up.\n";
|
||||
rdc_stop_embedded(rdc_handle);
|
||||
rdc_shutdown();
|
||||
return result;
|
||||
}
|
||||
|
||||
int run() {
|
||||
char group_name[] = {"group1"};
|
||||
char field_group_name[] = {"fieldgroup1"};
|
||||
uint64_t since_timestamp = 0;
|
||||
uint64_t next_timestamp = 0;
|
||||
uint64_t start_timestamp = 0;
|
||||
uint32_t count = 0;
|
||||
|
||||
// Select the embedded mode and standalone mode dynamically.
|
||||
std::cout << "Starting rdci in Embedded mode\n";
|
||||
|
||||
// Init the rdc
|
||||
result = rdc_init(0);
|
||||
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error initializing RDC. Return: " << rdc_status_string(result) << std::endl;
|
||||
return cleanup();
|
||||
} else {
|
||||
std::cout << "RDC Initialized.\n";
|
||||
}
|
||||
|
||||
result = rdc_start_embedded(RDC_OPERATION_MODE_AUTO, &rdc_handle);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error starting embedded RDC engine. Return: " << rdc_status_string(result)
|
||||
<< std::endl;
|
||||
return cleanup();
|
||||
}
|
||||
|
||||
// Get the list of devices in the system
|
||||
uint32_t gpu_index_list[RDC_MAX_NUM_DEVICES];
|
||||
result = rdc_device_get_all(rdc_handle, gpu_index_list, &count);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error to find devices on the system. Return: " << rdc_status_string(result);
|
||||
return cleanup();
|
||||
}
|
||||
if (count == 0) {
|
||||
std::cout << "No GPUs find on the sytem ";
|
||||
return cleanup();
|
||||
} else {
|
||||
std::cout << count << " GPUs found in the system.\n";
|
||||
}
|
||||
|
||||
// Create the group
|
||||
rdc_gpu_group_t group_id = 0;
|
||||
result = rdc_group_gpu_create(rdc_handle, RDC_GROUP_EMPTY, group_name, &group_id);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error creating group. Return: " << rdc_status_string(result);
|
||||
return cleanup();
|
||||
}
|
||||
std::cout << "Created the GPU group " << group_id << std::endl;
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
result = rdc_group_gpu_add(rdc_handle, group_id, gpu_index_list[i]); // Add GPU 0
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error adding group. Return: " << rdc_status_string(result);
|
||||
return cleanup();
|
||||
}
|
||||
rdc_device_attributes_t attribute;
|
||||
result = rdc_device_get_attributes(rdc_handle, gpu_index_list[i], &attribute);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error get GPU attribute. Return: " << rdc_status_string(result);
|
||||
return cleanup();
|
||||
}
|
||||
std::cout << "Add GPU " << gpu_index_list[i] << ":" << attribute.device_name << " to group "
|
||||
<< group_id << std::endl;
|
||||
}
|
||||
|
||||
// Create a field group to monitor multiple fields
|
||||
rdc_field_grp_t field_group_id = 0;
|
||||
std::vector<rdc_field_t> field_ids{};
|
||||
|
||||
field_ids.push_back(RDC_FI_GPU_MEMORY_USAGE);
|
||||
field_ids.push_back(RDC_FI_POWER_USAGE);
|
||||
// profiler metrics
|
||||
field_ids.push_back(RDC_FI_PROF_OCCUPANCY_PERCENT);
|
||||
field_ids.push_back(RDC_FI_PROF_ACTIVE_CYCLES);
|
||||
field_ids.push_back(RDC_FI_PROF_ACTIVE_WAVES);
|
||||
field_ids.push_back(RDC_FI_PROF_ELAPSED_CYCLES);
|
||||
// profiler metrics divided over time
|
||||
field_ids.push_back(RDC_FI_PROF_EVAL_MEM_R_BW);
|
||||
field_ids.push_back(RDC_FI_PROF_EVAL_MEM_W_BW);
|
||||
field_ids.push_back(RDC_FI_PROF_EVAL_FLOPS_16);
|
||||
field_ids.push_back(RDC_FI_PROF_EVAL_FLOPS_32);
|
||||
field_ids.push_back(RDC_FI_PROF_EVAL_FLOPS_64);
|
||||
field_ids.push_back(RDC_FI_PROF_SM_ACTIVE);
|
||||
result = rdc_group_field_create(rdc_handle, field_ids.size(), field_ids.data(), field_group_name,
|
||||
&field_group_id);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error create field group, Return: " << rdc_status_string(result);
|
||||
return cleanup();
|
||||
}
|
||||
std::cout << "Created the field group " << field_group_id << "\n";
|
||||
std::cout << "fields: ";
|
||||
for (auto field_id : field_ids) {
|
||||
std::cout << "- " << field_id << "\n";
|
||||
}
|
||||
|
||||
// Let the RDC to watch the fields and groups. The fields will be updated
|
||||
// once per second, the max keep age is 1 minutes and only keep 10 samples.
|
||||
result = rdc_field_watch(rdc_handle, group_id, field_group_id,
|
||||
static_cast<uint64_t>(1) * 10 * 1000, 60, 10);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error watch group fields. Return: " << rdc_status_string(result);
|
||||
return cleanup();
|
||||
}
|
||||
std::cout << "Start to watch group:" << group_id << ", field_group:" << field_group_id
|
||||
<< std::endl;
|
||||
std::cout << "Sleep a few seconds before retreive the data ...\n";
|
||||
|
||||
// Since we are running the RDC_OPERATION_MODE_AUTO mode, the rdc_update_
|
||||
// all_fields() will be called periodically at background. If running as
|
||||
// RDC_OPERATION_MODE_MANUAL mode, we must call rdc_field_update_all()
|
||||
// periodically to take samples.
|
||||
usleep(5 * 10 * 1000); // sleep 0.05 seconds before fetch the stats
|
||||
|
||||
// Retreive the field and group information from RDC
|
||||
rdc_group_info_t group_info;
|
||||
rdc_field_group_info_t field_info;
|
||||
result = rdc_group_gpu_get_info(rdc_handle, group_id, &group_info);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error get gpu group info. Return: " << rdc_status_string(result);
|
||||
return cleanup();
|
||||
}
|
||||
result = rdc_group_field_get_info(rdc_handle, field_group_id, &field_info);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error get field group info. Return: " << rdc_status_string(result);
|
||||
return cleanup();
|
||||
}
|
||||
|
||||
// Get the latest metrics
|
||||
std::cout << "Get the latest metrics for group:" << group_id << " field_group:" << field_group_id
|
||||
<< std::endl;
|
||||
std::cout << "time_stamp\t"
|
||||
<< "GPU_index\t"
|
||||
<< "field_name\t\t"
|
||||
<< "field_value\n";
|
||||
for (uint32_t gindex = 0; gindex < group_info.count; gindex++) {
|
||||
for (uint32_t findex = 0; findex < field_info.count; findex++) {
|
||||
rdc_field_value value;
|
||||
result = rdc_field_get_latest_value(rdc_handle, group_info.entity_ids[gindex],
|
||||
field_info.field_ids[findex], &value);
|
||||
if (result == RDC_ST_NOT_FOUND) {
|
||||
continue;
|
||||
}
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error get least value. Return: " << rdc_status_string(result);
|
||||
return cleanup();
|
||||
}
|
||||
// We only support the integer metrics so far
|
||||
std::cout << value.ts << "\t" << group_info.entity_ids[gindex] << "\t\t" << std::left
|
||||
<< std::setw(16) << field_id_string(value.field_id) << "\t"
|
||||
<< value_to_string(value) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Stop watching the field group
|
||||
result = rdc_field_unwatch(rdc_handle, group_id, field_group_id);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error stop watch fields. Return: " << rdc_status_string(result);
|
||||
return cleanup();
|
||||
}
|
||||
std::cout << "Stop watch group:" << group_id << ", field_group:" << field_group_id << std::endl;
|
||||
|
||||
// Get the history data last 0.1 seconds
|
||||
std::cout << "Get last 0.1 seconds metrics for group:" << group_id
|
||||
<< " field_group:" << field_group_id << std::endl;
|
||||
std::cout << "time_stamp\t"
|
||||
<< "GPU_index\t"
|
||||
<< "field_name\t\t"
|
||||
<< "field_value\n";
|
||||
start_timestamp = static_cast<uint64_t>(time(nullptr) - 10) * 1000;
|
||||
for (uint32_t gindex = 0; gindex < group_info.count; gindex++) {
|
||||
for (uint32_t findex = 0; findex < field_info.count; findex++) {
|
||||
since_timestamp = start_timestamp;
|
||||
while (true) {
|
||||
rdc_field_value value;
|
||||
result = rdc_field_get_value_since(rdc_handle, group_info.entity_ids[gindex],
|
||||
field_info.field_ids[findex], since_timestamp,
|
||||
&next_timestamp, &value);
|
||||
if (result == RDC_ST_NOT_FOUND) {
|
||||
break;
|
||||
}
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error get history data. Return: " << rdc_status_string(result);
|
||||
return cleanup();
|
||||
}
|
||||
std::cout << value.ts << "\t" << group_info.entity_ids[gindex] << "\t\t" << std::left
|
||||
<< std::setw(16) << field_id_string(value.field_id) << "\t"
|
||||
<< value_to_string(value) << std::endl;
|
||||
since_timestamp = next_timestamp;
|
||||
} // while
|
||||
} // for findex
|
||||
} // for gindex
|
||||
|
||||
// Delete the field group and GPU group
|
||||
result = rdc_group_field_destroy(rdc_handle, field_group_id);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error delete field group. Return: " << rdc_status_string(result);
|
||||
return cleanup();
|
||||
}
|
||||
std::cout << "Deleted the field group " << field_group_id << std::endl;
|
||||
|
||||
result = rdc_group_gpu_destroy(rdc_handle, group_id);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error delete GPU group. Return: " << rdc_status_string(result);
|
||||
return cleanup();
|
||||
}
|
||||
std::cout << "Deleted the GPU group " << group_id << std::endl;
|
||||
|
||||
return cleanup();
|
||||
}
|
||||
|
||||
int main(int, char**) { return run(); }
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
Copyright (C) Advanced Micro Devices. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "rdc/rdc.h"
|
||||
|
||||
static const char* topology_link_type_to_str(rdc_topology_link_type_t type) {
|
||||
if (type == RDC_IOLINK_TYPE_PCIEXPRESS) return "RDC_IOLINK_TYPE_PCIEXPRESS";
|
||||
if (type == RDC_IOLINK_TYPE_XGMI) return "RDC_IOLINK_TYPE_XGMI";
|
||||
return "Unknown_Type";
|
||||
}
|
||||
int main() {
|
||||
rdc_gpu_group_t group_id;
|
||||
rdc_status_t result;
|
||||
bool standalone = false;
|
||||
rdc_handle_t rdc_handle;
|
||||
uint32_t count = 0;
|
||||
|
||||
char hostIpAddress[] = {"localhost:50051"};
|
||||
char group_name[] = {"group1"};
|
||||
|
||||
// Select the embedded mode and standalone mode dynamically.
|
||||
std::cout << "Start rdci in: \n";
|
||||
std::cout << "0 - Embedded mode \n";
|
||||
std::cout << "1 - Standalone mode \n";
|
||||
while (!(std::cin >> standalone)) {
|
||||
std::cout << "Invalid input.\n";
|
||||
std::cin.clear();
|
||||
std::cin.ignore();
|
||||
}
|
||||
std::cout << std::endl;
|
||||
std::cout << (standalone ? "Standalone mode selected.\n" : "Embedded mode selected.\n");
|
||||
|
||||
// Init the rdc
|
||||
result = rdc_init(0);
|
||||
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error initializing RDC. Return: " << rdc_status_string(result) << std::endl;
|
||||
goto cleanup;
|
||||
} else {
|
||||
std::cout << "RDC Initialized.\n";
|
||||
}
|
||||
|
||||
if (standalone) { // standalone
|
||||
result = rdc_connect(hostIpAddress, &rdc_handle, nullptr, nullptr, nullptr);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error connecting to remote rdcd. Return: " << rdc_status_string(result)
|
||||
<< std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
} else { // embedded
|
||||
result = rdc_start_embedded(RDC_OPERATION_MODE_AUTO, &rdc_handle);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error starting embedded RDC engine. Return: " << rdc_status_string(result)
|
||||
<< std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
// Now we can use the same API for both standalone and embedded
|
||||
// Get the list of devices in the system
|
||||
uint32_t gpu_index_list[RDC_MAX_NUM_DEVICES];
|
||||
result = rdc_device_get_all(rdc_handle, gpu_index_list, &count);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error to find devices on the system. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
if (count == 0) {
|
||||
std::cout << "No GPUs find on the sytem ";
|
||||
goto cleanup;
|
||||
} else {
|
||||
std::cout << count << " GPUs found in the system.\n";
|
||||
}
|
||||
|
||||
// Create the group
|
||||
result = rdc_group_gpu_create(rdc_handle, RDC_GROUP_EMPTY, group_name, &group_id);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error creating group. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
std::cout << "Created the GPU group " << group_id << std::endl;
|
||||
|
||||
// Add all GPUs to the group
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
result = rdc_group_gpu_add(rdc_handle, group_id, gpu_index_list[i]); // Add GPU 0
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error adding group. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
rdc_device_attributes_t attribute;
|
||||
result = rdc_device_get_attributes(rdc_handle, gpu_index_list[i], &attribute);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error get GPU attribute. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
std::cout << "Add GPU " << gpu_index_list[i] << ":" << attribute.device_name << " to group "
|
||||
<< group_id << std::endl;
|
||||
}
|
||||
rdc_group_info_t group_info;
|
||||
result = rdc_group_gpu_get_info(rdc_handle, group_id, &group_info);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error get gpu group info. Return: " << rdc_status_string(result);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rdc_device_topology_t topo;
|
||||
result = rdc_device_topology_get(rdc_handle, group_info.entity_ids[0], &topo);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error clear topology, Return: " << rdc_status_string(result) << std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < topo.num_of_gpus; i++) {
|
||||
std::cout << "Topology Information Return \n "
|
||||
<< "gpu_index: " << std::to_string(topo.link_infos[i].gpu_index) << "\n"
|
||||
<< "weight: " << std::to_string(topo.link_infos[i].weight) << "\n"
|
||||
<< "min_bandwidth: " << std::to_string(topo.link_infos[i].min_bandwidth) << "\n"
|
||||
<< "max_bandwidth: " << std::to_string(topo.link_infos[i].max_bandwidth) << "\n"
|
||||
<< "hops: " << std::to_string(topo.link_infos[i].hops) << "\n"
|
||||
<< "link_type: " << topology_link_type_to_str(topo.link_infos[i].link_type) << "\n"
|
||||
<< "is_p2p_accessible: " << std::to_string(topo.link_infos[i].is_p2p_accessible)
|
||||
<< "\n"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
rdc_link_status_t link_status;
|
||||
result = rdc_link_status_get(rdc_handle, &link_status);
|
||||
if (result != RDC_ST_OK) {
|
||||
std::cout << "Error clear topology, Return: " << rdc_status_string(result) << std::endl;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
//... clean up
|
||||
cleanup:
|
||||
std::cout << "Cleaning up.\n";
|
||||
if (standalone)
|
||||
rdc_disconnect(rdc_handle);
|
||||
else
|
||||
rdc_stop_embedded(rdc_handle);
|
||||
rdc_shutdown();
|
||||
return result;
|
||||
}
|
||||
Reference in New Issue
Block a user