[PATCH i-g-t 1/2] tests: Exercise intel_context_prepare_remote_request

Janusz Krzysztofik janusz.krzysztofik at linux.intel.com
Fri Feb 10 13:23:52 UTC 2023


Users reported oopses on list corruptions when using i915 perf with a
number of concurrently running graphics applications.  That indicates we
are currently missing some important tests for such scenarios.  Cover
that gap.

Root cause analysis pointed out to an issue in barrier processing code and
its interaction with perf replacing kernel contexts' active barriers with
its own requests.

Add a new test aimed on exercising intel_context_prepare_remote_request
internal function of i915 and its interaction with other i915 subsystems.
As a first subtest, add the one that exercises interaction of remote
requests with barrier handling, especially barrier preallocate / acquire
operations performed during context first pin / last unpin.

v3: create a new test hosting the new subtest, update commit descripion,
  - prepare parameters for perf open still in the main thread to avoid
    test failures on platforms with no perf support (will skip now).
v2: convert to a separate subtest, not a variant of another one (that has
    been dropped from the series),
  - move the subtest out of tests/i915/perf.c (Ashutosh), add it to
    tests/i915/gem_ctx_exec.c,
  - don't touch lib/i915/perf.c (Umesh, Ashutosh), duplicate reused code
    from tests/i915/perf.c in tests/i915/gem_ctx_exec.c.

References: https://gitlab.freedesktop.org/drm/intel/-/issues/6333
Signed-off-by: Janusz Krzysztofik <janusz.krzysztofik at linux.intel.com>
---
 tests/i915/gem_remote_request.c | 180 ++++++++++++++++++++++++++++++++
 tests/meson.build               |   8 ++
 2 files changed, 188 insertions(+)
 create mode 100644 tests/i915/gem_remote_request.c

diff --git a/tests/i915/gem_remote_request.c b/tests/i915/gem_remote_request.c
new file mode 100644
index 0000000000..06d970038d
--- /dev/null
+++ b/tests/i915/gem_remote_request.c
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright(c) 2023 Intel Corporation. All rights reserved.
+ */
+
+#include <stdint.h>
+
+#include "drmtest.h"
+#include "igt_aux.h"
+#include "igt_core.h"
+#include "igt_gt.h"
+#include "intel_chipset.h"
+#include "intel_reg.h"
+#include "ioctl_wrappers.h"
+
+#include "i915/gem.h"
+#include "i915/gem_create.h"
+#include "i915/gem_engine_topology.h"
+#include "i915/perf.h"
+
+IGT_TEST_DESCRIPTION("Exercise intel_contex_prepare_remote_request() and its interaction with other i915 subsystems");
+
+/* Derived from similar function found in tests/i915/perf.c */
+static uint64_t timebase_scale(struct intel_perf *intel_perf, uint32_t u32_delta)
+{
+	return ((uint64_t)u32_delta * NSEC_PER_SEC) / intel_perf->devinfo.timestamp_frequency;
+}
+
+/* Derived from similar function found in tests/i915/perf.c */
+static int max_oa_exponent_for_period_lte(struct intel_perf *intel_perf, uint64_t period)
+{
+	/* NB: timebase_scale() takes a uint32_t and an exponent of 30
+	 * would already represent a period of ~3 minutes so there's
+	 * really no need to consider higher exponents.
+	 */
+	for (int i = 0; i < 30; i++) {
+		uint64_t oa_period = timebase_scale(intel_perf, 2 << i);
+
+		if (oa_period > period)
+			return max(0, i - 1);
+	}
+
+	igt_assert(!"reached");
+	return -1;
+}
+
+/* Based on code patterns found in tests/i915/perf.c */
+static void perf_open_close_workload(int fd, int *done)
+{
+	struct intel_perf_metric_set *metric_set = NULL, *metric_set_iter;
+	struct intel_perf *intel_perf = intel_perf_for_fd(fd);
+	uint64_t properties[] = {
+		DRM_I915_PERF_PROP_SAMPLE_OA, true,
+		DRM_I915_PERF_PROP_OA_METRICS_SET, 0,
+		DRM_I915_PERF_PROP_OA_FORMAT, 0,
+		DRM_I915_PERF_PROP_OA_EXPONENT, 0,
+	};
+	struct drm_i915_perf_open_param param = {
+		.flags = I915_PERF_FLAG_FD_CLOEXEC,
+		.num_properties = sizeof(properties) / 16,
+		.properties_ptr = to_user_pointer(properties),
+	};
+	uint32_t devid = intel_get_drm_devid(fd);
+
+	igt_require(intel_perf);
+	intel_perf_load_perf_configs(intel_perf, fd);
+
+	igt_require(devid);
+	igt_list_for_each_entry(metric_set_iter, &intel_perf->metric_sets, link) {
+		if (!strcmp(metric_set_iter->symbol_name,
+			    IS_HASWELL(devid) ? "RenderBasic" : "TestOa")) {
+			metric_set = metric_set_iter;
+			break;
+		}
+	}
+	igt_require(metric_set);
+	igt_require(metric_set->perf_oa_metrics_set);
+	properties[3] = metric_set->perf_oa_metrics_set;
+	properties[5] = metric_set->perf_oa_format;
+
+	igt_require(intel_perf->devinfo.timestamp_frequency);
+	properties[7] = max_oa_exponent_for_period_lte(intel_perf, 1000);
+
+	intel_perf_free(intel_perf);
+
+	igt_fork(child, 1) {
+		do {
+			int stream = igt_ioctl(fd, DRM_IOCTL_I915_PERF_OPEN, &param);
+
+			igt_assert_fd(stream);
+			close(stream);
+
+		} while (!READ_ONCE(*done));
+	}
+}
+
+static void remote_request_workload(int fd, int *done)
+{
+	/* Use DRM_IOCTL_I915_PERF_OPEN / close */
+	perf_open_close_workload(fd, done);
+}
+
+/* Copied from tests/i915/gem_ctx_exec.c */
+static int exec(int fd, uint32_t handle, int ring, int ctx_id)
+{
+	struct drm_i915_gem_exec_object2 obj = { .handle = handle };
+	struct drm_i915_gem_execbuffer2 execbuf = {
+		.buffers_ptr = to_user_pointer(&obj),
+		.buffer_count = 1,
+		.flags = ring,
+	};
+
+	i915_execbuffer2_set_context_id(execbuf, ctx_id);
+
+	return __gem_execbuf(fd, &execbuf);
+}
+
+static void gem_create_exec_close_loop(int fd, struct intel_execution_engine2 *e, int *done)
+{
+	const uint32_t batch[2] = { 0, MI_BATCH_BUFFER_END };
+
+	fd = gem_reopen_driver(fd);
+
+	do {
+		uint32_t handle = gem_create(fd, 4096);
+
+		gem_write(fd, handle, 0, batch, sizeof(batch));
+		igt_assert_eq(exec(fd, handle, e->flags, 0), 0);
+
+		gem_sync(fd, handle);
+		gem_close(fd, handle);
+
+	} while (!READ_ONCE(*done));
+}
+
+
+static void test_barrier_race(int fd, struct intel_execution_engine2 *e, unsigned int timeout)
+{
+	int *done = mmap(0, 4096, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
+
+	igt_assert(done != MAP_FAILED);
+
+	remote_request_workload(fd, done);
+
+	igt_fork(child, sysconf(_SC_NPROCESSORS_ONLN)) {
+		/*
+		 * Use gem_create -> gem_write -> gem_execbuf -> gem_sync -> gem_close
+		 * as intel context first pin / last unpin intensive workload
+		 */
+		gem_create_exec_close_loop(fd, e, done);
+	}
+
+	sleep(timeout);
+	*done = 1;
+	igt_waitchildren();
+	munmap(done, 4096);
+}
+
+igt_main
+{
+	int fd;
+
+	igt_fixture {
+		fd = drm_open_driver_render(DRIVER_INTEL);
+		igt_require_gem(fd);
+	}
+
+	igt_describe("Race intel_context_prepare_remote_request against intel_context_active_acquire/release");
+	igt_subtest_with_dynamic("barrier-race") {
+		struct intel_execution_engine2 *e;
+
+		for_each_physical_engine(fd, e) {
+			if (e->flags != I915_ENGINE_CLASS_RENDER)
+				continue;
+
+			igt_dynamic(e->name)
+				test_barrier_race(fd, e, 5);
+		}
+	}
+}
diff --git a/tests/meson.build b/tests/meson.build
index 6fb1bb86c9..07846dcdc1 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -389,6 +389,14 @@ test_executables += executable('i915_pm_rc6_residency',
 	   install : true)
 test_list += 'i915_pm_rc6_residency'
 
+test_executables += executable('gem_remote_request',
+	   join_paths('i915', 'gem_remote_request.c'),
+	   dependencies : test_deps + [ lib_igt_i915_perf ],
+	   install_dir : libexecdir,
+	   install_rpath : libexecdir_rpathdir,
+	   install : true)
+test_list += 'gem_remote_request'
+
 test_executables += executable('perf_pmu',
 	   join_paths('i915', 'perf_pmu.c'),
 	   dependencies : test_deps + [ lib_igt_perf ],
-- 
2.25.1



More information about the Intel-gfx-trybot mailing list