Merge amd-dev into amd-master 20240515

Signed-off-by: Maisam Arif <maisarif@amd.com>
Change-Id: I64bba263badc1b1dfa8fab5baf90a5f2ad8ea11d


[ROCm/amdsmi commit: b0fc5d2004]
This commit is contained in:
Maisam Arif
2024-05-15 03:29:23 -05:00
33 changed files with 7460 additions and 323 deletions
+94 -86
View File
@@ -1,27 +1,30 @@
# Change Log for AMD SMI Library
# Changelog for AMD SMI Library
Full documentation for amd_smi_lib is available at [https://rocm.docs.amd.com/](https://rocm.docs.amd.com/projects/amdsmi/en/latest/).
Full documentation for amd_smi_lib is available at [https://rocm.docs.amd.com/projects/amdsmi](https://rocm.docs.amd.com/projects/amdsmi/en/latest/).
***All information listed below is for reference and subject to change.***
## amd_smi_lib for ROCm 6.1.2
### Added
### Additions
- **Added Ring Hang event**
- **Added macros that were in `amdsmi.h` to the amdsmi Python library `amdsmi_interface.py`**.
Added macros to reference max size limitations for certain amdsmi functions such as max dpm policies and max fanspeed.
- **Added Ring Hang event**.
Added `AMDSMI_EVT_NOTIF_RING_HANG` to the possible events in the `amdsmi_evt_notification_type_t` enum.
- **Added process isolation and clean shader APIs and CLI commands**
- **Added process isolation and clean shader APIs and CLI commands**.
Added APIs CLI and APIs to address LeftoverLocals security issues. Allowing clearing the sram data and setting process isolation on a per GPU basis. New APIs:
- `amdsmi_get_gpu_process_isolation()`
- `amdsmi_set_gpu_process_isolation()`
- `amdsmi_set_gpu_clear_sram_data()`
- **Added `MIN_POWER` to output of `amd-smi static --limit`**
This change was to help users to identify what range they can change the power cap of the GPU to. We added this to simplify why a device supports (or does not support) power capping (also known as overdrive). See `amd-smi set -g all --power-cap <value in W>` or `amd-smi reset -g all --power-cap`.
- **Added `MIN_POWER` to output of `amd-smi static --limit`**.
This change helps users identify the range to which they can change the power cap of the GPU. The change is added to simplify why a device supports (or does not support) power capping (also known as overdrive). See `amd-smi set -g all --power-cap <value in W>` or `amd-smi reset -g all --power-cap`.
```shell
$ amd-smi static --limit
$ amd-smi static --limit
GPU: 0
LIMIT:
MAX_POWER: 203 W
@@ -47,16 +50,43 @@ GPU: 1
SHUTDOWN_VRAM_TEMPERATURE: 105 °C
```
### Changed
### Optimizations
- **`amdsmi_get_power_cap_info` now returns values in uW instead of W**
- **Updated `amd-smi monitor --pcie` output**.
The source for pcie bandwidth monitor output was a legacy file we no longer support and was causing delays within the monitor command. The output is no longer using TX/RX but instantaneous bandwidth from gpu_metrics instead; updated output:
```shell
$ amd-smi monitor --pcie
GPU PCIE_BW
0 26 Mb/s
```
- **Updated CLI voltage curve command output**.
The output for `amd-smi metric --voltage-curve` now splits the frequency and voltage output by curve point or outputs N/A if not applicable
```shell
GPU: 0
VOLTAGE_CURVE:
POINT_0_FREQUENCY: 872 Mhz
POINT_0_VOLTAGE: 736 mV
POINT_1_FREQUENCY: 1354 Mhz
POINT_1_VOLTAGE: 860 mV
POINT_2_FREQUENCY: 1837 Mhz
POINT_2_VOLTAGE: 1186 mV
```
- **Updated `amdsmi_get_gpu_board_info()` now has larger structure sizes for `amdsmi_board_info_t`**.
Updated sizes that work for retreiving relavant board information across AMD's
ASIC products. This requires users to update any ABIs using this structure.
- **`amdsmi_get_power_cap_info` now returns values in uW instead of W**.
`amdsmi_get_power_cap_info` will return in uW as originally reflected by driver. Previously `amdsmi_get_power_cap_info` returned W values, this conflicts with our sets and modifies values retrieved from driver. We decided to keep the values returned from driver untouched (in original units, uW). Then in CLI we will convert to watts (as previously done - no changes here). Additionally, driver made updates to min power cap displayed for devices when overdrive is disabled which prompted for this change (in this case min_power_cap and max_power_cap are the same).
- **Updated Python Library return types for amdsmi_get_gpu_memory_reserved_pages & amdsmi_get_gpu_bad_page_info**
- **Updated Python Library return types for amdsmi_get_gpu_memory_reserved_pages & amdsmi_get_gpu_bad_page_info**.
Previously calls were returning "No bad pages found." if no pages were found, now it only returns the list type and can be empty.
- **Updated `amd-smi metric --ecc-blocks` output**
The ecc blocks arguement was outputing blocks without counters available, updated the filtering show blocks that counters are available for:
- **Updated `amd-smi metric --ecc-blocks` output**.
The ecc blocks argument was outputing blocks without counters available, updated the filtering show blocks that counters are available for:
``` shell
$ amd-smi metric --ecc-block
@@ -92,23 +122,21 @@ GPU: 0
DEFERRED_COUNT: 0
```
- **Removed `amdsmi_get_gpu_process_info` from python library**
amdsmi_get_gpu_process_info was removed from the C library in an earlier build, but the API was still in the python interface
- **Removed `amdsmi_get_gpu_process_info` from Python library**.
amdsmi_get_gpu_process_info was removed from the C library in an earlier build, but the API was still in the Python interface.
### Optimizations
### Fixes
- **Updated `amd-smi monitor --pcie` output**
The source for pcie bandwidth monitor output was a legacy file we no longer support and was causing delays within the monitor command. The output is no longer using TX/RX but instantaneous bandwidth from gpu_metrics instead; updated output:
- **`amdsmi_get_gpu_board_info()` no longer returns junk char strings**.
Previously if there was a partial failure to retrieve character strings, we would return
garbage output to users using the API. This fix intends to populate as many values as possible.
Then any failure(s) found along the way, `\0` is provided to `amdsmi_board_info_t`
structures data members which cannot be populated. Ensuring empty char string values.
```shell
$ amd-smi monitor --pcie
GPU PCIE_BW
0 26 Mb/s
```
- **Fixed parsing of `pp_od_clk_voltage` within `amdsmi_get_gpu_od_volt_info`**.
The parsing of `pp_od_clk_voltage` was not dynamic enough to work with the dropping of voltage curve support on MI series cards. This propagates down to correcting the CLI's output `amd-smi metric --voltage-curve` to N/A if voltage curve is not enabled.
### Fixed
- **Fixed `amd-smi metric --power` now provides power output for Navi2x/Navi3x/MI1x**
- **Fixed `amd-smi metric --power` now provides power output for Navi2x/Navi3x/MI1x**.
These systems use an older version of gpu_metrics in amdgpu. This fix only updates what CLI outputs.
No change in any of our APIs.
@@ -133,11 +161,11 @@ GPU: 1
THROTTLE_STATUS: UNTHROTTLED
```
- **Fixed `amdsmitstReadWrite.TestPowerCapReadWrite` test for Navi3X, Navi2X, MI100**
- **Fixed `amdsmitstReadWrite.TestPowerCapReadWrite` test for Navi3X, Navi2X, MI100**.
Updates required `amdsmi_get_power_cap_info` to return in uW as originally reflected by driver. Previously `amdsmi_get_power_cap_info` returned W values, this conflicts with our sets and modifies values retrieved from driver. We decided to keep the values returned from driver untouched (in original units, uW). Then in CLI we will convert to watts (as previously done - no changes here). Additionally, driver made updates to min power cap displayed for devices when overdrive is disabled which prompted for this change (in this case min_power_cap and max_power_cap are the same).
- **Fixed python interface call amdsmi_get_gpu_memory_reserved_pages & amdsmi_get_gpu_bad_page_info**
Previously python interface calls to populated bad pages resulted in a `ValueError: NULL pointer access`. This fixes the bad-pages subcommand CLI subcommand as well.
- **Fixed Python interface call amdsmi_get_gpu_memory_reserved_pages & amdsmi_get_gpu_bad_page_info**.
Previously Python interface calls to populated bad pages resulted in a `ValueError: NULL pointer access`. This fixes the bad-pages subcommand CLI subcommand as well.
### Known Issues
@@ -145,13 +173,9 @@ Previously python interface calls to populated bad pages resulted in a `ValueErr
## amd_smi_lib for ROCm 6.1.1
### Added
### Changes
- N/A
### Changed
- **Updated metrics --clocks**
- **Updated metrics --clocks**.
Output for `amd-smi metric --clock` is updated to reflect each engine and bug fixes for the clock lock status and deep sleep status.
``` shell
@@ -262,7 +286,7 @@ GPU: 0
DEEP_SLEEP: ENABLED
```
- **Added deferred ecc counts**
- **Added deferred ecc counts**.
Added deferred error correctable counts to `amd-smi metric --ecc --ecc-blocks`
```shell
@@ -286,7 +310,7 @@ GPU: 0
...
```
- **Updated `amd-smi topology --json` to align with host/guest**
- **Updated `amd-smi topology --json` to align with host/guest**.
Topology's `--json` output now is changed to align with output host/guest systems. Additionally, users can select/filter specific topology details as desired (refer to `amd-smi topology -h` for full list). See examples shown below.
*Previous format:*
@@ -419,35 +443,31 @@ $ /opt/rocm/bin/amd-smi topology -a -t --json
]
```
### Optimizations
### Fixes
- N/A
### Fixed
- **Fix for GPU reset error on non-amdgpu cards**
- **Fix for GPU reset error on non-amdgpu cards**.
Previously our reset could attempting to reset non-amd GPUS- resuting in "Unable to reset non-amd GPU" error. Fix
updates CLI to target only AMD ASICs.
- **Fix for `amd-smi metric --pcie` and `amdsmi_get_pcie_info()`Navi32/31 cards**
- **Fix for `amd-smi metric --pcie` and `amdsmi_get_pcie_info()`Navi32/31 cards**.
Updated API to include `amdsmi_card_form_factor_t.AMDSMI_CARD_FORM_FACTOR_CEM`. Prevously, this would report "UNKNOWN". This fix
provides the correct board `SLOT_TYPE` associated with these ASICs (and other Navi cards).
- **Fix for `amd-smi process`**
- **Fix for `amd-smi process`**.
Fixed output results when getting processes running on a device.
- **Improved Error handling for `amd-smi process`**
- **Improved Error handling for `amd-smi process`**.
Fixed Attribute Error when getting process in csv format
### Known issues
- `amd-smi bad-pages` can results with "ValueError: NULL pointer access" with certain PM FW versions
- `amd-smi bad-pages` can results with "ValueError: NULL pointer access" with certain PM FW versions.
## amd_smi_lib for ROCm 6.1.0
### Added
### Additions
- **Added Monitor Command**
- **Added Monitor Command**.
Provides users the ability to customize GPU metrics to capture, collect, and observe. Output is provided in a table view. This aligns closer to ROCm SMI `rocm-smi` (no argument), additionally allows uers to customize what data is helpful for their use-case.
```shell
@@ -507,7 +527,7 @@ GPU POWER GPU_TEMP MEM_TEMP GFX_UTIL GFX_CLOCK MEM_UTIL MEM_CLOCK VRAM_U
7 175 W 34 °C 32 °C 0 % 113 MHz 0 % 900 MHz 283 MB 196300 MB
```
- **Integrated ESMI Tool**
- **Integrated ESMI Tool**.
Users can get CPU metrics and telemetry through our API and CLI tools. This information can be seen in `amd-smi static` and `amd-smi metric` commands. Only available for limited target processors. As of ROCm 6.0.2, this is listed as:
- AMD Zen3 based CPU Family 19h Models 0h-Fh and 30h-3Fh
- AMD Zen4 based CPU Family 19h Models 10h-1Fh and A0-AFh
@@ -657,7 +677,7 @@ CPU: 0
RESPONSE: N/A
```
- **Added support for new metrics: VCN, JPEG engines, and PCIe errors**
- **Added support for new metrics: VCN, JPEG engines, and PCIe errors**.
Using the AMD SMI tool, users can retreive VCN, JPEG engines, and PCIe errors by calling `amd-smi metric -P` or `amd-smi metric --usage`. Depending on device support, `VCN_ACTIVITY` will update for MI3x ASICs (with 4 separate VCN engine activities) for older asics `MM_ACTIVITY` with UVD/VCN engine activity (average of all engines). `JPEG_ACTIVITY` is a new field for MI3x ASICs, where device can support up to 32 JPEG engine activities. See our documentation for more in-depth understanding of these new fields.
```shell
@@ -690,7 +710,7 @@ GPU: 0
```
- **Added AMDSMI Tool Version**
- **Added AMDSMI Tool Version**.
AMD SMI will report ***three versions***: AMDSMI Tool, AMDSMI Library version, and ROCm version.
The AMDSMI Tool version is the CLI/tool version number with commit ID appended after `+` sign.
The AMDSMI Library version is the library package version number.
@@ -701,7 +721,7 @@ $ amd-smi version
AMDSMI Tool: 23.4.2+505b858 | AMDSMI Library version: 24.2.0.0 | ROCm version: 6.1.0
```
- **Added XGMI table**
- **Added XGMI table**.
Displays XGMI information for AMD GPU devices in a table format. Only available on supported ASICs (eg. MI300). Here users can view read/write data XGMI or PCIe accumulated data transfer size (in KiloBytes).
```shell
@@ -735,7 +755,7 @@ GPU7 0000:df:00.0 32 Gb/s 512 Gb/s XGMI
```
- **Added units of measure to JSON output.**
- **Added units of measure to JSON output**.
We added unit of measure to JSON/CSV `amd-smi metric`, `amd-smi static`, and `amd-smi monitor` commands.
Ex.
@@ -769,9 +789,9 @@ amd-smi metric -p --json
]
```
### Changed
### Changes
- **Topology is now left-aligned with BDF of each device listed individual table's row/coloumns.**
- **Topology is now left-aligned with BDF of each device listed individual table's row/coloumns**.
We provided each device's BDF for every table's row/columns, then left aligned data. We want AMD SMI Tool output to be easy to understand and digest for our users. Having users scroll up to find this information made it difficult to follow, especially for devices which have many devices associated with one ASIC.
```shell
@@ -832,15 +852,11 @@ NUMA BW TABLE:
0000:df:00.0 50000-50000 50000-50000 50000-50000 50000-50000 50000-50000 50000-50000 50000-50000 N/A
```
### Optimizations
### Fixes
- N/A
### Fixed
- **Fix for Navi3X/Navi2X/MI100 `amdsmi_get_gpu_pci_bandwidth()` in frequencies_read tests**
- **Fix for Navi3X/Navi2X/MI100 `amdsmi_get_gpu_pci_bandwidth()` in frequencies_read tests**.
Devices which do not report (eg. Navi3X/Navi2X/MI100) we have added checks to confirm these devices return AMDSMI_STATUS_NOT_SUPPORTED. Otherwise, tests now display a return string.
- **Fix for devices which have an older pyyaml installed**
- **Fix for devices which have an older pyyaml installed**.
Platforms which are identified as having an older pyyaml version or pip, we no manually update both pip and pyyaml as needed. This corrects issues identified below. Fix impacts the following CLI commands:
- `amd-smi list`
- `amd-smi static`
@@ -852,43 +868,35 @@ Platforms which are identified as having an older pyyaml version or pip, we no m
TypeError: dump_all() got an unexpected keyword argument 'sort_keys'
```
- **Fix for crash when user is not a member of video/render groups**
- **Fix for crash when user is not a member of video/render groups**.
AMD SMI now uses same mutex handler for devices as rocm-smi. This helps avoid crashes when DRM/device data is inaccessable to the logged in user.
### Known Issues
- N/A
## amd_smi_lib for ROCm 6.0.0
### Added
### Additions
- **Integrated the E-SMI (EPYC-SMI) library**
- **Integrated the E-SMI (EPYC-SMI) library**.
You can now query CPU-related information directly through AMD SMI. Metrics include power, energy, performance, and other system details.
- **Added support for gfx942 metrics**
- **Added support for gfx942 metrics**.
You can now query MI300 device metrics to get real-time information. Metrics include power, temperature, energy, and performance.
- **Compute and memory partition support**
- **Compute and memory partition support**.
Users can now view, set, and reset partitions. The topology display can provide a more in-depth look at the device's current configuration.
### Changed
- **GPU index sorting made consistent with other tools**
To ensure alignment with other ROCm software tools, GPU index sorting is optimized to use Bus:Device.Function (BDF) rather than the card number.
- **Topology output is now aligned with GPU BDF table**
Earlier versions of the topology output were difficult to read since each GPU was displayed linearly.
Now the information is displayed as a table by each GPU's BDF, which closer resembles rocm-smi output.
### Optimizations
- Updated to C++17, gtest-1.14, and cmake 3.14
### Fixed
### Changes
- **Fix for driver not initialized**
- **GPU index sorting made consistent with other tools**.
To ensure alignment with other ROCm software tools, GPU index sorting is optimized to use Bus:Device.Function (BDF) rather than the card number.
- **Topology output is now aligned with GPU BDF table**.
Earlier versions of the topology output were difficult to read since each GPU was displayed linearly.
Now the information is displayed as a table by each GPU's BDF, which closer resembles rocm-smi output.
### Fixes
- **Fix for driver not initialized**.
If driver module is not loaded, user retrieve error reponse indicating amdgpu module is not loaded.
### Known Issues
- N/A
+1 -1
View File
@@ -28,7 +28,7 @@ find_program(GIT NAMES git)
## Setup the package version based on git tags.
set(PKG_VERSION_GIT_TAG_PREFIX "amdsmi_pkg_ver")
get_package_version_number("24.5.2" ${PKG_VERSION_GIT_TAG_PREFIX} GIT)
get_package_version_number("24.5.3" ${PKG_VERSION_GIT_TAG_PREFIX} GIT)
message("Package version: ${PKG_VERSION_STR}")
set(${AMD_SMI_LIBS_TARGET}_VERSION_MAJOR "${CPACK_PACKAGE_VERSION_MAJOR}")
set(${AMD_SMI_LIBS_TARGET}_VERSION_MINOR "${CPACK_PACKAGE_VERSION_MINOR}")
+1 -1
View File
@@ -79,7 +79,7 @@ amd-smi will report the version and current platform detected when running the c
~$ amd-smi
usage: amd-smi [-h] ...
AMD System Management Interface | Version: 24.5.2.0 | ROCm version: 6.1.2 | Platform: Linux Baremetal
AMD System Management Interface | Version: 24.5.3.0 | ROCm version: 6.1.2 | Platform: Linux Baremetal
options:
-h, --help show this help message and exit
+26 -4
View File
@@ -1792,17 +1792,39 @@ class AMDSMICommands():
if args.voltage_curve:
try:
od_volt = amdsmi_interface.amdsmi_get_gpu_od_volt_info(args.gpu)
logging.debug(f"OD Voltage info: {od_volt}")
# Populate N/A values per voltage point
voltage_point_dict = {}
for point in range(amdsmi_interface.AMDSMI_NUM_VOLTAGE_CURVE_POINTS):
voltage_point_dict[f'point_{point}_frequency'] = "N/A"
voltage_point_dict[f'point_{point}_voltage'] = "N/A"
for point in range(3):
# Populate voltage point values
for point in range(amdsmi_interface.AMDSMI_NUM_VOLTAGE_CURVE_POINTS):
if isinstance(od_volt, dict):
logging.debug(f"point_{point} frequency: {od_volt['curve.vc_points'][point].frequency}")
logging.debug(f"point_{point} voltage: {od_volt['curve.vc_points'][point].voltage}")
frequency = int(od_volt["curve.vc_points"][point].frequency / 1000000)
voltage = int(od_volt["curve.vc_points"][point].voltage)
else:
frequency = 0
voltage = 0
voltage_point_dict[f'voltage_point_{point}'] = f"{frequency} Mhz {voltage} mV"
frequency = "N/A"
voltage = "N/A"
if frequency == 0:
frequency = "N/A"
if voltage == 0:
voltage = "N/A"
if frequency != "N/A":
frequency = self.helpers.unit_format(self.logger, frequency, "Mhz")
if voltage != "N/A":
voltage = self.helpers.unit_format(self.logger, voltage, "mV")
voltage_point_dict[f'point_{point}_frequency'] = frequency
voltage_point_dict[f'point_{point}_voltage'] = voltage
values_dict['voltage_curve'] = voltage_point_dict
except amdsmi_exception.AmdSmiLibraryException as e:
+1
View File
@@ -0,0 +1 @@
test
+5 -2
View File
@@ -48,7 +48,7 @@ PROJECT_NAME = AMD SMI
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = "24.5.2.0"
PROJECT_NUMBER = "24.5.3.0"
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -907,8 +907,11 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
INPUT = ../../README.md \
INPUT = ../reference/index.rst \
../../include/amd_smi/amdsmi.h
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,255 @@
.. meta::
:description: Using AMD SMI
:keywords: AMD, SMI, system, management, interface, ROCm
********************************
Usage Basics for the C Library
********************************
Device/Socket handles
----------------------
Many of the AMD SMI library's functions take a "socket handle" or "device handle." The socket is an abstraction of the hardware's physical socket. This will enable AMD SMI to provide a better representation of the hardware to the user. Although there is always one distinct GPU for a socket, the APU may have both GPU and CPU devices on the same socket. Moreover, for the MI200 series, it may have multiple GCDs.
To discover the sockets in the system, `amdsmi_get_socket_handles()` is called to get a list of socket handles, which, in turn, can be used to query the devices in that socket using `amdsmi_get_processor_handles().` The device handler is used to distinguish the detected devices from one another. It is important to note that a device may end up with a different device handle after restarting the application, so a device handle should not be relied upon to be constant over the process.
The list of socket handles discovered using `amdsmi_get_socket_handles()`, can also be used to query the CPUs in that socket using amdsmi_get_processor_handles_by_type(), which in turn can then be used to query the cores in that CPU using amdsmi_get_processor_handles_by_type() again.
Hello AMD SMI
--------------
The only required AMD SMI call for any program that wants to use AMD SMI is the `amdsmi_init()` call. This call initializes some internal data structures that subsequent AMD-SMI calls will use. A flag can be passed in the call if the application is only interested in a specific device type.
When AMD SMI is no longer used, `amdsmi_shut_down()` should be called. This provides a way to release resources that AMD-SMI may have held.
1) A simple "Hello World" type program that displays the temperature of detected devices would look like this:
.. code-block::
#include <iostream>
#include <vector>
#include "amd_smi/amdsmi.h"
int main() {
amdsmi_status_t ret;
// Init amdsmi for sockets and devices. Here we are only interested in AMD_GPUS.
ret = amdsmi_init(AMDSMI_INIT_AMD_GPUS);
// Get all sockets
uint32_t socket_count = 0;
// Get the socket count available in the system.
ret = amdsmi_get_socket_handles(&socket_count, nullptr);
// Allocate the memory for the sockets
std::vector<amdsmi_socket_handle> sockets(socket_count);
// Get the socket handles in the system
ret = amdsmi_get_socket_handles(&socket_count, &sockets[0]);
std::cout << "Total Socket: " << socket_count << std::endl;
// For each socket, get identifier and devices
for (uint32_t i=0; i < socket_count; i++) {
// Get Socket info
char socket_info[128];
ret = amdsmi_get_socket_info(sockets[i], 128, socket_info);
std::cout << "Socket " << socket_info<< std::endl;
// Get the device count for the socket.
uint32_t device_count = 0;
ret = amdsmi_get_processor_handles(sockets[i], &device_count, nullptr);
// Allocate the memory for the device handlers on the socket
std::vector<amdsmi_processor_handle> processor_handles(device_count);
// Get all devices of the socket
ret = amdsmi_get_processor_handles(sockets[i],
&device_count, &processor_handles[0]);
// For each device of the socket, get name and temperature.
for (uint32_t j=0; j < device_count; j++) {
// Get device type. Since the amdsmi is initialized with
// AMD_SMI_INIT_AMD_GPUS, the processor_type must be AMD_GPU.
processor_type_t processor_type;
ret = amdsmi_get_processor_type(processor_handles[j], &processor_type);
if (processor_type != AMD_GPU) {
std::cout << "Expect AMD_GPU device type!\n";
return 1;
}
// Get device name
amdsmi_board_info_t board_info;
ret = amdsmi_get_gpu_board_info(processor_handles[j], &board_info);
std::cout << "\tdevice "
<< j <<"\n\t\tName:" << board_info.product_name << std::endl;
// Get temperature
int64_t val_i64 = 0;
ret = amdsmi_get_temp_metric(processor_handles[j], TEMPERATURE_TYPE_EDGE,
AMDSMI_TEMP_CURRENT, &val_i64);
std::cout << "\t\tTemperature: " << val_i64 << "C" << std::endl;
}
}
// Clean up resources allocated at amdsmi_init. It will invalidate sockets
// and devices pointers
ret = amdsmi_shut_down();
return 0;
}
2) A sample program that displays the power of detected cpus would look like this:
.. code-block::
#include <iostream>
#include <vector>
#include "amd_smi/amdsmi.h"
int main(int argc, char **argv) {
amdsmi_status_t ret;
uint32_t socket_count = 0;
// Initialize amdsmi for AMD CPUs
ret = amdsmi_init(AMDSMI_INIT_AMD_CPUS);
ret = amdsmi_get_socket_handles(&socket_count, nullptr);
// Allocate the memory for the sockets
std::vector<amdsmi_socket_handle> sockets(socket_count);
// Get the sockets of the system
ret = amdsmi_get_socket_handles(&socket_count, &sockets[0]);
std::cout << "Total Socket: " << socket_count << std::endl;
// For each socket, get cpus
for (uint32_t i = 0; i < socket_count; i++) {
uint32_t cpu_count = 0;
// Set processor type as AMD_CPU
processor_type_t processor_type = AMD_CPU;
ret = amdsmi_get_processor_handles_by_type(sockets[i], processor_type, nullptr, &cpu_count);
// Allocate the memory for the cpus
std::vector<amdsmi_processor_handle> plist(cpu_count);
// Get the cpus for each socket
ret = amdsmi_get_processor_handles_by_type(sockets[i], processor_type, &plist[0], &cpu_count);
for (uint32_t index = 0; index < plist.size(); index++) {
uint32_t socket_power;
std::cout<<"CPU "<<index<<"\t"<< std::endl;
std::cout<<"Power (Watts): ";
ret = amdsmi_get_cpu_socket_power(plist[index], &socket_power);
if(ret != AMDSMI_STATUS_SUCCESS)
std::cout<<"Failed to get cpu socket power"<<"["<<index<<"] , Err["<<ret<<"] "<< std::endl;
if (!ret) {
std::cout<<static_cast<double>(socket_power)/1000<<std::endl;
}
std::cout<<std::endl;
}
}
// Clean up resources allocated at amdsmi_init
ret = amdsmi_shut_down();
return 0;
}
Building AMD SMI
-----------------
Rebuilding Python wrapper
==========================
Python wrapper (binding) is an auto-generated file `py-interface/amdsmi_wrapper.py`
The wrapper should be re-generated on each C++ API change by doing the following:
.. code-block:: bash
./update_wrapper.sh
After this command, the file in `py-interface/amdsmi_wrapper.py` will be automatically updated on each compile.
Note: To re-generate the Python wrapper, you must have **Docker** installed.
Note: Python_wrapper is NOT automatically re-generated. You must run `./update_wrapper.sh`.
Additional software required for building AMD SMI
--------------------------------------------------
The following components are required to build the library.
.. Note:: The software versions listed are what was used in development. Earlier versions are not guaranteed to work.
* CMake (v3.14.0) - `python3 -m pip install cmake`
* g++ (5.4.0)
The following components are required to build the AMD SMI Python package:
* Clang (14.0 or above)
* Python (3.6.8 or above)
* virtualenv - `python3 -m pip install virtualenv`
The following tools are required to build the latest documentation:
* Doxygen (1.8.11)
* Latex (pdfTeX 3.14159265-2.6-1.40.16)
The source code for AMD SMI is available on Github.
After the AMD SMI library git repository is cloned to a local Linux machine, the default location for the library and headers is /opt/rocm.
.. Note:: Before installation, the old ROCm directories must be deleted:
* /opt/rocm
* /opt/rocm-{number}
Building the library is achieved by following the typical CMake build sequence (run as root user or use 'sudo' before the 'make install' command), specifically:
.. code-block:: bash
mkdir -p build
cd build
cmake ..
make -j $(nproc)
make install
The built library will appear in the `build` folder.
In addition to the preceding steps, use the following instructions to build the rpm and deb packages:
.. code-block:: bash
make package
Building tests
-------------------
To verify the build and capability of AMD SMI on your system and see an example of how AMD SMI can be used, you may build and run the tests available in the repo. To build the tests, follow these steps:
.. code-block:: bash
mkdir -p build
cd build
cmake -DBUILD_TESTS=ON ..
make -j $(nproc)
Running tests
--------------
Execute the program `amdsmitst` that is built from the steps above to run the test.
Path to the program `amdsmitst`: `build/tests/amd_smi_test/`
File diff suppressed because it is too large Load Diff
-2
View File
@@ -1,2 +0,0 @@
```{include} ../README.md
```
+50
View File
@@ -0,0 +1,50 @@
.. meta::
:description: AMDSMI documentation and API reference library
:keywords: amdsmi, ROCm, API, documentation
********************************************************************
AMD SMI documentation
********************************************************************
The AMD System Management Interface (SMI) Library, or AMD SMI library, is a C library for Linux that provides a user space interface for applications to monitor and control AMD devices.
You can access the AMD SMI code on the `GitHub repository <https://github.com/ROCm/amdsmi>`_.
.. Note::
This project is a successor to `rocm_smi_lib. <https://github.com/RadeonOpenCompute/rocm_smi_lib>`_
.. grid:: 2
:gutter: 3
.. grid-item-card:: Install
* :doc:`AMD SMI installation <./install/install>`
.. grid-item-card:: API reference
* :doc:`Files <../doxygen/docBin/html/files>`
* :doc:`Globals <../doxygen/docBin/html/globals>`
* :doc:`Data structures <../doxygen/docBin/html/annotated>`
* :doc:`Modules <../doxygen/docBin/html/modules>`
* :doc:`Data fields <../doxygen/docBin/html/functions_data_fields>`
.. grid-item-card:: How to
* :doc:`Use AMD SMI for C++ library <how-to/using-amdsmi-for-C++>`
* :doc:`Use AMD SMI for Python library <how-to/using-amdsmi-for-python>`
* :doc:`Use AMD SMI CLI tool <how-to/using-AMD-SMI-CLI-tool>`
.. grid-item-card:: Tutorials
* `AMD SMI GitHub samples <https://github.com/ROCm/amdsmi/tree/develop/example>`_
* `ROCm SMI Github samples <https://github.com/ROCm/rocm_smi_lib/tree/develop/docs>`_
To contribute to the documentation, refer to
`Contributing to ROCm <https://rocm.docs.amd.com/en/latest/contribute/contributing.html>`_.
You can find licensing information on the
`Licensing <https://rocm.docs.amd.com/en/latest/about/license.html>`_ page.
+147
View File
@@ -0,0 +1,147 @@
.. meta::
:description: Install AMD SMI
:keywords: install, SMI, AMD, ROCm
********************************************************************
Installation
********************************************************************
AMD System Management Interface (AMD SMI) library
-------------------------------------------------
The AMD System Management Interface Library (AMD SMI library) is a C library for Linux that provides a user space interface for applications to monitor and control AMD devices.
.. Note::
This project is a successor to `rocm_smi_lib. <https://github.com/RadeonOpenCompute/rocm_smi_lib>`_
Supported platforms
=====================
In its initial release, the AMD SMI library supports Linux bare metal and Linux virtual machine guest for AMD GPUs. In a future release, the library will extend to support AMD EPYC™ CPUs.
The AMD SMI library can run on AMD ROCm-supported platforms. Refer to `System requirements - Linux <https://rocm.docs.amd.com/projects/install-on-linux/en/latest/reference/system-requirements.html>`_ for more information.
To run the AMD SMI library, the `amdgpu` driver and the `hsmp` driver must be installed. Optionally, `libdrm` can be installed to query firmware information and hardware IPs.
CLI tool and libraries installation
------------------------------------
Requirements
=============
* Python 3.6.8+ 64-bit
* amdgpu driver must be loaded for `amdsmi_init()` to pass
Installation steps
-------------------
1. Install amdgpu using ROCm.
2. Install amdgpu driver. See the following example. Note that your release and link may differ. The `amdgpu-install --usecase=rocm` triggers both the amdgpu driver update and AMD SMI packages to be installed on your device.
.. code-block:: shell
sudo apt update
wget https://repo.radeon.com/amdgpu-install/6.0.2/ubuntu/jammy/amdgpu-install_6.0.60002-1_all.deb
sudo apt install ./amdgpu-install_6.0.60002-1_all.deb
sudo amdgpu-install --usecase=rocm
amd-smi --help
3. Install an example for Ubuntu 22.04 (without ROCm).
.. code-block:: bash
apt install amd-smi-lib
# if installed with rocm ignore the export
export PATH="${PATH:+${PATH}:}~/opt/rocm/bin"
amd-smi --help
Optional autocompletion
------------------------
The `amd-smi` cli application supports autocompletion. The package should attempt to install it, if argcomplete is not installed, you can enable it by using the following commands:
.. code:: bash
python3 -m pip install argcomplete
activate-global-python-argcomplete --user
# restart shell to enable
Manual/Multiple ROCm instance Python library install
------------------------------------------------------
In the event there are multiple ROCm installations and `pyenv` is not being used to use the correct amdsmi version, you must uninstall previous versions of AMD SMI and install the latest version you want directly from your ROCm instance.
Python library install example for Ubuntu 22.04
=================================================
1. Remove any existing AMD SMI installation:
.. code-block:: bash
python3 -m pip list | grep amd
python3 -m pip uninstall amdsmi
2. Install Python library from your target ROCm instance:
.. code:: bash
apt install amd-smi-lib
cd /opt/rocm/share/amd_smi
python3 -m pip install --upgrade pip
python3 -m pip install --user
Now you have the AMD SMI Python library in your Python path:
.. code:: bash
~$ python3
Python 3.8.10 (default, May 26 2023, 14:05:08)
[GCC 9.4.0] on linux
3. Type "help", "copyright", "credits" or "license" for more information
.. code:: bash
import amdsmi
Sphinx documentation
=====================
Run the following commands to build the documentation locally:
.. code-block:: bash
cd docs
python3 -m pip install -r sphinx/requirements.txt
python3 -m sphinx -T -E -b html -d _build/doctrees -D language=en . _build/html
The output is available in `docs/_build/html`.
For additional details, see `Contribute to ROCm documentation <https://rocm.docs.amd.com/en/latest/contribute/contributing.html>`_.
+14
View File
@@ -0,0 +1,14 @@
.. meta::
:description: Install AMD SMI
:keywords: install, SMI, AMD, ROCm
******************
API reference
******************
This section provides technical descriptions and important information about the different AMD SMI and library components.
* {doc}`Library <../doxygen/docBin/html/files>`
* {doc}`Functions <../doxygen/docBin/html/globals>`
* {doc}`Data structures <../doxygen/docBin/html/annotated>`
@@ -0,0 +1,34 @@
====================
C++ Tutorials
====================
This chapter contains the ROCm SMI C++ API tutorials.
.. code-block:: c++
#include <stdint.h>
#include "rocm_smi/rocm_smi.h"
int main() {
rsmi_status_t ret;
uint32_t num_devices;
uint16_t dev_id;
// We will skip return code checks for this example, but it
// is recommended to always check this as some calls may not
// apply for some devices or ROCm releases
ret = rsmi_init(0);
ret = rsmi_num_monitor_devices(&num_devices);
for (int i=0; i < num_devices; ++i) {
ret = rsmi_dev_id_get(i, &dev_id);
// dev_id holds the device ID of device i, upon a
// successful call
}
ret = rsmi_shut_down();
return 0;
}
For more examples please check the `C++ example <https://github.com/ROCm/rocm_smi_lib/blob/develop/rocm_smi/example/rocm_smi_example.cc>`_
or `tests. <https://github.com/ROCm/rocm_smi_lib/tree/develop/tests/rocm_smi_test/functional>`_
@@ -0,0 +1,13 @@
.. meta::
:description: ROCm SMI documentation and API reference library
:keywords: SMI, ROCm, API, documentation
****************************************************
ROCm System Management Interface (ROCm SMI) library
****************************************************
The ROCm System Management Interface Library, or ROCm SMI library, is part of the ROCm software stack. It is a C library for Linux that provides a user space interface for applications to monitor and control GPU applications.
ROCm SMI Library still works in the current release, but its documentation is now integrated with AMD SMI. For information specific to ROCm SMI Library, refer to `ROCm SMI Library <https://github.com/ROCm/rocm_smi_lib/>`_
@@ -0,0 +1,269 @@
====================
Python API Reference
====================
This chapter describes the ROCm SMI Python module API.
.. default-domain:: py
.. py:currentmodule:: rocm_smi
Functions
---------
.. autofunction:: rocm_smi.driverInitialized
.. autofunction:: rocm_smi.formatJson
.. autofunction:: rocm_smi.formatCsv
.. autofunction:: rocm_smi.formatMatrixToJSON
.. autofunction:: rocm_smi.getBus
.. autofunction:: rocm_smi.getFanSpeed
.. autofunction:: rocm_smi.getGpuUse
.. autofunction:: rocm_smi.getDRMDeviceId
.. autofunction:: rocm_smi.getSubsystemId
.. autofunction:: rocm_smi.getVendor
.. autofunction:: rocm_smi.getGUID
.. autofunction:: rocm_smi.getTargetGfxVersion
.. autofunction:: rocm_smi.getNodeId
.. autofunction:: rocm_smi.getDeviceName
.. autofunction:: rocm_smi.getRev
.. autofunction:: rocm_smi.getMaxPower
.. autofunction:: rocm_smi.getMemInfo
.. autofunction:: rocm_smi.getProcessName
.. autofunction:: rocm_smi.getPerfLevel
.. autofunction:: rocm_smi.getPid
.. autofunction:: rocm_smi.getPidList
.. autofunction:: rocm_smi.getPower
.. autofunction:: rocm_smi.getRasEnablement
.. autofunction:: rocm_smi.getTemp
.. autofunction:: rocm_smi.findFirstAvailableTemp
.. autofunction:: rocm_smi.getTemperatureLabel
.. autofunction:: rocm_smi.getPowerLabel
.. autofunction:: rocm_smi.getVbiosVersion
.. autofunction:: rocm_smi.getVersion
.. autofunction:: rocm_smi.getComputePartition
.. autofunction:: rocm_smi.getMemoryPartition
.. autofunction:: rocm_smi.print2DArray
.. autofunction:: rocm_smi.printEmptyLine
.. autofunction:: rocm_smi.printErrLog
.. autofunction:: rocm_smi.printInfoLog
.. autofunction:: rocm_smi.printEventList
.. autofunction:: rocm_smi.printLog
.. autofunction:: rocm_smi.printListLog
.. autofunction:: rocm_smi.printLogSpacer
.. autofunction:: rocm_smi.printSysLog
.. autofunction:: rocm_smi.printTableLog
.. autofunction:: rocm_smi.printTableRow
.. autofunction:: rocm_smi.checkIfSecondaryDie
.. autofunction:: rocm_smi.resetClocks
.. autofunction:: rocm_smi.resetFans
.. autofunction:: rocm_smi.resetPowerOverDrive
.. autofunction:: rocm_smi.resetProfile
.. autofunction:: rocm_smi.resetXgmiErr
.. autofunction:: rocm_smi.resetPerfDeterminism
.. autofunction:: rocm_smi.resetComputePartition
.. autofunction:: rocm_smi.resetMemoryPartition
.. autofunction:: rocm_smi.setClockRange
.. autofunction:: rocm_smi.setClockExtremum
.. autofunction:: rocm_smi.setVoltageCurve
.. autofunction:: rocm_smi.setPowerPlayTableLevel
.. autofunction:: rocm_smi.setClockOverDrive
.. autofunction:: rocm_smi.setClocks
.. autofunction:: rocm_smi.setPerfDeterminism
.. autofunction:: rocm_smi.resetGpu
.. autofunction:: rocm_smi.isRasControlAvailable
.. autofunction:: rocm_smi.setRas
.. autofunction:: rocm_smi.setFanSpeed
.. autofunction:: rocm_smi.setPerformanceLevel
.. autofunction:: rocm_smi.setPowerOverDrive
.. autofunction:: rocm_smi.setProfile
.. autofunction:: rocm_smi.setComputePartition
.. autofunction:: rocm_smi.progressbar
.. autofunction:: rocm_smi.showProgressbar
.. autofunction:: rocm_smi.setMemoryPartition
.. autofunction:: rocm_smi.showVersion
.. autofunction:: rocm_smi.showAllConcise
.. autofunction:: rocm_smi.showAllConciseHw
.. autofunction:: rocm_smi.showBus
.. autofunction:: rocm_smi.showClocks
.. autofunction:: rocm_smi.showCurrentClocks
.. autofunction:: rocm_smi.showCurrentFans
.. autofunction:: rocm_smi.showCurrentTemps
.. autofunction:: rocm_smi.showFwInfo
.. autofunction:: rocm_smi.showGpusByPid
.. autofunction:: rocm_smi.getCoarseGrainUtil
.. autofunction:: rocm_smi.showGpuUse
.. autofunction:: rocm_smi.showEnergy
.. autofunction:: rocm_smi.showId
.. autofunction:: rocm_smi.showMaxPower
.. autofunction:: rocm_smi.showMemInfo
.. autofunction:: rocm_smi.showMemUse
.. autofunction:: rocm_smi.showMemVendor
.. autofunction:: rocm_smi.showOverDrive
.. autofunction:: rocm_smi.showPcieBw
.. autofunction:: rocm_smi.showPcieReplayCount
.. autofunction:: rocm_smi.showPerformanceLevel
.. autofunction:: rocm_smi.showPids
.. autofunction:: rocm_smi.showPower
.. autofunction:: rocm_smi.showPowerPlayTable
.. autofunction:: rocm_smi.showProduct
.. autofunction:: rocm_smi.showProfile
.. autofunction:: rocm_smi.showRange
.. autofunction:: rocm_smi.showRasInfo
.. autofunction:: rocm_smi.showRetiredPages
.. autofunction:: rocm_smi.showSerialNumber
.. autofunction:: rocm_smi.showUId
.. autofunction:: rocm_smi.showVbiosVersion
.. autofunction:: rocm_smi.showEvents
.. autofunction:: rocm_smi.showDriverVersion
.. autofunction:: rocm_smi.showVoltage
.. autofunction:: rocm_smi.showVoltageCurve
.. autofunction:: rocm_smi.showXgmiErr
.. autofunction:: rocm_smi.showAccessibleTopology
.. autofunction:: rocm_smi.showWeightTopology
.. autofunction:: rocm_smi.showHopsTopology
.. autofunction:: rocm_smi.showTypeTopology
.. autofunction:: rocm_smi.showNumaTopology
.. autofunction:: rocm_smi.showHwTopology
.. autofunction:: rocm_smi.showNodesBw
.. autofunction:: rocm_smi.showComputePartition
.. autofunction:: rocm_smi.showMemoryPartition
.. autofunction:: rocm_smi.checkAmdGpus
.. autofunction:: rocm_smi.component_str
.. autofunction:: rocm_smi.confirmOutOfSpecWarning
.. autofunction:: rocm_smi.doesDeviceExist
.. autofunction:: rocm_smi.initializeRsmi
.. autofunction:: rocm_smi.isAmdDevice
.. autofunction:: rocm_smi.listDevices
.. autofunction:: rocm_smi.load
.. autofunction:: rocm_smi.padHexValue
.. autofunction:: rocm_smi.profileString
.. autofunction:: rocm_smi.relaunchAsSudo
.. autofunction:: rocm_smi.rsmi_ret_ok
.. autofunction:: rocm_smi.save
@@ -0,0 +1,29 @@
====================
Python Tutorials
====================
This chapter is the rocm_smi Python api tutorials.
.. code-block:: python
import sys
sys.path.append("/opt/rocm/libexec/rocm_smi/")
try:
import rocm_smi
except ImportError:
raise ImportError("Could not import /opt/rocm/libexec/rocm_smi/rocm_smi.py")
class prof_utils:
def __init__(self, mode) -> None:
rocm_smi.initializeRsmi()
def getPower(self, device):
return rocm_smi.getPower(device)
def listDevices(self):
return rocm_smi.listDevices()
def getMemInfo(self, device):
(memUsed, memTotal) = rocm_smi.getMemInfo(device, "vram")
return round(float(memUsed)/float(memTotal) * 100, 2)
+47 -24
View File
@@ -1,26 +1,49 @@
# Anywhere {branch} is used, the branch name will be substituted.
# These comments will also be removed.
defaults:
numbered: False
maxdepth: 6
numbered: false
root: index
subtrees:
- caption: AMD SMI APIs
entries:
- file: doxygen/docBin/html/index
title: C
- file: py-interface_readme_link
title: Python
- caption: CLI Tools
entries:
- file: amdsmi_cli_readme_link
title: Python CLI Tool
- file: amdsmi_release_notes_link
title: Python CLI Release Notes
- caption: Changelog
entries:
- file: amdsmi_changelog_link
title: AMD-SMI Changelog
- caption: About
entries:
- file: license
subtrees:
- entries:
- file: what-is-AMDSMI.rst
title: What is AMD SMI?
- caption: Install
entries:
- file: install/install.rst
title: AMD SMI installation
- caption: How to
entries:
- file: how-to/using-amdsmi-for-C++.rst
title: Use AMD SMI for C++ library
- file: how-to/using-amdsmi-for-python.md
title: Use AMD SMI for Python library
- file: how-to/using-AMD-SMI-CLI-tool.md
title: Use AMD SMI CLI tool
- caption: API reference
entries:
- file: doxygen/docBin/html/files
title: Files
- file: doxygen/docBin/html/globals
title: Globals
- file: doxygen/docBin/html/annotated
title: Data structures
- file: doxygen/docBin/html/modules
title: Modules
- file: doxygen/docBin/html/functions_data_fields
title: Data fields
- caption: Tutorials
entries:
- url: https://github.com/ROCm/amdsmi/tree/develop/example
title: AMD SMI GitHub samples
- url: https://github.com/ROCm/rocm_smi_lib/tree/develop/docs
title: ROCm SMI lib GitHub samples
- caption: About
entries:
- file: license.md
+19 -18
View File
@@ -83,7 +83,7 @@ typedef enum {
#define AMDSMI_MAX_DEVICES 32
#define AMDSMI_MAX_NAME 32
#define AMDSMI_MAX_DRIVER_VERSION_LENGTH 80
#define AMDSMI_PRODUCT_NAME_LENGTH 128
#define AMDSMI_256_LENGTH 256
#define AMDSMI_MAX_CONTAINER_TYPE 2
#define AMDSMI_MAX_CACHE_TYPES 10
#define AMDSMI_MAX_NUM_XGMI_PHYSICAL_LINK 64
@@ -154,7 +154,7 @@ typedef enum {
#define AMDSMI_LIB_VERSION_MAJOR 5
//! Minor version should be updated for each API change, but without changing headers
#define AMDSMI_LIB_VERSION_MINOR 2
#define AMDSMI_LIB_VERSION_MINOR 3
//! Release version should be set to 0 as default and can be updated by the PMs for each CSP point release
#define AMDSMI_LIB_VERSION_RELEASE 0
@@ -573,7 +573,7 @@ typedef struct {
} amdsmi_fw_info_t;
typedef struct {
char market_name[AMDSMI_MAX_STRING_LENGTH];
char market_name[AMDSMI_256_LENGTH];
uint32_t vendor_id; //< Use 32 bit to be compatible with other platform.
char vendor_name[AMDSMI_MAX_STRING_LENGTH];
uint32_t subvendor_id; //< The subsystem vendor id
@@ -619,11 +619,11 @@ typedef struct {
} amdsmi_driver_info_t;
typedef struct {
char model_number[AMDSMI_NORMAL_STRING_LENGTH];
char model_number[AMDSMI_256_LENGTH];
char product_serial[AMDSMI_NORMAL_STRING_LENGTH];
char fru_id[AMDSMI_NORMAL_STRING_LENGTH];
char product_name[AMDSMI_PRODUCT_NAME_LENGTH];
char manufacturer_name[AMDSMI_NORMAL_STRING_LENGTH];
char product_name[AMDSMI_256_LENGTH];
char manufacturer_name[AMDSMI_MAX_STRING_LENGTH];
uint32_t reserved[32];
} amdsmi_board_info_t;
@@ -1255,7 +1255,7 @@ typedef struct {
typedef struct {
amdsmi_range_t curr_sclk_range; //!< The current SCLK frequency range
amdsmi_range_t curr_mclk_range; //!< The current MCLK frequency range;
//!< (upper bound only)
//!< (upper bound only)
amdsmi_range_t sclk_freq_limits; //!< The range possible of SCLK values
amdsmi_range_t mclk_freq_limits; //!< The range possible of MCLK values
@@ -2967,8 +2967,9 @@ amdsmi_status_t amdsmi_get_clk_freq(amdsmi_processor_handle processor_handle,
amdsmi_status_t amdsmi_reset_gpu(amdsmi_processor_handle processor_handle);
/**
* @brief This function retrieves the voltage/frequency curve information. It is
* not supported on virtual machine guest
* @brief This function retrieves the overdrive GFX & MCLK information. If valid
* for the GPU it will also populate the voltage curve data. It is not supported
* on virtual machine guest
*
* @platform{gpu_bm_linux}
*
@@ -3054,14 +3055,14 @@ amdsmi_status_t amdsmi_get_gpu_metrics_info(amdsmi_processor_handle processor_ha
* @param[inout] num_of_metrics a pointer to uint32_t to which the number of
* metrics is allocated for pm_metrics array as input, and the number of metrics retreived
* as output. If this parameter is NULL, this function will return
* ::AMDSMI_STATUS_INVALID_ARGS if the function is supported with the provided,
* ::AMDSMI_STATUS_INVAL if the function is supported with the provided,
* arguments and ::AMDSMI_STATUS_NOT_SUPPORTED if it is not supported with the
* provided arguments.
*
* @retval ::AMDSMI_STATUS_SUCCESS call was successful
* @retval ::AMDSMI_STATUS_NOT_SUPPORTED installed software or hardware does not
* support this function with the given arguments
* @retval ::AMDSMI_STATUS_INVALID_ARGS the provided arguments are not valid
* @retval ::AMDSMI_STATUS_INVAL the provided arguments are not valid
*
*/
amdsmi_status_t amdsmi_get_gpu_pm_metrics_info(
@@ -3092,14 +3093,14 @@ amdsmi_status_t amdsmi_get_gpu_pm_metrics_info(
* @param[inout] num_of_metrics a pointer to uint32_t to which the number of
* metrics is allocated for reg_metrics array as input, and the number of metrics retreived
* as output. If this parameter is NULL, this function will return
* ::AMDSMI_STATUS_INVALID_ARGS if the function is supported with the provided,
* ::AMDSMI_STATUS_INVAL if the function is supported with the provided,
* arguments and ::AMDSMI_STATUS_NOT_SUPPORTED if it is not supported with the
* provided arguments.
*
* @retval ::AMDSMI_STATUS_SUCCESS call was successful
* @retval ::AMDSMI_STATUS_NOT_SUPPORTED installed software or hardware does not
* support this function with the given arguments
* @retval ::AMDSMI_STATUS_INVALID_ARGS the provided arguments are not valid
* @retval ::AMDSMI_STATUS_INVAL the provided arguments are not valid
*
*/
amdsmi_status_t amdsmi_get_gpu_reg_table_info(
@@ -3504,7 +3505,7 @@ amdsmi_status_t amdsmi_set_gpu_process_isolation(amdsmi_processor_handle process
* @platform{gpu_bm_linux} @platform{guest_1vf}
*
* @details Given a processor handle @p processor_handle, and a sclean flag @p sclean,
* this function will clear the SRAM data of this processor. This can be called between
* this function will clear the SRAM data of this processor. This can be called between
* user logins to prevent information leak.
*
* @note This function requires root access
@@ -4222,7 +4223,7 @@ amdsmi_is_P2P_accessible(amdsmi_processor_handle processor_handle_src,
* , suggested length is 4 or greater.
*
* @retval ::AMDSMI_STATUS_SUCCESS call was successful
* @retval ::AMDSMI_STATUS_INVALID_ARGS the provided arguments are not valid
* @retval ::AMDSMI_STATUS_INVAL the provided arguments are not valid
* @retval ::AMDSMI_STATUS_UNEXPECTED_DATA data provided to function is not valid
* @retval ::AMDSMI_STATUS_NOT_SUPPORTED installed software or hardware does not
* support this function
@@ -4252,7 +4253,7 @@ amdsmi_get_gpu_compute_partition(amdsmi_processor_handle processor_handle,
*
* @retval ::AMDSMI_STATUS_SUCCESS call was successful
* @retval ::AMDSMI_STATUS_PERMISSION function requires root access
* @retval ::AMDSMI_STATUS_INVALID_ARGS the provided arguments are not valid
* @retval ::AMDSMI_STATUS_INVAL the provided arguments are not valid
* @retval ::AMDSMI_STATUS_SETTING_UNAVAILABLE the provided setting is
* unavailable for current device
* @retval ::AMDSMI_STATUS_NOT_SUPPORTED installed software or hardware does not
@@ -4312,7 +4313,7 @@ amdsmi_status_t amdsmi_reset_gpu_compute_partition(amdsmi_processor_handle proce
* suggested length is 5 or greater.
*
* @retval ::AMDSMI_STATUS_SUCCESS call was successful
* @retval ::AMDSMI_STATUS_INVALID_ARGS the provided arguments are not valid
* @retval ::AMDSMI_STATUS_INVAL the provided arguments are not valid
* @retval ::AMDSMI_STATUS_UNEXPECTED_DATA data provided to function is not valid
* @retval ::AMDSMI_STATUS_NOT_SUPPORTED installed software or hardware does not
* support this function
@@ -4341,7 +4342,7 @@ amdsmi_get_gpu_memory_partition(amdsmi_processor_handle processor_handle,
*
* @retval ::AMDSMI_STATUS_SUCCESS call was successful
* @retval ::AMDSMI_STATUS_PERMISSION function requires root access
* @retval ::AMDSMI_STATUS_INVALID_ARGS the provided arguments are not valid
* @retval ::AMDSMI_STATUS_INVAL the provided arguments are not valid
* @retval ::AMDSMI_STATUS_NOT_SUPPORTED installed software or hardware does not
* support this function
* @retval ::AMDSMI_STATUS_AMDGPU_RESTART_ERR could not successfully restart
+15 -14
View File
@@ -1224,7 +1224,7 @@ try:
print("No GPUs on machine")
else:
for device in devices:
amdsmi_set_gpu_pci_bandwidth(device, 0)
amdsmi_set_gpu_pci_bandwidth(device, 0)
except AmdSmiException as e:
print(e)
```
@@ -1620,7 +1620,7 @@ try:
print("No GPUs on machine")
else:
for device in devices:
amdsmi_set_gpu_od_clk_info(
amdsmi_set_gpu_od_clk_info(
device,
AmdSmiFreqInd.AMDSMI_FREQ_IND_MAX,
1000,
@@ -1691,7 +1691,7 @@ try:
print("No GPUs on machine")
else:
for device in devices:
amdsmi_set_gpu_od_volt_info(device, 1, 1000, 980)
amdsmi_set_gpu_od_volt_info(device, 1, 1000, 980)
except AmdSmiException as e:
print(e)
```
@@ -2168,15 +2168,16 @@ try:
print("No GPUs on machine")
else:
for device in devices:
amdsmi_get_clk_freq(device, AmdSmiClkType.SYS)
amdsmi_get_clk_freq(device, AmdSmiClkType.SYS)
except AmdSmiException as e:
print(e)
```
### amdsmi_get_gpu_od_volt_info
Description: This function retrieves the voltage/frequency curve information
It is not supported on virtual machine guest
Description: This function retrieves the voltage/frequency curve information.
If the num_regions is 0 then the voltage curve is not supported.
It is not supported on virtual machine guest.
Input parameters:
@@ -2190,8 +2191,8 @@ Field | Description
`curr_mclk_range` | <table> <thead><tr><th> Subfield </th><th>Description</th></tr></thead><tbody><tr><td>`lower_bound`</td><td>lower bound mclk range</td></tr><tr><td>`upper_bound`</td><td>upper bound mclk range</td></tr></tbody></table>
`sclk_freq_limits` | <table> <thead><tr><th> Subfield </th><th>Description</th></tr></thead><tbody><tr><td>`lower_bound`</td><td>lower bound sclk range limt</td></tr><tr><td>`upper_bound`</td><td>upper bound sclk range limit</td></tr></tbody></table>
`mclk_freq_limits` | <table> <thead><tr><th> Subfield </th><th>Description</th></tr></thead><tbody><tr><td>`lower_bound`</td><td>lower bound mclk range limit</td></tr><tr><td>`upper_bound`</td><td>upper bound mclk range limit</td></tr></tbody></table>
`curve.vc_points` | The number of supported frequencies
`num_regions` | The current frequency index
`curve.vc_points` | List of voltage curve points
`num_regions` | The number of voltage curve regions
Exceptions that can be thrown by `amdsmi_get_gpu_od_volt_info` function:
@@ -2208,7 +2209,7 @@ try:
print("No GPUs on machine")
else:
for device in devices:
amdsmi_get_gpu_od_volt_info(dev)
amdsmi_get_gpu_od_volt_info(dev)
except AmdSmiException as e:
print(e)
```
@@ -2300,7 +2301,7 @@ try:
print("No GPUs on machine")
else:
for device in devices:
amdsmi_get_gpu_metrics_info(dev)
amdsmi_get_gpu_metrics_info(dev)
except AmdSmiException as e:
print(e)
```
@@ -2337,7 +2338,7 @@ try:
print("No GPUs on machine")
else:
for device in devices:
amdsmi_get_gpu_od_volt_curve_regions(device, 3)
amdsmi_get_gpu_od_volt_curve_regions(device, 3)
except AmdSmiException as e:
print(e)
```
@@ -2375,7 +2376,7 @@ try:
print("No GPUs on machine")
else:
for device in devices:
amdsmi_get_gpu_power_profile_presets(device, 0)
amdsmi_get_gpu_power_profile_presets(device, 0)
except AmdSmiException as e:
print(e)
```
@@ -2604,7 +2605,7 @@ try:
print("No GPUs on machine")
else:
for device in devices:
amdsmi_set_gpu_perf_level(device, AmdSmiDevPerfLevel.STABLE_PEAK)
amdsmi_set_gpu_perf_level(device, AmdSmiDevPerfLevel.STABLE_PEAK)
except AmdSmiException as e:
print(e)
```
@@ -2907,7 +2908,7 @@ try:
print("No GPUs on machine")
else:
for device in devices:
amdsmi_set_gpu_overdrive_level(device, 0)
amdsmi_set_gpu_overdrive_level(device, 0)
except AmdSmiException as e:
print(e)
```
@@ -39,6 +39,37 @@ AMDSMI_MAX_NUM_VCN = 4
AMDSMI_MAX_NUM_CLKS = 4
AMDSMI_MAX_NUM_XGMI_LINKS = 8
AMDSMI_MAX_NUM_GFX_CLKS = 8
AMDSMI_MAX_AID = 4
AMDSMI_MAX_ENGINES = 8
AMDSMI_MAX_NUM_JPEG = 32
# Max number of DPM policies
AMDSMI_MAX_NUM_PM_POLICIES = 32
# Max supported frequencies
AMDSMI_MAX_NUM_FREQUENCIES = 33
# Max Fan speed
AMDSMI_MAX_FAN_SPEED = 255
# Max Votlage Curve Points
AMDSMI_NUM_VOLTAGE_CURVE_POINTS = 3
# Max size definitions
AMDSMI_MAX_MM_IP_COUNT = 8
AMDSMI_MAX_DATE_LENGTH = 32
AMDSMI_MAX_STRING_LENGTH = 64
AMDSMI_NORMAL_STRING_LENGTH = 32
AMDSMI_MAX_DEVICES = 32
AMDSMI_MAX_NAME = 32
AMDSMI_MAX_DRIVER_VERSION_LENGTH = 80
AMDSMI_256_LENGTH = 256
AMDSMI_MAX_CONTAINER_TYPE = 2
AMDSMI_MAX_CACHE_TYPES = 10
AMDSMI_MAX_NUM_XGMI_PHYSICAL_LINK = 64
AMDSMI_GPU_UUID_SIZE = 38
MAX_AMDSMI_NAME_LENGTH = 64
MAX_EVENT_NOTIFICATION_MSG_SIZE = 64
class AmdSmiInitFlags(IntEnum):
@@ -224,7 +255,6 @@ class AmdSmiEvtNotificationType(IntEnum):
GPU_POST_RESET = amdsmi_wrapper.AMDSMI_EVT_NOTIF_GPU_POST_RESET
RING_HANG = amdsmi_wrapper.AMDSMI_EVT_NOTIF_RING_HANG
class AmdSmiTemperatureMetric(IntEnum):
CURRENT = amdsmi_wrapper.AMDSMI_TEMP_CURRENT
MAX = amdsmi_wrapper.AMDSMI_TEMP_MAX
@@ -539,6 +569,21 @@ def _make_amdsmi_bdf_from_list(bdf):
amdsmi_bdf.fields.domain_number = bdf[0]
return amdsmi_bdf
def _padHexValue(value, length):
""" Pad a hexadecimal value with a given length of zeros
:param value: A hexadecimal value to be padded with zeros
:param length: Number of zeros to pad the hexadecimal value
:param return original string string or
padded hex of confirmed hex output (using length provided)
"""
# Ensure value entered meets the minimum length and is hexadecimal
if len(value) > 2 and length > 1 and value[:2].lower() == '0x' \
and all(c in '0123456789abcdefABCDEF' for c in value[2:]):
# Pad with zeros after '0x' prefix
return '0x' + value[2:].zfill(length)
return value
def amdsmi_get_socket_handles() -> List[amdsmi_wrapper.amdsmi_socket_handle]:
"""
@@ -1585,12 +1630,12 @@ def amdsmi_get_gpu_asic_info(
)
asic_info = {
"market_name": asic_info_struct.market_name.decode("utf-8"),
"market_name": _padHexValue(asic_info_struct.market_name.decode("utf-8"), 4),
"vendor_id": asic_info_struct.vendor_id,
"vendor_name": asic_info_struct.vendor_name.decode("utf-8"),
"subvendor_id": asic_info_struct.subvendor_id,
"device_id": asic_info_struct.device_id,
"rev_id": hex(asic_info_struct.rev_id),
"rev_id": _padHexValue(hex(asic_info_struct.rev_id), 2),
"asic_serial": asic_info_struct.asic_serial.decode("utf-8"),
"oam_id": asic_info_struct.oam_id
}
@@ -1863,17 +1908,16 @@ def amdsmi_get_gpu_board_info(
)
board_info_dict = {
"model_number": board_info.model_number.decode("utf-8").strip(),
"model_number": _padHexValue(board_info.model_number.decode("utf-8").strip(), 4),
"product_serial": board_info.product_serial.decode("utf-8").strip(),
"fru_id": board_info.fru_id.decode("utf-8").strip(),
"product_name": board_info.product_name.decode("utf-8").strip(),
"product_name": _padHexValue(board_info.product_name.decode("utf-8").strip(), 4),
"manufacturer_name": board_info.manufacturer_name.decode("utf-8").strip()
}
for key, value in board_info_dict.items():
if value == "":
board_info_dict[key] = "N/A"
return board_info_dict
@@ -882,7 +882,7 @@ class struct_amdsmi_asic_info_t(Structure):
struct_amdsmi_asic_info_t._pack_ = 1 # source:False
struct_amdsmi_asic_info_t._fields_ = [
('market_name', ctypes.c_char * 64),
('market_name', ctypes.c_char * 256),
('vendor_id', ctypes.c_uint32),
('vendor_name', ctypes.c_char * 64),
('subvendor_id', ctypes.c_uint32),
@@ -961,11 +961,11 @@ class struct_amdsmi_board_info_t(Structure):
struct_amdsmi_board_info_t._pack_ = 1 # source:False
struct_amdsmi_board_info_t._fields_ = [
('model_number', ctypes.c_char * 32),
('model_number', ctypes.c_char * 256),
('product_serial', ctypes.c_char * 32),
('fru_id', ctypes.c_char * 32),
('product_name', ctypes.c_char * 128),
('manufacturer_name', ctypes.c_char * 32),
('product_name', ctypes.c_char * 256),
('manufacturer_name', ctypes.c_char * 64),
('reserved', ctypes.c_uint32 * 32),
]
@@ -3451,8 +3451,7 @@ rsmi_status_t rsmi_dev_process_isolation_set(uint32_t dv_ind,
uint32_t pisolate);
/**
* @brief Clear the GPU SRAM data
*
* @brief Clear the GPU SRAM data
*
* @details Given a device index @p dv_ind, this function will clear the
* GPU SRAM data of this device. This can be called between user logins to prevent information leak.
@@ -45,14 +45,17 @@
#include <pthread.h>
#include <string>
#include <algorithm>
#include <cstdint>
#include <vector>
#include <sstream>
#include <iomanip>
#include <type_traits>
#include <tuple>
#include <iostream>
#include <limits>
#include <queue>
#include <sstream>
#include <string>
#include <tuple>
#include <type_traits>
#include <vector>
#include "rocm_smi/rocm_smi_device.h"
@@ -125,13 +128,33 @@ std::string print_rsmi_od_volt_freq_regions(uint32_t num_regions,
bool is_sudo_user();
rsmi_status_t rsmi_get_gfx_target_version(uint32_t dv_ind,
std::string *gfx_version);
std::string leftTrim(const std::string &s);
std::string rightTrim(const std::string &s);
std::string trim(const std::string &s);
std::string removeNewLines(const std::string &s);
std::string removeString(const std::string origStr,
const std::string &removeMe);
template <typename T>
std::string print_int_as_hex(T i, bool showHexNotation = true) {
std::string print_int_as_hex(T i, bool showHexNotation = true,
int overloadBitSize = 0) {
std::stringstream ss;
if (showHexNotation) {
ss << "0x" << std::setfill('0') << std::setw(sizeof(T) * 2) << std::hex;
if (overloadBitSize == 0) {
ss << "0x" << std::hex << std::setw(sizeof(T) * 2) << std::setfill('0');
} else {
// 8 bits per 1 byte
int byteSize = (overloadBitSize / 8) * 2;
ss << "0x" << std::hex << std::setw(byteSize) << std::setfill('0');
}
} else {
ss << std::setfill('0') << std::setw(sizeof(T) * 2) << std::hex;
if (overloadBitSize == 0) {
ss << std::hex << std::setw(sizeof(T) * 2) << std::setfill('0');
} else {
int byteSize = (overloadBitSize / 8) * 2;
ss << std::hex << std::setw(byteSize) << std::setfill('0');
}
}
if (std::is_same<std::uint8_t, T>::value) {
@@ -162,7 +185,8 @@ std::string print_unsigned_hex_and_int(T i, std::string heading="") {
}
ss << "Hex (MSB): " << print_int_as_hex(i) << ", "
<< "Unsigned int: " << print_unsigned_int(i) << ", "
<< "Byte Size: " << sizeof(T);
<< "Byte Size: " << sizeof(T) << ", "
<< "Bits: " << sizeof(T) * 8; // 8 bits per 1 byte
return ss.str();
}
@@ -283,8 +307,298 @@ class ScopedAcquire {
// In VM environment, the /proc/cpuinfo set hypervisor flag by default
bool is_vm_guest();
// trim a string
std::string trim(const std::string &s);
//
enum class TagSplitterPositional_t
{
kFIRST,
kBETWEEN,
kLAST,
kNONE,
};
template <typename PrimaryKeyType = std::string, typename PrimaryDataType = std::string,
typename SecondaryKeyType = PrimaryKeyType, typename SecondaryDataType = PrimaryDataType>
class TagTextContents_t
{
public:
using TextLines_t = std::vector<std::string>;
using PrimaryList_t = std::vector<PrimaryDataType>;
using SecondaryList_t = std::vector<SecondaryDataType>;
using PrimaryKeyTbl_t = std::map<PrimaryKeyType, PrimaryList_t>;
using SecondaryKeyTbl_t = std::map<SecondaryKeyType, SecondaryList_t>;
using StructuredKeysTbl_t = std::map<PrimaryDataType, std::map<SecondaryKeyType, SecondaryDataType>>;
//
TagTextContents_t() = default;
TagTextContents_t(const TagTextContents_t&) = delete;
TagTextContents_t(TagTextContents_t&&) = delete;
TagTextContents_t& operator=(const TagTextContents_t&) = delete;
TagTextContents_t& operator=(TagTextContents_t&&) = delete;
explicit TagTextContents_t(const TextLines_t& text_content)
: m_text_content(text_content) {}
TagTextContents_t& set_text_content(const TextLines_t& text_content)
{
m_text_content = text_content;
}
TagTextContents_t& set_title_terminator(const std::string& title_mark,
TagSplitterPositional_t title_mark_position) {
m_title_mark = title_mark;
m_title_mark_position = title_mark_position;
return *this;
}
TagTextContents_t& set_key_data_splitter(const std::string& line_splitter_mark,
TagSplitterPositional_t line_mark_position) {
m_line_splitter_mark = line_splitter_mark;
m_line_mark_position = line_mark_position;
return *this;
}
TagTextContents_t& structure_content() {
// Sanitizes the content.
if (!m_text_content.empty()) {
std::for_each(m_text_content.begin(), m_text_content.end(), trim);
section_title_lookup();
section_data_lookup();
}
return *this;
}
decltype(auto) get_title_size() {
return m_primary.size();
}
decltype(auto) get_structured_subkeys_size(const PrimaryKeyType& prim_key) {
return m_structured[prim_key].size();
}
decltype(auto) contains_title_key(const PrimaryKeyType& key) {
return (m_primary.find(key) != m_primary.end());
}
decltype(auto) contains_structured_key(const PrimaryKeyType& prim_key,
const SecondaryKeyType& sec_key) {
if (auto first_key_itr = m_structured.find(prim_key);
first_key_itr != m_structured.end()) {
if (auto sec_key_itr = first_key_itr->second.find(sec_key);
sec_key_itr != first_key_itr->second.end()) {
return true;
}
}
return false;
}
decltype(auto) get_structured_value_by_keys(const PrimaryKeyType& prim_key,
const SecondaryKeyType& sec_key,
bool is_value_id = true) {
if (auto first_key_itr = m_structured.find(prim_key);
first_key_itr != m_structured.end()) {
if (auto sec_key_itr = first_key_itr->second.find(sec_key);
sec_key_itr != first_key_itr->second.end()) {
SecondaryDataType key_value{};
if (is_value_id) {
key_value = SecondaryDataType(sec_key_itr->first) + " ";
}
key_value += sec_key_itr->second;
return key_value;
}
}
return SecondaryDataType{};
}
decltype(auto) get_structured_data_subkey_by_position(const PrimaryKeyType& prim_key,
uint32_t key_position) {
auto key_counter = uint32_t(0);
SecondaryKeyType data_key{};
if (key_position < (get_structured_subkeys_size(prim_key))) {
for (const auto& [sec_key, sec_value] : m_structured[prim_key]) {
if (key_counter == key_position) {
data_key = static_cast<SecondaryKeyType>(sec_key);
return data_key;
}
++key_counter;
}
}
return data_key;
}
decltype(auto) get_structured_data_subkey_first(const PrimaryKeyType& prim_key) {
return (get_structured_value_by_keys(prim_key,
get_structured_data_subkey_by_position(prim_key, 0)));
}
decltype(auto) get_structured_data_subkey_last(const PrimaryKeyType& prim_key) {
return (get_structured_value_by_keys(prim_key, get_structured_data_subkey_by_position(prim_key,
(get_structured_subkeys_size(prim_key) - 1))));
}
void reset() {
m_text_content.clear();
m_primary.clear();
m_structured.clear();
m_title_mark.clear();
m_line_splitter_mark.clear();
m_title_mark_position = TagSplitterPositional_t::kNONE;
m_line_mark_position = TagSplitterPositional_t::kNONE;
}
decltype(auto) dump_structured_content() {
std::ostringstream ostrstream;
ostrstream << __PRETTY_FUNCTION__ << "| ======= start =======" << "\n";
ostrstream << "** Primary Table **" << "\n";
for (const auto& [key, values] : m_primary) {
ostrstream << "key: " << key << " values: " << values.size() << "\n";
for (const auto& value : values) {
ostrstream << "\t value: " << value << "\n";
}
}
ostrstream << "\n ** Structured Table **" << "\n";
for (const auto& [prim_key, prim_values] : m_structured) {
ostrstream << "key: " << prim_key << "\n";
for (const auto& [sec_key, sec_value] : prim_values) {
ostrstream << "\t key: " << sec_key << " -> " << sec_value << "\n";
}
}
ostrstream << "\n\n";
return ostrstream.str();
}
private:
TextLines_t m_text_content;
PrimaryKeyTbl_t m_primary;
StructuredKeysTbl_t m_structured;
std::string m_title_mark;
std::string m_line_splitter_mark;
TagSplitterPositional_t m_title_mark_position;
TagSplitterPositional_t m_line_mark_position;
//
// Note: Organizes table with Title as a Key, and a list of values.
//
decltype(auto) section_title_lookup() {
if (m_title_mark.empty() ||
m_title_mark_position == TagSplitterPositional_t::kNONE) {
return;
}
//
// Note:
// - top_title_line: Left pointer for the sliding window
// - bottom_title_line: Right pointer for the sliding window
//
auto top_title_line = uint32_t(std::numeric_limits<uint32_t>::max());
auto bottom_title_line = uint32_t(std::numeric_limits<uint32_t>::max());
auto line_counter = uint32_t(0);
//
// Note: This whole interval/window where the section/title starts, and where it ends.
//
auto update_primary_tbl = [&](const uint32_t& from_line, const uint32_t& to_line) {
auto key = static_cast<PrimaryKeyType>(m_text_content[from_line]);
for (auto line_num(from_line + 1); line_num < to_line; ++line_num) {
if ((line_num < m_text_content.size()) && !m_text_content[line_num].empty()) {
m_primary[key].push_back(m_text_content[line_num]);
}
}
};
auto adjust_sliding_window = [&](const uint32_t& title_line) {
// First time top_title_line gets adjusted.
if (top_title_line == uint32_t(std::numeric_limits<uint32_t>::max())) {
top_title_line = title_line;
bottom_title_line = top_title_line;
return;
}
if (title_line > bottom_title_line) {
bottom_title_line = title_line;
update_primary_tbl(top_title_line, bottom_title_line);
top_title_line = bottom_title_line;
}
};
for (const auto& line : m_text_content) {
auto was_title_found{false};
switch (m_title_mark_position) {
case TagSplitterPositional_t::kFIRST:
// Section/Title Mark was found at the first position
if (line.find_first_of(m_title_mark.c_str()) == 0) {
was_title_found = true;
}
break;
case TagSplitterPositional_t::kLAST:
// Section/Title Mark was found at the last position
if ((line.find_last_of(m_title_mark.c_str()) + 1) == line.size()) {
was_title_found = true;
}
break;
default:
break;
}
if (was_title_found) {
adjust_sliding_window(line_counter);
}
++line_counter;
}
// Any remaining elements? If so, the data belongs to the last found section title
if (line_counter > bottom_title_line) {
update_primary_tbl(bottom_title_line, line_counter);
}
}
decltype(auto) section_data_lookup() {
if (m_line_splitter_mark.empty() ||
m_line_mark_position == TagSplitterPositional_t::kNONE) {
return;
}
//
// Note: Organizes table with Title as a Key, a Key/ID for values and values.
// It takes into consideration the initial constraints were all good and
// that the primary table has been populated.
auto sec_key = std::string();
auto sec_data = std::string();
auto auto_key = uint32_t(0);
for (const auto& [prim_key, prim_values] : m_primary) {
for (const auto& value : prim_values) {
if (auto mark_pos = value.find_first_of(m_line_splitter_mark.c_str());
mark_pos != std::string::npos) {
sec_key = trim(value.substr(0, mark_pos + 1));
sec_data = trim(value.substr((mark_pos + 1), value.size()));
}
// In case there is no 'key' based on the data token marker, generate one.
else {
sec_key = std::to_string(auto_key) + m_line_splitter_mark;
sec_data = trim(value.substr(0, value.size()));
++auto_key;
}
if (!sec_key.empty()) {
m_structured[prim_key].insert(std::make_pair(sec_key, sec_data));
}
}
}
}
};
using TextFileTagContents_t = TagTextContents_t<std::string, std::string,
std::string, std::string>;
} // namespace smi
} // namespace amd
+114 -85
View File
@@ -1415,17 +1415,6 @@ For the new format, GFXCLK field will show min and max values(0/1). If the curre
frequency in neither min/max but lies within the range, this is indicated by
an additional value followed by * at index 1 and max value at index 2.
*/
constexpr uint32_t kOD_SCLK_label_array_index = 0;
constexpr uint32_t kOD_MCLK_label_array_index =
kOD_SCLK_label_array_index + 3;
constexpr uint32_t kOD_VDDC_CURVE_label_array_index =
kOD_MCLK_label_array_index + 2;
constexpr uint32_t kOD_OD_RANGE_label_array_index =
kOD_VDDC_CURVE_label_array_index + 4;
constexpr uint32_t kOD_VDDC_CURVE_start_index =
kOD_OD_RANGE_label_array_index + 3;
// constexpr uint32_t kOD_VDDC_CURVE_num_lines =
// kOD_VDDC_CURVE_start_index + 4;
constexpr uint32_t kMIN_VALID_LINES = 2;
static rsmi_status_t get_od_clk_volt_info(uint32_t dv_ind,
@@ -1450,62 +1439,95 @@ static rsmi_status_t get_od_clk_volt_info(uint32_t dv_ind,
return RSMI_STATUS_NOT_YET_IMPLEMENTED;
}
assert(val_vec[kOD_SCLK_label_array_index] == "OD_SCLK:" ||
val_vec[kOD_SCLK_label_array_index] == "GFXCLK:");
if ((val_vec[kOD_SCLK_label_array_index] != "OD_SCLK:") &&
(val_vec[kOD_SCLK_label_array_index] != "GFXCLK:")) {
return RSMI_STATUS_UNEXPECTED_DATA;
// Tags expected in this file
const std::string kTAG_OD_SCLK{"OD_SCLK:"};
const std::string KTAG_OD_MCLK{"OD_MCLK:"};
const std::string kTAG_GFXCLK{"GFXCLK:"};
const std::string KTAG_MCLK{"MCLK:"};
const std::string KTAG_SCLK{"SCLK:"};
const std::string KTAG_OD_RANGE{"OD_RANGE:"};
const std::string KTAG_OD_VDDGFX_OFFSET{"OD_VDDGFX_OFFSET:"};
const std::string KTAG_FIRST_FREQ_IDX{"0:"};
amd::smi::TextFileTagContents_t txt_power_dev_od_voltage(val_vec);
txt_power_dev_od_voltage
.set_title_terminator(":", amd::smi::TagSplitterPositional_t::kLAST)
.set_key_data_splitter(":", amd::smi::TagSplitterPositional_t::kBETWEEN)
.structure_content();
//
// Note: We must have minimum of 'GFXCLK:' && 'MCLK:' OR:
// 'OD_SCLK:' && 'OD_MCLK:' tags.
if (txt_power_dev_od_voltage.get_title_size() < kMIN_VALID_LINES) {
return rsmi_status_t::RSMI_STATUS_NO_DATA;
}
// find last_item but skip empty lines
int last_item = val_vec.size()-1;
while (val_vec[last_item].empty() || val_vec[last_item][0] == 0)
last_item--;
p->curr_sclk_range.lower_bound = freq_string_to_int(val_vec, nullptr,
nullptr, kOD_SCLK_label_array_index + 1);
p->curr_sclk_range.upper_bound = freq_string_to_int(val_vec, nullptr,
nullptr, kOD_SCLK_label_array_index + 2);
if (val_vec.size() < (kOD_MCLK_label_array_index + 1)) {
return RSMI_STATUS_UNEXPECTED_SIZE;
}
// The condition below checks if it is the old style or new style format.
if (val_vec[kOD_MCLK_label_array_index] == "OD_MCLK:") {
p->curr_mclk_range.lower_bound = 0;
p->curr_mclk_range.upper_bound = freq_string_to_int(val_vec, nullptr,
nullptr, kOD_MCLK_label_array_index + 1);
} else if (val_vec[kOD_MCLK_label_array_index] == "MCLK:") {
p->curr_mclk_range.lower_bound = freq_string_to_int(val_vec, nullptr,
nullptr, kOD_MCLK_label_array_index + 1);
// the upper memory frequency is the last
p->curr_mclk_range.upper_bound = freq_string_to_int(val_vec, nullptr,
nullptr, last_item);
return RSMI_STATUS_SUCCESS;
} else {
if (val_vec.size() < (kOD_MCLK_label_array_index + 3)) {
return RSMI_STATUS_UNEXPECTED_SIZE;
}
if (val_vec[kOD_MCLK_label_array_index + 1] == "MCLK:") {
p->curr_sclk_range.upper_bound = freq_string_to_int(val_vec, nullptr,
nullptr, kOD_SCLK_label_array_index + 3);
p->curr_mclk_range.lower_bound = freq_string_to_int(val_vec, nullptr,
nullptr, kOD_MCLK_label_array_index + 2);
// the upper memory frequency is the last
p->curr_mclk_range.upper_bound = freq_string_to_int(val_vec, nullptr,
nullptr, last_item);
return RSMI_STATUS_SUCCESS;
}
return RSMI_STATUS_NOT_YET_IMPLEMENTED;
// Note: For debug builds/purposes only.
assert(txt_power_dev_od_voltage.contains_title_key(kTAG_GFXCLK) ||
txt_power_dev_od_voltage.contains_title_key(kTAG_OD_SCLK));
// Note: For release builds/purposes.
if (!txt_power_dev_od_voltage.contains_title_key(kTAG_GFXCLK) &&
!txt_power_dev_od_voltage.contains_title_key(kTAG_OD_SCLK)) {
return rsmi_status_t::RSMI_STATUS_UNEXPECTED_DATA;
}
if (val_vec.size() < kOD_VDDC_CURVE_label_array_index) {
return RSMI_STATUS_UNEXPECTED_SIZE;
// Note: Quick helpers for getting 1st and last elements found
auto build_lower_bound = [&](const std::string& prim_key) {
auto lower_bound_data = txt_power_dev_od_voltage.get_structured_data_subkey_first(prim_key);
return std::vector<std::string>{lower_bound_data};
};
auto build_upper_bound = [&](const std::string& prim_key) {
auto upper_bound_data = txt_power_dev_od_voltage.get_structured_data_subkey_last(prim_key);
return std::vector<std::string>{upper_bound_data};
};
// Validates 'OD_SCLK' is in the structure
if (txt_power_dev_od_voltage.contains_structured_key(kTAG_OD_SCLK,
KTAG_FIRST_FREQ_IDX)) {
p->curr_sclk_range.lower_bound = freq_string_to_int(build_lower_bound(kTAG_OD_SCLK), nullptr, nullptr, 0);
p->curr_sclk_range.upper_bound = freq_string_to_int(build_upper_bound(kTAG_OD_SCLK), nullptr, nullptr, 0);
// Validates 'OD_MCLK' is in the structure
if (txt_power_dev_od_voltage.contains_structured_key(KTAG_OD_MCLK,
KTAG_FIRST_FREQ_IDX)) {
p->curr_mclk_range.lower_bound = freq_string_to_int(build_lower_bound(KTAG_OD_MCLK), nullptr, nullptr, 0);
p->curr_mclk_range.upper_bound = freq_string_to_int(build_upper_bound(KTAG_OD_MCLK), nullptr, nullptr, 0);
}
// Validates 'OD_RANGE' is in the structure
if (txt_power_dev_od_voltage.contains_structured_key(KTAG_OD_RANGE,
KTAG_SCLK)) {
od_value_pair_str_to_range(txt_power_dev_od_voltage
.get_structured_value_by_keys(KTAG_OD_RANGE, KTAG_SCLK),
&p->sclk_freq_limits);
}
if (txt_power_dev_od_voltage.contains_structured_key(KTAG_OD_RANGE,
KTAG_MCLK)) {
od_value_pair_str_to_range(txt_power_dev_od_voltage
.get_structured_value_by_keys(KTAG_OD_RANGE, KTAG_MCLK),
&p->mclk_freq_limits);
}
}
// Validates 'GFXCLK' is in the structure
else if (txt_power_dev_od_voltage.contains_structured_key(kTAG_GFXCLK,
KTAG_FIRST_FREQ_IDX)) {
p->curr_sclk_range.lower_bound = freq_string_to_int(build_lower_bound(kTAG_GFXCLK), nullptr, nullptr, 0);
p->curr_sclk_range.upper_bound = freq_string_to_int(build_upper_bound(kTAG_GFXCLK), nullptr, nullptr, 0);
// Validates 'MCLK' is in the structure
if (txt_power_dev_od_voltage.contains_structured_key(KTAG_MCLK,
KTAG_FIRST_FREQ_IDX)) {
p->curr_mclk_range.lower_bound = freq_string_to_int(build_lower_bound(KTAG_MCLK), nullptr, nullptr, 0);
p->curr_mclk_range.upper_bound = freq_string_to_int(build_upper_bound(KTAG_MCLK), nullptr, nullptr, 0);
}
}
else {
return RSMI_STATUS_NOT_YET_IMPLEMENTED;
}
p->num_regions =
static_cast<uint32_t>((val_vec.size()) / 2);
// Note: No curve entries.
p->num_regions = 0;
return RSMI_STATUS_SUCCESS;
CATCH
@@ -1674,28 +1696,34 @@ rsmi_status_t rsmi_dev_od_volt_info_set(uint32_t dv_ind, uint32_t vpoint,
}
static void get_vc_region(uint32_t start_ind,
std::vector<std::string> *val_vec, rsmi_freq_volt_region_t *p) {
static void get_vc_region(const std::vector<std::string>& val_vec, rsmi_freq_volt_region_t& p)
{
std::ostringstream ss;
ss << __PRETTY_FUNCTION__ << " | ======= start =======";
LOG_TRACE(ss);
assert(p != nullptr);
assert(val_vec != nullptr);
THROW_IF_NULLPTR_DEREF(p)
THROW_IF_NULLPTR_DEREF(val_vec)
// There must be at least 1 region to read in
assert(val_vec->size() >= kOD_OD_RANGE_label_array_index + 2);
assert((*val_vec)[kOD_OD_RANGE_label_array_index] == "OD_RANGE:");
if ((val_vec->size() < kOD_OD_RANGE_label_array_index + 2) ||
((*val_vec)[kOD_OD_RANGE_label_array_index] != "OD_RANGE:") ) {
ss << __PRETTY_FUNCTION__ << " | ======= end ======= | returning "
<< getRSMIStatusString(RSMI_STATUS_UNEXPECTED_DATA);
LOG_TRACE(ss);
throw amd::smi::rsmi_exception(RSMI_STATUS_UNEXPECTED_DATA, __FUNCTION__);
//
amd::smi::TextFileTagContents_t txt_power_dev_od_voltage(val_vec);
txt_power_dev_od_voltage
.set_title_terminator(":", amd::smi::TagSplitterPositional_t::kLAST)
.set_key_data_splitter(":", amd::smi::TagSplitterPositional_t::kBETWEEN)
.structure_content();
const std::string KTAG_OD_RANGE{"OD_RANGE:"};
const std::string KTAG_MCLK{"MCLK:"};
const std::string KTAG_SCLK{"SCLK:"};
if (txt_power_dev_od_voltage.contains_structured_key(KTAG_OD_RANGE,
KTAG_SCLK)) {
od_value_pair_str_to_range(txt_power_dev_od_voltage
.get_structured_value_by_keys(KTAG_OD_RANGE, KTAG_SCLK),
&p.freq_range);
}
if (txt_power_dev_od_voltage.contains_structured_key(KTAG_OD_RANGE,
KTAG_MCLK)) {
od_value_pair_str_to_range(txt_power_dev_od_voltage
.get_structured_value_by_keys(KTAG_OD_RANGE, KTAG_MCLK),
&p.volt_range);
}
od_value_pair_str_to_range((*val_vec)[start_ind], &p->freq_range);
od_value_pair_str_to_range((*val_vec)[start_ind + 1], &p->volt_range);
}
/*
@@ -1729,23 +1757,24 @@ static rsmi_status_t get_od_clk_volt_curve_regions(uint32_t dv_ind,
// This is a work-around to handle systems where kDevPowerODVoltage is not
// fully supported yet.
if (val_vec.size() < 2) {
if (val_vec.size() < kMIN_VALID_LINES) {
ss << __PRETTY_FUNCTION__
<< " | Issue: val_vec.size() < 2" << "; returning "
<< " | Issue: val_vec.size() < " << kMIN_VALID_LINES << "; returning "
<< getRSMIStatusString(RSMI_STATUS_NOT_YET_IMPLEMENTED);
LOG_ERROR(ss);
return RSMI_STATUS_NOT_YET_IMPLEMENTED;
}
uint32_t val_vec_size = static_cast<uint32_t>(val_vec.size());
assert((val_vec_size - kOD_VDDC_CURVE_start_index) > 0);
ss << __PRETTY_FUNCTION__
<< " | val_vec_size = " << std::dec
<< val_vec_size
<< " | kOD_VDDC_CURVE_start_index = " << kOD_VDDC_CURVE_start_index;
<< val_vec_size;
LOG_DEBUG(ss);
*num_regions = std::min((val_vec_size) / 2, *num_regions);
// Note: No curve entries.
*num_regions = 0;
// Get OD ranges.
get_vc_region(val_vec, *p);
return RSMI_STATUS_SUCCESS;
CATCH
@@ -707,6 +707,8 @@ static bool isAMDGPU(std::string dev_path) {
uint32_t RocmSMI::DiscoverAmdgpuDevices(void) {
std::string err_msg;
uint32_t count = 0;
int32_t cardId = 0;
int32_t max_cardId = -1;
std::ostringstream ss;
// If this gets called more than once, clear previous findings.
@@ -730,6 +732,9 @@ uint32_t RocmSMI::DiscoverAmdgpuDevices(void) {
if ((strcmp(dentry->d_name, ".") == 0) ||
(strcmp(dentry->d_name, "..") == 0))
continue;
sscanf(&dentry->d_name[strlen(kDeviceNamePrefix)], "%d", &cardId);
if (cardId > max_cardId)
max_cardId = cardId;
count++;
}
dentry = readdir(drm_dir);
@@ -782,7 +787,7 @@ uint32_t RocmSMI::DiscoverAmdgpuDevices(void) {
uint32_t cardAdded = 0;
// Discover all root cards & gpu partitions associated with each
for (uint32_t cardId = 0; cardId < count; cardId++) {
for (uint32_t cardId = 0; cardId <= max_cardId; cardId++) {
std::string path = kPathDRMRoot;
path += "/card";
path += std::to_string(cardId);
@@ -1140,7 +1140,7 @@ std::string print_rsmi_od_volt_freq_data_t(rsmi_od_volt_freq_data_t *odv) {
&odv->mclk_freq_limits);
ss << "\t**Current Freq/Volt. curve: " << "\n";
ss << pt_vddc_curve(&odv->curve);
ss << "\t\t N/A" << "\n";
ss << "\t**Number of Freq./Volt. regions: " << odv->num_regions << "\n\n";
return ss.str();
@@ -1224,5 +1224,6 @@ std::queue<std::string> getAllDeviceGfxVers() {
return deviceGfxVersions;
}
} // namespace smi
} // namespace amd
+74 -6
View File
@@ -389,7 +389,6 @@ amdsmi_get_gpu_device_bdf(amdsmi_processor_handle processor_handle, amdsmi_bdf_t
}
amdsmi_status_t amdsmi_get_gpu_board_info(amdsmi_processor_handle processor_handle, amdsmi_board_info_t *board_info) {
AMDSMI_CHECK_INIT();
if (board_info == nullptr) {
@@ -405,17 +404,86 @@ amdsmi_status_t amdsmi_get_gpu_board_info(amdsmi_processor_handle processor_hand
if (gpu_device->check_if_drm_is_supported()) {
// Populate product_serial, product_name, & product_number from sysfs
status = smi_amdgpu_get_board_info(gpu_device, board_info);
}
else {
} else {
// ignore the errors so that it can populate as many fields as possible.
// call rocm-smi which search multiple places for device name
status = rsmi_wrapper(rsmi_dev_name_get, processor_handle,
board_info->product_name, AMDSMI_PRODUCT_NAME_LENGTH);
board_info->product_name, AMDSMI_256_LENGTH);
status = rsmi_wrapper(rsmi_dev_serial_number_get, processor_handle,
board_info->product_serial, AMDSMI_NORMAL_STRING_LENGTH);
}
std::ostringstream ss;
ss << __PRETTY_FUNCTION__ << "[Before rocm smi correction] "
<< "Returning status = AMDSMI_STATUS_SUCCESS"
<< "\n; info->model_number: |" << board_info->model_number << "|"
<< "\n; info->product_serial: |" << board_info->product_serial << "|"
<< "\n; info->fru_id: |" << board_info->fru_id << "|"
<< "\n; info->manufacturer_name: |" << board_info->manufacturer_name << "|"
<< "\n; info->product_name: |" << board_info->product_name << "|";
LOG_INFO(ss);
// Correct any missing details
if (board_info->model_number[0] == '\0') {
status = rsmi_wrapper(rsmi_dev_name_get, processor_handle, board_info->model_number,
AMDSMI_256_LENGTH);
if (status != AMDSMI_STATUS_SUCCESS) {
memset(board_info->model_number, 0,
AMDSMI_256_LENGTH * sizeof(board_info->model_number[0]));
}
ss << __PRETTY_FUNCTION__ << " | [rsmi_correction] board_info->model_number= |"
<< board_info->model_number << "|";
LOG_INFO(ss);
}
if (board_info->product_serial[0] == '\0') {
status = rsmi_wrapper(rsmi_dev_serial_number_get, processor_handle,
board_info->product_serial, AMDSMI_NORMAL_STRING_LENGTH);
if (status != AMDSMI_STATUS_SUCCESS) {
memset(board_info->product_serial, 0,
AMDSMI_NORMAL_STRING_LENGTH * sizeof(board_info->product_serial[0]));
}
ss << __PRETTY_FUNCTION__ << " | [rsmi_correction] board_info->product_serial= |"
<< board_info->product_serial << "|";
LOG_INFO(ss);
}
if (board_info->product_name[0] == '\0') {
status = rsmi_wrapper(rsmi_dev_subsystem_name_get,
processor_handle, board_info->product_name,
AMDSMI_256_LENGTH);
if (status != AMDSMI_STATUS_SUCCESS) {
memset(board_info->product_name, 0,
AMDSMI_256_LENGTH * sizeof(board_info->product_name[0]));
}
ss << __PRETTY_FUNCTION__ << " | [rsmi_correction] board_info->product_name= |"
<< board_info->product_name << "|";
LOG_INFO(ss);
}
if (board_info->manufacturer_name[0] == '\0') {
status = rsmi_wrapper(rsmi_dev_vendor_name_get,
processor_handle, board_info->manufacturer_name,
AMDSMI_MAX_STRING_LENGTH);
if (status != AMDSMI_STATUS_SUCCESS) {
memset(board_info->manufacturer_name, 0,
AMDSMI_MAX_STRING_LENGTH * sizeof(board_info->manufacturer_name[0]));
}
ss << __PRETTY_FUNCTION__ << " | [rsmi_correction] board_info->manufacturer_name= |"
<< board_info->manufacturer_name << "|";
LOG_INFO(ss);
}
ss << __PRETTY_FUNCTION__ << "[After rocm smi correction] "
<< "Returning status = AMDSMI_STATUS_SUCCESS"
<< "\n; info->model_number: |" << board_info->model_number << "|"
<< "\n; info->product_serial: |" << board_info->product_serial << "|"
<< "\n; info->fru_id: |" << board_info->fru_id << "|"
<< "\n; info->manufacturer_name: |" << board_info->manufacturer_name << "|"
<< "\n; info->product_name: |" << board_info->product_name << "|";
LOG_INFO(ss);
return AMDSMI_STATUS_SUCCESS;
}
@@ -654,7 +722,7 @@ amdsmi_get_gpu_asic_info(amdsmi_processor_handle processor_handle, amdsmi_asic_i
status = smi_amdgpu_get_market_name_from_dev_id(dev_info.device_id, info->market_name);
if (status != AMDSMI_STATUS_SUCCESS) {
rsmi_wrapper(rsmi_dev_brand_get, processor_handle,
info->market_name, AMDSMI_NORMAL_STRING_LENGTH);
info->market_name, AMDSMI_256_LENGTH);
}
info->device_id = dev_info.device_id;
@@ -667,7 +735,7 @@ amdsmi_get_gpu_asic_info(amdsmi_processor_handle processor_handle, amdsmi_asic_i
if (status == AMDSMI_STATUS_SUCCESS) snprintf(info->asic_serial, sizeof(info->asic_serial), "%lu", dv_uid);
status = rsmi_wrapper(rsmi_dev_brand_get, processor_handle,
info->market_name, AMDSMI_NORMAL_STRING_LENGTH);
info->market_name, AMDSMI_256_LENGTH);
status = rsmi_wrapper(rsmi_dev_vendor_id_get, processor_handle,
&vendor_id);
+82 -41
View File
@@ -36,7 +36,9 @@
#include <fstream>
#include <iostream>
#include <regex>
#include <cstdio>
#include <sstream>
#include <iterator>
#include <sys/ioctl.h>
#include <algorithm>
#include <limits.h>
@@ -45,6 +47,69 @@
#include "shared_mutex.h" // NOLINT
#include "rocm_smi/rocm_smi_logger.h"
std::string leftTrim(const std::string &s) {
if (!s.empty()) {
return std::regex_replace(s, std::regex("^\\s+"), "");
}
return s;
}
std::string rightTrim(const std::string &s) {
if (!s.empty()) {
return std::regex_replace(s, std::regex("\\s+$"), "");
}
return s;
}
std::string removeNewLines(const std::string &s) {
if (!s.empty()) {
return std::regex_replace(s, std::regex("\n+"), "");
}
return s;
}
std::string trim(const std::string &s) {
if (!s.empty()) {
// remove new lines -> trim white space at ends
std::string noNewLines = removeNewLines(s);
return leftTrim(rightTrim(noNewLines));
}
return s;
}
// Given original string and string to remove (removeMe)
// Return will provide the resulting modified string with the removed string(s)
std::string removeString(const std::string origStr,
const std::string &removeMe) {
std::string modifiedStr = origStr;
std::string::size_type l = removeMe.length();
for (std::string::size_type i = modifiedStr.find(removeMe);
i != std::string::npos;
i = modifiedStr.find(removeMe)) {
modifiedStr.erase(i, l);
}
return modifiedStr;
}
void openFileAndModifyBuffer(std::string path, char *buff, size_t sizeOfBuff) {
bool errorDiscovered = false;
std::ifstream file(path, std::ifstream::in);
std::string contents = {std::istreambuf_iterator<char>{file}, std::istreambuf_iterator<char>{}};
memset(buff, 0, sizeof(char) * sizeOfBuff);
if (!file.is_open()) {
errorDiscovered = true;
} else {
contents = trim(contents);
}
file.close();
if (!errorDiscovered && file.good() && !file.bad() && !file.fail() && !file.eof()
&& !contents.empty()) {
std::strncpy(buff, contents.c_str(), sizeOfBuff-1);
buff[sizeOfBuff-1] = '\0';
}
}
static const uint32_t kAmdGpuId = 0x1002;
static bool isAMDGPU(std::string dev_path) {
@@ -123,50 +188,26 @@ amdsmi_status_t smi_amdgpu_get_board_info(amd::smi::AMDSmiGPUDevice* device, amd
std::string manufacturer_name_path = "/sys/class/drm/" + device->get_gpu_path() + std::string("/device/manufacturer");
std::string product_name_path = "/sys/class/drm/" + device->get_gpu_path() + std::string("/device/product_name");
FILE *fp;
openFileAndModifyBuffer(model_number_path, info->model_number, AMDSMI_256_LENGTH);
openFileAndModifyBuffer(product_serial_path, info->product_serial, AMDSMI_NORMAL_STRING_LENGTH);
openFileAndModifyBuffer(fru_id_path, info->fru_id, AMDSMI_NORMAL_STRING_LENGTH);
openFileAndModifyBuffer(manufacturer_name_path, info->manufacturer_name,
AMDSMI_MAX_STRING_LENGTH);
openFileAndModifyBuffer(product_name_path, info->product_name, AMDSMI_256_LENGTH);
fp = fopen(model_number_path.c_str(), "rb");
if (fp) {
fgets(info->model_number, sizeof(info->model_number), fp);
fclose(fp);
}
fp = fopen(product_serial_path.c_str(), "rb");
if (fp) {
fgets(info->product_serial, sizeof(info->product_serial), fp);
fclose(fp);
}
fp = fopen(fru_id_path.c_str(), "rb");
if (fp) {
fgets(info->fru_id, sizeof(info->fru_id), fp);
fclose(fp);
}
fp = fopen(manufacturer_name_path.c_str(), "rb");
if (fp) {
fgets(info->manufacturer_name, sizeof(info->manufacturer_name), fp);
fclose(fp);
}
fp = fopen(product_name_path.c_str(), "rb");
if (fp) {
fgets(info->product_name, sizeof(info->product_name), fp);
fclose(fp);
}
std::ostringstream ss;
ss << __PRETTY_FUNCTION__
ss << __PRETTY_FUNCTION__ << "[Before correction] "
<< "Returning status = AMDSMI_STATUS_SUCCESS"
<< " | model_number_path = " << model_number_path
<< "; info->model_number: " << info->model_number
<< "\n product_serial_path = " << product_serial_path
<< "; info->product_serial: " << info->product_serial
<< "\n fru_id_path = " << fru_id_path
<< "; info->fru_id: " << info->fru_id
<< "\n manufacturer_name_path = " << manufacturer_name_path
<< "; info->manufacturer_name: " << info->manufacturer_name
<< "\n product_name_path = " << product_name_path
<< "; info->product_name: " << info->product_name;
<< " | model_number_path = |" << model_number_path << "|\n"
<< "; info->model_number: |" << info->model_number << "|\n"
<< "\n product_serial_path = |" << product_serial_path << "|\n"
<< "; info->product_serial: |" << info->product_serial << "|\n"
<< "\n fru_id_path = |" << fru_id_path << "|\n"
<< "; info->fru_id: |" << info->fru_id << "|\n"
<< "\n manufacturer_name_path = |" << manufacturer_name_path << "|\n"
<< "; info->manufacturer_name: |" << info->manufacturer_name << "|\n"
<< "\n product_name_path = |" << product_name_path << "|\n"
<< "; info->product_name: |" << info->product_name << "|";
LOG_INFO(ss);
return AMDSMI_STATUS_SUCCESS;
@@ -64,7 +64,7 @@ $BLACKLIST_ALL_ASICS\
# /sys/class/kfd/kfd/topology/nodes/*/properties
FILTER[90400]=\
$BLACKLIST_ALL_ASICS\
"amdsmitstReadOnly.TestVoltCurvRead"
# "amdsmitstReadOnly.TestVoltCurvRead"
FILTER[90401]=${FILTER[90400]}
FILTER[90402]=${FILTER[90400]}
@@ -183,10 +183,10 @@ void TestMutualExclusion::Run(void) {
int64_t dmy_i64 = 0;
char dmy_str[10];
amdsmi_dev_perf_level_t dmy_perf_lvl;
amdsmi_frequencies_t dmy_freqs;
amdsmi_od_volt_freq_data_t dmy_od_volt;
amdsmi_freq_volt_region_t dmy_vlt_reg;
amdsmi_error_count_t dmy_err_cnt;
amdsmi_frequencies_t dmy_freqs{};
amdsmi_od_volt_freq_data_t dmy_od_volt{};
amdsmi_freq_volt_region_t dmy_vlt_reg{};
amdsmi_error_count_t dmy_err_cnt{};
amdsmi_ras_err_state_t dmy_ras_err_st;
// This can be replaced with ASSERT_EQ() once env. stabilizes
@@ -92,9 +92,9 @@ void TestPerfDeterminism::Close() {
void TestPerfDeterminism::Run(void) {
amdsmi_status_t err;
amdsmi_dev_perf_level_t pfl;
amdsmi_od_volt_freq_data_t odv;
amdsmi_od_volt_freq_data_t odv{};
amdsmi_status_t ret;
uint64_t clkvalue;
uint64_t clkvalue(0);
TestBase::Run();
if (setup_failed_) {
std::cout << "** SetUp Failed for this test. Skipping.**" << std::endl;
@@ -146,7 +146,7 @@ static void print_amdsmi_od_volt_freq_regions(uint32_t num_regions,
void TestVoltCurvRead::Run(void) {
amdsmi_status_t err;
amdsmi_od_volt_freq_data_t odv;
amdsmi_od_volt_freq_data_t odv{};
TestBase::Run();
if (setup_failed_) {
@@ -172,7 +172,6 @@ void TestVoltCurvRead::Run(void) {
ASSERT_EQ(err, AMDSMI_STATUS_NOT_SUPPORTED);
}
} else {
CHK_ERR_ASRT(err)
// Verify api support checking functionality is working
err = amdsmi_get_gpu_od_volt_info(processor_handles_[i], nullptr);
ASSERT_EQ(err, AMDSMI_STATUS_INVAL);
@@ -182,15 +181,37 @@ void TestVoltCurvRead::Run(void) {
std::cout << "\t**Frequency-voltage curve data:" << std::endl;
print_amdsmi_od_volt_freq_data_t(&odv);
amdsmi_freq_volt_region_t *regions;
amdsmi_freq_volt_region_t *regions{};
uint32_t num_regions;
regions = new amdsmi_freq_volt_region_t[odv.num_regions];
ASSERT_TRUE(regions != nullptr);
ASSERT_NE(regions, nullptr);
num_regions = odv.num_regions;
err = amdsmi_get_gpu_od_volt_curve_regions(processor_handles_[i], &num_regions, regions);
CHK_ERR_ASRT(err)
ASSERT_TRUE(num_regions == odv.num_regions);
err = amdsmi_get_gpu_od_volt_curve_regions(processor_handles_[i],
&num_regions, regions);
IF_VERB(STANDARD) {
std::cout << "\t**amdsmi_get_gpu_od_volt_curve_regions("
<< "processor_handles_[i], &num_regions, regions): "
<< err << "\n"
<< "\t**Number of regions: " << std::dec << num_regions
<< "\n";
}
ASSERT_TRUE(err == AMDSMI_STATUS_SUCCESS
|| err == AMDSMI_STATUS_NOT_SUPPORTED
|| err == AMDSMI_STATUS_UNEXPECTED_DATA
|| err == AMDSMI_STATUS_UNEXPECTED_SIZE
|| err == AMDSMI_STATUS_INVAL);
if (err != AMDSMI_STATUS_SUCCESS) {
IF_VERB(STANDARD) {
std::cout << "\t**amdsmi_get_gpu_od_volt_curve_regions: "
"Not supported on this machine" << std::endl;
}
continue;
}
ASSERT_EQ(err, AMDSMI_STATUS_SUCCESS);
ASSERT_EQ(num_regions, odv.num_regions);
std::cout << "\t**Frequency-voltage curve regions:" << std::endl;
print_amdsmi_od_volt_freq_regions(num_regions, regions);