On 9/22/26 17:40, Alex Deucher wrote:
> On Tue, Sep 22, 2026 at 11:22 AM Timur Kristóf <[email protected]>
> wrote:
>>
>> On Tuesday, September 22, 2026 5:20:41 PM Central European Summer Time James
>> Zhu wrote:
>>> On 2026-09-22 11:09, Timur Kristóf wrote:
>>>> On Monday, September 21, 2026 10:03:02 PM Central European Summer Time
>>>> James>
>>>> Zhu wrote:
>>>>> Add the DRM_AMDGPU_PROFILER ioctl number and its argument structures, the
>>>>> UAPI for GPU performance monitoring features such as SPM (Stream
>>>>> Performance Monitor).
>>>>>
>>>>> struct drm_amdgpu_profiler_args carries an operation selector and a union
>>>>> of per-operation parameters, currently AMDGPU_PROFILER_OP_GET_VER and
>>>>> AMDGPU_PROFILER_OP_SPM. The SPM operations and the layout of the
>>>>> destination buffer are described by struct drm_amdgpu_spm_args and
>>>>> struct drm_amdgpu_spm_buffer_header.
>>>>>
>>>>> The ioctl number and struct layout are frozen here. The implementation
>>>>> lands in the rest of this series and the ioctl is not registered in
>>>>> amdgpu_ioctls_kms[] until then, so this header change alone does not make
>>>>> the interface reachable.
>>>>>
>>>>> Signed-off-by: James Zhu<[email protected]>
>>>>> Reviewed-by: Bing Ma<[email protected]>
>>>>
>>>> Hi,
>>>>
>>>> Can you guys please clarify why this is necessary and what the use case
>>>> is?
>>>>
>>>> Are we sure we want a uAPI for this? RADV has been using SPM from
>>>> userspace
>>>> for many years now.
>>>
>>> [JZ] current RADV SPM is for graphic engine. These patches are for
>>> compute engine SPM.
>>>
>>> Thanks!
>>
>> Is there any reason why it can't be done in userspace for compute too?
>
> There's only one SPM so there needs to be arbitration to avoid
> multiple applications trying to use it at the same time. It also only
> works on a single vmid at a time so the application using it has to
> request a fixed vmid.
Yeah, we already have an API for reserving a VMID for SPM.
We also have a TODO item to make that available for user queues which then both
ROCm and gfx can use.
So as far as I can see that work here is completely unnecessary.
Christian.
>
> Alex
>
>>
>>
>>>>
>>>>> ---
>>>>>
>>>>> include/uapi/drm/amdgpu_drm.h | 124 ++++++++++++++++++++++++++++++++++
>>>>> 1 file changed, 124 insertions(+)
>>>>>
>>>>> diff --git a/include/uapi/drm/amdgpu_drm.h
>>>>> b/include/uapi/drm/amdgpu_drm.h
>>>>> index 9e5fa6f53e59..285949d63eb6 100644
>>>>> --- a/include/uapi/drm/amdgpu_drm.h
>>>>> +++ b/include/uapi/drm/amdgpu_drm.h
>>>>> @@ -60,6 +60,7 @@ extern "C" {
>>>>>
>>>>> #define DRM_AMDGPU_GEM_LIST_HANDLES 0x19
>>>>> #define DRM_AMDGPU_PROC_OPTIONS 0x1A
>>>>> #define DRM_AMDGPU_TRAP 0x1B
>>>>>
>>>>> +#define DRM_AMDGPU_PROFILER 0x1C
>>>>>
>>>>> #define DRM_IOCTL_AMDGPU_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE +
>>>>>
>>>>> DRM_AMDGPU_GEM_CREATE, union drm_amdgpu_gem_create) #define
>>>>> DRM_IOCTL_AMDGPU_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE +
>>>>> DRM_AMDGPU_GEM_MMAP,
>>>>> union drm_amdgpu_gem_mmap) @@ -83,6 +84,7 @@ extern "C" {
>>>>>
>>>>> #define DRM_IOCTL_AMDGPU_GEM_LIST_HANDLES DRM_IOWR(DRM_COMMAND_BASE +
>>>>>
>>>>> DRM_AMDGPU_GEM_LIST_HANDLES, struct drm_amdgpu_gem_list_handles) #define
>>>>> DRM_IOCTL_AMDGPU_PROC_OPTIONS DRM_IOWR(DRM_COMMAND_BASE +
>>>>> DRM_AMDGPU_PROC_OPTIONS, struct drm_amdgpu_proc_options) #define
>>>>> DRM_IOCTL_AMDGPU_TRAP DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_TRAP,
>>>>
>>>> union
>>>>
>>>>> drm_amdgpu_trap) +#define
>>>>> DRM_IOCTL_AMDGPU_PROFILER DRM_IOWR(DRM_COMMAND_BASE +
>>>>
>>>> DRM_AMDGPU_PROFILER,
>>>>
>>>>> struct drm_amdgpu_profiler_args)
>>>>>
>>>>> /**
>>>>>
>>>>> * DOC: memory domains
>>>>>
>>>>> @@ -1821,6 +1823,128 @@ struct drm_amdgpu_proc_options {
>>>>>
>>>>> } kfd_sigbus_delay;
>>>>>
>>>>> };
>>>>>
>>>>> +/*
>>>>> + * Supported SPM (Stream Performance Monitor) Operations
>>>>> + */
>>>>> +/**
>>>>> + * drm_amdgpu_spm_op - SPM ioctl operations
>>>>> + */
>>>>> +enum drm_amdgpu_spm_op {
>>>>> + AMDGPU_SPM_OP_ACQUIRE = 1,
>>>>> + AMDGPU_SPM_OP_RELEASE,
>>>>> + AMDGPU_SPM_OP_SET_DEST_BUF
>>>>> +};
>>>>> +
>>>>> +/**
>>>>> + * drm_amdgpu_spm_args - Arguments for SPM ioctl
>>>>> + *
>>>>> + * @dest_buf: [in] used for the address of the destination buffer
>>>>> + * in @AMDGPU_SPM_OP_SET_DEST_BUF
>>>>> + * @buf_size: [in] size of the destination buffer
>>>>> + * @op: [in] specifies the operation to perform
>>>>> + * @timeout: [in/out] timeout in milliseconds (in), amount of time left
>>>>> + * in the timeout window (out)
>>>>> + * @bytes_copied: [out] total amount of data that was copied to the
>>>>> previous dest_buf + * @has_data_loss: [out] non-zero if data was lost
>>>>> (e.g.
>>>>> due to ring buffer overflow), + * zero otherwise
>>>>> + * @reserved: must be zero for forward compatibility
>>>>> + *
>>>>> + * This ioctl performs different functions depending on the @op
>>>>> parameter.
>>>>> + *
>>>>> + * AMDGPU_SPM_OP_ACQUIRE
>>>>> + * ------------------------
>>>>> + *
>>>>> + * Acquires exclusive access of SPM on the specified XCP for the calling
>>>>> process. + * This must be called before using AMDGPU_SPM_OP_SET_DEST_BUF.
>>>>> + *
>>>>> + * AMDGPU_SPM_OP_RELEASE
>>>>> + * ------------------------
>>>>> + *
>>>>> + * Releases exclusive access of SPM on the specified XCP for the calling
>>>>> process, + * which allows another process to acquire it in the future.
>>>>> + *
>>>>> + * AMDGPU_SPM_OP_SET_DEST_BUF
>>>>> + * -----------------------------
>>>>> + *
>>>>> + * If @dest_buf is NULL, the destination buffer address is unset and
>>>>> copying of counters + * is stopped.
>>>>> + *
>>>>> + * If @dest_buf is not NULL, it specifies the pointer to a new
>>>>> destination
>>>>> buffer. + * @buf_size specifies the size of the buffer.
>>>>> + *
>>>>> + * If @timeout is non-0, the call will wait for up to @timeout ms for
>>>>> the
>>>>> previous + * buffer to be filled. If the previous buffer is filled before
>>>>> the timeout, @timeout + * is updated with the time remaining. If the
>>>>> timeout is exceeded, the function + * copies any partial data available
>>>>> into the previous user buffer and returns success. + * The amount of
>>>>> valid
>>>>> data in the previous user buffer is indicated by @bytes_copied. + *
>>>>> + * If @timeout is 0, the function immediately replaces the previous
>>>>> destination buffer + * without waiting for the previous buffer to be
>>>>> filled. That means the previous buffer + * may only be partially filled,
>>>>> and @bytes_copied will indicate how much data has been + * copied to it.
>>>>> + *
>>>>> + * If data was lost, e.g. due to a ring buffer overflow, @has_data_loss
>>>>> will be non-0. + *
>>>>> + * Returns negative error code on failure, 0 on success.
>>>>> + */
>>>>> +struct drm_amdgpu_spm_args {
>>>>> + __u64 dest_buf;
>>>>> + __u32 buf_size;
>>>>> + __u32 op;
>>>>> + __u32 timeout;
>>>>> + __u32 bytes_copied;
>>>>> + __u32 has_data_loss;
>>>>> + __u32 reserved[9]; /* must be zero; pads this struct to 64
>>>>
>>>> bytes */
>>>>
>>>>> +};
>>>>> +
>>>>> +/**
>>>>> + * drm_amdgpu_spm_buffer_header - SPM Buffer header for
>>>>> drm_amdgpu_spm_args->dest_buf + *
>>>>> + * @version: [out] SPM version (0-23: minor, 24-31: major)
>>>>> + * @bytes_copied: [out] Amount of data copied for this sub-block
>>>>> + * @has_data_loss: [out] Boolean indicating whether data was lost for
>>>>> this
>>>>> sub-block + * (e.g. due to a ring-buffer overflow)
>>>>> + * @reserved: Reserved for future use, must be zero
>>>>> + *
>>>>> + * This header precedes the SPM data in the destination buffer. The
>>>>> reserved + * field maintains 64-byte cache line alignment (32 bytes
>>>>> total).
>>>>> + */
>>>>> +struct drm_amdgpu_spm_buffer_header {
>>>>> + __u32 version; /* 0-23: minor, 24-31: major */
>>>>> + __u32 bytes_copied;
>>>>> + __u32 has_data_loss;
>>>>> + __u32 reserved[5]; /* pad to 32 bytes (64-byte cache line / 2) */
>>>>> +};
>>>>> +
>>>>> +/* Supported Profiler Operation */
>>>>> +#define AMDGPU_PROFILER_OP_GET_VER 1 /* get profiler UAPI
>>>>
>>>> version */
>>>>
>>>>> +#define AMDGPU_PROFILER_OP_SPM 2
>>>>> +
>>>>> +/*
>>>>> + * Profiler IOCTL
>>>>> + */
>>>>> +/**
>>>>> + * struct drm_amdgpu_profiler_args - Profiler IOCTL arguments
>>>>> + * @op: Operation to perform (AMDGPU_PROFILER_OP_*)
>>>>> + * @pad: Must be zero for input validation
>>>>> + * @data: Operation-specific parameters (union)
>>>>> + *
>>>>> + * GET_VER operation:
>>>>> + * Returns the profiler UAPI version in @data.version as (MAJOR<<24) |
>>>>> MINOR. + * Input: @data must be zero (reserved for forward
>>>>> compatibility).
>>>>> + *
>>>>> + * Design note: GET_VER is intentionally a parameter-free query
>>>>> returning
>>>>> + * the global profiler UAPI version.
>>>>> + */
>>>>> +struct drm_amdgpu_profiler_args {
>>>>> + __u32 op; /*
>>>>
>>>> AMDGPU_PROFILER_OP_* */
>>>>
>>>>> + __u32 pad; /* must be zero */
>>>>> + union {
>>>>> + __u32 version; /* GET_VER: out
>>>>
>>>> (MAJOR<<24) | MINOR */
>>>>
>>>>> + struct drm_amdgpu_spm_args spm;
>>>>> + } data;
>>>>> +};
>>>>> +
>>>>>
>>>>> #if defined(__cplusplus)
>>>>> }
>>>>> #endif
>>
>>
>>
>>