SWDEV-361376 - Add events to python interface

- Implement context manager event class for easier usage instead of having 4 different
  APIs.
- Add support for with statement for easier cleanup.

Change-Id: I396947a93d3f04efc068e17804eab12eefa97cf0
Signed-off-by: Dalibor Stanisavljevic <Dalibor.Stanisavljevic@amd.com>


[ROCm/amdsmi commit: 23160fa8e0]
Этот коммит содержится в:
Dalibor Stanisavljevic
2022-11-09 15:38:30 +01:00
родитель 35196b25bd
Коммит b155d429c9
3 изменённых файлов: 100 добавлений и 26 удалений
+47 -24
Просмотреть файл
@@ -1089,50 +1089,73 @@ except SmiException as e:
print(e)
```
## EventListen class
## AmdSmiEventReader class
Description: Providing methods for event monitoring
Description: Providing methods for event monitoring. This is context manager class.
Can be used with `with` statement for automatic cleanup.
Methods:
## Constructor
Description: Allocates a new event reader notifier to monitor different types of events with the multiple GPUs
Description: Allocates a new event reader notifier to monitor different types of events for the given GPU
Input parameters:
* `event_types` types of events to monitor and react on
* `device_handle` device handle corresponding to the device on which to listen for events
* `event_types` list of event types from AmdSmiEvtNotificationType enum. Specifying which events to collect for the given device.
Event Type | Description
---|------
`VMFAULT` | VM page fault
`THERMAL_THROTTLE` | thermal throttle
`GPU_PRE_RESET` | gpu pre reset
`GPU_POST_RESET` | gpu post reset
## read
Description: Reads events on GPUs. When event is caught, device handle, event id, message, event type and
time are returned. Reading events stops when timestamp passes without event reading.
Description: Reads events on the given device. When event is caught, device handle, message and event type are returned. Reading events stops when timestamp passes without event reading.
Input parameters:
* `timestamp` Amount of miliseconds to wait for event. If event does not happen monitoring is finished
* `i` GPU index to which we need to listen to events. For example 0,1,2...
* `timestamp` number of milliseconds to wait for an event to occur. If event does not happen monitoring is finished
* `num_elem` number of events. This is optional parameter. Default value is 10.
Example:
```python
try:
devices = gpuvsmi_get_devices()
if len(devices) == 0:
print("No GPUs on machine")
else:
device = devices[0]
listener = EventListen(SmiEventType.GPU_PRE_RESET)
listener.read(10000)
except SmiException as e:
print(e)
```
## stop
## Destructor
Description: Detroys event listener object, closes all open files and directories
Description: Any resources used by event notification for the the given device will be freed with this function. This can be used explicitly or
automatically using `with` statement, like in the examples below. This should be called either manually or automatically for every created AmdSmiEventReader object.
Input parameters: `None`
Example with manual cleanup of AmdSmiEventReader:
```python
try:
devices = amdsmi_get_device_handles()
if len(devices) == 0:
print("No GPUs on machine")
else:
event = AmdSmiEventReader(device[0], AmdSmiEvtNotificationType.GPU_PRE_RESET, AmdSmiEvtNotificationType.GPU_POST_RESET)
event.read(10000)
except AmdSmiException as e:
print(e)
finally:
event.stop()
```
Example with automatic cleanup using `with` statement:
```python
try:
devices = amdsmi_get_device_handles()
if len(devices) == 0:
print("No GPUs on machine")
else:
with AmdSmiEventReader(device[0], AmdSmiEvtNotificationType.GPU_PRE_RESET, AmdSmiEvtNotificationType.GPU_POST_RESET) as event:
event.read(10000)
except AmdSmiException as e:
print(e)
```
## amdsmi_dev_supported_func_iterator_open
Description: Get a function name iterator of supported AMDSMI functions for a device
+1 -1
Просмотреть файл
@@ -89,7 +89,7 @@ from .amdsmi_interface import amdsmi_dev_perf_level_set_v1
# # Events
# from .smi_interface import EventListen
from .amdsmi_interface import AmdSmiEventReader
# # Enums
+52 -1
Просмотреть файл
@@ -22,7 +22,7 @@
import ctypes
from typing import Union, Any, Dict, List, Tuple
from enum import IntEnum
from collections.abc import Iterable
from . import amdsmi_wrapper
from .amdsmi_exception import *
@@ -291,6 +291,57 @@ class AmdSmiUtilizationCounterType(IntEnum):
COARSE_GRAIN_MEM_ACTIVITY = amdsmi_wrapper.AMDSMI_COARSE_GRAIN_MEM_ACTIVITY
class AmdSmiEventReader:
def __init__(self, device_handle: amdsmi_wrapper.amdsmi_device_handle, *event_types):
if not isinstance(device_handle, amdsmi_wrapper.amdsmi_device_handle):
raise AmdSmiParameterException(
device_handle, amdsmi_wrapper.amdsmi_device_handle
)
if not isinstance(event_types, Iterable):
raise AmdSmiParameterException(
event_types, Iterable
)
for event_type in event_types:
if not isinstance(event_type, AmdSmiEvtNotificationType):
raise AmdSmiParameterException(
event_type, AmdSmiEvtNotificationType
)
self.device_handle = device_handle
mask = 0
for event_type in event_types:
mask |= (1 << (int(event_type) - 1))
_check_res(amdsmi_wrapper.amdsmi_event_notification_init(device_handle))
_check_res(amdsmi_wrapper.amdsmi_event_notification_mask_set(device_handle, ctypes.c_uint64(mask)))
def read(self, timestamp, num_elem = 10):
self.event_info = (amdsmi_wrapper.amdsmi_evt_notification_data_t * num_elem)()
_check_res(amdsmi_wrapper.amdsmi_event_notification_get(ctypes.c_int(timestamp), ctypes.byref(
ctypes.c_uint32(num_elem)), self.event_info))
ret = list()
for i in range(0, num_elem):
if self.event_info[i].event in set(event.value for event in AmdSmiEvtNotificationType):
ret.append({
'device_handle' : self.event_info[i].device_handle,
'event': AmdSmiEvtNotificationType(self.event_info[i].event).name,
'message': self.event_info[i].message.decode("utf-8")
})
return ret
def stop(self):
_check_res(amdsmi_wrapper.amdsmi_event_notification_stop(self.device_handle))
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
self.stop()
_AMDSMI_MAX_DRIVER_VERSION_LENGTH = 80
_AMDSMI_GPU_UUID_SIZE = 38