Igt-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Iago Toral <itoral@igalia.com>
To: "Maíra Canal" <mcanal@igalia.com>,
	"Melissa Wen" <mwen@igalia.com>,
	"Kamil Konieczny" <kamil.konieczny@linux.intel.com>,
	"Juha-Pekka Heikkila" <juhapekka.heikkila@gmail.com>,
	"Bhanuprakash Modem" <bhanuprakash.modem@gmail.com>,
	"Ashutosh Dixit" <ashutosh.dixit@intel.com>,
	"Karthik B S" <karthik.b.s@intel.com>
Cc: igt-dev@lists.freedesktop.org, kernel-dev@igalia.com
Subject: Re: [PATCH i-g-t 5/5] tests/v3d_perfmon: Add global perfmon and counter isolation tests
Date: Tue, 12 May 2026 08:50:20 +0200	[thread overview]
Message-ID: <9ded122232024d0d4e9d18cd7267196b6471a745.camel@igalia.com> (raw)
In-Reply-To: <20260508124446.1260672-7-mcanal@igalia.com>

Hi Maíra,

patches 1-4 are:

Reviewed-by: Iago Toral Quiroga <itoral@igalia.com>

For patch 5, I have some comments below:

El vie, 08-05-2026 a las 09:42 -0300, Maíra Canal escribió:

(...)
> +	igt_describe("Make sure that the global perfmon is tracking
> all jobs consistently.");
> +	igt_subtest("global-perfmon-valid-perfmon") {
> +		struct drm_v3d_perfmon_set_global set_global = { 0
> };
> +		struct v3d_cl_job *job = igt_v3d_noop_job(fd);
> +		uint64_t *values1, *values2;
> +		uint32_t id, out_sync;
> +		uint8_t counters[2];
> +
> +		/*
> +		 * Different V3D versions have different performance
> counters
> +		 * IDs for the same counters.
> +		 */
> +		if (ver >= 71) {
> +			counters[0] = 0; /* cycle-count */
> +			counters[1] = 1; /* core-active */
> +		} else if (ver >= 42) {
> +			counters[0] = V3D_PERFCNT_CYCLE_COUNT;
> +			counters[1] = V3D_PERFCNT_CLE_ACTIVE;
> +		} else
> +			igt_abort_on_f(true, "This V3D version is
> not supported.");
> +
> +		id = igt_v3d_perfmon_create(fd,
> ARRAY_SIZE(counters), counters);
> +
> +		values1 = calloc(ARRAY_SIZE(counters),
> sizeof(*values1));
> +		values2 = calloc(ARRAY_SIZE(counters),
> sizeof(*values2));
> +
> +		set_global.id = id;
> +		do_ioctl(fd, DRM_IOCTL_V3D_PERFMON_SET_GLOBAL,
> &set_global);
> +
> +		igt_v3d_perfmon_get_values(fd, id, values1);
> +
> +		out_sync = syncobj_create(fd, 0);
> +		job->submit->out_sync = out_sync;
> +
> +		/* Submit an arbitrary number of CL jobs to stress
> the perfcnts. */
> +		for (int i = 0; i < 10; i++)
> +			do_ioctl(fd, DRM_IOCTL_V3D_SUBMIT_CL, job-
> >submit);
> +
> +		/* Wait for the last job to complete so counters are
> captured. */
> +		igt_assert(syncobj_wait(fd, &out_sync, 1, INT64_MAX,
> 0, NULL));

If the intent was to wait for all jobs to complete, should we not move
the syncobj_wait into the loop above and reset the syncobj after each
iteration? Otherwise I think this is only really waiting for the first
job's completion. Alternatively, you can set out_sync only for the last
job instead.

> +
> +		igt_v3d_perfmon_get_values(fd, id, values2);
> +
> +		/* As the global perfmon is active, the cycle-count
> must have
> +		 * increased with time.
> +		 */
> +		for (int i = 0; i < ARRAY_SIZE(counters); i++)
> +			igt_assert_lt(values1[i], values2[i]);
> +
> +		set_global.flags = DRM_V3D_PERFMON_CLEAR_GLOBAL;
> +		do_ioctl(fd, DRM_IOCTL_V3D_PERFMON_SET_GLOBAL,
> &set_global);
> +
> +		igt_v3d_perfmon_get_values(fd, id, values1);
> +
> +		/* Submit an arbitrary number of CL jobs to stress
> the perfcnts. */
> +		for (int i = 0; i < 10; i++)
> +			do_ioctl(fd, DRM_IOCTL_V3D_SUBMIT_CL, job-
> >submit);
> +

I think we would also want wait for completion of the jobs here before
retrieving the values below.

> +		igt_v3d_perfmon_get_values(fd, id, values2);
> +
> +		/* As the global perfmon was cleared, the perfmon is
> inactive
> +		 * and it must preserve its values.
> +		 */
> +		for (int i = 0; i < ARRAY_SIZE(counters); i++)
> +			igt_assert_eq(values1[i], values2[i]);
> +
> +		igt_v3d_perfmon_destroy(fd, id);
> +
> +		syncobj_destroy(fd, out_sync);
> +		igt_v3d_free_cl_job(fd, job);
> +
> +		free(values1);
> +		free(values2);
> +	}
> +
> +	igt_describe("Make sure that a global perfmon tracks jobs
> from other file descriptors.");
> +	igt_subtest("global-perfmon-multifd") {
> +		struct drm_v3d_perfmon_set_global set_global = { 0
> },
> +						  set_global2 = { 0
> };
> +		int fd2 = drm_open_driver_render(DRIVER_V3D);
> +		struct v3d_cl_job *job = igt_v3d_noop_job(fd2);
> +		uint32_t id1, id2, out_sync;
> +		uint64_t values1, values2;
> +		uint8_t counter;
> +
> +		/*
> +		 * Different V3D versions have different performance
> counters
> +		 * IDs for the same counters.
> +		 */
> +		if (ver >= 71)
> +			counter = 0; /* cycle-count */
> +		else if (ver >= 42)
> +			counter = V3D_PERFCNT_CYCLE_COUNT;
> +		else
> +			igt_abort_on_f(true, "This V3D version is
> not supported.");
> +
> +		/* Create and set global perfmon from fd. */
> +		id1 = igt_v3d_perfmon_create(fd, 1, &counter);
> +		set_global.id = id1;
> +		do_ioctl(fd, DRM_IOCTL_V3D_PERFMON_SET_GLOBAL,
> &set_global);
> +
> +		igt_v3d_perfmon_get_values(fd, id1, &values1);
> +
> +		/* Submit jobs from the second fd; the global
> perfmon should track them. */
> +		out_sync = syncobj_create(fd2, 0);
> +		job->submit->out_sync = out_sync;
> +		for (int i = 0; i < 10; i++)
> +			do_ioctl(fd2, DRM_IOCTL_V3D_SUBMIT_CL, job-
> >submit);
> +		igt_assert(syncobj_wait(fd2, &out_sync, 1,
> INT64_MAX, 0, NULL));
> +

Same issue here about using the same out_sync on all jobs.

> +		igt_v3d_perfmon_get_values(fd, id1, &values2);
> +		igt_assert_lt(values1, values2);
> +
> +		/* fd2 cannot set its own global perfmon while fd's
> is active. */
> +		id2 = igt_v3d_perfmon_create(fd2, 1, &counter);
> +		set_global2.id = id2;
> +		do_ioctl_err(fd2, DRM_IOCTL_V3D_PERFMON_SET_GLOBAL,
> &set_global2, EBUSY);
> +
> +		igt_v3d_perfmon_destroy(fd2, id2);
> +		igt_v3d_perfmon_destroy(fd, id1);
> +
> +		syncobj_destroy(fd2, out_sync);
> +		igt_v3d_free_cl_job(fd2, job);
> +
> +		drm_close_driver(fd2);
> +	}
> +
> +	igt_describe("Make sure closing a file descriptor with an
> active global "
> +		     "perfmon does not crash the driver.");
> +	igt_subtest("global-perfmon-destroy-multifd") {
> +		struct drm_v3d_perfmon_set_global set_global = { 0
> };
> +		struct v3d_cl_job *job = igt_v3d_noop_job(fd);
> +		int fd2 = drm_open_driver(DRIVER_V3D);
> +		uint32_t id, new_id, out_sync;
> +		uint8_t counter = 0;
> +
> +		/* Create and set global perfmon from fd2. */
> +		id = igt_v3d_perfmon_create(fd2, 1, &counter);
> +		set_global.id = id;
> +		do_ioctl(fd2, DRM_IOCTL_V3D_PERFMON_SET_GLOBAL,
> &set_global);
> +
> +		/* Keep HW busy from fd while fd2 is closed. */
> +		out_sync = syncobj_create(fd, 0);
> +		job->submit->out_sync = out_sync;
> +		for (int i = 0; i < 10; i++)
> +			do_ioctl(fd, DRM_IOCTL_V3D_SUBMIT_CL, job-
> >submit);
> +

Same here.


> +		/* Closing fd2 must cleanly stop the active global
> perfmon and
> +		 * clear the global perfmon without crashing.
> +		 */
> +		drm_close_driver(fd2);
> +
> +		igt_assert(syncobj_wait(fd, &out_sync, 1, INT64_MAX,
> 0, NULL));
> +
> +		/* fd can now set a new global perfmon without
> EBUSY. */
> +		new_id = igt_v3d_perfmon_create(fd, 1, &counter);
> +
> +		set_global.id = new_id;
> +		do_ioctl(fd, DRM_IOCTL_V3D_PERFMON_SET_GLOBAL,
> &set_global);
> +
> +		set_global.flags = DRM_V3D_PERFMON_CLEAR_GLOBAL;
> +		do_ioctl(fd, DRM_IOCTL_V3D_PERFMON_SET_GLOBAL,
> &set_global);
> +
> +		igt_v3d_perfmon_destroy(fd, new_id);
> +
> +		syncobj_destroy(fd, out_sync);
> +		igt_v3d_free_cl_job(fd, job);
> +	}
> +

(...)

> +
> +	igt_describe("Make sure a non-perfmon CL job submitted after
> a perfmon CL job "
> +		     "is serialized behind it and does not
> contaminate its counter values.");
> +	igt_subtest("perfmon-counter-isolation-subsequent-cl") {
> +		struct v3d_cl_job *job1 = igt_v3d_noop_job(fd);
> +		struct v3d_cl_job *job2 = igt_v3d_noop_job(fd);
> +		uint64_t id, values, values_after_j2;
> +		uint32_t blocker, out1, out2;
> +		int timeline, fence_fd;
> +		uint8_t counter;
> +
> +		igt_require_sw_sync();
> +
> +		/*
> +		 * Different V3D versions have different performance
> counters IDs
> +		 * for the same counters.
> +		 */
> +		if (ver >= 71)
> +			counter = 0; /* cycle-count */
> +		else if (ver >= 42)
> +			counter = V3D_PERFCNT_CYCLE_COUNT;
> +		else
> +			igt_abort_on_f(true, "This V3D version is
> not supported.");
> +
> +		id = igt_v3d_perfmon_create(fd, 1, &counter);
> +
> +		/*
> +		 * Create an unsignaled fence via sw_sync. job1 will
> wait on
> +		 * this fence and stay blocked until we increment
> the timeline.
> +		 */
> +		timeline = sw_sync_timeline_create();
> +		fence_fd = sw_sync_timeline_create_fence(timeline,
> 1);
> +
> +		blocker = syncobj_create(fd, 0);
> +		syncobj_import_sync_file(fd, blocker, fence_fd);
> +		close(fence_fd);
> +
> +		out1 = syncobj_create(fd, 0);
> +		out2 = syncobj_create(fd, 0);
> +
> +		/* job1: BIN job is blocked until we signal the
> blocker. */
> +		job1->submit->in_sync_bcl = blocker;
> +		job1->submit->perfmon_id = id;
> +		job1->submit->out_sync = out1;
> +		do_ioctl(fd, DRM_IOCTL_V3D_SUBMIT_CL, job1->submit);
> +
> +		/* job2: no perfmon, must wait for job1 due to job
> serialization. */
> +		job2->submit->out_sync = out2;
> +		do_ioctl(fd, DRM_IOCTL_V3D_SUBMIT_CL, job2->submit);
> +
> +		/* job2 is serialized behind job1, so it cannot have
> completed yet. */
> +		igt_assert_eq(syncobj_wait_err(fd, &out2, 1, 0, 0),
> -ETIME);
> +
> +		/* While job1 has not started, the perfmon must
> still read zero. */
> +		igt_v3d_perfmon_get_values(fd, id, &values);
> +		igt_assert_eq(values, 0);
> +
> +		/* Release the blocker. */
> +		sw_sync_timeline_inc(timeline, 1);
> +
> +		igt_assert(syncobj_wait(fd, &out1, 1, INT64_MAX, 0,
> NULL));
> +		igt_assert(syncobj_wait(fd, &out2, 1, INT64_MAX, 0,
> NULL));

I think that for the tests below to make sense you would want to move
the second wait after checking values for the first time....

> +
> +		/* job1 must have contributed cycles to the perfmon.
> */
> +		igt_v3d_perfmon_get_values(fd, id, &values);
> +		igt_assert_lt(0, values);

Otherwise, this is really checking potential contributions from both
jobs, not just job1.

> +
> +		/* job2 doesn't have a perfmon attached, so a second
> read must
> +		 * return the same value.
> +		 */
> +		igt_v3d_perfmon_get_values(fd, id,
> &values_after_j2);
> +		igt_assert_eq(values, values_after_j2);

And this is not really checking anything about job2, so it is always
going to give the same values.

> +
> +		close(timeline);
> +		syncobj_destroy(fd, blocker);
> +		syncobj_destroy(fd, out1);
> +		syncobj_destroy(fd, out2);
> +
> +		igt_v3d_perfmon_destroy(fd, id);
> +
> +		igt_v3d_free_cl_job(fd, job1);
> +		igt_v3d_free_cl_job(fd, job2);
> +	}
> +
>  	igt_fixture()
>  		drm_close_driver(fd);
>  }


  reply	other threads:[~2026-05-12  6:51 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-08 12:42 [PATCH i-g-t 0/5] tests/v3d_perfmon: Fix V3D 7.1 regression and extend perfmon testing Maíra Canal
2026-05-08 12:42 ` [PATCH i-g-t 1/5] tests/v3d_perfmon: Don't use the deprecated V3D_PERFCNT_NUM Maíra Canal
2026-05-08 12:42 ` [PATCH i-g-t 2/5] drm-uapi/v3d: Sync v3d UAPI Maíra Canal
2026-05-08 12:42 ` [PATCH i-g-t 3/5] lib/v3d: Allow callers to retrieve perfmon counter values Maíra Canal
2026-05-08 12:42 ` [PATCH i-g-t 4/5] lib/v3d: Add helper to query the V3D hardware version Maíra Canal
2026-05-08 12:42 ` [PATCH i-g-t 5/5] tests/v3d_perfmon: Add global perfmon and counter isolation tests Maíra Canal
2026-05-12  6:50   ` Iago Toral [this message]
2026-05-09  0:21 ` ✓ i915.CI.BAT: success for tests/v3d_perfmon: Fix V3D 7.1 regression and extend perfmon testing Patchwork
2026-05-09  0:28 ` ✓ Xe.CI.BAT: " Patchwork
2026-05-09 13:32 ` ✗ Xe.CI.FULL: failure " Patchwork
2026-05-10  1:38 ` ✓ i915.CI.Full: success " Patchwork

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=9ded122232024d0d4e9d18cd7267196b6471a745.camel@igalia.com \
    --to=itoral@igalia.com \
    --cc=ashutosh.dixit@intel.com \
    --cc=bhanuprakash.modem@gmail.com \
    --cc=igt-dev@lists.freedesktop.org \
    --cc=juhapekka.heikkila@gmail.com \
    --cc=kamil.konieczny@linux.intel.com \
    --cc=karthik.b.s@intel.com \
    --cc=kernel-dev@igalia.com \
    --cc=mcanal@igalia.com \
    --cc=mwen@igalia.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox