diff --git a/CMakeLists.txt b/CMakeLists.txt index 1db2b27601..19b97133af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -130,7 +130,8 @@ set ( HSAKMT_SRC "src/debug.c" "src/rbtree.c" "src/spm.c" "src/version.c" - "src/svm.c") + "src/svm.c" + "src/pc_sampling.c") ## Declare the library target name add_library ( ${HSAKMT_TARGET} "") diff --git a/include/hsakmt.h b/include/hsakmt.h index ce7b7e327c..7a37bec049 100644 --- a/include/hsakmt.h +++ b/include/hsakmt.h @@ -1044,6 +1044,122 @@ hsaKmtReturnAsanHeaderPage( void *addr // IN: Start of othe virtual address page ); +/** + Check whether kernel support pc sampling +*/ +HSAKMT_STATUS +HSAKMTAPI +hsaKmtPcSamplingSupport( + void +); + +/** + * Query device PC Sampling capabilities + * + * Arguments: + * @NodeId (IN) - GPU node_id + * @sample_info (IN) - Pointer to array of HSAPcSamplingInfo + * @sample_info_sz(IN) - Size of sampling_info in units of HSAPcSamplingInfo + * @sz_needed (OUT)- If sampling_info_sz is too small, sample_info_sz needed + * + * Return: + * HSAKMT_STATUS_ERROR - failed + * HSAKMT_STATUS_SUCCESS - successfully complete + * HSAKMT_STATUS_INVALID_PARAMETER - invalid input + * HSAKMT_STATUS_BUFFER_TOO_SMALL - sample buffer size is too small. Retry with sample_info_sz + * >= sz_needed + * HSAKMT_STATUS_NOT_SUPPORTED - this asic doesn't support pc sampling +*/ +HSAKMT_STATUS +HSAKMTAPI +hsaKmtPcSamplingQueryCapabilities( + HSAuint32 NodeId, + void *sample_info, + HSAuint32 sample_info_sz, + HSAuint32 *sz_needed +); + +/** + * Create PC Sampling Session + * + * Arguments: + * @NodeId (IN) - GPU node_id + * @sample_info(IN) - PC Sampling configuration requested + * @traceId (OUT) - Unique PC Sampling trace Id + * + * Return: + * HSAKMT_STATUS_ERROR - failed + * HSAKMT_STATUS_SUCCESS - successfully complete + * HSAKMT_STATUS_INVALID_PARAMETER - invalid input + * HSAKMT_STATUS_NO_MEMORY - not enough memory to create new pc sampling session + * HSAKMT_STATUS_UNAVAILABLE - a different pc sampling session started on this node +*/ +HSAKMT_STATUS +HSAKMTAPI +hsaKmtPcSamplingCreate( + HSAuint32 node_id, + HsaPcSamplingInfo *sample_info, + HsaPcSamplingTraceId *traceId +); + +/** + * Destroy PC Sampling Session + * + * Arguments: + * @NodeId (IN) - GPU node_id + * @traceId(IN) - PC Sampling trace Id + * + * Return: + * HSAKMT_STATUS_ERROR - failed + * HSAKMT_STATUS_SUCCESS - successfully complete + * HSAKMT_STATUS_INVALID_PARAMETER - invalid input +*/ +HSAKMT_STATUS +HSAKMTAPI +hsaKmtPcSamplingDestroy( + HSAuint32 NodeId, + HsaPcSamplingTraceId traceId +); + +/** + * Start PC Sampling Session + * + * Arguments: + * @NodeId (IN) - GPU node_id + * @traceId(IN) - PC Sampling trace Id + * + * Return: + * HSAKMT_STATUS_ERROR - failed + * HSAKMT_STATUS_SUCCESS - successfully complete + * HSAKMT_STATUS_INVALID_PARAMETER - invalid input +*/ +HSAKMT_STATUS +HSAKMTAPI +hsaKmtPcSamplingStart( + HSAuint32 NodeId, + HsaPcSamplingTraceId traceId +); + +/** + * Stop PC Sampling Session + * + * Arguments: + * @NodeId (IN) - GPU node_id + * @traceId(IN) - PC Sampling trace Id + * + * Return: + * HSAKMT_STATUS_ERROR - failed + * HSAKMT_STATUS_SUCCESS - successfully complete + * HSAKMT_STATUS_INVALID_PARAMETER - invalid input + * HSAKMT_STATUS_KERNEL_ALREADY_OPENED - stop already +*/ +HSAKMT_STATUS +HSAKMTAPI +hsaKmtPcSamplingStop( + HSAuint32 NodeId, + HsaPcSamplingTraceId traceId +); + #ifdef __cplusplus } //extern "C" #endif diff --git a/include/hsakmttypes.h b/include/hsakmttypes.h index 86cf248fa2..f94efa11c3 100644 --- a/include/hsakmttypes.h +++ b/include/hsakmttypes.h @@ -1467,6 +1467,32 @@ typedef enum _HSA_SVM_UNMAP_TRIGGERS { typedef void *HsaAMDGPUDeviceHandle; +typedef HSAuint32 HsaPcSamplingTraceId; + +typedef enum _HSA_PC_SAMPLING_METHOD_KIND +{ + HSA_PC_SAMPLING_METHOD_KIND_HOSTTRAP_V1 = 1, + HSA_PC_SAMPLING_METHOD_KIND_STOCHASTIC_V1, +} HSA_PC_SAMPLING_METHOD_KIND; + +typedef enum _HSA_PC_SAMPLING_UNITS +{ + HSA_PC_SAMPLING_UNIT_INTERVAL_MICROSECONDS, + HSA_PC_SAMPLING_UNIT_INTERVAL_CYCLES, + HSA_PC_SAMPLING_UNIT_INTERVAL_INSTRUCTIONS, +} HSA_PC_SAMPLING_UNIT_INTERVAL; + +typedef struct _HsaPcSamplingInfo +{ + HSAuint64 value; + HSAuint64 value_min; + HSAuint64 value_max; + HSAuint64 flags; + HSA_PC_SAMPLING_METHOD_KIND method; + HSA_PC_SAMPLING_UNIT_INTERVAL units; +} +HsaPcSamplingInfo; + #pragma pack(pop, hsakmttypes_h) diff --git a/src/libhsakmt.ver b/src/libhsakmt.ver index c04cefef41..8a64f8d7a8 100644 --- a/src/libhsakmt.ver +++ b/src/libhsakmt.ver @@ -82,6 +82,11 @@ hsaKmtWaitOnMultipleEvents_Ext; hsaKmtReplaceAsanHeaderPage; hsaKmtReturnAsanHeaderPage; hsaKmtGetAMDGPUDeviceHandle; +hsaKmtPcSamplingQueryCapabilities; +hsaKmtPcSamplingCreate; +hsaKmtPcSamplingDestroy; +hsaKmtPcSamplingStart; +hsaKmtPcSamplingStop; local: *; }; diff --git a/src/pc_sampling.c b/src/pc_sampling.c new file mode 100644 index 0000000000..3cb81dc97b --- /dev/null +++ b/src/pc_sampling.c @@ -0,0 +1,210 @@ +/* + * Copyright © 2023 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including + * the next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "libhsakmt.h" +#include "linux/kfd_ioctl.h" +#include +#include +#include +#include + +#define INVALID_TRACE_ID 0x0 + +HSAKMT_STATUS HSAKMTAPI hsaKmtPcSamplingSupport(void) +{ + CHECK_KFD_OPEN(); + CHECK_KFD_MINOR_VERSION(16); + + return HSAKMT_STATUS_SUCCESS; +} + +HSAKMT_STATUS HSAKMTAPI hsaKmtPcSamplingQueryCapabilities(HSAuint32 NodeId, void *sample_info, + HSAuint32 sample_info_sz, HSAuint32 *size) +{ + int ret; + struct kfd_ioctl_pc_sample_args args = {0}; + uint32_t gpu_id; + + if (size == NULL) + return HSAKMT_STATUS_INVALID_PARAMETER; + + CHECK_KFD_OPEN(); + CHECK_KFD_MINOR_VERSION(16); + + ret = validate_nodeid(NodeId, &gpu_id); + if (ret != HSAKMT_STATUS_SUCCESS) { + pr_err("[%s] invalid node ID: %d\n", __func__, NodeId); + return ret; + } + assert(sizeof(HsaPcSamplingInfo) == sizeof(struct kfd_pc_sample_info)); + + ret = HSAKMT_STATUS_SUCCESS; + args.op = KFD_IOCTL_PCS_OP_QUERY_CAPABILITIES; + args.gpu_id = gpu_id; + args.sample_info_ptr = (uint64_t)sample_info; + args.num_sample_info = sample_info_sz; + args.flags = 0; + + ret = kmtIoctl(kfd_fd, AMDKFD_IOC_PC_SAMPLE, &args); + + if (ret) { + return (ret == -ENOSPC) ? HSAKMT_STATUS_BUFFER_TOO_SMALL : + (ret == -EINVAL) ? HSAKMT_STATUS_INVALID_PARAMETER : + (ret == -EOPNOTSUPP) ? HSAKMT_STATUS_NOT_SUPPORTED : + (ret == -EBUSY) ? HSAKMT_STATUS_UNAVAILABLE : + HSAKMT_STATUS_ERROR; + } + *size = args.num_sample_info; + + return HSAKMT_STATUS_SUCCESS; +} + +HSAKMT_STATUS HSAKMTAPI hsaKmtPcSamplingCreate(HSAuint32 NodeId, HsaPcSamplingInfo *sample_info, + HsaPcSamplingTraceId *traceId) +{ + int ret; + struct kfd_ioctl_pc_sample_args args = {0}; + uint32_t gpu_id; + + if (sample_info == NULL || traceId == NULL) + return HSAKMT_STATUS_INVALID_PARAMETER; + + CHECK_KFD_OPEN(); + + *traceId = INVALID_TRACE_ID; + ret = validate_nodeid(NodeId, &gpu_id); + if (ret != HSAKMT_STATUS_SUCCESS) { + pr_err("[%s] invalid node ID: %d\n", __func__, NodeId); + return ret; + } + + ret = HSAKMT_STATUS_SUCCESS; + args.op = KFD_IOCTL_PCS_OP_CREATE; + args.gpu_id = gpu_id; + args.sample_info_ptr = (uint64_t)sample_info; + args.num_sample_info = 1; + args.trace_id = INVALID_TRACE_ID; + + ret = kmtIoctl(kfd_fd, AMDKFD_IOC_PC_SAMPLE, &args); + if (ret) { + return (ret == -EINVAL) ? HSAKMT_STATUS_INVALID_PARAMETER : + (ret == -ENOMEM) ? HSAKMT_STATUS_NO_MEMORY : + (ret == -EBUSY) ? HSAKMT_STATUS_UNAVAILABLE : + HSAKMT_STATUS_ERROR; + } + + *traceId = args.trace_id; + return HSAKMT_STATUS_SUCCESS; +} + +HSAKMT_STATUS HSAKMTAPI hsaKmtPcSamplingDestroy(HSAuint32 NodeId, HsaPcSamplingTraceId traceId) +{ + int ret; + struct kfd_ioctl_pc_sample_args args = {0}; + uint32_t gpu_id; + + if (traceId == INVALID_TRACE_ID) + return HSAKMT_STATUS_INVALID_HANDLE; + + CHECK_KFD_OPEN(); + + ret = validate_nodeid(NodeId, &gpu_id); + if (ret != HSAKMT_STATUS_SUCCESS) { + pr_err("[%s] invalid node ID: %d\n", __func__, NodeId); + return ret; + } + + hsaKmtPcSamplingStop(NodeId, traceId); + + ret = HSAKMT_STATUS_SUCCESS; + args.op = KFD_IOCTL_PCS_OP_DESTROY; + args.gpu_id = gpu_id; + args.trace_id = traceId; + + ret = kmtIoctl(kfd_fd, AMDKFD_IOC_PC_SAMPLE, &args); + return (ret == -EINVAL) ? HSAKMT_STATUS_INVALID_PARAMETER : + ret ? HSAKMT_STATUS_ERROR : + HSAKMT_STATUS_SUCCESS; +} + +HSAKMT_STATUS HSAKMTAPI hsaKmtPcSamplingStart(HSAuint32 NodeId, HsaPcSamplingTraceId traceId) +{ + int ret; + struct kfd_ioctl_pc_sample_args args = {0}; + uint32_t gpu_id; + + if (traceId == INVALID_TRACE_ID) + return HSAKMT_STATUS_INVALID_HANDLE; + + CHECK_KFD_OPEN(); + + ret = validate_nodeid(NodeId, &gpu_id); + if (ret != HSAKMT_STATUS_SUCCESS) { + pr_err("[%s] invalid node ID: %d\n", __func__, NodeId); + return ret; + } + + ret = HSAKMT_STATUS_SUCCESS; + args.op = KFD_IOCTL_PCS_OP_START; + args.gpu_id = gpu_id; + args.trace_id = traceId; + + ret = kmtIoctl(kfd_fd, AMDKFD_IOC_PC_SAMPLE, &args); + return (ret == -EINVAL) ? HSAKMT_STATUS_INVALID_PARAMETER : + (ret == -ENOMEM) ? HSAKMT_STATUS_OUT_OF_RESOURCES : + (ret == -EBUSY) ? HSAKMT_STATUS_UNAVAILABLE : + (ret == -EALREADY) ? HSAKMT_STATUS_KERNEL_ALREADY_OPENED : + ret ? HSAKMT_STATUS_ERROR : + HSAKMT_STATUS_SUCCESS; +} + +HSAKMT_STATUS HSAKMTAPI hsaKmtPcSamplingStop(HSAuint32 NodeId, HsaPcSamplingTraceId traceId) +{ + int ret; + struct kfd_ioctl_pc_sample_args args = {0}; + uint32_t gpu_id; + + if (traceId == INVALID_TRACE_ID) + return HSAKMT_STATUS_INVALID_HANDLE; + + CHECK_KFD_OPEN(); + + ret = validate_nodeid(NodeId, &gpu_id); + if (ret != HSAKMT_STATUS_SUCCESS) { + pr_err("[%s] invalid node ID: %d\n", __func__, NodeId); + return ret; + } + + ret = HSAKMT_STATUS_SUCCESS; + args.op = KFD_IOCTL_PCS_OP_STOP; + args.gpu_id = gpu_id; + args.trace_id = traceId; + + ret = kmtIoctl(kfd_fd, AMDKFD_IOC_PC_SAMPLE, &args); + return (ret == -EINVAL) ? HSAKMT_STATUS_INVALID_PARAMETER : + (ret == -EALREADY) ? HSAKMT_STATUS_KERNEL_ALREADY_OPENED : + ret ? HSAKMT_STATUS_ERROR : + HSAKMT_STATUS_SUCCESS; +} \ No newline at end of file