* [PATCH 0/2] tests/msm: Add PERFCNTR_CONFIG ioctl @ 2026-07-03 14:39 Rob Clark 2026-07-03 14:39 ` [PATCH 1/2] drm-uapi: Sync msm_drm.h Rob Clark 2026-07-03 14:39 ` [PATCH 2/2] tests/msm: Add perfcntrs test Rob Clark 0 siblings, 2 replies; 4+ messages in thread From: Rob Clark @ 2026-07-03 14:39 UTC (permalink / raw) To: igt-dev; +Cc: freedreno, Rob Clark Now that the new UABI is merged for v7.2, here are tests. Rob Clark (2): drm-uapi: Sync msm_drm.h tests/msm: Add perfcntrs test include/drm-uapi/msm_drm.h | 204 ++++++++++++++++++++++++++++++++++--- tests/msm/meson.build | 1 + tests/msm/msm_perfcntrs.c | 194 +++++++++++++++++++++++++++++++++++ 3 files changed, 383 insertions(+), 16 deletions(-) create mode 100644 tests/msm/msm_perfcntrs.c -- 2.54.0 ^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 1/2] drm-uapi: Sync msm_drm.h 2026-07-03 14:39 [PATCH 0/2] tests/msm: Add PERFCNTR_CONFIG ioctl Rob Clark @ 2026-07-03 14:39 ` Rob Clark 2026-07-03 14:39 ` [PATCH 2/2] tests/msm: Add perfcntrs test Rob Clark 1 sibling, 0 replies; 4+ messages in thread From: Rob Clark @ 2026-07-03 14:39 UTC (permalink / raw) To: igt-dev; +Cc: freedreno, Rob Clark Pull in updated UABI header with PERFCNTR_CONFIG ioctl. Sync with: commit 44c460d2cc8b87c08360fe60f861660c8045ef90 Merge: 9bb8af2770b7 9a967125427e Author: Dave Airlie <airlied@redhat.com> Merge tag 'drm-msm-next-2026-05-30' of https://gitlab.freedesktop.org/drm/msm into drm-next Signed-off-by: Rob Clark <rob.clark@oss.qualcomm.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/41158> --- include/drm-uapi/msm_drm.h | 204 ++++++++++++++++++++++++++++++++++--- 1 file changed, 188 insertions(+), 16 deletions(-) diff --git a/include/drm-uapi/msm_drm.h b/include/drm-uapi/msm_drm.h index 2377147b6af0..7f2e594be4eb 100644 --- a/include/drm-uapi/msm_drm.h +++ b/include/drm-uapi/msm_drm.h @@ -90,6 +90,34 @@ struct drm_msm_timespec { #define MSM_PARAM_RAYTRACING 0x11 /* RO */ #define MSM_PARAM_UBWC_SWIZZLE 0x12 /* RO */ #define MSM_PARAM_MACROTILE_MODE 0x13 /* RO */ +#define MSM_PARAM_UCHE_TRAP_BASE 0x14 /* RO */ +/* PRR (Partially Resident Region) is required for sparse residency: */ +#define MSM_PARAM_HAS_PRR 0x15 /* RO */ +/* MSM_PARAM_EN_VM_BIND is set to 1 to enable VM_BIND ops. + * + * With VM_BIND enabled, userspace is required to allocate iova and use the + * VM_BIND ops for map/unmap ioctls. MSM_INFO_SET_IOVA and MSM_INFO_GET_IOVA + * will be rejected. (The latter does not have a sensible meaning when a BO + * can have multiple and/or partial mappings.) + * + * With VM_BIND enabled, userspace does not include a submit_bo table in the + * SUBMIT ioctl (this will be rejected), the resident set is determined by + * the the VM_BIND ops. + * + * Enabling VM_BIND will fail on devices which do not have per-process pgtables. + * And it is not allowed to disable VM_BIND once it has been enabled. + * + * Enabling VM_BIND should be done (attempted) prior to allocating any BOs or + * submitqueues of type MSM_SUBMITQUEUE_VM_BIND. + * + * Relatedly, when VM_BIND mode is enabled, the kernel will not try to recover + * from GPU faults or failed async VM_BIND ops, in particular because it is + * difficult to communicate to userspace which op failed so that userspace + * could rewind and try again. When the VM is marked unusable, the SUBMIT + * ioctl will throw -EPIPE. + */ +#define MSM_PARAM_EN_VM_BIND 0x16 /* WO, once */ +#define MSM_PARAM_AQE 0x17 /* RO */ /* For backwards compat. The original support for preemption was based on * a single ring per priority level so # of priority levels equals the # @@ -113,6 +141,19 @@ struct drm_msm_param { #define MSM_BO_SCANOUT 0x00000001 /* scanout capable */ #define MSM_BO_GPU_READONLY 0x00000002 +/* Private buffers do not need to be explicitly listed in the SUBMIT + * ioctl, unless referenced by a drm_msm_gem_submit_cmd. Private + * buffers may NOT be imported/exported or used for scanout (or any + * other situation where buffers can be indefinitely pinned, but + * cases other than scanout are all kernel owned BOs which are not + * visible to userspace). + * + * In exchange for those constraints, all private BOs associated with + * a single context (drm_file) share a single dma_resv, and if there + * has been no eviction since the last submit, there are no per-BO + * bookeeping to do, significantly cutting the SUBMIT overhead. + */ +#define MSM_BO_NO_SHARE 0x00000004 #define MSM_BO_CACHE_MASK 0x000f0000 /* cache modes */ #define MSM_BO_CACHED 0x00010000 @@ -122,6 +163,7 @@ struct drm_msm_param { #define MSM_BO_FLAGS (MSM_BO_SCANOUT | \ MSM_BO_GPU_READONLY | \ + MSM_BO_NO_SHARE | \ MSM_BO_CACHE_MASK) struct drm_msm_gem_new { @@ -179,6 +221,17 @@ struct drm_msm_gem_cpu_fini { * Cmdstream Submission: */ +#define MSM_SYNCOBJ_RESET 0x00000001 /* Reset syncobj after wait. */ +#define MSM_SYNCOBJ_FLAGS ( \ + MSM_SYNCOBJ_RESET | \ + 0) + +struct drm_msm_syncobj { + __u32 handle; /* in, syncobj handle. */ + __u32 flags; /* in, from MSM_SUBMIT_SYNCOBJ_FLAGS */ + __u64 point; /* in, timepoint for timeline syncobjs. */ +}; + /* The value written into the cmdstream is logically: * * ((relocbuf->gpuaddr + reloc_offset) << shift) | or @@ -220,7 +273,10 @@ struct drm_msm_gem_submit_cmd { __u32 size; /* in, cmdstream size */ __u32 pad; __u32 nr_relocs; /* in, number of submit_reloc's */ - __u64 relocs; /* in, ptr to array of submit_reloc's */ + union { + __u64 relocs; /* in, ptr to array of submit_reloc's */ + __u64 iova; /* cmdstream address (for VM_BIND contexts) */ + }; }; /* Each buffer referenced elsewhere in the cmdstream submit (ie. the @@ -268,17 +324,6 @@ struct drm_msm_gem_submit_bo { MSM_SUBMIT_FENCE_SN_IN | \ 0) -#define MSM_SUBMIT_SYNCOBJ_RESET 0x00000001 /* Reset syncobj after wait. */ -#define MSM_SUBMIT_SYNCOBJ_FLAGS ( \ - MSM_SUBMIT_SYNCOBJ_RESET | \ - 0) - -struct drm_msm_gem_submit_syncobj { - __u32 handle; /* in, syncobj handle. */ - __u32 flags; /* in, from MSM_SUBMIT_SYNCOBJ_FLAGS */ - __u64 point; /* in, timepoint for timeline syncobjs. */ -}; - /* Each cmdstream submit consists of a table of buffers involved, and * one or more cmdstream buffers. This allows for conditional execution * (context-restore), and IB buffers needed for per tile/bin draw cmds. @@ -292,13 +337,80 @@ struct drm_msm_gem_submit { __u64 cmds; /* in, ptr to array of submit_cmd's */ __s32 fence_fd; /* in/out fence fd (see MSM_SUBMIT_FENCE_FD_IN/OUT) */ __u32 queueid; /* in, submitqueue id */ - __u64 in_syncobjs; /* in, ptr to array of drm_msm_gem_submit_syncobj */ - __u64 out_syncobjs; /* in, ptr to array of drm_msm_gem_submit_syncobj */ + __u64 in_syncobjs; /* in, ptr to array of drm_msm_syncobj */ + __u64 out_syncobjs; /* in, ptr to array of drm_msm_syncobj */ __u32 nr_in_syncobjs; /* in, number of entries in in_syncobj */ __u32 nr_out_syncobjs; /* in, number of entries in out_syncobj. */ __u32 syncobj_stride; /* in, stride of syncobj arrays. */ __u32 pad; /*in, reserved for future use, always 0. */ +}; + +#define MSM_VM_BIND_OP_UNMAP 0 +#define MSM_VM_BIND_OP_MAP 1 +#define MSM_VM_BIND_OP_MAP_NULL 2 +#define MSM_VM_BIND_OP_DUMP 1 +#define MSM_VM_BIND_OP_FLAGS ( \ + MSM_VM_BIND_OP_DUMP | \ + 0) + +/** + * struct drm_msm_vm_bind_op - bind/unbind op to run + */ +struct drm_msm_vm_bind_op { + /** @op: one of MSM_VM_BIND_OP_x */ + __u32 op; + /** @handle: GEM object handle, MBZ for UNMAP or MAP_NULL */ + __u32 handle; + /** @obj_offset: Offset into GEM object, MBZ for UNMAP or MAP_NULL */ + __u64 obj_offset; + /** @iova: Address to operate on */ + __u64 iova; + /** @range: Number of bites to to map/unmap */ + __u64 range; + /** @flags: Bitmask of MSM_VM_BIND_OP_FLAG_x */ + __u32 flags; + /** @pad: MBZ */ + __u32 pad; +}; + +#define MSM_VM_BIND_FENCE_FD_IN 0x00000001 +#define MSM_VM_BIND_FENCE_FD_OUT 0x00000002 +#define MSM_VM_BIND_FLAGS ( \ + MSM_VM_BIND_FENCE_FD_IN | \ + MSM_VM_BIND_FENCE_FD_OUT | \ + 0) + +/** + * struct drm_msm_vm_bind - Input of &DRM_IOCTL_MSM_VM_BIND + */ +struct drm_msm_vm_bind { + /** @flags: in, bitmask of MSM_VM_BIND_x */ + __u32 flags; + /** @nr_ops: the number of bind ops in this ioctl */ + __u32 nr_ops; + /** @fence_fd: in/out fence fd (see MSM_VM_BIND_FENCE_FD_IN/OUT) */ + __s32 fence_fd; + /** @queue_id: in, submitqueue id */ + __u32 queue_id; + /** @in_syncobjs: in, ptr to array of drm_msm_gem_syncobj */ + __u64 in_syncobjs; + /** @out_syncobjs: in, ptr to array of drm_msm_gem_syncobj */ + __u64 out_syncobjs; + /** @nr_in_syncobjs: in, number of entries in in_syncobj */ + __u32 nr_in_syncobjs; + /** @nr_out_syncobjs: in, number of entries in out_syncobj */ + __u32 nr_out_syncobjs; + /** @syncobj_stride: in, stride of syncobj arrays */ + __u32 syncobj_stride; + /** @op_stride: sizeof each struct drm_msm_vm_bind_op in @ops */ + __u32 op_stride; + union { + /** @op: used if num_ops == 1 */ + struct drm_msm_vm_bind_op op; + /** @ops: userptr to array of drm_msm_vm_bind_op if num_ops > 1 */ + __u64 ops; + }; }; #define MSM_WAIT_FENCE_BOOST 0x00000001 @@ -344,10 +456,20 @@ struct drm_msm_gem_madvise { /* * Draw queues allow the user to set specific submission parameter. Command * submissions specify a specific submitqueue to use. ID 0 is reserved for - * backwards compatibility as a "default" submitqueue + * backwards compatibility as a "default" submitqueue. + * + * Because VM_BIND async updates happen on the CPU, they must run on a + * virtual queue created with the flag MSM_SUBMITQUEUE_VM_BIND. If we had + * a way to do pgtable updates on the GPU, we could drop this restriction. */ -#define MSM_SUBMITQUEUE_FLAGS (0) +#define MSM_SUBMITQUEUE_ALLOW_PREEMPT 0x00000001 +#define MSM_SUBMITQUEUE_VM_BIND 0x00000002 /* virtual queue for VM_BIND ops */ + +#define MSM_SUBMITQUEUE_FLAGS ( \ + MSM_SUBMITQUEUE_ALLOW_PREEMPT | \ + MSM_SUBMITQUEUE_VM_BIND | \ + 0) /* * The submitqueue priority should be between 0 and MSM_PARAM_PRIORITIES-1, @@ -369,6 +491,52 @@ struct drm_msm_submitqueue_query { __u32 pad; }; +#define MSM_PERFCNTR_STREAM 0x00000001 +#define MSM_PERFCNTR_UPDATE 0x00000002 +#define MSM_PERFCNTR_FLAGS ( \ + MSM_PERFCNTR_STREAM | \ + MSM_PERFCNTR_UPDATE | \ + 0) + +struct drm_msm_perfcntr_group { + char group_name[16]; + __u32 nr_countables; + __u32 pad; /* mbz */ + __u64 countables; /* pointer to an array of nr_countables u32 */ +}; + +/* + * Note, for MSM_PERFCNTR_STREAM, the ioctl returns an fd to read recorded + * counters. This only works because the ioctl is DRM_IOW(), if we returned + * a out param in the ioctl struct the copy_to_user() (in drm_ioctl()) + * could fault, causing us to leak the fd. + * + * If the ioctl returns with error E2BIG, that means more counters/countables + * are requested than are currently available. If MSM_PERFCNTR_UPDATE flag + * is set, drm_msm_perfcntr_group::nr_countables will be updated to return + * the actual # of counters available. + * + * The data read from the has the following format for each sampling period: + * + * uint64_t timestamp; // CP_ALWAYS_ON_COUNTER captured at sample time + * uint32_t seqno; // increments by 1 each period, reset to 0 on discontinuity + * uint32_t mbz; // pad out counters to 64b + * struct { + * uint64_t counter[nr_countables]; + * } groups[nr_groups]; + * + * The ordering of groups and counters matches the order in PERFCNTR_CONFIG + * ioctl. + */ +struct drm_msm_perfcntr_config { + __u32 flags; /* bitmask of MSM_PERFCNTR_x */ + __u32 nr_groups; /* # of entries in groups array */ + __u64 groups; /* pointer to array of drm_msm_perfcntr_group */ + __u64 period; /* sampling period in ns */ + __u32 bufsz_shift; /* sample buffer size in bytes is 1<<bufsz_shift */ + __u32 group_stride; /* sizeof(struct drm_msm_perfcntr_group) */ +}; + #define DRM_MSM_GET_PARAM 0x00 #define DRM_MSM_SET_PARAM 0x01 #define DRM_MSM_GEM_NEW 0x02 @@ -384,6 +552,8 @@ struct drm_msm_submitqueue_query { #define DRM_MSM_SUBMITQUEUE_NEW 0x0A #define DRM_MSM_SUBMITQUEUE_CLOSE 0x0B #define DRM_MSM_SUBMITQUEUE_QUERY 0x0C +#define DRM_MSM_VM_BIND 0x0D +#define DRM_MSM_PERFCNTR_CONFIG 0x0E #define DRM_IOCTL_MSM_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GET_PARAM, struct drm_msm_param) #define DRM_IOCTL_MSM_SET_PARAM DRM_IOW (DRM_COMMAND_BASE + DRM_MSM_SET_PARAM, struct drm_msm_param) @@ -397,6 +567,8 @@ struct drm_msm_submitqueue_query { #define DRM_IOCTL_MSM_SUBMITQUEUE_NEW DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_SUBMITQUEUE_NEW, struct drm_msm_submitqueue) #define DRM_IOCTL_MSM_SUBMITQUEUE_CLOSE DRM_IOW (DRM_COMMAND_BASE + DRM_MSM_SUBMITQUEUE_CLOSE, __u32) #define DRM_IOCTL_MSM_SUBMITQUEUE_QUERY DRM_IOW (DRM_COMMAND_BASE + DRM_MSM_SUBMITQUEUE_QUERY, struct drm_msm_submitqueue_query) +#define DRM_IOCTL_MSM_VM_BIND DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_VM_BIND, struct drm_msm_vm_bind) +#define DRM_IOCTL_MSM_PERFCNTR_CONFIG DRM_IOW (DRM_COMMAND_BASE + DRM_MSM_PERFCNTR_CONFIG, struct drm_msm_perfcntr_config) #if defined(__cplusplus) } -- 2.54.0 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 2/2] tests/msm: Add perfcntrs test 2026-07-03 14:39 [PATCH 0/2] tests/msm: Add PERFCNTR_CONFIG ioctl Rob Clark 2026-07-03 14:39 ` [PATCH 1/2] drm-uapi: Sync msm_drm.h Rob Clark @ 2026-07-03 14:39 ` Rob Clark 2026-07-06 12:23 ` Kamil Konieczny 1 sibling, 1 reply; 4+ messages in thread From: Rob Clark @ 2026-07-03 14:39 UTC (permalink / raw) To: igt-dev; +Cc: freedreno, Rob Clark Add tests for new PERFCNTR_CONFIG ioctl. Signed-off-by: Rob Clark <rob.clark@oss.qualcomm.com> --- tests/msm/meson.build | 1 + tests/msm/msm_perfcntrs.c | 194 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+) create mode 100644 tests/msm/msm_perfcntrs.c diff --git a/tests/msm/meson.build b/tests/msm/meson.build index 2ba5b4db2279..0a7f35662c03 100644 --- a/tests/msm/meson.build +++ b/tests/msm/meson.build @@ -1,6 +1,7 @@ msm_progs = [ 'msm_bo', 'msm_mapping', + 'msm_perfcntrs', 'msm_recovery', 'msm_shrink', 'msm_submit', diff --git a/tests/msm/msm_perfcntrs.c b/tests/msm/msm_perfcntrs.c new file mode 100644 index 000000000000..7dab92b5c6bc --- /dev/null +++ b/tests/msm/msm_perfcntrs.c @@ -0,0 +1,194 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include <errno.h> + +#include "igt.h" +#include "igt_core.h" +#include "igt_msm.h" +#include "msm_drm.h" + +static int +__configure_counters(struct msm_device *dev, bool global, unsigned nr_groups, + const char **groups, unsigned count) +{ + uint32_t countables[count] = {}; /* selecting countable 0 for each counter is fine */ + struct drm_msm_perfcntr_group group[nr_groups]; + struct drm_msm_perfcntr_config req = { + .flags = global ? MSM_PERFCNTR_STREAM : 0, + .nr_groups = nr_groups, + .groups = VOID2U64(group), + .period = global ? NSEC_PER_SEC : 0, + .bufsz_shift = global ? 10 : 0, + .group_stride = sizeof(struct drm_msm_perfcntr_group), + }; + + memset(group, 0, sizeof(group)); + + for (unsigned i = 0; i < nr_groups; i++) { + strcpy(group[i].group_name, groups[i]); + group[i].nr_countables = count; + group[i].countables = global ? VOID2U64(countables) : 0; + } + + return drmIoctl(dev->fd, DRM_IOCTL_MSM_PERFCNTR_CONFIG, &req); +} + +static int +configure_counters(struct msm_device *dev, bool global, unsigned count) +{ + /* CP group is present on all gens.. SP would be another good candidate */ + const char *groups[] = {"CP"}; + return __configure_counters(dev, global, 1, groups, count); +} + +static unsigned +get_available_counters(struct msm_device *dev, bool global) +{ + for (unsigned i = 0; ; i++) { + int ret = configure_counters(dev, global, i + 1); + igt_warn("%u: ret=%d\n", i, ret); + if (ret < 0) + return i; + if (global) + close(ret); + } +} + + +int igt_main() +{ + /* device instance for global counter collection: */ + struct msm_device *dev_global = NULL; + /* device instances for local counter reservation: */ + struct msm_device *dev_local_1 = NULL; + struct msm_device *dev_local_2 = NULL; + unsigned num_counters; + + igt_fixture() { + dev_global = igt_msm_dev_open(); + dev_local_1 = igt_msm_dev_open(); + dev_local_2 = igt_msm_dev_open(); + + num_counters = get_available_counters(dev_global, true); + igt_info("num_counters=%u\n", num_counters); + } + + igt_describe("Multiple process should be able to reserve the same " + "counters for local counter collection"); + igt_subtest("perfcntrs-local-coexist") { + igt_require(num_counters > 0); + + igt_assert_eq(0, configure_counters(dev_local_1, false, num_counters)); + igt_assert_eq(0, configure_counters(dev_local_2, false, num_counters)); + + /* release the reservations: */ + configure_counters(dev_local_1, false, 0); + configure_counters(dev_local_2, false, 0); + } + + igt_describe("non-conflict global and local counters"); + igt_subtest("perfcntrs-non-conflict-global-local") { + int num_local = num_counters - 2; + int stream_fd; + + igt_require(num_counters > 2); + + igt_assert_eq(0, configure_counters(dev_local_1, false, num_local)); + igt_assert_eq(0, configure_counters(dev_local_2, false, num_local)); + + stream_fd = configure_counters(dev_global, true, 2); + igt_assert_lte(0, stream_fd); + close(stream_fd); + + /* release the reservations: */ + configure_counters(dev_local_1, false, 0); + configure_counters(dev_local_2, false, 0); + } + + igt_describe("conflict, local first"); + igt_subtest("conflict-local-first") { + int num_local = num_counters - 1; + int stream_fd; + + igt_require(num_counters > 2); + + igt_assert_eq(0, configure_counters(dev_local_1, false, num_local)); + igt_assert_eq(0, configure_counters(dev_local_2, false, num_local)); + + stream_fd = configure_counters(dev_global, true, 2); + igt_assert_lt(stream_fd, 0); + + /* release the reservation for dev_local_1: */ + configure_counters(dev_local_1, false, 0); + + /* should still fail: */ + stream_fd = configure_counters(dev_global, true, 2); + igt_assert_lt(stream_fd, 0); + + /* release the reservation for dev_local_2: */ + configure_counters(dev_local_2, false, 0); + + /* now should succeed: */ + stream_fd = configure_counters(dev_global, true, 2); + igt_assert_lte(0, stream_fd); + close(stream_fd); + } + + igt_describe("conflict, global first"); + igt_subtest("conflict-global-first") { + int num_local = num_counters - 1; + int stream_fd; + + igt_require(num_counters > 2); + + stream_fd = configure_counters(dev_global, true, 2); + igt_assert_lte(0, stream_fd); + + /* Should fail because two counters already allocated for global collection: */ + igt_assert_neq(0, configure_counters(dev_local_1, false, num_local)); + + /* release global counters: */ + close(stream_fd); + + /* Now reservation should succeed: */ + igt_assert_eq(0, configure_counters(dev_local_1, false, num_local)); + + /* release the reservations: */ + configure_counters(dev_local_1, false, 0); + } + + igt_describe("multiple groups"); + igt_subtest("multiple-groups") { + const char *groups[] = {"CP", "SP"}; + + igt_require(num_counters > 0); + + igt_assert_eq(0, + __configure_counters(dev_local_1, false, ARRAY_SIZE(groups), groups, 1)); + + /* release the reservations: */ + configure_counters(dev_local_1, false, 0); + } + + igt_describe("duplicate groups"); + igt_subtest("duplicate-groups") { + const char *groups[] = {"CP", "CP"}; + + igt_require(num_counters > 0); + + igt_assert_neq(0, + __configure_counters(dev_local_1, false, ARRAY_SIZE(groups), groups, 1)); + + /* release the reservations: */ + configure_counters(dev_local_1, false, 0); + } + + igt_fixture() { + igt_msm_dev_close(dev_global); + igt_msm_dev_close(dev_local_1); + igt_msm_dev_close(dev_local_2); + } +} -- 2.54.0 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH 2/2] tests/msm: Add perfcntrs test 2026-07-03 14:39 ` [PATCH 2/2] tests/msm: Add perfcntrs test Rob Clark @ 2026-07-06 12:23 ` Kamil Konieczny 0 siblings, 0 replies; 4+ messages in thread From: Kamil Konieczny @ 2026-07-06 12:23 UTC (permalink / raw) To: Rob Clark; +Cc: igt-dev, freedreno Hi Rob, On 2026-07-03 at 07:39:49 -0700, Rob Clark wrote: > Add tests for new PERFCNTR_CONFIG ioctl. > > Signed-off-by: Rob Clark <rob.clark@oss.qualcomm.com> Your series do not compile on arm64 docker image. [1451/1760] Compiling C object tests/msm/msm_perfcntrs.p/msm_perfcntrs.c.o FAILED: tests/msm/msm_perfcntrs.p/msm_perfcntrs.c.o ... msm_perfcntrs.p/msm_perfcntrs.c.o.d -o tests/msm/msm_perfcntrs.p/msm_perfcntrs.c.o -c ../tests/msm/msm_perfcntrs.c ../tests/msm/msm_perfcntrs.c: In function '__configure_counters': ../tests/msm/msm_perfcntrs.c:17:2: error: variable-sized object may not be initialized 17 | uint32_t countables[count] = {}; /* selecting countable 0 for each counter is fine */ | ^~~~~~~~ ninja: build stopped: subcommand failed. Regards, Kamil > --- > tests/msm/meson.build | 1 + > tests/msm/msm_perfcntrs.c | 194 ++++++++++++++++++++++++++++++++++++++ > 2 files changed, 195 insertions(+) > create mode 100644 tests/msm/msm_perfcntrs.c > > diff --git a/tests/msm/meson.build b/tests/msm/meson.build > index 2ba5b4db2279..0a7f35662c03 100644 > --- a/tests/msm/meson.build > +++ b/tests/msm/meson.build > @@ -1,6 +1,7 @@ > msm_progs = [ > 'msm_bo', > 'msm_mapping', > + 'msm_perfcntrs', > 'msm_recovery', > 'msm_shrink', > 'msm_submit', > diff --git a/tests/msm/msm_perfcntrs.c b/tests/msm/msm_perfcntrs.c > new file mode 100644 > index 000000000000..7dab92b5c6bc > --- /dev/null > +++ b/tests/msm/msm_perfcntrs.c > @@ -0,0 +1,194 @@ > +// SPDX-License-Identifier: MIT > +/* > + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. > + */ > + > +#include <errno.h> > + > +#include "igt.h" > +#include "igt_core.h" > +#include "igt_msm.h" > +#include "msm_drm.h" > + > +static int > +__configure_counters(struct msm_device *dev, bool global, unsigned nr_groups, > + const char **groups, unsigned count) > +{ > + uint32_t countables[count] = {}; /* selecting countable 0 for each counter is fine */ > + struct drm_msm_perfcntr_group group[nr_groups]; > + struct drm_msm_perfcntr_config req = { > + .flags = global ? MSM_PERFCNTR_STREAM : 0, > + .nr_groups = nr_groups, > + .groups = VOID2U64(group), > + .period = global ? NSEC_PER_SEC : 0, > + .bufsz_shift = global ? 10 : 0, > + .group_stride = sizeof(struct drm_msm_perfcntr_group), > + }; > + > + memset(group, 0, sizeof(group)); > + > + for (unsigned i = 0; i < nr_groups; i++) { > + strcpy(group[i].group_name, groups[i]); > + group[i].nr_countables = count; > + group[i].countables = global ? VOID2U64(countables) : 0; > + } > + > + return drmIoctl(dev->fd, DRM_IOCTL_MSM_PERFCNTR_CONFIG, &req); > +} > + > +static int > +configure_counters(struct msm_device *dev, bool global, unsigned count) > +{ > + /* CP group is present on all gens.. SP would be another good candidate */ > + const char *groups[] = {"CP"}; > + return __configure_counters(dev, global, 1, groups, count); > +} > + > +static unsigned > +get_available_counters(struct msm_device *dev, bool global) > +{ > + for (unsigned i = 0; ; i++) { > + int ret = configure_counters(dev, global, i + 1); > + igt_warn("%u: ret=%d\n", i, ret); > + if (ret < 0) > + return i; > + if (global) > + close(ret); > + } > +} > + > + > +int igt_main() > +{ > + /* device instance for global counter collection: */ > + struct msm_device *dev_global = NULL; > + /* device instances for local counter reservation: */ > + struct msm_device *dev_local_1 = NULL; > + struct msm_device *dev_local_2 = NULL; > + unsigned num_counters; > + > + igt_fixture() { > + dev_global = igt_msm_dev_open(); > + dev_local_1 = igt_msm_dev_open(); > + dev_local_2 = igt_msm_dev_open(); > + > + num_counters = get_available_counters(dev_global, true); > + igt_info("num_counters=%u\n", num_counters); > + } > + > + igt_describe("Multiple process should be able to reserve the same " > + "counters for local counter collection"); > + igt_subtest("perfcntrs-local-coexist") { > + igt_require(num_counters > 0); > + > + igt_assert_eq(0, configure_counters(dev_local_1, false, num_counters)); > + igt_assert_eq(0, configure_counters(dev_local_2, false, num_counters)); > + > + /* release the reservations: */ > + configure_counters(dev_local_1, false, 0); > + configure_counters(dev_local_2, false, 0); > + } > + > + igt_describe("non-conflict global and local counters"); > + igt_subtest("perfcntrs-non-conflict-global-local") { > + int num_local = num_counters - 2; > + int stream_fd; > + > + igt_require(num_counters > 2); > + > + igt_assert_eq(0, configure_counters(dev_local_1, false, num_local)); > + igt_assert_eq(0, configure_counters(dev_local_2, false, num_local)); > + > + stream_fd = configure_counters(dev_global, true, 2); > + igt_assert_lte(0, stream_fd); > + close(stream_fd); > + > + /* release the reservations: */ > + configure_counters(dev_local_1, false, 0); > + configure_counters(dev_local_2, false, 0); > + } > + > + igt_describe("conflict, local first"); > + igt_subtest("conflict-local-first") { > + int num_local = num_counters - 1; > + int stream_fd; > + > + igt_require(num_counters > 2); > + > + igt_assert_eq(0, configure_counters(dev_local_1, false, num_local)); > + igt_assert_eq(0, configure_counters(dev_local_2, false, num_local)); > + > + stream_fd = configure_counters(dev_global, true, 2); > + igt_assert_lt(stream_fd, 0); > + > + /* release the reservation for dev_local_1: */ > + configure_counters(dev_local_1, false, 0); > + > + /* should still fail: */ > + stream_fd = configure_counters(dev_global, true, 2); > + igt_assert_lt(stream_fd, 0); > + > + /* release the reservation for dev_local_2: */ > + configure_counters(dev_local_2, false, 0); > + > + /* now should succeed: */ > + stream_fd = configure_counters(dev_global, true, 2); > + igt_assert_lte(0, stream_fd); > + close(stream_fd); > + } > + > + igt_describe("conflict, global first"); > + igt_subtest("conflict-global-first") { > + int num_local = num_counters - 1; > + int stream_fd; > + > + igt_require(num_counters > 2); > + > + stream_fd = configure_counters(dev_global, true, 2); > + igt_assert_lte(0, stream_fd); > + > + /* Should fail because two counters already allocated for global collection: */ > + igt_assert_neq(0, configure_counters(dev_local_1, false, num_local)); > + > + /* release global counters: */ > + close(stream_fd); > + > + /* Now reservation should succeed: */ > + igt_assert_eq(0, configure_counters(dev_local_1, false, num_local)); > + > + /* release the reservations: */ > + configure_counters(dev_local_1, false, 0); > + } > + > + igt_describe("multiple groups"); > + igt_subtest("multiple-groups") { > + const char *groups[] = {"CP", "SP"}; > + > + igt_require(num_counters > 0); > + > + igt_assert_eq(0, > + __configure_counters(dev_local_1, false, ARRAY_SIZE(groups), groups, 1)); > + > + /* release the reservations: */ > + configure_counters(dev_local_1, false, 0); > + } > + > + igt_describe("duplicate groups"); > + igt_subtest("duplicate-groups") { > + const char *groups[] = {"CP", "CP"}; > + > + igt_require(num_counters > 0); > + > + igt_assert_neq(0, > + __configure_counters(dev_local_1, false, ARRAY_SIZE(groups), groups, 1)); > + > + /* release the reservations: */ > + configure_counters(dev_local_1, false, 0); > + } > + > + igt_fixture() { > + igt_msm_dev_close(dev_global); > + igt_msm_dev_close(dev_local_1); > + igt_msm_dev_close(dev_local_2); > + } > +} > -- > 2.54.0 > ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-07-06 12:24 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-07-03 14:39 [PATCH 0/2] tests/msm: Add PERFCNTR_CONFIG ioctl Rob Clark 2026-07-03 14:39 ` [PATCH 1/2] drm-uapi: Sync msm_drm.h Rob Clark 2026-07-03 14:39 ` [PATCH 2/2] tests/msm: Add perfcntrs test Rob Clark 2026-07-06 12:23 ` Kamil Konieczny
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox