* [PATCH 00/66] Test coverage for GPU debug support
@ 2024-07-29 16:00 Christoph Manszewski
2024-07-29 16:00 ` [PATCH 01/66] tests/xe_eudebug: Test eudebug connection Christoph Manszewski
` (67 more replies)
0 siblings, 68 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:00 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
Hi,
In this series the eudebug kernel and validation team would like to
add test coverage for GPU debug support recently proposed as an RFC.
(https://patchwork.freedesktop.org/series/136572/)
This series adds 'xe_eudebug' and 'xe_eudebug_online' tests together
with a library that encapsulates common paths in current and future
EU debugger scenarios. It also extends the 'xe_exec_sip' test and
'gpgpu_shader' library.
The aim of the 'xe_eudebug' test is to validate the eudebug resource
tracking and event delivery mechanism. The 'xe_eudebug_online' test is
dedicated for 'online' scenarios which means scenarios that exercise
hardware exception handling and thread state manipulation.
The xe_eudebug library provides an abstraction over debugger and debuggee
processes, asynchronous event reader, and event log buffers for post-mortem
analysis.
Latest kernel code can be found here:
https://gitlab.freedesktop.org/miku/kernel/-/commits/eudebug-dev
Thank you in advance for any comments and insight.
Andrzej Hajda (6):
tests/xe_eudebug: Add userptr variant of basic-vm-access test
lib/gpgpu_shader: Add write_on_exception template
lib/gpgpu_shader: Add set/clear exception register (cr0.1) helpers
lib/intel_batchbuffer: Add helper to get pointer at specified offset
lib/gpgpu_shader: Allow enabling illegal opcode exceptions in shader
tests/xe_exec_sip: Rework invalid instruction tests
Christoph Manszewski (17):
lib/xe_ioctl: Add wrapper with vm_bind_op extension parameter
lib/xe_eudebug: Add support for vm_bind events
lib/xe_eudebug: Add support for user fence acking
lib/xe_eudebug: Add support for dynamic debugger sysfs toggle
tests/xe_eudebug: Add basic vm-bind coverage
tests/xe_eudebug: Add support for dynamic debugger sysfs toggle
tests/xe_eudebug: Add coverage for sysfs debugger toggle
lib/xe_eudebug: Allow debugger to wait for client
tests/xe_eudebug: Add vm-bind discovery tests
tests/xe_eudebug: Add basic-vm-bind-ufence
tests/xe_eudebug: Add vm-bind-clear test
lib/gpgpu_shader: Extend shader building library
tests/xe_exec_sip: Port tests for shaders and sip
tests/xe_exec_sip: Add support for dynamic debugger sysfs toggle
tests/xe_eudebug_online: Add support for dynamic debugger sysfs toggle
tests/xe_eudebug_online: Add subtests w/o long running mode
tests/xe_live_ktest: Add xe_eudebug live test
Dominik Grzegorzek (18):
tests/xe_eudebug: Test eudebug connection
lib/xe_eudebug: Introduce eu debug testing framework
lib/xe_eudebug: Add exec_queue support
lib/xe_eudebug: Add attention events support
lib/xe_eudebug: Add metadata support
tests/xe_eudebug: Test open close events
tests/xe_eudebug: Exercise read_event ioctl
tests/xe_eudebug: Add vm events sanity check
tests/xe_eudebug: Race discovery against eudebug attach.
tests/xe_eudebug: Add TEST/SUBTEST documentation
tests/xe_eudebug: Introduce basic exec_queue testing
tests/xe_eudebug: Include exec queues in discovery testing
tests/xe_exec_sip: Check if we reset due to unhandled attention
tests/xe_exec_sip: Check usercoredump for attentions
tests/xe_eudebug_online: Debug client which runs workloads on EU
tests/xe_eudebug_online: Set dynamic breakpoint on interrupt-all
tests/xe_eudebug_online: What if user does not set debug mode?
tests/xe_eudebug_online: Check if eu debugger disables preemption
timeout
Dominik Karol Piatkowski (1):
tests/xe_eudebug_online: Add caching tests
Dominik Karol Piątkowski (5):
tests/xe_eudebug: Add multigpu scenarios
tests/xe_exec_sip: Add breakpoint-writesip-twice test
tests/xe_exec_sip: Add breakpoint-waitsip-heavy test
tests/xe_eudebug_online: Add tdctl-parameters test
tests/xe_eudebug_online: Add single-step and single-step-one tests
Gwan-gyeong Mun (1):
lib/intel_batchbuffer: Add support for long-running mode execution
Jonathan Cavitt (2):
tests/xe_eudebug: Exercise lseek
tests/xe_eudebug: Test multiple bo sizes
Karolina Stolarek (6):
tests/xe_eudebug: Add discovery-race-vmbind subtest
tests/xe_exec_sip: Add sanity-after-timeout test
tests/xe_exec_sip: Add nodebug test cases
lib/xe_eudebug: Expose xe_eudebug_connect
tests/xe_eudebug_online: Add interrupt-reconnect test
tests/xe_eudebug_online: Add multisession test cases
Kolanupaka Naveena (1):
tests/xe_eudebug_online: Adds debugger-reopen test
Maciej Patelczyk (3):
tests/xe_eudebug: Exercise debug metadata events sent to debugger
tests/xe_eudebug: Add basic-vm-bind-metadata-discovery
tests/xe_eudebug: Added connect-user test
Mika Kuoppala (2):
lib/xe_eudebug: Allow client to wait for debugger
tests/xe_eudebug: Add vm open/pread/pwrite basic tests
Pawel Sikora (4):
tests/xe_eudebug: Add basic-vm-access-parameters test
lib/xe_eudebug: Add mutex for log events write
tests/xe_eudebug: Add basic-client-th test
tests/xe_eudebug_online: Add reset-with-attention test
lib/gpgpu_shader.c | 474 +++++-
lib/gpgpu_shader.h | 29 +-
lib/iga64_generated_codes.c | 428 +++++-
lib/intel_batchbuffer.c | 153 +-
lib/intel_batchbuffer.h | 22 +
lib/meson.build | 1 +
lib/xe/xe_eudebug.c | 2186 ++++++++++++++++++++++++++++
lib/xe/xe_eudebug.h | 206 +++
lib/xe/xe_ioctl.c | 20 +-
lib/xe/xe_ioctl.h | 5 +
tests/intel/xe_eudebug.c | 2425 +++++++++++++++++++++++++++++++
tests/intel/xe_eudebug_online.c | 2117 +++++++++++++++++++++++++++
tests/intel/xe_exec_sip.c | 332 ++++-
tests/intel/xe_live_ktest.c | 6 +
tests/meson.build | 2 +
15 files changed, 8371 insertions(+), 35 deletions(-)
create mode 100644 lib/xe/xe_eudebug.c
create mode 100644 lib/xe/xe_eudebug.h
create mode 100644 tests/intel/xe_eudebug.c
create mode 100644 tests/intel/xe_eudebug_online.c
--
2.34.1
^ permalink raw reply [flat|nested] 71+ messages in thread
* [PATCH 01/66] tests/xe_eudebug: Test eudebug connection
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
@ 2024-07-29 16:00 ` Christoph Manszewski
2024-07-30 7:58 ` Zbigniew Kempczyński
2024-07-29 16:00 ` [PATCH 02/66] lib/xe_eudebug: Introduce eu debug testing framework Christoph Manszewski
` (66 subsequent siblings)
67 siblings, 1 reply; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:00 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Mika Kuoppala, Christoph Manszewski
From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Add basic tests checking xe eudebug connection capability.
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Cc: Christoph Manszewski <christoph.manszewski@intel.com>
---
tests/intel/xe_eudebug.c | 115 +++++++++++++++++++++++++++++++++++++++
tests/meson.build | 1 +
2 files changed, 116 insertions(+)
create mode 100644 tests/intel/xe_eudebug.c
diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
new file mode 100644
index 000000000..2bd5a44f9
--- /dev/null
+++ b/tests/intel/xe_eudebug.c
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#include <xe_drm.h>
+#include "igt.h"
+
+static int __debug_connect(int fd, int *debugfd, struct drm_xe_eudebug_connect *param)
+{
+ int ret = 0;
+
+ *debugfd = igt_ioctl(fd, DRM_IOCTL_XE_EUDEBUG_CONNECT, param);
+
+ if (*debugfd < 0) {
+ ret = -errno;
+ igt_assume(ret != 0);
+ }
+
+ errno = 0;
+ return ret;
+}
+
+static void test_connect(int fd)
+{
+ struct drm_xe_eudebug_connect param = {};
+ int debugfd, ret;
+ pid_t *pid;
+
+ pid = mmap(NULL, sizeof(pid_t), PROT_WRITE,
+ MAP_SHARED | MAP_ANON, -1, 0);
+
+ /* get fresh unrelated pid */
+ igt_fork(child, 1)
+ *pid = getpid();
+
+ igt_waitchildren();
+ param.pid = *pid;
+ munmap(pid, sizeof(pid_t));
+
+ ret = __debug_connect(fd, &debugfd, ¶m);
+ igt_assert(debugfd == -1);
+ igt_assert_eq(ret, param.pid ? -ENOENT : -EINVAL);
+
+ param.pid = 0;
+ ret = __debug_connect(fd, &debugfd, ¶m);
+ igt_assert(debugfd == -1);
+ igt_assert_eq(ret, -EINVAL);
+
+ param.pid = getpid();
+ param.version = -1;
+ ret = __debug_connect(fd, &debugfd, ¶m);
+ igt_assert(debugfd == -1);
+ igt_assert_eq(ret, -EINVAL);
+
+ param.version = 0;
+ param.flags = ~0;
+ ret = __debug_connect(fd, &debugfd, ¶m);
+ igt_assert(debugfd == -1);
+ igt_assert_eq(ret, -EINVAL);
+
+ param.flags = 0;
+ param.extensions = ~0;
+ ret = __debug_connect(fd, &debugfd, ¶m);
+ igt_assert(debugfd == -1);
+ igt_assert_eq(ret, -EINVAL);
+
+ param.extensions = 0;
+ ret = __debug_connect(fd, &debugfd, ¶m);
+ igt_assert_neq(debugfd, -1);
+ igt_assert_eq(ret, 0);
+
+ close(debugfd);
+}
+
+static void test_close(int fd)
+{
+ struct drm_xe_eudebug_connect param = { 0, };
+ int debug_fd1, debug_fd2;
+ int fd2;
+
+ param.pid = getpid();
+
+ igt_assert_eq(__debug_connect(fd, &debug_fd1, ¶m), 0);
+ igt_assert(debug_fd1 >= 0);
+ igt_assert_eq(__debug_connect(fd, &debug_fd2, ¶m), -EBUSY);
+ igt_assert_eq(debug_fd2, -1);
+
+ close(debug_fd1);
+ fd2 = drm_open_driver(DRIVER_XE);
+
+ igt_assert_eq(__debug_connect(fd2, &debug_fd2, ¶m), 0);
+ igt_assert(debug_fd2 >= 0);
+ close(fd2);
+ close(debug_fd2);
+ close(debug_fd1);
+}
+
+igt_main
+{
+ int fd;
+
+ igt_fixture {
+ fd = drm_open_driver(DRIVER_XE);
+ }
+
+ igt_subtest("basic-connect")
+ test_connect(fd);
+
+ igt_subtest("basic-close")
+ test_close(fd);
+
+ igt_fixture
+ drm_close_driver(fd);
+}
diff --git a/tests/meson.build b/tests/meson.build
index e649466be..35bf8ed35 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -279,6 +279,7 @@ intel_xe_progs = [
'xe_dma_buf_sync',
'xe_debugfs',
'xe_drm_fdinfo',
+ 'xe_eudebug',
'xe_evict',
'xe_evict_ccs',
'xe_exec_atomic',
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 02/66] lib/xe_eudebug: Introduce eu debug testing framework
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
2024-07-29 16:00 ` [PATCH 01/66] tests/xe_eudebug: Test eudebug connection Christoph Manszewski
@ 2024-07-29 16:00 ` Christoph Manszewski
2024-07-29 16:00 ` [PATCH 03/66] lib/xe_eudebug: Allow client to wait for debugger Christoph Manszewski
` (65 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:00 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Mika Kuoppala, Christoph Manszewski
From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Introduce library which simplifies testing of eu debug capability.
The library provides event log helpers together with asynchronous
abstraction for client proccess and the debugger itself.
xe_eudebug_client creates its own proccess with user's work function,
and gives machanisms to synchronize beginning of execution and event
logging.
xe_eudebug_debugger allows to attach to the given proccess, provides
asynchronous thread for event reading and introduces triggers - a
callback mechanism triggered every time subscribed event was read.
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuaoppala@linux.intel.com>
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
Cc: Christoph Manszewski <christoph.manszewski@intel.com>
---
lib/meson.build | 1 +
lib/xe/xe_eudebug.c | 1185 +++++++++++++++++++++++++++++++++++++++++++
lib/xe/xe_eudebug.h | 143 ++++++
3 files changed, 1329 insertions(+)
create mode 100644 lib/xe/xe_eudebug.c
create mode 100644 lib/xe/xe_eudebug.h
diff --git a/lib/meson.build b/lib/meson.build
index f711e60a7..969ca4101 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -111,6 +111,7 @@ lib_sources = [
'igt_msm.c',
'igt_dsc.c',
'xe/xe_gt.c',
+ 'xe/xe_eudebug.c',
'xe/xe_ioctl.c',
'xe/xe_mmio.c',
'xe/xe_query.c',
diff --git a/lib/xe/xe_eudebug.c b/lib/xe/xe_eudebug.c
new file mode 100644
index 000000000..59cd33990
--- /dev/null
+++ b/lib/xe/xe_eudebug.c
@@ -0,0 +1,1185 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#include <fcntl.h>
+#include <poll.h>
+#include <signal.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "igt.h"
+#include "xe_eudebug.h"
+#include "xe_ioctl.h"
+
+struct event_trigger {
+ xe_eudebug_trigger_fn fn;
+ int type;
+ struct igt_list_head link;
+};
+
+#define CLIENT_PID 1
+#define CLIENT_RUN 2
+#define CLIENT_FINI 3
+#define CLIENT_STOP 4
+
+#define DEBUGGER_WORKER_INACTIVE 0
+#define DEBUGGER_WORKER_ACTIVE 1
+#define DEBUGGER_WORKER_QUITTING 2
+
+static const char *type_to_str(unsigned int type)
+{
+ switch (type) {
+ case DRM_XE_EUDEBUG_EVENT_NONE:
+ return "none";
+ case DRM_XE_EUDEBUG_EVENT_READ:
+ return "read";
+ case DRM_XE_EUDEBUG_EVENT_OPEN:
+ return "client";
+ case DRM_XE_EUDEBUG_EVENT_VM:
+ return "vm";
+ }
+
+ return "UNKNOWN";
+}
+
+static const char *event_type_to_str(struct drm_xe_eudebug_event *e, char *buf)
+{
+ sprintf(buf, "%s(%d)", type_to_str(e->type), e->type);
+
+ return buf;
+}
+
+static const char *flags_to_str(unsigned int flags)
+{
+ if (flags & DRM_XE_EUDEBUG_EVENT_CREATE)
+ return "create";
+
+ if (flags & DRM_XE_EUDEBUG_EVENT_DESTROY)
+ return "destroy";
+
+ if (flags & DRM_XE_EUDEBUG_EVENT_STATE_CHANGE)
+ return "state-change";
+
+ return "flags unknown";
+}
+
+static const char *event_members_to_str(struct drm_xe_eudebug_event *e, char *b)
+{
+ switch (e->type) {
+ case DRM_XE_EUDEBUG_EVENT_OPEN: {
+ struct drm_xe_eudebug_event_client *ec = (struct drm_xe_eudebug_event_client *)e;
+
+ sprintf(b, "handle=%llu", ec->client_handle);
+ break;
+ }
+ case DRM_XE_EUDEBUG_EVENT_VM: {
+ struct drm_xe_eudebug_event_vm *evm = (struct drm_xe_eudebug_event_vm *)e;
+
+ sprintf(b, "client_handle=%llu, handle=%llu",
+ evm->client_handle, evm->vm_handle);
+ break;
+ }
+ default:
+ strcpy(b, "<...>");
+ }
+
+ return b;
+}
+
+/**
+ * xe_eudebug_event_to_str:
+ * @e: pointer to event
+ * @buf: target to write string representation of @e
+ * @len: size of target buffer @buf
+ *
+ * Creates string representation for given event.
+ *
+ * Returns: the written input buffer pointed by @buf.
+ */
+const char *xe_eudebug_event_to_str(struct drm_xe_eudebug_event *e, char *buf, size_t len)
+{
+ char a[256];
+ char b[256];
+
+ snprintf(buf, len, "(%llu) %15s:%s: %s",
+ e->seqno,
+ event_type_to_str(e, a),
+ flags_to_str(e->flags),
+ event_members_to_str(e, b));
+
+ return buf;
+}
+
+static void catch_child_failure(void)
+{
+ pid_t pid;
+ int status;
+
+ pid = waitpid(-1, &status, WNOHANG);
+
+ if (pid == 0 || pid == -1)
+ return;
+
+ if (!WIFEXITED(status))
+ return;
+
+ igt_assert_f(WEXITSTATUS(status) == 0, "Client failed!\n");
+}
+
+static int safe_pipe_read(int pipe[2], void *buf, int nbytes)
+{
+ int ret;
+ struct pollfd fd = {
+ .fd = pipe[0],
+ .events = POLLIN,
+ .revents = 0
+ };
+
+ /* When child fails we may get stuck forever. Check whether
+ * the child process ended with an error.
+ */
+ do {
+ ret = poll(&fd, 1, 1000);
+
+ if (!ret)
+ catch_child_failure();
+ } while (!ret);
+
+ return read(pipe[0], buf, nbytes);
+}
+
+static uint64_t pipe_wait_u64(int pipe[2])
+{
+ uint64_t in;
+ uint64_t ret;
+
+ ret = safe_pipe_read(pipe, &in, sizeof(in));
+ igt_assert(ret == sizeof(in));
+
+ return in;
+}
+
+#define pipe_wait pipe_wait_u64
+
+static void pipe_wait_token(int pipe[2], uint64_t token)
+{
+ uint64_t in;
+
+ in = pipe_wait_u64(pipe);
+ igt_assert_eq(token, in);
+}
+
+static void pipe_signal(int pipe[2], uint64_t token)
+{
+ igt_assert(write(pipe[1], &token, sizeof(token)) == sizeof(token));
+}
+
+static void pipe_close(int pipe[2])
+{
+ if (pipe[0] != -1)
+ close(pipe[0]);
+
+ if (pipe[1] != -1)
+ close(pipe[1]);
+}
+
+static int __xe_eudebug_connect(int fd, pid_t pid, uint32_t flags, uint64_t events)
+{
+ struct drm_xe_eudebug_connect param = {
+ .pid = pid,
+ .flags = flags,
+ };
+ int debugfd;
+
+ debugfd = igt_ioctl(fd, DRM_IOCTL_XE_EUDEBUG_CONNECT, ¶m);
+
+ if (debugfd < 0)
+ return -errno;
+
+ return debugfd;
+}
+
+static int xe_eudebug_connect(int fd, pid_t pid, uint32_t flags)
+{
+ int ret;
+ uint64_t events = 0; /* events filtering not supported yet! */
+
+ ret = __xe_eudebug_connect(fd, pid, flags, events);
+
+ return ret;
+}
+
+static void event_log_write_to_fd(struct xe_eudebug_event_log *l, int fd)
+{
+ igt_assert_eq(write(fd, &l->head, sizeof(l->head)),
+ sizeof(l->head));
+
+ igt_assert_eq(write(fd, l->log, l->head), l->head);
+}
+
+static void read_all(int fd, void *buf, size_t nbytes)
+{
+ ssize_t remaining_size = nbytes;
+ ssize_t current_size = 0;
+ ssize_t read_size = 0;
+
+ do {
+ read_size = read(fd, buf + current_size, remaining_size);
+ igt_assert_f(read_size >= 0, "read failed: %s\n", strerror(errno));
+
+ current_size += read_size;
+ remaining_size -= read_size;
+ } while (remaining_size > 0 && read_size > 0);
+
+ igt_assert_eq(current_size, nbytes);
+}
+
+static void event_log_read_from_fd(struct xe_eudebug_event_log *l, int fd)
+{
+ read_all(fd, &l->head, sizeof(l->head));
+ igt_assert_lt(l->head, l->max_size);
+
+ read_all(fd, l->log, l->head);
+}
+
+typedef int (*cmp_fn_t)(struct drm_xe_eudebug_event *, void *);
+
+static struct drm_xe_eudebug_event *
+event_cmp(struct xe_eudebug_event_log *l,
+ struct drm_xe_eudebug_event *current,
+ cmp_fn_t match,
+ void *data)
+{
+ struct drm_xe_eudebug_event *e = current;
+
+ xe_eudebug_for_each_event(e, l) {
+ if (match(e, data))
+ return e;
+ }
+
+ return NULL;
+}
+
+static int match_type_and_flags(struct drm_xe_eudebug_event *a, void *data)
+{
+ struct drm_xe_eudebug_event *b = data;
+
+ if (a->type == b->type &&
+ a->flags == b->flags)
+ return 1;
+
+ return 0;
+}
+
+static int match_client_handle(struct drm_xe_eudebug_event *e, void *data)
+{
+ uint64_t h = *(uint64_t *)data;
+
+ switch (e->type) {
+ case DRM_XE_EUDEBUG_EVENT_OPEN: {
+ struct drm_xe_eudebug_event_client *client = (struct drm_xe_eudebug_event_client *)e;
+
+ if (client->client_handle == h)
+ return 1;
+ break;
+ }
+ case DRM_XE_EUDEBUG_EVENT_VM: {
+ struct drm_xe_eudebug_event_vm *vm = (struct drm_xe_eudebug_event_vm *)e;
+
+ if (vm->client_handle == h)
+ return 1;
+ break;
+ }
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int match_opposite_resource(struct drm_xe_eudebug_event *e, void *data)
+{
+
+ struct drm_xe_eudebug_event *d = (void *)data;
+ int ret;
+
+ d->flags ^= DRM_XE_EUDEBUG_EVENT_CREATE | DRM_XE_EUDEBUG_EVENT_DESTROY;
+ ret = match_type_and_flags(e, data);
+ d->flags ^= DRM_XE_EUDEBUG_EVENT_CREATE | DRM_XE_EUDEBUG_EVENT_DESTROY;
+
+ if (!ret)
+ return 0;
+
+ switch (e->type) {
+ case DRM_XE_EUDEBUG_EVENT_OPEN: {
+ struct drm_xe_eudebug_event_client *client = (struct drm_xe_eudebug_event_client *)e;
+ struct drm_xe_eudebug_event_client *filter = (struct drm_xe_eudebug_event_client *)data;
+
+ if (client->client_handle == filter->client_handle)
+ return 1;
+ break;
+ }
+ case DRM_XE_EUDEBUG_EVENT_VM: {
+ struct drm_xe_eudebug_event_vm *vm = (struct drm_xe_eudebug_event_vm *)e;
+ struct drm_xe_eudebug_event_vm *filter = (struct drm_xe_eudebug_event_vm *)data;
+
+ if (vm->vm_handle == filter->vm_handle)
+ return 1;
+ break;
+ }
+ default:
+ break;
+ }
+ return 0;
+}
+
+static struct drm_xe_eudebug_event *
+event_type_match(struct xe_eudebug_event_log *l,
+ struct drm_xe_eudebug_event *filter,
+ struct drm_xe_eudebug_event *current)
+{
+ return event_cmp(l, current, match_type_and_flags, filter);
+}
+
+static struct drm_xe_eudebug_event *
+client_match(struct xe_eudebug_event_log *l,
+ uint64_t client_handle,
+ struct drm_xe_eudebug_event *current)
+{
+ return event_cmp(l, current, match_client_handle, &client_handle);
+}
+
+static struct drm_xe_eudebug_event *
+opposite_event_match(struct xe_eudebug_event_log *l,
+ struct drm_xe_eudebug_event *filter,
+ struct drm_xe_eudebug_event *current)
+{
+ return event_cmp(l, current, match_opposite_resource, filter);
+}
+
+static void compare_client(struct xe_eudebug_event_log *c, struct drm_xe_eudebug_event *_ce,
+ struct xe_eudebug_event_log *d, struct drm_xe_eudebug_event *_de)
+{
+ struct drm_xe_eudebug_event_client *ce = (void *)_ce;
+ struct drm_xe_eudebug_event_client *de = (void *)_de;
+ struct drm_xe_eudebug_event *hc, *hd;
+
+ igt_assert(ce);
+ igt_assert(de);
+
+ igt_debug("client: %llu -> %llu\n", ce->client_handle, de->client_handle);
+
+ hc = NULL;
+ hd = NULL;
+
+ do {
+ hc = client_match(c, ce->client_handle, hc);
+ if (!hc)
+ break;
+
+ hd = client_match(d, de->client_handle, hd);
+
+ igt_assert_f(hd, "%s (%llu): no matching event type %u found for client %llu\n",
+ c->name,
+ hc->seqno,
+ hc->type,
+ ce->client_handle);
+
+ igt_debug("comparing %s %llu vs %s %llu\n",
+ c->name, hc->seqno, d->name, hd->seqno);
+
+ igt_assert_eq(hc->type, hd->type);
+ igt_assert_eq(hc->flags, hd->flags);
+ } while (hc);
+}
+
+/*
+ * Yeah very slow but someone with lots of events
+ * will conjure a better datastruct
+ */
+struct drm_xe_eudebug_event *
+xe_eudebug_event_log_find_seqno(struct xe_eudebug_event_log *l, uint64_t seqno)
+{
+ struct drm_xe_eudebug_event *e = NULL, *found = NULL;
+
+ igt_assert_neq(seqno, 0);
+ /*
+ * Try to catch if seqno is corrupted and prevent too long tests,
+ * as our post processing of events is not optimized.
+ */
+ igt_assert_lt(seqno, 10 * 1000 * 1000);
+
+ xe_eudebug_for_each_event(e, l) {
+ if (e->seqno == seqno) {
+ if (found) {
+ igt_warn("Found multiple events with the same seqno %lu\n", seqno);
+ xe_eudebug_event_log_print(l, false);
+ igt_assert(!found);
+ }
+ found = e;
+ }
+ }
+
+ return found;
+}
+
+static void event_log_sort(struct xe_eudebug_event_log *l)
+{
+ struct xe_eudebug_event_log *tmp;
+ struct drm_xe_eudebug_event *e = NULL;
+ uint64_t first_seqno = 0;
+ uint64_t last_seqno = 0;
+ uint64_t events = 0, added = 0;
+ uint64_t i;
+
+ xe_eudebug_for_each_event(e, l) {
+ if (e->seqno > last_seqno)
+ last_seqno = e->seqno;
+
+ if (e->seqno < first_seqno)
+ first_seqno = e->seqno;
+
+ events++;
+ }
+
+ tmp = xe_eudebug_event_log_create("tmp", l->max_size);
+
+ for (i = 1; i <= last_seqno; i++) {
+ e = xe_eudebug_event_log_find_seqno(l, i);
+ if (e) {
+ xe_eudebug_event_log_write(tmp, e);
+ added++;
+ }
+ }
+
+ igt_assert_eq(events, added);
+ igt_assert_eq(tmp->head, l->head);
+
+ memcpy(l->log, tmp->log, tmp->head);
+
+ xe_eudebug_event_log_destroy(tmp);
+}
+
+/**
+ * xe_eudebug_event_log_create:
+ * @name: event log identifier
+ * @max_size: maximum size of created log
+ *
+ * Function creates an Eu Debugger event log with size equal to @max_size.
+ *
+ * Returns: pointer to just created log
+ */
+#define MAX_EVENT_LOG_SIZE (32 * 1024 * 1024)
+struct xe_eudebug_event_log *xe_eudebug_event_log_create(const char *name, unsigned int max_size)
+{
+ struct xe_eudebug_event_log *l;
+
+ l = calloc(1, sizeof(*l));
+ igt_assert(l);
+ l->log = calloc(1, max_size);
+ igt_assert(l->log);
+ l->max_size = max_size;
+ strncpy(l->name, name, sizeof(l->name) - 1);
+
+ return l;
+}
+
+/**
+ * xe_eudebug_event_log_destroy:
+ * @l: event log pointer
+ *
+ * Frees given event log @l.
+ */
+void xe_eudebug_event_log_destroy(struct xe_eudebug_event_log *l)
+{
+ free(l->log);
+ free(l);
+}
+
+/**
+ * xe_eudebug_event_log_write:
+ * @l: event log pointer
+ * @e: event to be written to event log
+ *
+ * Writes event @e to the event log.
+ */
+void xe_eudebug_event_log_write(struct xe_eudebug_event_log *l, struct drm_xe_eudebug_event *e)
+{
+ igt_assert(e->seqno);
+ /*
+ * Try to catch if seqno is corrupted and prevent too long tests,
+ * as our post processing of events is not optimized.
+ */
+ igt_assert_lt(e->seqno, 10 * 1000 * 1000);
+
+ igt_assert_lt(l->head + e->len, l->max_size);
+ memcpy(l->log + l->head, e, e->len);
+ l->head += e->len;
+
+#ifdef DEBUG_LOG
+ igt_info("%s: wrote %u bytes to eventlog, free %u bytes\n",
+ l->name, e->len, l->max_size - l->head);
+#endif
+}
+
+/**
+ * xe_eudebug_event_log_print:
+ * @l: event log pointer
+ * @debug: when true function uses igt_debug instead of igt_info.
+ *
+ * Prints given event log.
+ */
+void
+xe_eudebug_event_log_print(struct xe_eudebug_event_log *l, bool debug)
+{
+ struct drm_xe_eudebug_event *e = NULL;
+ int level = debug ? IGT_LOG_DEBUG : IGT_LOG_INFO;
+ char str[XE_EUDEBUG_EVENT_STRING_MAX_LEN];
+
+ igt_log(IGT_LOG_DOMAIN, level,
+ "event log '%s' (%u bytes):\n", l->name, l->head);
+
+ xe_eudebug_for_each_event(e, l) {
+ xe_eudebug_event_to_str(e, str, XE_EUDEBUG_EVENT_STRING_MAX_LEN);
+ igt_log(IGT_LOG_DOMAIN, level, "%s\n", str);
+ }
+}
+
+/**
+ * xe_eudebug_event_log_compare:
+ * @a: event log pointer
+ * @b: event log pointer
+ *
+ * Compares and asserts event logs @a, @b if the event
+ * sequence matches.
+ */
+void xe_eudebug_event_log_compare(struct xe_eudebug_event_log *a, struct xe_eudebug_event_log *b)
+{
+ struct drm_xe_eudebug_event *ae = NULL;
+ struct drm_xe_eudebug_event *be = NULL;
+
+ xe_eudebug_for_each_event(ae, a) {
+ if (ae->type == DRM_XE_EUDEBUG_EVENT_OPEN &&
+ ae->flags & DRM_XE_EUDEBUG_EVENT_CREATE) {
+ be = event_type_match(b, ae, be);
+
+ compare_client(a, ae, b, be);
+ compare_client(b, be, a, ae);
+ }
+ }
+}
+
+/**
+ * xe_eudebug_event_log_match_opposite:
+ * @l: event log pointer
+ *
+ * Matches and asserts content of all opposite events (create vs destroy).
+ */
+void
+xe_eudebug_event_log_match_opposite(struct xe_eudebug_event_log *l)
+{
+ struct drm_xe_eudebug_event *ce = NULL;
+ struct drm_xe_eudebug_event *de = NULL;
+
+ xe_eudebug_for_each_event(ce, l) {
+ if (ce->flags & DRM_XE_EUDEBUG_EVENT_CREATE) {
+ uint8_t offset = sizeof(struct drm_xe_eudebug_event);
+ int opposite_matching;
+
+ de = opposite_event_match(l, ce, ce);
+
+ igt_assert_f(de, "no opposite event of type %u found\n", ce->type);
+
+ igt_assert_eq(ce->len, de->len);
+ opposite_matching = memcmp((uint8_t *)de + offset,
+ (uint8_t *)ce + offset,
+ de->len - offset) == 0;
+
+ igt_assert_f(opposite_matching,
+ "%s: create|destroy event not "
+ "maching (%llu) vs (%llu)\n",
+ l->name, de->seqno, ce->seqno);
+ }
+ }
+}
+
+static void debugger_run_triggers(struct xe_eudebug_debugger *d,
+ struct drm_xe_eudebug_event *e)
+{
+ struct event_trigger *t;
+
+ igt_list_for_each_entry(t, &d->triggers, link) {
+ if (e->type == t->type)
+ t->fn(d, e);
+ }
+}
+
+#define MAX_EVENT_SIZE (32 * 1024)
+static int
+xe_eudebug_read_event(int fd, struct drm_xe_eudebug_event *event)
+{
+ int ret;
+
+ event->type = DRM_XE_EUDEBUG_EVENT_READ;
+ event->flags = 0;
+ event->len = MAX_EVENT_SIZE;
+
+ ret = igt_ioctl(fd, DRM_XE_EUDEBUG_IOCTL_READ_EVENT, event);
+ if (ret < 0)
+ return -errno;
+
+ return ret;
+}
+
+static void *debugger_worker_loop(void *data)
+{
+ uint8_t buf[MAX_EVENT_SIZE];
+ struct drm_xe_eudebug_event *e = (void *)buf;
+ struct xe_eudebug_debugger *d = data;
+ struct pollfd p = {
+ .events = POLLIN,
+ .revents = 0,
+ };
+ int timeout_ms = 100, ret;
+
+ igt_assert(d->master_fd >= 0);
+
+ do {
+ p.fd = d->fd;
+ ret = poll(&p, 1, timeout_ms);
+
+ if (ret == -1) {
+ igt_info("poll failed with errno %d\n", errno);
+ break;
+ }
+
+ if (ret == 1 && (p.revents & POLLIN)) {
+ int err = xe_eudebug_read_event(d->fd, e);
+
+ if (!err) {
+ ++d->event_count;
+
+ xe_eudebug_event_log_write(d->log, e);
+ debugger_run_triggers(d, e);
+ } else {
+ igt_info("xe_eudebug_read_event returned %d\n", ret);
+ }
+ }
+ } while ((ret && READ_ONCE(d->worker_state) == DEBUGGER_WORKER_QUITTING) ||
+ READ_ONCE(d->worker_state) == DEBUGGER_WORKER_ACTIVE);
+
+ d->worker_state = DEBUGGER_WORKER_INACTIVE;
+ return NULL;
+}
+
+/**
+ * xe_eudebug_debugger_create:
+ * @master_fd: xe client used to open the debugger connection
+ * @flags: flags stored in a debugger structure, can be used at will
+ * of the caller, i.e. to be used inside triggers.
+ * @data: test's private data, allocated with MAP_SHARED | MAP_ANONYMOUS,
+ * can be shared between client and debugger. Can be NULL.
+ *
+ * Returns: newly created xe_eudebug_debugger structure with its
+ * event log initialized. Note that to open the connection
+ * you need call @xe_eudebug_debugger_attach.
+ */
+struct xe_eudebug_debugger *
+xe_eudebug_debugger_create(int master_fd, uint64_t flags, void *data)
+{
+ struct xe_eudebug_debugger *d;
+
+ d = calloc(1, sizeof(*d));
+ d->flags = flags;
+ igt_assert(d);
+ IGT_INIT_LIST_HEAD(&d->triggers);
+ d->log = xe_eudebug_event_log_create("debugger", MAX_EVENT_LOG_SIZE);
+ d->fd = -1;
+ d->master_fd = master_fd;
+ d->ptr = data;
+
+ return d;
+}
+
+static void debugger_destroy_triggers(struct xe_eudebug_debugger *d)
+{
+ struct event_trigger *t, *tmp;
+
+ igt_list_for_each_entry_safe(t, tmp, &d->triggers, link)
+ free(t);
+}
+
+/**
+ * xe_eudebug_debugger_destroy:
+ * @d: pointer to the debugger
+ *
+ * Frees xe_eudebug_debugger structure pointed by @d. If the debugger
+ * connection was still opened it terminates it.
+ */
+void xe_eudebug_debugger_destroy(struct xe_eudebug_debugger *d)
+{
+ if (d->worker_state)
+ xe_eudebug_debugger_stop_worker(d, 1);
+
+ if (d->target_pid)
+ xe_eudebug_debugger_dettach(d);
+
+ xe_eudebug_event_log_destroy(d->log);
+ debugger_destroy_triggers(d);
+ free(d);
+}
+
+/**
+ * xe_eudebug_debugger_attach:
+ * @d: pointer to the debugger
+ * @target: pid of the process to attach debugger
+ *
+ * Opens the xe eu debugger connection to the @target proccess.
+ *
+ * Returns: 0 if the debugger was successfully attached, -errno otherwise.
+ */
+int xe_eudebug_debugger_attach(struct xe_eudebug_debugger *d, pid_t target)
+{
+ int ret;
+
+ igt_assert_eq(d->fd, -1);
+ ret = xe_eudebug_connect(d->master_fd, target, 0);
+
+ if (ret < 0)
+ return ret;
+
+ d->fd = ret;
+ d->target_pid = target;
+
+ igt_debug("debugger connected to %lu\n", d->target_pid);
+
+ return 0;
+}
+
+/**
+ * xe_eudebug_debugger_dettach:
+ * @d: pointer to the debugger
+ *
+ * Closes previously opened xe eu debugger connection. Asserts if
+ * the debugger has active session.
+ */
+void xe_eudebug_debugger_dettach(struct xe_eudebug_debugger *d)
+{
+ igt_assert(d->target_pid);
+ close(d->fd);
+ d->target_pid = 0;
+ d->fd = -1;
+}
+
+/**
+ * xe_eudebug_debugger_add_trigger:
+ * @d: pointer to the debugger
+ * @type: the type of the event which activates the trigger
+ * @fn: function to be called when event of @type was read by the debugger.
+ *
+ * Adds function @fn to the list of triggers activated when event of @type
+ * has been read by worker.
+ * Note: Triggers are activated by the worker.
+ */
+void xe_eudebug_debugger_add_trigger(struct xe_eudebug_debugger *d,
+ int type, xe_eudebug_trigger_fn fn)
+{
+ struct event_trigger *t;
+
+ t = calloc(1, sizeof(*t));
+ IGT_INIT_LIST_HEAD(&t->link);
+ t->type = type;
+ t->fn = fn;
+
+ igt_list_add_tail(&t->link, &d->triggers);
+ igt_debug("added trigger %p\n", t);
+}
+
+/**
+ * xe_eudebug_debugger_start_worker:
+ * @d: pointer to the debugger
+ *
+ * Starts the debugger worker. Worker is resposible for reading all
+ * incoming events from the debugger, put then into debugger log and
+ * execute appropriate event triggers. Note that using the debuggers
+ * event log while worker is running is not safe.
+ */
+void xe_eudebug_debugger_start_worker(struct xe_eudebug_debugger *d)
+{
+ int ret;
+
+ d->worker_state = true;
+ ret = pthread_create(&d->worker_thread, NULL, &debugger_worker_loop, d);
+
+ igt_assert_f(ret == 0, "Debugger worker thread creation failed!");
+}
+
+/**
+ * xe_eudebug_debugger_stop_worker:
+ * @d: pointer to the debugger
+ *
+ * Stops the debugger worker. Event log is sorted by seqno after closure.
+ */
+void xe_eudebug_debugger_stop_worker(struct xe_eudebug_debugger *d,
+ int timeout_s)
+{
+ struct timespec t = {};
+ int ret;
+
+ igt_assert(d->worker_state);
+
+ d->worker_state = DEBUGGER_WORKER_QUITTING; /* First time be polite. */
+ igt_assert_eq(clock_gettime(CLOCK_REALTIME, &t), 0);
+ t.tv_sec += timeout_s;
+
+ ret = pthread_timedjoin_np(d->worker_thread, NULL, &t);
+
+ if (ret == ETIMEDOUT) {
+ d->worker_state = DEBUGGER_WORKER_INACTIVE;
+ ret = pthread_join(d->worker_thread, NULL);
+ }
+
+ igt_assert_f(ret == 0 || ret != ESRCH,
+ "pthread join failed with error %d!\n", ret);
+
+ event_log_sort(d->log);
+}
+
+/**
+ * xe_eudebug_client_create:
+ * @master_fd: xe client used to open the debugger connection
+ * @work: function that opens xe device and executes arbitrary workload
+ * @flags: flags stored in a client structure, can be used at will
+ * of the caller, i.e. to provide the @work function an additional switch.
+ * @data: test's private data, allocated with MAP_SHARED | MAP_ANONYMOUS,
+ * can be shared between client and debugger. Accesible via client->ptr.
+ * Can be NULL.
+ *
+ * Forks and creates the debugger process. @work won't be called until
+ * xe_eudebug_client_start is called.
+ *
+ * Returns: newly created xe_eudebug_debugger structure with its
+ * event log initialized.
+ */
+struct xe_eudebug_client *xe_eudebug_client_create(int master_fd, xe_eudebug_client_work_fn work,
+ uint64_t flags, void *data)
+{
+ struct xe_eudebug_client *c;
+
+ c = calloc(1, sizeof(*c));
+ c->flags = flags;
+ igt_assert(c);
+ igt_assert(!pipe(c->p_in));
+ igt_assert(!pipe(c->p_out));
+ c->seqno = 1;
+ c->log = xe_eudebug_event_log_create("client", MAX_EVENT_LOG_SIZE);
+ c->done = 0;
+ c->ptr = data;
+ c->master_fd = master_fd;
+
+ igt_fork(child, 1) {
+ igt_assert_eq(c->pid, 0);
+
+ close(c->p_out[0]);
+ c->p_out[0] = -1;
+ close(c->p_in[1]);
+ c->p_in[1] = -1;
+
+ pipe_signal(c->p_out, CLIENT_PID);
+ pipe_signal(c->p_out, getpid());
+
+ pipe_wait_token(c->p_in, CLIENT_RUN);
+ work(c);
+ pipe_signal(c->p_out, CLIENT_FINI);
+
+ igt_assert_eq(c->pid, 0);
+ event_log_write_to_fd(c->log, c->p_out[1]);
+ pipe_signal(c->p_out, c->seqno);
+ pipe_wait_token(c->p_in, CLIENT_STOP);
+ }
+
+ close(c->p_out[1]);
+ c->p_out[1] = -1;
+ close(c->p_in[0]);
+ c->p_in[0] = -1;
+
+ pipe_wait_token(c->p_out, CLIENT_PID);
+ c->pid = pipe_wait(c->p_out);
+
+ igt_info("client running with pid %d\n", c->pid);
+
+ return c;
+}
+
+/**
+ * xe_eudebug_client_stop:
+ * @c: pointer to xe_eudbug_client structure
+ *
+ * Waits for the end of client's work and exits the proccess.
+ */
+void xe_eudebug_client_stop(struct xe_eudebug_client *c)
+{
+ if (c->pid) {
+ int waitstatus;
+
+ xe_eudebug_client_wait_done(c);
+
+ pipe_signal(c->p_in, CLIENT_STOP);
+ igt_assert_eq(waitpid(c->pid, &waitstatus, 0),
+ c->pid);
+ c->pid = 0;
+ }
+}
+
+/**
+ * xe_eudebug_client_destroy:
+ * @c: pointer to xe_eudbug_client structure to be freed
+ *
+ * Frees the @c client structure. Note that it calls xe_eudebug_client_stop if
+ * client proccess has not terminated yet.
+ */
+void xe_eudebug_client_destroy(struct xe_eudebug_client *c)
+{
+ xe_eudebug_client_stop(c);
+ pipe_close(c->p_in);
+ pipe_close(c->p_out);
+ xe_eudebug_event_log_destroy(c->log);
+ free(c);
+}
+
+/**
+ * xe_eudebug_client_get_seqno:
+ * @c: pointer to xe_eudbug_client structure
+ *
+ * Increments and returns current seqno value of the given client @c
+ *
+ * Returns: incremented seqno
+ */
+uint64_t xe_eudebug_client_get_seqno(struct xe_eudebug_client *c)
+{
+ return c->seqno++;
+}
+
+/**
+ * xe_eudebug_client_start:
+ * @c: pointer to xe_eudebug_client structure
+ *
+ * Starts execution of client's work function within the client's proccess.
+ */
+void xe_eudebug_client_start(struct xe_eudebug_client *c)
+{
+ pipe_signal(c->p_in, CLIENT_RUN);
+}
+
+/**
+ * xe_eudebug_client_wait_done:
+ * @c: pointer to xe_eudebug_client structure
+ *
+ * Waits for the client work end updates the event log.
+ * Doesn't terminate the client's proccess yet.
+ */
+void xe_eudebug_client_wait_done(struct xe_eudebug_client *c)
+{
+ if (!c->done) {
+ c->done = 1;
+ pipe_wait_token(c->p_out, CLIENT_FINI);
+ event_log_read_from_fd(c->log, c->p_out[0]);
+ c->seqno = pipe_wait(c->p_out);
+ }
+}
+
+/**
+ * xe_eudebug_session_create:
+ * @fd: XE file descriptor
+ * @work: function passed to the xe_eudebug_client_create
+ * @flags: flags passed to client and debugger
+ * @test_private: test's data, allocated with MAP_SHARED | MAP_ANONYMOUS,
+ * passed to client and debugger. Can be NULL.
+ *
+ * Creates session together with client and debugger structures.
+ */
+struct xe_eudebug_session *xe_eudebug_session_create(int fd,
+ xe_eudebug_client_work_fn work,
+ unsigned int flags,
+ void *test_private)
+{
+ struct xe_eudebug_session *s;
+
+ s = calloc(1, sizeof(*s));
+ igt_assert(s);
+
+ s->c = xe_eudebug_client_create(fd, work, flags, test_private);
+ s->d = xe_eudebug_debugger_create(fd, flags, test_private);
+ s->flags = flags;
+
+ return s;
+}
+
+/**
+ * xe_eudebug_session_run:
+ * @s: pointer to xe_eudebug_session structure
+ *
+ * Attaches debugger to client's proccess, starts debugger's
+ * async event reader, starts client and once client finish
+ * it stops debugger worker.
+ */
+void xe_eudebug_session_run(struct xe_eudebug_session *s)
+{
+ struct xe_eudebug_debugger *debugger = s->d;
+ struct xe_eudebug_client *client = s->c;
+
+ igt_assert_eq(xe_eudebug_debugger_attach(debugger, client->pid), 0);
+
+ xe_eudebug_debugger_start_worker(debugger);
+
+ xe_eudebug_client_start(client);
+ xe_eudebug_client_wait_done(client);
+
+ xe_eudebug_debugger_stop_worker(debugger, 1);
+
+ xe_eudebug_event_log_print(debugger->log, true);
+ xe_eudebug_event_log_print(client->log, true);
+}
+
+/**
+ * xe_eudebug_session_check:
+ * @s: pointer to xe_eudebug_session structure
+ * @match_opposite: indicates whether check should match all
+ * create and destroy events.
+ *
+ * Validate debugger's log against the log created by the client.
+ */
+void xe_eudebug_session_check(struct xe_eudebug_session *s, bool match_opposite)
+{
+ xe_eudebug_event_log_compare(s->c->log, s->d->log);
+
+ if (match_opposite)
+ xe_eudebug_event_log_match_opposite(s->d->log);
+}
+
+/**
+ * xe_eudebug_session_destroy:
+ * @s: pointer to xe_eudebug_session structure
+ *
+ * Destroy session together with its debugger and client.
+ */
+void xe_eudebug_session_destroy(struct xe_eudebug_session *s)
+{
+ xe_eudebug_debugger_destroy(s->d);
+ xe_eudebug_client_destroy(s->c);
+
+ free(s);
+}
+
+#define to_base(x) ((struct drm_xe_eudebug_event *)&x)
+
+static void base_event(struct xe_eudebug_client *c,
+ struct drm_xe_eudebug_event *e,
+ uint32_t type,
+ uint32_t flags,
+ uint64_t size)
+{
+ e->type = type;
+ e->flags = flags;
+ e->seqno = xe_eudebug_client_get_seqno(c);
+ e->len = size;
+}
+
+static void client_event(struct xe_eudebug_client *c, uint32_t flags, int client_fd)
+{
+ struct drm_xe_eudebug_event_client ec;
+
+ base_event(c, to_base(ec), DRM_XE_EUDEBUG_EVENT_OPEN, flags, sizeof(ec));
+
+ ec.client_handle = client_fd;
+
+ xe_eudebug_event_log_write(c->log, (void *)&ec);
+}
+
+static void vm_event(struct xe_eudebug_client *c, uint32_t flags, int client_fd, uint32_t vm_id)
+{
+ struct drm_xe_eudebug_event_vm evm;
+
+ base_event(c, to_base(evm), DRM_XE_EUDEBUG_EVENT_VM, flags, sizeof(evm));
+
+ evm.client_handle = client_fd;
+ evm.vm_handle = vm_id;
+
+ xe_eudebug_event_log_write(c->log, (void *)&evm);
+}
+
+/* Eu debugger wrappers around resource creating xe ioctls. */
+
+/**
+ * xe_eudebug_client_open_driver:
+ * @c: pointer to xe_eudebug_client structure
+ *
+ * Calls drm_open_client(DRIVER_XE) and logs the corresponding
+ * event in client's event log.
+ *
+ * Returns: valid DRM file descriptor
+ */
+int xe_eudebug_client_open_driver(struct xe_eudebug_client *c)
+{
+ int fd;
+
+ fd = drm_reopen_driver(c->master_fd);
+ client_event(c, DRM_XE_EUDEBUG_EVENT_CREATE, fd);
+
+ return fd;
+}
+
+/**
+ * xe_eudebug_client_close_driver:
+ * @c: pointer to xe_eudebug_client structure
+ * @fd: xe client
+ *
+ * Calls close driver and logs the corresponding event in
+ * client's event log.
+ */
+void xe_eudebug_client_close_driver(struct xe_eudebug_client *c, int fd)
+{
+ client_event(c, DRM_XE_EUDEBUG_EVENT_DESTROY, fd);
+ close(fd);
+}
+
+/**
+ * xe_eudebug_client_vm_create:
+ * @c: pointer to xe_eudebug_client structure
+ * @fd: xe client
+ * @flags: vm bind flags
+ * @ext: pointer to the first user extension
+ *
+ * Calls xe_vm_create() and logs the corresponding event in
+ * client's event log.
+ *
+ * Returns: valid vm handle
+ */
+uint32_t xe_eudebug_client_vm_create(struct xe_eudebug_client *c, int fd,
+ uint32_t flags, uint64_t ext)
+{
+ uint32_t vm;
+
+ vm = xe_vm_create(fd, flags, ext);
+ vm_event(c, DRM_XE_EUDEBUG_EVENT_CREATE, fd, vm);
+
+ return vm;
+}
+
+/**
+ * xe_eudebug_client_vm_destroy:
+ * @c: pointer to xe_eudebug_client structure
+ * fd: xe client
+ * vm: vm handle
+ *
+ * Calls xe_vm_destroy() and logs the corresponding event in
+ * client's event log.
+ */
+void xe_eudebug_client_vm_destroy(struct xe_eudebug_client *c, int fd, uint32_t vm)
+{
+ xe_vm_destroy(fd, vm);
+ vm_event(c, DRM_XE_EUDEBUG_EVENT_DESTROY, fd, vm);
+}
diff --git a/lib/xe/xe_eudebug.h b/lib/xe/xe_eudebug.h
new file mode 100644
index 000000000..a0cae245d
--- /dev/null
+++ b/lib/xe/xe_eudebug.h
@@ -0,0 +1,143 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <xe_drm.h>
+
+#include "igt_list.h"
+
+struct xe_eudebug_event_log {
+ uint8_t *log;
+ unsigned int head;
+ unsigned int max_size;
+ char name[80];
+};
+
+struct xe_eudebug_debugger {
+ int fd;
+ uint64_t flags;
+
+ /* Used to smuggle private data */
+ void *ptr;
+
+ struct xe_eudebug_event_log *log;
+
+ uint64_t event_count;
+
+ uint64_t target_pid;
+
+ struct igt_list_head triggers;
+
+ int master_fd;
+
+ pthread_t worker_thread;
+ int worker_state;
+
+};
+
+struct xe_eudebug_client {
+ int pid;
+ uint64_t seqno;
+ uint64_t flags;
+
+ /* Used to smuggle private data */
+ void *ptr;
+
+ struct xe_eudebug_event_log *log;
+
+ int done;
+ int p_in[2];
+ int p_out[2];
+
+ /* Used to pickup right device (the one used in debugger) */
+ int master_fd;
+};
+
+struct xe_eudebug_session {
+ uint64_t flags;
+ struct xe_eudebug_client *c;
+ struct xe_eudebug_debugger *d;
+};
+
+typedef void (*xe_eudebug_client_work_fn)(struct xe_eudebug_client *);
+typedef void (*xe_eudebug_trigger_fn)(struct xe_eudebug_debugger *,
+ struct drm_xe_eudebug_event *);
+
+#define xe_eudebug_for_each_event(_e, _log) \
+ for ((_e) = (_e) ? (void *)(uint8_t *)(_e) + (_e)->len : \
+ (void *)(_log)->log; \
+ (uint8_t *)(_e) < (_log)->log + (_log)->head; \
+ (_e) = (void *)(uint8_t *)(_e) + (_e)->len)
+
+#define xe_eudebug_assert(d, c) \
+ do { \
+ if (!(c)) { \
+ xe_eudebug_event_log_print((d)->log, true); \
+ igt_assert(c); \
+ } \
+ } while (0)
+
+#define xe_eudebug_assert_f(d, c, f...) \
+ do { \
+ if (!(c)) { \
+ xe_eudebug_event_log_print((d)->log, true); \
+ igt_assert_f(c, f); \
+ } \
+ } while (0)
+
+#define XE_EUDEBUG_EVENT_STRING_MAX_LEN 4096
+
+/*
+ * Default abort timeout to use across xe_eudebug lib and tests if no specific
+ * timeout value is required.
+ */
+#define XE_EUDEBUG_DEFAULT_TIMEOUT_MS 25000ULL
+
+const char *xe_eudebug_event_to_str(struct drm_xe_eudebug_event *e, char *buf, size_t len);
+struct drm_xe_eudebug_event *
+xe_eudebug_event_log_find_seqno(struct xe_eudebug_event_log *l, uint64_t seqno);
+struct xe_eudebug_event_log *
+xe_eudebug_event_log_create(const char *name, unsigned int max_size);
+void xe_eudebug_event_log_destroy(struct xe_eudebug_event_log *l);
+void xe_eudebug_event_log_print(struct xe_eudebug_event_log *l, bool debug);
+void xe_eudebug_event_log_compare(struct xe_eudebug_event_log *c, struct xe_eudebug_event_log *d);
+void xe_eudebug_event_log_write(struct xe_eudebug_event_log *l, struct drm_xe_eudebug_event *e);
+void xe_eudebug_event_log_match_opposite(struct xe_eudebug_event_log *l);
+
+struct xe_eudebug_debugger *
+xe_eudebug_debugger_create(int xe, uint64_t flags, void *data);
+void xe_eudebug_debugger_destroy(struct xe_eudebug_debugger *d);
+int xe_eudebug_debugger_attach(struct xe_eudebug_debugger *d, pid_t pid);
+void xe_eudebug_debugger_start_worker(struct xe_eudebug_debugger *d);
+void xe_eudebug_debugger_stop_worker(struct xe_eudebug_debugger *d, int timeout_s);
+void xe_eudebug_debugger_dettach(struct xe_eudebug_debugger *d);
+void xe_eudebug_debugger_set_data(struct xe_eudebug_debugger *c, void *ptr);
+void xe_eudebug_debugger_add_trigger(struct xe_eudebug_debugger *d, int type,
+ xe_eudebug_trigger_fn fn);
+
+struct xe_eudebug_client *
+xe_eudebug_client_create(int xe, xe_eudebug_client_work_fn work, uint64_t flags, void *data);
+void xe_eudebug_client_destroy(struct xe_eudebug_client *c);
+void xe_eudebug_client_start(struct xe_eudebug_client *c);
+void xe_eudebug_client_stop(struct xe_eudebug_client *c);
+void xe_eudebug_client_wait_done(struct xe_eudebug_client *c);
+uint64_t xe_eudebug_client_get_seqno(struct xe_eudebug_client *c);
+void xe_eudebug_client_set_data(struct xe_eudebug_client *c, void *ptr);
+
+int xe_eudebug_client_open_driver(struct xe_eudebug_client *c);
+void xe_eudebug_client_close_driver(struct xe_eudebug_client *c, int fd);
+uint32_t xe_eudebug_client_vm_create(struct xe_eudebug_client *c, int fd,
+ uint32_t flags, uint64_t ext);
+void xe_eudebug_client_vm_destroy(struct xe_eudebug_client *c, int fd, uint32_t vm);
+
+struct xe_eudebug_session *xe_eudebug_session_create(int fd,
+ xe_eudebug_client_work_fn work,
+ unsigned int flags,
+ void *test_private);
+void xe_eudebug_session_destroy(struct xe_eudebug_session *s);
+void xe_eudebug_session_run(struct xe_eudebug_session *s);
+void xe_eudebug_session_check(struct xe_eudebug_session *s, bool match_opposite);
+
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 03/66] lib/xe_eudebug: Allow client to wait for debugger
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
2024-07-29 16:00 ` [PATCH 01/66] tests/xe_eudebug: Test eudebug connection Christoph Manszewski
2024-07-29 16:00 ` [PATCH 02/66] lib/xe_eudebug: Introduce eu debug testing framework Christoph Manszewski
@ 2024-07-29 16:00 ` Christoph Manszewski
2024-07-29 16:00 ` [PATCH 04/66] lib/xe_eudebug: Add exec_queue support Christoph Manszewski
` (64 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:00 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Mika Kuoppala
From: Mika Kuoppala <mika.kuoppala@linux.intel.com>
In some tests, we need to pause the client into a certain
stage it has setup so that debugger can then examine that
setup and crosscheck.
Add a possibility to pause client and debugger to signal
continuation.
We need to take into account that the debugger might
disappear before signaling continuation so a timeout
mechanism for all pipe token reads needs to be added.
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
lib/xe/xe_eudebug.c | 159 +++++++++++++++++++++++++++++++++-----------
lib/xe/xe_eudebug.h | 8 ++-
2 files changed, 129 insertions(+), 38 deletions(-)
diff --git a/lib/xe/xe_eudebug.c b/lib/xe/xe_eudebug.c
index 59cd33990..70769e532 100644
--- a/lib/xe/xe_eudebug.c
+++ b/lib/xe/xe_eudebug.c
@@ -24,6 +24,7 @@ struct event_trigger {
#define CLIENT_RUN 2
#define CLIENT_FINI 3
#define CLIENT_STOP 4
+#define CLIENT_STAGE 5
#define DEBUGGER_WORKER_INACTIVE 0
#define DEBUGGER_WORKER_ACTIVE 1
@@ -129,9 +130,10 @@ static void catch_child_failure(void)
igt_assert_f(WEXITSTATUS(status) == 0, "Client failed!\n");
}
-static int safe_pipe_read(int pipe[2], void *buf, int nbytes)
+static int safe_pipe_read(int pipe[2], void *buf, int nbytes, int timeout_ms)
{
int ret;
+ int t = 0;
struct pollfd fd = {
.fd = pipe[0],
.events = POLLIN,
@@ -142,36 +144,33 @@ static int safe_pipe_read(int pipe[2], void *buf, int nbytes)
* the child process ended with an error.
*/
do {
- ret = poll(&fd, 1, 1000);
+ const int interval_ms = 1000;
- if (!ret)
+ ret = poll(&fd, 1, interval_ms);
+
+ if (!ret) {
catch_child_failure();
- } while (!ret);
+ t += interval_ms;
+ }
+ } while (!ret && t < timeout_ms);
- return read(pipe[0], buf, nbytes);
+ if (ret > 0)
+ return read(pipe[0], buf, nbytes);
+
+ return 0;
}
-static uint64_t pipe_wait_u64(int pipe[2])
+static uint64_t pipe_read(int pipe[2], int timeout_ms)
{
uint64_t in;
uint64_t ret;
- ret = safe_pipe_read(pipe, &in, sizeof(in));
+ ret = safe_pipe_read(pipe, &in, sizeof(in), timeout_ms);
igt_assert(ret == sizeof(in));
return in;
}
-#define pipe_wait pipe_wait_u64
-
-static void pipe_wait_token(int pipe[2], uint64_t token)
-{
- uint64_t in;
-
- in = pipe_wait_u64(pipe);
- igt_assert_eq(token, in);
-}
-
static void pipe_signal(int pipe[2], uint64_t token)
{
igt_assert(write(pipe[1], &token, sizeof(token)) == sizeof(token));
@@ -186,6 +185,42 @@ static void pipe_close(int pipe[2])
close(pipe[1]);
}
+static uint64_t __wait_token(int p[2], const uint64_t token, int timeout_ms)
+{
+ uint64_t in;
+
+ in = pipe_read(p, timeout_ms);
+
+ igt_assert_eq(in, token);
+
+ return pipe_read(p, timeout_ms);
+}
+
+static uint64_t client_wait_token(struct xe_eudebug_client *c,
+ const uint64_t token)
+{
+ return __wait_token(c->p_in, token, c->timeout_ms);
+}
+
+static uint64_t wait_from_client(struct xe_eudebug_client *c,
+ const uint64_t token)
+{
+ return __wait_token(c->p_out, token, c->timeout_ms);
+}
+
+static void token_signal(int p[2], const uint64_t token, const uint64_t value)
+{
+ pipe_signal(p, token);
+ pipe_signal(p, value);
+}
+
+static void client_signal(struct xe_eudebug_client *c,
+ const uint64_t token,
+ const uint64_t value)
+{
+ token_signal(c->p_out, token, value);
+}
+
static int __xe_eudebug_connect(int fd, pid_t pid, uint32_t flags, uint64_t events)
{
struct drm_xe_eudebug_connect param = {
@@ -735,24 +770,28 @@ void xe_eudebug_debugger_destroy(struct xe_eudebug_debugger *d)
/**
* xe_eudebug_debugger_attach:
* @d: pointer to the debugger
- * @target: pid of the process to attach debugger
+ * @c: pointer to the client
*
- * Opens the xe eu debugger connection to the @target proccess.
+ * Opens the xe eu debugger connection to the process described by @c (c->pid)
*
* Returns: 0 if the debugger was successfully attached, -errno otherwise.
*/
-int xe_eudebug_debugger_attach(struct xe_eudebug_debugger *d, pid_t target)
+int xe_eudebug_debugger_attach(struct xe_eudebug_debugger *d,
+ struct xe_eudebug_client *c)
{
int ret;
igt_assert_eq(d->fd, -1);
- ret = xe_eudebug_connect(d->master_fd, target, 0);
+ igt_assert_neq(c->pid, 0);
+ ret = xe_eudebug_connect(d->master_fd, c->pid, 0);
if (ret < 0)
return ret;
d->fd = ret;
- d->target_pid = target;
+ d->target_pid = c->pid;
+ d->p_client[0] = c->p_in[0];
+ d->p_client[1] = c->p_in[1];
igt_debug("debugger connected to %lu\n", d->target_pid);
@@ -848,6 +887,19 @@ void xe_eudebug_debugger_stop_worker(struct xe_eudebug_debugger *d,
event_log_sort(d->log);
}
+/**
+ * xe_eudebug_debugger_signal_stage:
+ * @d: pointer to the debugger
+ * @stage: stage to signal
+ *
+ * Signals to client, waiting in xe_eudebug_client_wait_stage(),
+ * releasing it to proceed.
+ */
+void xe_eudebug_debugger_signal_stage(struct xe_eudebug_debugger *d, uint64_t stage)
+{
+ token_signal(d->p_client, CLIENT_STAGE, stage);
+}
+
/**
* xe_eudebug_client_create:
* @master_fd: xe client used to open the debugger connection
@@ -879,8 +931,11 @@ struct xe_eudebug_client *xe_eudebug_client_create(int master_fd, xe_eudebug_cli
c->done = 0;
c->ptr = data;
c->master_fd = master_fd;
+ c->timeout_ms = XE_EUDEBUG_DEFAULT_TIMEOUT_MS;
igt_fork(child, 1) {
+ int mypid;
+
igt_assert_eq(c->pid, 0);
close(c->p_out[0]);
@@ -888,17 +943,20 @@ struct xe_eudebug_client *xe_eudebug_client_create(int master_fd, xe_eudebug_cli
close(c->p_in[1]);
c->p_in[1] = -1;
- pipe_signal(c->p_out, CLIENT_PID);
- pipe_signal(c->p_out, getpid());
+ mypid = getpid();
+ client_signal(c, CLIENT_PID, mypid);
- pipe_wait_token(c->p_in, CLIENT_RUN);
- work(c);
- pipe_signal(c->p_out, CLIENT_FINI);
+ c->pid = client_wait_token(c, CLIENT_RUN);
+ igt_assert_eq(c->pid, mypid);
+ if (work)
+ work(c);
+
+ client_signal(c, CLIENT_FINI, c->seqno);
- igt_assert_eq(c->pid, 0);
event_log_write_to_fd(c->log, c->p_out[1]);
- pipe_signal(c->p_out, c->seqno);
- pipe_wait_token(c->p_in, CLIENT_STOP);
+
+ c->pid = client_wait_token(c, CLIENT_STOP);
+ igt_assert_eq(c->pid, mypid);
}
close(c->p_out[1]);
@@ -906,8 +964,7 @@ struct xe_eudebug_client *xe_eudebug_client_create(int master_fd, xe_eudebug_cli
close(c->p_in[0]);
c->p_in[0] = -1;
- pipe_wait_token(c->p_out, CLIENT_PID);
- c->pid = pipe_wait(c->p_out);
+ c->pid = wait_from_client(c, CLIENT_PID);
igt_info("client running with pid %d\n", c->pid);
@@ -927,7 +984,7 @@ void xe_eudebug_client_stop(struct xe_eudebug_client *c)
xe_eudebug_client_wait_done(c);
- pipe_signal(c->p_in, CLIENT_STOP);
+ token_signal(c->p_in, CLIENT_STOP, c->pid);
igt_assert_eq(waitpid(c->pid, &waitstatus, 0),
c->pid);
c->pid = 0;
@@ -971,7 +1028,7 @@ uint64_t xe_eudebug_client_get_seqno(struct xe_eudebug_client *c)
*/
void xe_eudebug_client_start(struct xe_eudebug_client *c)
{
- pipe_signal(c->p_in, CLIENT_RUN);
+ token_signal(c->p_in, CLIENT_RUN, c->pid);
}
/**
@@ -985,12 +1042,40 @@ void xe_eudebug_client_wait_done(struct xe_eudebug_client *c)
{
if (!c->done) {
c->done = 1;
- pipe_wait_token(c->p_out, CLIENT_FINI);
+ c->seqno = wait_from_client(c, CLIENT_FINI);
event_log_read_from_fd(c->log, c->p_out[0]);
- c->seqno = pipe_wait(c->p_out);
}
}
+/**
+ * xe_eudebug_client_wait_stage:
+ * @c: pointer to xe_eudebug_client structure
+ * @stage: stage to wait on
+ *
+ * Pauses client until the debugger has signalled the corresponding stage with
+ * xe_eudebug_debugger_signal_stage. This is only for situations where the
+ * actual event flow is not enough to coordinate between client/debugger and extra
+ * sync mechanism is needed.
+ *
+ */
+void xe_eudebug_client_wait_stage(struct xe_eudebug_client *c, uint64_t stage)
+{
+ u64 stage_in;
+
+ if (c->done) {
+ igt_warn("client: %d already done before %lu\n", c->pid, stage);
+ return;
+ }
+
+ igt_debug("client: %d pausing for stage %lu\n", c->pid, stage);
+
+ stage_in = client_wait_token(c, CLIENT_STAGE);
+ igt_debug("client: %d stage %lu, expected %lu, stage\n", c->pid, stage_in, stage);
+
+ igt_assert_eq(stage_in, stage);
+}
+
+
/**
* xe_eudebug_session_create:
* @fd: XE file descriptor
@@ -1031,7 +1116,7 @@ void xe_eudebug_session_run(struct xe_eudebug_session *s)
struct xe_eudebug_debugger *debugger = s->d;
struct xe_eudebug_client *client = s->c;
- igt_assert_eq(xe_eudebug_debugger_attach(debugger, client->pid), 0);
+ igt_assert_eq(xe_eudebug_debugger_attach(debugger, client), 0);
xe_eudebug_debugger_start_worker(debugger);
diff --git a/lib/xe/xe_eudebug.h b/lib/xe/xe_eudebug.h
index a0cae245d..5ec63e46b 100644
--- a/lib/xe/xe_eudebug.h
+++ b/lib/xe/xe_eudebug.h
@@ -36,6 +36,7 @@ struct xe_eudebug_debugger {
pthread_t worker_thread;
int worker_state;
+ int p_client[2];
};
struct xe_eudebug_client {
@@ -54,6 +55,8 @@ struct xe_eudebug_client {
/* Used to pickup right device (the one used in debugger) */
int master_fd;
+
+ int timeout_ms;
};
struct xe_eudebug_session {
@@ -110,13 +113,14 @@ void xe_eudebug_event_log_match_opposite(struct xe_eudebug_event_log *l);
struct xe_eudebug_debugger *
xe_eudebug_debugger_create(int xe, uint64_t flags, void *data);
void xe_eudebug_debugger_destroy(struct xe_eudebug_debugger *d);
-int xe_eudebug_debugger_attach(struct xe_eudebug_debugger *d, pid_t pid);
+int xe_eudebug_debugger_attach(struct xe_eudebug_debugger *d, struct xe_eudebug_client *c);
void xe_eudebug_debugger_start_worker(struct xe_eudebug_debugger *d);
void xe_eudebug_debugger_stop_worker(struct xe_eudebug_debugger *d, int timeout_s);
void xe_eudebug_debugger_dettach(struct xe_eudebug_debugger *d);
void xe_eudebug_debugger_set_data(struct xe_eudebug_debugger *c, void *ptr);
void xe_eudebug_debugger_add_trigger(struct xe_eudebug_debugger *d, int type,
xe_eudebug_trigger_fn fn);
+void xe_eudebug_debugger_signal_stage(struct xe_eudebug_debugger *d, uint64_t stage);
struct xe_eudebug_client *
xe_eudebug_client_create(int xe, xe_eudebug_client_work_fn work, uint64_t flags, void *data);
@@ -124,6 +128,8 @@ void xe_eudebug_client_destroy(struct xe_eudebug_client *c);
void xe_eudebug_client_start(struct xe_eudebug_client *c);
void xe_eudebug_client_stop(struct xe_eudebug_client *c);
void xe_eudebug_client_wait_done(struct xe_eudebug_client *c);
+void xe_eudebug_client_wait_stage(struct xe_eudebug_client *c, uint64_t stage);
+
uint64_t xe_eudebug_client_get_seqno(struct xe_eudebug_client *c);
void xe_eudebug_client_set_data(struct xe_eudebug_client *c, void *ptr);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 04/66] lib/xe_eudebug: Add exec_queue support
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (2 preceding siblings ...)
2024-07-29 16:00 ` [PATCH 03/66] lib/xe_eudebug: Allow client to wait for debugger Christoph Manszewski
@ 2024-07-29 16:00 ` Christoph Manszewski
2024-07-29 16:00 ` [PATCH 05/66] lib/xe_eudebug: Add attention events support Christoph Manszewski
` (63 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:00 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Add support for exec_queue events to eudebug library.
Check event specific fields in post mortem log check. (Christoph)
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Cc: Christoph Manszewski <christoph.manszewski@intel.com>
---
lib/xe/xe_eudebug.c | 188 +++++++++++++++++++++++++++++++++++++++++++-
lib/xe/xe_eudebug.h | 5 +-
2 files changed, 189 insertions(+), 4 deletions(-)
diff --git a/lib/xe/xe_eudebug.c b/lib/xe/xe_eudebug.c
index 70769e532..ca030704b 100644
--- a/lib/xe/xe_eudebug.c
+++ b/lib/xe/xe_eudebug.c
@@ -20,6 +20,17 @@ struct event_trigger {
struct igt_list_head link;
};
+struct seqno_list_entry {
+ struct igt_list_head link;
+ uint64_t seqno;
+};
+
+struct match_dto {
+ struct drm_xe_eudebug_event *target;
+ struct igt_list_head *seqno_list;
+ uint64_t client_handle;
+};
+
#define CLIENT_PID 1
#define CLIENT_RUN 2
#define CLIENT_FINI 3
@@ -41,6 +52,8 @@ static const char *type_to_str(unsigned int type)
return "client";
case DRM_XE_EUDEBUG_EVENT_VM:
return "vm";
+ case DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE:
+ return "exec_queue";
}
return "UNKNOWN";
@@ -83,6 +96,15 @@ static const char *event_members_to_str(struct drm_xe_eudebug_event *e, char *b)
evm->client_handle, evm->vm_handle);
break;
}
+ case DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE: {
+ struct drm_xe_eudebug_event_exec_queue *ee = (void *)e;
+
+ sprintf(b, "client_handle=%llu, vm_handle=%llu, "
+ "exec_queue_handle=%llu, engine_class=%d, exec_queue_width=%d",
+ ee->client_handle, ee->vm_handle,
+ ee->exec_queue_handle, ee->engine_class, ee->width);
+ break;
+ }
default:
strcpy(b, "<...>");
}
@@ -309,6 +331,34 @@ static int match_type_and_flags(struct drm_xe_eudebug_event *a, void *data)
return 0;
}
+static int match_fields(struct drm_xe_eudebug_event *a, void *data)
+{
+ struct drm_xe_eudebug_event *b = data;
+ int ret = 0;
+
+ ret = match_type_and_flags(a, data);
+ if (!ret)
+ return ret;
+
+ ret = 0;
+
+ switch (a->type) {
+ case DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE: {
+ struct drm_xe_eudebug_event_exec_queue *ae = (void *)a;
+ struct drm_xe_eudebug_event_exec_queue *be = (void *)b;
+
+ if (ae->engine_class == be->engine_class && ae->width == be->width)
+ ret = 1;
+ break;
+ }
+ default:
+ ret = 1;
+ break;
+ }
+
+ return ret;
+}
+
static int match_client_handle(struct drm_xe_eudebug_event *e, void *data)
{
uint64_t h = *(uint64_t *)data;
@@ -328,6 +378,13 @@ static int match_client_handle(struct drm_xe_eudebug_event *e, void *data)
return 1;
break;
}
+ case DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE: {
+ struct drm_xe_eudebug_event_exec_queue *ee = (struct drm_xe_eudebug_event_exec_queue *)e;
+
+ if (ee->client_handle == h)
+ return 1;
+ break;
+ }
default:
break;
}
@@ -365,12 +422,43 @@ static int match_opposite_resource(struct drm_xe_eudebug_event *e, void *data)
return 1;
break;
}
+ case DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE: {
+ struct drm_xe_eudebug_event_exec_queue *ee = (void *)e;
+ struct drm_xe_eudebug_event_exec_queue *filter = (struct drm_xe_eudebug_event_exec_queue *)data;
+
+ if (ee->exec_queue_handle == filter->exec_queue_handle)
+ return 1;
+ break;
+ }
default:
break;
}
return 0;
}
+static int match_full(struct drm_xe_eudebug_event *e, void *data)
+{
+ struct seqno_list_entry *sl;
+
+ struct match_dto *md = (void *)data;
+ int ret = 0;
+
+ ret = match_client_handle(e, &md->client_handle);
+ if (!ret)
+ return 0;
+
+ ret = match_fields(e, md->target);
+ if (!ret)
+ return 0;
+
+ igt_list_for_each_entry(sl, md->seqno_list, link) {
+ if (sl->seqno == e->seqno)
+ return 0;
+ }
+
+ return 1;
+}
+
static struct drm_xe_eudebug_event *
event_type_match(struct xe_eudebug_event_log *l,
struct drm_xe_eudebug_event *filter,
@@ -395,6 +483,21 @@ opposite_event_match(struct xe_eudebug_event_log *l,
return event_cmp(l, current, match_opposite_resource, filter);
}
+static struct drm_xe_eudebug_event *
+event_match(struct xe_eudebug_event_log *l,
+ struct drm_xe_eudebug_event *target,
+ uint64_t client_handle,
+ struct igt_list_head *seqno_list)
+{
+ struct match_dto md = {
+ .target = target,
+ .client_handle = client_handle,
+ .seqno_list = seqno_list,
+ };
+
+ return event_cmp(l, NULL, match_full, &md);
+}
+
static void compare_client(struct xe_eudebug_event_log *c, struct drm_xe_eudebug_event *_ce,
struct xe_eudebug_event_log *d, struct drm_xe_eudebug_event *_de)
{
@@ -402,6 +505,9 @@ static void compare_client(struct xe_eudebug_event_log *c, struct drm_xe_eudebug
struct drm_xe_eudebug_event_client *de = (void *)_de;
struct drm_xe_eudebug_event *hc, *hd;
+ struct igt_list_head matched_seqno_list;
+ struct seqno_list_entry *entry, *tmp;
+
igt_assert(ce);
igt_assert(de);
@@ -409,13 +515,14 @@ static void compare_client(struct xe_eudebug_event_log *c, struct drm_xe_eudebug
hc = NULL;
hd = NULL;
+ IGT_INIT_LIST_HEAD(&matched_seqno_list);
do {
hc = client_match(c, ce->client_handle, hc);
if (!hc)
break;
- hd = client_match(d, de->client_handle, hd);
+ hd = event_match(d, hc, de->client_handle, &matched_seqno_list);
igt_assert_f(hd, "%s (%llu): no matching event type %u found for client %llu\n",
c->name,
@@ -426,9 +533,18 @@ static void compare_client(struct xe_eudebug_event_log *c, struct drm_xe_eudebug
igt_debug("comparing %s %llu vs %s %llu\n",
c->name, hc->seqno, d->name, hd->seqno);
- igt_assert_eq(hc->type, hd->type);
- igt_assert_eq(hc->flags, hd->flags);
+ /*
+ * Store the seqno of the event that was matched above,
+ * inside 'matched_seqno_list', to avoid it getting matched
+ * by subsequent 'event_match' calls.
+ */
+ entry = malloc(sizeof(*entry));
+ entry->seqno = hd->seqno;
+ igt_list_add(&entry->link, &matched_seqno_list);
} while (hc);
+
+ igt_list_for_each_entry_safe(entry, tmp, &matched_seqno_list, link)
+ free(entry);
}
/*
@@ -1196,6 +1312,25 @@ static void vm_event(struct xe_eudebug_client *c, uint32_t flags, int client_fd,
xe_eudebug_event_log_write(c->log, (void *)&evm);
}
+static void exec_queue_event(struct xe_eudebug_client *c, uint32_t flags,
+ int client_fd, uint32_t vm_id,
+ uint32_t exec_queue_handle, uint16_t class,
+ uint16_t width)
+{
+ struct drm_xe_eudebug_event_exec_queue ee;
+
+ base_event(c, to_base(ee), DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE,
+ flags, sizeof(ee));
+
+ ee.client_handle = client_fd;
+ ee.vm_handle = vm_id;
+ ee.exec_queue_handle = exec_queue_handle;
+ ee.engine_class = class;
+ ee.width = width;
+
+ xe_eudebug_event_log_write(c->log, (void *)&ee);
+}
+
/* Eu debugger wrappers around resource creating xe ioctls. */
/**
@@ -1268,3 +1403,50 @@ void xe_eudebug_client_vm_destroy(struct xe_eudebug_client *c, int fd, uint32_t
xe_vm_destroy(fd, vm);
vm_event(c, DRM_XE_EUDEBUG_EVENT_DESTROY, fd, vm);
}
+
+/**
+ * xe_eudebug_client_exec_queue_create:
+ * @c: pointer to xe_eudebug_client structure
+ * @fd: xe client
+ * @create: exec_queue create drm struct
+ *
+ * Calls xe exec queue create ioctl and logs the corresponding event in
+ * client's event log.
+ *
+ * Returns: valid exec queue handle
+ */
+uint32_t xe_eudebug_client_exec_queue_create(struct xe_eudebug_client *c, int fd,
+ struct drm_xe_exec_queue_create *create)
+{
+ uint16_t class = ((struct drm_xe_engine_class_instance *)(create->instances))[0].engine_class;
+
+ igt_assert_eq(igt_ioctl(fd, DRM_IOCTL_XE_EXEC_QUEUE_CREATE, create), 0);
+
+ if (class == DRM_XE_ENGINE_CLASS_COMPUTE || class == DRM_XE_ENGINE_CLASS_RENDER)
+ exec_queue_event(c, DRM_XE_EUDEBUG_EVENT_CREATE, fd, create->vm_id,
+ create->exec_queue_id, class, create->width);
+
+ return create->exec_queue_id;
+}
+
+/**
+ * xe_eudebug_client_exec_queue_destroy:
+ * @c: pointer to xe_eudebug_client structure
+ * @fd: xe client
+ * @create: exec_queue create drm struct which was used for creation
+ *
+ * Calls xe exec_queue destroy ioctl and logs the corresponding event in
+ * client's event log.
+ */
+void xe_eudebug_client_exec_queue_destroy(struct xe_eudebug_client *c, int fd,
+ struct drm_xe_exec_queue_create *create)
+{
+ struct drm_xe_exec_queue_destroy destroy = { .exec_queue_id = create->exec_queue_id, };
+ uint16_t class = ((struct drm_xe_engine_class_instance *)(create->instances))[0].engine_class;
+
+ if (class == DRM_XE_ENGINE_CLASS_COMPUTE || class == DRM_XE_ENGINE_CLASS_RENDER)
+ exec_queue_event(c, DRM_XE_EUDEBUG_EVENT_DESTROY, fd, create->vm_id,
+ create->exec_queue_id, class, create->width);
+
+ igt_assert_eq(igt_ioctl(fd, DRM_IOCTL_XE_EXEC_QUEUE_DESTROY, &destroy), 0);
+}
diff --git a/lib/xe/xe_eudebug.h b/lib/xe/xe_eudebug.h
index 5ec63e46b..8dc153d27 100644
--- a/lib/xe/xe_eudebug.h
+++ b/lib/xe/xe_eudebug.h
@@ -138,6 +138,10 @@ void xe_eudebug_client_close_driver(struct xe_eudebug_client *c, int fd);
uint32_t xe_eudebug_client_vm_create(struct xe_eudebug_client *c, int fd,
uint32_t flags, uint64_t ext);
void xe_eudebug_client_vm_destroy(struct xe_eudebug_client *c, int fd, uint32_t vm);
+uint32_t xe_eudebug_client_exec_queue_create(struct xe_eudebug_client *c, int fd,
+ struct drm_xe_exec_queue_create *create);
+void xe_eudebug_client_exec_queue_destroy(struct xe_eudebug_client *c, int fd,
+ struct drm_xe_exec_queue_create *create);
struct xe_eudebug_session *xe_eudebug_session_create(int fd,
xe_eudebug_client_work_fn work,
@@ -146,4 +150,3 @@ struct xe_eudebug_session *xe_eudebug_session_create(int fd,
void xe_eudebug_session_destroy(struct xe_eudebug_session *s);
void xe_eudebug_session_run(struct xe_eudebug_session *s);
void xe_eudebug_session_check(struct xe_eudebug_session *s, bool match_opposite);
-
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 05/66] lib/xe_eudebug: Add attention events support
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (3 preceding siblings ...)
2024-07-29 16:00 ` [PATCH 04/66] lib/xe_eudebug: Add exec_queue support Christoph Manszewski
@ 2024-07-29 16:00 ` Christoph Manszewski
2024-07-29 16:00 ` [PATCH 06/66] lib/xe_ioctl: Add wrapper with vm_bind_op extension parameter Christoph Manszewski
` (62 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:00 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Respect attention events in eu debugger library.
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Cc: Christoph Manszewski <christoph.manszewski@intel.com>
---
lib/xe/xe_eudebug.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/lib/xe/xe_eudebug.c b/lib/xe/xe_eudebug.c
index ca030704b..801317a23 100644
--- a/lib/xe/xe_eudebug.c
+++ b/lib/xe/xe_eudebug.c
@@ -54,6 +54,8 @@ static const char *type_to_str(unsigned int type)
return "vm";
case DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE:
return "exec_queue";
+ case DRM_XE_EUDEBUG_EVENT_EU_ATTENTION:
+ return "attention";
}
return "UNKNOWN";
@@ -105,6 +107,15 @@ static const char *event_members_to_str(struct drm_xe_eudebug_event *e, char *b)
ee->exec_queue_handle, ee->engine_class, ee->width);
break;
}
+ case DRM_XE_EUDEBUG_EVENT_EU_ATTENTION: {
+ struct drm_xe_eudebug_event_eu_attention *ea = (void *)e;
+
+ sprintf(b, "client_handle=%llu, exec_queue_handle=%llu, "
+ "lrc_handle=%llu, bitmask_size=%d",
+ ea->client_handle, ea->exec_queue_handle,
+ ea->lrc_handle, ea->bitmask_size);
+ break;
+ }
default:
strcpy(b, "<...>");
}
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 06/66] lib/xe_ioctl: Add wrapper with vm_bind_op extension parameter
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (4 preceding siblings ...)
2024-07-29 16:00 ` [PATCH 05/66] lib/xe_eudebug: Add attention events support Christoph Manszewski
@ 2024-07-29 16:00 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 07/66] lib/xe_eudebug: Add support for vm_bind events Christoph Manszewski
` (61 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:00 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski, Mika Kuoppala
Currently there is no way to set drm_xe_vm_bind_op extension field. Add
vm_bind wrapper that allows pass this field as a parameter.
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
---
lib/xe/xe_ioctl.c | 20 ++++++++++++++++----
lib/xe/xe_ioctl.h | 5 +++++
2 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/lib/xe/xe_ioctl.c b/lib/xe/xe_ioctl.c
index ae43ffd15..6d8388918 100644
--- a/lib/xe/xe_ioctl.c
+++ b/lib/xe/xe_ioctl.c
@@ -96,15 +96,17 @@ void xe_vm_bind_array(int fd, uint32_t vm, uint32_t exec_queue,
igt_assert_eq(igt_ioctl(fd, DRM_IOCTL_XE_VM_BIND, &bind), 0);
}
-int __xe_vm_bind(int fd, uint32_t vm, uint32_t exec_queue, uint32_t bo,
- uint64_t offset, uint64_t addr, uint64_t size, uint32_t op,
- uint32_t flags, struct drm_xe_sync *sync, uint32_t num_syncs,
- uint32_t prefetch_region, uint8_t pat_index, uint64_t ext)
+int ___xe_vm_bind(int fd, uint32_t vm, uint32_t exec_queue, uint32_t bo,
+ uint64_t offset, uint64_t addr, uint64_t size, uint32_t op,
+ uint32_t flags, struct drm_xe_sync *sync, uint32_t num_syncs,
+ uint32_t prefetch_region, uint8_t pat_index, uint64_t ext,
+ uint64_t op_ext)
{
struct drm_xe_vm_bind bind = {
.extensions = ext,
.vm_id = vm,
.num_binds = 1,
+ .bind.extensions = op_ext,
.bind.obj = bo,
.bind.obj_offset = offset,
.bind.range = size,
@@ -125,6 +127,16 @@ int __xe_vm_bind(int fd, uint32_t vm, uint32_t exec_queue, uint32_t bo,
return 0;
}
+int __xe_vm_bind(int fd, uint32_t vm, uint32_t exec_queue, uint32_t bo,
+ uint64_t offset, uint64_t addr, uint64_t size, uint32_t op,
+ uint32_t flags, struct drm_xe_sync *sync, uint32_t num_syncs,
+ uint32_t prefetch_region, uint8_t pat_index, uint64_t ext)
+{
+ return ___xe_vm_bind(fd, vm, exec_queue, bo, offset, addr, size, op,
+ flags, sync, num_syncs, prefetch_region,
+ pat_index, ext, 0);
+}
+
void __xe_vm_bind_assert(int fd, uint32_t vm, uint32_t exec_queue, uint32_t bo,
uint64_t offset, uint64_t addr, uint64_t size,
uint32_t op, uint32_t flags, struct drm_xe_sync *sync,
diff --git a/lib/xe/xe_ioctl.h b/lib/xe/xe_ioctl.h
index b27c0053f..18cc2b72b 100644
--- a/lib/xe/xe_ioctl.h
+++ b/lib/xe/xe_ioctl.h
@@ -20,6 +20,11 @@
uint32_t xe_cs_prefetch_size(int fd);
uint64_t xe_bb_size(int fd, uint64_t reqsize);
uint32_t xe_vm_create(int fd, uint32_t flags, uint64_t ext);
+int ___xe_vm_bind(int fd, uint32_t vm, uint32_t exec_queue, uint32_t bo,
+ uint64_t offset, uint64_t addr, uint64_t size, uint32_t op,
+ uint32_t flags, struct drm_xe_sync *sync, uint32_t num_syncs,
+ uint32_t prefetch_region, uint8_t pat_index, uint64_t ext,
+ uint64_t op_ext);
int __xe_vm_bind(int fd, uint32_t vm, uint32_t exec_queue, uint32_t bo,
uint64_t offset, uint64_t addr, uint64_t size, uint32_t op,
uint32_t flags, struct drm_xe_sync *sync, uint32_t num_syncs,
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 07/66] lib/xe_eudebug: Add support for vm_bind events
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (5 preceding siblings ...)
2024-07-29 16:00 ` [PATCH 06/66] lib/xe_ioctl: Add wrapper with vm_bind_op extension parameter Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 08/66] lib/xe_eudebug: Add metadata support Christoph Manszewski
` (60 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski, Mika Kuoppala
Add support for logging and filtering vm_bind events.
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
lib/xe/xe_eudebug.c | 488 +++++++++++++++++++++++++++++++++++++++++---
lib/xe/xe_eudebug.h | 45 +++-
2 files changed, 507 insertions(+), 26 deletions(-)
diff --git a/lib/xe/xe_eudebug.c b/lib/xe/xe_eudebug.c
index 801317a23..97f847409 100644
--- a/lib/xe/xe_eudebug.c
+++ b/lib/xe/xe_eudebug.c
@@ -11,6 +11,7 @@
#include <sys/wait.h>
#include "igt.h"
+#include "intel_pat.h"
#include "xe_eudebug.h"
#include "xe_ioctl.h"
@@ -29,6 +30,12 @@ struct match_dto {
struct drm_xe_eudebug_event *target;
struct igt_list_head *seqno_list;
uint64_t client_handle;
+ uint32_t filter;
+
+ /* store latest 'EVENT_VM_BIND' seqno */
+ uint64_t *bind_seqno;
+ /* latest vm_bind_op seqno matching bind_seqno */
+ uint64_t *bind_op_seqno;
};
#define CLIENT_PID 1
@@ -56,6 +63,12 @@ static const char *type_to_str(unsigned int type)
return "exec_queue";
case DRM_XE_EUDEBUG_EVENT_EU_ATTENTION:
return "attention";
+ case DRM_XE_EUDEBUG_EVENT_VM_BIND:
+ return "vm_bind";
+ case DRM_XE_EUDEBUG_EVENT_VM_BIND_OP:
+ return "vm_bind_op";
+ case DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE:
+ return "vm_bind_ufence";
}
return "UNKNOWN";
@@ -70,15 +83,20 @@ static const char *event_type_to_str(struct drm_xe_eudebug_event *e, char *buf)
static const char *flags_to_str(unsigned int flags)
{
- if (flags & DRM_XE_EUDEBUG_EVENT_CREATE)
- return "create";
-
+ if (flags & DRM_XE_EUDEBUG_EVENT_CREATE) {
+ if (flags & DRM_XE_EUDEBUG_EVENT_NEED_ACK)
+ return "create|ack";
+ else
+ return "create";
+ }
if (flags & DRM_XE_EUDEBUG_EVENT_DESTROY)
return "destroy";
if (flags & DRM_XE_EUDEBUG_EVENT_STATE_CHANGE)
return "state-change";
+ igt_assert(!(flags & DRM_XE_EUDEBUG_EVENT_NEED_ACK));
+
return "flags unknown";
}
@@ -116,6 +134,26 @@ static const char *event_members_to_str(struct drm_xe_eudebug_event *e, char *b)
ea->lrc_handle, ea->bitmask_size);
break;
}
+ case DRM_XE_EUDEBUG_EVENT_VM_BIND: {
+ struct drm_xe_eudebug_event_vm_bind *evmb = (void *)e;
+
+ sprintf(b, "client_handle=%llu, vm_handle=%llu, flags=0x%x, num_binds=%u",
+ evmb->client_handle, evmb->vm_handle, evmb->flags, evmb->num_binds);
+ break;
+ }
+ case DRM_XE_EUDEBUG_EVENT_VM_BIND_OP: {
+ struct drm_xe_eudebug_event_vm_bind_op *op = (void *)e;
+
+ sprintf(b, "vm_bind_ref_seqno=%lld, addr=%016llx, range=%llu num_extensions=%llu",
+ op->vm_bind_ref_seqno, op->addr, op->range, op->num_extensions);
+ break;
+ }
+ case DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE: {
+ struct drm_xe_eudebug_event_vm_bind_ufence *f = (void *)e;
+
+ sprintf(b, "vm_bind_ref_seqno=%lld", f->vm_bind_ref_seqno);
+ break;
+ }
default:
strcpy(b, "<...>");
}
@@ -362,6 +400,23 @@ static int match_fields(struct drm_xe_eudebug_event *a, void *data)
ret = 1;
break;
}
+ case DRM_XE_EUDEBUG_EVENT_VM_BIND: {
+ struct drm_xe_eudebug_event_vm_bind *ea = (void *)a;
+ struct drm_xe_eudebug_event_vm_bind *eb = (void *)b;
+
+ if (ea->num_binds == eb->num_binds)
+ ret = 1;
+ break;
+ }
+ case DRM_XE_EUDEBUG_EVENT_VM_BIND_OP: {
+ struct drm_xe_eudebug_event_vm_bind_op *ea = (void *)a;
+ struct drm_xe_eudebug_event_vm_bind_op *eb = (void *)b;
+
+ if (ea->addr == eb->addr && ea->range == eb->range &&
+ ea->num_extensions == eb->num_extensions)
+ ret = 1;
+ break;
+ }
default:
ret = 1;
break;
@@ -372,7 +427,13 @@ static int match_fields(struct drm_xe_eudebug_event *a, void *data)
static int match_client_handle(struct drm_xe_eudebug_event *e, void *data)
{
- uint64_t h = *(uint64_t *)data;
+ struct match_dto *md = (void *)data;
+ uint64_t *bind_seqno = md->bind_seqno;
+ uint64_t *bind_op_seqno = md->bind_op_seqno;
+ uint64_t h = md->client_handle;
+
+ if (XE_EUDEBUG_EVENT_IS_FILTERED(e->type, md->filter))
+ return 0;
switch (e->type) {
case DRM_XE_EUDEBUG_EVENT_OPEN: {
@@ -396,6 +457,32 @@ static int match_client_handle(struct drm_xe_eudebug_event *e, void *data)
return 1;
break;
}
+ case DRM_XE_EUDEBUG_EVENT_VM_BIND: {
+ struct drm_xe_eudebug_event_vm_bind *evmb = (struct drm_xe_eudebug_event_vm_bind *)e;
+
+ if (evmb->client_handle == h) {
+ *bind_seqno = evmb->base.seqno;
+ return 1;
+ }
+ break;
+ }
+ case DRM_XE_EUDEBUG_EVENT_VM_BIND_OP: {
+ struct drm_xe_eudebug_event_vm_bind_op *eo = (struct drm_xe_eudebug_event_vm_bind_op *)e;
+
+ if (eo->vm_bind_ref_seqno == *bind_seqno) {
+ *bind_op_seqno = eo->base.seqno;
+ return 1;
+ }
+ break;
+ }
+ case DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE: {
+ struct drm_xe_eudebug_event_vm_bind_ufence *ef = (struct drm_xe_eudebug_event_vm_bind_ufence *)e;
+
+ if (ef->vm_bind_ref_seqno == *bind_seqno)
+ return 1;
+
+ break;
+ }
default:
break;
}
@@ -410,6 +497,7 @@ static int match_opposite_resource(struct drm_xe_eudebug_event *e, void *data)
int ret;
d->flags ^= DRM_XE_EUDEBUG_EVENT_CREATE | DRM_XE_EUDEBUG_EVENT_DESTROY;
+ d->flags &= ~(DRM_XE_EUDEBUG_EVENT_NEED_ACK);
ret = match_type_and_flags(e, data);
d->flags ^= DRM_XE_EUDEBUG_EVENT_CREATE | DRM_XE_EUDEBUG_EVENT_DESTROY;
@@ -441,6 +529,24 @@ static int match_opposite_resource(struct drm_xe_eudebug_event *e, void *data)
return 1;
break;
}
+ case DRM_XE_EUDEBUG_EVENT_VM_BIND: {
+ struct drm_xe_eudebug_event_vm_bind *evmb = (void *)e;
+ struct drm_xe_eudebug_event_vm_bind *filter = (struct drm_xe_eudebug_event_vm_bind *)data;
+
+ if (evmb->vm_handle == filter->vm_handle &&
+ evmb->num_binds == filter->num_binds)
+ return 1;
+ break;
+ }
+ case DRM_XE_EUDEBUG_EVENT_VM_BIND_OP: {
+ struct drm_xe_eudebug_event_vm_bind_op *avmb = (void *)e;
+ struct drm_xe_eudebug_event_vm_bind_op *filter = (struct drm_xe_eudebug_event_vm_bind_op *)data;
+
+ if (avmb->addr == filter->addr &&
+ avmb->range == filter->range)
+ return 1;
+ break;
+ }
default:
break;
}
@@ -454,7 +560,7 @@ static int match_full(struct drm_xe_eudebug_event *e, void *data)
struct match_dto *md = (void *)data;
int ret = 0;
- ret = match_client_handle(e, &md->client_handle);
+ ret = match_client_handle(e, md);
if (!ret)
return 0;
@@ -472,51 +578,67 @@ static int match_full(struct drm_xe_eudebug_event *e, void *data)
static struct drm_xe_eudebug_event *
event_type_match(struct xe_eudebug_event_log *l,
- struct drm_xe_eudebug_event *filter,
+ struct drm_xe_eudebug_event *target,
struct drm_xe_eudebug_event *current)
{
- return event_cmp(l, current, match_type_and_flags, filter);
+ return event_cmp(l, current, match_type_and_flags, target);
}
static struct drm_xe_eudebug_event *
client_match(struct xe_eudebug_event_log *l,
uint64_t client_handle,
- struct drm_xe_eudebug_event *current)
+ struct drm_xe_eudebug_event *current,
+ uint32_t filter,
+ uint64_t *bind_seqno,
+ uint64_t *bind_op_seqno)
{
- return event_cmp(l, current, match_client_handle, &client_handle);
+ struct match_dto md = {
+ .client_handle = client_handle,
+ .filter = filter,
+ .bind_seqno = bind_seqno,
+ .bind_op_seqno = bind_op_seqno,
+ };
+
+ return event_cmp(l, current, match_client_handle, &md);
}
static struct drm_xe_eudebug_event *
opposite_event_match(struct xe_eudebug_event_log *l,
- struct drm_xe_eudebug_event *filter,
+ struct drm_xe_eudebug_event *target,
struct drm_xe_eudebug_event *current)
{
- return event_cmp(l, current, match_opposite_resource, filter);
+ return event_cmp(l, current, match_opposite_resource, target);
}
static struct drm_xe_eudebug_event *
event_match(struct xe_eudebug_event_log *l,
struct drm_xe_eudebug_event *target,
uint64_t client_handle,
- struct igt_list_head *seqno_list)
+ struct igt_list_head *seqno_list,
+ uint64_t *bind_seqno,
+ uint64_t *bind_op_seqno)
{
struct match_dto md = {
.target = target,
.client_handle = client_handle,
.seqno_list = seqno_list,
+ .bind_seqno = bind_seqno,
+ .bind_op_seqno = bind_op_seqno,
};
return event_cmp(l, NULL, match_full, &md);
}
static void compare_client(struct xe_eudebug_event_log *c, struct drm_xe_eudebug_event *_ce,
- struct xe_eudebug_event_log *d, struct drm_xe_eudebug_event *_de)
+ struct xe_eudebug_event_log *d, struct drm_xe_eudebug_event *_de,
+ uint32_t filter)
{
struct drm_xe_eudebug_event_client *ce = (void *)_ce;
struct drm_xe_eudebug_event_client *de = (void *)_de;
- struct drm_xe_eudebug_event *hc, *hd;
+ uint64_t cbs = 0, dbs = 0, cbso = 0, dbso = 0;
struct igt_list_head matched_seqno_list;
+ struct drm_xe_eudebug_event *hc, *hd;
struct seqno_list_entry *entry, *tmp;
igt_assert(ce);
@@ -529,11 +651,11 @@ static void compare_client(struct xe_eudebug_event_log *c, struct drm_xe_eudebug
IGT_INIT_LIST_HEAD(&matched_seqno_list);
do {
- hc = client_match(c, ce->client_handle, hc);
+ hc = client_match(c, ce->client_handle, hc, filter, &cbs, &cbso);
if (!hc)
break;
- hd = event_match(d, hc, de->client_handle, &matched_seqno_list);
+ hd = event_match(d, hc, de->client_handle, &matched_seqno_list, &dbs, &dbso);
igt_assert_f(hd, "%s (%llu): no matching event type %u found for client %llu\n",
c->name,
@@ -714,11 +836,15 @@ xe_eudebug_event_log_print(struct xe_eudebug_event_log *l, bool debug)
* xe_eudebug_event_log_compare:
* @a: event log pointer
* @b: event log pointer
+ * @filter: mask that represents events to be skipped during comparison, useful
+ * for events like 'VM_BIND' since they can be asymmetric. Note that
+ * 'DRM_XE_EUDEUBG_EVENT_OPEN' will always be matched.
*
* Compares and asserts event logs @a, @b if the event
* sequence matches.
*/
-void xe_eudebug_event_log_compare(struct xe_eudebug_event_log *a, struct xe_eudebug_event_log *b)
+void xe_eudebug_event_log_compare(struct xe_eudebug_event_log *a, struct xe_eudebug_event_log *b,
+ uint32_t filter)
{
struct drm_xe_eudebug_event *ae = NULL;
struct drm_xe_eudebug_event *be = NULL;
@@ -728,8 +854,8 @@ void xe_eudebug_event_log_compare(struct xe_eudebug_event_log *a, struct xe_eude
ae->flags & DRM_XE_EUDEBUG_EVENT_CREATE) {
be = event_type_match(b, ae, be);
- compare_client(a, ae, b, be);
- compare_client(b, be, a, ae);
+ compare_client(a, ae, b, be, filter);
+ compare_client(b, be, a, ae, filter);
}
}
}
@@ -737,11 +863,13 @@ void xe_eudebug_event_log_compare(struct xe_eudebug_event_log *a, struct xe_eude
/**
* xe_eudebug_event_log_match_opposite:
* @l: event log pointer
+ * @filter: mask that represents events to be skipped during comparison, useful
+ * for events like 'VM_BIND' since they can be asymmetric
*
* Matches and asserts content of all opposite events (create vs destroy).
*/
void
-xe_eudebug_event_log_match_opposite(struct xe_eudebug_event_log *l)
+xe_eudebug_event_log_match_opposite(struct xe_eudebug_event_log *l, uint32_t filter)
{
struct drm_xe_eudebug_event *ce = NULL;
struct drm_xe_eudebug_event *de = NULL;
@@ -751,6 +879,14 @@ xe_eudebug_event_log_match_opposite(struct xe_eudebug_event_log *l)
uint8_t offset = sizeof(struct drm_xe_eudebug_event);
int opposite_matching;
+ if (XE_EUDEBUG_EVENT_IS_FILTERED(ce->type, filter))
+ continue;
+
+ /* No opposite matching for binds */
+ if (ce->type >= DRM_XE_EUDEBUG_EVENT_VM_BIND &&
+ ce->type <= DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE)
+ continue;
+
de = opposite_event_match(l, ce, ce);
igt_assert_f(de, "no opposite event of type %u found\n", ce->type);
@@ -1261,15 +1397,17 @@ void xe_eudebug_session_run(struct xe_eudebug_session *s)
* @s: pointer to xe_eudebug_session structure
* @match_opposite: indicates whether check should match all
* create and destroy events.
+ * @filter: mask that represents events to be skipped during comparison, useful
+ * for events like 'VM_BIND' since they can be asymmetric
*
* Validate debugger's log against the log created by the client.
*/
-void xe_eudebug_session_check(struct xe_eudebug_session *s, bool match_opposite)
+void xe_eudebug_session_check(struct xe_eudebug_session *s, bool match_opposite, uint32_t filter)
{
- xe_eudebug_event_log_compare(s->c->log, s->d->log);
+ xe_eudebug_event_log_compare(s->c->log, s->d->log, filter);
if (match_opposite)
- xe_eudebug_event_log_match_opposite(s->d->log);
+ xe_eudebug_event_log_match_opposite(s->d->log, filter);
}
/**
@@ -1461,3 +1599,307 @@ void xe_eudebug_client_exec_queue_destroy(struct xe_eudebug_client *c, int fd,
igt_assert_eq(igt_ioctl(fd, DRM_IOCTL_XE_EXEC_QUEUE_DESTROY, &destroy), 0);
}
+
+/**
+ * xe_eudebug_client_vm_bind_event:
+ * @c: pointer to xe_eudebug_client structure
+ * @event_flags: base event flags
+ * @fd: xe client
+ * @vm: vm handle
+ * @bind_flags: bind flags of vm_bind_event
+ * @num_binds: number of bind (operations) for event
+ * @ref_seqno: base vm bind reference seqno
+ * Logs vm bind event in client's event log.
+ */
+void xe_eudebug_client_vm_bind_event(struct xe_eudebug_client *c,
+ uint32_t event_flags, int fd,
+ uint32_t vm, uint32_t bind_flags,
+ uint32_t num_binds, u64 *ref_seqno)
+{
+ struct drm_xe_eudebug_event_vm_bind evmb;
+
+ base_event(c, to_base(evmb), DRM_XE_EUDEBUG_EVENT_VM_BIND,
+ event_flags, sizeof(evmb));
+ evmb.client_handle = fd;
+ evmb.vm_handle = vm;
+ evmb.flags = bind_flags;
+ evmb.num_binds = num_binds;
+
+ *ref_seqno = evmb.base.seqno;
+
+ xe_eudebug_event_log_write(c->log, (void *)&evmb);
+}
+
+/**
+ * xe_eudebug_client_vm_bind_op_event:
+ * @c: pointer to xe_eudebug_client structure
+ * @event_flags: base event flags
+ * @bind_ref_seqno: base vm bind reference seqno
+ * @op_ref_seqno: output, the vm_bind_op event seqno
+ * @addr: ppgtt address
+ * @size: size of the binding
+ * @num_extensions: number of vm bind op extensions
+ *
+ * Logs vm bind op event in client's event log.
+ */
+void xe_eudebug_client_vm_bind_op_event(struct xe_eudebug_client *c, uint32_t event_flags,
+ uint64_t bind_ref_seqno, uint64_t *op_ref_seqno,
+ uint64_t addr, uint64_t range,
+ uint64_t num_extensions)
+{
+ struct drm_xe_eudebug_event_vm_bind_op op;
+
+ base_event(c, to_base(op), DRM_XE_EUDEBUG_EVENT_VM_BIND_OP,
+ event_flags, sizeof(op));
+ op.vm_bind_ref_seqno = bind_ref_seqno;
+ op.addr = addr;
+ op.range = range;
+ op.num_extensions = num_extensions;
+
+ *op_ref_seqno = op.base.seqno;
+
+ xe_eudebug_event_log_write(c->log, (void *)&op);
+}
+
+/**
+ * xe_eudebug_client_vm_bind_op_metadata_event:
+ * @c: pointer to xe_eudebug_client structure
+ * @event_flags: base event flags
+ * @op_ref_seqno: base vm bind op reference seqno
+ * @metadata_handle: metadata handle
+ * @metadata_cookie: metadata cookie
+ *
+ * Logs vm bind op metadata event in client's event log.
+ */
+void xe_eudebug_client_vm_bind_op_metadata_event(struct xe_eudebug_client *c,
+ uint32_t event_flags, uint64_t op_ref_seqno,
+ uint64_t metadata_handle, uint64_t metadata_cookie)
+{
+ struct drm_xe_eudebug_event_vm_bind_op_metadata op;
+
+ base_event(c, to_base(op), DRM_XE_EUDEBUG_EVENT_VM_BIND_OP_METADATA,
+ event_flags, sizeof(op));
+ op.vm_bind_op_ref_seqno = op_ref_seqno;
+ op.metadata_handle = metadata_handle;
+ op.metadata_cookie = metadata_cookie;
+
+ xe_eudebug_event_log_write(c->log, (void *)&op);
+}
+
+/**
+ * xe_eudebug_client_vm_bind_ufence_event:
+ * @c: pointer to xe_eudebug_client structure
+ * @event_flags: base event flags
+ * @ref_seqno: base vm bind event seqno
+ *
+ * Logs vm bind ufence event in client's event log.
+ */
+void xe_eudebug_client_vm_bind_ufence_event(struct xe_eudebug_client *c, uint32_t event_flags,
+ uint64_t ref_seqno)
+{
+ struct drm_xe_eudebug_event_vm_bind_ufence f;
+
+ base_event(c, to_base(f), DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE,
+ event_flags, sizeof(f));
+ f.vm_bind_ref_seqno = ref_seqno;
+
+ xe_eudebug_event_log_write(c->log, (void *)&f);
+}
+
+static bool has_user_fence(const struct drm_xe_sync *sync, uint32_t num_syncs)
+{
+ while (num_syncs--)
+ if (sync[num_syncs].type == DRM_XE_SYNC_TYPE_USER_FENCE)
+ return true;
+
+ return false;
+}
+
+#define for_each_metadata(__m, __ext) \
+ for ((__m) = from_user_pointer(__ext); \
+ (__m); \
+ (__m) = from_user_pointer((__m)->base.next_extension)) \
+ if ((__m)->base.name == XE_VM_BIND_OP_EXTENSIONS_ATTACH_DEBUG)
+
+static int __xe_eudebug_client_vm_bind(struct xe_eudebug_client *c,
+ int fd, uint32_t vm, uint32_t exec_queue,
+ uint32_t bo, uint64_t offset,
+ uint64_t addr, uint64_t size,
+ uint32_t op, uint32_t flags,
+ struct drm_xe_sync *sync,
+ uint32_t num_syncs,
+ uint32_t prefetch_region,
+ uint8_t pat_index, uint64_t op_ext)
+{
+ struct drm_xe_vm_bind_op_ext_attach_debug *metadata;
+ const bool ufence = has_user_fence(sync, num_syncs);
+ const uint32_t bind_flags = ufence ?
+ DRM_XE_EUDEBUG_EVENT_VM_BIND_FLAG_UFENCE : 0;
+ uint64_t seqno = 0, op_seqno = 0, num_metadata = 0;
+ uint32_t bind_base_flags = 0;
+ int ret;
+
+ for_each_metadata(metadata, op_ext)
+ num_metadata++;
+
+ switch (op) {
+ case DRM_XE_VM_BIND_OP_MAP:
+ bind_base_flags = DRM_XE_EUDEBUG_EVENT_CREATE;
+ break;
+ case DRM_XE_VM_BIND_OP_UNMAP:
+ bind_base_flags = DRM_XE_EUDEBUG_EVENT_DESTROY;
+ igt_assert_eq(num_metadata, 0);
+ igt_assert_eq(ufence, false);
+ break;
+ default:
+ /* XXX unmap all? */
+ igt_assert(op);
+ break;
+ }
+
+ ret = ___xe_vm_bind(fd, vm, exec_queue, bo, offset, addr, size,
+ op, flags, sync, num_syncs, prefetch_region,
+ pat_index, 0, op_ext);
+
+ if (ret)
+ return ret;
+
+ if (!bind_base_flags)
+ return -EINVAL;
+
+ xe_eudebug_client_vm_bind_event(c, DRM_XE_EUDEBUG_EVENT_STATE_CHANGE,
+ fd, vm, bind_flags, 1, &seqno);
+ xe_eudebug_client_vm_bind_op_event(c, bind_base_flags,
+ seqno, &op_seqno, addr, size,
+ num_metadata);
+
+ for_each_metadata(metadata, op_ext)
+ xe_eudebug_client_vm_bind_op_metadata_event(c,
+ DRM_XE_EUDEBUG_EVENT_CREATE,
+ op_seqno,
+ metadata->metadata_id,
+ metadata->cookie);
+ if (ufence)
+ xe_eudebug_client_vm_bind_ufence_event(c, DRM_XE_EUDEBUG_EVENT_CREATE |
+ DRM_XE_EUDEBUG_EVENT_NEED_ACK,
+ seqno);
+ return ret;
+}
+
+static void _xe_eudebug_client_vm_bind(struct xe_eudebug_client *c, int fd,
+ uint32_t vm, uint32_t bo,
+ uint64_t offset, uint64_t addr, uint64_t size,
+ uint32_t op,
+ uint32_t flags,
+ struct drm_xe_sync *sync,
+ uint32_t num_syncs,
+ uint64_t op_ext)
+{
+ const uint32_t exec_queue_id = 0;
+ const uint32_t prefetch_region = 0;
+
+ igt_assert_eq(__xe_eudebug_client_vm_bind(c, fd, vm, exec_queue_id, bo, offset,
+ addr, size, op, flags,
+ sync, num_syncs, prefetch_region,
+ DEFAULT_PAT_INDEX, op_ext),
+ 0);
+}
+
+/**
+ * xe_eudebug_client_vm_bind_flags
+ * @c: pointer to xe_eudebug_client structure
+ * @fd: xe client
+ * @vm: vm handle
+ * @bo: buffer object handle
+ * @offset: offset within buffer object
+ * @addr: ppgtt address
+ * @size: size of the binding
+ * @flags: vm_bind flags
+ * @sync: sync objects
+ * @num_syncs: number of sync objects
+ * @op_ext: BIND_OP extensions
+ *
+ * Calls xe vm_bind ioctl and logs the corresponding event in client's event log.
+ */
+void xe_eudebug_client_vm_bind_flags(struct xe_eudebug_client *c, int fd, uint32_t vm,
+ uint32_t bo, uint64_t offset,
+ uint64_t addr, uint64_t size, uint32_t flags,
+ struct drm_xe_sync *sync, uint32_t num_syncs,
+ uint64_t op_ext)
+{
+ _xe_eudebug_client_vm_bind(c, fd, vm, bo, offset, addr, size,
+ DRM_XE_VM_BIND_OP_MAP, flags,
+ sync, num_syncs, op_ext);
+}
+
+/**
+ * xe_eudebug_client_vm_bind
+ * @c: pointer to xe_eudebug_client structure
+ * @fd: xe client
+ * @vm: vm handle
+ * @bo: buffer object handle
+ * @offset: offset within buffer object
+ * @addr: ppgtt address
+ * @size: size of the binding
+ *
+ * Calls xe vm_bind ioctl and logs the corresponding event in client's event log.
+ */
+void xe_eudebug_client_vm_bind(struct xe_eudebug_client *c, int fd, uint32_t vm,
+ uint32_t bo, uint64_t offset,
+ uint64_t addr, uint64_t size)
+{
+ const uint32_t flags = 0;
+ struct drm_xe_sync *sync = NULL;
+ const uint32_t num_syncs = 0;
+ const uint64_t op_ext = 0;
+
+ xe_eudebug_client_vm_bind_flags(c, fd, vm, bo, offset, addr, size,
+ flags,
+ sync, num_syncs, op_ext);
+}
+
+/**
+ * xe_eudebug_client_vm_unbind_flags
+ * @c: pointer to xe_eudebug_client structure
+ * @fd: xe client
+ * @vm: vm handle
+ * @offset: offset
+ * @addr: ppgtt address
+ * @size: size of the binding
+ * @flags: vm_bind flags
+ * @sync: sync objects
+ * @num_syncs: number of sync objects
+ *
+ * Calls xe vm_unbind ioctl and logs the corresponding event in client's event log.
+ */
+void xe_eudebug_client_vm_unbind_flags(struct xe_eudebug_client *c, int fd,
+ uint32_t vm, uint64_t offset,
+ uint64_t addr, uint64_t size, uint32_t flags,
+ struct drm_xe_sync *sync, uint32_t num_syncs)
+{
+ _xe_eudebug_client_vm_bind(c, fd, vm, 0, offset, addr, size,
+ DRM_XE_VM_BIND_OP_UNMAP, flags,
+ sync, num_syncs, 0);
+}
+
+/**
+ * xe_eudebug_client_vm_unbind
+ * @c: pointer to xe_eudebug_client structure
+ * @fd: xe client
+ * @vm: vm handle
+ * @offset: offset
+ * @addr: ppgtt address
+ * @size: size of the binding
+ *
+ * Calls xe vm_unbind ioctl and logs the corresponding event in client's event log.
+ */
+void xe_eudebug_client_vm_unbind(struct xe_eudebug_client *c, int fd, uint32_t vm,
+ uint64_t offset, uint64_t addr, uint64_t size)
+{
+ const uint32_t flags = 0;
+ struct drm_xe_sync *sync = NULL;
+ const uint32_t num_syncs = 0;
+
+ xe_eudebug_client_vm_unbind_flags(c, fd, vm, offset, addr, size,
+ flags, sync, num_syncs);
+}
diff --git a/lib/xe/xe_eudebug.h b/lib/xe/xe_eudebug.h
index 8dc153d27..1592704ab 100644
--- a/lib/xe/xe_eudebug.h
+++ b/lib/xe/xe_eudebug.h
@@ -99,6 +99,18 @@ typedef void (*xe_eudebug_trigger_fn)(struct xe_eudebug_debugger *,
*/
#define XE_EUDEBUG_DEFAULT_TIMEOUT_MS 25000ULL
+#define XE_EUDEBUG_FILTER_EVENT_NONE BIT(DRM_XE_EUDEBUG_EVENT_NONE)
+#define XE_EUDEBUG_FILTER_EVENT_READ BIT(DRM_XE_EUDEBUG_EVENT_READ)
+#define XE_EUDEBUG_FILTER_EVENT_OPEN BIT(DRM_XE_EUDEBUG_EVENT_OPEN)
+#define XE_EUDEBUG_FILTER_EVENT_VM BIT(DRM_XE_EUDEBUG_EVENT_VM)
+#define XE_EUDEBUG_FILTER_EVENT_EXEC_QUEUE BIT(DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE)
+#define XE_EUDEBUG_FILTER_EVENT_EU_ATTENTION BIT(DRM_XE_EUDEBUG_EVENT_EU_ATTENTION)
+#define XE_EUDEBUG_FILTER_EVENT_VM_BIND BIT(DRM_XE_EUDEBUG_EVENT_VM_BIND)
+#define XE_EUDEBUG_FILTER_EVENT_VM_BIND_OP BIT(DRM_XE_EUDEBUG_EVENT_VM_BIND_OP)
+#define XE_EUDEBUG_FILTER_EVENT_VM_BIND_UFENCE BIT(DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE)
+#define XE_EUDEUBG_FILTER_ALL GENMASK(DRM_XE_EUDEBUG_EVENT_MAX_EVENT, 0)
+#define XE_EUDEBUG_EVENT_IS_FILTERED(_e, _f) ((1UL << _e) & _f)
+
const char *xe_eudebug_event_to_str(struct drm_xe_eudebug_event *e, char *buf, size_t len);
struct drm_xe_eudebug_event *
xe_eudebug_event_log_find_seqno(struct xe_eudebug_event_log *l, uint64_t seqno);
@@ -106,9 +118,10 @@ struct xe_eudebug_event_log *
xe_eudebug_event_log_create(const char *name, unsigned int max_size);
void xe_eudebug_event_log_destroy(struct xe_eudebug_event_log *l);
void xe_eudebug_event_log_print(struct xe_eudebug_event_log *l, bool debug);
-void xe_eudebug_event_log_compare(struct xe_eudebug_event_log *c, struct xe_eudebug_event_log *d);
+void xe_eudebug_event_log_compare(struct xe_eudebug_event_log *c, struct xe_eudebug_event_log *d,
+ uint32_t filter);
void xe_eudebug_event_log_write(struct xe_eudebug_event_log *l, struct drm_xe_eudebug_event *e);
-void xe_eudebug_event_log_match_opposite(struct xe_eudebug_event_log *l);
+void xe_eudebug_event_log_match_opposite(struct xe_eudebug_event_log *l, uint32_t filter);
struct xe_eudebug_debugger *
xe_eudebug_debugger_create(int xe, uint64_t flags, void *data);
@@ -142,6 +155,32 @@ uint32_t xe_eudebug_client_exec_queue_create(struct xe_eudebug_client *c, int fd
struct drm_xe_exec_queue_create *create);
void xe_eudebug_client_exec_queue_destroy(struct xe_eudebug_client *c, int fd,
struct drm_xe_exec_queue_create *create);
+void xe_eudebug_client_vm_bind_event(struct xe_eudebug_client *c, uint32_t event_flags, int fd,
+ uint32_t vm, uint32_t bind_flags,
+ uint32_t num_ops, uint64_t *ref_seqno);
+void xe_eudebug_client_vm_bind_op_event(struct xe_eudebug_client *c, uint32_t event_flags,
+ uint64_t ref_seqno, uint64_t *op_ref_seqno,
+ uint64_t addr, uint64_t range,
+ uint64_t num_extensions);
+void xe_eudebug_client_vm_bind_op_metadata_event(struct xe_eudebug_client *c,
+ uint32_t event_flags, uint64_t op_ref_seqno,
+ uint64_t metadata_handle, uint64_t metadata_cookie);
+void xe_eudebug_client_vm_bind_ufence_event(struct xe_eudebug_client *c, uint32_t event_flags,
+ uint64_t ref_seqno);
+void xe_eudebug_client_vm_bind_flags(struct xe_eudebug_client *c, int fd, uint32_t vm,
+ uint32_t bo, uint64_t offset,
+ uint64_t addr, uint64_t size, uint32_t flags,
+ struct drm_xe_sync *sync, uint32_t num_syncs,
+ uint64_t op_ext);
+void xe_eudebug_client_vm_bind(struct xe_eudebug_client *c, int fd, uint32_t vm,
+ uint32_t bo, uint64_t offset,
+ uint64_t addr, uint64_t size);
+void xe_eudebug_client_vm_unbind_flags(struct xe_eudebug_client *c, int fd,
+ uint32_t vm, uint64_t offset,
+ uint64_t addr, uint64_t size, uint32_t flags,
+ struct drm_xe_sync *sync, uint32_t num_syncs);
+void xe_eudebug_client_vm_unbind(struct xe_eudebug_client *c, int fd, uint32_t vm,
+ uint64_t offset, uint64_t addr, uint64_t size);
struct xe_eudebug_session *xe_eudebug_session_create(int fd,
xe_eudebug_client_work_fn work,
@@ -149,4 +188,4 @@ struct xe_eudebug_session *xe_eudebug_session_create(int fd,
void *test_private);
void xe_eudebug_session_destroy(struct xe_eudebug_session *s);
void xe_eudebug_session_run(struct xe_eudebug_session *s);
-void xe_eudebug_session_check(struct xe_eudebug_session *s, bool match_opposite);
+void xe_eudebug_session_check(struct xe_eudebug_session *s, bool match_opposite, uint32_t filter);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 08/66] lib/xe_eudebug: Add metadata support
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (6 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 07/66] lib/xe_eudebug: Add support for vm_bind events Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 09/66] lib/xe_eudebug: Add support for user fence acking Christoph Manszewski
` (59 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Support metadata events in debugger library by:
- Adding metadata events to log checking functions.
- Introducing eudebug vm_bind wrapper which allows to attach debug
metadata and cookie
- Implementing xe_eudebug_client_metadata_create|destroy wrappers.
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
Cc: Christoph Manszewski <christoph.manszewski@intel.com>
---
lib/xe/xe_eudebug.c | 136 ++++++++++++++++++++++++++++++++++++++++++--
lib/xe/xe_eudebug.h | 6 ++
2 files changed, 138 insertions(+), 4 deletions(-)
diff --git a/lib/xe/xe_eudebug.c b/lib/xe/xe_eudebug.c
index 97f847409..1cea77420 100644
--- a/lib/xe/xe_eudebug.c
+++ b/lib/xe/xe_eudebug.c
@@ -69,6 +69,10 @@ static const char *type_to_str(unsigned int type)
return "vm_bind_op";
case DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE:
return "vm_bind_ufence";
+ case DRM_XE_EUDEBUG_EVENT_METADATA:
+ return "metadata";
+ case DRM_XE_EUDEBUG_EVENT_VM_BIND_OP_METADATA:
+ return "vm_bind_op_metadata";
}
return "UNKNOWN";
@@ -154,6 +158,20 @@ static const char *event_members_to_str(struct drm_xe_eudebug_event *e, char *b)
sprintf(b, "vm_bind_ref_seqno=%lld", f->vm_bind_ref_seqno);
break;
}
+ case DRM_XE_EUDEBUG_EVENT_METADATA: {
+ struct drm_xe_eudebug_event_metadata *em = (void *)e;
+
+ sprintf(b, "client_handle=%llu, metadata_handle=%llu, type=%llu, len=%llu",
+ em->client_handle, em->metadata_handle, em->type, em->len);
+ break;
+ }
+ case DRM_XE_EUDEBUG_EVENT_VM_BIND_OP_METADATA: {
+ struct drm_xe_eudebug_event_vm_bind_op_metadata *op = (void *)e;
+
+ sprintf(b, "vm_bind_op_ref_seqno=%lld, metadata_handle=%llu, metadata_cookie=%llu",
+ op->vm_bind_op_ref_seqno, op->metadata_handle, op->metadata_cookie);
+ break;
+ }
default:
strcpy(b, "<...>");
}
@@ -417,6 +435,16 @@ static int match_fields(struct drm_xe_eudebug_event *a, void *data)
ret = 1;
break;
}
+ case DRM_XE_EUDEBUG_EVENT_VM_BIND_OP_METADATA: {
+ struct drm_xe_eudebug_event_vm_bind_op_metadata *ea = (void *)a;
+ struct drm_xe_eudebug_event_vm_bind_op_metadata *eb = (void *)b;
+
+ if (ea->metadata_handle == eb->metadata_handle &&
+ ea->metadata_cookie == eb->metadata_cookie)
+ ret = 1;
+ break;
+ }
+
default:
ret = 1;
break;
@@ -483,6 +511,20 @@ static int match_client_handle(struct drm_xe_eudebug_event *e, void *data)
break;
}
+ case DRM_XE_EUDEBUG_EVENT_METADATA: {
+ struct drm_xe_eudebug_event_metadata *em = (struct drm_xe_eudebug_event_metadata *)e;
+
+ if (em->client_handle == h)
+ return 1;
+ break;
+ }
+ case DRM_XE_EUDEBUG_EVENT_VM_BIND_OP_METADATA: {
+ struct drm_xe_eudebug_event_vm_bind_op_metadata *eo = (struct drm_xe_eudebug_event_vm_bind_op_metadata *)e;
+
+ if (eo->vm_bind_op_ref_seqno == *bind_op_seqno)
+ return 1;
+ break;
+ }
default:
break;
}
@@ -547,6 +589,24 @@ static int match_opposite_resource(struct drm_xe_eudebug_event *e, void *data)
return 1;
break;
}
+ case DRM_XE_EUDEBUG_EVENT_METADATA: {
+ struct drm_xe_eudebug_event_metadata *em = (void *)e;
+ struct drm_xe_eudebug_event_metadata *filter = (struct drm_xe_eudebug_event_metadata *)data;
+
+ if (em->metadata_handle == filter->metadata_handle)
+ return 1;
+ break;
+ }
+ case DRM_XE_EUDEBUG_EVENT_VM_BIND_OP_METADATA: {
+ struct drm_xe_eudebug_event_vm_bind_op_metadata *avmb = (void *)e;
+ struct drm_xe_eudebug_event_vm_bind_op_metadata *filter = (struct drm_xe_eudebug_event_vm_bind_op_metadata *)data;
+
+ if (avmb->metadata_handle == filter->metadata_handle &&
+ avmb->metadata_cookie == filter->metadata_cookie)
+ return 1;
+ break;
+ }
+
default:
break;
}
@@ -883,8 +943,9 @@ xe_eudebug_event_log_match_opposite(struct xe_eudebug_event_log *l, uint32_t fil
continue;
/* No opposite matching for binds */
- if (ce->type >= DRM_XE_EUDEBUG_EVENT_VM_BIND &&
- ce->type <= DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE)
+ if ((ce->type >= DRM_XE_EUDEBUG_EVENT_VM_BIND &&
+ ce->type <= DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE) ||
+ ce->type == DRM_XE_EUDEBUG_EVENT_VM_BIND_OP_METADATA)
continue;
de = opposite_event_match(l, ce, ce);
@@ -1480,6 +1541,22 @@ static void exec_queue_event(struct xe_eudebug_client *c, uint32_t flags,
xe_eudebug_event_log_write(c->log, (void *)&ee);
}
+static void metadata_event(struct xe_eudebug_client *c, uint32_t flags,
+ int client_fd, uint32_t id, uint64_t type, uint64_t len)
+{
+ struct drm_xe_eudebug_event_metadata em;
+
+ base_event(c, to_base(em), DRM_XE_EUDEBUG_EVENT_METADATA,
+ flags, sizeof(em));
+
+ em.client_handle = client_fd;
+ em.metadata_handle = id;
+ em.type = type;
+ em.len = len;
+
+ xe_eudebug_event_log_write(c->log, (void *)&em);
+}
+
/* Eu debugger wrappers around resource creating xe ioctls. */
/**
@@ -1522,8 +1599,8 @@ void xe_eudebug_client_close_driver(struct xe_eudebug_client *c, int fd)
* @flags: vm bind flags
* @ext: pointer to the first user extension
*
- * Calls xe_vm_create() and logs the corresponding event in
- * client's event log.
+ * Calls xe_vm_create() and logs corresponding events
+ * (including vm set metadata events) in client's event log.
*
* Returns: valid vm handle
*/
@@ -1903,3 +1980,54 @@ void xe_eudebug_client_vm_unbind(struct xe_eudebug_client *c, int fd, uint32_t v
xe_eudebug_client_vm_unbind_flags(c, fd, vm, offset, addr, size,
flags, sync, num_syncs);
}
+
+/**
+ * xe_eudebug_client_metadata_create:
+ * @c: pointer to xe_eudebug_client structure
+ * @fd: xe client
+ * @type: debug metadata type
+ * @len: size of @data
+ * @data: debug metadata paylad
+ *
+ * Calls xe metadata create ioctl and logs the corresponding event in
+ * client's event log.
+ *
+ * Return: valid debug metadata id.
+ */
+uint32_t xe_eudebug_client_metadata_create(struct xe_eudebug_client *c, int fd,
+ int type, size_t len, void *data)
+{
+ struct drm_xe_debug_metadata_create create = {
+ .type = type,
+ .user_addr = to_user_pointer(data),
+ .len = len
+ };
+
+ igt_assert_eq(igt_ioctl(fd, DRM_IOCTL_XE_DEBUG_METADATA_CREATE, &create), 0);
+
+ metadata_event(c, DRM_XE_EUDEBUG_EVENT_CREATE, fd, create.metadata_id, type, len);
+
+ return create.metadata_id;
+}
+
+/**
+ * xe_eudebug_client_metadata_destroy:
+ * @c: pointer to xe_eudebug_client structure
+ * @fd: xe client
+ * @id: xe debug metadata handle
+ * @type: debug metadata type
+ * @len: size of debug metadata payload
+ *
+ * Calls xe metadata destroy ioctl and logs the corresponding event in
+ * client's event log.
+ */
+void xe_eudebug_client_metadata_destroy(struct xe_eudebug_client *c, int fd,
+ uint32_t id, int type, size_t len)
+{
+ struct drm_xe_debug_metadata_destroy destroy = { .metadata_id = id };
+
+
+ igt_assert_eq(igt_ioctl(fd, DRM_IOCTL_XE_DEBUG_METADATA_DESTROY, &destroy), 0);
+
+ metadata_event(c, DRM_XE_EUDEBUG_EVENT_DESTROY, fd, id, type, len);
+}
diff --git a/lib/xe/xe_eudebug.h b/lib/xe/xe_eudebug.h
index 1592704ab..24336981f 100644
--- a/lib/xe/xe_eudebug.h
+++ b/lib/xe/xe_eudebug.h
@@ -167,6 +167,7 @@ void xe_eudebug_client_vm_bind_op_metadata_event(struct xe_eudebug_client *c,
uint64_t metadata_handle, uint64_t metadata_cookie);
void xe_eudebug_client_vm_bind_ufence_event(struct xe_eudebug_client *c, uint32_t event_flags,
uint64_t ref_seqno);
+
void xe_eudebug_client_vm_bind_flags(struct xe_eudebug_client *c, int fd, uint32_t vm,
uint32_t bo, uint64_t offset,
uint64_t addr, uint64_t size, uint32_t flags,
@@ -182,6 +183,11 @@ void xe_eudebug_client_vm_unbind_flags(struct xe_eudebug_client *c, int fd,
void xe_eudebug_client_vm_unbind(struct xe_eudebug_client *c, int fd, uint32_t vm,
uint64_t offset, uint64_t addr, uint64_t size);
+uint32_t xe_eudebug_client_metadata_create(struct xe_eudebug_client *c, int fd,
+ int type, size_t len, void *data);
+void xe_eudebug_client_metadata_destroy(struct xe_eudebug_client *c, int fd,
+ uint32_t id, int type, size_t len);
+
struct xe_eudebug_session *xe_eudebug_session_create(int fd,
xe_eudebug_client_work_fn work,
unsigned int flags,
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 09/66] lib/xe_eudebug: Add support for user fence acking
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (7 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 08/66] lib/xe_eudebug: Add metadata support Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 10/66] lib/xe_eudebug: Add support for dynamic debugger sysfs toggle Christoph Manszewski
` (58 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
If the debugee uses user fences for synchronization, the debugger will
recieve a 'UFENCE_EVENT' and the fence won't be released untill the
debugger acks it. Note that for the fence to release, both the job
completion and debugger ack are required. Add a library function
to ack user fences.
Signed-off-by: Mika Kuoppala <mika.kuoppala@intel.com>
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
lib/xe/xe_eudebug.c | 14 ++++++++++++++
lib/xe/xe_eudebug.h | 2 ++
2 files changed, 16 insertions(+)
diff --git a/lib/xe/xe_eudebug.c b/lib/xe/xe_eudebug.c
index 1cea77420..7f99fabc5 100644
--- a/lib/xe/xe_eudebug.c
+++ b/lib/xe/xe_eudebug.c
@@ -2031,3 +2031,17 @@ void xe_eudebug_client_metadata_destroy(struct xe_eudebug_client *c, int fd,
metadata_event(c, DRM_XE_EUDEBUG_EVENT_DESTROY, fd, id, type, len);
}
+
+void xe_eudebug_ack_ufence(int debugfd,
+ const struct drm_xe_eudebug_event_vm_bind_ufence *f)
+{
+ struct drm_xe_eudebug_ack_event ack = { 0, };
+ char event_str[XE_EUDEBUG_EVENT_STRING_MAX_LEN];
+
+ ack.type = f->base.type;
+ ack.seqno = f->base.seqno;
+
+ xe_eudebug_event_to_str((void *)f, event_str, XE_EUDEBUG_EVENT_STRING_MAX_LEN);
+ igt_debug("delivering ack for event: %s\n", event_str);
+ igt_assert_eq(igt_ioctl(debugfd, DRM_XE_EUDEBUG_IOCTL_ACK_EVENT, &ack), 0);
+}
diff --git a/lib/xe/xe_eudebug.h b/lib/xe/xe_eudebug.h
index 24336981f..ec75634f5 100644
--- a/lib/xe/xe_eudebug.h
+++ b/lib/xe/xe_eudebug.h
@@ -167,6 +167,8 @@ void xe_eudebug_client_vm_bind_op_metadata_event(struct xe_eudebug_client *c,
uint64_t metadata_handle, uint64_t metadata_cookie);
void xe_eudebug_client_vm_bind_ufence_event(struct xe_eudebug_client *c, uint32_t event_flags,
uint64_t ref_seqno);
+void xe_eudebug_ack_ufence(int debugfd,
+ const struct drm_xe_eudebug_event_vm_bind_ufence *f);
void xe_eudebug_client_vm_bind_flags(struct xe_eudebug_client *c, int fd, uint32_t vm,
uint32_t bo, uint64_t offset,
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 10/66] lib/xe_eudebug: Add support for dynamic debugger sysfs toggle
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (8 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 09/66] lib/xe_eudebug: Add support for user fence acking Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 11/66] tests/xe_eudebug: Test open close events Christoph Manszewski
` (57 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
The debugger now uses a dedicated sysfs entry:
/sys/class/drm/card<N>/device/enable_eudebug
to toggle the debugger on/off. This change adds helper functons for
toggling the debugger.
Signed-off-by: Mika Kuoppala <mika.kuoppala@intel.com>
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
lib/xe/xe_eudebug.c | 88 +++++++++++++++++++++++++++++++++++++++++++++
lib/xe/xe_eudebug.h | 3 ++
2 files changed, 91 insertions(+)
diff --git a/lib/xe/xe_eudebug.c b/lib/xe/xe_eudebug.c
index 7f99fabc5..18e0ac422 100644
--- a/lib/xe/xe_eudebug.c
+++ b/lib/xe/xe_eudebug.c
@@ -7,10 +7,12 @@
#include <poll.h>
#include <signal.h>
#include <sys/select.h>
+#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "igt.h"
+#include "igt_sysfs.h"
#include "intel_pat.h"
#include "xe_eudebug.h"
#include "xe_ioctl.h"
@@ -1034,6 +1036,24 @@ static void *debugger_worker_loop(void *data)
return NULL;
}
+/**
+ * xe_eudebug_debugger_available:
+ * @fd: Xe file descriptor
+ *
+ * Returns: true it debugger connection is available, false otherwise.
+ */
+bool xe_eudebug_debugger_available(int fd)
+{
+ struct drm_xe_eudebug_connect param = { .pid = getpid() };
+ int debugfd;
+
+ debugfd = igt_ioctl(fd, DRM_IOCTL_XE_EUDEBUG_CONNECT, ¶m);
+ if (debugfd >= 0)
+ close(debugfd);
+
+ return debugfd >= 0;
+}
+
/**
* xe_eudebug_debugger_create:
* @master_fd: xe client used to open the debugger connection
@@ -1557,6 +1577,74 @@ static void metadata_event(struct xe_eudebug_client *c, uint32_t flags,
xe_eudebug_event_log_write(c->log, (void *)&em);
}
+static int enable_getset(int fd, bool *old, bool *new)
+{
+ static const char * const fname = "enable_eudebug";
+ int ret = 0;
+
+ int sysfs, device_fd;
+ bool val_before;
+ struct stat st;
+
+ igt_assert(new || old);
+
+ igt_assert_eq(fstat(fd, &st), 0);
+ sysfs = igt_sysfs_open(fd);
+ if (sysfs < 0)
+ return -1;
+
+ device_fd = openat(sysfs, "device", O_DIRECTORY | O_RDONLY);
+ close(sysfs);
+ if (device_fd < 0)
+ return -1;
+
+ if (!__igt_sysfs_get_boolean(device_fd, fname, &val_before)) {
+ ret = -1;
+ goto out;
+ }
+
+ igt_debug("enable_eudebug before: %d\n", val_before);
+
+ if (old)
+ *old = val_before;
+
+ ret = 0;
+ if (new) {
+ if (__igt_sysfs_set_boolean(device_fd, fname, *new))
+ igt_assert_eq(igt_sysfs_get_boolean(device_fd, fname), *new);
+ else
+ ret = -1;
+ }
+
+out:
+ close(device_fd);
+ return ret;
+}
+
+/**
+ * xe_eudebug_enable
+ * @fd: xe client
+ * @enable: state toggle - true to enable, false to disable
+ *
+ * Enables/disables eudebug capability by writing to
+ * '/sys/class/drm/card<N>/device/enable_eudebug' sysfs entry.
+ *
+ * Returns: previous toggle value, i.e. true when eudebugging was enabled,
+ * false when eudebugging was disabled.
+ */
+bool xe_eudebug_enable(int fd, bool enable)
+{
+ bool old = false;
+ int ret = enable_getset(fd, &old, &enable);
+
+ if (ret) {
+ igt_skip_on(enable);
+ old = false;
+ }
+
+ return old;
+}
+
/* Eu debugger wrappers around resource creating xe ioctls. */
/**
diff --git a/lib/xe/xe_eudebug.h b/lib/xe/xe_eudebug.h
index ec75634f5..1343cb25c 100644
--- a/lib/xe/xe_eudebug.h
+++ b/lib/xe/xe_eudebug.h
@@ -123,6 +123,7 @@ void xe_eudebug_event_log_compare(struct xe_eudebug_event_log *c, struct xe_eude
void xe_eudebug_event_log_write(struct xe_eudebug_event_log *l, struct drm_xe_eudebug_event *e);
void xe_eudebug_event_log_match_opposite(struct xe_eudebug_event_log *l, uint32_t filter);
+bool xe_eudebug_debugger_available(int fd);
struct xe_eudebug_debugger *
xe_eudebug_debugger_create(int xe, uint64_t flags, void *data);
void xe_eudebug_debugger_destroy(struct xe_eudebug_debugger *d);
@@ -146,6 +147,8 @@ void xe_eudebug_client_wait_stage(struct xe_eudebug_client *c, uint64_t stage);
uint64_t xe_eudebug_client_get_seqno(struct xe_eudebug_client *c);
void xe_eudebug_client_set_data(struct xe_eudebug_client *c, void *ptr);
+bool xe_eudebug_enable(int fd, bool enable);
+
int xe_eudebug_client_open_driver(struct xe_eudebug_client *c);
void xe_eudebug_client_close_driver(struct xe_eudebug_client *c, int fd);
uint32_t xe_eudebug_client_vm_create(struct xe_eudebug_client *c, int fd,
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 11/66] tests/xe_eudebug: Test open close events
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (9 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 10/66] lib/xe_eudebug: Add support for dynamic debugger sysfs toggle Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 12/66] tests/xe_eudebug: Exercise read_event ioctl Christoph Manszewski
` (56 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Mika Kuoppala, Christoph Manszewski
From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Introduce basic tests which validate client create/destroy events
sent on xe drm client open/close.
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Cc: Christoph Manszewski <christoph.manszewski@intel.com>
---
tests/intel/xe_eudebug.c | 38 +++++++++++++++++++++++++++++++++++++-
1 file changed, 37 insertions(+), 1 deletion(-)
diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
index 2bd5a44f9..d0dc38436 100644
--- a/tests/intel/xe_eudebug.c
+++ b/tests/intel/xe_eudebug.c
@@ -3,8 +3,16 @@
* Copyright © 2023 Intel Corporation
*/
-#include <xe_drm.h>
#include "igt.h"
+#include "xe/xe_eudebug.h"
+
+static void run_basic_client(struct xe_eudebug_client *c)
+{
+ int fd;
+
+ fd = xe_eudebug_client_open_driver(c);
+ xe_eudebug_client_close_driver(c, fd);
+}
static int __debug_connect(int fd, int *debugfd, struct drm_xe_eudebug_connect *param)
{
@@ -96,6 +104,28 @@ static void test_close(int fd)
close(debug_fd1);
}
+static void test_basic_sessions(int fd, unsigned int flags, int count)
+{
+ struct xe_eudebug_session **s;
+ int i;
+
+ s = calloc(count, sizeof(*s));
+
+ igt_assert(s);
+
+ for (i = 0; i < count; i++)
+ s[i] = xe_eudebug_session_create(fd, run_basic_client, flags, NULL);
+
+ for (i = 0; i < count; i++)
+ xe_eudebug_session_run(s[i]);
+
+ for (i = 0; i < count; i++)
+ xe_eudebug_session_check(s[i], true, 0);
+
+ for (i = 0; i < count; i++)
+ xe_eudebug_session_destroy(s[i]);
+}
+
igt_main
{
int fd;
@@ -110,6 +140,12 @@ igt_main
igt_subtest("basic-close")
test_close(fd);
+ igt_subtest("basic-client")
+ test_basic_sessions(fd, 0, 1);
+
+ igt_subtest("multiple-sessions")
+ test_basic_sessions(fd, 0, 4);
+
igt_fixture
drm_close_driver(fd);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 12/66] tests/xe_eudebug: Exercise read_event ioctl
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (10 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 11/66] tests/xe_eudebug: Test open close events Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 13/66] tests/xe_eudebug: Add vm events sanity check Christoph Manszewski
` (55 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Introduce synchronous test, which validates eu debugger read_event
ioctl.
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Cc: Christoph Manszewski <christoph.manszewski@intel.com>
---
tests/intel/xe_eudebug.c | 107 +++++++++++++++++++++++++++++++++++++++
1 file changed, 107 insertions(+)
diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
index d0dc38436..6bbad795c 100644
--- a/tests/intel/xe_eudebug.c
+++ b/tests/intel/xe_eudebug.c
@@ -2,6 +2,8 @@
/*
* Copyright © 2023 Intel Corporation
*/
+#include <poll.h>
+#include <sys/ioctl.h>
#include "igt.h"
#include "xe/xe_eudebug.h"
@@ -14,6 +16,45 @@ static void run_basic_client(struct xe_eudebug_client *c)
xe_eudebug_client_close_driver(c, fd);
}
+static int read_event(int debugfd, struct drm_xe_eudebug_event *event)
+{
+ int ret;
+
+ ret = igt_ioctl(debugfd, DRM_XE_EUDEBUG_IOCTL_READ_EVENT, event);
+ if (ret < 0)
+ return -errno;
+
+ return ret;
+}
+
+static int __read_event(int debugfd, struct drm_xe_eudebug_event *event)
+{
+ int ret;
+
+ ret = ioctl(debugfd, DRM_XE_EUDEBUG_IOCTL_READ_EVENT, event);
+ if (ret < 0)
+ return -errno;
+
+ return ret;
+}
+
+static int poll_event(int fd, int timeout_ms)
+{
+ int ret;
+
+ struct pollfd p = {
+ .fd = fd,
+ .events = POLLIN,
+ .revents = 0,
+ };
+
+ ret = poll(&p, 1, timeout_ms);
+ if (ret == -1)
+ return -errno;
+
+ return ret == 1 && (p.revents & POLLIN);
+}
+
static int __debug_connect(int fd, int *debugfd, struct drm_xe_eudebug_connect *param)
{
int ret = 0;
@@ -104,6 +145,69 @@ static void test_close(int fd)
close(debug_fd1);
}
+/**
+ * SUBTEST: basic-read-event
+ * Description:
+ * Synchronously exercise eu debugger event polling and reading.
+ */
+#define MAX_EVENT_SIZE (32 * 1024)
+static void test_read_event(int fd)
+{
+ struct drm_xe_eudebug_event *event;
+ struct xe_eudebug_debugger *d;
+ struct xe_eudebug_client *c;
+
+ event = malloc(MAX_EVENT_SIZE);
+ igt_assert(event);
+ memset(event, 0, sizeof(*event));
+
+ c = xe_eudebug_client_create(fd, run_basic_client, 0, NULL);
+ d = xe_eudebug_debugger_create(fd, 0, NULL);
+
+ igt_assert_eq(xe_eudebug_debugger_attach(d, c), 0);
+ igt_assert_eq(poll_event(d->fd, 500), 0);
+
+ event->len = 1;
+ event->type = DRM_XE_EUDEBUG_EVENT_NONE;
+ igt_assert_eq(read_event(d->fd, event), -EINVAL);
+
+ event->len = MAX_EVENT_SIZE;
+ event->type = DRM_XE_EUDEBUG_EVENT_NONE;
+ igt_assert_eq(read_event(d->fd, event), -EINVAL);
+
+ xe_eudebug_client_start(c);
+
+ igt_assert_eq(poll_event(d->fd, 500), 1);
+ event->type = DRM_XE_EUDEBUG_EVENT_READ;
+ igt_assert_eq(read_event(d->fd, event), 0);
+
+ igt_assert_eq(poll_event(d->fd, 500), 1);
+ event->len = MAX_EVENT_SIZE;
+ event->flags = 0;
+ event->type = DRM_XE_EUDEBUG_EVENT_READ;
+ igt_assert_eq(read_event(d->fd, event), 0);
+
+ fcntl(d->fd, F_SETFL, fcntl(d->fd, F_GETFL) | O_NONBLOCK);
+ igt_assert(fcntl(d->fd, F_GETFL) & O_NONBLOCK);
+
+ igt_assert_eq(poll_event(d->fd, 500), 0);
+ event->len = MAX_EVENT_SIZE;
+ event->flags = 0;
+ event->type = DRM_XE_EUDEBUG_EVENT_READ;
+ igt_assert_eq(__read_event(d->fd, event), -EAGAIN);
+
+ xe_eudebug_client_wait_done(c);
+ xe_eudebug_client_stop(c);
+
+ igt_assert_eq(poll_event(d->fd, 500), 0);
+ igt_assert_eq(__read_event(d->fd, event), -EAGAIN);
+
+ xe_eudebug_debugger_destroy(d);
+ xe_eudebug_client_destroy(c);
+
+ free(event);
+}
+
static void test_basic_sessions(int fd, unsigned int flags, int count)
{
struct xe_eudebug_session **s;
@@ -140,6 +244,9 @@ igt_main
igt_subtest("basic-close")
test_close(fd);
+ igt_subtest("basic-read-event")
+ test_read_event(fd);
+
igt_subtest("basic-client")
test_basic_sessions(fd, 0, 1);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 13/66] tests/xe_eudebug: Add vm events sanity check
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (11 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 12/66] tests/xe_eudebug: Exercise read_event ioctl Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 14/66] tests/xe_eudebug: Race discovery against eudebug attach Christoph Manszewski
` (54 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Add basic test validating eudebug vm events.
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Cc: Christoph Manszewski <christoph.manszewski@intel.com>
---
tests/intel/xe_eudebug.c | 23 +++++++++++++++++++++--
1 file changed, 21 insertions(+), 2 deletions(-)
diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
index 6bbad795c..5a11e7347 100644
--- a/tests/intel/xe_eudebug.c
+++ b/tests/intel/xe_eudebug.c
@@ -8,11 +8,27 @@
#include "igt.h"
#include "xe/xe_eudebug.h"
+#define CREATE_VMS (1 << 0)
static void run_basic_client(struct xe_eudebug_client *c)
{
- int fd;
+ int fd, i;
fd = xe_eudebug_client_open_driver(c);
+
+ if (c->flags & CREATE_VMS) {
+ const uint32_t flags[] = {
+ DRM_XE_VM_CREATE_FLAG_SCRATCH_PAGE,
+ DRM_XE_VM_CREATE_FLAG_LR_MODE,
+ };
+ uint32_t vms[ARRAY_SIZE(flags)];
+
+ for (i = 0; i < ARRAY_SIZE(flags); i++)
+ vms[i] = xe_eudebug_client_vm_create(c, fd, flags[i], 0);
+
+ for (i--; i >= 0; i--)
+ xe_eudebug_client_vm_destroy(c, fd, vms[i]);
+ }
+
xe_eudebug_client_close_driver(c, fd);
}
@@ -251,7 +267,10 @@ igt_main
test_basic_sessions(fd, 0, 1);
igt_subtest("multiple-sessions")
- test_basic_sessions(fd, 0, 4);
+ test_basic_sessions(fd, CREATE_VMS, 4);
+
+ igt_subtest("basic-vms")
+ test_basic_sessions(fd, CREATE_VMS, 1);
igt_fixture
drm_close_driver(fd);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 14/66] tests/xe_eudebug: Race discovery against eudebug attach.
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (12 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 13/66] tests/xe_eudebug: Add vm events sanity check Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 15/66] tests/xe_eudebug: Add TEST/SUBTEST documentation Christoph Manszewski
` (53 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Karolina Stolarek, Christoph Manszewski
From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Validate eu debug resource discovery in a pretty cruel way.
Add subtests:
1) discovery-race - spawns N client proccesses, which create
N+N*N resources each, then it creates M debugger
threads competing for an access to the client proccess. After
successful attach, with probability of 0.5 read and assert
discovered resources, immediately detach otherwise.
2) discovery-empty[|-clients] - same as 1#, but destroy
resources in flight (explicetly or by closing the client).
Expect the last discovery not sending any events.
Currently N = 4, M = 3.
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Signed-off-by: Karolina Stolarek <karolina.stolarek@intel.com>
Cc: Christoph Manszewski <christoph.manszewski@intel.com>
---
tests/intel/xe_eudebug.c | 244 +++++++++++++++++++++++++++++++++++++++
1 file changed, 244 insertions(+)
diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
index 5a11e7347..147836bd1 100644
--- a/tests/intel/xe_eudebug.c
+++ b/tests/intel/xe_eudebug.c
@@ -246,6 +246,241 @@ static void test_basic_sessions(int fd, unsigned int flags, int count)
xe_eudebug_session_destroy(s[i]);
}
+#define RESOURCE_COUNT 16
+#define PRIMARY_THREAD (1 << 0)
+#define DISCOVERY_CLOSE_CLIENT (1 << 1)
+#define DISCOVERY_DESTROY_RESOURCES (1 << 2)
+static void run_discovery_client(struct xe_eudebug_client *c)
+{
+ int fd[RESOURCE_COUNT], i;
+ bool skip_sleep = c->flags & (DISCOVERY_DESTROY_RESOURCES | DISCOVERY_CLOSE_CLIENT);
+
+ srand(getpid());
+
+ for (i = 0; i < RESOURCE_COUNT; i++) {
+ fd[i] = xe_eudebug_client_open_driver(c);
+
+ /*
+ * Give the debugger a break in event stream after every
+ * other client, that allows to read discovery and dettach in quiet.
+ */
+ if (random() % 2 == 0 && !skip_sleep)
+ sleep(1);
+
+ for (int j = 0; j < RESOURCE_COUNT; j++) {
+ uint32_t vm = xe_eudebug_client_vm_create(c, fd[i], 0, 0);
+
+ if (c->flags & DISCOVERY_DESTROY_RESOURCES)
+ xe_eudebug_client_vm_destroy(c, fd[i], vm);
+ }
+
+ if (c->flags & DISCOVERY_CLOSE_CLIENT)
+ xe_eudebug_client_close_driver(c, fd[i]);
+ }
+}
+
+static void *discovery_race_thread(void *data)
+{
+ struct {
+ uint64_t client_handle;
+ int vm_count;
+ } clients[RESOURCE_COUNT];
+ struct xe_eudebug_session *s = data;
+ int expected = RESOURCE_COUNT * (1 + RESOURCE_COUNT);
+ const int tries = 100;
+ bool done = false;
+ int ret = 0;
+
+ for (int try = 0; try < tries && !done; try++) {
+
+ ret = xe_eudebug_debugger_attach(s->d, s->c);
+
+ if (ret == -EBUSY) {
+ usleep(100000);
+ continue;
+ }
+
+ igt_assert_eq(ret, 0);
+
+ if (random() % 2) {
+ struct drm_xe_eudebug_event *e = NULL;
+ int i = -1;
+
+ xe_eudebug_debugger_start_worker(s->d);
+ sleep(1);
+ xe_eudebug_debugger_stop_worker(s->d, 1);
+ igt_debug("Resources discovered: %lu\n", s->d->event_count);
+
+ xe_eudebug_for_each_event(e, s->d->log) {
+ if (e->type == DRM_XE_EUDEBUG_EVENT_OPEN) {
+ struct drm_xe_eudebug_event_client *eo = (void *)e;
+
+ if (i >= 0) {
+ igt_assert_eq(clients[i].vm_count,
+ RESOURCE_COUNT);
+ }
+
+ igt_assert(++i < RESOURCE_COUNT);
+ clients[i].client_handle = eo->client_handle;
+ clients[i].vm_count = 0;
+ }
+
+ if (e->type == DRM_XE_EUDEBUG_EVENT_VM)
+ clients[i].vm_count++;
+ };
+
+ igt_assert_lte(0, i);
+
+ for (int j = 0; j < i; j++)
+ for (int k = 0; k < i; k++) {
+ if (k == j)
+ continue;
+
+ igt_assert_neq(clients[j].client_handle,
+ clients[k].client_handle);
+ }
+
+ if (s->d->event_count >= expected)
+ done = true;
+ }
+
+ xe_eudebug_debugger_dettach(s->d);
+ s->d->log->head = 0;
+ s->d->event_count = 0;
+ }
+
+ /* Primary thread must read everything */
+ if (s->flags & PRIMARY_THREAD) {
+ while ((ret = xe_eudebug_debugger_attach(s->d, s->c)) == -EBUSY)
+ usleep(100000);
+
+ igt_assert_eq(ret, 0);
+
+ xe_eudebug_debugger_start_worker(s->d);
+ xe_eudebug_client_wait_done(s->c);
+
+ if (READ_ONCE(s->d->event_count) != expected)
+ sleep(5);
+
+ xe_eudebug_debugger_stop_worker(s->d, 1);
+ xe_eudebug_debugger_dettach(s->d);
+ }
+
+ return NULL;
+}
+
+static void test_race_discovery(int fd, unsigned int flags, int clients)
+{
+ const int debuggers_per_client = 3;
+ int count = clients * debuggers_per_client;
+ struct xe_eudebug_session *sessions, *s;
+ struct xe_eudebug_client *c;
+ pthread_t *threads;
+ int i, j;
+
+ sessions = calloc(count, sizeof(*sessions));
+ threads = calloc(count, sizeof(*threads));
+
+ for (i = 0; i < clients; i++) {
+ c = xe_eudebug_client_create(fd, run_discovery_client, flags, NULL);
+ for (j = 0; j < debuggers_per_client; j++) {
+ s = &sessions[i * debuggers_per_client + j];
+ s->c = c;
+ s->d = xe_eudebug_debugger_create(fd, flags, NULL);
+ s->flags = flags | (!j ? PRIMARY_THREAD : 0);
+ }
+ }
+
+ for (i = 0; i < count; i++) {
+ if (sessions[i].flags & PRIMARY_THREAD)
+ xe_eudebug_client_start(sessions[i].c);
+
+ pthread_create(&threads[i], NULL, discovery_race_thread, &sessions[i]);
+ }
+
+ for (i = 0; i < count; i++)
+ pthread_join(threads[i], NULL);
+
+ for (i = count - 1; i > 0; i--) {
+ if (sessions[i].flags & PRIMARY_THREAD) {
+ igt_assert_eq(sessions[i].c->seqno-1, sessions[i].d->event_count);
+
+ xe_eudebug_event_log_compare(sessions[0].d->log,
+ sessions[i].d->log, 0);
+
+ xe_eudebug_client_destroy(sessions[i].c);
+ }
+ xe_eudebug_debugger_destroy(sessions[i].d);
+ }
+}
+
+static void *attach_dettach_thread(void *data)
+{
+ struct xe_eudebug_session *s = data;
+ const int tries = 100;
+ int ret = 0;
+
+ for (int try = 0; try < tries; try++) {
+
+ ret = xe_eudebug_debugger_attach(s->d, s->c);
+
+ if (ret == -EBUSY) {
+ usleep(100000);
+ continue;
+ }
+
+ igt_assert_eq(ret, 0);
+
+ if (random() % 2 == 0) {
+ xe_eudebug_debugger_start_worker(s->d);
+ xe_eudebug_debugger_stop_worker(s->d, 1);
+ }
+
+ xe_eudebug_debugger_dettach(s->d);
+ s->d->log->head = 0;
+ s->d->event_count = 0;
+ }
+
+ return NULL;
+}
+
+static void test_empty_discovery(int fd, unsigned int flags, int clients)
+{
+ struct xe_eudebug_session **s;
+ pthread_t *threads;
+ int i, expected = flags & DISCOVERY_CLOSE_CLIENT ? 0 : RESOURCE_COUNT;
+
+ igt_assert(flags & (DISCOVERY_DESTROY_RESOURCES | DISCOVERY_CLOSE_CLIENT));
+
+ s = calloc(clients, sizeof(struct xe_eudebug_session *));
+ threads = calloc(clients, sizeof(*threads));
+
+ for (i = 0; i < clients; i++)
+ s[i] = xe_eudebug_session_create(fd, run_discovery_client, flags, NULL);
+
+ for (i = 0; i < clients; i++) {
+ xe_eudebug_client_start(s[i]->c);
+
+ pthread_create(&threads[i], NULL, attach_dettach_thread, s[i]);
+ }
+
+ for (i = 0; i < clients; i++)
+ pthread_join(threads[i], NULL);
+
+ for (i = 0; i < clients; i++) {
+ xe_eudebug_client_wait_done(s[i]->c);
+ igt_assert_eq(xe_eudebug_debugger_attach(s[i]->d, s[i]->c), 0);
+
+ xe_eudebug_debugger_start_worker(s[i]->d);
+ xe_eudebug_debugger_stop_worker(s[i]->d, 5);
+ xe_eudebug_debugger_dettach(s[i]->d);
+
+ igt_assert_eq(s[i]->d->event_count, expected);
+
+ xe_eudebug_session_destroy(s[i]);
+ }
+}
+
igt_main
{
int fd;
@@ -272,6 +507,15 @@ igt_main
igt_subtest("basic-vms")
test_basic_sessions(fd, CREATE_VMS, 1);
+ igt_subtest("discovery-race")
+ test_race_discovery(fd, 0, 4);
+
+ igt_subtest("discovery-empty")
+ test_empty_discovery(fd, DISCOVERY_CLOSE_CLIENT, 16);
+
+ igt_subtest("discovery-empty-clients")
+ test_empty_discovery(fd, DISCOVERY_DESTROY_RESOURCES, 16);
+
igt_fixture
drm_close_driver(fd);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 15/66] tests/xe_eudebug: Add TEST/SUBTEST documentation
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (13 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 14/66] tests/xe_eudebug: Race discovery against eudebug attach Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 16/66] tests/xe_eudebug: Introduce basic exec_queue testing Christoph Manszewski
` (52 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun
From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Document xe_eudebug IGT test basing on its internal logic.
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
tests/intel/xe_eudebug.c | 45 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
index 147836bd1..cf8f01684 100644
--- a/tests/intel/xe_eudebug.c
+++ b/tests/intel/xe_eudebug.c
@@ -2,6 +2,16 @@
/*
* Copyright © 2023 Intel Corporation
*/
+
+/**
+ * TEST: Test EU Debugger functionality
+ * Category: Core
+ * Mega feature: EUdebug
+ * Sub-category: EUdebug tests
+ * Functionality: eu debugger framework
+ * Test category: functionality test
+ */
+
#include <poll.h>
#include <sys/ioctl.h>
@@ -86,6 +96,12 @@ static int __debug_connect(int fd, int *debugfd, struct drm_xe_eudebug_connect *
return ret;
}
+/**
+ * SUBTEST: basic-connect
+ * Description:
+ * Exercise XE_EUDEBG_CONNECT ioctl with passing
+ * valid and invalid params.
+ */
static void test_connect(int fd)
{
struct drm_xe_eudebug_connect param = {};
@@ -138,6 +154,11 @@ static void test_connect(int fd)
close(debugfd);
}
+/**
+ * SUBTEST: basic-close
+ * Description:
+ * Test whether eudebug can be reattached after closure.
+ */
static void test_close(int fd)
{
struct drm_xe_eudebug_connect param = { 0, };
@@ -224,6 +245,20 @@ static void test_read_event(int fd)
free(event);
}
+/**
+ * SUBTEST: basic-client
+ * Description:
+ * Attach the debugger to process which opens and closes xe drm client.
+ *
+ * SUBTEST: multiple-sessions
+ * Description:
+ * Simultaneously attach many debuggers to many processes.
+ * Each process opens and closes xe drm client.
+ *
+ * SUBTEST: basic-vms
+ * Description:
+ * Attach the debugger to process which creates and destroys a few vms.
+ */
static void test_basic_sessions(int fd, unsigned int flags, int count)
{
struct xe_eudebug_session **s;
@@ -279,6 +314,16 @@ static void run_discovery_client(struct xe_eudebug_client *c)
}
}
+/**
+ * SUBTEST: discovery-%s
+ * Description: Race discovery against %arg[1] and the debugger dettach.
+ *
+ * arg[1]:
+ *
+ * @race: resources creation
+ * @empty: resources destruction
+ * @empty-clients: client closure
+ */
static void *discovery_race_thread(void *data)
{
struct {
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 16/66] tests/xe_eudebug: Introduce basic exec_queue testing
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (14 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 15/66] tests/xe_eudebug: Add TEST/SUBTEST documentation Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 17/66] tests/xe_eudebug: Include exec queues in discovery testing Christoph Manszewski
` (51 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Exercise events send by the debugger on exec_queue create/destroy.
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Cc: Christoph Manszewski <christoph.manszewski@intel.com>
---
tests/intel/xe_eudebug.c | 64 +++++++++++++++++++++++++++++++++++++---
1 file changed, 60 insertions(+), 4 deletions(-)
diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
index cf8f01684..47523982d 100644
--- a/tests/intel/xe_eudebug.c
+++ b/tests/intel/xe_eudebug.c
@@ -17,13 +17,16 @@
#include "igt.h"
#include "xe/xe_eudebug.h"
+#include "xe/xe_query.h"
#define CREATE_VMS (1 << 0)
+#define CREATE_EXEC_QUEUES (1 << 1)
static void run_basic_client(struct xe_eudebug_client *c)
{
int fd, i;
fd = xe_eudebug_client_open_driver(c);
+ xe_device_get(fd);
if (c->flags & CREATE_VMS) {
const uint32_t flags[] = {
@@ -39,6 +42,51 @@ static void run_basic_client(struct xe_eudebug_client *c)
xe_eudebug_client_vm_destroy(c, fd, vms[i]);
}
+ if (c->flags & CREATE_EXEC_QUEUES) {
+ struct drm_xe_exec_queue_create *create;
+ struct drm_xe_engine_class_instance *hwe;
+ struct drm_xe_engine_class_instance bind_sync = {
+ .engine_class = DRM_XE_ENGINE_CLASS_VM_BIND,
+ .engine_instance = 0,
+ };
+ struct drm_xe_engine_class_instance bind_async = {
+ .engine_class = DRM_XE_ENGINE_CLASS_VM_BIND,
+ .engine_instance = 0,
+ };
+ uint32_t vm;
+
+ create = calloc((xe_number_engines(fd) + 2), sizeof(*create));
+
+ vm = xe_eudebug_client_vm_create(c, fd, 0, 0);
+
+ i = 0;
+ xe_for_each_engine(fd, hwe) {
+ create[i].instances = to_user_pointer(hwe);
+ create[i].vm_id = vm;
+ create[i].width = 1;
+ create[i].num_placements = 1;
+ xe_eudebug_client_exec_queue_create(c, fd, &create[i++]);
+ }
+
+ create[i].instances = to_user_pointer(&bind_sync),
+ create[i].vm_id = vm;
+ create[i].width = 1,
+ create[i].num_placements = 1,
+ xe_eudebug_client_exec_queue_create(c, fd, &create[i++]);
+
+ create[i].instances = to_user_pointer(&bind_async),
+ create[i].vm_id = vm;
+ create[i].width = 1,
+ create[i].num_placements = 1,
+ xe_eudebug_client_exec_queue_create(c, fd, &create[i]);
+
+ for (; i >= 0; i--)
+ xe_eudebug_client_exec_queue_destroy(c, fd, &create[i]);
+
+ xe_eudebug_client_vm_destroy(c, fd, vm);
+ }
+
+ xe_device_put(fd);
xe_eudebug_client_close_driver(c, fd);
}
@@ -253,11 +301,16 @@ static void test_read_event(int fd)
* SUBTEST: multiple-sessions
* Description:
* Simultaneously attach many debuggers to many processes.
- * Each process opens and closes xe drm client.
+ * Each process opens and closes xe drm client and creates few resources.
*
- * SUBTEST: basic-vms
+ * SUBTEST: basic-%s
* Description:
- * Attach the debugger to process which creates and destroys a few vms.
+ * Attach the debugger to process which creates and destroys a few %arg[1].
+ *
+ * arg[1]:
+ *
+ * @vms: vms
+ * @exec-queues: exec queues
*/
static void test_basic_sessions(int fd, unsigned int flags, int count)
{
@@ -547,11 +600,14 @@ igt_main
test_basic_sessions(fd, 0, 1);
igt_subtest("multiple-sessions")
- test_basic_sessions(fd, CREATE_VMS, 4);
+ test_basic_sessions(fd, CREATE_VMS | CREATE_EXEC_QUEUES, 4);
igt_subtest("basic-vms")
test_basic_sessions(fd, CREATE_VMS, 1);
+ igt_subtest("basic-exec-queues")
+ test_basic_sessions(fd, CREATE_EXEC_QUEUES, 1);
+
igt_subtest("discovery-race")
test_race_discovery(fd, 0, 4);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 17/66] tests/xe_eudebug: Include exec queues in discovery testing
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (15 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 16/66] tests/xe_eudebug: Introduce basic exec_queue testing Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 18/66] tests/xe_eudebug: Add vm open/pread/pwrite basic tests Christoph Manszewski
` (50 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Extend discovery-* subtests to create exec_queue resources.
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Cc: Christoph Manszewski <christoph.manszewski@intel.com>
---
tests/intel/xe_eudebug.c | 41 ++++++++++++++++++++++++++++++++++++----
1 file changed, 37 insertions(+), 4 deletions(-)
diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
index 47523982d..d16bc9c19 100644
--- a/tests/intel/xe_eudebug.c
+++ b/tests/intel/xe_eudebug.c
@@ -340,6 +340,7 @@ static void test_basic_sessions(int fd, unsigned int flags, int count)
#define DISCOVERY_DESTROY_RESOURCES (1 << 2)
static void run_discovery_client(struct xe_eudebug_client *c)
{
+ struct drm_xe_engine_class_instance *hwe = NULL;
int fd[RESOURCE_COUNT], i;
bool skip_sleep = c->flags & (DISCOVERY_DESTROY_RESOURCES | DISCOVERY_CLOSE_CLIENT);
@@ -348,6 +349,20 @@ static void run_discovery_client(struct xe_eudebug_client *c)
for (i = 0; i < RESOURCE_COUNT; i++) {
fd[i] = xe_eudebug_client_open_driver(c);
+ if (!i) {
+ bool found = false;
+
+ xe_device_get(fd[0]);
+ xe_for_each_engine(fd[0], hwe) {
+ if (hwe->engine_class == DRM_XE_ENGINE_CLASS_COMPUTE ||
+ hwe->engine_class == DRM_XE_ENGINE_CLASS_RENDER) {
+ found = true;
+ break;
+ }
+ }
+ igt_assert(found);
+ }
+
/*
* Give the debugger a break in event stream after every
* other client, that allows to read discovery and dettach in quiet.
@@ -356,15 +371,25 @@ static void run_discovery_client(struct xe_eudebug_client *c)
sleep(1);
for (int j = 0; j < RESOURCE_COUNT; j++) {
- uint32_t vm = xe_eudebug_client_vm_create(c, fd[i], 0, 0);
+ struct drm_xe_exec_queue_create create = {
+ .width = 1,
+ .num_placements = 1,
+ .vm_id = xe_eudebug_client_vm_create(c, fd[i], 0, 0),
+ .instances = to_user_pointer(hwe)
+ };
- if (c->flags & DISCOVERY_DESTROY_RESOURCES)
- xe_eudebug_client_vm_destroy(c, fd[i], vm);
+ xe_eudebug_client_exec_queue_create(c, fd[i], &create);
+
+ if (c->flags & DISCOVERY_DESTROY_RESOURCES) {
+ xe_eudebug_client_exec_queue_destroy(c, fd[i], &create);
+ xe_eudebug_client_vm_destroy(c, fd[i], create.vm_id);
+ }
}
if (c->flags & DISCOVERY_CLOSE_CLIENT)
xe_eudebug_client_close_driver(c, fd[i]);
}
+ xe_device_put(fd[0]);
}
/**
@@ -382,9 +407,10 @@ static void *discovery_race_thread(void *data)
struct {
uint64_t client_handle;
int vm_count;
+ int exec_queue_count;
} clients[RESOURCE_COUNT];
struct xe_eudebug_session *s = data;
- int expected = RESOURCE_COUNT * (1 + RESOURCE_COUNT);
+ int expected = RESOURCE_COUNT * (1 + 2 * RESOURCE_COUNT);
const int tries = 100;
bool done = false;
int ret = 0;
@@ -416,15 +442,22 @@ static void *discovery_race_thread(void *data)
if (i >= 0) {
igt_assert_eq(clients[i].vm_count,
RESOURCE_COUNT);
+
+ igt_assert_eq(clients[i].exec_queue_count,
+ RESOURCE_COUNT);
}
igt_assert(++i < RESOURCE_COUNT);
clients[i].client_handle = eo->client_handle;
clients[i].vm_count = 0;
+ clients[i].exec_queue_count = 0;
}
if (e->type == DRM_XE_EUDEBUG_EVENT_VM)
clients[i].vm_count++;
+
+ if (e->type == DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE)
+ clients[i].exec_queue_count++;
};
igt_assert_lte(0, i);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 18/66] tests/xe_eudebug: Add vm open/pread/pwrite basic tests
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (16 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 17/66] tests/xe_eudebug: Include exec queues in discovery testing Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 19/66] tests/xe_eudebug: Add basic vm-bind coverage Christoph Manszewski
` (49 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Mika Kuoppala
From: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Add basic tests for opening, writing and reading into
client's vm.
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
tests/intel/xe_eudebug.c | 276 +++++++++++++++++++++++++++++++++++++++
1 file changed, 276 insertions(+)
diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
index d16bc9c19..0951129da 100644
--- a/tests/intel/xe_eudebug.c
+++ b/tests/intel/xe_eudebug.c
@@ -16,9 +16,139 @@
#include <sys/ioctl.h>
#include "igt.h"
+#include "intel_pat.h"
+#include "lib/igt_syncobj.h"
#include "xe/xe_eudebug.h"
+#include "xe/xe_ioctl.h"
#include "xe/xe_query.h"
+#define BO_ADDR 0x1a0000
+#define BO_ITEMS 4096
+#define MIN_BO_SIZE (BO_ITEMS * sizeof(uint64_t))
+
+struct bind_list {
+ int fd;
+ uint32_t vm;
+ uint32_t *bo;
+ struct drm_xe_vm_bind_op *bind_ops;
+ unsigned int n;
+};
+
+static void bo_prime(int fd, uint32_t bo, const uint64_t addr, const uint64_t size)
+{
+ uint64_t *d;
+ uint64_t i;
+
+ d = xe_bo_map(fd, bo, size);
+ igt_assert(d);
+
+ for (i = 0; i < size/sizeof(*d); i++)
+ d[i] = addr + i;
+
+ munmap(d, size);
+}
+
+static void bo_check(int fd, uint32_t bo, const uint64_t addr, const uint64_t size)
+{
+ uint64_t *d;
+ uint64_t i;
+
+ d = xe_bo_map(fd, bo, size);
+ igt_assert(d);
+
+ for (i = 0; i < size/sizeof(*d); i++)
+ igt_assert_eq(d[i], addr + i + 1);
+
+ munmap(d, size);
+}
+
+static uint32_t *vm_create_objects(int fd, uint32_t bo_placement, uint32_t vm, unsigned int size,
+ unsigned int n)
+{
+ uint32_t *bo;
+ unsigned int i;
+
+ bo = calloc(n, sizeof(*bo));
+ igt_assert(bo);
+
+ for (i = 0; i < n; i++) {
+ bo[i] = xe_bo_create(fd, vm, size, bo_placement, 0);
+ igt_assert(bo[i]);
+ }
+
+ return bo;
+}
+
+static struct bind_list *create_bind_list(int fd, uint32_t bo_placement,
+ uint32_t vm, unsigned int n)
+{
+ const unsigned int bo_size = max_t(bo_size, xe_get_default_alignment(fd), MIN_BO_SIZE);
+ struct bind_list *bl;
+ unsigned int i;
+
+ bl = malloc(sizeof(*bl));
+ bl->fd = fd;
+ bl->vm = vm;
+ bl->bo = vm_create_objects(fd, bo_placement, vm, bo_size, n);
+ bl->n = n;
+ bl->bind_ops = calloc(n, sizeof(*bl->bind_ops));
+ igt_assert(bl->bind_ops);
+
+ for (i = 0; i < n; i++) {
+ struct drm_xe_vm_bind_op *o = &bl->bind_ops[i];
+
+ o->range = bo_size;
+ o->addr = BO_ADDR + 2 * i * bo_size;
+ o->flags = 0;
+ o->pat_index = intel_get_pat_idx_wb(fd);
+ o->prefetch_mem_region_instance = 0;
+ o->reserved[0] = 0;
+ o->reserved[1] = 0;
+ }
+
+ for (i = 0; i < bl->n; i++) {
+ struct drm_xe_vm_bind_op *o = &bl->bind_ops[i];
+
+ igt_debug("bo %d: addr 0x%llx, range 0x%llx\n", i, o->addr, o->range);
+ bo_prime(fd, bl->bo[i], o->addr, o->range);
+ }
+
+ return bl;
+}
+
+static void do_bind_list(struct xe_eudebug_client *c,
+ struct bind_list *bl, struct drm_xe_sync *sync)
+{
+ int i;
+ uint64_t ref_seqno = 0, op_ref_seqno = 0;
+
+ xe_vm_bind_array(bl->fd, bl->vm, 0, bl->bind_ops, bl->n, sync, sync ? 1 : 0);
+ xe_eudebug_client_vm_bind_event(c, DRM_XE_EUDEBUG_EVENT_STATE_CHANGE,
+ bl->fd, bl->vm, 0, bl->n, &ref_seqno);
+ for (i = 0; i < bl->n; i++)
+ xe_eudebug_client_vm_bind_op_event(c, DRM_XE_EUDEBUG_EVENT_CREATE,
+ ref_seqno,
+ &op_ref_seqno,
+ bl->bind_ops[i].addr,
+ bl->bind_ops[i].range,
+ 0);
+
+ if (sync)
+ igt_assert(syncobj_wait(bl->fd, &sync->handle, 1, INT64_MAX, 0, NULL));
+}
+
+static void check_bind_list(struct bind_list *bl)
+{
+ unsigned int i;
+
+ for (i = 0; i < bl->n; i++) {
+ igt_debug("%d: checking 0x%llx (%lld)\n",
+ i, bl->bind_ops[i].addr, bl->bind_ops[i].addr);
+ bo_check(bl->fd, bl->bo[i], bl->bind_ops[i].addr,
+ bl->bind_ops[i].range);
+ }
+}
+
#define CREATE_VMS (1 << 0)
#define CREATE_EXEC_QUEUES (1 << 1)
static void run_basic_client(struct xe_eudebug_client *c)
@@ -612,6 +742,149 @@ static void test_empty_discovery(int fd, unsigned int flags, int clients)
}
}
+typedef void (*client_run_t)(struct xe_eudebug_client *);
+
+static void test_client_with_trigger(int fd, unsigned int flags, int count,
+ client_run_t client_fn, int type,
+ xe_eudebug_trigger_fn trigger_fn,
+ struct drm_xe_engine_class_instance *hwe,
+ bool match_opposite, uint32_t event_filter)
+{
+ struct xe_eudebug_session **s;
+ int i;
+
+ s = calloc(count, sizeof(*s));
+
+ igt_assert(s);
+
+ for (i = 0; i < count; i++)
+ s[i] = xe_eudebug_session_create(fd, client_fn, flags, hwe);
+
+ if (trigger_fn)
+ for (i = 0; i < count; i++)
+ xe_eudebug_debugger_add_trigger(s[i]->d, type, trigger_fn);
+
+ for (i = 0; i < count; i++)
+ xe_eudebug_session_run(s[i]);
+
+ for (i = 0; i < count; i++)
+ xe_eudebug_session_check(s[i], match_opposite, event_filter);
+
+ for (i = 0; i < count; i++)
+ xe_eudebug_session_destroy(s[i]);
+}
+
+static void vm_access_client(struct xe_eudebug_client *c)
+{
+ struct drm_xe_sync sync = {
+ .flags = DRM_XE_SYNC_TYPE_SYNCOBJ | DRM_XE_SYNC_FLAG_SIGNAL, };
+ struct drm_xe_engine_class_instance *hwe = c->ptr;
+ struct bind_list *bl;
+ uint32_t vm;
+ int fd, i;
+
+ igt_debug("Using %s\n", xe_engine_class_string(hwe->engine_class));
+
+ fd = xe_eudebug_client_open_driver(c);
+ xe_device_get(fd);
+
+ vm = xe_eudebug_client_vm_create(c, fd, 0, 0);
+
+ bl = create_bind_list(fd, vram_if_possible(fd, hwe->gt_id), vm, 4);
+ sync.handle = syncobj_create(bl->fd, 0);
+ do_bind_list(c, bl, &sync);
+ syncobj_destroy(bl->fd, sync.handle);
+
+ for (i = 0; i < bl->n; i++)
+ xe_eudebug_client_wait_stage(c, bl->bind_ops[i].addr);
+
+ check_bind_list(bl);
+
+ xe_eudebug_client_vm_destroy(c, fd, vm);
+
+ xe_device_put(fd);
+ xe_eudebug_client_close_driver(c, fd);
+}
+
+static void debugger_test_vma(struct xe_eudebug_debugger *d,
+ uint64_t client_handle,
+ uint64_t vm_handle,
+ uint64_t va_start,
+ uint64_t va_length)
+{
+ struct drm_xe_eudebug_vm_open vo = { 0, };
+ uint64_t *v;
+ uint64_t items = va_length / sizeof(uint64_t);
+ int fd;
+ int r, i;
+
+ v = malloc(va_length);
+ igt_assert(v);
+
+ vo.client_handle = client_handle;
+ vo.vm_handle = vm_handle;
+
+ fd = igt_ioctl(d->fd, DRM_XE_EUDEBUG_IOCTL_VM_OPEN, &vo);
+ igt_assert_lte(0, fd);
+
+ r = pread(fd, v, va_length, va_start);
+ igt_assert_eq(r, va_length);
+
+ for (i = 0; i < items; i++)
+ igt_assert_eq(v[i], va_start + i);
+
+ for (i = 0; i < items; i++)
+ v[i] = va_start + i + 1;
+
+ r = pwrite(fd, v, va_length, va_start);
+ igt_assert_eq(r, va_length);
+
+ fsync(fd);
+
+ close(fd);
+ free(v);
+}
+
+static void vm_trigger(struct xe_eudebug_debugger *d,
+ struct drm_xe_eudebug_event *e)
+{
+ struct drm_xe_eudebug_event_vm_bind_op *eo = (void *)e;
+
+ if (e->flags & DRM_XE_EUDEBUG_EVENT_CREATE) {
+ struct drm_xe_eudebug_event_vm_bind *eb;
+
+ igt_debug("vm bind op event received with ref %lld, addr 0x%llx, range 0x%llx\n",
+ eo->vm_bind_ref_seqno,
+ eo->addr,
+ eo->range);
+
+ eb = (struct drm_xe_eudebug_event_vm_bind *)
+ xe_eudebug_event_log_find_seqno(d->log, eo->vm_bind_ref_seqno);
+ igt_assert(eb);
+
+ debugger_test_vma(d, eb->client_handle, eb->vm_handle,
+ eo->addr, eo->range);
+ xe_eudebug_debugger_signal_stage(d, eo->addr);
+ }
+}
+
+/**
+ * SUBTEST: basic-vm-access
+ * Description:
+ * Exercise XE_EUDEBG_VM_OPEN with pread and pwrite into the vm fd
+ */
+static void test_vm_access(int fd, unsigned int flags, int num_clients)
+{
+ struct drm_xe_engine_class_instance *hwe;
+
+ xe_for_each_engine(fd, hwe)
+ test_client_with_trigger(fd, flags, num_clients,
+ vm_access_client,
+ DRM_XE_EUDEBUG_EVENT_VM_BIND_OP,
+ vm_trigger, hwe,
+ false, XE_EUDEBUG_FILTER_EVENT_VM_BIND_OP);
+}
+
igt_main
{
int fd;
@@ -632,6 +905,9 @@ igt_main
igt_subtest("basic-client")
test_basic_sessions(fd, 0, 1);
+ igt_subtest("basic-vm-access")
+ test_vm_access(fd, 0, 1);
+
igt_subtest("multiple-sessions")
test_basic_sessions(fd, CREATE_VMS | CREATE_EXEC_QUEUES, 4);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 19/66] tests/xe_eudebug: Add basic vm-bind coverage
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (17 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 18/66] tests/xe_eudebug: Add vm open/pread/pwrite basic tests Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 20/66] tests/xe_eudebug: Exercise debug metadata events sent to debugger Christoph Manszewski
` (48 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
Add basic coverage for vm-bind event delivery mechanism that enables the
user to track client vm-bind ioctl calls.
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
tests/intel/xe_eudebug.c | 117 ++++++++++++++++++++++++++++++++++++---
1 file changed, 109 insertions(+), 8 deletions(-)
diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
index 0951129da..35c2a0cc0 100644
--- a/tests/intel/xe_eudebug.c
+++ b/tests/intel/xe_eudebug.c
@@ -22,6 +22,41 @@
#include "xe/xe_ioctl.h"
#include "xe/xe_query.h"
+#define CREATE_VMS (1 << 0)
+#define CREATE_EXEC_QUEUES (1 << 1)
+#define VM_BIND (1 << 2)
+#define VM_BIND_VM_DESTROY (1 << 3)
+#define VM_BIND_EXTENDED (1 << 4)
+
+static void basic_vm_bind_client(int fd, struct xe_eudebug_client *c)
+{
+ uint32_t vm = xe_eudebug_client_vm_create(c, fd, 0, 0);
+ size_t bo_size = xe_get_default_alignment(fd);
+ uint32_t bo = xe_bo_create(fd, 0, bo_size,
+ system_memory(fd), 0);
+ uint64_t addr = 0x1a0000;
+
+ xe_eudebug_client_vm_bind(c, fd, vm, bo, 0, addr, bo_size);
+ xe_eudebug_client_vm_unbind(c, fd, vm, 0, addr, bo_size);
+
+ gem_close(fd, bo);
+ xe_eudebug_client_vm_destroy(c, fd, vm);
+}
+
+static void basic_vm_bind_vm_destroy_client(int fd, struct xe_eudebug_client *c)
+{
+ uint32_t vm = xe_eudebug_client_vm_create(c, fd, 0, 0);
+ size_t bo_size = xe_get_default_alignment(fd);
+ uint32_t bo = xe_bo_create(fd, 0, bo_size,
+ system_memory(fd), 0);
+ uint64_t addr = 0x1a0000;
+
+ xe_eudebug_client_vm_bind(c, fd, vm, bo, 0, addr, bo_size);
+ xe_eudebug_client_vm_destroy(c, fd, vm);
+
+ gem_close(fd, bo);
+}
+
#define BO_ADDR 0x1a0000
#define BO_ITEMS 4096
#define MIN_BO_SIZE (BO_ITEMS * sizeof(uint64_t))
@@ -149,8 +184,41 @@ static void check_bind_list(struct bind_list *bl)
}
}
-#define CREATE_VMS (1 << 0)
-#define CREATE_EXEC_QUEUES (1 << 1)
+static void vm_bind_client(int fd, struct xe_eudebug_client *c)
+{
+ uint64_t op_ref_seqno, ref_seqno;
+ struct bind_list *bl;
+ size_t bo_size = 3 * xe_get_default_alignment(fd);
+ uint32_t bo[2] = {
+ xe_bo_create(fd, 0, bo_size, system_memory(fd), 0),
+ xe_bo_create(fd, 0, bo_size, system_memory(fd), 0),
+ };
+ uint32_t vm = xe_eudebug_client_vm_create(c, fd, 0, 0);
+ uint64_t addr[] = {0x2a0000, 0x3a0000};
+ uint64_t rebind_bo_offset = 2 * bo_size / 3;
+ uint64_t size = bo_size / 3;
+
+ xe_eudebug_client_vm_bind(c, fd, vm, bo[0], 0, addr[0], bo_size);
+ xe_eudebug_client_vm_unbind(c, fd, vm, 0, addr[0] + size, size);
+
+ xe_eudebug_client_vm_bind(c, fd, vm, bo[1], 0, addr[1], bo_size);
+ xe_eudebug_client_vm_bind(c, fd, vm, bo[1], rebind_bo_offset, addr[1], size);
+
+ bl = create_bind_list(fd, system_memory(fd), vm, 4);
+ do_bind_list(c, bl, NULL);
+
+ xe_vm_unbind_all_async(fd, vm, 0, bo[1], NULL, 0);
+
+ xe_eudebug_client_vm_bind_event(c, DRM_XE_EUDEBUG_EVENT_STATE_CHANGE, fd, vm, 0,
+ 1, &ref_seqno);
+ xe_eudebug_client_vm_bind_op_event(c, DRM_XE_EUDEBUG_EVENT_DESTROY, ref_seqno,
+ &op_ref_seqno, 0, 0, 0);
+
+ gem_close(fd, bo[0]);
+ gem_close(fd, bo[1]);
+ xe_eudebug_client_vm_destroy(c, fd, vm);
+}
+
static void run_basic_client(struct xe_eudebug_client *c)
{
int fd, i;
@@ -216,6 +284,15 @@ static void run_basic_client(struct xe_eudebug_client *c)
xe_eudebug_client_vm_destroy(c, fd, vm);
}
+ if (c->flags & VM_BIND)
+ basic_vm_bind_client(fd, c);
+
+ if (c->flags & VM_BIND_EXTENDED)
+ vm_bind_client(fd, c);
+
+ if (c->flags & VM_BIND_VM_DESTROY)
+ basic_vm_bind_vm_destroy_client(fd, c);
+
xe_device_put(fd);
xe_eudebug_client_close_driver(c, fd);
}
@@ -437,12 +514,27 @@ static void test_read_event(int fd)
* Description:
* Attach the debugger to process which creates and destroys a few %arg[1].
*
+ * SUBTEST: basic-vm-bind
+ * Description:
+ * Attach the debugger to a process that performs synchronous vm bind
+ * and vm unbind.
+ *
+ * SUBTEST: basic-vm-bind-vm-destroy
+ * Description:
+ * Attach the debugger to a process that performs vm bind, and destroys
+ * the vm without unbinding. Make sure that we don't get unbind events.
+ *
+ * SUBTEST: basic-vm-bind-extended
+ * Description:
+ * Attach the debugger to a process that performs bind, bind array, rebind,
+ * partial unbind, unbind and unbind all operations.
+ *
* arg[1]:
*
* @vms: vms
* @exec-queues: exec queues
*/
-static void test_basic_sessions(int fd, unsigned int flags, int count)
+static void test_basic_sessions(int fd, unsigned int flags, int count, bool match_opposite)
{
struct xe_eudebug_session **s;
int i;
@@ -458,7 +550,7 @@ static void test_basic_sessions(int fd, unsigned int flags, int count)
xe_eudebug_session_run(s[i]);
for (i = 0; i < count; i++)
- xe_eudebug_session_check(s[i], true, 0);
+ xe_eudebug_session_check(s[i], match_opposite, 0);
for (i = 0; i < count; i++)
xe_eudebug_session_destroy(s[i]);
@@ -903,19 +995,28 @@ igt_main
test_read_event(fd);
igt_subtest("basic-client")
- test_basic_sessions(fd, 0, 1);
+ test_basic_sessions(fd, 0, 1, true);
igt_subtest("basic-vm-access")
test_vm_access(fd, 0, 1);
igt_subtest("multiple-sessions")
- test_basic_sessions(fd, CREATE_VMS | CREATE_EXEC_QUEUES, 4);
+ test_basic_sessions(fd, CREATE_VMS | CREATE_EXEC_QUEUES, 4, true);
igt_subtest("basic-vms")
- test_basic_sessions(fd, CREATE_VMS, 1);
+ test_basic_sessions(fd, CREATE_VMS, 1, true);
igt_subtest("basic-exec-queues")
- test_basic_sessions(fd, CREATE_EXEC_QUEUES, 1);
+ test_basic_sessions(fd, CREATE_EXEC_QUEUES, 1, true);
+
+ igt_subtest("basic-vm-bind")
+ test_basic_sessions(fd, VM_BIND, 1, true);
+
+ igt_subtest("basic-vm-bind-vm-destroy")
+ test_basic_sessions(fd, VM_BIND_VM_DESTROY, 1, false);
+
+ igt_subtest("basic-vm-bind-extended")
+ test_basic_sessions(fd, VM_BIND_EXTENDED, 1, true);
igt_subtest("discovery-race")
test_race_discovery(fd, 0, 4);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 20/66] tests/xe_eudebug: Exercise debug metadata events sent to debugger
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (18 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 19/66] tests/xe_eudebug: Add basic vm-bind coverage Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 21/66] tests/xe_eudebug: Add support for dynamic debugger sysfs toggle Christoph Manszewski
` (47 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
From: Maciej Patelczyk <maciej.patelczyk@intel.com>
Add tests which exercise setting debug metadata and correctness
of events received by currently attached debugger.
Extended the attach-debug-metadata so that it has multimple metadatas per
bind. (Maciej)
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
Cc: Christoph Manszewski <christoph.manszewski@intel.com>
---
tests/intel/xe_eudebug.c | 164 +++++++++++++++++++++++++++++++++++++++
1 file changed, 164 insertions(+)
diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
index 35c2a0cc0..f5240e838 100644
--- a/tests/intel/xe_eudebug.c
+++ b/tests/intel/xe_eudebug.c
@@ -27,6 +27,7 @@
#define VM_BIND (1 << 2)
#define VM_BIND_VM_DESTROY (1 << 3)
#define VM_BIND_EXTENDED (1 << 4)
+#define VM_METADATA (1 << 5)
static void basic_vm_bind_client(int fd, struct xe_eudebug_client *c)
{
@@ -977,6 +978,163 @@ static void test_vm_access(int fd, unsigned int flags, int num_clients)
false, XE_EUDEBUG_FILTER_EVENT_VM_BIND_OP);
}
+#define PAGE_SIZE 4096
+#define MDATA_SIZE (WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_NUM * PAGE_SIZE)
+static void metadata_access_client(struct xe_eudebug_client *c)
+{
+ const uint64_t addr = 0x1a0000;
+ struct drm_xe_vm_bind_op_ext_attach_debug *ext;
+ uint8_t *data;
+ size_t bo_size;
+ uint32_t bo, vm;
+ int fd, i;
+
+ fd = xe_eudebug_client_open_driver(c);
+ xe_device_get(fd);
+
+ bo_size = xe_get_default_alignment(fd);
+ vm = xe_eudebug_client_vm_create(c, fd, 0, 0);
+ bo = xe_bo_create(fd, vm, bo_size, system_memory(fd), 0);
+
+ data = calloc(MDATA_SIZE, sizeof(*data));
+ igt_assert(data);
+
+ for (i = 0; i < MDATA_SIZE; i++)
+ data[i] = 0xff & (i + (i > PAGE_SIZE));
+
+ ext = calloc(WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_SIP_AREA + 1, sizeof(*ext));
+ igt_assert(ext);
+
+ for (i = 0; i < WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_SIP_AREA + 1; i++) {
+ ext[i].base.name = XE_VM_BIND_OP_EXTENSIONS_ATTACH_DEBUG;
+ ext[i].metadata_id = xe_eudebug_client_metadata_create(c, fd, i,
+ (i + 1) * PAGE_SIZE, data);
+ ext[i].cookie = i;
+
+ if (i < WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_SIP_AREA)
+ ext[i].base.next_extension = to_user_pointer(&ext[i+1]);
+ }
+
+ xe_eudebug_client_vm_bind_flags(c, fd, vm, bo, 0, addr,
+ bo_size, 0, NULL, 0, to_user_pointer(ext));
+
+ for (i = 0; i < WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_NUM; i++)
+ xe_eudebug_client_wait_stage(c, i);
+
+ xe_eudebug_client_vm_unbind(c, fd, vm, 0, addr, bo_size);
+
+ for (i = 0; i < WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_SIP_AREA + 1; i++)
+ xe_eudebug_client_metadata_destroy(c, fd, ext[i].metadata_id, i, (i + 1) * PAGE_SIZE);
+
+ close(bo);
+ xe_eudebug_client_vm_destroy(c, fd, vm);
+
+ xe_device_put(fd);
+ xe_eudebug_client_close_driver(c, fd);
+
+ free(data);
+ free(ext);
+}
+
+static void debugger_test_metadata(struct xe_eudebug_debugger *d,
+ uint64_t client_handle,
+ uint64_t metadata_handle,
+ uint64_t type,
+ uint64_t len)
+{
+ struct drm_xe_eudebug_read_metadata rm = {
+ .client_handle = client_handle,
+ .metadata_handle = metadata_handle,
+ .size = len,
+ };
+ uint8_t *data;
+ int i;
+
+ data = malloc(len);
+ igt_assert(data);
+
+ rm.ptr = to_user_pointer(data);
+
+ igt_assert_eq(igt_ioctl(d->fd, DRM_XE_EUDEBUG_IOCTL_READ_METADATA, &rm), 0);
+
+ /* syntetic check, test sets different size per metadata type */
+ igt_assert_eq((type + 1) * PAGE_SIZE, rm.size);
+
+ for (i = 0; i < rm.size; i++)
+ igt_assert_eq(data[i], 0xff & (i + (i > PAGE_SIZE)));
+
+ free(data);
+}
+
+static void metadata_read_trigger(struct xe_eudebug_debugger *d,
+ struct drm_xe_eudebug_event *e)
+{
+ struct drm_xe_eudebug_event_metadata *em = (void *)e;
+
+ /* syntetic check, test sets different size per metadata type */
+ igt_assert_eq((em->type + 1) * PAGE_SIZE, em->len);
+
+ if (e->flags & DRM_XE_EUDEBUG_EVENT_CREATE) {
+ debugger_test_metadata(d, em->client_handle, em->metadata_handle,
+ em->type, em->len);
+ xe_eudebug_debugger_signal_stage(d, em->type);
+ }
+}
+
+static void metadata_read_on_vm_bind_trigger(struct xe_eudebug_debugger *d,
+ struct drm_xe_eudebug_event *e)
+{
+ struct drm_xe_eudebug_event_vm_bind_op_metadata *em = (void *)e;
+ struct drm_xe_eudebug_event_vm_bind_op *eo = (void *)e;
+ struct drm_xe_eudebug_event_vm_bind *eb;
+
+ /* For testing purpose client sets metadata_cookie = type */
+
+ /*
+ * Metadata event has a reference to vm-bind-op event which has a reference
+ * to vm-bind event which contains proper client-handle.
+ */
+ eo = (struct drm_xe_eudebug_event_vm_bind_op *)
+ xe_eudebug_event_log_find_seqno(d->log, em->vm_bind_op_ref_seqno);
+ igt_assert(eo);
+ eb = (struct drm_xe_eudebug_event_vm_bind *)
+ xe_eudebug_event_log_find_seqno(d->log, eo->vm_bind_ref_seqno);
+ igt_assert(eb);
+
+ debugger_test_metadata(d,
+ eb->client_handle,
+ em->metadata_handle,
+ em->metadata_cookie,
+ MDATA_SIZE); /* max size */
+
+ xe_eudebug_debugger_signal_stage(d, em->metadata_cookie);
+}
+
+/**
+ * SUBTEST: read-metadata
+ * Description:
+ * Exercise DRM_XE_EUDEBUG_IOCTL_READ_METADATA and debug metadata create|destroy events.
+ */
+static void test_metadata_read(int fd, unsigned int flags, int num_clients)
+{
+ test_client_with_trigger(fd, flags, num_clients, metadata_access_client,
+ DRM_XE_EUDEBUG_EVENT_METADATA, metadata_read_trigger,
+ NULL, true, 0);
+}
+
+/**
+ * SUBTEST: attach-debug-metadata
+ * Description:
+ * Read debug metadata when vm_bind has it attached.
+ */
+static void test_metadata_attach(int fd, unsigned int flags, int num_clients)
+{
+ test_client_with_trigger(fd, flags, num_clients, metadata_access_client,
+ DRM_XE_EUDEBUG_EVENT_VM_BIND_OP_METADATA,
+ metadata_read_on_vm_bind_trigger,
+ NULL, true, 0);
+}
+
igt_main
{
int fd;
@@ -1018,6 +1176,12 @@ igt_main
igt_subtest("basic-vm-bind-extended")
test_basic_sessions(fd, VM_BIND_EXTENDED, 1, true);
+ igt_subtest("read-metadata")
+ test_metadata_read(fd, 0, 1);
+
+ igt_subtest("attach-debug-metadata")
+ test_metadata_attach(fd, 0, 1);
+
igt_subtest("discovery-race")
test_race_discovery(fd, 0, 4);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 21/66] tests/xe_eudebug: Add support for dynamic debugger sysfs toggle
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (19 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 20/66] tests/xe_eudebug: Exercise debug metadata events sent to debugger Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 22/66] tests/xe_eudebug: Add coverage for sysfs debugger toggle Christoph Manszewski
` (46 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
From now on the debugger is disabled by default so it is required
to enable the debugger before using it. This change addresses that
fact by calling necessary library functions within test fixtures.
Signed-off-by: Mika Kuoppala <mika.kuoppala@intel.com>
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
tests/intel/xe_eudebug.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
index f5240e838..adf5e79ac 100644
--- a/tests/intel/xe_eudebug.c
+++ b/tests/intel/xe_eudebug.c
@@ -1137,10 +1137,12 @@ static void test_metadata_attach(int fd, unsigned int flags, int num_clients)
igt_main
{
+ bool was_enabled;
int fd;
igt_fixture {
fd = drm_open_driver(DRIVER_XE);
+ was_enabled = xe_eudebug_enable(fd, true);
}
igt_subtest("basic-connect")
@@ -1191,6 +1193,8 @@ igt_main
igt_subtest("discovery-empty-clients")
test_empty_discovery(fd, DISCOVERY_DESTROY_RESOURCES, 16);
- igt_fixture
+ igt_fixture {
+ xe_eudebug_enable(fd, was_enabled);
drm_close_driver(fd);
+ }
}
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 22/66] tests/xe_eudebug: Add coverage for sysfs debugger toggle
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (20 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 21/66] tests/xe_eudebug: Add support for dynamic debugger sysfs toggle Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 23/66] lib/xe_eudebug: Allow debugger to wait for client Christoph Manszewski
` (45 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
Add subtest for checking sysfs debugger toggle logic and debugger state.
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
tests/intel/xe_eudebug.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
index adf5e79ac..fa81cbfe6 100644
--- a/tests/intel/xe_eudebug.c
+++ b/tests/intel/xe_eudebug.c
@@ -22,6 +22,30 @@
#include "xe/xe_ioctl.h"
#include "xe/xe_query.h"
+/**
+ * SUBTEST: sysfs-toggle
+ * Description:
+ * Excercise the debugger enable/disable sysfs toggle logic
+ */
+static void test_sysfs_toggle(int fd)
+{
+ xe_eudebug_enable(fd, false);
+ igt_assert(!xe_eudebug_debugger_available(fd));
+
+ xe_eudebug_enable(fd, true);
+ igt_assert(xe_eudebug_debugger_available(fd));
+ xe_eudebug_enable(fd, true);
+ igt_assert(xe_eudebug_debugger_available(fd));
+
+ xe_eudebug_enable(fd, false);
+ igt_assert(!xe_eudebug_debugger_available(fd));
+ xe_eudebug_enable(fd, false);
+ igt_assert(!xe_eudebug_debugger_available(fd));
+
+ xe_eudebug_enable(fd, true);
+ igt_assert(xe_eudebug_debugger_available(fd));
+}
+
#define CREATE_VMS (1 << 0)
#define CREATE_EXEC_QUEUES (1 << 1)
#define VM_BIND (1 << 2)
@@ -1145,6 +1169,9 @@ igt_main
was_enabled = xe_eudebug_enable(fd, true);
}
+ igt_subtest("sysfs-toggle")
+ test_sysfs_toggle(fd);
+
igt_subtest("basic-connect")
test_connect(fd);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 23/66] lib/xe_eudebug: Allow debugger to wait for client
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (21 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 22/66] tests/xe_eudebug: Add coverage for sysfs debugger toggle Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 24/66] tests/xe_eudebug: Add vm-bind discovery tests Christoph Manszewski
` (44 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski, Karolina Stolarek
In some tests, we need to pause the debugger at a certain stage as
the point at which the client performs certain activities, determines
the executed code path in the driver.
Add a possibility to pause debugger and to signal continuation by
the client.
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
Cc: Karolina Stolarek <karolina.stolarek@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
lib/xe/xe_eudebug.c | 37 +++++++++++++++++++++++++++++++++++++
lib/xe/xe_eudebug.h | 2 ++
2 files changed, 39 insertions(+)
diff --git a/lib/xe/xe_eudebug.c b/lib/xe/xe_eudebug.c
index 18e0ac422..919dd1d49 100644
--- a/lib/xe/xe_eudebug.c
+++ b/lib/xe/xe_eudebug.c
@@ -45,6 +45,7 @@ struct match_dto {
#define CLIENT_FINI 3
#define CLIENT_STOP 4
#define CLIENT_STAGE 5
+#define DEBUGGER_STAGE 6
#define DEBUGGER_WORKER_INACTIVE 0
#define DEBUGGER_WORKER_ACTIVE 1
@@ -1244,6 +1245,29 @@ void xe_eudebug_debugger_signal_stage(struct xe_eudebug_debugger *d, uint64_t st
token_signal(d->p_client, CLIENT_STAGE, stage);
}
+/**
+ * xe_eudebug_debugger_wait_stage:
+ * @s: pointer to xe_eudebug_debugger structure
+ * @stage: stage to wait on
+ *
+ * Pauses debugger until the client has signalled the corresponding stage with
+ * xe_eudebug_client_signal_stage. This is only for situatuons where the actual
+ * event flow is not enough to coordinate between client/debugger and extra sync
+ * mechanism is needed.
+ */
+void xe_eudebug_debugger_wait_stage(struct xe_eudebug_session *s, uint64_t stage)
+{
+ u64 stage_in;
+
+ igt_debug("debugger xe client fd: %d pausing for stage %lu\n", s->d->master_fd, stage);
+
+ stage_in = wait_from_client(s->c, DEBUGGER_STAGE);
+ igt_debug("debugger xe client fd: %d stage %lu, expected %lu, stage\n", s->d->master_fd,
+ stage_in, stage);
+
+ igt_assert_eq(stage_in, stage);
+}
+
/**
* xe_eudebug_client_create:
* @master_fd: xe client used to open the debugger connection
@@ -1391,6 +1415,19 @@ void xe_eudebug_client_wait_done(struct xe_eudebug_client *c)
}
}
+/**
+ * xe_eudebug_client_signal_stage:
+ * @c: pointer to the client
+ * @stage: stage to signal
+ *
+ * Signals to debugger, waiting in xe_eudebug_debugger_wait_stage(),
+ * releasing it to proceed.
+ */
+void xe_eudebug_client_signal_stage(struct xe_eudebug_client *c, uint64_t stage)
+{
+ token_signal(c->p_out, DEBUGGER_STAGE, stage);
+}
+
/**
* xe_eudebug_client_wait_stage:
* @c: pointer to xe_eudebug_client structure
diff --git a/lib/xe/xe_eudebug.h b/lib/xe/xe_eudebug.h
index 1343cb25c..81c33417f 100644
--- a/lib/xe/xe_eudebug.h
+++ b/lib/xe/xe_eudebug.h
@@ -135,6 +135,7 @@ void xe_eudebug_debugger_set_data(struct xe_eudebug_debugger *c, void *ptr);
void xe_eudebug_debugger_add_trigger(struct xe_eudebug_debugger *d, int type,
xe_eudebug_trigger_fn fn);
void xe_eudebug_debugger_signal_stage(struct xe_eudebug_debugger *d, uint64_t stage);
+void xe_eudebug_debugger_wait_stage(struct xe_eudebug_session *s, uint64_t stage);
struct xe_eudebug_client *
xe_eudebug_client_create(int xe, xe_eudebug_client_work_fn work, uint64_t flags, void *data);
@@ -142,6 +143,7 @@ void xe_eudebug_client_destroy(struct xe_eudebug_client *c);
void xe_eudebug_client_start(struct xe_eudebug_client *c);
void xe_eudebug_client_stop(struct xe_eudebug_client *c);
void xe_eudebug_client_wait_done(struct xe_eudebug_client *c);
+void xe_eudebug_client_signal_stage(struct xe_eudebug_client *c, uint64_t stage);
void xe_eudebug_client_wait_stage(struct xe_eudebug_client *c, uint64_t stage);
uint64_t xe_eudebug_client_get_seqno(struct xe_eudebug_client *c);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 24/66] tests/xe_eudebug: Add vm-bind discovery tests
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (22 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 23/66] lib/xe_eudebug: Allow debugger to wait for client Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 25/66] tests/xe_eudebug: Add basic-vm-bind-metadata-discovery Christoph Manszewski
` (43 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski, Karolina Stolarek
Extend vm-bind testing by adding variations of existing subtests,
that exercise the eu debugger's discovery mechanism, by attaching
after relevant vm-bind operations were performed by the client.
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
Cc: Karolina Stolarek <karolina.stolarek@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
tests/intel/xe_eudebug.c | 133 ++++++++++++++++++++++++++++++++++++---
1 file changed, 125 insertions(+), 8 deletions(-)
diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
index fa81cbfe6..3a3cf5e45 100644
--- a/tests/intel/xe_eudebug.c
+++ b/tests/intel/xe_eudebug.c
@@ -46,22 +46,33 @@ static void test_sysfs_toggle(int fd)
igt_assert(xe_eudebug_debugger_available(fd));
}
+#define STAGE_PRE_DEBUG_RESOURCES_DONE 1
+#define STAGE_DISCOVERY_DONE 2
+
#define CREATE_VMS (1 << 0)
#define CREATE_EXEC_QUEUES (1 << 1)
#define VM_BIND (1 << 2)
#define VM_BIND_VM_DESTROY (1 << 3)
#define VM_BIND_EXTENDED (1 << 4)
#define VM_METADATA (1 << 5)
+#define TEST_DISCOVERY (1 << 31)
static void basic_vm_bind_client(int fd, struct xe_eudebug_client *c)
{
uint32_t vm = xe_eudebug_client_vm_create(c, fd, 0, 0);
size_t bo_size = xe_get_default_alignment(fd);
+ bool test_discovery = c->flags & TEST_DISCOVERY;
uint32_t bo = xe_bo_create(fd, 0, bo_size,
system_memory(fd), 0);
uint64_t addr = 0x1a0000;
xe_eudebug_client_vm_bind(c, fd, vm, bo, 0, addr, bo_size);
+
+ if (test_discovery) {
+ xe_eudebug_client_signal_stage(c, STAGE_PRE_DEBUG_RESOURCES_DONE);
+ xe_eudebug_client_wait_stage(c, STAGE_DISCOVERY_DONE);
+ }
+
xe_eudebug_client_vm_unbind(c, fd, vm, 0, addr, bo_size);
gem_close(fd, bo);
@@ -72,12 +83,25 @@ static void basic_vm_bind_vm_destroy_client(int fd, struct xe_eudebug_client *c)
{
uint32_t vm = xe_eudebug_client_vm_create(c, fd, 0, 0);
size_t bo_size = xe_get_default_alignment(fd);
+ bool test_discovery = c->flags & TEST_DISCOVERY;
uint32_t bo = xe_bo_create(fd, 0, bo_size,
system_memory(fd), 0);
uint64_t addr = 0x1a0000;
- xe_eudebug_client_vm_bind(c, fd, vm, bo, 0, addr, bo_size);
- xe_eudebug_client_vm_destroy(c, fd, vm);
+ if (test_discovery) {
+ vm = xe_vm_create(fd, 0, 0);
+
+ xe_vm_bind_async(fd, vm, 0, bo, 0, addr, bo_size, NULL, 0);
+
+ xe_vm_destroy(fd, vm);
+
+ xe_eudebug_client_signal_stage(c, STAGE_PRE_DEBUG_RESOURCES_DONE);
+ xe_eudebug_client_wait_stage(c, STAGE_DISCOVERY_DONE);
+ } else {
+ vm = xe_eudebug_client_vm_create(c, fd, 0, 0);
+ xe_eudebug_client_vm_bind(c, fd, vm, bo, 0, addr, bo_size);
+ xe_eudebug_client_vm_destroy(c, fd, vm);
+ }
gem_close(fd, bo);
}
@@ -213,6 +237,7 @@ static void vm_bind_client(int fd, struct xe_eudebug_client *c)
{
uint64_t op_ref_seqno, ref_seqno;
struct bind_list *bl;
+ bool test_discovery = c->flags & TEST_DISCOVERY;
size_t bo_size = 3 * xe_get_default_alignment(fd);
uint32_t bo[2] = {
xe_bo_create(fd, 0, bo_size, system_memory(fd), 0),
@@ -222,15 +247,48 @@ static void vm_bind_client(int fd, struct xe_eudebug_client *c)
uint64_t addr[] = {0x2a0000, 0x3a0000};
uint64_t rebind_bo_offset = 2 * bo_size / 3;
uint64_t size = bo_size / 3;
+ int i = 0;
+
+ if (test_discovery) {
+ xe_vm_bind_async(fd, vm, 0, bo[0], 0, addr[0], bo_size, NULL, 0);
+
+ xe_vm_unbind_async(fd, vm, 0, 0, addr[0] + size, size, NULL, 0);
- xe_eudebug_client_vm_bind(c, fd, vm, bo[0], 0, addr[0], bo_size);
- xe_eudebug_client_vm_unbind(c, fd, vm, 0, addr[0] + size, size);
+ xe_vm_bind_async(fd, vm, 0, bo[1], 0, addr[1], bo_size, NULL, 0);
- xe_eudebug_client_vm_bind(c, fd, vm, bo[1], 0, addr[1], bo_size);
- xe_eudebug_client_vm_bind(c, fd, vm, bo[1], rebind_bo_offset, addr[1], size);
+ xe_vm_bind_async(fd, vm, 0, bo[1], rebind_bo_offset, addr[1], size, NULL, 0);
- bl = create_bind_list(fd, system_memory(fd), vm, 4);
- do_bind_list(c, bl, NULL);
+ bl = create_bind_list(fd, system_memory(fd), vm, 4);
+ xe_vm_bind_array(bl->fd, bl->vm, 0, bl->bind_ops, bl->n, NULL, 0);
+
+ xe_vm_unbind_all_async(fd, vm, 0, bo[0], NULL, 0);
+
+ xe_eudebug_client_vm_bind_event(c, DRM_XE_EUDEBUG_EVENT_STATE_CHANGE,
+ bl->fd, bl->vm, 0, bl->n + 2, &ref_seqno);
+
+ xe_eudebug_client_vm_bind_op_event(c, DRM_XE_EUDEBUG_EVENT_CREATE, ref_seqno,
+ &op_ref_seqno, addr[1], size, 0);
+ xe_eudebug_client_vm_bind_op_event(c, DRM_XE_EUDEBUG_EVENT_CREATE, ref_seqno,
+ &op_ref_seqno, addr[1] + size, size * 2, 0);
+
+ for (i = 0; i < bl->n; i++)
+ xe_eudebug_client_vm_bind_op_event(c, DRM_XE_EUDEBUG_EVENT_CREATE,
+ ref_seqno, &op_ref_seqno,
+ bl->bind_ops[i].addr,
+ bl->bind_ops[i].range, 0);
+
+ xe_eudebug_client_signal_stage(c, STAGE_PRE_DEBUG_RESOURCES_DONE);
+ xe_eudebug_client_wait_stage(c, STAGE_DISCOVERY_DONE);
+ } else {
+ xe_eudebug_client_vm_bind(c, fd, vm, bo[0], 0, addr[0], bo_size);
+ xe_eudebug_client_vm_unbind(c, fd, vm, 0, addr[0] + size, size);
+
+ xe_eudebug_client_vm_bind(c, fd, vm, bo[1], 0, addr[1], bo_size);
+ xe_eudebug_client_vm_bind(c, fd, vm, bo[1], rebind_bo_offset, addr[1], size);
+
+ bl = create_bind_list(fd, system_memory(fd), vm, 4);
+ do_bind_list(c, bl, NULL);
+ }
xe_vm_unbind_all_async(fd, vm, 0, bo[1], NULL, 0);
@@ -581,6 +639,56 @@ static void test_basic_sessions(int fd, unsigned int flags, int count, bool matc
xe_eudebug_session_destroy(s[i]);
}
+/**
+ * SUBTEST: basic-vm-bind-discovery
+ * Description:
+ * Attach the debugger to a process that performs vm-bind before attaching
+ * and check if the discovery process reports it.
+ *
+ * SUBTEST: basic-vm-bind-vm-destroy-discovery
+ * Description:
+ * Attach the debugger to a process that performs vm bind, and destroys
+ * the vm without unbinding before attaching. Make sure that we don't get
+ * any bind/unbind and vm create/destroy events.
+ *
+ * SUBTEST: basic-vm-bind-extended-discovery
+ * Description:
+ * Attach the debugger to a process that performs bind, bind array, rebind,
+ * partial unbind, and unbind all operations before attaching. Ensure that
+ * we get a only a singe 'VM_BIND' event from the discovery worker.
+ */
+static void test_basic_discovery(int fd, unsigned int flags, bool match_opposite)
+{
+ struct xe_eudebug_debugger *d;
+ struct xe_eudebug_session *s;
+ struct xe_eudebug_client *c;
+
+ s = xe_eudebug_session_create(fd, run_basic_client, flags | TEST_DISCOVERY, NULL);
+
+ c = s->c;
+ d = s->d;
+
+ xe_eudebug_client_start(c);
+ xe_eudebug_debugger_wait_stage(s, STAGE_PRE_DEBUG_RESOURCES_DONE);
+
+ igt_assert_eq(xe_eudebug_debugger_attach(d, c), 0);
+ xe_eudebug_debugger_start_worker(d);
+
+ /* give the worker time to do it's job */
+ sleep(2);
+ xe_eudebug_debugger_signal_stage(d, STAGE_DISCOVERY_DONE);
+
+ xe_eudebug_client_wait_done(c);
+
+ xe_eudebug_debugger_stop_worker(d, 1);
+
+ xe_eudebug_event_log_print(d->log, true);
+ xe_eudebug_event_log_print(c->log, true);
+
+ xe_eudebug_session_check(s, match_opposite, 0);
+ xe_eudebug_session_destroy(s);
+}
+
#define RESOURCE_COUNT 16
#define PRIMARY_THREAD (1 << 0)
#define DISCOVERY_CLOSE_CLIENT (1 << 1)
@@ -1199,12 +1307,21 @@ igt_main
igt_subtest("basic-vm-bind")
test_basic_sessions(fd, VM_BIND, 1, true);
+ igt_subtest("basic-vm-bind-discovery")
+ test_basic_discovery(fd, VM_BIND, true);
+
igt_subtest("basic-vm-bind-vm-destroy")
test_basic_sessions(fd, VM_BIND_VM_DESTROY, 1, false);
+ igt_subtest("basic-vm-bind-vm-destroy-discovery")
+ test_basic_discovery(fd, VM_BIND_VM_DESTROY, false);
+
igt_subtest("basic-vm-bind-extended")
test_basic_sessions(fd, VM_BIND_EXTENDED, 1, true);
+ igt_subtest("basic-vm-bind-extended-discovery")
+ test_basic_discovery(fd, VM_BIND_EXTENDED, true);
+
igt_subtest("read-metadata")
test_metadata_read(fd, 0, 1);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 25/66] tests/xe_eudebug: Add basic-vm-bind-metadata-discovery
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (23 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 24/66] tests/xe_eudebug: Add vm-bind discovery tests Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 26/66] tests/xe_eudebug: Add basic-vm-access-parameters test Christoph Manszewski
` (42 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun
From: Maciej Patelczyk <maciej.patelczyk@intel.com>
Added VM BIND Discovery type test that shall detect attached metadata.
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
tests/intel/xe_eudebug.c | 89 +++++++++++++++++++++++++++++-----------
1 file changed, 64 insertions(+), 25 deletions(-)
diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
index 3a3cf5e45..50c944ba9 100644
--- a/tests/intel/xe_eudebug.c
+++ b/tests/intel/xe_eudebug.c
@@ -55,18 +55,67 @@ static void test_sysfs_toggle(int fd)
#define VM_BIND_VM_DESTROY (1 << 3)
#define VM_BIND_EXTENDED (1 << 4)
#define VM_METADATA (1 << 5)
+#define VM_BIND_METADATA (1 << 6)
#define TEST_DISCOVERY (1 << 31)
+#define PAGE_SIZE 4096
+static struct drm_xe_vm_bind_op_ext_attach_debug *
+basic_vm_bind_metadata_ext_prepare(int fd, struct xe_eudebug_client *c,
+ uint8_t **data, uint32_t data_size)
+{
+ struct drm_xe_vm_bind_op_ext_attach_debug *ext;
+ int i;
+
+ *data = calloc(data_size, sizeof(*data));
+ igt_assert(*data);
+
+ for (i = 0; i < data_size; i++)
+ (*data)[i] = 0xff & (i + (i > PAGE_SIZE));
+
+
+ ext = calloc(WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_NUM, sizeof(*ext));
+ igt_assert(ext);
+
+ for (i = 0; i < WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_NUM; i++) {
+ ext[i].base.name = XE_VM_BIND_OP_EXTENSIONS_ATTACH_DEBUG;
+ ext[i].metadata_id = xe_eudebug_client_metadata_create(c, fd, i,
+ (i + 1) * PAGE_SIZE, *data);
+ ext[i].cookie = i;
+
+ if (i < WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_NUM - 1)
+ ext[i].base.next_extension = to_user_pointer(&ext[i+1]);
+ }
+ return ext;
+}
+
+static void basic_vm_bind_metadata_ext_del(int fd, struct xe_eudebug_client *c,
+ struct drm_xe_vm_bind_op_ext_attach_debug *ext,
+ uint8_t *data)
+{
+ for (int i = 0; i < WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_NUM; i++)
+ xe_eudebug_client_metadata_destroy(c, fd, ext[i].metadata_id,
+ i, (i + 1) * PAGE_SIZE);
+ free(ext);
+ free(data);
+}
+
static void basic_vm_bind_client(int fd, struct xe_eudebug_client *c)
{
+ struct drm_xe_vm_bind_op_ext_attach_debug *ext = NULL;
uint32_t vm = xe_eudebug_client_vm_create(c, fd, 0, 0);
size_t bo_size = xe_get_default_alignment(fd);
bool test_discovery = c->flags & TEST_DISCOVERY;
+ bool test_metadata = c->flags & VM_BIND_METADATA;
uint32_t bo = xe_bo_create(fd, 0, bo_size,
system_memory(fd), 0);
uint64_t addr = 0x1a0000;
+ uint8_t *data = NULL;
+
+ if (test_metadata)
+ ext = basic_vm_bind_metadata_ext_prepare(fd, c, &data, PAGE_SIZE);
- xe_eudebug_client_vm_bind(c, fd, vm, bo, 0, addr, bo_size);
+ xe_eudebug_client_vm_bind_flags(c, fd, vm, bo, 0, addr,
+ bo_size, 0, NULL, 0, to_user_pointer(ext));
if (test_discovery) {
xe_eudebug_client_signal_stage(c, STAGE_PRE_DEBUG_RESOURCES_DONE);
@@ -75,6 +124,9 @@ static void basic_vm_bind_client(int fd, struct xe_eudebug_client *c)
xe_eudebug_client_vm_unbind(c, fd, vm, 0, addr, bo_size);
+ if (test_metadata)
+ basic_vm_bind_metadata_ext_del(fd, c, ext, data);
+
gem_close(fd, bo);
xe_eudebug_client_vm_destroy(c, fd, vm);
}
@@ -367,7 +419,7 @@ static void run_basic_client(struct xe_eudebug_client *c)
xe_eudebug_client_vm_destroy(c, fd, vm);
}
- if (c->flags & VM_BIND)
+ if (c->flags & VM_BIND || c->flags & VM_BIND_METADATA)
basic_vm_bind_client(fd, c);
if (c->flags & VM_BIND_EXTENDED)
@@ -645,6 +697,11 @@ static void test_basic_sessions(int fd, unsigned int flags, int count, bool matc
* Attach the debugger to a process that performs vm-bind before attaching
* and check if the discovery process reports it.
*
+ * SUBTEST: basic-vm-bind-metadata-discovery
+ * Description:
+ * Attach the debugger to a process that performs vm-bind with metadata attached
+ * before attaching and check if the discovery process reports it.
+ *
* SUBTEST: basic-vm-bind-vm-destroy-discovery
* Description:
* Attach the debugger to a process that performs vm bind, and destroys
@@ -1128,24 +1185,7 @@ static void metadata_access_client(struct xe_eudebug_client *c)
vm = xe_eudebug_client_vm_create(c, fd, 0, 0);
bo = xe_bo_create(fd, vm, bo_size, system_memory(fd), 0);
- data = calloc(MDATA_SIZE, sizeof(*data));
- igt_assert(data);
-
- for (i = 0; i < MDATA_SIZE; i++)
- data[i] = 0xff & (i + (i > PAGE_SIZE));
-
- ext = calloc(WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_SIP_AREA + 1, sizeof(*ext));
- igt_assert(ext);
-
- for (i = 0; i < WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_SIP_AREA + 1; i++) {
- ext[i].base.name = XE_VM_BIND_OP_EXTENSIONS_ATTACH_DEBUG;
- ext[i].metadata_id = xe_eudebug_client_metadata_create(c, fd, i,
- (i + 1) * PAGE_SIZE, data);
- ext[i].cookie = i;
-
- if (i < WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_SIP_AREA)
- ext[i].base.next_extension = to_user_pointer(&ext[i+1]);
- }
+ ext = basic_vm_bind_metadata_ext_prepare(fd, c, &data, MDATA_SIZE);
xe_eudebug_client_vm_bind_flags(c, fd, vm, bo, 0, addr,
bo_size, 0, NULL, 0, to_user_pointer(ext));
@@ -1155,17 +1195,13 @@ static void metadata_access_client(struct xe_eudebug_client *c)
xe_eudebug_client_vm_unbind(c, fd, vm, 0, addr, bo_size);
- for (i = 0; i < WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_SIP_AREA + 1; i++)
- xe_eudebug_client_metadata_destroy(c, fd, ext[i].metadata_id, i, (i + 1) * PAGE_SIZE);
+ basic_vm_bind_metadata_ext_del(fd, c, ext, data);
close(bo);
xe_eudebug_client_vm_destroy(c, fd, vm);
xe_device_put(fd);
xe_eudebug_client_close_driver(c, fd);
-
- free(data);
- free(ext);
}
static void debugger_test_metadata(struct xe_eudebug_debugger *d,
@@ -1310,6 +1346,9 @@ igt_main
igt_subtest("basic-vm-bind-discovery")
test_basic_discovery(fd, VM_BIND, true);
+ igt_subtest("basic-vm-bind-metadata-discovery")
+ test_basic_discovery(fd, VM_BIND_METADATA, true);
+
igt_subtest("basic-vm-bind-vm-destroy")
test_basic_sessions(fd, VM_BIND_VM_DESTROY, 1, false);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 26/66] tests/xe_eudebug: Add basic-vm-access-parameters test
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (24 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 25/66] tests/xe_eudebug: Add basic-vm-bind-metadata-discovery Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 27/66] lib/xe_eudebug: Add mutex for log events write Christoph Manszewski
` (41 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
From: Pawel Sikora <pawel.sikora@intel.com>
This new test checks negative scenarios of VM_OPEN
ioctl and pread/pwrite usage.
Signed-off-by: Pawel Sikora <pawel.sikora@intel.com>
Cc: Christoph Manszewski <christoph.manszewski@intel.com>
---
tests/intel/xe_eudebug.c | 143 +++++++++++++++++++++++++++++++++++++++
1 file changed, 143 insertions(+)
diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
index 50c944ba9..37b4f4e27 100644
--- a/tests/intel/xe_eudebug.c
+++ b/tests/intel/xe_eudebug.c
@@ -1167,6 +1167,146 @@ static void test_vm_access(int fd, unsigned int flags, int num_clients)
false, XE_EUDEBUG_FILTER_EVENT_VM_BIND_OP);
}
+static void debugger_test_vma_parameters(struct xe_eudebug_debugger *d,
+ uint64_t client_handle,
+ uint64_t vm_handle,
+ uint64_t va_start,
+ uint64_t va_length)
+{
+ struct drm_xe_eudebug_vm_open vo = { 0, };
+ uint64_t *v;
+ uint64_t items = va_length / sizeof(uint64_t);
+ int fd;
+ int r, i;
+
+ v = malloc(va_length);
+ igt_assert(v);
+
+ /* Negative VM open - bad client handle */
+ vo.client_handle = client_handle + 123;
+ vo.vm_handle = vm_handle;
+ fd = igt_ioctl(d->fd, DRM_XE_EUDEBUG_IOCTL_VM_OPEN, &vo);
+ igt_assert(fd < 0);
+
+ /* Negative VM open - bad vm handle */
+ vo.client_handle = client_handle;
+ vo.vm_handle = vm_handle + 123;
+ fd = igt_ioctl(d->fd, DRM_XE_EUDEBUG_IOCTL_VM_OPEN, &vo);
+ igt_assert(fd < 0);
+
+ /* Positive VM open */
+ vo.client_handle = client_handle;
+ vo.vm_handle = vm_handle;
+ fd = igt_ioctl(d->fd, DRM_XE_EUDEBUG_IOCTL_VM_OPEN, &vo);
+ igt_assert_lte(0, fd);
+
+ /* Negative pread - bad fd */
+ r = pread(fd + 123, v, va_length, va_start);
+ igt_assert(r < 0);
+
+ /* Negative pread - bad va_start */
+ r = pread(fd, v, va_length, 0);
+ igt_assert(r < 0);
+
+ /* Negative pread - bad va_start */
+ r = pread(fd, v, va_length, va_start - 1);
+ igt_assert(r < 0);
+
+ /* Positive pread - zero va_length */
+ r = pread(fd, v, 0, va_start);
+ igt_assert_eq(r, 0);
+
+ /* Negative pread - out of range */
+ r = pread(fd, v, va_length + 1, va_start);
+ igt_assert_eq(r, va_length);
+
+ /* Negative pread - bad va_start */
+ r = pread(fd, v, 1, va_start + va_length);
+ igt_assert(r < 0);
+
+ /* Positive pread - whole range */
+ r = pread(fd, v, va_length, va_start);
+ igt_assert_eq(r, va_length);
+
+ /* Positive pread */
+ r = pread(fd, v, 1, va_start + va_length - 1);
+ igt_assert_eq(r, 1);
+
+ for (i = 0; i < items; i++)
+ igt_assert_eq(v[i], va_start + i);
+
+ for (i = 0; i < items; i++)
+ v[i] = va_start + i + 1;
+
+ /* Negative pwrite - bad fd */
+ r = pwrite(fd + 123, v, va_length, va_start);
+ igt_assert(r < 0);
+
+ /* Negative pwrite - bad va_start */
+ r = pwrite(fd, v, va_length, -1);
+ igt_assert(r < 0);
+
+ /* Negative pwrite - zero va_start */
+ r = pwrite(fd, v, va_length, 0);
+ igt_assert(r < 0);
+
+ /* Negative pwrite - bad va_length */
+ r = pwrite(fd, v, va_length + 1, va_start);
+ igt_assert_eq(r, va_length);
+
+ /* Positive pwrite - zero va_length */
+ r = pwrite(fd, v, 0, va_start);
+ igt_assert_eq(r, 0);
+
+ /* Positive pwrite */
+ r = pwrite(fd, v, va_length, va_start);
+ igt_assert_eq(r, va_length);
+ fsync(fd);
+
+ close(fd);
+ free(v);
+}
+
+static void vm_trigger_access_parameters(struct xe_eudebug_debugger *d,
+ struct drm_xe_eudebug_event *e)
+{
+ struct drm_xe_eudebug_event_vm_bind_op *eo = (void *)e;
+
+ if (e->flags & DRM_XE_EUDEBUG_EVENT_CREATE) {
+ struct drm_xe_eudebug_event_vm_bind *eb;
+
+ igt_debug("vm bind op event received with ref %lld, addr 0x%llx, range 0x%llx\n",
+ eo->vm_bind_ref_seqno,
+ eo->addr,
+ eo->range);
+
+ eb = (struct drm_xe_eudebug_event_vm_bind *)
+ xe_eudebug_event_log_find_seqno(d->log, eo->vm_bind_ref_seqno);
+ igt_assert(eb);
+
+ debugger_test_vma_parameters(d, eb->client_handle, eb->vm_handle,
+ eo->addr, eo->range);
+ xe_eudebug_debugger_signal_stage(d, eo->addr);
+ }
+}
+
+/**
+ * SUBTEST: basic-vm-access-parameters
+ * Description:
+ * Check negative scenarios of VM_OPEN ioctl and pread/pwrite usage.
+ */
+static void test_vm_access_parameters(int fd, unsigned int flags, int num_clients)
+{
+ struct drm_xe_engine_class_instance *hwe;
+
+ xe_for_each_engine(fd, hwe)
+ test_client_with_trigger(fd, flags, num_clients,
+ vm_access_client,
+ DRM_XE_EUDEBUG_EVENT_VM_BIND_OP,
+ vm_trigger_access_parameters, hwe,
+ false, XE_EUDEBUG_FILTER_EVENT_VM_BIND_OP);
+}
+
#define PAGE_SIZE 4096
#define MDATA_SIZE (WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_NUM * PAGE_SIZE)
static void metadata_access_client(struct xe_eudebug_client *c)
@@ -1331,6 +1471,9 @@ igt_main
igt_subtest("basic-vm-access")
test_vm_access(fd, 0, 1);
+ igt_subtest("basic-vm-access-parameters")
+ test_vm_access_parameters(fd, 0, 1);
+
igt_subtest("multiple-sessions")
test_basic_sessions(fd, CREATE_VMS | CREATE_EXEC_QUEUES, 4, true);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 27/66] lib/xe_eudebug: Add mutex for log events write
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (25 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 26/66] tests/xe_eudebug: Add basic-vm-access-parameters test Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 28/66] tests/xe_eudebug: Add basic-client-th test Christoph Manszewski
` (40 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun
From: Pawel Sikora <pawel.sikora@intel.com>
Make 'xe_eudebug_event_log_write' to be thread-safe.
Signed-off-by: Pawel Sikora <pawel.sikora@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
lib/xe/xe_eudebug.c | 6 +++++-
lib/xe/xe_eudebug.h | 1 +
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/lib/xe/xe_eudebug.c b/lib/xe/xe_eudebug.c
index 919dd1d49..41809429d 100644
--- a/lib/xe/xe_eudebug.c
+++ b/lib/xe/xe_eudebug.c
@@ -830,6 +830,7 @@ struct xe_eudebug_event_log *xe_eudebug_event_log_create(const char *name, unsig
igt_assert(l->log);
l->max_size = max_size;
strncpy(l->name, name, sizeof(l->name) - 1);
+ pthread_mutex_init(&l->lock, NULL);
return l;
}
@@ -842,6 +843,7 @@ struct xe_eudebug_event_log *xe_eudebug_event_log_create(const char *name, unsig
*/
void xe_eudebug_event_log_destroy(struct xe_eudebug_event_log *l)
{
+ pthread_mutex_destroy(&l->lock);
free(l->log);
free(l);
}
@@ -851,7 +853,7 @@ void xe_eudebug_event_log_destroy(struct xe_eudebug_event_log *l)
* @l: event log pointer
* @e: event to be written to event log
*
- * Writes event @e to the event log.
+ * Writes event @e to the event log, thread-safe.
*/
void xe_eudebug_event_log_write(struct xe_eudebug_event_log *l, struct drm_xe_eudebug_event *e)
{
@@ -862,6 +864,7 @@ void xe_eudebug_event_log_write(struct xe_eudebug_event_log *l, struct drm_xe_eu
*/
igt_assert_lt(e->seqno, 10 * 1000 * 1000);
+ pthread_mutex_lock(&l->lock);
igt_assert_lt(l->head + e->len, l->max_size);
memcpy(l->log + l->head, e, e->len);
l->head += e->len;
@@ -870,6 +873,7 @@ void xe_eudebug_event_log_write(struct xe_eudebug_event_log *l, struct drm_xe_eu
igt_info("%s: wrote %u bytes to eventlog, free %u bytes\n",
l->name, e->len, l->max_size - l->head);
#endif
+ pthread_mutex_unlock(&l->lock);
}
/**
diff --git a/lib/xe/xe_eudebug.h b/lib/xe/xe_eudebug.h
index 81c33417f..a499cc977 100644
--- a/lib/xe/xe_eudebug.h
+++ b/lib/xe/xe_eudebug.h
@@ -14,6 +14,7 @@ struct xe_eudebug_event_log {
unsigned int head;
unsigned int max_size;
char name[80];
+ pthread_mutex_t lock;
};
struct xe_eudebug_debugger {
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 28/66] tests/xe_eudebug: Add basic-client-th test
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (26 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 27/66] lib/xe_eudebug: Add mutex for log events write Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 29/66] tests/xe_eudebug: Added connect-user test Christoph Manszewski
` (39 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun
From: Pawel Sikora <pawel.sikora@intel.com>
Add basic-client-th test which is a multithreaded version of basic-client.
Create random number of VMs in random number of threads.
Signed-off-by: Pawel Sikora <pawel.sikora@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
tests/intel/xe_eudebug.c | 78 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 78 insertions(+)
diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
index 37b4f4e27..022b39f1f 100644
--- a/tests/intel/xe_eudebug.c
+++ b/tests/intel/xe_eudebug.c
@@ -13,6 +13,7 @@
*/
#include <poll.h>
+#include <pthread.h>
#include <sys/ioctl.h>
#include "igt.h"
@@ -640,6 +641,10 @@ static void test_read_event(int fd)
* Description:
* Attach the debugger to process which opens and closes xe drm client.
*
+ * SUBTEST: basic-client-th
+ * Description:
+ * Create client basic resources (vms) in multiple threads
+ *
* SUBTEST: multiple-sessions
* Description:
* Simultaneously attach many debuggers to many processes.
@@ -669,6 +674,7 @@ static void test_read_event(int fd)
* @vms: vms
* @exec-queues: exec queues
*/
+
static void test_basic_sessions(int fd, unsigned int flags, int count, bool match_opposite)
{
struct xe_eudebug_session **s;
@@ -1056,6 +1062,75 @@ static void test_client_with_trigger(int fd, unsigned int flags, int count,
xe_eudebug_session_destroy(s[i]);
}
+struct thread_fn_args {
+ struct xe_eudebug_client *client;
+ int fd;
+};
+
+static void *basic_client_th(void *data)
+{
+ struct thread_fn_args *f = data;
+ struct xe_eudebug_client *c = f->client;
+ uint32_t *vms;
+ int fd, i, num_vms;
+
+ fd = f->fd;
+ igt_assert(fd);
+
+ xe_device_get(fd);
+
+ num_vms = 2 + rand() % 16;
+ vms = calloc(num_vms, sizeof(*vms));
+ igt_assert(vms);
+ igt_debug("Create %d client vms\n", num_vms);
+
+ for (i = 0; i < num_vms; i++)
+ vms[i] = xe_eudebug_client_vm_create(c, fd, DRM_XE_VM_CREATE_FLAG_SCRATCH_PAGE, 0);
+
+ for (i = 0; i < num_vms; i++)
+ xe_eudebug_client_vm_destroy(c, fd, vms[i]);
+
+ xe_device_put(fd);
+ free(vms);
+
+ return NULL;
+}
+
+static void run_basic_client_th(struct xe_eudebug_client *c)
+{
+ struct thread_fn_args *args;
+ int i, num_threads, fd;
+ pthread_t *threads;
+
+ args = calloc(1, sizeof(*args));
+ igt_assert(args);
+
+ num_threads = 2 + random() % 16;
+ igt_debug("Run on %d threads\n", num_threads);
+ threads = calloc(num_threads, sizeof(*threads));
+ igt_assert(threads);
+
+ fd = xe_eudebug_client_open_driver(c);
+ args->client = c;
+ args->fd = fd;
+
+ for (i = 0; i < num_threads; i++)
+ pthread_create(&threads[i], NULL, basic_client_th, args);
+
+ for (i = 0; i < num_threads; i++)
+ pthread_join(threads[i], NULL);
+
+ xe_eudebug_client_close_driver(c, fd);
+ free(args);
+ free(threads);
+}
+
+static void test_basic_sessions_th(int fd, unsigned int flags, int num_clients, bool match_opposite)
+{
+ test_client_with_trigger(fd, flags, num_clients, run_basic_client_th,
+ 0, NULL, NULL, match_opposite, 0);
+}
+
static void vm_access_client(struct xe_eudebug_client *c)
{
struct drm_xe_sync sync = {
@@ -1468,6 +1543,9 @@ igt_main
igt_subtest("basic-client")
test_basic_sessions(fd, 0, 1, true);
+ igt_subtest("basic-client-th")
+ test_basic_sessions_th(fd, 0, 1, true);
+
igt_subtest("basic-vm-access")
test_vm_access(fd, 0, 1);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 29/66] tests/xe_eudebug: Added connect-user test
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (27 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 28/66] tests/xe_eudebug: Add basic-client-th test Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 30/66] tests/xe_eudebug: Add discovery-race-vmbind subtest Christoph Manszewski
` (38 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun
From: Maciej Patelczyk <maciej.patelczyk@intel.com>
Verify the connection:
* user to user
* user to root
* root to user
* user to other user
The test uses two known non-privileged users lp and mail to verify
the scenarios. Test drops root privileges to one of users if necessary.
ptrace cannot access process which is not dumpable. The default value
of this property is stored in '/proc/sys/fs/suid_dumpable'. If process
drops privileges then it gets the value from mentioned suid_dumpable.
In our case the value after switching userm, to non privileged one,
is 2 (SUID_DUMP_ROOT). Enforce it to be 1 (SUID_DUMP_USER).
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
tests/intel/xe_eudebug.c | 164 +++++++++++++++++++++++++++++++++++++++
1 file changed, 164 insertions(+)
diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
index 022b39f1f..8c21cffc7 100644
--- a/tests/intel/xe_eudebug.c
+++ b/tests/intel/xe_eudebug.c
@@ -12,9 +12,12 @@
* Test category: functionality test
*/
+#include <grp.h>
#include <poll.h>
#include <pthread.h>
+#include <pwd.h>
#include <sys/ioctl.h>
+#include <sys/prctl.h>
#include "igt.h"
#include "intel_pat.h"
@@ -545,6 +548,164 @@ static void test_connect(int fd)
close(debugfd);
}
+static void switch_user(__uid_t uid, __gid_t gid)
+{
+ struct group *gr;
+ __gid_t gr_v;
+
+ /* Users other then root need to belong to video group */
+ gr = getgrnam("video");
+ igt_assert(gr);
+
+ /* Drop all */
+ igt_assert_eq(setgroups(1, &gr->gr_gid), 0);
+ igt_assert_eq(setgid(gid), 0);
+ igt_assert_eq(setuid(uid), 0);
+
+ igt_assert_eq(getgroups(1, &gr_v), 1);
+ igt_assert_eq(gr_v, gr->gr_gid);
+ igt_assert_eq(getgid(), gid);
+ igt_assert_eq(getuid(), uid);
+
+ igt_assert_eq(prctl(PR_SET_DUMPABLE, 1L), 0);
+}
+
+/**
+ * SUBTEST: connect-user
+ * Description:
+ * Verify unprivileged XE_EUDEBG_CONNECT ioctl.
+ * Check:
+ * - user debugger to user workload connection
+ * - user debugger to other user workload connection
+ * - user debugger to privileged workload connection
+ */
+static void test_connect_user(int fd)
+{
+ struct drm_xe_eudebug_connect param = {};
+ struct passwd *pwd, *pwd2;
+ const char *user1 = "lp";
+ const char *user2 = "mail";
+ int debugfd, ret, i;
+ int p1[2], p2[2];
+ __uid_t u1, u2;
+ __gid_t g1, g2;
+ int newfd;
+ pid_t pid;
+
+#define NUM_USER_TESTS 4
+#define P_APP 0
+#define P_GDB 1
+ struct conn_user {
+ /* u[0] - process uid, u[1] - gdb uid */
+ __uid_t u[P_GDB + 1];
+ /* g[0] - process gid, g[1] - gdb gid */
+ __gid_t g[P_GDB + 1];
+ /* Expected fd from open */
+ int ret;
+ /* Skip this test case */
+ int skip;
+ const char *desc;
+ } test[NUM_USER_TESTS] = {};
+
+ igt_assert(!pipe(p1));
+ igt_assert(!pipe(p2));
+
+ pwd = getpwnam(user1);
+ igt_require(pwd);
+ u1 = pwd->pw_uid;
+ g1 = pwd->pw_gid;
+
+ /*
+ * Keep a copy of needed contents as it is a static
+ * memory area and subsequent calls will overwrite
+ * what's in.
+ * However getpwnam() returns NULL if cannot find
+ * user in passwd.
+ */
+ setpwent();
+ pwd2 = getpwnam(user2);
+ if (pwd2) {
+ u2 = pwd2->pw_uid;
+ g2 = pwd2->pw_gid;
+ }
+
+ test[0].skip = !pwd;
+ test[0].u[P_GDB] = u1;
+ test[0].g[P_GDB] = g1;
+ test[0].ret = -EACCES;
+ test[0].desc = "User GDB to Root App";
+
+ test[1].skip = !pwd;
+ test[1].u[P_APP] = u1;
+ test[1].g[P_APP] = g1;
+ test[1].u[P_GDB] = u1;
+ test[1].g[P_GDB] = g1;
+ test[1].ret = 0;
+ test[1].desc = "User GDB to User App";
+
+ test[2].skip = !pwd;
+ test[2].u[P_APP] = u1;
+ test[2].g[P_APP] = g1;
+ test[2].ret = 0;
+ test[2].desc = "Root GDB to User App";
+
+ test[3].skip = !pwd2;
+ test[3].u[P_APP] = u1;
+ test[3].g[P_APP] = g1;
+ test[3].u[P_GDB] = u2;
+ test[3].g[P_GDB] = g2;
+ test[3].ret = -EACCES;
+ test[3].desc = "User GDB to Other User App";
+
+ if (!pwd2)
+ igt_warn("User %s not available in the system. Skipping subtests: %s.\n",
+ user2, test[3].desc);
+
+ for (i = 0; i < NUM_USER_TESTS; i++) {
+ if (test[i].skip) {
+ igt_debug("Subtest %s skipped\n", test[i].desc);
+ continue;
+ }
+ igt_debug("Executing connection: %s\n", test[i].desc);
+ igt_fork(child, 2) {
+ if (!child) {
+ if (test[i].u[P_APP])
+ switch_user(test[i].u[P_APP], test[i].g[P_APP]);
+
+ pid = getpid();
+ /* Signal the PID */
+ igt_assert(write(p1[1], &pid, sizeof(pid)) == sizeof(pid));
+ /* wait with exit */
+ igt_assert(read(p2[0], &pid, sizeof(pid)) == sizeof(pid));
+ } else {
+ if (test[i].u[P_GDB])
+ switch_user(test[i].u[P_GDB], test[i].g[P_GDB]);
+
+ igt_assert(read(p1[0], &pid, sizeof(pid)) == sizeof(pid));
+ param.pid = pid;
+
+ newfd = drm_open_driver(DRIVER_XE);
+ ret = __debug_connect(newfd, &debugfd, ¶m);
+
+ /* Release the app first */
+ igt_assert(write(p2[1], &pid, sizeof(pid)) == sizeof(pid));
+
+ igt_assert_eq(ret, test[i].ret);
+ if (!ret)
+ close(debugfd);
+ }
+ }
+ igt_waitchildren();
+ }
+ close(p1[0]);
+ close(p1[1]);
+ close(p2[0]);
+ close(p2[1]);
+#undef NUM_USER_TESTS
+#undef P_APP
+#undef P_GDB
+}
+
/**
* SUBTEST: basic-close
* Description:
@@ -1534,6 +1695,9 @@ igt_main
igt_subtest("basic-connect")
test_connect(fd);
+ igt_subtest("connect-user")
+ test_connect_user(fd);
+
igt_subtest("basic-close")
test_close(fd);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 30/66] tests/xe_eudebug: Add discovery-race-vmbind subtest
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (28 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 29/66] tests/xe_eudebug: Added connect-user test Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 31/66] tests/xe_eudebug: Add userptr variant of basic-vm-access test Christoph Manszewski
` (37 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Karolina Stolarek
From: Karolina Stolarek <karolina.stolarek@intel.com>
Extend discovery-race test case with BO creation and vm_bind operation
to verify that all vm_bind_op events are properly registered and
replayed.
Signed-off-by: Karolina Stolarek <karolina.stolarek@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Cc: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
---
tests/intel/xe_eudebug.c | 31 +++++++++++++++++++++++++++++--
1 file changed, 29 insertions(+), 2 deletions(-)
diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
index 8c21cffc7..c368e30e7 100644
--- a/tests/intel/xe_eudebug.c
+++ b/tests/intel/xe_eudebug.c
@@ -917,11 +917,13 @@ static void test_basic_discovery(int fd, unsigned int flags, bool match_opposite
#define PRIMARY_THREAD (1 << 0)
#define DISCOVERY_CLOSE_CLIENT (1 << 1)
#define DISCOVERY_DESTROY_RESOURCES (1 << 2)
+#define DISCOVERY_VM_BIND (1 << 3)
static void run_discovery_client(struct xe_eudebug_client *c)
{
struct drm_xe_engine_class_instance *hwe = NULL;
int fd[RESOURCE_COUNT], i;
bool skip_sleep = c->flags & (DISCOVERY_DESTROY_RESOURCES | DISCOVERY_CLOSE_CLIENT);
+ uint64_t addr = 0x1a0000;
srand(getpid());
@@ -950,18 +952,29 @@ static void run_discovery_client(struct xe_eudebug_client *c)
sleep(1);
for (int j = 0; j < RESOURCE_COUNT; j++) {
+ uint32_t vm = xe_eudebug_client_vm_create(c, fd[i], 0, 0);
struct drm_xe_exec_queue_create create = {
.width = 1,
.num_placements = 1,
- .vm_id = xe_eudebug_client_vm_create(c, fd[i], 0, 0),
+ .vm_id = vm,
.instances = to_user_pointer(hwe)
};
+ const unsigned int bo_size = max_t(bo_size,
+ xe_get_default_alignment(fd[i]),
+ MIN_BO_SIZE);
+ uint32_t bo = xe_bo_create(fd[i], 0, bo_size, system_memory(fd[i]), 0);
xe_eudebug_client_exec_queue_create(c, fd[i], &create);
+ if (c->flags & DISCOVERY_VM_BIND) {
+ xe_eudebug_client_vm_bind(c, fd[i], vm, bo, 0, addr, bo_size);
+ addr += 0x100000;
+ }
+
if (c->flags & DISCOVERY_DESTROY_RESOURCES) {
xe_eudebug_client_exec_queue_destroy(c, fd[i], &create);
xe_eudebug_client_vm_destroy(c, fd[i], create.vm_id);
+ gem_close(fd[i], bo);
}
}
@@ -978,6 +991,7 @@ static void run_discovery_client(struct xe_eudebug_client *c)
* arg[1]:
*
* @race: resources creation
+ * @race-vmbind: vm-bind operations
* @empty: resources destruction
* @empty-clients: client closure
*/
@@ -987,6 +1001,7 @@ static void *discovery_race_thread(void *data)
uint64_t client_handle;
int vm_count;
int exec_queue_count;
+ int vm_bind_op_count;
} clients[RESOURCE_COUNT];
struct xe_eudebug_session *s = data;
int expected = RESOURCE_COUNT * (1 + 2 * RESOURCE_COUNT);
@@ -1024,12 +1039,17 @@ static void *discovery_race_thread(void *data)
igt_assert_eq(clients[i].exec_queue_count,
RESOURCE_COUNT);
+
+ if (s->c->flags & DISCOVERY_VM_BIND)
+ igt_assert_eq(clients[i].vm_bind_op_count,
+ RESOURCE_COUNT);
}
igt_assert(++i < RESOURCE_COUNT);
clients[i].client_handle = eo->client_handle;
clients[i].vm_count = 0;
clients[i].exec_queue_count = 0;
+ clients[i].vm_bind_op_count = 0;
}
if (e->type == DRM_XE_EUDEBUG_EVENT_VM)
@@ -1037,6 +1057,9 @@ static void *discovery_race_thread(void *data)
if (e->type == DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE)
clients[i].exec_queue_count++;
+
+ if (e->type == DRM_XE_EUDEBUG_EVENT_VM_BIND_OP)
+ clients[i].vm_bind_op_count++;
};
igt_assert_lte(0, i);
@@ -1116,7 +1139,8 @@ static void test_race_discovery(int fd, unsigned int flags, int clients)
igt_assert_eq(sessions[i].c->seqno-1, sessions[i].d->event_count);
xe_eudebug_event_log_compare(sessions[0].d->log,
- sessions[i].d->log, 0);
+ sessions[i].d->log,
+ XE_EUDEBUG_FILTER_EVENT_VM_BIND);
xe_eudebug_client_destroy(sessions[i].c);
}
@@ -1755,6 +1779,9 @@ igt_main
igt_subtest("discovery-race")
test_race_discovery(fd, 0, 4);
+ igt_subtest("discovery-race-vmbind")
+ test_race_discovery(fd, DISCOVERY_VM_BIND, 4);
+
igt_subtest("discovery-empty")
test_empty_discovery(fd, DISCOVERY_CLOSE_CLIENT, 16);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 31/66] tests/xe_eudebug: Add userptr variant of basic-vm-access test
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (29 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 30/66] tests/xe_eudebug: Add discovery-race-vmbind subtest Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 32/66] tests/xe_eudebug: Add basic-vm-bind-ufence Christoph Manszewski
` (36 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun
From: Andrzej Hajda <andrzej.hajda@intel.com>
The variant uses DRM_XE_VM_BIND_OP_MAP_USERPTR to bind memory
from userspace.
Signed-off-by: Andrzej Hajda <andrzej.hajda@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
tests/intel/xe_eudebug.c | 103 ++++++++++++++++++++++++++++++---------
1 file changed, 80 insertions(+), 23 deletions(-)
diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
index c368e30e7..1e9f16765 100644
--- a/tests/intel/xe_eudebug.c
+++ b/tests/intel/xe_eudebug.c
@@ -60,6 +60,7 @@ static void test_sysfs_toggle(int fd)
#define VM_BIND_EXTENDED (1 << 4)
#define VM_METADATA (1 << 5)
#define VM_BIND_METADATA (1 << 6)
+#define VM_BIND_OP_MAP_USERPTR (1 << 7)
#define TEST_DISCOVERY (1 << 31)
#define PAGE_SIZE 4096
@@ -166,54 +167,82 @@ static void basic_vm_bind_vm_destroy_client(int fd, struct xe_eudebug_client *c)
#define BO_ITEMS 4096
#define MIN_BO_SIZE (BO_ITEMS * sizeof(uint64_t))
+union buf_id {
+ uint32_t fd;
+ void *userptr;
+};
+
struct bind_list {
int fd;
uint32_t vm;
- uint32_t *bo;
+ union buf_id *bo;
struct drm_xe_vm_bind_op *bind_ops;
unsigned int n;
};
-static void bo_prime(int fd, uint32_t bo, const uint64_t addr, const uint64_t size)
+static void *bo_get_ptr(int fd, struct drm_xe_vm_bind_op *o)
+{
+ void *ptr;
+
+ if (o->op != DRM_XE_VM_BIND_OP_MAP_USERPTR)
+ ptr = xe_bo_map(fd, o->obj, o->range);
+ else
+ ptr = (void *)(uintptr_t)o->userptr;
+
+ igt_assert(ptr);
+
+ return ptr;
+}
+
+static void bo_put_ptr(int fd, struct drm_xe_vm_bind_op *o, void *ptr)
+{
+ if (o->op != DRM_XE_VM_BIND_OP_MAP_USERPTR)
+ munmap(ptr, o->range);
+}
+
+static void bo_prime(int fd, struct drm_xe_vm_bind_op *o)
{
uint64_t *d;
uint64_t i;
- d = xe_bo_map(fd, bo, size);
- igt_assert(d);
+ d = bo_get_ptr(fd, o);
- for (i = 0; i < size/sizeof(*d); i++)
- d[i] = addr + i;
+ for (i = 0; i < o->range / sizeof(*d); i++)
+ d[i] = o->addr + i;
- munmap(d, size);
+ bo_put_ptr(fd, o, d);
}
-static void bo_check(int fd, uint32_t bo, const uint64_t addr, const uint64_t size)
+static void bo_check(int fd, struct drm_xe_vm_bind_op *o)
{
uint64_t *d;
uint64_t i;
- d = xe_bo_map(fd, bo, size);
- igt_assert(d);
+ d = bo_get_ptr(fd, o);
- for (i = 0; i < size/sizeof(*d); i++)
- igt_assert_eq(d[i], addr + i + 1);
+ for (i = 0; i < o->range / sizeof(*d); i++)
+ igt_assert_eq(d[i], o->addr + i + 1);
- munmap(d, size);
+ bo_put_ptr(fd, o, d);
}
-static uint32_t *vm_create_objects(int fd, uint32_t bo_placement, uint32_t vm, unsigned int size,
+static union buf_id *vm_create_objects(int fd, uint32_t bo_placement, uint32_t vm, unsigned int size,
unsigned int n)
{
- uint32_t *bo;
+ union buf_id *bo;
unsigned int i;
bo = calloc(n, sizeof(*bo));
igt_assert(bo);
for (i = 0; i < n; i++) {
- bo[i] = xe_bo_create(fd, vm, size, bo_placement, 0);
- igt_assert(bo[i]);
+ if (bo_placement) {
+ bo[i].fd = xe_bo_create(fd, vm, size, bo_placement, 0);
+ igt_assert(bo[i].fd);
+ } else {
+ bo[i].userptr = aligned_alloc(PAGE_SIZE, size);
+ igt_assert(bo[i].userptr);
+ }
}
return bo;
@@ -223,6 +252,7 @@ static struct bind_list *create_bind_list(int fd, uint32_t bo_placement,
uint32_t vm, unsigned int n)
{
const unsigned int bo_size = max_t(bo_size, xe_get_default_alignment(fd), MIN_BO_SIZE);
+ bool is_userptr = !bo_placement;
struct bind_list *bl;
unsigned int i;
@@ -237,6 +267,16 @@ static struct bind_list *create_bind_list(int fd, uint32_t bo_placement,
for (i = 0; i < n; i++) {
struct drm_xe_vm_bind_op *o = &bl->bind_ops[i];
+ if (is_userptr) {
+ o->obj = 0;
+ o->userptr = (uintptr_t)bl->bo[i].userptr;
+ o->op = DRM_XE_VM_BIND_OP_MAP_USERPTR;
+ } else {
+ o->obj = bl->bo[i].fd;
+ o->obj_offset = 0;
+ o->op = DRM_XE_VM_BIND_OP_MAP;
+ }
+
o->range = bo_size;
o->addr = BO_ADDR + 2 * i * bo_size;
o->flags = 0;
@@ -250,7 +290,7 @@ static struct bind_list *create_bind_list(int fd, uint32_t bo_placement,
struct drm_xe_vm_bind_op *o = &bl->bind_ops[i];
igt_debug("bo %d: addr 0x%llx, range 0x%llx\n", i, o->addr, o->range);
- bo_prime(fd, bl->bo[i], o->addr, o->range);
+ bo_prime(fd, o);
}
return bl;
@@ -277,16 +317,21 @@ static void do_bind_list(struct xe_eudebug_client *c,
igt_assert(syncobj_wait(bl->fd, &sync->handle, 1, INT64_MAX, 0, NULL));
}
-static void check_bind_list(struct bind_list *bl)
+static void free_bind_list(struct bind_list *bl)
{
unsigned int i;
for (i = 0; i < bl->n; i++) {
igt_debug("%d: checking 0x%llx (%lld)\n",
i, bl->bind_ops[i].addr, bl->bind_ops[i].addr);
- bo_check(bl->fd, bl->bo[i], bl->bind_ops[i].addr,
- bl->bind_ops[i].range);
+ bo_check(bl->fd, &bl->bind_ops[i]);
+ if (bl->bind_ops[i].op == DRM_XE_VM_BIND_OP_MAP_USERPTR)
+ free(bl->bo[i].userptr);
}
+
+ free(bl->bind_ops);
+ free(bl->bo);
+ free(bl);
}
static void vm_bind_client(int fd, struct xe_eudebug_client *c)
@@ -1321,6 +1366,7 @@ static void vm_access_client(struct xe_eudebug_client *c)
struct drm_xe_sync sync = {
.flags = DRM_XE_SYNC_TYPE_SYNCOBJ | DRM_XE_SYNC_FLAG_SIGNAL, };
struct drm_xe_engine_class_instance *hwe = c->ptr;
+ uint32_t bo_placement;
struct bind_list *bl;
uint32_t vm;
int fd, i;
@@ -1332,7 +1378,11 @@ static void vm_access_client(struct xe_eudebug_client *c)
vm = xe_eudebug_client_vm_create(c, fd, 0, 0);
- bl = create_bind_list(fd, vram_if_possible(fd, hwe->gt_id), vm, 4);
+ if (c->flags & VM_BIND_OP_MAP_USERPTR)
+ bo_placement = 0;
+ else
+ bo_placement = vram_if_possible(fd, hwe->gt_id);
+ bl = create_bind_list(fd, bo_placement, vm, 4);
sync.handle = syncobj_create(bl->fd, 0);
do_bind_list(c, bl, &sync);
syncobj_destroy(bl->fd, sync.handle);
@@ -1340,7 +1390,7 @@ static void vm_access_client(struct xe_eudebug_client *c)
for (i = 0; i < bl->n; i++)
xe_eudebug_client_wait_stage(c, bl->bind_ops[i].addr);
- check_bind_list(bl);
+ free_bind_list(bl);
xe_eudebug_client_vm_destroy(c, fd, vm);
@@ -1414,6 +1464,10 @@ static void vm_trigger(struct xe_eudebug_debugger *d,
* SUBTEST: basic-vm-access
* Description:
* Exercise XE_EUDEBG_VM_OPEN with pread and pwrite into the vm fd
+ *
+ * SUBTEST: basic-vm-access-userptr
+ * Description:
+ * Exercise XE_EUDEBG_VM_OPEN with pread and pwrite into the vm fd, but backed by userptr
*/
static void test_vm_access(int fd, unsigned int flags, int num_clients)
{
@@ -1737,6 +1791,9 @@ igt_main
igt_subtest("basic-vm-access")
test_vm_access(fd, 0, 1);
+ igt_subtest("basic-vm-access-userptr")
+ test_vm_access(fd, VM_BIND_OP_MAP_USERPTR, 1);
+
igt_subtest("basic-vm-access-parameters")
test_vm_access_parameters(fd, 0, 1);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 32/66] tests/xe_eudebug: Add basic-vm-bind-ufence
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (30 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 31/66] tests/xe_eudebug: Add userptr variant of basic-vm-access test Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 33/66] tests/xe_eudebug: Add multigpu scenarios Christoph Manszewski
` (35 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
Add a basic test to check if ufence will be blocked and released
by debugger ack.
Signed-off-by: Mika Kuoppala <mika.kuoppala@intel.com>
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
tests/intel/xe_eudebug.c | 214 +++++++++++++++++++++++++++++++++++++++
1 file changed, 214 insertions(+)
diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
index 1e9f16765..4bcca4fc6 100644
--- a/tests/intel/xe_eudebug.c
+++ b/tests/intel/xe_eudebug.c
@@ -1757,6 +1757,217 @@ static void test_metadata_attach(int fd, unsigned int flags, int num_clients)
NULL, true, 0);
}
+#define STAGE_CLIENT_WAIT_ON_UFENCE_DONE 1337
+
+#define UFENCE_EVENT_COUNT_EXPECTED 4
+#define UFENCE_EVENT_COUNT_MAX 100
+
+struct ufence_bind {
+ struct drm_xe_sync f;
+ uint64_t addr;
+ uint64_t range;
+ uint64_t value;
+ struct {
+ uint64_t vm_sync;
+ } *fence_data;
+};
+
+static void basic_ufence_client(struct xe_eudebug_client *c)
+{
+ const int64_t default_fence_timeout_ns = MS_TO_NS(500);
+ const unsigned int n = UFENCE_EVENT_COUNT_EXPECTED;
+ int fd = xe_eudebug_client_open_driver(c);
+ uint32_t vm = xe_eudebug_client_vm_create(c, fd, 0, 0);
+ size_t bo_size = n * xe_get_default_alignment(fd);
+ uint32_t bo = xe_bo_create(fd, 0, bo_size,
+ system_memory(fd), 0);
+ struct ufence_bind *binds;
+ int64_t timeout_ns;
+ int err;
+
+ binds = calloc(n, sizeof(*binds));
+ igt_assert(binds);
+
+ for (int i = 0; i < n; i++) {
+ struct ufence_bind *b = &binds[i];
+
+ b->range = 0x1000;
+ b->addr = 0x100000 + b->range * i;
+ b->fence_data = aligned_alloc(xe_get_default_alignment(fd),
+ sizeof(*b->fence_data));
+ igt_assert(b->fence_data);
+ memset(b->fence_data, 0, sizeof(*b->fence_data));
+
+ b->f.type = DRM_XE_SYNC_TYPE_USER_FENCE;
+ b->f.flags = DRM_XE_SYNC_FLAG_SIGNAL;
+ b->f.addr = to_user_pointer(&b->fence_data->vm_sync);
+ b->f.timeline_value = UFENCE_EVENT_COUNT_EXPECTED + i;
+ }
+
+ for (int i = 0; i < n; i++) {
+ struct ufence_bind *b = &binds[i];
+
+ xe_eudebug_client_vm_bind_flags(c, fd, vm, bo, 0, b->addr, b->range, 0,
+ &b->f, 1, 0);
+ }
+
+ /* Ensure that wait on unacked ufence times out */
+ for (int i = 0; i < n; i++) {
+ struct ufence_bind *b = &binds[i];
+
+ timeout_ns = default_fence_timeout_ns;
+ err = __xe_wait_ufence(fd, &b->fence_data->vm_sync, b->f.timeline_value,
+ 0, &timeout_ns);
+ igt_assert_eq(err, -ETIME);
+ igt_assert_neq(b->fence_data->vm_sync, b->f.timeline_value);
+ igt_debug("wait #%d blocked on ack\n", i);
+ }
+
+ /* Wait on fence timed out, now tell the debugger to ack */
+ xe_eudebug_client_signal_stage(c, STAGE_CLIENT_WAIT_ON_UFENCE_DONE);
+
+ /* Check that ack unblocks ufence */
+ for (int i = 0; i < n; i++) {
+ struct ufence_bind *b = &binds[i];
+
+ timeout_ns = MS_TO_NS(XE_EUDEBUG_DEFAULT_TIMEOUT_MS);
+ err = __xe_wait_ufence(fd, &b->fence_data->vm_sync, b->f.timeline_value,
+ 0, &timeout_ns);
+ igt_assert_eq(err, 0);
+ igt_assert_eq(b->fence_data->vm_sync, b->f.timeline_value);
+ igt_debug("wait #%d completed\n", i);
+ }
+
+ for (int i = 0; i < n; i++) {
+ struct ufence_bind *b = &binds[i];
+
+ xe_eudebug_client_vm_unbind(c, fd, vm, 0, b->addr, b->range);
+ }
+
+ free(binds);
+ gem_close(fd, bo);
+ xe_eudebug_client_vm_destroy(c, fd, vm);
+ xe_eudebug_client_close_driver(c, fd);
+}
+
+struct ufence_priv {
+ struct drm_xe_eudebug_event_vm_bind_ufence ufence_events[UFENCE_EVENT_COUNT_MAX];
+ unsigned int ufence_event_count;
+ pthread_mutex_t mutex;
+};
+
+static struct ufence_priv *ufence_priv_create(void)
+{
+ struct ufence_priv *priv;
+
+ priv = mmap(0, ALIGN(sizeof(*priv), PAGE_SIZE),
+ PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
+ igt_assert(priv);
+ memset(priv, 0, sizeof(*priv));
+ pthread_mutex_init(&priv->mutex, NULL);
+
+ return priv;
+}
+
+static void ufence_priv_destroy(struct ufence_priv *priv)
+{
+ munmap(priv, ALIGN(sizeof(*priv), PAGE_SIZE));
+}
+
+static void ack_fences(struct xe_eudebug_debugger *d)
+{
+ struct ufence_priv *priv = d->ptr;
+
+ for (int i = 0; i < priv->ufence_event_count; i++)
+ xe_eudebug_ack_ufence(d->fd, &priv->ufence_events[i]);
+}
+
+static void basic_ufence_trigger(struct xe_eudebug_debugger *d,
+ struct drm_xe_eudebug_event *e)
+{
+ struct drm_xe_eudebug_event_vm_bind_ufence *ef = (void *)e;
+ struct ufence_priv *priv = d->ptr;
+
+ if (e->flags & DRM_XE_EUDEBUG_EVENT_CREATE) {
+ char event_str[XE_EUDEBUG_EVENT_STRING_MAX_LEN];
+ struct drm_xe_eudebug_event_vm_bind *eb;
+
+ xe_eudebug_event_to_str(e, event_str, XE_EUDEBUG_EVENT_STRING_MAX_LEN);
+ igt_debug("ufence event received: %s\n", event_str);
+
+ xe_eudebug_assert_f(d, priv->ufence_event_count < UFENCE_EVENT_COUNT_EXPECTED,
+ "surplus ufence event received: %s\n", event_str);
+ xe_eudebug_assert(d, ef->vm_bind_ref_seqno);
+
+ memcpy(&priv->ufence_events[priv->ufence_event_count++], ef, sizeof(*ef));
+
+ eb = (struct drm_xe_eudebug_event_vm_bind *)
+ xe_eudebug_event_log_find_seqno(d->log, ef->vm_bind_ref_seqno);
+ xe_eudebug_assert_f(d, eb, "vm bind event with seqno (%lld) not found\n",
+ ef->vm_bind_ref_seqno);
+ }
+}
+
+static int wait_for_ufence_events(struct ufence_priv *priv, int timeout_ms)
+{
+ int ret = -ETIMEDOUT;
+
+ igt_for_milliseconds(timeout_ms) {
+ pthread_mutex_lock(&priv->mutex);
+ if (priv->ufence_event_count == UFENCE_EVENT_COUNT_EXPECTED)
+ ret = 0;
+ pthread_mutex_unlock(&priv->mutex);
+
+ if (!ret)
+ break;
+ usleep(1000);
+ }
+
+ return ret;
+}
+
+/**
+ * SUBTEST: basic-vm-bind-ufence
+ * Description:
+ * Give user fence in application and check if ufence ack works
+ */
+static void test_basic_ufence(int fd, unsigned int flags)
+{
+ struct xe_eudebug_debugger *d;
+ struct xe_eudebug_session *s;
+ struct xe_eudebug_client *c;
+ struct ufence_priv *priv;
+
+ priv = ufence_priv_create();
+ s = xe_eudebug_session_create(fd, basic_ufence_client, flags, priv);
+ c = s->c;
+ d = s->d;
+
+ xe_eudebug_debugger_add_trigger(d,
+ DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE,
+ basic_ufence_trigger);
+
+ igt_assert_eq(xe_eudebug_debugger_attach(d, c), 0);
+ xe_eudebug_debugger_start_worker(d);
+ xe_eudebug_client_start(c);
+
+ xe_eudebug_debugger_wait_stage(s, STAGE_CLIENT_WAIT_ON_UFENCE_DONE);
+ xe_eudebug_assert_f(d, wait_for_ufence_events(priv, XE_EUDEBUG_DEFAULT_TIMEOUT_MS) == 0,
+ "missing ufence events\n");
+ ack_fences(d);
+
+ xe_eudebug_client_wait_done(c);
+ xe_eudebug_debugger_stop_worker(d, 1);
+
+ xe_eudebug_event_log_print(d->log, true);
+ xe_eudebug_event_log_print(c->log, true);
+
+ xe_eudebug_session_check(s, true, XE_EUDEBUG_FILTER_EVENT_VM_BIND_UFENCE);
+
+ xe_eudebug_session_destroy(s);
+ ufence_priv_destroy(priv);
+}
+
igt_main
{
bool was_enabled;
@@ -1809,6 +2020,9 @@ igt_main
igt_subtest("basic-vm-bind")
test_basic_sessions(fd, VM_BIND, 1, true);
+ igt_subtest("basic-vm-bind-ufence")
+ test_basic_ufence(fd, 0);
+
igt_subtest("basic-vm-bind-discovery")
test_basic_discovery(fd, VM_BIND, true);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 33/66] tests/xe_eudebug: Add multigpu scenarios
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (31 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 32/66] tests/xe_eudebug: Add basic-vm-bind-ufence Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 34/66] tests/xe_eudebug: Add vm-bind-clear test Christoph Manszewski
` (34 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun
From: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
Add multigpu-basic-client and multigpu-basic-client-many tests,
extending basic-client and multiple-session tests.
Signed-off-by: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
tests/intel/xe_eudebug.c | 62 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 61 insertions(+), 1 deletion(-)
diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
index 4bcca4fc6..1f4bb49af 100644
--- a/tests/intel/xe_eudebug.c
+++ b/tests/intel/xe_eudebug.c
@@ -875,6 +875,15 @@ static void test_read_event(int fd)
* Attach the debugger to a process that performs bind, bind array, rebind,
* partial unbind, unbind and unbind all operations.
*
+ * SUBTEST: multigpu-basic-client
+ * Description:
+ * Attach the debugger to process which opens and closes xe drm client on all Xe devices.
+ *
+ * SUBTEST: multigpu-basic-client-many
+ * Description:
+ * Simultaneously attach many debuggers to many processes on all Xe devices.
+ * Each process opens and closes xe drm client and creates few resources.
+ *
* arg[1]:
*
* @vms: vms
@@ -1971,7 +1980,8 @@ static void test_basic_ufence(int fd, unsigned int flags)
igt_main
{
bool was_enabled;
- int fd;
+ bool *multigpu_was_enabled;
+ int fd, gpu_count;
igt_fixture {
fd = drm_open_driver(DRIVER_XE);
@@ -2063,4 +2073,54 @@ igt_main
xe_eudebug_enable(fd, was_enabled);
drm_close_driver(fd);
}
+
+ igt_subtest_group {
+ igt_fixture {
+ gpu_count = drm_prepare_filtered_multigpu(DRIVER_XE);
+ igt_require(gpu_count >= 2);
+
+ multigpu_was_enabled = malloc(gpu_count * sizeof(bool));
+ igt_assert(multigpu_was_enabled);
+ for (int i = 0; i < gpu_count; i++) {
+ fd = drm_open_filtered_card(i);
+ multigpu_was_enabled[i] = xe_eudebug_enable(fd, true);
+ close(fd);
+ }
+ }
+
+ igt_subtest("multigpu-basic-client") {
+ igt_multi_fork(child, gpu_count) {
+ fd = drm_open_filtered_card(child);
+ igt_assert_f(fd > 0, "cannot open gpu-%d, errno=%d\n",
+ child, errno);
+ igt_assert(is_xe_device(fd));
+
+ test_basic_sessions(fd, 0, 1, true);
+ close(fd);
+ }
+ igt_waitchildren();
+ }
+
+ igt_subtest("multigpu-basic-client-many") {
+ igt_multi_fork(child, gpu_count) {
+ fd = drm_open_filtered_card(child);
+ igt_assert_f(fd > 0, "cannot open gpu-%d, errno=%d\n",
+ child, errno);
+ igt_assert(is_xe_device(fd));
+
+ test_basic_sessions(fd, 0, 4, true);
+ close(fd);
+ }
+ igt_waitchildren();
+ }
+
+ igt_fixture {
+ for (int i = 0; i < gpu_count; i++) {
+ fd = drm_open_filtered_card(i);
+ xe_eudebug_enable(fd, multigpu_was_enabled[i]);
+ close(fd);
+ }
+ free(multigpu_was_enabled);
+ }
+ }
}
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 34/66] tests/xe_eudebug: Add vm-bind-clear test
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (32 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 33/66] tests/xe_eudebug: Add multigpu scenarios Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 35/66] tests/xe_eudebug: Exercise lseek Christoph Manszewski
` (33 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
Port i915_debugger sanity check that fresh buffers we vm_bind into
the ppGTT are always clear.
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
Cc: Pawel Sikora <pawel.sikora@intel.com>
---
tests/intel/xe_eudebug.c | 276 +++++++++++++++++++++++++++++++++++++++
1 file changed, 276 insertions(+)
diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
index 1f4bb49af..edb76685e 100644
--- a/tests/intel/xe_eudebug.c
+++ b/tests/intel/xe_eudebug.c
@@ -1977,6 +1977,279 @@ static void test_basic_ufence(int fd, unsigned int flags)
ufence_priv_destroy(priv);
}
+struct vm_bind_clear_thread_priv {
+ struct drm_xe_engine_class_instance *hwe;
+ struct xe_eudebug_client *c;
+ pthread_t thread;
+ uint64_t region;
+ unsigned long sum;
+};
+
+struct vm_bind_clear_priv {
+ unsigned long unbind_count;
+ unsigned long bind_count;
+ unsigned long sum;
+};
+
+static struct vm_bind_clear_priv *vm_bind_clear_priv_create(void)
+{
+ struct vm_bind_clear_priv *priv;
+
+ priv = mmap(0, ALIGN(sizeof(*priv), PAGE_SIZE),
+ PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
+ igt_assert(priv);
+ memset(priv, 0, sizeof(*priv));
+
+ return priv;
+}
+
+static void vm_bind_clear_priv_destroy(struct vm_bind_clear_priv *priv)
+{
+ munmap(priv, ALIGN(sizeof(*priv), PAGE_SIZE));
+}
+
+static void *vm_bind_clear_thread(void *data)
+{
+ const uint32_t CS_GPR0 = 0x600;
+ const size_t batch_size = 16;
+ struct drm_xe_sync uf_sync = {
+ .type = DRM_XE_SYNC_TYPE_USER_FENCE, .flags = DRM_XE_SYNC_FLAG_SIGNAL,
+ };
+ struct vm_bind_clear_thread_priv *priv = data;
+ int fd = xe_eudebug_client_open_driver(priv->c);
+ uint32_t gtt_size = 1ull << min_t(uint32_t, xe_va_bits(fd), 48);
+ uint32_t vm = xe_eudebug_client_vm_create(priv->c, fd, 0, 0);
+ size_t bo_size = xe_bb_size(fd, batch_size);
+ unsigned long count = 0;
+ uint64_t *fence_data;
+
+ /* init uf_sync */
+ fence_data = aligned_alloc(xe_get_default_alignment(fd), sizeof(*fence_data));
+ igt_assert(fence_data);
+ uf_sync.timeline_value = 1337;
+ uf_sync.addr = to_user_pointer(fence_data);
+
+ igt_debug("Run on: %s%u\n", xe_engine_class_string(priv->hwe->engine_class),
+ priv->hwe->engine_instance);
+
+ igt_until_timeout(5) {
+ struct drm_xe_exec_queue_create eq_create = { 0 };
+ uint32_t clean_bo = 0;
+ uint32_t batch_bo = 0;
+ uint64_t clean_offset, batch_offset;
+ uint32_t exec_queue;
+ uint32_t *map, *cs;
+ uint64_t delta;
+
+ /* calculate offsets (vma addresses) */
+ batch_offset = (random() * SZ_2M) & (gtt_size - 1);
+ /* XXX: for some platforms/memory regions batch offset '0' can be problematic */
+ if (batch_offset == 0)
+ batch_offset = SZ_2M;
+
+ do {
+ clean_offset = (random() * SZ_2M) & (gtt_size - 1);
+ if (clean_offset == 0)
+ clean_offset = SZ_2M;
+ } while (clean_offset == batch_offset);
+
+ batch_offset += random() % SZ_2M & -bo_size;
+ clean_offset += random() % SZ_2M & -bo_size;
+
+ delta = (random() % bo_size) & -4;
+
+ /* prepare clean bo */
+ clean_bo = xe_bo_create(fd, vm, bo_size, priv->region,
+ DRM_XE_GEM_CREATE_FLAG_NEEDS_VISIBLE_VRAM);
+ memset(fence_data, 0, sizeof(*fence_data));
+ xe_eudebug_client_vm_bind_flags(priv->c, fd, vm, clean_bo, 0, clean_offset, bo_size,
+ 0, &uf_sync, 1, 0);
+ xe_wait_ufence(fd, fence_data, uf_sync.timeline_value, 0,
+ MS_TO_NS(XE_EUDEBUG_DEFAULT_TIMEOUT_MS));
+
+ /* prepare batch bo */
+ batch_bo = xe_bo_create(fd, vm, bo_size, priv->region,
+ DRM_XE_GEM_CREATE_FLAG_NEEDS_VISIBLE_VRAM);
+ memset(fence_data, 0, sizeof(*fence_data));
+ xe_eudebug_client_vm_bind_flags(priv->c, fd, vm, batch_bo, 0, batch_offset, bo_size,
+ 0, &uf_sync, 1, 0);
+ xe_wait_ufence(fd, fence_data, uf_sync.timeline_value, 0,
+ MS_TO_NS(XE_EUDEBUG_DEFAULT_TIMEOUT_MS));
+
+ map = xe_bo_map(fd, batch_bo, bo_size);
+
+ cs = map;
+ *cs++ = MI_NOOP | 0xc5a3;
+ *cs++ = MI_LOAD_REGISTER_MEM_CMD | MI_LRI_LRM_CS_MMIO | 2;
+ *cs++ = CS_GPR0;
+ *cs++ = clean_offset + delta;
+ *cs++ = (clean_offset + delta) >> 32;
+ *cs++ = MI_STORE_REGISTER_MEM_CMD | MI_LRI_LRM_CS_MMIO | 2;
+ *cs++ = CS_GPR0;
+ *cs++ = batch_offset;
+ *cs++ = batch_offset >> 32;
+ *cs++ = MI_BATCH_BUFFER_END;
+
+ /* execute batch */
+ eq_create.width = 1;
+ eq_create.num_placements = 1;
+ eq_create.vm_id = vm;
+ eq_create.instances = to_user_pointer(priv->hwe);
+ exec_queue = xe_eudebug_client_exec_queue_create(priv->c, fd, &eq_create);
+ xe_exec_wait(fd, exec_queue, batch_offset);
+
+ igt_assert_eq(*map, 0);
+
+ /* cleanup */
+ xe_eudebug_client_exec_queue_destroy(priv->c, fd, &eq_create);
+ munmap(map, bo_size);
+
+ xe_eudebug_client_vm_unbind(priv->c, fd, vm, 0, batch_offset, bo_size);
+ gem_close(fd, batch_bo);
+
+ xe_eudebug_client_vm_unbind(priv->c, fd, vm, 0, clean_offset, bo_size);
+ gem_close(fd, clean_bo);
+
+ count++;
+ }
+
+ priv->sum = count;
+
+ free(fence_data);
+ xe_eudebug_client_close_driver(priv->c, fd);
+ return NULL;
+}
+
+static void vm_bind_clear_client(struct xe_eudebug_client *c)
+{
+ int fd = xe_eudebug_client_open_driver(c);
+ struct xe_device *xe_dev = xe_device_get(fd);
+ int count = xe_number_engines(fd) * xe_dev->mem_regions->num_mem_regions;
+ uint64_t memreg = all_memory_regions(fd);
+ struct vm_bind_clear_priv *priv = c->ptr;
+ int current = 0;
+ struct drm_xe_engine_class_instance *engine;
+ struct vm_bind_clear_thread_priv *threads;
+ uint64_t region;
+
+ threads = calloc(count, sizeof(*threads));
+ igt_assert(threads);
+ priv->sum = 0;
+
+ xe_for_each_mem_region(fd, memreg, region) {
+ xe_for_each_engine(fd, engine) {
+ threads[current].c = c;
+ threads[current].hwe = engine;
+ threads[current].region = region;
+
+ pthread_create(&threads[current].thread, NULL,
+ vm_bind_clear_thread, &threads[current]);
+ current++;
+ }
+ }
+
+ for (current = 0; current < count; current++)
+ pthread_join(threads[current].thread, NULL);
+
+ xe_for_each_mem_region(fd, memreg, region) {
+ unsigned long sum = 0;
+
+ for (current = 0; current < count; current++)
+ if (threads[current].region == region)
+ sum += threads[current].sum;
+
+ igt_info("%s sampled %lu objects\n", xe_region_name(region), sum);
+ priv->sum += sum;
+ }
+
+ free(threads);
+ xe_device_put(fd);
+ xe_eudebug_client_close_driver(c, fd);
+}
+
+static void vm_bind_clear_test_trigger(struct xe_eudebug_debugger *d,
+ struct drm_xe_eudebug_event *e)
+{
+ struct drm_xe_eudebug_event_vm_bind_op *eo = (void *)e;
+ struct vm_bind_clear_priv *priv = d->ptr;
+
+ if (e->flags & DRM_XE_EUDEBUG_EVENT_CREATE) {
+ if (random() & 1) {
+ struct drm_xe_eudebug_vm_open vo = { 0, };
+ uint32_t v = 0xc1c1c1c1;
+
+ struct drm_xe_eudebug_event_vm_bind *eb;
+ int fd, delta, r;
+
+ igt_debug("vm bind op event received with ref %lld, addr 0x%llx, range 0x%llx\n",
+ eo->vm_bind_ref_seqno,
+ eo->addr,
+ eo->range);
+
+ eb = (struct drm_xe_eudebug_event_vm_bind *)
+ xe_eudebug_event_log_find_seqno(d->log, eo->vm_bind_ref_seqno);
+ igt_assert(eb);
+
+ vo.client_handle = eb->client_handle;
+ vo.vm_handle = eb->vm_handle;
+
+ fd = igt_ioctl(d->fd, DRM_XE_EUDEBUG_IOCTL_VM_OPEN, &vo);
+ igt_assert_lte(0, fd);
+
+ delta = (random() % eo->range) & -4;
+ r = pread(fd, &v, sizeof(v), eo->addr + delta);
+ igt_assert_eq(r, sizeof(v));
+ igt_assert_eq_u32(v, 0);
+
+ close(fd);
+ }
+ priv->bind_count++;
+ }
+
+ if (e->flags & DRM_XE_EUDEBUG_EVENT_DESTROY)
+ priv->unbind_count++;
+}
+
+static void vm_bind_clear_ack_trigger(struct xe_eudebug_debugger *d,
+ struct drm_xe_eudebug_event *e)
+{
+ struct drm_xe_eudebug_event_vm_bind_ufence *ef = (void *)e;
+
+ xe_eudebug_ack_ufence(d->fd, ef);
+}
+
+/**
+ * SUBTEST: vm-bind-clear
+ * Description:
+ * Check that fresh buffers we vm_bind into the ppGTT are always clear.
+ */
+static void test_vm_bind_clear(int fd)
+{
+ struct vm_bind_clear_priv *priv;
+ struct xe_eudebug_session *s;
+
+ priv = vm_bind_clear_priv_create();
+ s = xe_eudebug_session_create(fd, vm_bind_clear_client, 0, priv);
+
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_VM_BIND_OP,
+ vm_bind_clear_test_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE,
+ vm_bind_clear_ack_trigger);
+
+ igt_assert_eq(xe_eudebug_debugger_attach(s->d, s->c), 0);
+ xe_eudebug_debugger_start_worker(s->d);
+ xe_eudebug_client_start(s->c);
+
+ xe_eudebug_client_wait_done(s->c);
+ xe_eudebug_debugger_stop_worker(s->d, 1);
+
+ igt_assert_eq(priv->bind_count, priv->unbind_count);
+ igt_assert_eq(priv->sum * 2, priv->bind_count);
+
+ xe_eudebug_session_destroy(s);
+ vm_bind_clear_priv_destroy(priv);
+}
+
igt_main
{
bool was_enabled;
@@ -2033,6 +2306,9 @@ igt_main
igt_subtest("basic-vm-bind-ufence")
test_basic_ufence(fd, 0);
+ igt_subtest("vm-bind-clear")
+ test_vm_bind_clear(fd);
+
igt_subtest("basic-vm-bind-discovery")
test_basic_discovery(fd, VM_BIND, true);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 35/66] tests/xe_eudebug: Exercise lseek
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (33 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 34/66] tests/xe_eudebug: Add vm-bind-clear test Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 36/66] tests/xe_eudebug: Test multiple bo sizes Christoph Manszewski
` (32 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Jonathan Cavitt, Christoph Manszewski
From: Jonathan Cavitt <jonathan.cavitt@intel.com>
Add an additional check in debugger_test_vma that simultaneously
exercises lseek support and also that pwrite successfully wrote the
new buffer contents to the vma via pwrite.
Suggested-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Signed-off-by: Jonathan Cavitt <jonathan.cavitt@intel.com>
Cc: Christoph Manszewski <christoph.manszewski@intel.com>
---
tests/intel/xe_eudebug.c | 26 ++++++++++++++++++--------
1 file changed, 18 insertions(+), 8 deletions(-)
diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
index edb76685e..928dcdce4 100644
--- a/tests/intel/xe_eudebug.c
+++ b/tests/intel/xe_eudebug.c
@@ -1414,13 +1414,15 @@ static void debugger_test_vma(struct xe_eudebug_debugger *d,
uint64_t va_length)
{
struct drm_xe_eudebug_vm_open vo = { 0, };
- uint64_t *v;
+ uint64_t *v1, *v2;
uint64_t items = va_length / sizeof(uint64_t);
int fd;
int r, i;
- v = malloc(va_length);
- igt_assert(v);
+ v1 = malloc(va_length);
+ igt_assert(v1);
+ v2 = malloc(va_length);
+ igt_assert(v2);
vo.client_handle = client_handle;
vo.vm_handle = vm_handle;
@@ -1428,22 +1430,30 @@ static void debugger_test_vma(struct xe_eudebug_debugger *d,
fd = igt_ioctl(d->fd, DRM_XE_EUDEBUG_IOCTL_VM_OPEN, &vo);
igt_assert_lte(0, fd);
- r = pread(fd, v, va_length, va_start);
+ r = pread(fd, v1, va_length, va_start);
igt_assert_eq(r, va_length);
for (i = 0; i < items; i++)
- igt_assert_eq(v[i], va_start + i);
+ igt_assert_eq(v1[i], va_start + i);
for (i = 0; i < items; i++)
- v[i] = va_start + i + 1;
+ v1[i] = va_start + i + 1;
- r = pwrite(fd, v, va_length, va_start);
+ r = pwrite(fd, v1, va_length, va_start);
+ igt_assert_eq(r, va_length);
+
+ lseek(fd, va_start, SEEK_SET);
+ r = read(fd, v2, va_length);
igt_assert_eq(r, va_length);
+ for (i = 0; i < items; i++)
+ igt_assert_eq(v1[i], v2[i]);
+
fsync(fd);
close(fd);
- free(v);
+ free(v1);
+ free(v2);
}
static void vm_trigger(struct xe_eudebug_debugger *d,
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 36/66] tests/xe_eudebug: Test multiple bo sizes
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (34 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 35/66] tests/xe_eudebug: Exercise lseek Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 37/66] lib/gpgpu_shader: Extend shader building library Christoph Manszewski
` (31 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Jonathan Cavitt, Christoph Manszewski
From: Jonathan Cavitt <jonathan.cavitt@intel.com>
Extend the basic vm access tests to allow for specifying the target bo
size per bo in the bind list. The size still has to be at least the
minimum, but can be overwritten to be larger.
Make sure that the vm is unbound during bind list destroy, to avoid
overlapping vmas.
Suggested-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Signed-off-by: Jonathan Cavitt <jonathan.cavitt@intel.com>
Cc: Christoph Manszewski <christoph.manszewski@intel.com>
---
tests/intel/xe_eudebug.c | 45 ++++++++++++++++++++++++++--------------
1 file changed, 29 insertions(+), 16 deletions(-)
diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
index 928dcdce4..db6d96a92 100644
--- a/tests/intel/xe_eudebug.c
+++ b/tests/intel/xe_eudebug.c
@@ -249,12 +249,13 @@ static union buf_id *vm_create_objects(int fd, uint32_t bo_placement, uint32_t v
}
static struct bind_list *create_bind_list(int fd, uint32_t bo_placement,
- uint32_t vm, unsigned int n)
+ uint32_t vm, unsigned int n,
+ unsigned int target_size)
{
- const unsigned int bo_size = max_t(bo_size, xe_get_default_alignment(fd), MIN_BO_SIZE);
+ unsigned int i = target_size ?: MIN_BO_SIZE;
+ const unsigned int bo_size = max_t(bo_size, xe_get_default_alignment(fd), i);
bool is_userptr = !bo_placement;
struct bind_list *bl;
- unsigned int i;
bl = malloc(sizeof(*bl));
bl->fd = fd;
@@ -317,7 +318,7 @@ static void do_bind_list(struct xe_eudebug_client *c,
igt_assert(syncobj_wait(bl->fd, &sync->handle, 1, INT64_MAX, 0, NULL));
}
-static void free_bind_list(struct bind_list *bl)
+static void free_bind_list(struct xe_eudebug_client *c, struct bind_list *bl)
{
unsigned int i;
@@ -327,6 +328,9 @@ static void free_bind_list(struct bind_list *bl)
bo_check(bl->fd, &bl->bind_ops[i]);
if (bl->bind_ops[i].op == DRM_XE_VM_BIND_OP_MAP_USERPTR)
free(bl->bo[i].userptr);
+ xe_eudebug_client_vm_unbind(c, bl->fd, bl->vm, 0,
+ bl->bind_ops[i].addr,
+ bl->bind_ops[i].range);
}
free(bl->bind_ops);
@@ -359,7 +363,7 @@ static void vm_bind_client(int fd, struct xe_eudebug_client *c)
xe_vm_bind_async(fd, vm, 0, bo[1], rebind_bo_offset, addr[1], size, NULL, 0);
- bl = create_bind_list(fd, system_memory(fd), vm, 4);
+ bl = create_bind_list(fd, system_memory(fd), vm, 4, 0);
xe_vm_bind_array(bl->fd, bl->vm, 0, bl->bind_ops, bl->n, NULL, 0);
xe_vm_unbind_all_async(fd, vm, 0, bo[0], NULL, 0);
@@ -387,7 +391,7 @@ static void vm_bind_client(int fd, struct xe_eudebug_client *c)
xe_eudebug_client_vm_bind(c, fd, vm, bo[1], 0, addr[1], bo_size);
xe_eudebug_client_vm_bind(c, fd, vm, bo[1], rebind_bo_offset, addr[1], size);
- bl = create_bind_list(fd, system_memory(fd), vm, 4);
+ bl = create_bind_list(fd, system_memory(fd), vm, 4, 0);
do_bind_list(c, bl, NULL);
}
@@ -1378,7 +1382,7 @@ static void vm_access_client(struct xe_eudebug_client *c)
uint32_t bo_placement;
struct bind_list *bl;
uint32_t vm;
- int fd, i;
+ int fd, i, j;
igt_debug("Using %s\n", xe_engine_class_string(hwe->engine_class));
@@ -1391,16 +1395,20 @@ static void vm_access_client(struct xe_eudebug_client *c)
bo_placement = 0;
else
bo_placement = vram_if_possible(fd, hwe->gt_id);
- bl = create_bind_list(fd, bo_placement, vm, 4);
- sync.handle = syncobj_create(bl->fd, 0);
- do_bind_list(c, bl, &sync);
- syncobj_destroy(bl->fd, sync.handle);
- for (i = 0; i < bl->n; i++)
- xe_eudebug_client_wait_stage(c, bl->bind_ops[i].addr);
+ for (j = 0; j < 5; j++) {
+ unsigned int target_size = MIN_BO_SIZE * (1 << j);
- free_bind_list(bl);
+ bl = create_bind_list(fd, bo_placement, vm, 4, target_size);
+ sync.handle = syncobj_create(bl->fd, 0);
+ do_bind_list(c, bl, &sync);
+ syncobj_destroy(bl->fd, sync.handle);
+ for (i = 0; i < bl->n; i++)
+ xe_eudebug_client_wait_stage(c, bl->bind_ops[i].addr);
+
+ free_bind_list(c, bl);
+ }
xe_eudebug_client_vm_destroy(c, fd, vm);
xe_device_put(fd);
@@ -1482,11 +1490,16 @@ static void vm_trigger(struct xe_eudebug_debugger *d,
/**
* SUBTEST: basic-vm-access
* Description:
- * Exercise XE_EUDEBG_VM_OPEN with pread and pwrite into the vm fd
+ * Exercise XE_EUDEBG_VM_OPEN with pread and pwrite into the
+ * vm fd, concerning many different offsets inside the vm,
+ * and many virtual addresses of the vm_bound object.
*
* SUBTEST: basic-vm-access-userptr
* Description:
- * Exercise XE_EUDEBG_VM_OPEN with pread and pwrite into the vm fd, but backed by userptr
+ * Exercise XE_EUDEBG_VM_OPEN with pread and pwrite into the
+ * vm fd, concerning many different offsets inside the vm,
+ * and many virtual addresses of the vm_bound object, but backed
+ * by userptr.
*/
static void test_vm_access(int fd, unsigned int flags, int num_clients)
{
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 37/66] lib/gpgpu_shader: Extend shader building library
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (35 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 36/66] tests/xe_eudebug: Test multiple bo sizes Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 38/66] tests/xe_exec_sip: Port tests for shaders and sip Christoph Manszewski
` (30 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
Add shader building functions and iga64 code used by eudebug subtests.
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
Signed-off-by: Andrzej Hajda <andrzej.hajda@intel.com>
Signed-off-by: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
lib/gpgpu_shader.c | 386 +++++++++++++++++++++++++++++++++++-
lib/gpgpu_shader.h | 24 ++-
lib/iga64_generated_codes.c | 321 +++++++++++++++++++++++++++++-
3 files changed, 727 insertions(+), 4 deletions(-)
diff --git a/lib/gpgpu_shader.c b/lib/gpgpu_shader.c
index 991455c49..3b16db593 100644
--- a/lib/gpgpu_shader.c
+++ b/lib/gpgpu_shader.c
@@ -7,10 +7,16 @@
#include <i915_drm.h>
+#include "igt_map.h"
#include "ioctl_wrappers.h"
#include "gpgpu_shader.h"
#include "gpu_cmds.h"
+struct label_entry {
+ uint32_t id;
+ uint32_t offset;
+};
+
#define IGA64_ARG0 0xc0ded000
#define IGA64_ARG_MASK 0xffffff00
@@ -32,7 +38,7 @@ static void gpgpu_shader_extend(struct gpgpu_shader *shdr)
igt_assert(shdr->code);
}
-void
+uint32_t
__emit_iga64_code(struct gpgpu_shader *shdr, struct iga64_template const *tpls,
int argc, uint32_t *argv)
{
@@ -60,6 +66,8 @@ __emit_iga64_code(struct gpgpu_shader *shdr, struct iga64_template const *tpls,
}
shdr->size += tpls->size;
+
+ return tpls->size;
}
static uint32_t fill_sip(struct intel_bb *ibb,
@@ -235,6 +243,7 @@ struct gpgpu_shader *gpgpu_shader_create(int fd)
shdr->gen_ver = 100 * info->graphics_ver + info->graphics_rel;
shdr->max_size = 16 * 4;
shdr->code = malloc(4 * shdr->max_size);
+ shdr->labels = igt_map_create(igt_map_hash_32, igt_map_equal_32);
igt_assert(shdr->code);
return shdr;
}
@@ -251,6 +260,70 @@ void gpgpu_shader_destroy(struct gpgpu_shader *shdr)
free(shdr);
}
+/**
+ * gpgpu_shader_dump:
+ * @shdr: shader to be printed
+ *
+ * Print shader instructions from @shdr in hex.
+ */
+void gpgpu_shader_dump(struct gpgpu_shader *shdr)
+{
+ for (int i = 0; i < shdr->size / 4; i++)
+ igt_info("0x%08x 0x%08x 0x%08x 0x%08x\n",
+ shdr->instr[i][0], shdr->instr[i][1],
+ shdr->instr[i][2], shdr->instr[i][3]);
+}
+
+/**
+ * gpgpu_shader__breakpoint_on:
+ * @shdr: shader to create breakpoint in
+ * @cmd_no: index of the instruction to break on
+ *
+ * Insert a breakpoint on the @cmd_no'th instruction within @shdr.
+ */
+void gpgpu_shader__breakpoint_on(struct gpgpu_shader *shdr, uint32_t cmd_no)
+{
+ shdr->instr[cmd_no][0] |= 1<<30;
+}
+
+/**
+ * gpgpu_shader__breakpoint:
+ * @shdr: shader to create breakpoint in
+ *
+ * Insert a breakpoint on the last instruction in @shdr.
+ */
+void gpgpu_shader__breakpoint(struct gpgpu_shader *shdr)
+{
+ gpgpu_shader__breakpoint_on(shdr, shdr->size / 4 - 1);
+}
+
+/**
+ * gpgpu_shader__wait:
+ * @shdr: shader to be modified
+ *
+ * Append wait instruction to @shader. This instruction raises attention
+ * and stops execution.
+ */
+void gpgpu_shader__wait(struct gpgpu_shader *shdr)
+{
+ emit_iga64_code(shdr, sync_host, " \n\
+(W) sync.host null \n\
+ ");
+}
+
+/**
+ * gpgpu_shader__nop:
+ * @shdr: shader to be modified
+ *
+ * Append a no-op instruction to @shdr.
+ */
+void gpgpu_shader__nop(struct gpgpu_shader *shdr)
+{
+ emit_iga64_code(shdr, nop, " \n\
+(W) nop \n\
+ ");
+}
+
/**
* gpgpu_shader__eot:
* @shdr: shader to be modified
@@ -269,6 +342,247 @@ void gpgpu_shader__eot(struct gpgpu_shader *shdr)
");
}
+/**
+ * gpgpu_shader__label:
+ * @shdr: shader to be modified
+ * @label_id: id of the label to be created
+ *
+ * Create a label for the last instruction within @shdr.
+ */
+void gpgpu_shader__label(struct gpgpu_shader *shdr, int label_id)
+{
+ struct label_entry *l = malloc(sizeof(*l));
+
+ l->id = label_id;
+ l->offset = shdr->size;
+ igt_map_insert(shdr->labels, &l->id, l);
+}
+
+#define OPCODE(x) (x & 0x7f)
+#define OPCODE_JUMP_INDEXED 0x20
+static void __patch_indexed_jump(struct gpgpu_shader *shdr, int label_id,
+ uint32_t jump_iga64_size)
+{
+ struct label_entry *l;
+ uint32_t *start, *end, *label;
+ int32_t relative;
+
+ l = igt_map_search(shdr->labels, &label_id);
+ igt_assert(l);
+
+ igt_assert(jump_iga64_size % 4 == 0);
+
+ label = shdr->code + l->offset;
+ end = shdr->code + shdr->size;
+ start = end - jump_iga64_size;
+
+ for (; start < end; start += 4)
+ if (OPCODE(*start) == OPCODE_JUMP_INDEXED) {
+ relative = (label - start) * 4;
+ *(start + 3) = relative;
+ break;
+ }
+}
+
+/**
+ * gpgpu_shader__jump:
+ * @shdr: shader to be modified
+ * @label_id: label to jump to
+ *
+ * Append jump instruction to @shdr. Jump to instruction with label @label_id.
+ */
+void gpgpu_shader__jump(struct gpgpu_shader *shdr, int label_id)
+{
+ size_t shader_size;
+
+ shader_size = emit_iga64_code(shdr, jump, " \n\
+L0: \n\
+(W) jmpi L0 \n\
+ ");
+
+ __patch_indexed_jump(shdr, label_id, shader_size);
+}
+
+/**
+ * gpgpu_shader__jump_neq:
+ * @shdr: shader to be modified
+ * @label_id: label to jump to
+ * @y_offset: offset within target buffer in rows
+ * @value: expected value
+ *
+ * Append jump instruction to @shdr. Jump to instruction with label @label_id
+ * when @value is not equal to dword stored at @dw_offset within the surface.
+ *
+ * Note: @dw_offset has to be aligned to 4
+ */
+void gpgpu_shader__jump_neq(struct gpgpu_shader *shdr, int label_id,
+ uint32_t y_offset, uint32_t value)
+{
+ uint32_t size;
+
+ size = emit_iga64_code(shdr, jump_dw_neq, " \n\
+L0: \n\
+(W) mov (16|M0) r30.0<1>:ud 0x0:ud \n\
+#if GEN_VER < 2000 // Media Block Write \n\
+ // Y offset of the block in rows := thread group id Y \n\
+(W) mov (1|M0) r30.1<1>:ud ARG(0):ud \n\
+ // block width [0,63] representing 1 to 64 bytes, we want dword \n\
+(W) mov (1|M0) r30.2<1>:ud 0x3:ud \n\
+ // FFTID := FFTID from R0 header \n\
+(W) mov (1|M0) r30.4<1>:ud r0.5<0;1,0>:ud \n\
+(W) send.dc1 (16|M0) r31 r30 null 0x0 0x2190000 \n\
+#else // Typed 2D Block Store \n\
+ // Store X and Y block start (160:191 and 192:223) \n\
+(W) mov (2|M0) r30.6<1>:ud ARG(0):ud \n\
+ // Store X and Y block size (224:231 and 232:239) \n\
+(W) mov (1|M0) r30.7<1>:ud 0x3:ud \n\
+(W) send.tgm (16|M0) r31 r30 null:0 0x0 0x62100003 \n\
+#endif \n\
+ // clear the flag register \n\
+(W) mov (1|M0) f0.0<1>:ud 0x0:ud \n\
+(W) cmp (1|M0) (ne)f0.0 null<1>:ud r31.0<0;1,0>:ud ARG(1):ud \n\
+(W&f0.0) jmpi L0 \n\
+ ", y_offset, value);
+
+ __patch_indexed_jump(shdr, label_id, size);
+}
+
+/**
+ * gpgpu_shader__loop_begin:
+ * @shdr: shader to be modified
+ * @label_id: id of the label to be created
+ *
+ * Begin a counting loop in @shdr. All subsequent instructions will constitute
+ * the loop body up until 'gpgpu_shader__loop_end' gets called. The first
+ * instruction of the loop will be at label @label_id.
+ */
+void gpgpu_shader__loop_begin(struct gpgpu_shader *shdr, int label_id)
+{
+ emit_iga64_code(shdr, clear_r40, " \n\
+L0: \n\
+(W) mov (1|M0) r40:ud 0x0:ud \n\
+ ");
+
+ gpgpu_shader__label(shdr, label_id);
+}
+
+/**
+ * gpgpu_shader__loop_end:
+ * @shdr: shader to be modified
+ * @label_id: label id passed to 'gpgpu_shader__loop_begin'
+ * @iter: iteration count
+ *
+ * End loop body in @shdr.
+ */
+void gpgpu_shader__loop_end(struct gpgpu_shader *shdr, int label_id, uint32_t iter)
+{
+ uint32_t size;
+
+ size = emit_iga64_code(shdr, inc_r40_jump_neq, " \n\
+L0: \n\
+(W) add (1|M0) r40:ud r40.0<0;1,0>:ud 0x1:ud \n\
+(W) mov (1|M0) f0.0<1>:ud 0x0:ud \n\
+(W) cmp (1|M0) (ne)f0.0 null<1>:ud r40.0<0;1,0>:ud ARG(0):ud \n\
+(W&f0.0) jmpi L0 \n\
+ ", iter);
+
+ __patch_indexed_jump(shdr, label_id, size);
+}
+
+/**
+ * gpgpu_shader__common_target_write:
+ * @shdr: shader to be modified
+ * @y_offset: write target offset within target buffer in rows
+ * @value: oword to be written
+ *
+ * Write the oword stored in @value to the target buffer at @y_offset.
+ */
+void gpgpu_shader__common_target_write(struct gpgpu_shader *shdr,
+ uint32_t y_offset, const uint32_t value[4])
+{
+ emit_iga64_code(shdr, common_target_write, " \n\
+(W) mov (16|M0) r31.0<1>:ud 0x0:ud \n\
+(W) mov (1|M0) r31.0<1>:ud ARG(1):ud \n\
+(W) mov (1|M0) r31.1<1>:ud ARG(2):ud \n\
+(W) mov (1|M0) r31.2<1>:ud ARG(3):ud \n\
+(W) mov (1|M0) r31.3<1>:ud ARG(4):ud \n\
+(W) mov (16|M0) r30.0<1>:ud 0x0:ud \n\
+#if GEN_VER < 2000 // Media Block Write \n\
+ // Y offset of the block in rows \n\
+(W) mov (1|M0) r30.1<1>:ud ARG(0):ud \n\
+ // block width [0,63] representing 1 to 64 bytes \n\
+(W) mov (1|M0) r30.2<1>:ud 0xf:ud \n\
+ // FFTID := FFTID from R0 header \n\
+(W) mov (1|M0) r30.4<1>:ud r0.5<0;1,0>:ud \n\
+ // written value \n\
+(W) send.dc1 (16|M0) null r30 src1_null 0x0 0x40A8000 \n\
+#else // Typed 2D Block Store \n\
+ // Store X and Y block start (160:191 and 192:223) \n\
+(W) mov (2|M0) r30.6<1>:ud ARG(0):ud \n\
+ // Store X and Y block size (224:231 and 232:239) \n\
+(W) mov (1|M0) r30.7<1>:ud 0xf:ud \n\
+(W) send.tgm (16|M0) null r30 null:0 0x0 0x64000007 \n\
+#endif \n\
+ ", y_offset, value[0], value[1], value[2], value[3]);
+}
+
+/**
+ * gpgpu_shader__common_target_write_u32:
+ * @shdr: shader to be modified
+ * @y_offset: write target offset within target buffer in rows
+ * @value: dword to be written
+ *
+ * Fill oword at @y_offset with dword stored in @value.
+ */
+void gpgpu_shader__common_target_write_u32(struct gpgpu_shader *shdr,
+ uint32_t y_offset, uint32_t value)
+{
+ const uint32_t owblock[4] = {
+ value, value, value, value
+ };
+ gpgpu_shader__common_target_write(shdr, y_offset, owblock);
+}
+
+/**
+ * gpgpu_shader__write_aip:
+ * @shdr: shader to be modified
+ * @y_offset: write target offset within the surface in rows
+ *
+ * Write address instruction pointer to row tg_id_y + @y_offset.
+ */
+void gpgpu_shader__write_aip(struct gpgpu_shader *shdr, uint32_t y_offset)
+{
+ emit_iga64_code(shdr, media_block_write_aip, " \n\
+ // Payload \n\
+(W) mov (1|M0) r5.0<1>:ud cr0.2:ud \n\
+#if GEN_VER < 2000 // Media Block Write \n\
+ // X offset of the block in bytes := (thread group id X << ARG(0)) \n\
+(W) shl (1|M0) r4.0<1>:ud r0.1<0;1,0>:ud 0x2:ud \n\
+ // Y offset of the block in rows := thread group id Y \n\
+(W) mov (1|M0) r4.1<1>:ud r0.6<0;1,0>:ud \n\
+(W) add (1|M0) r4.1<1>:ud r4.1<0;1,0>:ud ARG(0):ud \n\
+ // block width [0,63] representing 1 to 64 bytes \n\
+(W) mov (1|M0) r4.2<1>:ud 0x3:ud \n\
+ // FFTID := FFTID from R0 header \n\
+(W) mov (1|M0) r4.4<1>:ud r0.5<0;1,0>:ud \n\
+(W) send.dc1 (16|M0) null r4 src1_null 0 0x40A8000 \n\
+#else // Typed 2D Block Store \n\
+ // Load r2.0-3 with tg id X << ARG(0) \n\
+(W) shl (1|M0) r2.0<1>:ud r0.1<0;1,0>:ud 0x2:ud \n\
+ // Load r2.4-7 with tg id Y + ARG(1):ud \n\
+(W) mov (1|M0) r2.1<1>:ud r0.6<0;1,0>:ud \n\
+(W) add (1|M0) r2.1<1>:ud r2.1<0;1,0>:ud ARG(0):ud \n\
+ // payload setup \n\
+(W) mov (16|M0) r4.0<1>:ud 0x0:ud \n\
+ // Store X and Y block start (160:191 and 192:223) \n\
+(W) mov (2|M0) r4.5<1>:ud r2.0<2;2,1>:ud \n\
+ // Store X and Y block max_size (224:231 and 232:239) \n\
+(W) mov (1|M0) r4.7<1>:ud 0x3:ud \n\
+(W) send.tgm (16|M0) null r4 null:0 0 0x64000007 \n\
+#endif \n\
+ ", y_offset);
+}
+
/**
* gpgpu_shader__write_dword:
* @shdr: shader to be modified
@@ -313,3 +627,73 @@ void gpgpu_shader__write_dword(struct gpgpu_shader *shdr, uint32_t value,
#endif \n\
", 2, y_offset, 3, value, value, value, value);
}
+
+/**
+ * gpgpu_shader__end_system_routine:
+ * @shdr: shader to be modified
+ * @breakpoint_suppress: breakpoint suppress flag
+ *
+ * Return from system routine. To prevent infinite jumping to the system
+ * routine on a breakpoint, @breakpoint_suppres flag has to be set.
+ */
+void gpgpu_shader__end_system_routine(struct gpgpu_shader *shdr,
+ bool breakpoint_suppress)
+{
+ /*
+ * set breakpoint suppress bit to avoid an endless loop
+ * when sip was invoked by a breakpoint
+ */
+ if (breakpoint_suppress)
+ emit_iga64_code(shdr, breakpoint_suppress, " \n\
+(W) or (1|M0) cr0.0<1>:ud cr0.0<0;1,0>:ud 0x8000:ud \n\
+ ");
+
+ emit_iga64_code(shdr, end_system_routine, " \n\
+(W) and (1|M0) cr0.1<1>:ud cr0.1<0;1,0>:ud ARG(0):ud \n\
+ // return to an application \n\
+(W) and (1|M0) cr0.0<1>:ud cr0.0<0;1,0>:ud 0x7FFFFFFD:ud \n\
+ ", 0x7fffff | (1 << 26)); /* clear all exceptions, except read only bit */
+}
+
+/**
+ * gpgpu_shader__end_system_routine_step_if_eq:
+ * @shdr: shader to be modified
+ * @y_offset: offset within target buffer in rows
+ * @value: expected value for single stepping execution
+ *
+ * Return from system routine. Don't clear breakpoint exception when @value
+ * is equal to value stored at @dw_offset. This triggers the system routine
+ * after the subsequent instruction, resulting in single stepping execution.
+ */
+void gpgpu_shader__end_system_routine_step_if_eq(struct gpgpu_shader *shdr,
+ uint32_t y_offset,
+ uint32_t value)
+{
+ emit_iga64_code(shdr, end_system_routine_step_if_eq, " \n\
+(W) or (1|M0) cr0.0<1>:ud cr0.0<0;1,0>:ud 0x8000:ud \n\
+(W) and (1|M0) cr0.1<1>:ud cr0.1<0;1,0>:ud ARG(0):ud \n\
+(W) mov (16|M0) r30.0<1>:ud 0x0:ud \n\
+#if GEN_VER < 2000 // Media Block Write \n\
+ // Y offset of the block in rows := thread group id Y \n\
+(W) mov (1|M0) r30.1<1>:ud ARG(1):ud \n\
+ // block width [0,63] representing 1 to 64 bytes, we want dword \n\
+(W) mov (1|M0) r30.2<1>:ud 0x3:ud \n\
+ // FFTID := FFTID from R0 header \n\
+(W) mov (1|M0) r30.4<1>:ud r0.5<0;1,0>:ud \n\
+(W) send.dc1 (16|M0) r31 r30 null 0x0 0x2190000 \n\
+#else // Typed 2D Block Store \n\
+ // Store X and Y block start (160:191 and 192:223) \n\
+(W) mov (2|M0) r30.6<1>:ud ARG(1):ud \n\
+ // Store X and Y block size (224:231 and 232:239) \n\
+(W) mov (1|M0) r30.7<1>:ud 0x3:ud \n\
+(W) send.tgm (16|M0) r31 r30 null:0 0x0 0x62100003 \n\
+#endif \n\
+ // clear the flag register \n\
+(W) mov (1|M0) f0.0<1>:ud 0x0:ud \n\
+(W) cmp (1|M0) (ne)f0.0 null<1>:ud r31.0<0;1,0>:ud ARG(2):ud \n\
+(W&f0.0) and (1|M0) cr0.1<1>:ud cr0.1<0;1,0>:ud ARG(3):ud \n\
+ // return to an application \n\
+(W) and (1|M0) cr0.0<1>:ud cr0.0<0;1,0>:ud 0x7FFFFFFD:ud \n\
+ ", 0x807fffff, /* leave breakpoint exception */
+ y_offset, value, 0x7fffff /* clear all exceptions */ );
+}
diff --git a/lib/gpgpu_shader.h b/lib/gpgpu_shader.h
index 255f93b4d..e4ca0be4c 100644
--- a/lib/gpgpu_shader.h
+++ b/lib/gpgpu_shader.h
@@ -21,6 +21,7 @@ struct gpgpu_shader {
uint32_t *code;
uint32_t (*instr)[4];
};
+ struct igt_map *labels;
};
struct iga64_template {
@@ -31,7 +32,7 @@ struct iga64_template {
#pragma GCC diagnostic ignored "-Wnested-externs"
-void
+uint32_t
__emit_iga64_code(struct gpgpu_shader *shdr, const struct iga64_template *tpls,
int argc, uint32_t *argv);
@@ -56,8 +57,27 @@ void gpgpu_shader_exec(struct intel_bb *ibb,
struct gpgpu_shader *sip,
uint64_t ring, bool explicit_engine);
+void gpgpu_shader__wait(struct gpgpu_shader *shdr);
+void gpgpu_shader__breakpoint_on(struct gpgpu_shader *shdr, uint32_t cmd_no);
+void gpgpu_shader__breakpoint(struct gpgpu_shader *shdr);
+void gpgpu_shader__nop(struct gpgpu_shader *shdr);
void gpgpu_shader__eot(struct gpgpu_shader *shdr);
+void gpgpu_shader__common_target_write(struct gpgpu_shader *shdr,
+ uint32_t y_offset, const uint32_t value[4]);
+void gpgpu_shader__common_target_write_u32(struct gpgpu_shader *shdr,
+ uint32_t y_offset, uint32_t value);
+void gpgpu_shader__end_system_routine(struct gpgpu_shader *shdr,
+ bool breakpoint_suppress);
+void gpgpu_shader__end_system_routine_step_if_eq(struct gpgpu_shader *shdr,
+ uint32_t dw_offset,
+ uint32_t value);
+void gpgpu_shader__write_aip(struct gpgpu_shader *shdr, uint32_t y_offset);
void gpgpu_shader__write_dword(struct gpgpu_shader *shdr, uint32_t value,
uint32_t y_offset);
-
+void gpgpu_shader__label(struct gpgpu_shader *shdr, int label_id);
+void gpgpu_shader__jump(struct gpgpu_shader *shdr, int label_id);
+void gpgpu_shader__jump_neq(struct gpgpu_shader *shdr, int label_id,
+ uint32_t dw_offset, uint32_t value);
+void gpgpu_shader__loop_begin(struct gpgpu_shader *shdr, int label_id);
+void gpgpu_shader__loop_end(struct gpgpu_shader *shdr, int label_id, uint32_t iter);
#endif /* GPGPU_SHADER_H */
diff --git a/lib/iga64_generated_codes.c b/lib/iga64_generated_codes.c
index f609ad711..c121893db 100644
--- a/lib/iga64_generated_codes.c
+++ b/lib/iga64_generated_codes.c
@@ -3,7 +3,95 @@
#include "gpgpu_shader.h"
-#define MD5_SUM_IGA64_ASMS 2c503cbfbd7b3043e9a52188ae4da7a8
+#define MD5_SUM_IGA64_ASMS 61a15534954fe7c6bd0e983fbfd54c27
+
+struct iga64_template const iga64_code_end_system_routine_step_if_eq[] = {
+ { .gen_ver = 2000, .size = 44, .code = (const uint32_t []) {
+ 0x80000966, 0x80018220, 0x02008000, 0x00008000,
+ 0x80000965, 0x80118220, 0x02008010, 0xc0ded000,
+ 0x80100961, 0x1e054220, 0x00000000, 0x00000000,
+ 0x80040061, 0x1e654220, 0x00000000, 0xc0ded001,
+ 0x80000061, 0x1e754220, 0x00000000, 0x00000003,
+ 0x80132031, 0x1f0c0000, 0xd0061e8c, 0x04000000,
+ 0x80000061, 0x30014220, 0x00000000, 0x00000000,
+ 0x80008070, 0x00018220, 0x22001f04, 0xc0ded002,
+ 0x84000965, 0x80118220, 0x02008010, 0xc0ded003,
+ 0x80000965, 0x80018220, 0x02008000, 0x7ffffffd,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 1272, .size = 48, .code = (const uint32_t []) {
+ 0x80000966, 0x80018220, 0x02008000, 0x00008000,
+ 0x80000965, 0x80118220, 0x02008010, 0xc0ded000,
+ 0x80100961, 0x1e054220, 0x00000000, 0x00000000,
+ 0x80000061, 0x1e154220, 0x00000000, 0xc0ded001,
+ 0x80000061, 0x1e254220, 0x00000000, 0x00000003,
+ 0x80000061, 0x1e450220, 0x00000054, 0x00000000,
+ 0x80132031, 0x1f0c0000, 0xc0001e0c, 0x02400000,
+ 0x80000061, 0x30014220, 0x00000000, 0x00000000,
+ 0x80008070, 0x00018220, 0x22001f04, 0xc0ded002,
+ 0x84000965, 0x80118220, 0x02008010, 0xc0ded003,
+ 0x80000965, 0x80018220, 0x02008000, 0x7ffffffd,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 1250, .size = 52, .code = (const uint32_t []) {
+ 0x80000966, 0x80018220, 0x02008000, 0x00008000,
+ 0x80000965, 0x80218220, 0x02008020, 0xc0ded000,
+ 0x80040961, 0x1e054220, 0x00000000, 0x00000000,
+ 0x80000061, 0x1e254220, 0x00000000, 0xc0ded001,
+ 0x80000061, 0x1e454220, 0x00000000, 0x00000003,
+ 0x80000061, 0x1e850220, 0x000000a4, 0x00000000,
+ 0x80001901, 0x00010000, 0x00000000, 0x00000000,
+ 0x80044031, 0x1f0c0000, 0xc0001e0c, 0x02400000,
+ 0x80000061, 0x30014220, 0x00000000, 0x00000000,
+ 0x80002070, 0x00018220, 0x22001f04, 0xc0ded002,
+ 0x81000965, 0x80218220, 0x02008020, 0xc0ded003,
+ 0x80000965, 0x80018220, 0x02008000, 0x7ffffffd,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 0, .size = 48, .code = (const uint32_t []) {
+ 0x80000166, 0x80018220, 0x02008000, 0x00008000,
+ 0x80000165, 0x80218220, 0x02008020, 0xc0ded000,
+ 0x80040161, 0x1e054220, 0x00000000, 0x00000000,
+ 0x80000061, 0x1e254220, 0x00000000, 0xc0ded001,
+ 0x80000061, 0x1e454220, 0x00000000, 0x00000003,
+ 0x80000061, 0x1e850220, 0x000000a4, 0x00000000,
+ 0x80049031, 0x1f0c0000, 0xc0001e0c, 0x02400000,
+ 0x80000061, 0x30014220, 0x00000000, 0x00000000,
+ 0x80002070, 0x00018220, 0x22001f04, 0xc0ded002,
+ 0x81000165, 0x80218220, 0x02008020, 0xc0ded003,
+ 0x80000165, 0x80018220, 0x02008000, 0x7ffffffd,
+ 0x80000101, 0x00010000, 0x00000000, 0x00000000,
+ }}
+};
+
+struct iga64_template const iga64_code_end_system_routine[] = {
+ { .gen_ver = 1272, .size = 12, .code = (const uint32_t []) {
+ 0x80000965, 0x80118220, 0x02008010, 0xc0ded000,
+ 0x80000965, 0x80018220, 0x02008000, 0x7ffffffd,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 1250, .size = 12, .code = (const uint32_t []) {
+ 0x80000965, 0x80218220, 0x02008020, 0xc0ded000,
+ 0x80000965, 0x80018220, 0x02008000, 0x7ffffffd,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 0, .size = 12, .code = (const uint32_t []) {
+ 0x80000165, 0x80218220, 0x02008020, 0xc0ded000,
+ 0x80000165, 0x80018220, 0x02008000, 0x7ffffffd,
+ 0x80000101, 0x00010000, 0x00000000, 0x00000000,
+ }}
+};
+
+struct iga64_template const iga64_code_breakpoint_suppress[] = {
+ { .gen_ver = 1250, .size = 8, .code = (const uint32_t []) {
+ 0x80000966, 0x80018220, 0x02008000, 0x00008000,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 0, .size = 8, .code = (const uint32_t []) {
+ 0x80000166, 0x80018220, 0x02008000, 0x00008000,
+ 0x80000101, 0x00010000, 0x00000000, 0x00000000,
+ }}
+};
struct iga64_template const iga64_code_media_block_write[] = {
{ .gen_ver = 2000, .size = 56, .code = (const uint32_t []) {
@@ -70,6 +158,215 @@ struct iga64_template const iga64_code_media_block_write[] = {
}}
};
+struct iga64_template const iga64_code_media_block_write_aip[] = {
+ { .gen_ver = 2000, .size = 44, .code = (const uint32_t []) {
+ 0x80000961, 0x05050220, 0x00008020, 0x00000000,
+ 0x80000969, 0x02058220, 0x02000014, 0x00000002,
+ 0x80000061, 0x02150220, 0x00000064, 0x00000000,
+ 0x80001940, 0x02158220, 0x02000214, 0xc0ded000,
+ 0x80100061, 0x04054220, 0x00000000, 0x00000000,
+ 0x80041a61, 0x04550220, 0x00220205, 0x00000000,
+ 0x80000061, 0x04754220, 0x00000000, 0x00000003,
+ 0x80132031, 0x00000000, 0xd00e0494, 0x04000000,
+ 0x80000001, 0x00010000, 0x20000000, 0x00000000,
+ 0x80000001, 0x00010000, 0x30000000, 0x00000000,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 1272, .size = 40, .code = (const uint32_t []) {
+ 0x80000961, 0x05050220, 0x00008020, 0x00000000,
+ 0x80000969, 0x04058220, 0x02000014, 0x00000002,
+ 0x80000061, 0x04150220, 0x00000064, 0x00000000,
+ 0x80001940, 0x04158220, 0x02000414, 0xc0ded000,
+ 0x80000061, 0x04254220, 0x00000000, 0x00000003,
+ 0x80000061, 0x04450220, 0x00000054, 0x00000000,
+ 0x80132031, 0x00000000, 0xc0000414, 0x02a00000,
+ 0x80000001, 0x00010000, 0x20000000, 0x00000000,
+ 0x80000001, 0x00010000, 0x30000000, 0x00000000,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 1250, .size = 44, .code = (const uint32_t []) {
+ 0x80000961, 0x05050220, 0x00008040, 0x00000000,
+ 0x80000969, 0x04058220, 0x02000024, 0x00000002,
+ 0x80000061, 0x04250220, 0x000000c4, 0x00000000,
+ 0x80001940, 0x04258220, 0x02000424, 0xc0ded000,
+ 0x80000061, 0x04454220, 0x00000000, 0x00000003,
+ 0x80000061, 0x04850220, 0x000000a4, 0x00000000,
+ 0x80001901, 0x00010000, 0x00000000, 0x00000000,
+ 0x80044031, 0x00000000, 0xc0000414, 0x02a00000,
+ 0x80000001, 0x00010000, 0x20000000, 0x00000000,
+ 0x80000001, 0x00010000, 0x30000000, 0x00000000,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 0, .size = 40, .code = (const uint32_t []) {
+ 0x80000161, 0x05050220, 0x00008040, 0x00000000,
+ 0x80000169, 0x04058220, 0x02000024, 0x00000002,
+ 0x80000061, 0x04250220, 0x000000c4, 0x00000000,
+ 0x80000140, 0x04258220, 0x02000424, 0xc0ded000,
+ 0x80000061, 0x04454220, 0x00000000, 0x00000003,
+ 0x80000061, 0x04850220, 0x000000a4, 0x00000000,
+ 0x80049031, 0x00000000, 0xc0000414, 0x02a00000,
+ 0x80000001, 0x00010000, 0x20000000, 0x00000000,
+ 0x80000001, 0x00010000, 0x30000000, 0x00000000,
+ 0x80000101, 0x00010000, 0x00000000, 0x00000000,
+ }}
+};
+
+struct iga64_template const iga64_code_common_target_write[] = {
+ { .gen_ver = 2000, .size = 48, .code = (const uint32_t []) {
+ 0x80100061, 0x1f054220, 0x00000000, 0x00000000,
+ 0x80000061, 0x1f054220, 0x00000000, 0xc0ded001,
+ 0x80000061, 0x1f154220, 0x00000000, 0xc0ded002,
+ 0x80000061, 0x1f254220, 0x00000000, 0xc0ded003,
+ 0x80000061, 0x1f354220, 0x00000000, 0xc0ded004,
+ 0x80100061, 0x1e054220, 0x00000000, 0x00000000,
+ 0x80040061, 0x1e654220, 0x00000000, 0xc0ded000,
+ 0x80000061, 0x1e754220, 0x00000000, 0x0000000f,
+ 0x80132031, 0x00000000, 0xd00e1e94, 0x04000000,
+ 0x80000001, 0x00010000, 0x20000000, 0x00000000,
+ 0x80000001, 0x00010000, 0x30000000, 0x00000000,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 1272, .size = 52, .code = (const uint32_t []) {
+ 0x80100061, 0x1f054220, 0x00000000, 0x00000000,
+ 0x80000061, 0x1f054220, 0x00000000, 0xc0ded001,
+ 0x80000061, 0x1f154220, 0x00000000, 0xc0ded002,
+ 0x80000061, 0x1f254220, 0x00000000, 0xc0ded003,
+ 0x80000061, 0x1f354220, 0x00000000, 0xc0ded004,
+ 0x80100061, 0x1e054220, 0x00000000, 0x00000000,
+ 0x80000061, 0x1e154220, 0x00000000, 0xc0ded000,
+ 0x80000061, 0x1e254220, 0x00000000, 0x0000000f,
+ 0x80000061, 0x1e450220, 0x00000054, 0x00000000,
+ 0x80132031, 0x00000000, 0xc0001e14, 0x02a00000,
+ 0x80000001, 0x00010000, 0x20000000, 0x00000000,
+ 0x80000001, 0x00010000, 0x30000000, 0x00000000,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 1250, .size = 56, .code = (const uint32_t []) {
+ 0x80040061, 0x1f054220, 0x00000000, 0x00000000,
+ 0x80000061, 0x1f054220, 0x00000000, 0xc0ded001,
+ 0x80000061, 0x1f254220, 0x00000000, 0xc0ded002,
+ 0x80000061, 0x1f454220, 0x00000000, 0xc0ded003,
+ 0x80000061, 0x1f654220, 0x00000000, 0xc0ded004,
+ 0x80040061, 0x1e054220, 0x00000000, 0x00000000,
+ 0x80000061, 0x1e254220, 0x00000000, 0xc0ded000,
+ 0x80000061, 0x1e454220, 0x00000000, 0x0000000f,
+ 0x80000061, 0x1e850220, 0x000000a4, 0x00000000,
+ 0x80001901, 0x00010000, 0x00000000, 0x00000000,
+ 0x80044031, 0x00000000, 0xc0001e14, 0x02a00000,
+ 0x80000001, 0x00010000, 0x20000000, 0x00000000,
+ 0x80000001, 0x00010000, 0x30000000, 0x00000000,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 0, .size = 52, .code = (const uint32_t []) {
+ 0x80040061, 0x1f054220, 0x00000000, 0x00000000,
+ 0x80000061, 0x1f054220, 0x00000000, 0xc0ded001,
+ 0x80000061, 0x1f254220, 0x00000000, 0xc0ded002,
+ 0x80000061, 0x1f454220, 0x00000000, 0xc0ded003,
+ 0x80000061, 0x1f654220, 0x00000000, 0xc0ded004,
+ 0x80040061, 0x1e054220, 0x00000000, 0x00000000,
+ 0x80000061, 0x1e254220, 0x00000000, 0xc0ded000,
+ 0x80000061, 0x1e454220, 0x00000000, 0x0000000f,
+ 0x80000061, 0x1e850220, 0x000000a4, 0x00000000,
+ 0x80049031, 0x00000000, 0xc0001e14, 0x02a00000,
+ 0x80000001, 0x00010000, 0x20000000, 0x00000000,
+ 0x80000001, 0x00010000, 0x30000000, 0x00000000,
+ 0x80000101, 0x00010000, 0x00000000, 0x00000000,
+ }}
+};
+
+struct iga64_template const iga64_code_inc_r40_jump_neq[] = {
+ { .gen_ver = 1272, .size = 20, .code = (const uint32_t []) {
+ 0x80000040, 0x28058220, 0x02002804, 0x00000001,
+ 0x80000061, 0x30014220, 0x00000000, 0x00000000,
+ 0x80001a70, 0x00018220, 0x22002804, 0xc0ded000,
+ 0x84000020, 0x00004000, 0x00000000, 0xffffffd0,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 1250, .size = 20, .code = (const uint32_t []) {
+ 0x80000040, 0x28058220, 0x02002804, 0x00000001,
+ 0x80000061, 0x30014220, 0x00000000, 0x00000000,
+ 0x80001a70, 0x00018220, 0x22002804, 0xc0ded000,
+ 0x81000020, 0x00004000, 0x00000000, 0xffffffd0,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 0, .size = 20, .code = (const uint32_t []) {
+ 0x80000040, 0x28058220, 0x02002804, 0x00000001,
+ 0x80000061, 0x30014220, 0x00000000, 0x00000000,
+ 0x80000270, 0x00018220, 0x22002804, 0xc0ded000,
+ 0x81000020, 0x00004000, 0x00000000, 0xffffffd0,
+ 0x80000101, 0x00010000, 0x00000000, 0x00000000,
+ }}
+};
+
+struct iga64_template const iga64_code_clear_r40[] = {
+ { .gen_ver = 1250, .size = 8, .code = (const uint32_t []) {
+ 0x80000061, 0x28054220, 0x00000000, 0x00000000,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 0, .size = 8, .code = (const uint32_t []) {
+ 0x80000061, 0x28054220, 0x00000000, 0x00000000,
+ 0x80000101, 0x00010000, 0x00000000, 0x00000000,
+ }}
+};
+
+struct iga64_template const iga64_code_jump_dw_neq[] = {
+ { .gen_ver = 2000, .size = 32, .code = (const uint32_t []) {
+ 0x80100061, 0x1e054220, 0x00000000, 0x00000000,
+ 0x80040061, 0x1e654220, 0x00000000, 0xc0ded000,
+ 0x80000061, 0x1e754220, 0x00000000, 0x00000003,
+ 0x80132031, 0x1f0c0000, 0xd0061e8c, 0x04000000,
+ 0x80000061, 0x30014220, 0x00000000, 0x00000000,
+ 0x80008070, 0x00018220, 0x22001f04, 0xc0ded001,
+ 0x84000020, 0x00004000, 0x00000000, 0xffffffa0,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 1272, .size = 36, .code = (const uint32_t []) {
+ 0x80100061, 0x1e054220, 0x00000000, 0x00000000,
+ 0x80000061, 0x1e154220, 0x00000000, 0xc0ded000,
+ 0x80000061, 0x1e254220, 0x00000000, 0x00000003,
+ 0x80000061, 0x1e450220, 0x00000054, 0x00000000,
+ 0x80132031, 0x1f0c0000, 0xc0001e0c, 0x02400000,
+ 0x80000061, 0x30014220, 0x00000000, 0x00000000,
+ 0x80008070, 0x00018220, 0x22001f04, 0xc0ded001,
+ 0x84000020, 0x00004000, 0x00000000, 0xffffff90,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 1250, .size = 40, .code = (const uint32_t []) {
+ 0x80040061, 0x1e054220, 0x00000000, 0x00000000,
+ 0x80000061, 0x1e254220, 0x00000000, 0xc0ded000,
+ 0x80000061, 0x1e454220, 0x00000000, 0x00000003,
+ 0x80000061, 0x1e850220, 0x000000a4, 0x00000000,
+ 0x80001901, 0x00010000, 0x00000000, 0x00000000,
+ 0x80044031, 0x1f0c0000, 0xc0001e0c, 0x02400000,
+ 0x80000061, 0x30014220, 0x00000000, 0x00000000,
+ 0x80002070, 0x00018220, 0x22001f04, 0xc0ded001,
+ 0x81000020, 0x00004000, 0x00000000, 0xffffff80,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 0, .size = 36, .code = (const uint32_t []) {
+ 0x80040061, 0x1e054220, 0x00000000, 0x00000000,
+ 0x80000061, 0x1e254220, 0x00000000, 0xc0ded000,
+ 0x80000061, 0x1e454220, 0x00000000, 0x00000003,
+ 0x80000061, 0x1e850220, 0x000000a4, 0x00000000,
+ 0x80049031, 0x1f0c0000, 0xc0001e0c, 0x02400000,
+ 0x80000061, 0x30014220, 0x00000000, 0x00000000,
+ 0x80002070, 0x00018220, 0x22001f04, 0xc0ded001,
+ 0x81000020, 0x00004000, 0x00000000, 0xffffff90,
+ 0x80000101, 0x00010000, 0x00000000, 0x00000000,
+ }}
+};
+
+struct iga64_template const iga64_code_jump[] = {
+ { .gen_ver = 1250, .size = 8, .code = (const uint32_t []) {
+ 0x80000020, 0x00004000, 0x00000000, 0x00000000,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 0, .size = 8, .code = (const uint32_t []) {
+ 0x80000020, 0x00004000, 0x00000000, 0x00000000,
+ 0x80000101, 0x00010000, 0x00000000, 0x00000000,
+ }}
+};
+
struct iga64_template const iga64_code_eot[] = {
{ .gen_ver = 1272, .size = 8, .code = (const uint32_t []) {
0x800c0061, 0x70050220, 0x00460005, 0x00000000,
@@ -85,3 +382,25 @@ struct iga64_template const iga64_code_eot[] = {
0x80049031, 0x00000004, 0x7020700c, 0x10000000,
}}
};
+
+struct iga64_template const iga64_code_nop[] = {
+ { .gen_ver = 1250, .size = 8, .code = (const uint32_t []) {
+ 0x00000060, 0x00000000, 0x00000000, 0x00000000,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 0, .size = 8, .code = (const uint32_t []) {
+ 0x00000060, 0x00000000, 0x00000000, 0x00000000,
+ 0x80000101, 0x00010000, 0x00000000, 0x00000000,
+ }}
+};
+
+struct iga64_template const iga64_code_sync_host[] = {
+ { .gen_ver = 1250, .size = 8, .code = (const uint32_t []) {
+ 0x80000001, 0x00010000, 0xf0000000, 0x00000000,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 0, .size = 8, .code = (const uint32_t []) {
+ 0x80000001, 0x00010000, 0xf0000000, 0x00000000,
+ 0x80000101, 0x00010000, 0x00000000, 0x00000000,
+ }}
+};
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 38/66] tests/xe_exec_sip: Port tests for shaders and sip
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (36 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 37/66] lib/gpgpu_shader: Extend shader building library Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 39/66] tests/xe_exec_sip: Check if we reset due to unhandled attention Christoph Manszewski
` (29 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski, Mika Kuoppala
SIP is a System Instruction Pointer, which the hardware will
except/jump into when some defined event occurs, debug mode
is enabled and pipeline setup has included sip program.
Events like illegal instruction or breakpoint hit will jump
into SIP directly. Driver can also except into sip during hang
resolution and SIP can do, for example, eu thread state snapshot
before the hang resolution ends up in a hardware state reset.
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
tests/intel/xe_exec_sip.c | 129 ++++++++++++++++++++++++++++++++++----
1 file changed, 116 insertions(+), 13 deletions(-)
diff --git a/tests/intel/xe_exec_sip.c b/tests/intel/xe_exec_sip.c
index 4b599e7f6..e52889818 100644
--- a/tests/intel/xe_exec_sip.c
+++ b/tests/intel/xe_exec_sip.c
@@ -21,6 +21,7 @@
#include "gpgpu_shader.h"
#include "igt.h"
#include "igt_sysfs.h"
+#include "xe/xe_eudebug.h"
#include "xe/xe_ioctl.h"
#include "xe/xe_query.h"
@@ -30,9 +31,16 @@
#define COLOR_C4 0xc4
#define SHADER_CANARY 0x01010101
+#define SIP_CANARY 0x02020202
#define NSEC_PER_MSEC (1000 * 1000ull)
+#define SHADER_BREAKPOINT 0
+#define SHADER_WRITE 1
+#define SHADER_WAIT 2
+#define SIP_WRITE 3
+#define SIP_NULL 4
+
static struct intel_buf *
create_fill_buf(int fd, int width, int height, uint8_t color)
{
@@ -52,27 +60,78 @@ create_fill_buf(int fd, int width, int height, uint8_t color)
return buf;
}
-static struct gpgpu_shader *get_shader(int fd)
+static struct gpgpu_shader *get_shader(int fd, const int shadertype)
{
static struct gpgpu_shader *shader;
shader = gpgpu_shader_create(fd);
gpgpu_shader__write_dword(shader, SHADER_CANARY, 0);
+
+ switch (shadertype) {
+ case SHADER_WAIT:
+ gpgpu_shader__wait(shader);
+ break;
+ case SHADER_WRITE:
+ break;
+ case SHADER_BREAKPOINT:
+ gpgpu_shader__nop(shader);
+ gpgpu_shader__breakpoint(shader);
+ break;
+ }
+
gpgpu_shader__eot(shader);
return shader;
}
-static uint32_t gpgpu_shader(int fd, struct intel_bb *ibb, unsigned int threads,
- unsigned int width, unsigned int height)
+static struct gpgpu_shader *get_sip(int fd, const int siptype,
+ const int shadertype, unsigned int y_offset)
+{
+ static struct gpgpu_shader *sip;
+
+ if (siptype == SIP_NULL)
+ return NULL;
+
+ sip = gpgpu_shader_create(fd);
+ gpgpu_shader__write_dword(sip, SIP_CANARY, y_offset);
+
+ switch (siptype) {
+ case SIP_WRITE:
+ break;
+ /* TODO: Add alternative SIP instructions here */
+ }
+
+ gpgpu_shader__end_system_routine(sip, shadertype == SHADER_BREAKPOINT);
+ return sip;
+}
+
+static uint32_t gpgpu_shader(int fd, struct intel_bb *ibb, const int shadertype, const int siptype,
+ unsigned int threads, unsigned int width, unsigned int height)
{
struct intel_buf *buf = create_fill_buf(fd, width, height, COLOR_C4);
- struct gpgpu_shader *shader = get_shader(fd);
+ struct gpgpu_shader *sip = get_sip(fd, siptype, shadertype, height / 2);
+ struct gpgpu_shader *shader = get_shader(fd, shadertype);
+
+ gpgpu_shader_exec(ibb, buf, 1, threads, shader, sip, 0, 0);
- gpgpu_shader_exec(ibb, buf, 1, threads, shader, NULL, 0, 0);
+ if (sip)
+ gpgpu_shader_destroy(sip);
gpgpu_shader_destroy(shader);
+
return buf->handle;
}
+static bool has_debugger(int fd)
+{
+ struct drm_xe_eudebug_connect param = { .pid = getpid() };
+ int debugfd;
+
+ debugfd = igt_ioctl(fd, DRM_IOCTL_XE_EUDEBUG_CONNECT, ¶m);
+ if (debugfd >= 0)
+ close(debugfd);
+
+ return debugfd >= 0;
+}
+
static void check_fill_buf(uint8_t *ptr, const int width, const int x,
const int y, const uint8_t color)
{
@@ -84,10 +143,10 @@ static void check_fill_buf(uint8_t *ptr, const int width, const int x,
}
static void check_buf(int fd, uint32_t handle, int width, int height,
- uint8_t poison_c)
+ int siptype, uint8_t poison_c)
{
unsigned int sz = ALIGN(width * height, 4096);
- int thread_count = 0;
+ int thread_count = 0, sip_count = 0;
uint32_t *ptr;
int i, j;
@@ -105,7 +164,25 @@ static void check_buf(int fd, uint32_t handle, int width, int height,
i = 0;
}
+ for (i = 0, j = height / 2; j < height; ++j) {
+ if (ptr[j * width / 4] == SIP_CANARY) {
+ ++sip_count;
+ i = 4;
+ }
+
+ for (; i < width; i++)
+ check_fill_buf((uint8_t *)ptr, width, i, j, poison_c);
+
+ i = 0;
+ }
+
igt_assert(thread_count);
+ if (siptype != SIP_NULL && has_debugger(fd))
+ igt_assert_f(thread_count == sip_count,
+ "Thread and SIP count mismatch, %d != %d\n",
+ thread_count, sip_count);
+ else
+ igt_assert(sip_count == 0);
munmap(ptr, sz);
}
@@ -128,16 +205,22 @@ xe_sysfs_get_job_timeout_ms(int fd, struct drm_xe_engine_class_instance *eci)
* Description: check basic shader with write operation
* Run type: BAT
*
+ * SUBTEST: wait-writesip-nodebug
+ * Description: verify that we don't enter SIP after wait with debugging disabled.
+ *
+ * SUBTEST: breakpoint-writesip
+ * Description: Test that we enter SIP after hitting breakpoint in shader.
+ *
*/
-static void test_sip(struct drm_xe_engine_class_instance *eci, uint32_t flags)
+static void test_sip(int shader, int sip, struct drm_xe_engine_class_instance *eci)
{
unsigned int threads = 512;
unsigned int height = max_t(threads, HEIGHT, threads * 2);
- uint32_t exec_queue_id, handle, vm_id;
unsigned int width = WIDTH;
struct timespec ts = { };
- uint64_t timeout;
+ uint32_t exec_queue_id, handle, vm_id;
struct intel_bb *ibb;
+ uint64_t timeout;
int fd;
igt_debug("Using %s\n", xe_engine_class_string(eci->engine_class));
@@ -156,12 +239,12 @@ static void test_sip(struct drm_xe_engine_class_instance *eci, uint32_t flags)
ibb = intel_bb_create_with_context(fd, exec_queue_id, vm_id, NULL, 4096);
igt_nsec_elapsed(&ts);
- handle = gpgpu_shader(fd, ibb, threads, width, height);
+ handle = gpgpu_shader(fd, ibb, shader, sip, threads, width, height);
intel_bb_sync(ibb);
igt_assert_lt_u64(igt_nsec_elapsed(&ts), timeout);
- check_buf(fd, handle, width, height, COLOR_C4);
+ check_buf(fd, handle, width, height, sip, COLOR_C4);
gem_close(fd, handle);
intel_bb_destroy(ibb);
@@ -189,7 +272,27 @@ igt_main
fd = drm_open_driver(DRIVER_XE);
test_render_and_compute("sanity", fd, eci)
- test_sip(eci, 0);
+ test_sip(SHADER_WRITE, SIP_NULL, eci);
+
+ /* Debugger disabled (TD_CTL not set) */
+ igt_subtest_group {
+ igt_fixture {
+ igt_require(!has_debugger(fd));
+ }
+
+ test_render_and_compute("wait-writesip-nodebug", fd, eci)
+ test_sip(SHADER_WAIT, SIP_WRITE, eci);
+ }
+
+ /* Debugger enabled (TD_CTL set) */
+ igt_subtest_group {
+ igt_fixture {
+ igt_require(has_debugger(fd));
+ }
+
+ test_render_and_compute("breakpoint-writesip", fd, eci)
+ test_sip(SHADER_BREAKPOINT, SIP_WRITE, eci);
+ }
igt_fixture
drm_close_driver(fd);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 39/66] tests/xe_exec_sip: Check if we reset due to unhandled attention
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (37 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 38/66] tests/xe_exec_sip: Port tests for shaders and sip Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 40/66] tests/xe_exec_sip: Check usercoredump for attentions Christoph Manszewski
` (28 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Add breakpoint-waitsip test which checks whether we reset upon
unhandled attention.
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Cc: Christoph Manszewski <christoph.manszewski@intel.com>
---
tests/intel/xe_exec_sip.c | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/tests/intel/xe_exec_sip.c b/tests/intel/xe_exec_sip.c
index e52889818..1b0accb3b 100644
--- a/tests/intel/xe_exec_sip.c
+++ b/tests/intel/xe_exec_sip.c
@@ -40,6 +40,7 @@
#define SHADER_WAIT 2
#define SIP_WRITE 3
#define SIP_NULL 4
+#define SIP_WAIT 5
static struct intel_buf *
create_fill_buf(int fd, int width, int height, uint8_t color)
@@ -97,7 +98,9 @@ static struct gpgpu_shader *get_sip(int fd, const int siptype,
switch (siptype) {
case SIP_WRITE:
break;
- /* TODO: Add alternative SIP instructions here */
+ case SIP_WAIT:
+ gpgpu_shader__wait(sip);
+ break;
}
gpgpu_shader__end_system_routine(sip, shadertype == SHADER_BREAKPOINT);
@@ -211,12 +214,20 @@ xe_sysfs_get_job_timeout_ms(int fd, struct drm_xe_engine_class_instance *eci)
* SUBTEST: breakpoint-writesip
* Description: Test that we enter SIP after hitting breakpoint in shader.
*
+ * SUBTEST: breakpoint-waitsip
+ * Description: Test that we reset after seeing the attention without the debugger.
+ *
*/
static void test_sip(int shader, int sip, struct drm_xe_engine_class_instance *eci)
{
unsigned int threads = 512;
unsigned int height = max_t(threads, HEIGHT, threads * 2);
unsigned int width = WIDTH;
+ struct drm_xe_ext_set_property ext = {
+ .base.name = DRM_XE_EXEC_QUEUE_EXTENSION_SET_PROPERTY,
+ .property = DRM_XE_EXEC_QUEUE_SET_PROPERTY_EUDEBUG,
+ .value = DRM_XE_EXEC_QUEUE_EUDEBUG_FLAG_ENABLE,
+ };
struct timespec ts = { };
uint32_t exec_queue_id, handle, vm_id;
struct intel_bb *ibb;
@@ -228,6 +239,7 @@ static void test_sip(int shader, int sip, struct drm_xe_engine_class_instance *e
fd = drm_open_driver(DRIVER_XE);
xe_device_get(fd);
+
vm_id = xe_vm_create(fd, 0, 0);
/* Get timeout for job, and add 4s to ensure timeout processes in subtest. */
@@ -235,7 +247,9 @@ static void test_sip(int shader, int sip, struct drm_xe_engine_class_instance *e
timeout *= NSEC_PER_MSEC;
timeout *= igt_run_in_simulation() ? 10 : 1;
- exec_queue_id = xe_exec_queue_create(fd, vm_id, eci, 0);
+ exec_queue_id = xe_exec_queue_create(fd, vm_id, eci,
+ has_debugger(fd) ?
+ to_user_pointer(&ext) : 0);
ibb = intel_bb_create_with_context(fd, exec_queue_id, vm_id, NULL, 4096);
igt_nsec_elapsed(&ts);
@@ -292,6 +306,9 @@ igt_main
test_render_and_compute("breakpoint-writesip", fd, eci)
test_sip(SHADER_BREAKPOINT, SIP_WRITE, eci);
+
+ test_render_and_compute("breakpoint-waitsip", fd, eci)
+ test_sip(SHADER_BREAKPOINT, SIP_WAIT, eci);
}
igt_fixture
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 40/66] tests/xe_exec_sip: Check usercoredump for attentions
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (38 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 39/66] tests/xe_exec_sip: Check if we reset due to unhandled attention Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 41/66] tests/xe_exec_sip: Add support for dynamic debugger sysfs toggle Christoph Manszewski
` (27 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Check for attentions within usercoredump in tests that raise attentions.
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Cc: Christoph Manszewski <christoph.manszewski@intel.com>
---
tests/intel/xe_exec_sip.c | 64 +++++++++++++++++++++++++++++++++++++--
1 file changed, 61 insertions(+), 3 deletions(-)
diff --git a/tests/intel/xe_exec_sip.c b/tests/intel/xe_exec_sip.c
index 1b0accb3b..a315bd3a9 100644
--- a/tests/intel/xe_exec_sip.c
+++ b/tests/intel/xe_exec_sip.c
@@ -145,7 +145,7 @@ static void check_fill_buf(uint8_t *ptr, const int width, const int x,
color, val, x, y);
}
-static void check_buf(int fd, uint32_t handle, int width, int height,
+static int check_buf(int fd, uint32_t handle, int width, int height,
int siptype, uint8_t poison_c)
{
unsigned int sz = ALIGN(width * height, 4096);
@@ -188,6 +188,63 @@ static void check_buf(int fd, uint32_t handle, int width, int height,
igt_assert(sip_count == 0);
munmap(ptr, sz);
+
+ return sip_count;
+}
+
+#define USERCOREDUMP_FORMAT "usercoredumps/%d/%d"
+static char *get_latest_usercoredump(int dir)
+{
+ char tmp[256];
+ int i = 1;
+
+ do {
+ snprintf(tmp, sizeof(tmp), USERCOREDUMP_FORMAT, getpid(), i++);
+ } while (igt_sysfs_has_attr(dir, tmp));
+
+ snprintf(tmp, sizeof(tmp), USERCOREDUMP_FORMAT, getpid(), i-2);
+ return igt_sysfs_get(dir, tmp);
+}
+
+static void check_usercoredump(int fd, int sip, int dispatched)
+{
+ int dir = igt_debugfs_dir(fd);
+ char *usercoredump, *str;
+ unsigned int before, after;
+ char match[256];
+
+ if (sip != SIP_WAIT)
+ return;
+
+ /* XXX reinstate when offline coredumps are implemented */
+#ifndef XXX_ATTENTIONS_THROUGH_COREDUMPS
+ return;
+#endif
+ usercoredump = get_latest_usercoredump(dir);
+ igt_assert(usercoredump);
+ igt_debug("%s\n", usercoredump);
+
+ snprintf(match, sizeof(match), "PID: %d", getpid());
+ str = strstr(usercoredump, match);
+ igt_assert(str);
+
+ snprintf(match, sizeof(match), "Comm: %s", igt_test_name());
+ str = strstr(str, match);
+ igt_assert(str);
+
+ str = strstr(str, "TD_ATT");
+ igt_assert(str);
+ igt_assert_eq(sscanf(str, "TD_ATT before (%d):", &before), 1);
+ str = strstr(str + 1, "TD_ATT");
+ igt_assert_eq(sscanf(str, "TD_ATT after (%d):", &after), 1);
+
+ igt_info("attentions %d before, %d after\n", before, after);
+
+ igt_assert_eq(before, dispatched);
+ igt_assert_eq(after, dispatched);
+
+ free(usercoredump);
+ close(dir);
}
static uint64_t
@@ -232,7 +289,7 @@ static void test_sip(int shader, int sip, struct drm_xe_engine_class_instance *e
uint32_t exec_queue_id, handle, vm_id;
struct intel_bb *ibb;
uint64_t timeout;
- int fd;
+ int dispatched, fd;
igt_debug("Using %s\n", xe_engine_class_string(eci->engine_class));
@@ -258,7 +315,8 @@ static void test_sip(int shader, int sip, struct drm_xe_engine_class_instance *e
intel_bb_sync(ibb);
igt_assert_lt_u64(igt_nsec_elapsed(&ts), timeout);
- check_buf(fd, handle, width, height, sip, COLOR_C4);
+ dispatched = check_buf(fd, handle, width, height, sip, COLOR_C4);
+ check_usercoredump(fd, sip, dispatched);
gem_close(fd, handle);
intel_bb_destroy(ibb);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 41/66] tests/xe_exec_sip: Add support for dynamic debugger sysfs toggle
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (39 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 40/66] tests/xe_exec_sip: Check usercoredump for attentions Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 42/66] tests/xe_exec_sip: Add breakpoint-writesip-twice test Christoph Manszewski
` (26 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
From now on the debugger is disabled by default so it is required
to enable the debugger before using it. This change addresses that
fact by calling necessary library functions within test fixtures.
Signed-off-by: Mika Kuoppala <mika.kuoppala@intel.com>
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
tests/intel/xe_exec_sip.c | 28 ++++++++++++----------------
1 file changed, 12 insertions(+), 16 deletions(-)
diff --git a/tests/intel/xe_exec_sip.c b/tests/intel/xe_exec_sip.c
index a315bd3a9..832c26bac 100644
--- a/tests/intel/xe_exec_sip.c
+++ b/tests/intel/xe_exec_sip.c
@@ -123,18 +123,6 @@ static uint32_t gpgpu_shader(int fd, struct intel_bb *ibb, const int shadertype,
return buf->handle;
}
-static bool has_debugger(int fd)
-{
- struct drm_xe_eudebug_connect param = { .pid = getpid() };
- int debugfd;
-
- debugfd = igt_ioctl(fd, DRM_IOCTL_XE_EUDEBUG_CONNECT, ¶m);
- if (debugfd >= 0)
- close(debugfd);
-
- return debugfd >= 0;
-}
-
static void check_fill_buf(uint8_t *ptr, const int width, const int x,
const int y, const uint8_t color)
{
@@ -180,7 +168,7 @@ static int check_buf(int fd, uint32_t handle, int width, int height,
}
igt_assert(thread_count);
- if (siptype != SIP_NULL && has_debugger(fd))
+ if (siptype != SIP_NULL && xe_eudebug_debugger_available(fd))
igt_assert_f(thread_count == sip_count,
"Thread and SIP count mismatch, %d != %d\n",
thread_count, sip_count);
@@ -305,7 +293,7 @@ static void test_sip(int shader, int sip, struct drm_xe_engine_class_instance *e
timeout *= igt_run_in_simulation() ? 10 : 1;
exec_queue_id = xe_exec_queue_create(fd, vm_id, eci,
- has_debugger(fd) ?
+ xe_eudebug_debugger_available(fd) ?
to_user_pointer(&ext) : 0);
ibb = intel_bb_create_with_context(fd, exec_queue_id, vm_id, NULL, 4096);
@@ -338,6 +326,7 @@ static void test_sip(int shader, int sip, struct drm_xe_engine_class_instance *e
igt_main
{
struct drm_xe_engine_class_instance *eci;
+ bool was_enabled;
int fd;
igt_fixture
@@ -349,17 +338,21 @@ igt_main
/* Debugger disabled (TD_CTL not set) */
igt_subtest_group {
igt_fixture {
- igt_require(!has_debugger(fd));
+ was_enabled = xe_eudebug_enable(fd, false);
+ igt_require(!xe_eudebug_debugger_available(fd));
}
test_render_and_compute("wait-writesip-nodebug", fd, eci)
test_sip(SHADER_WAIT, SIP_WRITE, eci);
+
+ igt_fixture
+ xe_eudebug_enable(fd, was_enabled);
}
/* Debugger enabled (TD_CTL set) */
igt_subtest_group {
igt_fixture {
- igt_require(has_debugger(fd));
+ was_enabled = xe_eudebug_enable(fd, true);
}
test_render_and_compute("breakpoint-writesip", fd, eci)
@@ -367,6 +360,9 @@ igt_main
test_render_and_compute("breakpoint-waitsip", fd, eci)
test_sip(SHADER_BREAKPOINT, SIP_WAIT, eci);
+
+ igt_fixture
+ xe_eudebug_enable(fd, was_enabled);
}
igt_fixture
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 42/66] tests/xe_exec_sip: Add breakpoint-writesip-twice test
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (40 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 41/66] tests/xe_exec_sip: Add support for dynamic debugger sysfs toggle Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 43/66] tests/xe_exec_sip: Add sanity-after-timeout test Christoph Manszewski
` (25 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Karolina Stolarek
From: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
Add breakpoint-writesip-twice test that checks twice if
we enter SIP after hitting breakpoint in shader.
Signed-off-by: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
Cc: Karolina Stolarek <karolina.stolarek@intel.com>
---
tests/intel/xe_exec_sip.c | 40 ++++++++++++++++++++++++---------------
1 file changed, 25 insertions(+), 15 deletions(-)
diff --git a/tests/intel/xe_exec_sip.c b/tests/intel/xe_exec_sip.c
index 832c26bac..7b4305576 100644
--- a/tests/intel/xe_exec_sip.c
+++ b/tests/intel/xe_exec_sip.c
@@ -42,6 +42,8 @@
#define SIP_NULL 4
#define SIP_WAIT 5
+#define F_SUBMIT_TWICE (1 << 0)
+
static struct intel_buf *
create_fill_buf(int fd, int width, int height, uint8_t color)
{
@@ -259,11 +261,14 @@ xe_sysfs_get_job_timeout_ms(int fd, struct drm_xe_engine_class_instance *eci)
* SUBTEST: breakpoint-writesip
* Description: Test that we enter SIP after hitting breakpoint in shader.
*
+ * SUBTEST: breakpoint-writesip-twice
+ * Description: Test twice that we enter SIP after hitting breakpoint in shader.
+ *
* SUBTEST: breakpoint-waitsip
* Description: Test that we reset after seeing the attention without the debugger.
*
*/
-static void test_sip(int shader, int sip, struct drm_xe_engine_class_instance *eci)
+static void test_sip(int shader, int sip, struct drm_xe_engine_class_instance *eci, uint32_t flags)
{
unsigned int threads = 512;
unsigned int height = max_t(threads, HEIGHT, threads * 2);
@@ -274,6 +279,7 @@ static void test_sip(int shader, int sip, struct drm_xe_engine_class_instance *e
.value = DRM_XE_EXEC_QUEUE_EUDEBUG_FLAG_ENABLE,
};
struct timespec ts = { };
+ int done = 0;
uint32_t exec_queue_id, handle, vm_id;
struct intel_bb *ibb;
uint64_t timeout;
@@ -284,7 +290,6 @@ static void test_sip(int shader, int sip, struct drm_xe_engine_class_instance *e
fd = drm_open_driver(DRIVER_XE);
xe_device_get(fd);
-
vm_id = xe_vm_create(fd, 0, 0);
/* Get timeout for job, and add 4s to ensure timeout processes in subtest. */
@@ -295,19 +300,21 @@ static void test_sip(int shader, int sip, struct drm_xe_engine_class_instance *e
exec_queue_id = xe_exec_queue_create(fd, vm_id, eci,
xe_eudebug_debugger_available(fd) ?
to_user_pointer(&ext) : 0);
- ibb = intel_bb_create_with_context(fd, exec_queue_id, vm_id, NULL, 4096);
+ do {
+ ibb = intel_bb_create_with_context(fd, exec_queue_id, vm_id, NULL, 4096);
- igt_nsec_elapsed(&ts);
- handle = gpgpu_shader(fd, ibb, shader, sip, threads, width, height);
+ igt_nsec_elapsed(&ts);
+ handle = gpgpu_shader(fd, ibb, shader, sip, threads, width, height);
- intel_bb_sync(ibb);
- igt_assert_lt_u64(igt_nsec_elapsed(&ts), timeout);
+ intel_bb_sync(ibb);
+ igt_assert_lt_u64(igt_nsec_elapsed(&ts), timeout);
- dispatched = check_buf(fd, handle, width, height, sip, COLOR_C4);
- check_usercoredump(fd, sip, dispatched);
+ dispatched = check_buf(fd, handle, width, height, sip, COLOR_C4);
+ check_usercoredump(fd, sip, dispatched);
- gem_close(fd, handle);
- intel_bb_destroy(ibb);
+ gem_close(fd, handle);
+ intel_bb_destroy(ibb);
+ } while (!done++ && (flags & F_SUBMIT_TWICE));
xe_exec_queue_destroy(fd, exec_queue_id);
xe_vm_destroy(fd, vm_id);
@@ -333,7 +340,7 @@ igt_main
fd = drm_open_driver(DRIVER_XE);
test_render_and_compute("sanity", fd, eci)
- test_sip(SHADER_WRITE, SIP_NULL, eci);
+ test_sip(SHADER_WRITE, SIP_NULL, eci, 0);
/* Debugger disabled (TD_CTL not set) */
igt_subtest_group {
@@ -343,7 +350,7 @@ igt_main
}
test_render_and_compute("wait-writesip-nodebug", fd, eci)
- test_sip(SHADER_WAIT, SIP_WRITE, eci);
+ test_sip(SHADER_WAIT, SIP_WRITE, eci, 0);
igt_fixture
xe_eudebug_enable(fd, was_enabled);
@@ -356,10 +363,13 @@ igt_main
}
test_render_and_compute("breakpoint-writesip", fd, eci)
- test_sip(SHADER_BREAKPOINT, SIP_WRITE, eci);
+ test_sip(SHADER_BREAKPOINT, SIP_WRITE, eci, 0);
+
+ test_render_and_compute("breakpoint-writesip-twice", fd, eci)
+ test_sip(SHADER_BREAKPOINT, SIP_WRITE, eci, F_SUBMIT_TWICE);
test_render_and_compute("breakpoint-waitsip", fd, eci)
- test_sip(SHADER_BREAKPOINT, SIP_WAIT, eci);
+ test_sip(SHADER_BREAKPOINT, SIP_WAIT, eci, 0);
igt_fixture
xe_eudebug_enable(fd, was_enabled);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 43/66] tests/xe_exec_sip: Add sanity-after-timeout test
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (41 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 42/66] tests/xe_exec_sip: Add breakpoint-writesip-twice test Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 44/66] tests/xe_exec_sip: Add breakpoint-waitsip-heavy test Christoph Manszewski
` (24 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Karolina Stolarek, Christoph Manszewski
From: Karolina Stolarek <karolina.stolarek@intel.com>
Introduce sanity-after-timeout test to check if the shader
gets executed after a hang.
Signed-off-by: Karolina Stolarek <karolina.stolarek@intel.com>
Cc: Christoph Manszewski <christoph.manszewski@intel.com>
Cc: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
---
tests/intel/xe_exec_sip.c | 24 +++++++++++++++++++++---
1 file changed, 21 insertions(+), 3 deletions(-)
diff --git a/tests/intel/xe_exec_sip.c b/tests/intel/xe_exec_sip.c
index 7b4305576..92da8f14d 100644
--- a/tests/intel/xe_exec_sip.c
+++ b/tests/intel/xe_exec_sip.c
@@ -38,9 +38,10 @@
#define SHADER_BREAKPOINT 0
#define SHADER_WRITE 1
#define SHADER_WAIT 2
-#define SIP_WRITE 3
-#define SIP_NULL 4
-#define SIP_WAIT 5
+#define SHADER_HANG 3
+#define SIP_WRITE 4
+#define SIP_NULL 5
+#define SIP_WAIT 6
#define F_SUBMIT_TWICE (1 << 0)
@@ -71,6 +72,11 @@ static struct gpgpu_shader *get_shader(int fd, const int shadertype)
gpgpu_shader__write_dword(shader, SHADER_CANARY, 0);
switch (shadertype) {
+ case SHADER_HANG:
+ gpgpu_shader__label(shader, 0);
+ gpgpu_shader__nop(shader);
+ gpgpu_shader__jump(shader, 0);
+ break;
case SHADER_WAIT:
gpgpu_shader__wait(shader);
break;
@@ -255,6 +261,9 @@ xe_sysfs_get_job_timeout_ms(int fd, struct drm_xe_engine_class_instance *eci)
* Description: check basic shader with write operation
* Run type: BAT
*
+ * SUBTEST: sanity-after-timeout
+ * Description: check basic shader execution after job timeout
+ *
* SUBTEST: wait-writesip-nodebug
* Description: verify that we don't enter SIP after wait with debugging disabled.
*
@@ -342,6 +351,15 @@ igt_main
test_render_and_compute("sanity", fd, eci)
test_sip(SHADER_WRITE, SIP_NULL, eci, 0);
+ test_render_and_compute("sanity-after-timeout", fd, eci) {
+ test_sip(SHADER_HANG, SIP_NULL, eci, 0);
+
+ xe_for_each_engine(fd, eci)
+ if (eci->engine_class == DRM_XE_ENGINE_CLASS_RENDER ||
+ eci->engine_class == DRM_XE_ENGINE_CLASS_COMPUTE)
+ test_sip(SHADER_WRITE, SIP_NULL, eci, 0);
+ }
+
/* Debugger disabled (TD_CTL not set) */
igt_subtest_group {
igt_fixture {
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 44/66] tests/xe_exec_sip: Add breakpoint-waitsip-heavy test
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (42 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 43/66] tests/xe_exec_sip: Add sanity-after-timeout test Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 45/66] tests/xe_exec_sip: Add nodebug test cases Christoph Manszewski
` (23 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
From: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
Add breakpoint-waitsip-heavy test that walks checks if we reset
after seeing the attention from heavy SIP without the debugger.
Signed-off-by: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
Cc: Christoph Manszewski <christoph.manszewski@intel.com>
---
tests/intel/xe_exec_sip.c | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/tests/intel/xe_exec_sip.c b/tests/intel/xe_exec_sip.c
index 92da8f14d..a27d3cba6 100644
--- a/tests/intel/xe_exec_sip.c
+++ b/tests/intel/xe_exec_sip.c
@@ -42,6 +42,7 @@
#define SIP_WRITE 4
#define SIP_NULL 5
#define SIP_WAIT 6
+#define SIP_HEAVY 7
#define F_SUBMIT_TWICE (1 << 0)
@@ -107,6 +108,23 @@ static struct gpgpu_shader *get_sip(int fd, const int siptype,
case SIP_WRITE:
break;
case SIP_WAIT:
+ gpgpu_shader__wait(sip);
+ break;
+ case SIP_HEAVY:
+ /* Depending on the generation, the production sip
+ * executes between 145 to 157 instructions.
+ * It performs at most 45 data port writes and 5 data port reads.
+ * Make sure our heavy sip is at least twice heavy as production one.
+ */
+ gpgpu_shader__loop_begin(sip, 0);
+ gpgpu_shader__write_dword(sip, 0xdeadbeef, y_offset);
+ gpgpu_shader__write_dword(sip, SIP_CANARY, y_offset);
+ gpgpu_shader__loop_end(sip, 0, 45);
+
+ gpgpu_shader__loop_begin(sip, 1);
+ gpgpu_shader__jump_neq(sip, 1, y_offset, SIP_CANARY);
+ gpgpu_shader__loop_end(sip, 1, 10);
+
gpgpu_shader__wait(sip);
break;
}
@@ -209,7 +227,7 @@ static void check_usercoredump(int fd, int sip, int dispatched)
unsigned int before, after;
char match[256];
- if (sip != SIP_WAIT)
+ if (sip != SIP_WAIT && sip != SIP_HEAVY)
return;
/* XXX reinstate when offline coredumps are implemented */
@@ -276,6 +294,10 @@ xe_sysfs_get_job_timeout_ms(int fd, struct drm_xe_engine_class_instance *eci)
* SUBTEST: breakpoint-waitsip
* Description: Test that we reset after seeing the attention without the debugger.
*
+ * SUBTEST: breakpoint-waitsip-heavy
+ * Description:
+ * Test that we reset after seeing the attention from heavy SIP, that resembles
+ * the production one, without the debugger.
*/
static void test_sip(int shader, int sip, struct drm_xe_engine_class_instance *eci, uint32_t flags)
{
@@ -389,6 +411,9 @@ igt_main
test_render_and_compute("breakpoint-waitsip", fd, eci)
test_sip(SHADER_BREAKPOINT, SIP_WAIT, eci, 0);
+ test_render_and_compute("breakpoint-waitsip-heavy", fd, eci)
+ test_sip(SHADER_BREAKPOINT, SIP_HEAVY, eci, 0);
+
igt_fixture
xe_eudebug_enable(fd, was_enabled);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 45/66] tests/xe_exec_sip: Add nodebug test cases
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (43 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 44/66] tests/xe_exec_sip: Add breakpoint-waitsip-heavy test Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 46/66] lib/gpgpu_shader: Add write_on_exception template Christoph Manszewski
` (22 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Karolina Stolarek
From: Karolina Stolarek <karolina.stolarek@intel.com>
Introduce tests that make sure we don't enter SIP when debugging
is disabled.
Signed-off-by: Karolina Stolarek <karolina.stolarek@intel.com>
Cc: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
---
tests/intel/xe_exec_sip.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/tests/intel/xe_exec_sip.c b/tests/intel/xe_exec_sip.c
index a27d3cba6..35d65bcc4 100644
--- a/tests/intel/xe_exec_sip.c
+++ b/tests/intel/xe_exec_sip.c
@@ -285,6 +285,10 @@ xe_sysfs_get_job_timeout_ms(int fd, struct drm_xe_engine_class_instance *eci)
* SUBTEST: wait-writesip-nodebug
* Description: verify that we don't enter SIP after wait with debugging disabled.
*
+ * SUBTEST: breakpoint-writesip-nodebug
+ * Description: verify that we don't enter SIP after hitting breakpoint in shader
+ * when debugging is disabled.
+ *
* SUBTEST: breakpoint-writesip
* Description: Test that we enter SIP after hitting breakpoint in shader.
*
@@ -392,6 +396,9 @@ igt_main
test_render_and_compute("wait-writesip-nodebug", fd, eci)
test_sip(SHADER_WAIT, SIP_WRITE, eci, 0);
+ test_render_and_compute("breakpoint-writesip-nodebug", fd, eci)
+ test_sip(SHADER_BREAKPOINT, SIP_WRITE, eci, 0);
+
igt_fixture
xe_eudebug_enable(fd, was_enabled);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 46/66] lib/gpgpu_shader: Add write_on_exception template
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (44 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 45/66] tests/xe_exec_sip: Add nodebug test cases Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 47/66] lib/gpgpu_shader: Add set/clear exception register (cr0.1) helpers Christoph Manszewski
` (21 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun
From: Andrzej Hajda <andrzej.hajda@intel.com>
Writing specific value to memory location on unexpected value in exception
register allows to report errors from inside shader or siplet.
Signed-off-by: Andrzej Hajda <andrzej.hajda@intel.com>
---
lib/gpgpu_shader.c | 56 ++++++++++++++++++++++++++
lib/gpgpu_shader.h | 2 +
lib/iga64_generated_codes.c | 79 ++++++++++++++++++++++++++++++++++++-
3 files changed, 136 insertions(+), 1 deletion(-)
diff --git a/lib/gpgpu_shader.c b/lib/gpgpu_shader.c
index 3b16db593..a98abc57e 100644
--- a/lib/gpgpu_shader.c
+++ b/lib/gpgpu_shader.c
@@ -628,6 +628,62 @@ void gpgpu_shader__write_dword(struct gpgpu_shader *shdr, uint32_t value,
", 2, y_offset, 3, value, value, value, value);
}
+/**
+ * gpgpu_shader__write_on_exception:
+ * @shdr: shader to be modified
+ * @value: dword to be written
+ * @y_offset: write target offset within the surface in rows
+ * @mask: mask to be applied on exception register
+ * @expected: expected value of exception register with @mask applied
+ *
+ * Check if bits specified by @mask in exception register(cr0.1) are equal
+ * to provided ones: cr0.1 & @mask == @expected,
+ * if yes fill dword in (row, column/dword) == (tg_id_y + @y_offset, tg_id_x).
+ */
+void gpgpu_shader__write_on_exception(struct gpgpu_shader *shdr, uint32_t value,
+ uint32_t y_offset, uint32_t mask, uint32_t expected)
+{
+ emit_iga64_code(shdr, write_on_exception, " \n\
+ // Payload \n\
+(W) mov (1|M0) r5.0<1>:ud ARG(3):ud \n\
+(W) mov (1|M0) r5.1<1>:ud ARG(4):ud \n\
+(W) mov (1|M0) r5.2<1>:ud ARG(5):ud \n\
+(W) mov (1|M0) r5.3<1>:ud ARG(6):ud \n\
+#if GEN_VER < 2000 // prepare Media Block Write \n\
+ // X offset of the block in bytes := (thread group id X << ARG(0)) \n\
+(W) shl (1|M0) r4.0<1>:ud r0.1<0;1,0>:ud ARG(0):ud \n\
+ // Y offset of the block in rows := thread group id Y \n\
+(W) mov (1|M0) r4.1<1>:ud r0.6<0;1,0>:ud \n\
+(W) add (1|M0) r4.1<1>:ud r4.1<0;1,0>:ud ARG(1):ud \n\
+ // block width [0,63] representing 1 to 64 bytes \n\
+(W) mov (1|M0) r4.2<1>:ud ARG(2):ud \n\
+ // FFTID := FFTID from R0 header \n\
+(W) mov (1|M0) r4.4<1>:ud r0.5<0;1,0>:ud \n\
+#else // prepare Typed 2D Block Store \n\
+ // Load r2.0-3 with tg id X << ARG(0) \n\
+(W) shl (1|M0) r2.0<1>:ud r0.1<0;1,0>:ud ARG(0):ud \n\
+ // Load r2.4-7 with tg id Y + ARG(1):ud \n\
+(W) mov (1|M0) r2.1<1>:ud r0.6<0;1,0>:ud \n\
+(W) add (1|M0) r2.1<1>:ud r2.1<0;1,0>:ud ARG(1):ud \n\
+ // payload setup \n\
+(W) mov (16|M0) r4.0<1>:ud 0x0:ud \n\
+ // Store X and Y block start (160:191 and 192:223) \n\
+(W) mov (2|M0) r4.5<1>:ud r2.0<2;2,1>:ud \n\
+ // Store X and Y block max_size (224:231 and 232:239) \n\
+(W) mov (1|M0) r4.7<1>:ud ARG(2):ud \n\
+#endif \n\
+ // Check if masked exception is equal to provided value and write conditionally \n\
+(W) and (1|M0) r3.0<1>:ud cr0.1<0;1,0>:ud ARG(7):ud \n\
+(W) mov (1|M0) f0.0<1>:ud 0x0:ud \n\
+(W) cmp (1|M0) (eq)f0.0 null:ud r3.0<0;1,0>:ud ARG(8):ud \n\
+#if GEN_VER < 2000 // Media Block Write \n\
+(W&f0.0) send.dc1 (16|M0) null r4 src1_null 0 0x40A8000 \n\
+#else // Typed 2D Block Store \n\
+(W&f0.0) send.tgm (16|M0) null r4 null:0 0 0x64000007 \n\
+#endif \n\
+ ", 2, y_offset, 3, value, value, value, value, mask, expected);
+}
+
/**
* gpgpu_shader__end_system_routine:
* @shdr: shader to be modified
diff --git a/lib/gpgpu_shader.h b/lib/gpgpu_shader.h
index e4ca0be4c..76ff4989e 100644
--- a/lib/gpgpu_shader.h
+++ b/lib/gpgpu_shader.h
@@ -74,6 +74,8 @@ void gpgpu_shader__end_system_routine_step_if_eq(struct gpgpu_shader *shdr,
void gpgpu_shader__write_aip(struct gpgpu_shader *shdr, uint32_t y_offset);
void gpgpu_shader__write_dword(struct gpgpu_shader *shdr, uint32_t value,
uint32_t y_offset);
+void gpgpu_shader__write_on_exception(struct gpgpu_shader *shdr, uint32_t dw,
+ uint32_t y_offset, uint32_t mask, uint32_t value);
void gpgpu_shader__label(struct gpgpu_shader *shdr, int label_id);
void gpgpu_shader__jump(struct gpgpu_shader *shdr, int label_id);
void gpgpu_shader__jump_neq(struct gpgpu_shader *shdr, int label_id,
diff --git a/lib/iga64_generated_codes.c b/lib/iga64_generated_codes.c
index c121893db..0cfcae957 100644
--- a/lib/iga64_generated_codes.c
+++ b/lib/iga64_generated_codes.c
@@ -3,7 +3,7 @@
#include "gpgpu_shader.h"
-#define MD5_SUM_IGA64_ASMS 61a15534954fe7c6bd0e983fbfd54c27
+#define MD5_SUM_IGA64_ASMS 88529cc180578939c0b8c4bb29da7db6
struct iga64_template const iga64_code_end_system_routine_step_if_eq[] = {
{ .gen_ver = 2000, .size = 44, .code = (const uint32_t []) {
@@ -93,6 +93,83 @@ struct iga64_template const iga64_code_breakpoint_suppress[] = {
}}
};
+struct iga64_template const iga64_code_write_on_exception[] = {
+ { .gen_ver = 2000, .size = 68, .code = (const uint32_t []) {
+ 0x80000061, 0x05054220, 0x00000000, 0xc0ded003,
+ 0x80000061, 0x05154220, 0x00000000, 0xc0ded004,
+ 0x80000061, 0x05254220, 0x00000000, 0xc0ded005,
+ 0x80000061, 0x05354220, 0x00000000, 0xc0ded006,
+ 0x80000069, 0x02058220, 0x02000014, 0xc0ded000,
+ 0x80000061, 0x02150220, 0x00000064, 0x00000000,
+ 0x80001940, 0x02158220, 0x02000214, 0xc0ded001,
+ 0x80100061, 0x04054220, 0x00000000, 0x00000000,
+ 0x80041a61, 0x04550220, 0x00220205, 0x00000000,
+ 0x80000061, 0x04754220, 0x00000000, 0xc0ded002,
+ 0x80000965, 0x03058220, 0x02008010, 0xc0ded007,
+ 0x80000961, 0x30014220, 0x00000000, 0x00000000,
+ 0x80001a70, 0x00018220, 0x12000304, 0xc0ded008,
+ 0x84134031, 0x00000000, 0xd00e0494, 0x04000000,
+ 0x80000001, 0x00010000, 0x20000000, 0x00000000,
+ 0x80000001, 0x00010000, 0x30000000, 0x00000000,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 1272, .size = 64, .code = (const uint32_t []) {
+ 0x80000061, 0x05054220, 0x00000000, 0xc0ded003,
+ 0x80000061, 0x05154220, 0x00000000, 0xc0ded004,
+ 0x80000061, 0x05254220, 0x00000000, 0xc0ded005,
+ 0x80000061, 0x05354220, 0x00000000, 0xc0ded006,
+ 0x80000069, 0x04058220, 0x02000014, 0xc0ded000,
+ 0x80000061, 0x04150220, 0x00000064, 0x00000000,
+ 0x80001940, 0x04158220, 0x02000414, 0xc0ded001,
+ 0x80000061, 0x04254220, 0x00000000, 0xc0ded002,
+ 0x80000061, 0x04450220, 0x00000054, 0x00000000,
+ 0x80000965, 0x03058220, 0x02008010, 0xc0ded007,
+ 0x80000961, 0x30014220, 0x00000000, 0x00000000,
+ 0x80001a70, 0x00018220, 0x12000304, 0xc0ded008,
+ 0x84134031, 0x00000000, 0xc0000414, 0x02a00000,
+ 0x80000001, 0x00010000, 0x20000000, 0x00000000,
+ 0x80000001, 0x00010000, 0x30000000, 0x00000000,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 1250, .size = 68, .code = (const uint32_t []) {
+ 0x80000061, 0x05054220, 0x00000000, 0xc0ded003,
+ 0x80000061, 0x05254220, 0x00000000, 0xc0ded004,
+ 0x80000061, 0x05454220, 0x00000000, 0xc0ded005,
+ 0x80000061, 0x05654220, 0x00000000, 0xc0ded006,
+ 0x80000069, 0x04058220, 0x02000024, 0xc0ded000,
+ 0x80000061, 0x04250220, 0x000000c4, 0x00000000,
+ 0x80001940, 0x04258220, 0x02000424, 0xc0ded001,
+ 0x80000061, 0x04454220, 0x00000000, 0xc0ded002,
+ 0x80000061, 0x04850220, 0x000000a4, 0x00000000,
+ 0x80000965, 0x03058220, 0x02008020, 0xc0ded007,
+ 0x80000961, 0x30014220, 0x00000000, 0x00000000,
+ 0x80001a70, 0x00018220, 0x12000304, 0xc0ded008,
+ 0x80001a01, 0x00010000, 0x00000000, 0x00000000,
+ 0x81044031, 0x00000000, 0xc0000414, 0x02a00000,
+ 0x80000001, 0x00010000, 0x20000000, 0x00000000,
+ 0x80000001, 0x00010000, 0x30000000, 0x00000000,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 0, .size = 64, .code = (const uint32_t []) {
+ 0x80000061, 0x05054220, 0x00000000, 0xc0ded003,
+ 0x80000061, 0x05254220, 0x00000000, 0xc0ded004,
+ 0x80000061, 0x05454220, 0x00000000, 0xc0ded005,
+ 0x80000061, 0x05654220, 0x00000000, 0xc0ded006,
+ 0x80000069, 0x04058220, 0x02000024, 0xc0ded000,
+ 0x80000061, 0x04250220, 0x000000c4, 0x00000000,
+ 0x80000140, 0x04258220, 0x02000424, 0xc0ded001,
+ 0x80000061, 0x04454220, 0x00000000, 0xc0ded002,
+ 0x80000061, 0x04850220, 0x000000a4, 0x00000000,
+ 0x80000165, 0x03058220, 0x02008020, 0xc0ded007,
+ 0x80000161, 0x30014220, 0x00000000, 0x00000000,
+ 0x80000270, 0x00018220, 0x12000304, 0xc0ded008,
+ 0x8104a031, 0x00000000, 0xc0000414, 0x02a00000,
+ 0x80000001, 0x00010000, 0x20000000, 0x00000000,
+ 0x80000001, 0x00010000, 0x30000000, 0x00000000,
+ 0x80000101, 0x00010000, 0x00000000, 0x00000000,
+ }}
+};
+
struct iga64_template const iga64_code_media_block_write[] = {
{ .gen_ver = 2000, .size = 56, .code = (const uint32_t []) {
0x80000061, 0x05054220, 0x00000000, 0xc0ded003,
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 47/66] lib/gpgpu_shader: Add set/clear exception register (cr0.1) helpers
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (45 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 46/66] lib/gpgpu_shader: Add write_on_exception template Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 48/66] lib/intel_batchbuffer: Add helper to get pointer at specified offset Christoph Manszewski
` (20 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun
From: Andrzej Hajda <andrzej.hajda@intel.com>
To allow enabling and handling exceptions from shader and siplet
proper helpers should be provided.
Signed-off-by: Andrzej Hajda <andrzej.hajda@intel.com>
---
lib/gpgpu_shader.c | 28 ++++++++++++++++++++++++++++
lib/gpgpu_shader.h | 2 ++
lib/iga64_generated_codes.c | 32 +++++++++++++++++++++++++++++++-
3 files changed, 61 insertions(+), 1 deletion(-)
diff --git a/lib/gpgpu_shader.c b/lib/gpgpu_shader.c
index a98abc57e..40161c52b 100644
--- a/lib/gpgpu_shader.c
+++ b/lib/gpgpu_shader.c
@@ -628,6 +628,34 @@ void gpgpu_shader__write_dword(struct gpgpu_shader *shdr, uint32_t value,
", 2, y_offset, 3, value, value, value, value);
}
+/**
+ * gpgpu_shader__clear_exception:
+ * @shdr: shader to be modified
+ * @value: exception bits to be cleared
+ *
+ * Clear provided bits in exception register: cr0.1 &= ~value.
+ */
+void gpgpu_shader__clear_exception(struct gpgpu_shader *shdr, uint32_t value)
+{
+ emit_iga64_code(shdr, clear_exception, " \n\
+(W) and (1|M0) cr0.1<1>:ud cr0.1<0;1,0>:ud ARG(0):ud \n\
+ ", ~value);
+}
+
+/**
+ * gpgpu_shader__set_exception:
+ * @shdr: shader to be modified
+ * @value: exception bits to be set
+ *
+ * Set provided bits in exception register: cr0.1 |= value.
+ */
+void gpgpu_shader__set_exception(struct gpgpu_shader *shdr, uint32_t value)
+{
+ emit_iga64_code(shdr, set_exception, " \n\
+(W) or (1|M0) cr0.1<1>:ud cr0.1<0;1,0>:ud ARG(0):ud \n\
+ ", value);
+}
+
/**
* gpgpu_shader__write_on_exception:
* @shdr: shader to be modified
diff --git a/lib/gpgpu_shader.h b/lib/gpgpu_shader.h
index 76ff4989e..0bbeae66f 100644
--- a/lib/gpgpu_shader.h
+++ b/lib/gpgpu_shader.h
@@ -66,6 +66,8 @@ void gpgpu_shader__common_target_write(struct gpgpu_shader *shdr,
uint32_t y_offset, const uint32_t value[4]);
void gpgpu_shader__common_target_write_u32(struct gpgpu_shader *shdr,
uint32_t y_offset, uint32_t value);
+void gpgpu_shader__clear_exception(struct gpgpu_shader *shdr, uint32_t value);
+void gpgpu_shader__set_exception(struct gpgpu_shader *shdr, uint32_t value);
void gpgpu_shader__end_system_routine(struct gpgpu_shader *shdr,
bool breakpoint_suppress);
void gpgpu_shader__end_system_routine_step_if_eq(struct gpgpu_shader *shdr,
diff --git a/lib/iga64_generated_codes.c b/lib/iga64_generated_codes.c
index 0cfcae957..e9bb80785 100644
--- a/lib/iga64_generated_codes.c
+++ b/lib/iga64_generated_codes.c
@@ -3,7 +3,7 @@
#include "gpgpu_shader.h"
-#define MD5_SUM_IGA64_ASMS 88529cc180578939c0b8c4bb29da7db6
+#define MD5_SUM_IGA64_ASMS 6cfe013e2a99076bcdf69ecdbf4333cf
struct iga64_template const iga64_code_end_system_routine_step_if_eq[] = {
{ .gen_ver = 2000, .size = 44, .code = (const uint32_t []) {
@@ -170,6 +170,36 @@ struct iga64_template const iga64_code_write_on_exception[] = {
}}
};
+struct iga64_template const iga64_code_set_exception[] = {
+ { .gen_ver = 1272, .size = 8, .code = (const uint32_t []) {
+ 0x80000966, 0x80118220, 0x02008010, 0xc0ded000,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 1250, .size = 8, .code = (const uint32_t []) {
+ 0x80000966, 0x80218220, 0x02008020, 0xc0ded000,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 0, .size = 8, .code = (const uint32_t []) {
+ 0x80000166, 0x80218220, 0x02008020, 0xc0ded000,
+ 0x80000101, 0x00010000, 0x00000000, 0x00000000,
+ }}
+};
+
+struct iga64_template const iga64_code_clear_exception[] = {
+ { .gen_ver = 1272, .size = 8, .code = (const uint32_t []) {
+ 0x80000965, 0x80118220, 0x02008010, 0xc0ded000,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 1250, .size = 8, .code = (const uint32_t []) {
+ 0x80000965, 0x80218220, 0x02008020, 0xc0ded000,
+ 0x80000901, 0x00010000, 0x00000000, 0x00000000,
+ }},
+ { .gen_ver = 0, .size = 8, .code = (const uint32_t []) {
+ 0x80000165, 0x80218220, 0x02008020, 0xc0ded000,
+ 0x80000101, 0x00010000, 0x00000000, 0x00000000,
+ }}
+};
+
struct iga64_template const iga64_code_media_block_write[] = {
{ .gen_ver = 2000, .size = 56, .code = (const uint32_t []) {
0x80000061, 0x05054220, 0x00000000, 0xc0ded003,
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 48/66] lib/intel_batchbuffer: Add helper to get pointer at specified offset
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (46 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 47/66] lib/gpgpu_shader: Add set/clear exception register (cr0.1) helpers Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 49/66] lib/gpgpu_shader: Allow enabling illegal opcode exceptions in shader Christoph Manszewski
` (19 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun
From: Andrzej Hajda <andrzej.hajda@intel.com>
The helper will be used to access data placed in batchbuffer.
Signed-off-by: Andrzej Hajda <andrzej.hajda@intel.com>
Cc: Mika Kuoppala <mika.kuoppala@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
lib/intel_batchbuffer.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/lib/intel_batchbuffer.h b/lib/intel_batchbuffer.h
index cb32206e5..7caf6c518 100644
--- a/lib/intel_batchbuffer.h
+++ b/lib/intel_batchbuffer.h
@@ -353,6 +353,11 @@ static inline uint32_t intel_bb_offset(struct intel_bb *ibb)
return (uint32_t) ((uint8_t *) ibb->ptr - (uint8_t *) ibb->batch);
}
+static inline void *intel_bb_ptr_get(struct intel_bb *ibb, uint32_t offset)
+{
+ return ((uint8_t *) ibb->batch + offset);
+}
+
static inline void intel_bb_ptr_set(struct intel_bb *ibb, uint32_t offset)
{
ibb->ptr = (void *) ((uint8_t *) ibb->batch + offset);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 49/66] lib/gpgpu_shader: Allow enabling illegal opcode exceptions in shader
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (47 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 48/66] lib/intel_batchbuffer: Add helper to get pointer at specified offset Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 50/66] tests/xe_exec_sip: Rework invalid instruction tests Christoph Manszewski
` (18 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun
From: Andrzej Hajda <andrzej.hajda@intel.com>
Illegal opcode exceptions can be enabled in interface descriptor data
passed to COMPUTE_WALKER instruction.
Signed-off-by: Andrzej Hajda <andrzej.hajda@intel.com>
Cc: Mika Kuoppala <mika.kuoppala@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
lib/gpgpu_shader.c | 4 ++++
lib/gpgpu_shader.h | 1 +
2 files changed, 5 insertions(+)
diff --git a/lib/gpgpu_shader.c b/lib/gpgpu_shader.c
index 40161c52b..e53c61553 100644
--- a/lib/gpgpu_shader.c
+++ b/lib/gpgpu_shader.c
@@ -103,6 +103,7 @@ __xelp_gpgpu_execfunc(struct intel_bb *ibb,
struct gpgpu_shader *sip,
uint64_t ring, bool explicit_engine)
{
+ struct gen8_interface_descriptor_data *idd;
uint32_t interface_descriptor, sip_offset;
uint64_t engine;
@@ -113,6 +114,8 @@ __xelp_gpgpu_execfunc(struct intel_bb *ibb,
interface_descriptor = gen8_fill_interface_descriptor(ibb, target,
shdr->instr,
4 * shdr->size);
+ idd = intel_bb_ptr_get(ibb, interface_descriptor);
+ idd->desc2.illegal_opcode_exception_enable = shdr->illegal_opcode_exception_enable;
if (sip && sip->size)
sip_offset = fill_sip(ibb, sip->instr, 4 * sip->size);
@@ -163,6 +166,7 @@ __xehp_gpgpu_execfunc(struct intel_bb *ibb,
xehp_fill_interface_descriptor(ibb, target, shdr->instr,
4 * shdr->size, &idd);
+ idd.desc2.illegal_opcode_exception_enable = shdr->illegal_opcode_exception_enable;
if (sip && sip->size)
sip_offset = fill_sip(ibb, sip->instr, 4 * sip->size);
diff --git a/lib/gpgpu_shader.h b/lib/gpgpu_shader.h
index 0bbeae66f..26a117a0b 100644
--- a/lib/gpgpu_shader.h
+++ b/lib/gpgpu_shader.h
@@ -22,6 +22,7 @@ struct gpgpu_shader {
uint32_t (*instr)[4];
};
struct igt_map *labels;
+ bool illegal_opcode_exception_enable;
};
struct iga64_template {
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 50/66] tests/xe_exec_sip: Rework invalid instruction tests
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (48 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 49/66] lib/gpgpu_shader: Allow enabling illegal opcode exceptions in shader Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 51/66] lib/intel_batchbuffer: Add support for long-running mode execution Christoph Manszewski
` (17 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun
From: Andrzej Hajda <andrzej.hajda@intel.com>
The tests depended on undefined behavior of GPU. Invalid instruction
provided by the test has 29th bit set, which on Xe2 causes SIP call without
providing any exception reason and AIP address, unless eudebug is enabled,
in such case breakpoint exception is signalled.
Xe2 and earlier gens are able to handle very limited set of invalid
instructions - only illegal and undefined opcodes, other errors in
instruction can cause undefined behavior.
Illegal/undefined opcode results in:
- setting illegal opcode status bit - cr0.1[28],
- calling SIP if illegal opcode bit is enabled - cr0.1[12].
cr0.1[12] can be enabled directly from the thread or by thread dispatcher
from Interface Descriptor Data provided to COMPUTE_WALKER instruction.
Re-worked tests works similar way to OOB tests:
- check if SIP is not called when exception is not enabled,
- check if SIP is called when exception is enabled from EU thread,
- check if SIP is called when exception is enabled from COMPUTE_WALKER.
Signed-off-by: Andrzej Hajda <andrzej.hajda@intel.com>
Cc: Mika Kuoppala <mika.kuoppala@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
tests/intel/xe_exec_sip.c | 70 ++++++++++++++++++++++++++++++++++-----
1 file changed, 62 insertions(+), 8 deletions(-)
diff --git a/tests/intel/xe_exec_sip.c b/tests/intel/xe_exec_sip.c
index 35d65bcc4..0db0dc4b8 100644
--- a/tests/intel/xe_exec_sip.c
+++ b/tests/intel/xe_exec_sip.c
@@ -38,14 +38,22 @@
#define SHADER_BREAKPOINT 0
#define SHADER_WRITE 1
#define SHADER_WAIT 2
-#define SHADER_HANG 3
-#define SIP_WRITE 4
-#define SIP_NULL 5
-#define SIP_WAIT 6
-#define SIP_HEAVY 7
+#define SHADER_INV_INSTR_DISABLED 3
+#define SHADER_INV_INSTR_THREAD_ENABLED 4
+#define SHADER_INV_INSTR_WALKER_ENABLED 5
+#define SHADER_HANG 6
+#define SIP_WRITE 7
+#define SIP_NULL 8
+#define SIP_WAIT 9
+#define SIP_HEAVY 10
+#define SIP_INV_INSTR 11
#define F_SUBMIT_TWICE (1 << 0)
+/* Control Register cr0.1 bits for exception handling */
+#define ILLEGAL_OPCODE_ENABLE BIT(12)
+#define ILLEGAL_OPCODE_STATUS BIT(28)
+
static struct intel_buf *
create_fill_buf(int fd, int width, int height, uint8_t color)
{
@@ -68,8 +76,12 @@ create_fill_buf(int fd, int width, int height, uint8_t color)
static struct gpgpu_shader *get_shader(int fd, const int shadertype)
{
static struct gpgpu_shader *shader;
+ uint32_t bad;
shader = gpgpu_shader_create(fd);
+ if (shadertype == SHADER_INV_INSTR_WALKER_ENABLED)
+ shader->illegal_opcode_exception_enable = true;
+
gpgpu_shader__write_dword(shader, SHADER_CANARY, 0);
switch (shadertype) {
@@ -87,6 +99,21 @@ static struct gpgpu_shader *get_shader(int fd, const int shadertype)
gpgpu_shader__nop(shader);
gpgpu_shader__breakpoint(shader);
break;
+ case SHADER_INV_INSTR_THREAD_ENABLED:
+ gpgpu_shader__set_exception(shader, ILLEGAL_OPCODE_ENABLE);
+ /* fall through */
+ case SHADER_INV_INSTR_DISABLED:
+ case SHADER_INV_INSTR_WALKER_ENABLED:
+ bad = (shadertype == SHADER_INV_INSTR_DISABLED) ? ILLEGAL_OPCODE_ENABLE : 0;
+ gpgpu_shader__write_on_exception(shader, 1, 0, ILLEGAL_OPCODE_ENABLE, bad);
+ gpgpu_shader__nop(shader);
+ gpgpu_shader__nop(shader);
+ /* modify second nop, set only opcode bits[6:0] */
+ shader->instr[shader->size/4 - 1][0] = 0x7f;
+ /* SIP should clear exception bit */
+ bad = ILLEGAL_OPCODE_STATUS;
+ gpgpu_shader__write_on_exception(shader, 2, 0, ILLEGAL_OPCODE_STATUS, bad);
+ break;
}
gpgpu_shader__eot(shader);
@@ -127,6 +154,9 @@ static struct gpgpu_shader *get_sip(int fd, const int siptype,
gpgpu_shader__wait(sip);
break;
+ case SIP_INV_INSTR:
+ gpgpu_shader__write_on_exception(sip, 1, y_offset, ILLEGAL_OPCODE_STATUS, 0);
+ break;
}
gpgpu_shader__end_system_routine(sip, shadertype == SHADER_BREAKPOINT);
@@ -160,7 +190,7 @@ static void check_fill_buf(uint8_t *ptr, const int width, const int x,
}
static int check_buf(int fd, uint32_t handle, int width, int height,
- int siptype, uint8_t poison_c)
+ int shadertype, int siptype, uint8_t poison_c)
{
unsigned int sz = ALIGN(width * height, 4096);
int thread_count = 0, sip_count = 0;
@@ -194,7 +224,10 @@ static int check_buf(int fd, uint32_t handle, int width, int height,
}
igt_assert(thread_count);
- if (siptype != SIP_NULL && xe_eudebug_debugger_available(fd))
+ if (shadertype == SHADER_INV_INSTR_DISABLED)
+ igt_assert(!sip_count);
+ else if ((siptype != SIP_NULL && xe_eudebug_debugger_available(fd)) ||
+ (siptype == SIP_INV_INSTR && shadertype != SHADER_INV_INSTR_DISABLED))
igt_assert_f(thread_count == sip_count,
"Thread and SIP count mismatch, %d != %d\n",
thread_count, sip_count);
@@ -285,6 +318,18 @@ xe_sysfs_get_job_timeout_ms(int fd, struct drm_xe_engine_class_instance *eci)
* SUBTEST: wait-writesip-nodebug
* Description: verify that we don't enter SIP after wait with debugging disabled.
*
+ * SUBTEST: invalidinstr-disabled
+ * Description: Verify that we don't enter SIP after running into an invalid
+ * instruction when exception is not enabled.
+ *
+ * SUBTEST: invalidinstr-thread-enabled
+ * Description: Verify that we enter SIP after running into an invalid instruction
+ * when exception is enabled from thread.
+ *
+ * SUBTEST: invalidinstr-walker-enabled
+ * Description: Verify that we enter SIP after running into an invalid instruction
+ * when exception is enabled from COMPUTE_WALKER.
+ *
* SUBTEST: breakpoint-writesip-nodebug
* Description: verify that we don't enter SIP after hitting breakpoint in shader
* when debugging is disabled.
@@ -344,7 +389,7 @@ static void test_sip(int shader, int sip, struct drm_xe_engine_class_instance *e
intel_bb_sync(ibb);
igt_assert_lt_u64(igt_nsec_elapsed(&ts), timeout);
- dispatched = check_buf(fd, handle, width, height, sip, COLOR_C4);
+ dispatched = check_buf(fd, handle, width, height, shader, sip, COLOR_C4);
check_usercoredump(fd, sip, dispatched);
gem_close(fd, handle);
@@ -396,6 +441,15 @@ igt_main
test_render_and_compute("wait-writesip-nodebug", fd, eci)
test_sip(SHADER_WAIT, SIP_WRITE, eci, 0);
+ test_render_and_compute("invalidinstr-disabled", fd, eci)
+ test_sip(SHADER_INV_INSTR_DISABLED, SIP_INV_INSTR, eci, 0);
+
+ test_render_and_compute("invalidinstr-thread-enabled", fd, eci)
+ test_sip(SHADER_INV_INSTR_THREAD_ENABLED, SIP_INV_INSTR, eci, 0);
+
+ test_render_and_compute("invalidinstr-walker-enabled", fd, eci)
+ test_sip(SHADER_INV_INSTR_WALKER_ENABLED, SIP_INV_INSTR, eci, 0);
+
test_render_and_compute("breakpoint-writesip-nodebug", fd, eci)
test_sip(SHADER_BREAKPOINT, SIP_WRITE, eci, 0);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 51/66] lib/intel_batchbuffer: Add support for long-running mode execution
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (49 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 50/66] tests/xe_exec_sip: Rework invalid instruction tests Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 52/66] tests/xe_eudebug_online: Debug client which runs workloads on EU Christoph Manszewski
` (16 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
From: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
To execute in lr (long-running) mode, apart from setting
'DRM_XE_VM_CREATE_FLAG_LR_MODE' flag during vm creation, it is required
to use 'DRM_XE_SYNC_TYPE_USER_FENCE' syncs with vm_bind and xe_exec
ioctls.
Make it possible to execute batch buffers via intel_bb_exec() in lr mode
by setting the 'lr_mode' field with the supplied setter.
Signed-off-by: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
---
lib/intel_batchbuffer.c | 153 ++++++++++++++++++++++++++++++++++++++--
lib/intel_batchbuffer.h | 17 +++++
2 files changed, 165 insertions(+), 5 deletions(-)
diff --git a/lib/intel_batchbuffer.c b/lib/intel_batchbuffer.c
index 824e92831..43bf5b04b 100644
--- a/lib/intel_batchbuffer.c
+++ b/lib/intel_batchbuffer.c
@@ -992,6 +992,7 @@ __intel_bb_create(int fd, uint32_t ctx, uint32_t vm, const intel_ctx_cfg_t *cfg,
igt_assert(ibb->batch);
ibb->ptr = ibb->batch;
ibb->fence = -1;
+ ibb->user_fence_offset = -1;
/* Cache context configuration */
if (cfg) {
@@ -1455,7 +1456,7 @@ int intel_bb_sync(struct intel_bb *ibb)
{
int ret;
- if (ibb->fence < 0 && !ibb->engine_syncobj)
+ if (ibb->fence < 0 && !ibb->engine_syncobj && ibb->user_fence_offset < 0)
return 0;
if (ibb->fence >= 0) {
@@ -1464,10 +1465,28 @@ int intel_bb_sync(struct intel_bb *ibb)
close(ibb->fence);
ibb->fence = -1;
}
- } else {
- igt_assert_neq(ibb->engine_syncobj, 0);
+ } else if(ibb->engine_syncobj) {
ret = syncobj_wait_err(ibb->fd, &ibb->engine_syncobj,
1, INT64_MAX, 0);
+ } else {
+ int64_t timeout = -1;
+ uint64_t *sync_data;
+ void *map;
+
+ igt_assert(ibb->user_fence_offset >= 0);
+
+ map = xe_bo_map(ibb->fd, ibb->handle, ibb->size);
+ sync_data = (void*)((uint8_t *)map + ibb->user_fence_offset);
+
+ ret = __xe_wait_ufence(ibb->fd, sync_data, ibb->user_fence_value,
+ ibb->ctx ?: ibb->engine_id, &timeout);
+
+ gem_munmap(map, ibb->size);
+ ibb->user_fence_offset = -1;
+
+ /* Workload finished forcibly, but finished none the less */
+ if (ret == -EIO)
+ ret = 0;
}
return ret;
@@ -2441,6 +2460,126 @@ __xe_bb_exec(struct intel_bb *ibb, uint64_t flags, bool sync)
return 0;
}
+static int
+__xe_lr_bb_exec(struct intel_bb *ibb, uint64_t flags, bool sync)
+{
+ uint32_t engine = flags & (I915_EXEC_BSD_MASK | I915_EXEC_RING_MASK);
+ uint32_t engine_id;
+#define USER_FENCE_VALUE 0xdeadbeefdeadbeefull
+ /*
+ * LR mode vm_bind requires to use DRM_XE_SYNC_TYPE_USER_FENCE type sync
+ * LR mode xe_exec requires to use DRM_XE_SYNC_TYPE_USER_FENCE type sync
+ */
+ struct drm_xe_sync syncs[2] = {
+ { .type = DRM_XE_SYNC_TYPE_USER_FENCE,
+ .flags = DRM_XE_SYNC_FLAG_SIGNAL,
+ .timeline_value = USER_FENCE_VALUE
+ },
+ { .type = DRM_XE_SYNC_TYPE_USER_FENCE,
+ .flags = DRM_XE_SYNC_FLAG_SIGNAL,
+ .timeline_value = USER_FENCE_VALUE
+ },
+ };
+ struct drm_xe_vm_bind_op *bind_ops;
+ struct {
+ uint64_t vm_sync;
+ uint64_t exec_sync;
+ } *sync_data;
+ uint32_t sync_offset;
+ uint64_t ibb_addr, vm_sync_addr, exec_sync_addr;
+ void *map;
+
+ igt_assert_eq(ibb->num_relocs, 0);
+ igt_assert_eq(ibb->xe_bound, false);
+
+ if (ibb->ctx) {
+ engine_id = ibb->ctx;
+ } else if (ibb->last_engine != engine) {
+ struct drm_xe_engine_class_instance inst = { };
+
+ inst.engine_instance =
+ (flags & I915_EXEC_BSD_MASK) >> I915_EXEC_BSD_SHIFT;
+
+ switch (flags & I915_EXEC_RING_MASK) {
+ case I915_EXEC_DEFAULT:
+ case I915_EXEC_BLT:
+ inst.engine_class = DRM_XE_ENGINE_CLASS_COPY;
+ break;
+ case I915_EXEC_BSD:
+ inst.engine_class = DRM_XE_ENGINE_CLASS_VIDEO_DECODE;
+ break;
+ case I915_EXEC_RENDER:
+ if (xe_has_engine_class(ibb->fd, DRM_XE_ENGINE_CLASS_RENDER))
+ inst.engine_class = DRM_XE_ENGINE_CLASS_RENDER;
+ else
+ inst.engine_class = DRM_XE_ENGINE_CLASS_COMPUTE;
+ break;
+ case I915_EXEC_VEBOX:
+ inst.engine_class = DRM_XE_ENGINE_CLASS_VIDEO_ENHANCE;
+ break;
+ default:
+ igt_assert_f(false, "Unknown engine: %x", (uint32_t) flags);
+ }
+ igt_debug("Run on %s\n", xe_engine_class_string(inst.engine_class));
+
+ if (ibb->engine_id)
+ xe_exec_queue_destroy(ibb->fd, ibb->engine_id);
+
+ ibb->engine_id = engine_id =
+ xe_exec_queue_create(ibb->fd, ibb->vm_id, &inst, 0);
+ } else {
+ engine_id = ibb->engine_id;
+ }
+ ibb->last_engine = engine;
+
+ /* User fence add for sync: sync.addr has a quadword align limitation */
+ intel_bb_ptr_align(ibb, 8);
+ sync_offset = intel_bb_offset(ibb);
+ intel_bb_ptr_add(ibb, sizeof(*sync_data));
+
+ map = xe_bo_map(ibb->fd, ibb->handle, ibb->size);
+ memcpy(map, ibb->batch, ibb->size);
+
+ sync_data = (void*)((uint8_t *)map + sync_offset);
+ /* vm_sync userfence userspace address. */
+ vm_sync_addr = to_user_pointer(&sync_data->vm_sync);
+ ibb_addr = ibb->batch_offset;
+ /* exec_sync userfence ppgtt address. */
+ exec_sync_addr = ibb_addr + sync_offset + sizeof(uint64_t);
+ syncs[0].addr = vm_sync_addr;
+ syncs[1].addr = exec_sync_addr;
+
+ if (ibb->num_objects > 1) {
+ bind_ops = xe_alloc_bind_ops(ibb, DRM_XE_VM_BIND_OP_MAP, 0, 0);
+ xe_vm_bind_array(ibb->fd, ibb->vm_id, 0, bind_ops,
+ ibb->num_objects, syncs, 1);
+ free(bind_ops);
+ } else {
+ igt_debug("bind: MAP\n");
+ igt_debug(" handle: %u, offset: %llx, size: %llx\n",
+ ibb->handle, (long long)ibb->batch_offset,
+ (long long)ibb->size);
+ xe_vm_bind_async(ibb->fd, ibb->vm_id, 0, ibb->handle, 0,
+ ibb->batch_offset, ibb->size, syncs, 1);
+ }
+
+ /* use default vm_bind_exec_queue */
+ xe_wait_ufence(ibb->fd, &sync_data->vm_sync, USER_FENCE_VALUE, 0, -1);
+ gem_munmap(map, ibb->size);
+
+ ibb->xe_bound = true;
+ ibb->user_fence_value = USER_FENCE_VALUE;
+ ibb->user_fence_offset = sync_offset + sizeof(uint64_t);
+
+ xe_exec_sync(ibb->fd, engine_id, ibb->batch_offset, &syncs[1], 1);
+
+ if (sync)
+ intel_bb_sync(ibb);
+
+ return 0;
+}
+
+
/*
* __intel_bb_exec:
* @ibb: pointer to intel_bb
@@ -2541,8 +2680,12 @@ void intel_bb_exec(struct intel_bb *ibb, uint32_t end_offset,
if (ibb->driver == INTEL_DRIVER_I915)
igt_assert_eq(__intel_bb_exec(ibb, end_offset, flags, sync), 0);
- else
- igt_assert_eq(__xe_bb_exec(ibb, flags, sync), 0);
+ else {
+ if (intel_bb_get_lr_mode(ibb))
+ igt_assert_eq(__xe_lr_bb_exec(ibb, flags, sync), 0);
+ else
+ igt_assert_eq(__xe_bb_exec(ibb, flags, sync), 0);
+ }
}
/**
diff --git a/lib/intel_batchbuffer.h b/lib/intel_batchbuffer.h
index 7caf6c518..051c336de 100644
--- a/lib/intel_batchbuffer.h
+++ b/lib/intel_batchbuffer.h
@@ -303,6 +303,11 @@ struct intel_bb {
* is not thread-safe.
*/
int32_t refcount;
+
+ /* long running mode */
+ bool lr_mode;
+ int64_t user_fence_offset;
+ uint64_t user_fence_value;
};
struct intel_bb *
@@ -421,6 +426,18 @@ static inline uint32_t intel_bb_pxp_appid(struct intel_bb *ibb)
return ibb->pxp.appid;
}
+static inline void intel_bb_set_lr_mode(struct intel_bb *ibb, bool lr_mode)
+{
+ igt_assert(ibb);
+ ibb->lr_mode = lr_mode;
+}
+
+static inline bool intel_bb_get_lr_mode(struct intel_bb *ibb)
+{
+ igt_assert(ibb);
+ return ibb->lr_mode;
+}
+
struct drm_i915_gem_exec_object2 *
intel_bb_add_object(struct intel_bb *ibb, uint32_t handle, uint64_t size,
uint64_t offset, uint64_t alignment, bool write);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 52/66] tests/xe_eudebug_online: Debug client which runs workloads on EU
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (50 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 51/66] lib/intel_batchbuffer: Add support for long-running mode execution Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 53/66] tests/xe_eudebug_online: Set dynamic breakpoint on interrupt-all Christoph Manszewski
` (15 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
1# Sanity check for attention events
Introduce first online scenario (basic-attention-event)
in which we schedule EU workload with breakpoint bit set.
We expect to get eu attention and peacefully resume workload.
2# Basic coverage for eu thread control
Eu thread control is an ioctl which allows the debugger to
interfere with eu thread execution. Provide initial coverage for
that functionality Exercise interrupt-all, stopped,
and resume with bunch of different granularities.
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Cc: Christoph Manszewski <christoph.manszewski@intel.com> #1
Cc: Mika Kuoppala <mika.kuoppala@intel.com> #2
---
tests/intel/xe_eudebug_online.c | 977 ++++++++++++++++++++++++++++++++
tests/meson.build | 1 +
2 files changed, 978 insertions(+)
create mode 100644 tests/intel/xe_eudebug_online.c
diff --git a/tests/intel/xe_eudebug_online.c b/tests/intel/xe_eudebug_online.c
new file mode 100644
index 000000000..8791b29fa
--- /dev/null
+++ b/tests/intel/xe_eudebug_online.c
@@ -0,0 +1,977 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+/**
+ * TEST: Tests for eudebug online functionality
+ * Category: Core
+ * Mega feature: EUdebug
+ * Sub-category: EUdebug tests
+ * Functionality: eu kernel debug
+ * Test category: functionality test
+ */
+
+#include "xe/xe_eudebug.h"
+#include "xe/xe_ioctl.h"
+#include "xe/xe_query.h"
+#include "igt.h"
+#include "intel_pat.h"
+#include "intel_mocs.h"
+#include "gpgpu_shader.h"
+
+#define SHADER_BREAKPOINT (1 << 0)
+#define SHADER_LOOP (1 << 1)
+#define TRIGGER_RESUME_DELAYED (1 << 29)
+#define TRIGGER_RESUME_DSS (1 << 30)
+#define TRIGGER_RESUME_ONE (1 << 31)
+
+#define STEERING_END_LOOP 0xdeadca11
+
+#define SHADER_CANARY 0x01010101
+
+#define WALKER_X_DIM 4
+#define WALKER_ALIGNMENT 16
+#define SIMD_SIZE 16
+
+#define STARTUP_TIMEOUT_MS 3000
+
+#define PAGE_SIZE 4096
+
+struct dim_t {
+ uint32_t x;
+ uint32_t y;
+ uint32_t alignment;
+};
+
+static struct dim_t walker_dimensions(int threads)
+{
+ uint32_t x_dim = min_t(x_dim, threads, WALKER_X_DIM);
+ struct dim_t ret = {
+ .x = x_dim,
+ .y = threads / x_dim,
+ .alignment = WALKER_ALIGNMENT
+ };
+
+ return ret;
+}
+
+static struct dim_t surface_dimensions(int threads)
+{
+ struct dim_t ret = walker_dimensions(threads);
+
+ ret.y = max_t(ret.y, threads/ret.x, 4);
+ ret.x *= SIMD_SIZE;
+ ret.alignment *= SIMD_SIZE;
+
+ return ret;
+}
+
+static uint32_t steering_offset(int threads)
+{
+ struct dim_t w = walker_dimensions(threads);
+
+ return ALIGN(w.x, w.alignment) * w.y * 4;
+}
+
+static struct intel_buf *create_uc_buf(int fd, int width, int height)
+{
+ struct intel_buf *buf;
+
+ buf = intel_buf_create_full(buf_ops_create(fd), 0, width/4, height,
+ 32, 0, I915_TILING_NONE, 0, 0, 0,
+ vram_if_possible(fd, 0),
+ DEFAULT_PAT_INDEX, DEFAULT_MOCS_INDEX);
+
+ return buf;
+}
+
+static int get_number_of_threads(uint64_t flags)
+{
+ if (flags & (TRIGGER_RESUME_ONE))
+ return 32;
+
+ return 512;
+}
+
+static struct gpgpu_shader *get_shader(int fd, const unsigned int flags)
+{
+ struct dim_t w_dim = walker_dimensions(get_number_of_threads(flags));
+ static struct gpgpu_shader *shader;
+
+ shader = gpgpu_shader_create(fd);
+
+ gpgpu_shader__write_dword(shader, SHADER_CANARY, 0);
+ if (flags & SHADER_BREAKPOINT) {
+ gpgpu_shader__nop(shader);
+ gpgpu_shader__breakpoint(shader);
+ } else if (flags & SHADER_LOOP) {
+ gpgpu_shader__label(shader, 0);
+ gpgpu_shader__write_dword(shader, SHADER_CANARY, 0);
+ gpgpu_shader__jump_neq(shader, 0, w_dim.y, STEERING_END_LOOP);
+ gpgpu_shader__write_dword(shader, SHADER_CANARY, 0);
+ }
+
+ gpgpu_shader__eot(shader);
+ return shader;
+}
+
+static struct gpgpu_shader *get_sip(int fd)
+{
+ static struct gpgpu_shader *sip;
+
+ sip = gpgpu_shader_create(fd);
+ gpgpu_shader__write_aip(sip, 0);
+
+ gpgpu_shader__wait(sip);
+ gpgpu_shader__end_system_routine(sip, true);
+ return sip;
+}
+
+static int count_set_bits(void *ptr, size_t size)
+{
+ uint8_t *p = ptr;
+ int count = 0;
+ int i, j;
+
+ for (i = 0; i < size; i++)
+ for (j = 0; j < 8; j++)
+ count += !!(p[i] & (1 << j));
+
+ return count;
+}
+
+static int count_canaries_eq(uint32_t *ptr, struct dim_t w_dim, uint32_t value)
+{
+ int count = 0;
+ int x, y;
+
+ for (x = 0; x < w_dim.x; x++)
+ for (y = 0; y < w_dim.y; y++)
+ if (READ_ONCE(ptr[x + ALIGN(w_dim.x, w_dim.alignment) * y]) == value)
+ count++;
+
+ return count;
+}
+
+static int count_canaries_neq(uint32_t *ptr, struct dim_t w_dim, uint32_t value)
+{
+ return w_dim.x * w_dim.y - count_canaries_eq(ptr, w_dim, value);
+}
+
+static const char *td_ctl_cmd_to_str(uint32_t cmd)
+{
+ switch (cmd) {
+ case DRM_XE_EUDEBUG_EU_CONTROL_CMD_INTERRUPT_ALL:
+ return "interrupt all";
+ case DRM_XE_EUDEBUG_EU_CONTROL_CMD_STOPPED:
+ return "stopped";
+ case DRM_XE_EUDEBUG_EU_CONTROL_CMD_RESUME:
+ return "resume";
+ default:
+ return "unknown command";
+ }
+}
+
+static int __eu_ctl(int debugfd, uint64_t client,
+ uint64_t exec_queue, uint64_t lrc,
+ uint8_t *bitmask, uint32_t *bitmask_size,
+ uint32_t cmd, uint64_t *seqno)
+{
+ struct drm_xe_eudebug_eu_control control = {
+ .client_handle = lower_32_bits(client),
+ .exec_queue_handle = exec_queue,
+ .lrc_handle = lrc,
+ .cmd = cmd,
+ .bitmask_ptr = to_user_pointer(bitmask),
+ };
+ int ret;
+
+ if (bitmask_size)
+ control.bitmask_size = *bitmask_size;
+
+ ret = igt_ioctl(debugfd, DRM_XE_EUDEBUG_IOCTL_EU_CONTROL, &control);
+
+ if (ret < 0)
+ return -errno;
+
+ igt_debug("EU CONTROL[%llu]: %s\n", control.seqno, td_ctl_cmd_to_str(cmd));
+
+ if (bitmask_size)
+ *bitmask_size = control.bitmask_size;
+
+ if (seqno)
+ *seqno = control.seqno;
+
+ return 0;
+
+}
+
+static uint64_t eu_ctl(int debugfd, uint64_t client,
+ uint64_t exec_queue, uint64_t lrc,
+ uint8_t *bitmask, uint32_t *bitmask_size, uint32_t cmd)
+{
+ uint64_t seqno;
+
+ igt_assert_eq(__eu_ctl(debugfd, client, exec_queue, lrc, bitmask,
+ bitmask_size, cmd, &seqno), 0);
+
+ return seqno;
+}
+
+static bool intel_gen_needs_resume_wa(int fd)
+{
+ const uint32_t id = intel_get_drm_devid(fd);
+
+ return intel_gen(id) == 12 && intel_graphics_ver(id) < IP_VER(12, 55);
+}
+
+static uint64_t eu_ctl_resume(int fd, int debugfd, uint64_t client,
+ uint64_t exec_queue, uint64_t lrc,
+ uint8_t *bitmask, uint32_t bitmask_size)
+{
+ int i;
+
+ /* XXX: WA for hsd: 14011332042 */
+ if (intel_gen_needs_resume_wa(fd)) {
+ uint32_t *att_reg_half = (uint32_t *)bitmask;
+
+ for (i = 0; i < bitmask_size / sizeof(uint32_t); i += 2) {
+ att_reg_half[i] |= att_reg_half[i + 1];
+ att_reg_half[i + 1] |= att_reg_half[i];
+ }
+ }
+
+ return eu_ctl(debugfd, client, exec_queue, lrc, bitmask, &bitmask_size,
+ DRM_XE_EUDEBUG_EU_CONTROL_CMD_RESUME);
+}
+
+static inline uint64_t eu_ctl_stopped(int debugfd, uint64_t client,
+ uint64_t exec_queue, uint64_t lrc,
+ uint8_t *bitmask, uint32_t *bitmask_size)
+{
+ return eu_ctl(debugfd, client, exec_queue, lrc, bitmask, bitmask_size,
+ DRM_XE_EUDEBUG_EU_CONTROL_CMD_STOPPED);
+}
+
+static inline uint64_t eu_ctl_interrupt_all(int debugfd, uint64_t client,
+ uint64_t exec_queue, uint64_t lrc)
+{
+ return eu_ctl(debugfd, client, exec_queue, lrc, NULL, 0,
+ DRM_XE_EUDEBUG_EU_CONTROL_CMD_INTERRUPT_ALL);
+}
+
+struct online_debug_data {
+ pthread_mutex_t mutex;
+ /* client in */
+ struct drm_xe_engine_class_instance hwe;
+ /* client out */
+ int threads_count;
+ /* debugger internals */
+ uint64_t client_handle;
+ uint64_t exec_queue_handle;
+ uint64_t lrc_handle;
+ uint64_t target_offset;
+ size_t target_size;
+ uint64_t bb_offset;
+ size_t bb_size;
+ int vm_fd;
+ struct timespec exception_arrived;
+ int last_eu_control_seqno;
+};
+
+static struct online_debug_data *
+online_debug_data_create(struct drm_xe_engine_class_instance *hwe)
+{
+ struct online_debug_data *data;
+
+ data = mmap(0, ALIGN(sizeof(*data), PAGE_SIZE),
+ PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
+ memcpy(&data->hwe, hwe, sizeof(*hwe));
+ pthread_mutex_init(&data->mutex, NULL);
+ data->client_handle = -1ULL;
+ data->exec_queue_handle = -1ULL;
+ data->lrc_handle = -1ULL;
+ data->vm_fd = -1;
+
+ return data;
+}
+
+static void online_debug_data_destroy(struct online_debug_data *data)
+{
+
+ munmap(data, ALIGN(sizeof(*data), PAGE_SIZE));
+}
+
+static void eu_attention_debug_trigger(struct xe_eudebug_debugger *d,
+ struct drm_xe_eudebug_event *e)
+{
+ struct drm_xe_eudebug_event_eu_attention *att = (void *) e;
+ uint32_t *ptr = (uint32_t *) att->bitmask;
+
+ igt_debug("EVENT[%llu] eu-attenttion; threads=%d "
+ "client[%llu], exec_queue[%llu], lrc[%llu], bitmask_size[%d]\n",
+ att->base.seqno, count_set_bits(att->bitmask, att->bitmask_size),
+ att->client_handle, att->exec_queue_handle,
+ att->lrc_handle, att->bitmask_size);
+
+ for (uint32_t i = 0; i < att->bitmask_size/4; i += 2)
+ igt_debug("bitmask[%d] = 0x%08x%08x\n", i/2, ptr[i], ptr[i+1]);
+
+}
+
+static void copy_first_bit(uint8_t *dst, uint8_t *src, int size)
+{
+ bool found = false;
+ int i, j;
+
+ for (i = 0; i < size; i++) {
+ if (found) {
+ dst[i] = 0;
+ } else {
+ uint32_t tmp = src[i]; /* in case dst == src */
+
+ for (j = 0; j < 8; j++) {
+ dst[i] = tmp & (1 << j);
+ if (dst[i]) {
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+}
+
+#define MAX_PREEMPT_TIMEOUT 10ull
+static void eu_attention_resume_trigger(struct xe_eudebug_debugger *d,
+ struct drm_xe_eudebug_event *e)
+{
+ struct drm_xe_eudebug_event_eu_attention *att = (void *) e;
+ struct online_debug_data *data = d->ptr;
+ uint32_t bitmask_size = att->bitmask_size;
+ uint8_t *bitmask;
+ int i;
+
+ if (data->last_eu_control_seqno > att->base.seqno)
+ return;
+
+ bitmask = calloc(1, att->bitmask_size);
+
+ eu_ctl_stopped(d->fd, att->client_handle, att->exec_queue_handle,
+ att->lrc_handle, bitmask, &bitmask_size);
+ igt_assert(bitmask_size == att->bitmask_size);
+ igt_assert(memcmp(bitmask, att->bitmask, att->bitmask_size) == 0);
+
+ pthread_mutex_lock(&data->mutex);
+ if (igt_nsec_elapsed(&data->exception_arrived) < (MAX_PREEMPT_TIMEOUT + 1) * NSEC_PER_SEC &&
+ d->flags & TRIGGER_RESUME_DELAYED) {
+ pthread_mutex_unlock(&data->mutex);
+ free(bitmask);
+ return;
+ } else if (d->flags & TRIGGER_RESUME_ONE) {
+ copy_first_bit(bitmask, bitmask, bitmask_size);
+ } else if (d->flags & TRIGGER_RESUME_DSS) {
+ uint64_t *event = (uint64_t *)att->bitmask;
+ uint64_t *resume = (uint64_t *)bitmask;
+
+ memset(bitmask, 0, bitmask_size);
+ for (i = 0; i < att->bitmask_size / sizeof(uint64_t); i++) {
+ if (!event[i])
+ continue;
+
+ resume[i] = event[i];
+ break;
+ }
+ }
+
+ if (d->flags & SHADER_LOOP) {
+ uint32_t threads = get_number_of_threads(d->flags);
+ uint32_t val = STEERING_END_LOOP;
+
+ igt_assert_eq(pwrite(data->vm_fd, &val, sizeof(uint32_t),
+ data->target_offset + steering_offset(threads)),
+ sizeof(uint32_t));
+ fsync(data->vm_fd);
+ }
+ pthread_mutex_unlock(&data->mutex);
+
+ data->last_eu_control_seqno = eu_ctl_resume(d->master_fd, d->fd, att->client_handle,
+ att->exec_queue_handle, att->lrc_handle,
+ bitmask, att->bitmask_size);
+
+ free(bitmask);
+}
+
+static void open_trigger(struct xe_eudebug_debugger *d,
+ struct drm_xe_eudebug_event *e)
+{
+ struct drm_xe_eudebug_event_client *client = (void *)e;
+ struct online_debug_data *data = d->ptr;
+
+ if (e->flags & DRM_XE_EUDEBUG_EVENT_DESTROY)
+ return;
+
+ pthread_mutex_lock(&data->mutex);
+ data->client_handle = client->client_handle;
+ pthread_mutex_unlock(&data->mutex);
+}
+
+static void exec_queue_trigger(struct xe_eudebug_debugger *d,
+ struct drm_xe_eudebug_event *e)
+{
+ struct drm_xe_eudebug_event_exec_queue *eq = (void *)e;
+ struct online_debug_data *data = d->ptr;
+
+ if (e->flags & DRM_XE_EUDEBUG_EVENT_DESTROY)
+ return;
+
+ pthread_mutex_lock(&data->mutex);
+ data->exec_queue_handle = eq->exec_queue_handle;
+ data->lrc_handle = eq->lrc_handle[0];
+ pthread_mutex_unlock(&data->mutex);
+}
+
+static void vm_open_trigger(struct xe_eudebug_debugger *d,
+ struct drm_xe_eudebug_event *e)
+{
+ struct drm_xe_eudebug_event_vm *vm = (void *)e;
+ struct online_debug_data *data = d->ptr;
+ struct drm_xe_eudebug_vm_open vo = {
+ .client_handle = vm->client_handle,
+ .vm_handle = vm->vm_handle,
+ };
+ int fd;
+
+ if (e->flags & DRM_XE_EUDEBUG_EVENT_CREATE) {
+ fd = igt_ioctl(d->fd, DRM_XE_EUDEBUG_IOCTL_VM_OPEN, &vo);
+ igt_assert_lte(0, fd);
+
+ pthread_mutex_lock(&data->mutex);
+ igt_assert(data->vm_fd == -1);
+ data->vm_fd = fd;
+ pthread_mutex_unlock(&data->mutex);
+ return;
+ }
+
+ pthread_mutex_lock(&data->mutex);
+ close(data->vm_fd);
+ data->vm_fd = -1;
+ pthread_mutex_unlock(&data->mutex);
+}
+
+static void read_metadata(struct xe_eudebug_debugger *d,
+ uint64_t client_handle,
+ uint64_t metadata_handle,
+ uint64_t type,
+ uint64_t len)
+{
+ struct drm_xe_eudebug_read_metadata rm = {
+ .client_handle = client_handle,
+ .metadata_handle = metadata_handle,
+ .size = len,
+ };
+ struct online_debug_data *data = d->ptr;
+ uint64_t *metadata;
+
+ metadata = malloc(len);
+ igt_assert(metadata);
+
+ rm.ptr = to_user_pointer(metadata);
+ igt_assert_eq(igt_ioctl(d->fd, DRM_XE_EUDEBUG_IOCTL_READ_METADATA, &rm), 0);
+
+ pthread_mutex_lock(&data->mutex);
+ switch (type) {
+ case DRM_XE_DEBUG_METADATA_ELF_BINARY:
+ data->bb_offset = metadata[0];
+ data->bb_size = metadata[1];
+ break;
+ case DRM_XE_DEBUG_METADATA_PROGRAM_MODULE:
+ data->target_offset = metadata[0];
+ data->target_size = metadata[1];
+ break;
+ default:
+ break;
+ }
+ pthread_mutex_unlock(&data->mutex);
+
+ free(metadata);
+}
+
+static void create_metadata_trigger(struct xe_eudebug_debugger *d, struct drm_xe_eudebug_event *e)
+{
+ struct drm_xe_eudebug_event_metadata *em = (void *)e;
+
+ if (e->flags & DRM_XE_EUDEBUG_EVENT_CREATE) {
+ read_metadata(d, em->client_handle, em->metadata_handle, em->type, em->len);
+ }
+}
+
+static struct intel_bb *xe_bb_create_on_offset(int fd, uint32_t exec_queue, uint32_t vm,
+ uint64_t offset, uint32_t size)
+{
+ struct intel_bb *ibb;
+
+ ibb = intel_bb_create_with_context(fd, exec_queue, vm, NULL, size);
+
+ /* update intel bb offset */
+ intel_bb_remove_object(ibb, ibb->handle, ibb->batch_offset, ibb->size);
+ intel_bb_add_object(ibb, ibb->handle, ibb->size, offset, ibb->alignment, false);
+ ibb->batch_offset = offset;
+
+ return ibb;
+}
+
+static void run_online_client(struct xe_eudebug_client *c)
+{
+ const int threads = c->flags & (TRIGGER_RESUME_ONE) ? 64 : 512;
+ const uint64_t target_offset = 0x1a000000;
+ const uint64_t bb_offset = 0x1b000000;
+ const size_t bb_size = 4096;
+ struct online_debug_data *data = c->ptr;
+ struct drm_xe_engine_class_instance hwe = data->hwe;
+ struct drm_xe_ext_set_property ext = {
+ .base.name = DRM_XE_EXEC_QUEUE_EXTENSION_SET_PROPERTY,
+ .property = DRM_XE_EXEC_QUEUE_SET_PROPERTY_EUDEBUG,
+ .value = DRM_XE_EXEC_QUEUE_EUDEBUG_FLAG_ENABLE,
+ };
+ struct drm_xe_exec_queue_create create = {
+ .instances = to_user_pointer(&hwe),
+ .width = 1,
+ .num_placements = 1,
+ .extensions = to_user_pointer(&ext)
+ };
+ struct dim_t w_dim = walker_dimensions(threads);
+ struct dim_t s_dim = surface_dimensions(threads);
+ struct timespec ts = { };
+ struct gpgpu_shader *sip, *shader;
+ uint32_t metadata_id[2];
+ uint64_t *metadata[2];
+ struct intel_bb *ibb;
+ struct intel_buf *buf;
+ uint32_t *ptr;
+ int fd;
+
+ metadata[0] = calloc(2, sizeof(*metadata));
+ metadata[1] = calloc(2, sizeof(*metadata));
+ igt_assert(metadata[0]);
+ igt_assert(metadata[1]);
+
+ fd = xe_eudebug_client_open_driver(c);
+ xe_device_get(fd);
+
+ /* Additional memory for steering control */
+ if (c->flags & SHADER_LOOP)
+ s_dim.y++;
+ buf = create_uc_buf(fd, s_dim.x, s_dim.y);
+
+ buf->addr.offset = target_offset;
+
+ metadata[0][0] = bb_offset;
+ metadata[0][1] = bb_size;
+ metadata[1][0] = target_offset;
+ metadata[1][1] = buf->size;
+ metadata_id[0] = xe_eudebug_client_metadata_create(c, fd, DRM_XE_DEBUG_METADATA_ELF_BINARY,
+ 2 * sizeof(*metadata), metadata[0]);
+ metadata_id[1] = xe_eudebug_client_metadata_create(c, fd,
+ DRM_XE_DEBUG_METADATA_PROGRAM_MODULE,
+ 2 * sizeof(*metadata), metadata[1]);
+
+ create.vm_id = xe_eudebug_client_vm_create(c, fd, DRM_XE_VM_CREATE_FLAG_LR_MODE, 0);
+ xe_eudebug_client_exec_queue_create(c, fd, &create);
+
+ ibb = xe_bb_create_on_offset(fd, create.exec_queue_id, create.vm_id,
+ bb_offset, bb_size);
+ intel_bb_set_lr_mode(ibb, true);
+
+ sip = get_sip(fd);
+ shader = get_shader(fd, c->flags);
+
+ igt_nsec_elapsed(&ts);
+ gpgpu_shader_exec(ibb, buf, w_dim.x, w_dim.y, shader, sip, 0, 0);
+
+ gpgpu_shader_destroy(sip);
+ gpgpu_shader_destroy(shader);
+
+ intel_bb_sync(ibb);
+
+ /* Make sure it wasn't the timeout. */
+ igt_assert(igt_nsec_elapsed(&ts) <
+ XE_EUDEBUG_DEFAULT_TIMEOUT_MS / MSEC_PER_SEC * NSEC_PER_SEC);
+
+ ptr = xe_bo_mmap_ext(fd, buf->handle, buf->size, PROT_READ);
+ data->threads_count = count_canaries_neq(ptr, w_dim, 0);
+ igt_assert_f(data->threads_count, "No canaries found, nothing executed?\n");
+
+ if (c->flags & SHADER_BREAKPOINT) {
+ uint32_t aip = ptr[0];
+
+ igt_assert_f(aip != SHADER_CANARY, "Workload executed but breakpoint not hit!\n");
+ igt_assert_eq(count_canaries_eq(ptr, w_dim, aip), data->threads_count);
+ igt_debug("Breakpoint hit in %d threads, AIP=0x%08x\n", data->threads_count, aip);
+ }
+
+ munmap(ptr, buf->size);
+
+ intel_bb_destroy(ibb);
+
+ xe_eudebug_client_exec_queue_destroy(c, fd, &create);
+ xe_eudebug_client_vm_destroy(c, fd, create.vm_id);
+
+ xe_eudebug_client_metadata_destroy(c, fd, metadata_id[0], DRM_XE_DEBUG_METADATA_ELF_BINARY,
+ 2 * sizeof(*metadata));
+ xe_eudebug_client_metadata_destroy(c, fd, metadata_id[1],
+ DRM_XE_DEBUG_METADATA_PROGRAM_MODULE,
+ 2 * sizeof(*metadata));
+
+ xe_device_put(fd);
+ xe_eudebug_client_close_driver(c, fd);
+}
+
+static bool intel_gen_has_lockstep_eus(int fd)
+{
+ const uint32_t id = intel_get_drm_devid(fd);
+
+ /*
+ * Lockstep (or in some parlance, fused) EUs are pair of EUs
+ * that work in sync, supposedly same clock and same control flow.
+ * Thus for attentions, if the control has breakpoint, both will be
+ * excepted into SIP. In this level, the hardware has only one attention
+ * thread bit for units. PVC is the first one without lockstepping.
+ */
+ return !(intel_graphics_ver(id) == IP_VER(12, 60) || intel_gen(id) >= 20);
+}
+
+static int query_attention_bitmask_size(int fd, int gt)
+{
+ const unsigned int threads = 8;
+ struct drm_xe_query_topology_mask *c_dss = NULL, *g_dss = NULL, *eu_per_dss = NULL;
+ struct drm_xe_query_topology_mask *topology;
+ struct drm_xe_device_query query = {
+ .extensions = 0,
+ .query = DRM_XE_DEVICE_QUERY_GT_TOPOLOGY,
+ .size = 0,
+ .data = 0,
+ };
+ int pos = 0, eus;
+ uint8_t *any_dss;
+
+ igt_assert_eq(igt_ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query), 0);
+ igt_assert_neq(query.size, 0);
+
+ topology = malloc(query.size);
+ igt_assert(topology);
+
+ query.data = to_user_pointer(topology);
+ igt_assert_eq(igt_ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query), 0);
+
+ while (query.size >= sizeof(struct drm_xe_query_topology_mask)) {
+ struct drm_xe_query_topology_mask *topo;
+ int sz;
+
+ topo = (struct drm_xe_query_topology_mask *)((unsigned char *)topology + pos);
+ sz = sizeof(struct drm_xe_query_topology_mask) + topo->num_bytes;
+
+ query.size -= sz;
+ pos += sz;
+
+ if (topo->gt_id != gt)
+ continue;
+
+ if (topo->type == DRM_XE_TOPO_DSS_GEOMETRY)
+ g_dss = topo;
+ else if (topo->type == DRM_XE_TOPO_DSS_COMPUTE)
+ c_dss = topo;
+ else if (topo->type == DRM_XE_TOPO_EU_PER_DSS ||
+ topo->type == DRM_XE_TOPO_SIMD16_EU_PER_DSS)
+ eu_per_dss = topo;
+ }
+
+ igt_assert(g_dss && c_dss && eu_per_dss);
+ igt_assert_eq_u32(c_dss->num_bytes, g_dss->num_bytes);
+
+ any_dss = malloc(c_dss->num_bytes);
+
+ for (int i = 0; i < c_dss->num_bytes; i++)
+ any_dss[i] = c_dss->mask[i] | g_dss->mask[i];
+
+ eus = count_set_bits(any_dss, c_dss->num_bytes);
+ eus *= count_set_bits(eu_per_dss->mask, eu_per_dss->num_bytes);
+
+ if (intel_gen_has_lockstep_eus(fd))
+ eus /= 2;
+
+ free(any_dss);
+ free(topology);
+
+ return eus * threads / 8;
+}
+
+static struct drm_xe_eudebug_event_exec_queue *
+match_attention_with_exec_queue(struct xe_eudebug_event_log *log,
+ struct drm_xe_eudebug_event_eu_attention *ea)
+{
+ struct drm_xe_eudebug_event_exec_queue *ee;
+ struct drm_xe_eudebug_event *event = NULL, *current = NULL, *matching_destroy = NULL;
+ int lrc_idx;
+
+ xe_eudebug_for_each_event(event, log) {
+ if (event->type == DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE &&
+ event->flags == DRM_XE_EUDEBUG_EVENT_CREATE) {
+ ee = (struct drm_xe_eudebug_event_exec_queue *)event;
+
+ if (ee->exec_queue_handle != ea->exec_queue_handle)
+ continue;
+
+ if (ee->client_handle != ea->client_handle)
+ continue;
+
+ for (lrc_idx = 0; lrc_idx < ee->width; lrc_idx++) {
+ if (ee->lrc_handle[lrc_idx] == ea->lrc_handle)
+ break;
+ }
+
+ if (lrc_idx >= ee->width) {
+ igt_debug("No matching lrc handle within matching exec_queue!");
+ continue;
+ }
+
+ /* event logs are sorted, every found next would not be present. */
+ if (ea->base.seqno < ee->base.seqno)
+ break;
+
+ /* sanity check whether attention did
+ * not appear yet on already destroyed exec_queue
+ */
+ current = event;
+ xe_eudebug_for_each_event(current, log) {
+ if (current->type == DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE &&
+ current->flags == DRM_XE_EUDEBUG_EVENT_DESTROY) {
+ uint8_t offset = sizeof(struct drm_xe_eudebug_event);
+
+ if (memcmp((uint8_t *)current + offset,
+ (uint8_t *)event + offset,
+ current->len - offset) == 0) {
+ matching_destroy = current;
+ }
+ }
+ }
+
+ if (!matching_destroy || ea->base.seqno > matching_destroy->seqno)
+ continue;
+
+ return ee;
+ }
+ }
+
+ return NULL;
+}
+
+static void online_session_check(struct xe_eudebug_session *s, int flags)
+{
+ struct drm_xe_eudebug_event_eu_attention *ea = NULL;
+ struct drm_xe_eudebug_event *event = NULL;
+ struct online_debug_data *data = s->c->ptr;
+ int sum = 0;
+ int bitmask_size;
+
+ xe_eudebug_session_check(s, true, XE_EUDEBUG_FILTER_EVENT_VM_BIND |
+ XE_EUDEBUG_FILTER_EVENT_VM_BIND_OP |
+ XE_EUDEBUG_FILTER_EVENT_VM_BIND_UFENCE);
+
+ bitmask_size = query_attention_bitmask_size(s->d->master_fd, data->hwe.gt_id);
+
+ xe_eudebug_for_each_event(event, s->d->log) {
+ if (event->type == DRM_XE_EUDEBUG_EVENT_EU_ATTENTION) {
+ ea = (struct drm_xe_eudebug_event_eu_attention *)event;
+
+ igt_assert(event->flags == DRM_XE_EUDEBUG_EVENT_STATE_CHANGE);
+ igt_assert_eq(ea->bitmask_size, bitmask_size);
+ sum += count_set_bits(ea->bitmask, bitmask_size);
+ igt_assert(match_attention_with_exec_queue(s->d->log, ea));
+ }
+ }
+
+ /*
+ * We can expect attention to sum up only
+ * if we have a breakpoint set and we resume all threads always.
+ */
+ if (flags == SHADER_BREAKPOINT)
+ igt_assert_eq(sum, data->threads_count);
+
+ igt_assert(sum > 0);
+}
+
+static void ufence_ack_trigger(struct xe_eudebug_debugger *d,
+ struct drm_xe_eudebug_event *e)
+{
+ struct drm_xe_eudebug_event_vm_bind_ufence *ef = (void *)e;
+
+ if (e->flags & DRM_XE_EUDEBUG_EVENT_CREATE)
+ xe_eudebug_ack_ufence(d->fd, ef);
+}
+
+/**
+ * SUBTEST: basic-breakpoint
+ * Description:
+ * Check whether KMD sends attention events
+ * for runalone workload stopped on breakpoint.
+ *
+ * SUBTEST: stopped-thread
+ * Description:
+ * Hits breakpoint on runalone workload and
+ * reads attention for fixed time.
+ *
+ * SUBTEST: resume-%s
+ * Description:
+ * Resumes stopped on a breakpoint workload
+ * with granularity of %arg[1].
+ *
+ *
+ * arg[1]:
+ *
+ * @one: one thread
+ * @dss: threads running on one subslice
+ */
+static void test_basic_online(int fd, struct drm_xe_engine_class_instance *hwe, int flags)
+{
+ struct xe_eudebug_session *s;
+ struct online_debug_data *data;
+
+ data = online_debug_data_create(hwe);
+ s = xe_eudebug_session_create(fd, run_online_client, flags, data);
+
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
+ eu_attention_debug_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
+ eu_attention_resume_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE,
+ ufence_ack_trigger);
+
+ xe_eudebug_session_run(s);
+ online_session_check(s, s->flags);
+
+ xe_eudebug_session_destroy(s);
+ online_debug_data_destroy(data);
+}
+
+/**
+ * SUBTEST: interrupt-all
+ * Description:
+ * Schedules EU workload which should last about a few seconds, then
+ * interrupts all threads, checks whether attention event came, and
+ * resumes stopped threads back.
+ */
+static void test_interrupt_all(int fd, struct drm_xe_engine_class_instance *hwe, int flags)
+{
+ struct xe_eudebug_session *s;
+ struct online_debug_data *data;
+ uint32_t val;
+
+ data = online_debug_data_create(hwe);
+ s = xe_eudebug_session_create(fd, run_online_client, flags, data);
+
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_OPEN,
+ open_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE,
+ exec_queue_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
+ eu_attention_debug_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
+ eu_attention_resume_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_VM, vm_open_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_METADATA,
+ create_metadata_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE,
+ ufence_ack_trigger);
+
+ igt_assert_eq(xe_eudebug_debugger_attach(s->d, s->c), 0);
+ xe_eudebug_debugger_start_worker(s->d);
+ xe_eudebug_client_start(s->c);
+
+ /* wait for workload to start */
+ igt_for_milliseconds(STARTUP_TIMEOUT_MS) {
+ /* collect needed data from triggers */
+ if (READ_ONCE(data->vm_fd) == -1 || READ_ONCE(data->target_size) == 0)
+ continue;
+
+ if (pread(data->vm_fd, &val, sizeof(val), data->target_offset) == sizeof(val))
+ if (val != 0)
+ break;
+ }
+
+ pthread_mutex_lock(&data->mutex);
+ igt_assert(data->client_handle != -1);
+ igt_assert(data->exec_queue_handle != -1);
+ eu_ctl_interrupt_all(s->d->fd, data->client_handle,
+ data->exec_queue_handle, data->lrc_handle);
+ pthread_mutex_unlock(&data->mutex);
+
+ xe_eudebug_client_wait_done(s->c);
+
+ xe_eudebug_debugger_stop_worker(s->d, 1);
+
+ xe_eudebug_event_log_print(s->d->log, true);
+ xe_eudebug_event_log_print(s->c->log, true);
+
+ online_session_check(s, s->flags);
+
+ xe_eudebug_session_destroy(s);
+ online_debug_data_destroy(data);
+}
+
+static struct drm_xe_engine_class_instance *pick_compute(int fd, int gt)
+{
+ struct drm_xe_engine_class_instance *hwe;
+ int count = 0;
+
+ #define match(__e) ((__e->engine_class == DRM_XE_ENGINE_CLASS_RENDER || \
+ __e->engine_class == DRM_XE_ENGINE_CLASS_COMPUTE) && __e->gt_id == gt)
+
+ xe_for_each_engine(fd, hwe)
+ if (match(hwe))
+ count++;
+
+ xe_for_each_engine(fd, hwe)
+ if (match(hwe) && rand() % count-- == 0)
+ return hwe;
+ #undef match
+
+ return NULL;
+}
+
+#define test_gt_render_or_compute(t, i915, __hwe) \
+ igt_subtest_with_dynamic(t) \
+ for (int gt = 0; (__hwe = pick_compute(i915, gt)); gt++) \
+ igt_dynamic_f("%s%d", xe_engine_class_string(__hwe->engine_class), hwe->engine_instance)
+
+igt_main
+{
+ struct drm_xe_engine_class_instance *hwe;
+ int fd;
+
+ igt_fixture {
+ fd = drm_open_driver(DRIVER_XE);
+ intel_allocator_multiprocess_start();
+ igt_srandom();
+ }
+
+ test_gt_render_or_compute("basic-breakpoint", fd, hwe)
+ test_basic_online(fd, hwe, SHADER_BREAKPOINT);
+
+ test_gt_render_or_compute("stopped-thread", fd, hwe)
+ test_basic_online(fd, hwe, SHADER_BREAKPOINT | TRIGGER_RESUME_DELAYED);
+
+ test_gt_render_or_compute("resume-one", fd, hwe)
+ test_basic_online(fd, hwe, SHADER_BREAKPOINT | TRIGGER_RESUME_ONE);
+
+ test_gt_render_or_compute("resume-dss", fd, hwe)
+ test_basic_online(fd, hwe, SHADER_BREAKPOINT | TRIGGER_RESUME_DSS);
+
+ test_gt_render_or_compute("interrupt-all", fd, hwe)
+ test_interrupt_all(fd, hwe, SHADER_LOOP);
+
+ igt_fixture {
+ intel_allocator_multiprocess_stop();
+ drm_close_driver(fd);
+ }
+}
diff --git a/tests/meson.build b/tests/meson.build
index 35bf8ed35..f18eec7e7 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -280,6 +280,7 @@ intel_xe_progs = [
'xe_debugfs',
'xe_drm_fdinfo',
'xe_eudebug',
+ 'xe_eudebug_online',
'xe_evict',
'xe_evict_ccs',
'xe_exec_atomic',
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 53/66] tests/xe_eudebug_online: Set dynamic breakpoint on interrupt-all
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (51 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 52/66] tests/xe_eudebug_online: Debug client which runs workloads on EU Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 54/66] tests/xe_eudebug_online: Add support for dynamic debugger sysfs toggle Christoph Manszewski
` (14 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun
From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Implement interrupt-all-set-breakpoint, which interrupts all threads,
and once spots attention it sets a breakpoint on the next instruction.
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Cc: Mika Kuoppala <mika.kuoppala@intel.com>
---
tests/intel/xe_eudebug_online.c | 81 ++++++++++++++++++++++++++++++++-
1 file changed, 80 insertions(+), 1 deletion(-)
diff --git a/tests/intel/xe_eudebug_online.c b/tests/intel/xe_eudebug_online.c
index 8791b29fa..5bb165fef 100644
--- a/tests/intel/xe_eudebug_online.c
+++ b/tests/intel/xe_eudebug_online.c
@@ -22,6 +22,7 @@
#define SHADER_BREAKPOINT (1 << 0)
#define SHADER_LOOP (1 << 1)
+#define TRIGGER_RESUME_SET_BP (1 << 28)
#define TRIGGER_RESUME_DELAYED (1 << 29)
#define TRIGGER_RESUME_DSS (1 << 30)
#define TRIGGER_RESUME_ONE (1 << 31)
@@ -276,6 +277,7 @@ struct online_debug_data {
uint64_t bb_offset;
size_t bb_size;
int vm_fd;
+ uint32_t first_aip;
struct timespec exception_arrived;
int last_eu_control_seqno;
};
@@ -342,6 +344,71 @@ static void copy_first_bit(uint8_t *dst, uint8_t *src, int size)
}
}
+/*
+ * Searches for the first instruction. It stands on assumption,
+ * that shader kernel is placed before sip within the bb.
+ */
+static uint32_t find_kernel_in_bb(struct gpgpu_shader *kernel,
+ struct online_debug_data *data)
+{
+ uint32_t *p = kernel->code;
+ size_t sz = 4 * sizeof(uint32_t);
+ uint32_t buf[4];
+ int i;
+
+ for (i = 0; i < data->bb_size; i += sz) {
+ igt_assert_eq(pread(data->vm_fd, &buf, sz, data->bb_offset + i), sz);
+
+
+ if (memcmp(p, buf, sz) == 0)
+ break;
+ }
+
+ igt_assert(i < data->bb_size);
+
+ return i;
+}
+
+static void set_breakpoint_once(struct xe_eudebug_debugger *d,
+ struct online_debug_data *data)
+{
+ const uint32_t breakpoint_bit = 1 << 30;
+ size_t sz = sizeof(uint32_t);
+ struct gpgpu_shader *kernel;
+ uint32_t aip;
+
+ kernel = get_shader(d->master_fd, d->flags);
+
+ if (data->first_aip) {
+ uint32_t expected = find_kernel_in_bb(kernel, data) + kernel->size * 4 - 0x10;
+
+ igt_assert_eq(pread(data->vm_fd, &aip, sz, data->target_offset), sz);
+ igt_assert_eq_u32(aip, expected);
+ } else {
+ uint32_t instr_usdw;
+
+ igt_assert(data->vm_fd != -1);
+ igt_assert(data->target_size != 0);
+ igt_assert(data->bb_size != 0);
+
+ igt_assert_eq(pread(data->vm_fd, &aip, sz, data->target_offset), sz);
+ data->first_aip = aip;
+
+ aip = find_kernel_in_bb(kernel, data);
+
+ /* set breakpoint on last instruction */
+ aip += kernel->size * 4 - 0x10;
+ igt_assert_eq(pread(data->vm_fd, &instr_usdw, sz,
+ data->bb_offset + aip), sz);
+ instr_usdw |= breakpoint_bit;
+ igt_assert_eq(pwrite(data->vm_fd, &instr_usdw, sz,
+ data->bb_offset + aip), sz);
+
+ }
+
+ gpgpu_shader_destroy(kernel);
+}
+
#define MAX_PREEMPT_TIMEOUT 10ull
static void eu_attention_resume_trigger(struct xe_eudebug_debugger *d,
struct drm_xe_eudebug_event *e)
@@ -382,6 +449,8 @@ static void eu_attention_resume_trigger(struct xe_eudebug_debugger *d,
resume[i] = event[i];
break;
}
+ } else if (d->flags & TRIGGER_RESUME_SET_BP) {
+ set_breakpoint_once(d, data);
}
if (d->flags & SHADER_LOOP) {
@@ -602,7 +671,7 @@ static void run_online_client(struct xe_eudebug_client *c)
data->threads_count = count_canaries_neq(ptr, w_dim, 0);
igt_assert_f(data->threads_count, "No canaries found, nothing executed?\n");
- if (c->flags & SHADER_BREAKPOINT) {
+ if (c->flags & SHADER_BREAKPOINT || c->flags & TRIGGER_RESUME_SET_BP) {
uint32_t aip = ptr[0];
igt_assert_f(aip != SHADER_CANARY, "Workload executed but breakpoint not hit!\n");
@@ -860,6 +929,13 @@ static void test_basic_online(int fd, struct drm_xe_engine_class_instance *hwe,
* Schedules EU workload which should last about a few seconds, then
* interrupts all threads, checks whether attention event came, and
* resumes stopped threads back.
+ *
+ * SUBTEST: interrupt-all-set-breakpoint
+ * Description:
+ * Schedules EU workload which should last about a few seconds, then
+ * interrupts all threads, once attention event come it sets breakpoint on
+ * the very next instruction and resumes stopped thereads back. It expects
+ * that every thread hits the breakpoint.
*/
static void test_interrupt_all(int fd, struct drm_xe_engine_class_instance *hwe, int flags)
{
@@ -970,6 +1046,9 @@ igt_main
test_gt_render_or_compute("interrupt-all", fd, hwe)
test_interrupt_all(fd, hwe, SHADER_LOOP);
+ test_gt_render_or_compute("interrupt-all-set-breakpoint", fd, hwe)
+ test_interrupt_all(fd, hwe, SHADER_LOOP | TRIGGER_RESUME_SET_BP);
+
igt_fixture {
intel_allocator_multiprocess_stop();
drm_close_driver(fd);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 54/66] tests/xe_eudebug_online: Add support for dynamic debugger sysfs toggle
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (52 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 53/66] tests/xe_eudebug_online: Set dynamic breakpoint on interrupt-all Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 55/66] tests/xe_eudebug_online: Add tdctl-parameters test Christoph Manszewski
` (13 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
From now on the debugger is disabled by default so it is required
to enable the debugger before using it. This change addresses that
fact by calling necessary library functions within test fixtures.
Signed-off-by: Mika Kuoppala <mika.kuoppala@intel.com>
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
tests/intel/xe_eudebug_online.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/tests/intel/xe_eudebug_online.c b/tests/intel/xe_eudebug_online.c
index 5bb165fef..12edd0eb5 100644
--- a/tests/intel/xe_eudebug_online.c
+++ b/tests/intel/xe_eudebug_online.c
@@ -1023,12 +1023,14 @@ static struct drm_xe_engine_class_instance *pick_compute(int fd, int gt)
igt_main
{
struct drm_xe_engine_class_instance *hwe;
+ bool was_enabled;
int fd;
igt_fixture {
fd = drm_open_driver(DRIVER_XE);
intel_allocator_multiprocess_start();
igt_srandom();
+ was_enabled = xe_eudebug_enable(fd, true);
}
test_gt_render_or_compute("basic-breakpoint", fd, hwe)
@@ -1050,6 +1052,8 @@ igt_main
test_interrupt_all(fd, hwe, SHADER_LOOP | TRIGGER_RESUME_SET_BP);
igt_fixture {
+ xe_eudebug_enable(fd, was_enabled);
+
intel_allocator_multiprocess_stop();
drm_close_driver(fd);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 55/66] tests/xe_eudebug_online: Add tdctl-parameters test
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (53 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 54/66] tests/xe_eudebug_online: Add support for dynamic debugger sysfs toggle Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 56/66] tests/xe_eudebug_online: Add reset-with-attention test Christoph Manszewski
` (12 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun
From: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
Add tdctl-parameters test that checks negative scenarios of EU_THREADS
ioctl usage.
This patch shortens the loop in run_online_client in order to avoid
hitting the timeout that caused the test to fail.
Signed-off-by: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
tests/intel/xe_eudebug_online.c | 111 ++++++++++++++++++++++++++++++++
1 file changed, 111 insertions(+)
diff --git a/tests/intel/xe_eudebug_online.c b/tests/intel/xe_eudebug_online.c
index 12edd0eb5..0b92507f4 100644
--- a/tests/intel/xe_eudebug_online.c
+++ b/tests/intel/xe_eudebug_online.c
@@ -995,6 +995,114 @@ static void test_interrupt_all(int fd, struct drm_xe_engine_class_instance *hwe,
online_debug_data_destroy(data);
}
+/**
+ * SUBTEST: tdctl-parameters
+ * Description:
+ * Schedules EU workload which should last about a few seconds, then
+ * checks negative scenarios of EU_THREADS ioctl usage, interrupts all threads,
+ * checks whether attention event came, and resumes stopped threads back.
+ */
+static void test_tdctl_parameters(int fd, struct drm_xe_engine_class_instance *hwe, int flags)
+{
+ struct xe_eudebug_session *s;
+ struct online_debug_data *data;
+ uint32_t val;
+ uint32_t random_command;
+ uint32_t bitmask_size = query_attention_bitmask_size(fd, hwe->gt_id);
+ uint8_t *attention_bitmask = malloc(bitmask_size * sizeof(uint8_t));
+ igt_assert(attention_bitmask);
+
+ data = online_debug_data_create(hwe);
+ s = xe_eudebug_session_create(fd, run_online_client, flags, data);
+
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_OPEN,
+ open_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE,
+ exec_queue_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
+ eu_attention_debug_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
+ eu_attention_resume_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_VM, vm_open_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_METADATA,
+ create_metadata_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE,
+ ufence_ack_trigger);
+
+ igt_assert_eq(xe_eudebug_debugger_attach(s->d, s->c), 0);
+ xe_eudebug_debugger_start_worker(s->d);
+ xe_eudebug_client_start(s->c);
+
+ /* wait for workload to start */
+ igt_for_milliseconds(STARTUP_TIMEOUT_MS) {
+ /* collect needed data from triggers */
+ if (READ_ONCE(data->vm_fd) == -1 || READ_ONCE(data->target_size) == 0)
+ continue;
+
+ if (pread(data->vm_fd, &val, sizeof(val), data->target_offset) == sizeof(val))
+ if (val != 0)
+ break;
+ }
+
+ pthread_mutex_lock(&data->mutex);
+ igt_assert(data->client_handle != -1);
+ igt_assert(data->exec_queue_handle != -1);
+ igt_assert(data->lrc_handle != -1);
+
+ /* fail on invalid lrc_handle */
+ igt_assert(__eu_ctl(s->d->fd, data->client_handle,
+ data->exec_queue_handle, data->lrc_handle + 1,
+ attention_bitmask, &bitmask_size,
+ DRM_XE_EUDEBUG_EU_CONTROL_CMD_INTERRUPT_ALL, NULL) == -EINVAL);
+
+ /* fail on invalid exec_queue_handle */
+ igt_assert(__eu_ctl(s->d->fd, data->client_handle,
+ data->exec_queue_handle + 1, data->lrc_handle,
+ attention_bitmask, &bitmask_size,
+ DRM_XE_EUDEBUG_EU_CONTROL_CMD_INTERRUPT_ALL, NULL) == -EINVAL);
+
+ /* fail on invalid client */
+ igt_assert(__eu_ctl(s->d->fd, data->client_handle + 1,
+ data->exec_queue_handle, data->lrc_handle,
+ attention_bitmask, &bitmask_size,
+ DRM_XE_EUDEBUG_EU_CONTROL_CMD_INTERRUPT_ALL, NULL) == -EINVAL);
+
+ /*
+ * bitmask size must be aligned to sizeof(u32) for all commands
+ * and be zero for interrupt all
+ */
+ bitmask_size = sizeof(uint32_t) - 1;
+ igt_assert(__eu_ctl(s->d->fd, data->client_handle,
+ data->exec_queue_handle, data->lrc_handle,
+ attention_bitmask, &bitmask_size,
+ DRM_XE_EUDEBUG_EU_CONTROL_CMD_STOPPED, NULL) == -EINVAL);
+ bitmask_size = 0;
+
+ /* fail on invalid command */
+ random_command = random() | (DRM_XE_EUDEBUG_EU_CONTROL_CMD_RESUME + 1);
+ igt_assert(__eu_ctl(s->d->fd, data->client_handle,
+ data->exec_queue_handle, data->lrc_handle,
+ attention_bitmask, &bitmask_size, random_command, NULL) == -EINVAL);
+
+ free(attention_bitmask);
+
+ eu_ctl_interrupt_all(s->d->fd, data->client_handle,
+ data->exec_queue_handle, data->lrc_handle);
+ pthread_mutex_unlock(&data->mutex);
+
+ xe_eudebug_client_wait_done(s->c);
+
+ xe_eudebug_debugger_stop_worker(s->d, 1);
+
+ xe_eudebug_event_log_print(s->d->log, true);
+ xe_eudebug_event_log_print(s->c->log, true);
+
+ online_session_check(s, s->flags);
+
+ xe_eudebug_session_destroy(s);
+ online_debug_data_destroy(data);
+}
+
static struct drm_xe_engine_class_instance *pick_compute(int fd, int gt)
{
struct drm_xe_engine_class_instance *hwe;
@@ -1051,6 +1159,9 @@ igt_main
test_gt_render_or_compute("interrupt-all-set-breakpoint", fd, hwe)
test_interrupt_all(fd, hwe, SHADER_LOOP | TRIGGER_RESUME_SET_BP);
+ test_gt_render_or_compute("tdctl-parameters", fd, hwe)
+ test_tdctl_parameters(fd, hwe, SHADER_LOOP);
+
igt_fixture {
xe_eudebug_enable(fd, was_enabled);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 56/66] tests/xe_eudebug_online: Add reset-with-attention test
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (54 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 55/66] tests/xe_eudebug_online: Add tdctl-parameters test Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 57/66] lib/xe_eudebug: Expose xe_eudebug_connect Christoph Manszewski
` (11 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
From: Pawel Sikora <pawel.sikora@intel.com>
This new test performs a GPU GT forced reset on the attention event raised.
Then the test runs a new session with a workload to check if the GPU is usable.
Signed-off-by: Pawel Sikora <pawel.sikora@intel.com>
Cc: Christoph Manszewski <christoph.manszewski@intel.com>
---
tests/intel/xe_eudebug_online.c | 58 +++++++++++++++++++++++++++++++++
1 file changed, 58 insertions(+)
diff --git a/tests/intel/xe_eudebug_online.c b/tests/intel/xe_eudebug_online.c
index 0b92507f4..c101bde2f 100644
--- a/tests/intel/xe_eudebug_online.c
+++ b/tests/intel/xe_eudebug_online.c
@@ -322,6 +322,25 @@ static void eu_attention_debug_trigger(struct xe_eudebug_debugger *d,
}
+static void eu_attention_reset_trigger(struct xe_eudebug_debugger *d,
+ struct drm_xe_eudebug_event *e)
+{
+ struct drm_xe_eudebug_event_eu_attention *att = (void *) e;
+ uint32_t *ptr = (uint32_t *) att->bitmask;
+ struct online_debug_data *data = d->ptr;
+
+ igt_debug("EVENT[%llu] eu-attenttion with reset; threads=%d "
+ "client[%llu], exec_queue[%llu], lrc[%llu], bitmask_size[%d]\n",
+ att->base.seqno, count_set_bits(att->bitmask, att->bitmask_size),
+ att->client_handle, att->exec_queue_handle,
+ att->lrc_handle, att->bitmask_size);
+
+ for (uint32_t i = 0; i < att->bitmask_size/4; i += 2)
+ igt_debug("bitmask[%d] = 0x%08x%08x\n", i/2, ptr[i], ptr[i+1]);
+
+ xe_force_gt_reset_async(d->master_fd, data->hwe.gt_id);
+}
+
static void copy_first_bit(uint8_t *dst, uint8_t *src, int size)
{
bool found = false;
@@ -923,6 +942,42 @@ static void test_basic_online(int fd, struct drm_xe_engine_class_instance *hwe,
online_debug_data_destroy(data);
}
+/**
+ * SUBTEST: reset-with-attention
+ * Description:
+ * Check whether GPU is usable after resetting with attention raised
+ * (stopped on breakpoint) by running the same workload again.
+ */
+static void test_reset_with_attention_online(int fd, struct drm_xe_engine_class_instance *hwe, int flags)
+{
+ struct xe_eudebug_session *s1, *s2;
+ struct online_debug_data *data;
+
+ data = online_debug_data_create(hwe);
+ s1 = xe_eudebug_session_create(fd, run_online_client, flags, data);
+
+ xe_eudebug_debugger_add_trigger(s1->d, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
+ eu_attention_reset_trigger);
+ xe_eudebug_debugger_add_trigger(s1->d, DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE,
+ ufence_ack_trigger);
+
+ xe_eudebug_session_run(s1);
+ xe_eudebug_session_destroy(s1);
+
+ s2 = xe_eudebug_session_create(fd, run_online_client, flags, data);
+ xe_eudebug_debugger_add_trigger(s2->d, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
+ eu_attention_resume_trigger);
+ xe_eudebug_debugger_add_trigger(s2->d, DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE,
+ ufence_ack_trigger);
+
+ xe_eudebug_session_run(s2);
+
+ online_session_check(s2, s2->flags);
+
+ xe_eudebug_session_destroy(s2);
+ online_debug_data_destroy(data);
+}
+
/**
* SUBTEST: interrupt-all
* Description:
@@ -1162,6 +1217,9 @@ igt_main
test_gt_render_or_compute("tdctl-parameters", fd, hwe)
test_tdctl_parameters(fd, hwe, SHADER_LOOP);
+ test_gt_render_or_compute("reset-with-attention", fd, hwe)
+ test_reset_with_attention_online(fd, hwe, SHADER_BREAKPOINT);
+
igt_fixture {
xe_eudebug_enable(fd, was_enabled);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 57/66] lib/xe_eudebug: Expose xe_eudebug_connect
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (55 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 56/66] tests/xe_eudebug_online: Add reset-with-attention test Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 58/66] tests/xe_eudebug_online: Add interrupt-reconnect test Christoph Manszewski
` (10 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Karolina Stolarek, Christoph Manszewski
From: Karolina Stolarek <karolina.stolarek@intel.com>
Expose xe_eudebug_connect library function to use it directly in tests.
Signed-off-by: Karolina Stolarek <karolina.stolarek@intel.com>
Cc: Christoph Manszewski <christoph.manszewski@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
lib/xe/xe_eudebug.c | 30 ++++++++++++++++++++----------
lib/xe/xe_eudebug.h | 1 +
2 files changed, 21 insertions(+), 10 deletions(-)
diff --git a/lib/xe/xe_eudebug.c b/lib/xe/xe_eudebug.c
index 41809429d..1fa9cbaf1 100644
--- a/lib/xe/xe_eudebug.c
+++ b/lib/xe/xe_eudebug.c
@@ -329,16 +329,6 @@ static int __xe_eudebug_connect(int fd, pid_t pid, uint32_t flags, uint64_t even
return debugfd;
}
-static int xe_eudebug_connect(int fd, pid_t pid, uint32_t flags)
-{
- int ret;
- uint64_t events = 0; /* events filtering not supported yet! */
-
- ret = __xe_eudebug_connect(fd, pid, flags, events);
-
- return ret;
-}
-
static void event_log_write_to_fd(struct xe_eudebug_event_log *l, int fd)
{
igt_assert_eq(write(fd, &l->head, sizeof(l->head)),
@@ -810,6 +800,26 @@ static void event_log_sort(struct xe_eudebug_event_log *l)
xe_eudebug_event_log_destroy(tmp);
}
+/**
+ * xe_eudebug_connect:
+ * @fd: Xe file descriptor
+ * @pid: client PID
+ * @flags: connection flags
+ *
+ * Opens the xe eu debugger connection to the process described by @pid
+ *
+ * Returns: 0 if the debugger was successfully attached, -errno otherwise.
+ */
+int xe_eudebug_connect(int fd, pid_t pid, uint32_t flags)
+{
+ int ret;
+ uint64_t events = 0; /* events filtering not supported yet! */
+
+ ret = __xe_eudebug_connect(fd, pid, flags, events);
+
+ return ret;
+}
+
/**
* xe_eudebug_event_log_create:
* @name: event log identifier
diff --git a/lib/xe/xe_eudebug.h b/lib/xe/xe_eudebug.h
index a499cc977..4654b462f 100644
--- a/lib/xe/xe_eudebug.h
+++ b/lib/xe/xe_eudebug.h
@@ -112,6 +112,7 @@ typedef void (*xe_eudebug_trigger_fn)(struct xe_eudebug_debugger *,
#define XE_EUDEUBG_FILTER_ALL GENMASK(DRM_XE_EUDEBUG_EVENT_MAX_EVENT, 0)
#define XE_EUDEBUG_EVENT_IS_FILTERED(_e, _f) ((1UL << _e) & _f)
+int xe_eudebug_connect(int fd, pid_t pid, uint32_t flags);
const char *xe_eudebug_event_to_str(struct drm_xe_eudebug_event *e, char *buf, size_t len);
struct drm_xe_eudebug_event *
xe_eudebug_event_log_find_seqno(struct xe_eudebug_event_log *l, uint64_t seqno);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 58/66] tests/xe_eudebug_online: Add interrupt-reconnect test
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (56 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 57/66] lib/xe_eudebug: Expose xe_eudebug_connect Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 59/66] tests/xe_eudebug_online: Add single-step and single-step-one tests Christoph Manszewski
` (9 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Karolina Stolarek, Christoph Manszewski
From: Karolina Stolarek <karolina.stolarek@intel.com>
Introduce interrupt-reconnect test case where the debugger is
closed and reopened on attention event. Check if the workload
is reset when there is no active debugger detected.
Signed-off-by: Karolina Stolarek <karolina.stolarek@intel.com>
Cc: Christoph Manszewski <christoph.manszewski@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
tests/intel/xe_eudebug_online.c | 126 +++++++++++++++++++++++++++++++-
1 file changed, 123 insertions(+), 3 deletions(-)
diff --git a/tests/intel/xe_eudebug_online.c b/tests/intel/xe_eudebug_online.c
index c101bde2f..9f55cec74 100644
--- a/tests/intel/xe_eudebug_online.c
+++ b/tests/intel/xe_eudebug_online.c
@@ -22,11 +22,14 @@
#define SHADER_BREAKPOINT (1 << 0)
#define SHADER_LOOP (1 << 1)
+#define TRIGGER_RECONNECT (1 << 27)
#define TRIGGER_RESUME_SET_BP (1 << 28)
#define TRIGGER_RESUME_DELAYED (1 << 29)
#define TRIGGER_RESUME_DSS (1 << 30)
#define TRIGGER_RESUME_ONE (1 << 31)
+#define DEBUGGER_REATTACHED 1
+
#define STEERING_END_LOOP 0xdeadca11
#define SHADER_CANARY 0x01010101
@@ -682,9 +685,12 @@ static void run_online_client(struct xe_eudebug_client *c)
intel_bb_sync(ibb);
- /* Make sure it wasn't the timeout. */
- igt_assert(igt_nsec_elapsed(&ts) <
- XE_EUDEBUG_DEFAULT_TIMEOUT_MS / MSEC_PER_SEC * NSEC_PER_SEC);
+ if (c->flags & TRIGGER_RECONNECT)
+ xe_eudebug_client_wait_stage(c, DEBUGGER_REATTACHED);
+ else
+ /* Make sure it wasn't the timeout. */
+ igt_assert(igt_nsec_elapsed(&ts) <
+ XE_EUDEBUG_DEFAULT_TIMEOUT_MS / MSEC_PER_SEC * NSEC_PER_SEC);
ptr = xe_bo_mmap_ext(fd, buf->handle, buf->size, PROT_READ);
data->threads_count = count_canaries_neq(ptr, w_dim, 0);
@@ -1158,6 +1164,117 @@ static void test_tdctl_parameters(int fd, struct drm_xe_engine_class_instance *h
online_debug_data_destroy(data);
}
+static void eu_attention_debugger_detach_trigger(struct xe_eudebug_debugger *d,
+ struct drm_xe_eudebug_event *event)
+{
+ struct online_debug_data *data = d->ptr;
+ unsigned int max_size;
+ uint64_t c_pid;
+ int ret;
+
+ c_pid = d->target_pid;
+
+ /* Reset VM data so the re-triggered VM open handler works properly */
+ data->vm_fd = -1;
+
+ xe_eudebug_debugger_dettach(d);
+
+ /* Let the KMD scan function notice unhandled EU attention */
+ sleep(1);
+
+ /*
+ * New session that is created by EU debugger on reconnect restarts
+ * seqno, causing isses with log sorting. To avoid that, create
+ * a new event log.
+ */
+ max_size = d->log->max_size;
+ xe_eudebug_event_log_destroy(d->log);
+ d->log = xe_eudebug_event_log_create("debugger-reconnect", max_size);
+
+ ret = xe_eudebug_connect(d->master_fd, c_pid, 0);
+ igt_assert(ret >= 0);
+ d->fd = ret;
+ d->target_pid = c_pid;
+
+ /* Let the discovery worker discover resources */
+ sleep(2);
+
+ xe_eudebug_debugger_signal_stage(d, DEBUGGER_REATTACHED);
+}
+
+/**
+ * SUBTEST: interrupt-reconnect
+ * Description:
+ * Schedules EU workload which should last about a few seconds,
+ * interrupts all threads and detaches debugger when attention is
+ * raised. The test checks if KMD resets the workload when there's
+ * no debugger attached and does the event playback on discovery.
+ */
+static void test_interrupt_reconnect(int fd, struct drm_xe_engine_class_instance *hwe, int flags)
+{
+ struct drm_xe_eudebug_event *e = NULL;
+ struct online_debug_data *data;
+ struct xe_eudebug_session *s;
+ uint32_t val;
+
+ data = online_debug_data_create(hwe);
+ s = xe_eudebug_session_create(fd, run_online_client, flags, data);
+
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_OPEN,
+ open_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE,
+ exec_queue_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
+ eu_attention_debug_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
+ eu_attention_debugger_detach_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_VM, vm_open_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_METADATA,
+ create_metadata_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE,
+ ufence_ack_trigger);
+
+ igt_assert_eq(xe_eudebug_debugger_attach(s->d, s->c), 0);
+ xe_eudebug_debugger_start_worker(s->d);
+ xe_eudebug_client_start(s->c);
+
+ /* wait for workload to start */
+ igt_for_milliseconds(STARTUP_TIMEOUT_MS) {
+ /* collect needed data from triggers */
+ if (READ_ONCE(data->vm_fd) == -1 || READ_ONCE(data->target_size) == 0)
+ continue;
+
+ if (pread(data->vm_fd, &val, sizeof(val), data->target_offset) == sizeof(val))
+ if (val != 0)
+ break;
+ }
+
+ pthread_mutex_lock(&data->mutex);
+ igt_assert(data->client_handle != -1);
+ igt_assert(data->exec_queue_handle != -1);
+ eu_ctl_interrupt_all(s->d->fd, data->client_handle,
+ data->exec_queue_handle, data->lrc_handle);
+ pthread_mutex_unlock(&data->mutex);
+
+ xe_eudebug_client_wait_done(s->c);
+
+ xe_eudebug_debugger_stop_worker(s->d, 1);
+
+ xe_eudebug_event_log_print(s->d->log, true);
+ xe_eudebug_event_log_print(s->c->log, true);
+
+ xe_eudebug_session_check(s, true, XE_EUDEBUG_FILTER_EVENT_VM_BIND |
+ XE_EUDEBUG_FILTER_EVENT_VM_BIND_OP |
+ XE_EUDEBUG_FILTER_EVENT_VM_BIND_UFENCE);
+
+ /* We expect workload reset, so no attention should be raised */
+ xe_eudebug_for_each_event(e, s->d->log)
+ igt_assert(e->type != DRM_XE_EUDEBUG_EVENT_EU_ATTENTION);
+
+ xe_eudebug_session_destroy(s);
+ online_debug_data_destroy(data);
+}
+
static struct drm_xe_engine_class_instance *pick_compute(int fd, int gt)
{
struct drm_xe_engine_class_instance *hwe;
@@ -1220,6 +1337,9 @@ igt_main
test_gt_render_or_compute("reset-with-attention", fd, hwe)
test_reset_with_attention_online(fd, hwe, SHADER_BREAKPOINT);
+ test_gt_render_or_compute("interrupt-reconnect", fd, hwe)
+ test_interrupt_reconnect(fd, hwe, SHADER_LOOP | TRIGGER_RECONNECT);
+
igt_fixture {
xe_eudebug_enable(fd, was_enabled);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 59/66] tests/xe_eudebug_online: Add single-step and single-step-one tests
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (57 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 58/66] tests/xe_eudebug_online: Add interrupt-reconnect test Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 60/66] tests/xe_eudebug_online: What if user does not set debug mode? Christoph Manszewski
` (8 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun
From: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
Add single-step test that walks debugger over shader
instruction by instruction in every thread in parallel.
Add single-step-one test that walks debugger over shader
instruction by instruction in one thread at a time.
Signed-off-by: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
tests/intel/xe_eudebug_online.c | 260 ++++++++++++++++++++++++++++++--
1 file changed, 246 insertions(+), 14 deletions(-)
diff --git a/tests/intel/xe_eudebug_online.c b/tests/intel/xe_eudebug_online.c
index 9f55cec74..cabe2101e 100644
--- a/tests/intel/xe_eudebug_online.c
+++ b/tests/intel/xe_eudebug_online.c
@@ -20,16 +20,23 @@
#include "intel_mocs.h"
#include "gpgpu_shader.h"
-#define SHADER_BREAKPOINT (1 << 0)
-#define SHADER_LOOP (1 << 1)
-#define TRIGGER_RECONNECT (1 << 27)
-#define TRIGGER_RESUME_SET_BP (1 << 28)
-#define TRIGGER_RESUME_DELAYED (1 << 29)
-#define TRIGGER_RESUME_DSS (1 << 30)
-#define TRIGGER_RESUME_ONE (1 << 31)
+#define SHADER_BREAKPOINT (1 << 0)
+#define SHADER_LOOP (1 << 1)
+#define SHADER_SINGLE_STEP (1 << 2)
+#define SIP_SINGLE_STEP (1 << 3)
+#define TRIGGER_RESUME_SINGLE_WALK (1 << 25)
+#define TRIGGER_RESUME_PARALLEL_WALK (1 << 26)
+#define TRIGGER_RECONNECT (1 << 27)
+#define TRIGGER_RESUME_SET_BP (1 << 28)
+#define TRIGGER_RESUME_DELAYED (1 << 29)
+#define TRIGGER_RESUME_DSS (1 << 30)
+#define TRIGGER_RESUME_ONE (1 << 31)
#define DEBUGGER_REATTACHED 1
+#define SINGLE_STEP_COUNT 16
+#define STEERING_SINGLE_STEP 0
+#define STEERING_CONTINUE 0x00c0ffee
#define STEERING_END_LOOP 0xdeadca11
#define SHADER_CANARY 0x01010101
@@ -92,7 +99,8 @@ static struct intel_buf *create_uc_buf(int fd, int width, int height)
static int get_number_of_threads(uint64_t flags)
{
- if (flags & (TRIGGER_RESUME_ONE))
+ if (flags & (TRIGGER_RESUME_ONE | TRIGGER_RESUME_SINGLE_WALK |
+ TRIGGER_RESUME_PARALLEL_WALK))
return 32;
return 512;
@@ -114,21 +122,30 @@ static struct gpgpu_shader *get_shader(int fd, const unsigned int flags)
gpgpu_shader__write_dword(shader, SHADER_CANARY, 0);
gpgpu_shader__jump_neq(shader, 0, w_dim.y, STEERING_END_LOOP);
gpgpu_shader__write_dword(shader, SHADER_CANARY, 0);
+ } else if (flags & SHADER_SINGLE_STEP) {
+ gpgpu_shader__nop(shader);
+ gpgpu_shader__breakpoint(shader);
+ for (int i = 0; i < SINGLE_STEP_COUNT; i++)
+ gpgpu_shader__nop(shader);
}
gpgpu_shader__eot(shader);
return shader;
}
-static struct gpgpu_shader *get_sip(int fd)
+static struct gpgpu_shader *get_sip(int fd, const unsigned int flags)
{
+ struct dim_t w_dim = walker_dimensions(get_number_of_threads(flags));
static struct gpgpu_shader *sip;
sip = gpgpu_shader_create(fd);
gpgpu_shader__write_aip(sip, 0);
gpgpu_shader__wait(sip);
- gpgpu_shader__end_system_routine(sip, true);
+ if (flags & SIP_SINGLE_STEP)
+ gpgpu_shader__end_system_routine_step_if_eq(sip, w_dim.y, 0);
+ else
+ gpgpu_shader__end_system_routine(sip, true);
return sip;
}
@@ -281,6 +298,10 @@ struct online_debug_data {
size_t bb_size;
int vm_fd;
uint32_t first_aip;
+ uint64_t *aips_offset_table;
+ uint32_t steps_done;
+ uint8_t *single_step_bitmask;
+ int stepped_threads_count;
struct timespec exception_arrived;
int last_eu_control_seqno;
};
@@ -298,13 +319,14 @@ online_debug_data_create(struct drm_xe_engine_class_instance *hwe)
data->exec_queue_handle = -1ULL;
data->lrc_handle = -1ULL;
data->vm_fd = -1;
+ data->stepped_threads_count = -1;
return data;
}
static void online_debug_data_destroy(struct online_debug_data *data)
{
-
+ free(data->aips_offset_table);
munmap(data, ALIGN(sizeof(*data), PAGE_SIZE));
}
@@ -366,6 +388,25 @@ static void copy_first_bit(uint8_t *dst, uint8_t *src, int size)
}
}
+static void copy_nth_bit(uint8_t *dst, uint8_t *src, int size, int n)
+{
+ int count = 0;
+
+ for (int i = 0; i < size; i++) {
+ uint32_t tmp = src[i];
+ for (int j = 7; j >= 0; j--) {
+ if (tmp & (1 << j)) {
+ count++;
+ if (count == n)
+ dst[i] |= (1 << j);
+ else
+ dst[i] &= ~(1 << j);
+ } else
+ dst[i] &= ~(1 << j);
+ }
+ }
+}
+
/*
* Searches for the first instruction. It stands on assumption,
* that shader kernel is placed before sip within the bb.
@@ -431,6 +472,57 @@ static void set_breakpoint_once(struct xe_eudebug_debugger *d,
gpgpu_shader_destroy(kernel);
}
+static void get_aips_offset_table(struct online_debug_data *data, int threads)
+{
+ size_t sz = sizeof(uint32_t);
+ uint32_t aip;
+ uint32_t first_aip;
+ int table_index = 0;
+
+ if (data->aips_offset_table)
+ return;
+
+ data->aips_offset_table = malloc(threads * sizeof(uint64_t));
+ igt_assert(data->aips_offset_table);
+
+ igt_assert_eq(pread(data->vm_fd, &first_aip, sz, data->target_offset), sz);
+ data->first_aip = first_aip;
+ data->aips_offset_table[table_index++] = 0;
+
+ fsync(data->vm_fd);
+ for (int i = 1; i < data->target_size; i++) {
+ igt_assert_eq(pread(data->vm_fd, &aip, sz, data->target_offset + i), sz);
+ if (aip == first_aip)
+ data->aips_offset_table[table_index++] = i;
+ }
+
+ igt_assert_eq(threads, table_index);
+
+ igt_debug("AIPs offset table:\n");
+ for (int i = 0; i < threads; i++) {
+ igt_debug("%lx\n", data->aips_offset_table[i]);
+ }
+}
+
+static int get_stepped_threads_count(struct online_debug_data *data, int threads)
+{
+ int count = 0;
+ size_t sz = sizeof(uint32_t);
+ uint32_t aip;
+
+ fsync(data->vm_fd);
+ for (int i = 0; i < threads; i++) {
+ igt_assert_eq(pread(data->vm_fd, &aip, sz,
+ data->target_offset + data->aips_offset_table[i]), sz);
+ if (aip != data->first_aip) {
+ igt_assert(aip == data->first_aip + 0x10);
+ count++;
+ }
+ }
+
+ return count;
+}
+
#define MAX_PREEMPT_TIMEOUT 10ull
static void eu_attention_resume_trigger(struct xe_eudebug_debugger *d,
struct drm_xe_eudebug_event *e)
@@ -493,6 +585,98 @@ static void eu_attention_resume_trigger(struct xe_eudebug_debugger *d,
free(bitmask);
}
+static void eu_attention_resume_single_step_trigger(struct xe_eudebug_debugger *d,
+ struct drm_xe_eudebug_event *e)
+{
+ struct drm_xe_eudebug_event_eu_attention *att = (void *) e;
+ struct online_debug_data *data = d->ptr;
+ const int threads = get_number_of_threads(d->flags);
+ uint32_t val;
+ size_t sz = sizeof(uint32_t);
+
+ get_aips_offset_table(data, threads);
+
+ if (d->flags & TRIGGER_RESUME_PARALLEL_WALK) {
+ if (data->stepped_threads_count != -1)
+ if (data->steps_done < SINGLE_STEP_COUNT) {
+ int stepped_threads_count_after_resume =
+ get_stepped_threads_count(data, threads);
+ igt_debug("Stepped threads after: %d\n",
+ stepped_threads_count_after_resume);
+
+ if (stepped_threads_count_after_resume == threads) {
+ data->first_aip += 0x10;
+ data->steps_done++;
+ }
+
+ igt_debug("Shader steps: %d\n", data->steps_done);
+ igt_assert(data->stepped_threads_count == 0);
+ igt_assert(stepped_threads_count_after_resume == threads);
+ }
+
+ if (data->steps_done < SINGLE_STEP_COUNT) {
+ data->stepped_threads_count = get_stepped_threads_count(data, threads);
+ igt_debug("Stepped threads before: %d\n", data->stepped_threads_count);
+ }
+
+ val = data->steps_done < SINGLE_STEP_COUNT ? STEERING_SINGLE_STEP :
+ STEERING_CONTINUE;
+ } else if (d->flags & TRIGGER_RESUME_SINGLE_WALK) {
+ if (data->stepped_threads_count != -1)
+ if (data->steps_done < 2) {
+ int stepped_threads_count_after_resume =
+ get_stepped_threads_count(data, threads);
+ igt_debug("Stepped threads after: %d\n",
+ stepped_threads_count_after_resume);
+
+ if (stepped_threads_count_after_resume == threads) {
+ data->first_aip += 0x10;
+ data->steps_done++;
+ free(data->single_step_bitmask);
+ data->single_step_bitmask = 0;
+ }
+
+ igt_debug("Shader steps: %d\n", data->steps_done);
+ igt_assert(data->stepped_threads_count +
+ (intel_gen_needs_resume_wa(d->master_fd) ? 2 : 1) ==
+ stepped_threads_count_after_resume);
+ }
+
+ if (data->steps_done < 2) {
+ data->stepped_threads_count = get_stepped_threads_count(data, threads);
+ igt_debug("Stepped threads before: %d\n", data->stepped_threads_count);
+ if (intel_gen_needs_resume_wa(d->master_fd)) {
+ if (!data->single_step_bitmask) {
+ data->single_step_bitmask = malloc(att->bitmask_size *
+ sizeof(uint8_t));
+ igt_assert(data->single_step_bitmask);
+ memcpy(data->single_step_bitmask, att->bitmask,
+ att->bitmask_size);
+ }
+
+ copy_first_bit(att->bitmask, data->single_step_bitmask,
+ att->bitmask_size);
+ } else
+ copy_nth_bit(att->bitmask, att->bitmask, att->bitmask_size,
+ data->stepped_threads_count + 1);
+ }
+
+ val = data->steps_done < 2 ? STEERING_SINGLE_STEP : STEERING_CONTINUE;
+ }
+
+ igt_assert_eq(pwrite(data->vm_fd, &val, sz,
+ data->target_offset + steering_offset(threads)), sz);
+ fsync(data->vm_fd);
+
+ eu_ctl_resume(d->master_fd, d->fd, att->client_handle,
+ att->exec_queue_handle, att->lrc_handle,
+ att->bitmask, att->bitmask_size);
+
+ if (data->single_step_bitmask)
+ for (int i = 0; i < att->bitmask_size; i++)
+ data->single_step_bitmask[i] &= ~att->bitmask[i];
+}
+
static void open_trigger(struct xe_eudebug_debugger *d,
struct drm_xe_eudebug_event *e)
{
@@ -614,7 +798,7 @@ static struct intel_bb *xe_bb_create_on_offset(int fd, uint32_t exec_queue, uint
static void run_online_client(struct xe_eudebug_client *c)
{
- const int threads = c->flags & (TRIGGER_RESUME_ONE) ? 64 : 512;
+ int threads = get_number_of_threads(c->flags);
const uint64_t target_offset = 0x1a000000;
const uint64_t bb_offset = 0x1b000000;
const size_t bb_size = 4096;
@@ -651,7 +835,7 @@ static void run_online_client(struct xe_eudebug_client *c)
xe_device_get(fd);
/* Additional memory for steering control */
- if (c->flags & SHADER_LOOP)
+ if (c->flags & SHADER_LOOP || c->flags & SHADER_SINGLE_STEP)
s_dim.y++;
buf = create_uc_buf(fd, s_dim.x, s_dim.y);
@@ -674,7 +858,7 @@ static void run_online_client(struct xe_eudebug_client *c)
bb_offset, bb_size);
intel_bb_set_lr_mode(ibb, true);
- sip = get_sip(fd);
+ sip = get_sip(fd, c->flags);
shader = get_shader(fd, c->flags);
igt_nsec_elapsed(&ts);
@@ -1275,6 +1459,46 @@ static void test_interrupt_reconnect(int fd, struct drm_xe_engine_class_instance
online_debug_data_destroy(data);
}
+/**
+ * SUBTEST: single-step
+ * Description:
+ * Schedules EU workload with 16 nops after breakpoint, then single-steps
+ * through the shader, advances all threads each step, checking if all
+ * threads advanced every step.
+ *
+ * SUBTEST: single-step-one
+ * Description:
+ * Schedules EU workload with 16 nops after breakpoint, then single-steps
+ * through the shader, advances one thread each step, checking if one
+ * thread advanced every step. Due to the time constraint, only first two
+ * shader instructions after breakpoint are validated.
+ */
+static void test_single_step(int fd, struct drm_xe_engine_class_instance *hwe, int flags)
+{
+ struct xe_eudebug_session *s;
+ struct online_debug_data *data;
+
+ data = online_debug_data_create(hwe);
+ s = xe_eudebug_session_create(fd, run_online_client, flags, data);
+
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_OPEN,
+ open_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
+ eu_attention_debug_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
+ eu_attention_resume_single_step_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_VM, vm_open_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_METADATA,
+ create_metadata_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE,
+ ufence_ack_trigger);
+
+ xe_eudebug_session_run(s);
+ online_session_check(s, s->flags);
+ xe_eudebug_session_destroy(s);
+ online_debug_data_destroy(data);
+}
+
static struct drm_xe_engine_class_instance *pick_compute(int fd, int gt)
{
struct drm_xe_engine_class_instance *hwe;
@@ -1340,6 +1564,14 @@ igt_main
test_gt_render_or_compute("interrupt-reconnect", fd, hwe)
test_interrupt_reconnect(fd, hwe, SHADER_LOOP | TRIGGER_RECONNECT);
+ test_gt_render_or_compute("single-step", fd, hwe)
+ test_single_step(fd, hwe, SHADER_SINGLE_STEP | SIP_SINGLE_STEP |
+ TRIGGER_RESUME_PARALLEL_WALK);
+
+ test_gt_render_or_compute("single-step-one", fd, hwe)
+ test_single_step(fd, hwe, SHADER_SINGLE_STEP | SIP_SINGLE_STEP |
+ TRIGGER_RESUME_SINGLE_WALK);
+
igt_fixture {
xe_eudebug_enable(fd, was_enabled);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 60/66] tests/xe_eudebug_online: What if user does not set debug mode?
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (58 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 59/66] tests/xe_eudebug_online: Add single-step and single-step-one tests Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 61/66] tests/xe_eudebug_online: Adds debugger-reopen test Christoph Manszewski
` (7 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Implement test proving that workload is terminated if we hit
exception without having exec queue in debug mode.
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Cc: Christoph Manszewski <christoph.manszewski@intel.com>
---
tests/intel/xe_eudebug_online.c | 22 ++++++++++++++++++----
1 file changed, 18 insertions(+), 4 deletions(-)
diff --git a/tests/intel/xe_eudebug_online.c b/tests/intel/xe_eudebug_online.c
index cabe2101e..8361b6db4 100644
--- a/tests/intel/xe_eudebug_online.c
+++ b/tests/intel/xe_eudebug_online.c
@@ -24,6 +24,7 @@
#define SHADER_LOOP (1 << 1)
#define SHADER_SINGLE_STEP (1 << 2)
#define SIP_SINGLE_STEP (1 << 3)
+#define DISABLE_DEBUG_MODE (1 << 4)
#define TRIGGER_RESUME_SINGLE_WALK (1 << 25)
#define TRIGGER_RESUME_PARALLEL_WALK (1 << 26)
#define TRIGGER_RECONNECT (1 << 27)
@@ -813,7 +814,7 @@ static void run_online_client(struct xe_eudebug_client *c)
.instances = to_user_pointer(&hwe),
.width = 1,
.num_placements = 1,
- .extensions = to_user_pointer(&ext)
+ .extensions = c->flags & DISABLE_DEBUG_MODE ? 0 : to_user_pointer(&ext)
};
struct dim_t w_dim = walker_dimensions(threads);
struct dim_t s_dim = surface_dimensions(threads);
@@ -880,7 +881,8 @@ static void run_online_client(struct xe_eudebug_client *c)
data->threads_count = count_canaries_neq(ptr, w_dim, 0);
igt_assert_f(data->threads_count, "No canaries found, nothing executed?\n");
- if (c->flags & SHADER_BREAKPOINT || c->flags & TRIGGER_RESUME_SET_BP) {
+ if ((c->flags & SHADER_BREAKPOINT || c->flags & TRIGGER_RESUME_SET_BP) &&
+ !(c->flags & DISABLE_DEBUG_MODE)) {
uint32_t aip = ptr[0];
igt_assert_f(aip != SHADER_CANARY, "Workload executed but breakpoint not hit!\n");
@@ -1049,6 +1051,7 @@ static void online_session_check(struct xe_eudebug_session *s, int flags)
struct drm_xe_eudebug_event_eu_attention *ea = NULL;
struct drm_xe_eudebug_event *event = NULL;
struct online_debug_data *data = s->c->ptr;
+ bool expect_exception = flags & DISABLE_DEBUG_MODE ? false : true;
int sum = 0;
int bitmask_size;
@@ -1076,7 +1079,10 @@ static void online_session_check(struct xe_eudebug_session *s, int flags)
if (flags == SHADER_BREAKPOINT)
igt_assert_eq(sum, data->threads_count);
- igt_assert(sum > 0);
+ if (expect_exception)
+ igt_assert(sum > 0);
+ else
+ igt_assert(sum == 0);
}
static void ufence_ack_trigger(struct xe_eudebug_debugger *d,
@@ -1092,7 +1098,12 @@ static void ufence_ack_trigger(struct xe_eudebug_debugger *d,
* SUBTEST: basic-breakpoint
* Description:
* Check whether KMD sends attention events
- * for runalone workload stopped on breakpoint.
+ * for workload in debug mode stopped on breakpoint.
+ *
+ * SUBTEST: breakpoint-not-in-debug-mode
+ * Description:
+ * Check whether KMD resets the GPU when it spots an attention
+ * coming from workload not in debug mode.
*
* SUBTEST: stopped-thread
* Description:
@@ -1540,6 +1551,9 @@ igt_main
test_gt_render_or_compute("basic-breakpoint", fd, hwe)
test_basic_online(fd, hwe, SHADER_BREAKPOINT);
+ test_gt_render_or_compute("breakpoint-not-in-debug-mode", fd, hwe)
+ test_basic_online(fd, hwe, SHADER_BREAKPOINT | DISABLE_DEBUG_MODE);
+
test_gt_render_or_compute("stopped-thread", fd, hwe)
test_basic_online(fd, hwe, SHADER_BREAKPOINT | TRIGGER_RESUME_DELAYED);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 61/66] tests/xe_eudebug_online: Adds debugger-reopen test
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (59 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 60/66] tests/xe_eudebug_online: What if user does not set debug mode? Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 62/66] tests/xe_eudebug_online: Add caching tests Christoph Manszewski
` (6 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun
From: Kolanupaka Naveena <kolanupaka.naveena@intel.com>
Introducing a test which will close and reopen the debugger after
resume on each breakpoint to make sure that the debugger is able to
capture the further events after reopening it.
Signed-off-by: Kolanupaka Naveena <kolanupaka.naveena@intel.com>
Cc: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
---
tests/intel/xe_eudebug_online.c | 68 +++++++++++++++++++++++++++++++--
1 file changed, 64 insertions(+), 4 deletions(-)
diff --git a/tests/intel/xe_eudebug_online.c b/tests/intel/xe_eudebug_online.c
index 8361b6db4..c3c82b061 100644
--- a/tests/intel/xe_eudebug_online.c
+++ b/tests/intel/xe_eudebug_online.c
@@ -25,6 +25,7 @@
#define SHADER_SINGLE_STEP (1 << 2)
#define SIP_SINGLE_STEP (1 << 3)
#define DISABLE_DEBUG_MODE (1 << 4)
+#define SHADER_N_NOOP_BREAKPOINT (1 << 5)
#define TRIGGER_RESUME_SINGLE_WALK (1 << 25)
#define TRIGGER_RESUME_PARALLEL_WALK (1 << 26)
#define TRIGGER_RECONNECT (1 << 27)
@@ -35,6 +36,7 @@
#define DEBUGGER_REATTACHED 1
+#define SHADER_LOOP_N 3
#define SINGLE_STEP_COUNT 16
#define STEERING_SINGLE_STEP 0
#define STEERING_CONTINUE 0x00c0ffee
@@ -128,6 +130,11 @@ static struct gpgpu_shader *get_shader(int fd, const unsigned int flags)
gpgpu_shader__breakpoint(shader);
for (int i = 0; i < SINGLE_STEP_COUNT; i++)
gpgpu_shader__nop(shader);
+ } else if (flags & SHADER_N_NOOP_BREAKPOINT) {
+ for (int i = 0; i < SHADER_LOOP_N; i++) {
+ gpgpu_shader__nop(shader);
+ gpgpu_shader__breakpoint(shader);
+ }
}
gpgpu_shader__eot(shader);
@@ -525,6 +532,7 @@ static int get_stepped_threads_count(struct online_debug_data *data, int threads
}
#define MAX_PREEMPT_TIMEOUT 10ull
+static int is_client_resumed;
static void eu_attention_resume_trigger(struct xe_eudebug_debugger *d,
struct drm_xe_eudebug_event *e)
{
@@ -583,6 +591,7 @@ static void eu_attention_resume_trigger(struct xe_eudebug_debugger *d,
att->exec_queue_handle, att->lrc_handle,
bitmask, att->bitmask_size);
+ is_client_resumed = 1;
free(bitmask);
}
@@ -881,8 +890,8 @@ static void run_online_client(struct xe_eudebug_client *c)
data->threads_count = count_canaries_neq(ptr, w_dim, 0);
igt_assert_f(data->threads_count, "No canaries found, nothing executed?\n");
- if ((c->flags & SHADER_BREAKPOINT || c->flags & TRIGGER_RESUME_SET_BP) &&
- !(c->flags & DISABLE_DEBUG_MODE)) {
+ if ((c->flags & SHADER_BREAKPOINT || c->flags & TRIGGER_RESUME_SET_BP ||
+ c->flags & SHADER_N_NOOP_BREAKPOINT) && !(c->flags & DISABLE_DEBUG_MODE)) {
uint32_t aip = ptr[0];
igt_assert_f(aip != SHADER_CANARY, "Workload executed but breakpoint not hit!\n");
@@ -1375,7 +1384,8 @@ static void eu_attention_debugger_detach_trigger(struct xe_eudebug_debugger *d,
xe_eudebug_debugger_dettach(d);
/* Let the KMD scan function notice unhandled EU attention */
- sleep(1);
+ if (!(d->flags & SHADER_N_NOOP_BREAKPOINT))
+ sleep(1);
/*
* New session that is created by EU debugger on reconnect restarts
@@ -1394,7 +1404,8 @@ static void eu_attention_debugger_detach_trigger(struct xe_eudebug_debugger *d,
/* Let the discovery worker discover resources */
sleep(2);
- xe_eudebug_debugger_signal_stage(d, DEBUGGER_REATTACHED);
+ if (!(d->flags & SHADER_N_NOOP_BREAKPOINT))
+ xe_eudebug_debugger_signal_stage(d, DEBUGGER_REATTACHED);
}
/**
@@ -1510,6 +1521,52 @@ static void test_single_step(int fd, struct drm_xe_engine_class_instance *hwe, i
online_debug_data_destroy(data);
}
+static int debugger_detach_count;
+static void eu_attention_debugger_ndetach_trigger(struct xe_eudebug_debugger *d,
+ struct drm_xe_eudebug_event *event)
+{
+ if (debugger_detach_count < (SHADER_LOOP_N - 1)) {
+ /* Make sure the resume command has issued before detaching the debugger */
+ if (!is_client_resumed)
+ return;
+ eu_attention_debugger_detach_trigger(d, event);
+ debugger_detach_count++;
+ } else {
+ igt_debug("Reached Nth breakpoint hence preventing the debugger detach\n");
+ }
+ is_client_resumed = 0;
+}
+
+/**
+ * SUBTEST: debugger-reopen
+ * Description:
+ * Check whether the debugger is able to reopen the connection and
+ * capture the events of already running client.
+ */
+static void test_debugger_reopen(int fd, struct drm_xe_engine_class_instance *hwe, int flags)
+{
+ struct xe_eudebug_session *s;
+ struct online_debug_data *data;
+
+ data = online_debug_data_create(hwe);
+
+ s = xe_eudebug_session_create(fd, run_online_client, flags, data);
+
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
+ eu_attention_debug_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
+ eu_attention_resume_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
+ eu_attention_debugger_ndetach_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE,
+ ufence_ack_trigger);
+
+ xe_eudebug_session_run(s);
+
+ xe_eudebug_session_destroy(s);
+ online_debug_data_destroy(data);
+}
+
static struct drm_xe_engine_class_instance *pick_compute(int fd, int gt)
{
struct drm_xe_engine_class_instance *hwe;
@@ -1586,6 +1643,9 @@ igt_main
test_single_step(fd, hwe, SHADER_SINGLE_STEP | SIP_SINGLE_STEP |
TRIGGER_RESUME_SINGLE_WALK);
+ test_gt_render_or_compute("debugger-reopen", fd, hwe)
+ test_debugger_reopen(fd, hwe, SHADER_N_NOOP_BREAKPOINT);
+
igt_fixture {
xe_eudebug_enable(fd, was_enabled);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 62/66] tests/xe_eudebug_online: Add caching tests
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (60 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 61/66] tests/xe_eudebug_online: Adds debugger-reopen test Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 63/66] tests/xe_eudebug_online: Add subtests w/o long running mode Christoph Manszewski
` (5 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun
From: Dominik Karol Piatkowski <dominik.karol.piatkowski@intel.com>
Add caching tests that write incrementing values to 2-page-long target
surface, poisoning the data one breakpoint before each write instruction
and restoring it when the poisoned instruction breakpoint is hit. Expect
to never see poison values in target surface.
Signed-off-by: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
tests/intel/xe_eudebug_online.c | 194 +++++++++++++++++++++++++++++++-
1 file changed, 192 insertions(+), 2 deletions(-)
diff --git a/tests/intel/xe_eudebug_online.c b/tests/intel/xe_eudebug_online.c
index c3c82b061..96129c06a 100644
--- a/tests/intel/xe_eudebug_online.c
+++ b/tests/intel/xe_eudebug_online.c
@@ -26,6 +26,8 @@
#define SIP_SINGLE_STEP (1 << 3)
#define DISABLE_DEBUG_MODE (1 << 4)
#define SHADER_N_NOOP_BREAKPOINT (1 << 5)
+#define SHADER_CACHING_SRAM (1 << 6)
+#define SHADER_CACHING_VRAM (1 << 7)
#define TRIGGER_RESUME_SINGLE_WALK (1 << 25)
#define TRIGGER_RESUME_PARALLEL_WALK (1 << 26)
#define TRIGGER_RECONNECT (1 << 27)
@@ -42,6 +44,10 @@
#define STEERING_CONTINUE 0x00c0ffee
#define STEERING_END_LOOP 0xdeadca11
+#define CACHING_INIT_VALUE 0xcafe0000
+#define CACHING_POISON_VALUE 0xcafedead
+#define CACHING_VALUE(n) (CACHING_INIT_VALUE + n)
+
#define SHADER_CANARY 0x01010101
#define WALKER_X_DIM 4
@@ -103,15 +109,31 @@ static struct intel_buf *create_uc_buf(int fd, int width, int height)
static int get_number_of_threads(uint64_t flags)
{
if (flags & (TRIGGER_RESUME_ONE | TRIGGER_RESUME_SINGLE_WALK |
- TRIGGER_RESUME_PARALLEL_WALK))
+ TRIGGER_RESUME_PARALLEL_WALK | SHADER_CACHING_SRAM | SHADER_CACHING_VRAM))
return 32;
return 512;
}
+static int caching_get_instruction_count(int fd, uint32_t s_dim__x, int flags)
+{
+ uint64_t memory;
+
+ igt_assert((flags & SHADER_CACHING_SRAM) || (flags & SHADER_CACHING_VRAM));
+
+ if (flags & SHADER_CACHING_SRAM)
+ memory = system_memory(fd);
+ else
+ memory = vram_memory(fd, 0);
+
+ /* each instruction writes to given y offset */
+ return (2 * xe_min_page_size(fd, memory)) / s_dim__x;
+}
+
static struct gpgpu_shader *get_shader(int fd, const unsigned int flags)
{
struct dim_t w_dim = walker_dimensions(get_number_of_threads(flags));
+ struct dim_t s_dim = surface_dimensions(get_number_of_threads(flags));
static struct gpgpu_shader *shader;
shader = gpgpu_shader_create(fd);
@@ -135,6 +157,13 @@ static struct gpgpu_shader *get_shader(int fd, const unsigned int flags)
gpgpu_shader__nop(shader);
gpgpu_shader__breakpoint(shader);
}
+ } else if ((flags & SHADER_CACHING_SRAM) || (flags & SHADER_CACHING_VRAM)) {
+ gpgpu_shader__nop(shader);
+ gpgpu_shader__breakpoint(shader);
+ for (int i = 0; i < caching_get_instruction_count(fd, s_dim.x, flags); i++)
+ gpgpu_shader__common_target_write_u32(shader, s_dim.y + i, CACHING_VALUE(i));
+ gpgpu_shader__nop(shader);
+ gpgpu_shader__breakpoint(shader);
}
gpgpu_shader__eot(shader);
@@ -791,6 +820,108 @@ static void create_metadata_trigger(struct xe_eudebug_debugger *d, struct drm_xe
}
}
+static void overwrite_immediate_value_in_common_target_write(int vm_fd, uint64_t offset,
+ uint32_t old_val, uint32_t new_val)
+{
+ uint64_t addr = offset;
+ int vals_changed = 0;
+ uint32_t val;
+
+ while (vals_changed < 4) {
+ igt_assert_eq(pread(vm_fd, &val, sizeof(uint32_t), addr), sizeof(uint32_t));
+ if (val == old_val) {
+ igt_debug("val_before_write[%d]: %08x\n", vals_changed, val);
+ igt_assert_eq(pwrite(vm_fd, &new_val, sizeof(uint32_t), addr),
+ sizeof(uint32_t));
+ igt_assert_eq(pread(vm_fd, &val, sizeof(uint32_t), addr),
+ sizeof(uint32_t));
+ igt_debug("val_before_fsync[%d]: %08x\n", vals_changed, val);
+ fsync(vm_fd);
+ igt_assert_eq(pread(vm_fd, &val, sizeof(uint32_t), addr),
+ sizeof(uint32_t));
+ igt_debug("val_after_fsync[%d]: %08x\n", vals_changed, val);
+ igt_assert_eq_u32(val, new_val);
+ vals_changed++;
+ }
+ addr += sizeof(uint32_t);
+ }
+}
+
+static void eu_attention_resume_caching_trigger(struct xe_eudebug_debugger *d,
+ struct drm_xe_eudebug_event *e)
+{
+ struct drm_xe_eudebug_event_eu_attention *att = (void *) e;
+ struct online_debug_data *data = d->ptr;
+ static int counter = 0;
+ static int kernel_in_bb = 0;
+ struct dim_t s_dim = surface_dimensions(get_number_of_threads(d->flags));
+ int val;
+ uint32_t instr_usdw;
+ struct gpgpu_shader *kernel;
+ const uint32_t breakpoint_bit = 1 << 30;
+ struct gpgpu_shader *shader_preamble;
+ struct gpgpu_shader *shader_write_instr;
+
+ shader_preamble = gpgpu_shader_create(d->master_fd);
+ gpgpu_shader__write_dword(shader_preamble, SHADER_CANARY, 0);
+ gpgpu_shader__nop(shader_preamble);
+ gpgpu_shader__breakpoint(shader_preamble);
+
+ shader_write_instr = gpgpu_shader_create(d->master_fd);
+ gpgpu_shader__common_target_write_u32(shader_write_instr, 0, 0);
+
+ if (!kernel_in_bb) {
+ kernel = get_shader(d->master_fd, d->flags);
+ kernel_in_bb = find_kernel_in_bb(kernel, data);
+ gpgpu_shader_destroy(kernel);
+ }
+
+ /* set breakpoint on next write instruction */
+ if (counter < caching_get_instruction_count(d->master_fd, s_dim.x, d->flags)) {
+ igt_assert_eq(pread(data->vm_fd, &instr_usdw, sizeof(instr_usdw),
+ data->bb_offset + kernel_in_bb + shader_preamble->size * 4 +
+ shader_write_instr->size * 4 * counter), sizeof(instr_usdw));
+ instr_usdw |= breakpoint_bit;
+ igt_assert_eq(pwrite(data->vm_fd, &instr_usdw, sizeof(instr_usdw),
+ data->bb_offset + kernel_in_bb + shader_preamble->size * 4 +
+ shader_write_instr->size * 4 * counter), sizeof(instr_usdw));
+ fsync(data->vm_fd);
+ }
+
+ /* restore current instruction */
+ if (counter && counter <= caching_get_instruction_count(d->master_fd, s_dim.x, d->flags))
+ overwrite_immediate_value_in_common_target_write(data->vm_fd,
+ data->bb_offset + kernel_in_bb +
+ shader_preamble->size * 4 +
+ shader_write_instr->size * 4 * (counter - 1),
+ CACHING_POISON_VALUE,
+ CACHING_VALUE(counter - 1));
+
+ /* poison next instruction */
+ if (counter < caching_get_instruction_count(d->master_fd, s_dim.x, d->flags))
+ overwrite_immediate_value_in_common_target_write(data->vm_fd,
+ data->bb_offset + kernel_in_bb +
+ shader_preamble->size * 4 +
+ shader_write_instr->size * 4 * counter,
+ CACHING_VALUE(counter),
+ CACHING_POISON_VALUE);
+
+ gpgpu_shader_destroy(shader_write_instr);
+ gpgpu_shader_destroy(shader_preamble);
+
+ for (int i = 0; i < data->target_size; i += sizeof(uint32_t)) {
+ igt_assert_eq(pread(data->vm_fd, &val, sizeof(val), data->target_offset + i),
+ sizeof(val));
+ igt_assert_f(val != CACHING_POISON_VALUE, "Poison value found at %04d!\n", i);
+ }
+
+ eu_ctl_resume(d->master_fd, d->fd, att->client_handle,
+ att->exec_queue_handle, att->lrc_handle,
+ att->bitmask, att->bitmask_size);
+
+ counter++;
+}
+
static struct intel_bb *xe_bb_create_on_offset(int fd, uint32_t exec_queue, uint32_t vm,
uint64_t offset, uint32_t size)
{
@@ -806,12 +937,20 @@ static struct intel_bb *xe_bb_create_on_offset(int fd, uint32_t exec_queue, uint
return ibb;
}
+static size_t get_bb_size(int flags)
+{
+ if ((flags & SHADER_CACHING_SRAM) || (flags & SHADER_CACHING_VRAM))
+ return 32768;
+
+ return 4096;
+}
+
static void run_online_client(struct xe_eudebug_client *c)
{
int threads = get_number_of_threads(c->flags);
const uint64_t target_offset = 0x1a000000;
const uint64_t bb_offset = 0x1b000000;
- const size_t bb_size = 4096;
+ const size_t bb_size = get_bb_size(c->flags);
struct online_debug_data *data = c->ptr;
struct drm_xe_engine_class_instance hwe = data->hwe;
struct drm_xe_ext_set_property ext = {
@@ -847,6 +986,9 @@ static void run_online_client(struct xe_eudebug_client *c)
/* Additional memory for steering control */
if (c->flags & SHADER_LOOP || c->flags & SHADER_SINGLE_STEP)
s_dim.y++;
+ /* Additional memory for caching check */
+ if ((c->flags & SHADER_CACHING_SRAM) || (c->flags & SHADER_CACHING_VRAM))
+ s_dim.y += caching_get_instruction_count(fd, s_dim.x, c->flags);
buf = create_uc_buf(fd, s_dim.x, s_dim.y);
buf->addr.offset = target_offset;
@@ -1567,6 +1709,48 @@ static void test_debugger_reopen(int fd, struct drm_xe_engine_class_instance *hw
online_debug_data_destroy(data);
}
+/**
+ * SUBTEST: writes-caching-%s
+ * Description:
+ * Write incrementing values to 2-page-long target surface, poisoning the data one breakpoint
+ * before each write instruction and restoring it when the poisoned instruction breakpoint
+ * is hit. Expect to never see poison values in target surface.
+ *
+ *
+ * arg[1]:
+ *
+ * @sram: Use page size of SRAM
+ * @vram: Use page size of VRAM
+ */
+static void test_caching(int fd, struct drm_xe_engine_class_instance *hwe, int flags)
+{
+ struct xe_eudebug_session *s;
+ struct online_debug_data *data;
+
+ if (flags & SHADER_CACHING_VRAM)
+ igt_skip_on_f(!xe_has_vram(fd), "Device does not have VRAM.\n");
+
+ data = online_debug_data_create(hwe);
+ s = xe_eudebug_session_create(fd, run_online_client, flags, data);
+
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_OPEN,
+ open_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
+ eu_attention_debug_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
+ eu_attention_resume_caching_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_VM, vm_open_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_METADATA,
+ create_metadata_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE,
+ ufence_ack_trigger);
+
+ xe_eudebug_session_run(s);
+ online_session_check(s, s->flags);
+ xe_eudebug_session_destroy(s);
+ online_debug_data_destroy(data);
+}
+
static struct drm_xe_engine_class_instance *pick_compute(int fd, int gt)
{
struct drm_xe_engine_class_instance *hwe;
@@ -1646,6 +1830,12 @@ igt_main
test_gt_render_or_compute("debugger-reopen", fd, hwe)
test_debugger_reopen(fd, hwe, SHADER_N_NOOP_BREAKPOINT);
+ test_gt_render_or_compute("writes-caching-sram", fd, hwe)
+ test_caching(fd, hwe, SHADER_CACHING_SRAM);
+
+ test_gt_render_or_compute("writes-caching-vram", fd, hwe)
+ test_caching(fd, hwe, SHADER_CACHING_VRAM);
+
igt_fixture {
xe_eudebug_enable(fd, was_enabled);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 63/66] tests/xe_eudebug_online: Add subtests w/o long running mode
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (61 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 62/66] tests/xe_eudebug_online: Add caching tests Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 64/66] tests/xe_eudebug_online: Add multisession test cases Christoph Manszewski
` (4 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
Currently all our online tests use vms in long running mode. Add 3 subtests
without it to have some coverage for non-lr mode.
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
Cc: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
---
tests/intel/xe_eudebug_online.c | 31 +++++++++++++++++++++++++++++--
1 file changed, 29 insertions(+), 2 deletions(-)
diff --git a/tests/intel/xe_eudebug_online.c b/tests/intel/xe_eudebug_online.c
index 96129c06a..864591a34 100644
--- a/tests/intel/xe_eudebug_online.c
+++ b/tests/intel/xe_eudebug_online.c
@@ -28,6 +28,7 @@
#define SHADER_N_NOOP_BREAKPOINT (1 << 5)
#define SHADER_CACHING_SRAM (1 << 6)
#define SHADER_CACHING_VRAM (1 << 7)
+#define DISABLE_LONG_RUNNING_MODE (1 << 8)
#define TRIGGER_RESUME_SINGLE_WALK (1 << 25)
#define TRIGGER_RESUME_PARALLEL_WALK (1 << 26)
#define TRIGGER_RECONNECT (1 << 27)
@@ -1003,12 +1004,16 @@ static void run_online_client(struct xe_eudebug_client *c)
DRM_XE_DEBUG_METADATA_PROGRAM_MODULE,
2 * sizeof(*metadata), metadata[1]);
- create.vm_id = xe_eudebug_client_vm_create(c, fd, DRM_XE_VM_CREATE_FLAG_LR_MODE, 0);
+ if (c->flags & DISABLE_LONG_RUNNING_MODE)
+ create.vm_id = xe_eudebug_client_vm_create(c, fd, 0, 0);
+ else
+ create.vm_id = xe_eudebug_client_vm_create(c, fd, DRM_XE_VM_CREATE_FLAG_LR_MODE, 0);
+
xe_eudebug_client_exec_queue_create(c, fd, &create);
ibb = xe_bb_create_on_offset(fd, create.exec_queue_id, create.vm_id,
bb_offset, bb_size);
- intel_bb_set_lr_mode(ibb, true);
+ intel_bb_set_lr_mode(ibb, !(c->flags & DISABLE_LONG_RUNNING_MODE));
sip = get_sip(fd, c->flags);
shader = get_shader(fd, c->flags);
@@ -1251,6 +1256,10 @@ static void ufence_ack_trigger(struct xe_eudebug_debugger *d,
* Check whether KMD sends attention events
* for workload in debug mode stopped on breakpoint.
*
+ * SUBTEST: basic-breakpoint-no-lr
+ * Description:
+ * Same as basic-breakpoint but without vm in long running mode.
+ *
* SUBTEST: breakpoint-not-in-debug-mode
* Description:
* Check whether KMD resets the GPU when it spots an attention
@@ -1337,6 +1346,10 @@ static void test_reset_with_attention_online(int fd, struct drm_xe_engine_class_
* interrupts all threads, checks whether attention event came, and
* resumes stopped threads back.
*
+ * SUBTEST: interrupt-all-no-lr
+ * Description:
+ * Same as interrupt-all but without vm in long running mode.
+ *
* SUBTEST: interrupt-all-set-breakpoint
* Description:
* Schedules EU workload which should last about a few seconds, then
@@ -1557,6 +1570,10 @@ static void eu_attention_debugger_detach_trigger(struct xe_eudebug_debugger *d,
* interrupts all threads and detaches debugger when attention is
* raised. The test checks if KMD resets the workload when there's
* no debugger attached and does the event playback on discovery.
+ *
+ * SUBTEST: interrupt-reconnect-no-lr
+ * Description:
+ * Same as interrupt-reconnect but without vm in long running mode.
*/
static void test_interrupt_reconnect(int fd, struct drm_xe_engine_class_instance *hwe, int flags)
{
@@ -1792,6 +1809,9 @@ igt_main
test_gt_render_or_compute("basic-breakpoint", fd, hwe)
test_basic_online(fd, hwe, SHADER_BREAKPOINT);
+ test_gt_render_or_compute("basic-breakpoint-no-lr", fd, hwe)
+ test_basic_online(fd, hwe, SHADER_BREAKPOINT | DISABLE_LONG_RUNNING_MODE);
+
test_gt_render_or_compute("breakpoint-not-in-debug-mode", fd, hwe)
test_basic_online(fd, hwe, SHADER_BREAKPOINT | DISABLE_DEBUG_MODE);
@@ -1807,6 +1827,9 @@ igt_main
test_gt_render_or_compute("interrupt-all", fd, hwe)
test_interrupt_all(fd, hwe, SHADER_LOOP);
+ test_gt_render_or_compute("interrupt-all-no-lr", fd, hwe)
+ test_interrupt_all(fd, hwe, SHADER_LOOP | DISABLE_LONG_RUNNING_MODE);
+
test_gt_render_or_compute("interrupt-all-set-breakpoint", fd, hwe)
test_interrupt_all(fd, hwe, SHADER_LOOP | TRIGGER_RESUME_SET_BP);
@@ -1819,6 +1842,10 @@ igt_main
test_gt_render_or_compute("interrupt-reconnect", fd, hwe)
test_interrupt_reconnect(fd, hwe, SHADER_LOOP | TRIGGER_RECONNECT);
+ test_gt_render_or_compute("interrupt-reconnect-no-lr", fd, hwe)
+ test_interrupt_reconnect(fd, hwe, SHADER_LOOP | TRIGGER_RECONNECT |
+ DISABLE_LONG_RUNNING_MODE);
+
test_gt_render_or_compute("single-step", fd, hwe)
test_single_step(fd, hwe, SHADER_SINGLE_STEP | SIP_SINGLE_STEP |
TRIGGER_RESUME_PARALLEL_WALK);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 64/66] tests/xe_eudebug_online: Add multisession test cases
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (62 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 63/66] tests/xe_eudebug_online: Add subtests w/o long running mode Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 65/66] tests/xe_eudebug_online: Check if eu debugger disables preemption timeout Christoph Manszewski
` (3 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Karolina Stolarek
From: Karolina Stolarek <karolina.stolarek@intel.com>
Add subtests where we run many sessions, either on a single or
multiple tiles. Extract a macro that selects compute or render
engine from the same GT so it can be used in a helper.
Signed-off-by: Karolina Stolarek <karolina.stolarek@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
tests/intel/xe_eudebug_online.c | 208 +++++++++++++++++++++++++++++++-
1 file changed, 202 insertions(+), 6 deletions(-)
diff --git a/tests/intel/xe_eudebug_online.c b/tests/intel/xe_eudebug_online.c
index 864591a34..ab1a57d9b 100644
--- a/tests/intel/xe_eudebug_online.c
+++ b/tests/intel/xe_eudebug_online.c
@@ -29,6 +29,7 @@
#define SHADER_CACHING_SRAM (1 << 6)
#define SHADER_CACHING_VRAM (1 << 7)
#define DISABLE_LONG_RUNNING_MODE (1 << 8)
+#define SHADER_MIN_THREADS (1 << 9)
#define TRIGGER_RESUME_SINGLE_WALK (1 << 25)
#define TRIGGER_RESUME_PARALLEL_WALK (1 << 26)
#define TRIGGER_RECONNECT (1 << 27)
@@ -56,6 +57,7 @@
#define SIMD_SIZE 16
#define STARTUP_TIMEOUT_MS 3000
+#define WORKLOAD_DELAY_US (5000 * 1000)
#define PAGE_SIZE 4096
@@ -109,6 +111,9 @@ static struct intel_buf *create_uc_buf(int fd, int width, int height)
static int get_number_of_threads(uint64_t flags)
{
+ if (flags & SHADER_MIN_THREADS)
+ return 16;
+
if (flags & (TRIGGER_RESUME_ONE | TRIGGER_RESUME_SINGLE_WALK |
TRIGGER_RESUME_PARALLEL_WALK | SHADER_CACHING_SRAM | SHADER_CACHING_VRAM))
return 32;
@@ -342,6 +347,7 @@ struct online_debug_data {
int stepped_threads_count;
struct timespec exception_arrived;
int last_eu_control_seqno;
+ struct drm_xe_eudebug_event *exception_event;
};
static struct online_debug_data *
@@ -561,6 +567,19 @@ static int get_stepped_threads_count(struct online_debug_data *data, int threads
return count;
}
+static void save_first_exception_trigger(struct xe_eudebug_debugger *d,
+ struct drm_xe_eudebug_event *e)
+{
+ struct online_debug_data *data = d->ptr;
+
+ pthread_mutex_lock(&data->mutex);
+ if (!data->exception_event) {
+ igt_gettime(&data->exception_arrived);
+ data->exception_event = igt_memdup(e, e->len);
+ }
+ pthread_mutex_unlock(&data->mutex);
+}
+
#define MAX_PREEMPT_TIMEOUT 10ull
static int is_client_resumed;
static void eu_attention_resume_trigger(struct xe_eudebug_debugger *d,
@@ -1768,22 +1787,193 @@ static void test_caching(int fd, struct drm_xe_engine_class_instance *hwe, int f
online_debug_data_destroy(data);
}
+static int wait_for_exception(struct online_debug_data *data, int timeout)
+{
+ int ret = -ETIMEDOUT;
+
+ igt_for_milliseconds(timeout) {
+ pthread_mutex_lock(&data->mutex);
+ if ((data->exception_arrived.tv_sec |
+ data->exception_arrived.tv_nsec) != 0)
+ ret = 0;
+ pthread_mutex_unlock(&data->mutex);
+
+ if (!ret)
+ break;
+ usleep(1000);
+ }
+
+ return ret;
+}
+
+#define is_compute_on_gt(__e, __gt) ((__e->engine_class == DRM_XE_ENGINE_CLASS_RENDER || \
+ __e->engine_class == DRM_XE_ENGINE_CLASS_COMPUTE) && \
+ __e->gt_id == __gt)
+
+struct xe_engine_list_entry {
+ struct igt_list_head link;
+ struct drm_xe_engine_class_instance *hwe;
+};
+
+#define MAX_TILES 2
+static int find_suitable_engines(struct drm_xe_engine_class_instance *hwes[GEM_MAX_ENGINES],
+ int fd, bool many_tiles)
+{
+ struct xe_device *xe_dev;
+ struct drm_xe_engine_class_instance *e;
+ struct xe_engine_list_entry *en, *tmp;
+ struct igt_list_head compute_engines[MAX_TILES];
+ int gt_id;
+ int tile_id, i, engine_count = 0, tile_count = 0;
+
+ xe_dev = xe_device_get(fd);
+
+ for (i = 0; i < MAX_TILES; i++)
+ IGT_INIT_LIST_HEAD(&compute_engines[i]);
+
+ xe_for_each_gt(fd, gt_id) {
+ xe_for_each_engine(fd, e) {
+ if (is_compute_on_gt(e, gt_id)) {
+ tile_id = xe_dev->gt_list->gt_list[gt_id].tile_id;
+
+ en = malloc(sizeof(struct xe_engine_list_entry));
+ en->hwe = e;
+
+ igt_list_add_tail(&en->link, &compute_engines[tile_id]);
+ }
+ }
+ }
+
+ for (i = 0; i < MAX_TILES; i++) {
+ if (igt_list_empty(&compute_engines[i]))
+ continue;
+
+ if (many_tiles) {
+ en = igt_list_first_entry(&compute_engines[i], en, link);
+ hwes[engine_count++] = en->hwe;
+ tile_count++;
+ } else {
+ if (igt_list_length(&compute_engines[i]) > 1) {
+ igt_list_for_each_entry(en, &compute_engines[i], link)
+ hwes[engine_count++] = en->hwe;
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < MAX_TILES; i++) {
+ igt_list_for_each_entry_safe(en, tmp, &compute_engines[i], link) {
+ igt_list_del(&en->link);
+ free(en);
+ }
+ }
+
+ if (many_tiles)
+ igt_require_f(tile_count > 1, "Mulit-tile scenario requires more tiles\n");
+
+ return engine_count;
+}
+
+/**
+ * SUBTEST: breakpoint-many-sessions-single-tile
+ * Description:
+ * Schedules EU workload with preinstalled breakpoint on every compute engine
+ * available on the tile. Checks if the contexts hit breakpoint in sequence
+ * and resumes them.
+ *
+ * SUBTEST: breakpoint-many-sessions-tiles
+ * Description:
+ * Schedules EU workload with preinstalled breakpoint on selected compute
+ * engines, with one per tile. Checks if each context hit breakpoint and
+ * resumes them.
+ */
+static void test_many_sessions_on_tiles(int fd, bool multi_tile)
+{
+ int n = 0, flags = SHADER_BREAKPOINT | SHADER_MIN_THREADS;
+ struct xe_eudebug_session *s[GEM_MAX_ENGINES] = {};
+ struct online_debug_data *data[GEM_MAX_ENGINES] = {};
+ struct drm_xe_engine_class_instance *hwe[GEM_MAX_ENGINES] = {};
+ struct drm_xe_eudebug_event_eu_attention *eus;
+ uint64_t current_t, next_t, diff;
+ int i;
+
+ n = find_suitable_engines(hwe, fd, multi_tile);
+
+ igt_require_f(n > 1, "Test requires at least two parallel compute engines!\n");
+
+ for (i = 0; i < n; i++) {
+ data[i] = online_debug_data_create(hwe[i]);
+ s[i] = xe_eudebug_session_create(fd, run_online_client, flags, data[i]);
+
+ xe_eudebug_debugger_add_trigger(s[i]->d, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
+ eu_attention_debug_trigger);
+ xe_eudebug_debugger_add_trigger(s[i]->d, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
+ save_first_exception_trigger);
+ xe_eudebug_debugger_add_trigger(s[i]->d, DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE,
+ ufence_ack_trigger);
+
+ igt_assert_eq(xe_eudebug_debugger_attach(s[i]->d, s[i]->c), 0);
+
+ xe_eudebug_debugger_start_worker(s[i]->d);
+ xe_eudebug_client_start(s[i]->c);
+ }
+
+ for (i = 0; i < n; i++) {
+ /* XXX: Sometimes racy, expects clients to execute in sequence */
+ igt_assert(!wait_for_exception(data[i], STARTUP_TIMEOUT_MS));
+
+ eus = (struct drm_xe_eudebug_event_eu_attention *)data[i]->exception_event;
+
+ /* Delay all but the last workload to check serialization */
+ if (i < n - 1)
+ usleep(WORKLOAD_DELAY_US);
+
+ eu_ctl_resume(s[i]->d->master_fd, s[i]->d->fd,
+ eus->client_handle, eus->exec_queue_handle,
+ eus->lrc_handle, eus->bitmask, eus->bitmask_size);
+ free(eus);
+ }
+
+ for (i = 0; i < n - 1; i++) {
+ /* Convert timestamps to microseconds */
+ current_t = data[i]->exception_arrived.tv_nsec * 1000;
+ next_t = data[i + 1]->exception_arrived.tv_nsec * 1000;
+ diff = current_t < next_t ? next_t - current_t : current_t - next_t;
+
+ if (multi_tile)
+ igt_assert_f(diff < WORKLOAD_DELAY_US,
+ "Expected to execute workloads concurrently. Actual delay: %lu ms\n",
+ diff);
+ else
+ igt_assert_f(diff >= WORKLOAD_DELAY_US,
+ "Expected a serialization of workloads. Actual delay: %lu ms\n",
+ diff);
+ }
+
+ for (i = 0; i < n; i++) {
+ xe_eudebug_client_wait_done(s[i]->c);
+ xe_eudebug_debugger_stop_worker(s[i]->d, 1);
+
+ xe_eudebug_event_log_print(s[i]->d->log, true);
+ online_session_check(s[i], flags);
+
+ xe_eudebug_session_destroy(s[i]);
+ online_debug_data_destroy(data[i]);
+ }
+}
+
static struct drm_xe_engine_class_instance *pick_compute(int fd, int gt)
{
struct drm_xe_engine_class_instance *hwe;
int count = 0;
- #define match(__e) ((__e->engine_class == DRM_XE_ENGINE_CLASS_RENDER || \
- __e->engine_class == DRM_XE_ENGINE_CLASS_COMPUTE) && __e->gt_id == gt)
-
xe_for_each_engine(fd, hwe)
- if (match(hwe))
+ if (is_compute_on_gt(hwe, gt))
count++;
xe_for_each_engine(fd, hwe)
- if (match(hwe) && rand() % count-- == 0)
+ if (is_compute_on_gt(hwe, gt) && rand() % count-- == 0)
return hwe;
- #undef match
return NULL;
}
@@ -1863,6 +2053,12 @@ igt_main
test_gt_render_or_compute("writes-caching-vram", fd, hwe)
test_caching(fd, hwe, SHADER_CACHING_VRAM);
+ igt_subtest("breakpoint-many-sessions-single-tile")
+ test_many_sessions_on_tiles(fd, false);
+
+ igt_subtest("breakpoint-many-sessions-tiles")
+ test_many_sessions_on_tiles(fd, true);
+
igt_fixture {
xe_eudebug_enable(fd, was_enabled);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 65/66] tests/xe_eudebug_online: Check if eu debugger disables preemption timeout
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (63 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 64/66] tests/xe_eudebug_online: Add multisession test cases Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 16:01 ` [PATCH 66/66] tests/xe_live_ktest: Add xe_eudebug live test Christoph Manszewski
` (2 subsequent siblings)
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Workloads could potentially be stopped on a breakpoint for a long time,
due to that eu debugger needs to disable preemption timeout to
prevent reset of such workload. Verify that.
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Cc: Christoph Manszewski <christoph.manszewski@intel.com>
---
tests/intel/xe_eudebug_online.c | 49 +++++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
diff --git a/tests/intel/xe_eudebug_online.c b/tests/intel/xe_eudebug_online.c
index ab1a57d9b..6a451b2a4 100644
--- a/tests/intel/xe_eudebug_online.c
+++ b/tests/intel/xe_eudebug_online.c
@@ -20,6 +20,7 @@
#include "intel_mocs.h"
#include "gpgpu_shader.h"
+#define SHADER_NOP (0 << 0)
#define SHADER_BREAKPOINT (1 << 0)
#define SHADER_LOOP (1 << 1)
#define SHADER_SINGLE_STEP (1 << 2)
@@ -1322,6 +1323,51 @@ static void test_basic_online(int fd, struct drm_xe_engine_class_instance *hwe,
online_debug_data_destroy(data);
}
+/**
+ * SUBTEST: preempt-breakpoint
+ * Description:
+ * Verify that eu debugger disables preemption timeout to
+ * prevent reset of workload stopped on breakpoint.
+ */
+static void test_preemption(int fd, struct drm_xe_engine_class_instance *hwe)
+{
+ int flags = SHADER_BREAKPOINT | TRIGGER_RESUME_DELAYED;
+ struct xe_eudebug_session *s;
+ struct online_debug_data *data;
+ struct xe_eudebug_client *other;
+
+ data = online_debug_data_create(hwe);
+ s = xe_eudebug_session_create(fd, run_online_client, flags, data);
+ other = xe_eudebug_client_create(fd, run_online_client, SHADER_NOP, data);
+
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
+ eu_attention_debug_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
+ eu_attention_resume_trigger);
+ xe_eudebug_debugger_add_trigger(s->d, DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE,
+ ufence_ack_trigger);
+
+ igt_assert_eq(xe_eudebug_debugger_attach(s->d, s->c), 0);
+ xe_eudebug_debugger_start_worker(s->d);
+
+ xe_eudebug_client_start(s->c);
+ sleep(1); /* make sure s->c starts first */
+ xe_eudebug_client_start(other);
+
+ xe_eudebug_client_wait_done(s->c);
+ xe_eudebug_client_wait_done(other);
+
+ xe_eudebug_debugger_stop_worker(s->d, 1);
+
+ xe_eudebug_session_destroy(s);
+ xe_eudebug_client_destroy(other);
+
+ igt_assert_f(data->last_eu_control_seqno != 0,
+ "Workload with breakpoint has ended without resume!\n");
+
+ online_debug_data_destroy(data);
+}
+
/**
* SUBTEST: reset-with-attention
* Description:
@@ -2002,6 +2048,9 @@ igt_main
test_gt_render_or_compute("basic-breakpoint-no-lr", fd, hwe)
test_basic_online(fd, hwe, SHADER_BREAKPOINT | DISABLE_LONG_RUNNING_MODE);
+ test_gt_render_or_compute("preempt-breakpoint", fd, hwe)
+ test_preemption(fd, hwe);
+
test_gt_render_or_compute("breakpoint-not-in-debug-mode", fd, hwe)
test_basic_online(fd, hwe, SHADER_BREAKPOINT | DISABLE_DEBUG_MODE);
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 66/66] tests/xe_live_ktest: Add xe_eudebug live test
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (64 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 65/66] tests/xe_eudebug_online: Check if eu debugger disables preemption timeout Christoph Manszewski
@ 2024-07-29 16:01 ` Christoph Manszewski
2024-07-29 19:18 ` ✗ Fi.CI.BUILD: failure for Test coverage for GPU debug support Patchwork
2024-07-29 19:21 ` ✗ GitLab.Pipeline: warning " Patchwork
67 siblings, 0 replies; 71+ messages in thread
From: Christoph Manszewski @ 2024-07-29 16:01 UTC (permalink / raw)
To: igt-dev
Cc: Zbigniew Kempczyński, Kamil Konieczny, Dominik Grzegorzek,
Maciej Patelczyk, Dominik Karol Piątkowski, Pawel Sikora,
Andrzej Hajda, Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun,
Christoph Manszewski
xe_eudebug introduces a dedicated kunit test to the live test module.
Add it to the list of live tests to be executed.
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
---
tests/intel/xe_live_ktest.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/tests/intel/xe_live_ktest.c b/tests/intel/xe_live_ktest.c
index 4376d5df7..50af97ecc 100644
--- a/tests/intel/xe_live_ktest.c
+++ b/tests/intel/xe_live_ktest.c
@@ -30,6 +30,11 @@
* Description:
* Kernel dynamic selftests to check mocs configuration.
* Functionality: mocs configuration
+ *
+ * SUBTEST: xe_eudebug
+ * Description:
+ * Kernel dynamic selftests to check eudebug functionality.
+ * Functionality: eudebug kunit
*/
static const char *live_tests[] = {
@@ -37,6 +42,7 @@ static const char *live_tests[] = {
"xe_dma_buf",
"xe_migrate",
"xe_mocs",
+ "xe_eudebug",
};
igt_main
--
2.34.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* ✗ Fi.CI.BUILD: failure for Test coverage for GPU debug support
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (65 preceding siblings ...)
2024-07-29 16:01 ` [PATCH 66/66] tests/xe_live_ktest: Add xe_eudebug live test Christoph Manszewski
@ 2024-07-29 19:18 ` Patchwork
2024-07-29 19:21 ` ✗ GitLab.Pipeline: warning " Patchwork
67 siblings, 0 replies; 71+ messages in thread
From: Patchwork @ 2024-07-29 19:18 UTC (permalink / raw)
To: Christoph Manszewski; +Cc: igt-dev
== Series Details ==
Series: Test coverage for GPU debug support
URL : https://patchwork.freedesktop.org/series/136623/
State : failure
== Summary ==
IGT patchset build failed on latest successful build
0f02dc176959e6296866b1bafd3982e277a5e44b tests/core_hotunplug: Fix inline comment on missing device nodes
Tail of build.log:
138 | xe_eudebug_trigger_fn fn);
| ~~~~~~~~~~~~~~~~~~~~~~^~
../../../usr/src/igt-gpu-tools/tests/intel/xe_eudebug_online.c: In function ‘test_many_sessions_on_tiles’:
../../../usr/src/igt-gpu-tools/tests/intel/xe_eudebug_online.c:1954:44: error: ‘DRM_XE_EUDEBUG_EVENT_EU_ATTENTION’ undeclared (first use in this function); did you mean ‘XE_EUDEBUG_FILTER_EVENT_EU_ATTENTION’?
1954 | xe_eudebug_debugger_add_trigger(s[i]->d, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| XE_EUDEBUG_FILTER_EVENT_EU_ATTENTION
../../../usr/src/igt-gpu-tools/tests/intel/xe_eudebug_online.c:1955:7: warning: passing argument 3 of ‘xe_eudebug_debugger_add_trigger’ from incompatible pointer type [-Wincompatible-pointer-types]
1955 | eu_attention_debug_trigger);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
| |
| void (*)(struct xe_eudebug_debugger *, struct drm_xe_eudebug_event *)
In file included from ../../../usr/src/igt-gpu-tools/tests/intel/xe_eudebug_online.c:15:
../../../usr/src/igt-gpu-tools/lib/xe/xe_eudebug.h:138:32: note: expected ‘xe_eudebug_trigger_fn’ {aka ‘void (*)(struct xe_eudebug_debugger *, struct drm_xe_eudebug_event *)’} but argument is of type ‘void (*)(struct xe_eudebug_debugger *, struct drm_xe_eudebug_event *)’
138 | xe_eudebug_trigger_fn fn);
| ~~~~~~~~~~~~~~~~~~~~~~^~
../../../usr/src/igt-gpu-tools/tests/intel/xe_eudebug_online.c:1957:7: warning: passing argument 3 of ‘xe_eudebug_debugger_add_trigger’ from incompatible pointer type [-Wincompatible-pointer-types]
1957 | save_first_exception_trigger);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
| |
| void (*)(struct xe_eudebug_debugger *, struct drm_xe_eudebug_event *)
In file included from ../../../usr/src/igt-gpu-tools/tests/intel/xe_eudebug_online.c:15:
../../../usr/src/igt-gpu-tools/lib/xe/xe_eudebug.h:138:32: note: expected ‘xe_eudebug_trigger_fn’ {aka ‘void (*)(struct xe_eudebug_debugger *, struct drm_xe_eudebug_event *)’} but argument is of type ‘void (*)(struct xe_eudebug_debugger *, struct drm_xe_eudebug_event *)’
138 | xe_eudebug_trigger_fn fn);
| ~~~~~~~~~~~~~~~~~~~~~~^~
../../../usr/src/igt-gpu-tools/tests/intel/xe_eudebug_online.c:1958:44: error: ‘DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE’ undeclared (first use in this function); did you mean ‘XE_EUDEBUG_FILTER_EVENT_VM_BIND_UFENCE’?
1958 | xe_eudebug_debugger_add_trigger(s[i]->d, DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| XE_EUDEBUG_FILTER_EVENT_VM_BIND_UFENCE
../../../usr/src/igt-gpu-tools/tests/intel/xe_eudebug_online.c:1959:7: warning: passing argument 3 of ‘xe_eudebug_debugger_add_trigger’ from incompatible pointer type [-Wincompatible-pointer-types]
1959 | ufence_ack_trigger);
| ^~~~~~~~~~~~~~~~~~
| |
| void (*)(struct xe_eudebug_debugger *, struct drm_xe_eudebug_event *)
In file included from ../../../usr/src/igt-gpu-tools/tests/intel/xe_eudebug_online.c:15:
../../../usr/src/igt-gpu-tools/lib/xe/xe_eudebug.h:138:32: note: expected ‘xe_eudebug_trigger_fn’ {aka ‘void (*)(struct xe_eudebug_debugger *, struct drm_xe_eudebug_event *)’} but argument is of type ‘void (*)(struct xe_eudebug_debugger *, struct drm_xe_eudebug_event *)’
138 | xe_eudebug_trigger_fn fn);
| ~~~~~~~~~~~~~~~~~~~~~~^~
../../../usr/src/igt-gpu-tools/tests/intel/xe_eudebug_online.c:1978:13: error: dereferencing pointer to incomplete type ‘struct drm_xe_eudebug_event_eu_attention’
1978 | eus->client_handle, eus->exec_queue_handle,
| ^~
../../../usr/src/igt-gpu-tools/tests/intel/xe_eudebug_online.c: In function ‘eu_ctl_interrupt_all’:
../../../usr/src/igt-gpu-tools/tests/intel/xe_eudebug_online.c:327:1: error: control reaches end of non-void function [-Werror=return-type]
327 | }
| ^
cc1: some warnings being treated as errors
[694/1764] Compiling C object 'tests/59830eb@@perf_pmu@exe/intel_perf_pmu.c.o'.
[695/1764] Compiling C object 'tests/59830eb@@gem_exec_schedule@exe/intel_gem_exec_schedule.c.o'.
[696/1764] Compiling C object 'tests/59830eb@@perf@exe/intel_perf.c.o'.
ninja: build stopped: subcommand failed.
^ permalink raw reply [flat|nested] 71+ messages in thread
* ✗ GitLab.Pipeline: warning for Test coverage for GPU debug support
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
` (66 preceding siblings ...)
2024-07-29 19:18 ` ✗ Fi.CI.BUILD: failure for Test coverage for GPU debug support Patchwork
@ 2024-07-29 19:21 ` Patchwork
67 siblings, 0 replies; 71+ messages in thread
From: Patchwork @ 2024-07-29 19:21 UTC (permalink / raw)
To: Christoph Manszewski; +Cc: igt-dev
== Series Details ==
Series: Test coverage for GPU debug support
URL : https://patchwork.freedesktop.org/series/136623/
State : warning
== Summary ==
Pipeline status: FAILED.
see https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/pipelines/1236035 for the overview.
build:tests-debian-meson has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/61654173):
int __n1 = (n1), __n2 = (n2); \
^~
../lib/xe/xe_eudebug.c:2185:2: note: in expansion of macro ‘igt_assert_eq’
igt_assert_eq(igt_ioctl(debugfd, DRM_XE_EUDEBUG_IOCTL_ACK_EVENT, &ack), 0);
^~~~~~~~~~~~~
../lib/xe/xe_eudebug.c:2177:34: warning: unused variable ‘ack’ [-Wunused-variable]
struct drm_xe_eudebug_ack_event ack = { 0, };
^~~
../lib/xe/xe_eudebug.c: In function ‘xe_eudebug_client_metadata_create’:
../lib/xe/xe_eudebug.c:2150:1: error: control reaches end of non-void function [-Werror=return-type]
}
^
cc1: some warnings being treated as errors
ninja: build stopped: subcommand failed.
section_end:1722280796:step_script
section_start:1722280796:cleanup_file_variables
Cleaning up project directory and file based variables
section_end:1722280797:cleanup_file_variables
ERROR: Job failed: exit code 1
build:tests-debian-meson-arm64 has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/61654176):
int __n1 = (n1), __n2 = (n2); \
^~
../lib/xe/xe_eudebug.c:2185:2: note: in expansion of macro ‘igt_assert_eq’
igt_assert_eq(igt_ioctl(debugfd, DRM_XE_EUDEBUG_IOCTL_ACK_EVENT, &ack), 0);
^~~~~~~~~~~~~
../lib/xe/xe_eudebug.c:2177:34: warning: unused variable ‘ack’ [-Wunused-variable]
struct drm_xe_eudebug_ack_event ack = { 0, };
^~~
../lib/xe/xe_eudebug.c: In function ‘xe_eudebug_client_metadata_create’:
../lib/xe/xe_eudebug.c:2150:1: error: control reaches end of non-void function [-Werror=return-type]
}
^
cc1: some warnings being treated as errors
ninja: build stopped: subcommand failed.
section_end:1722280801:step_script
section_start:1722280801:cleanup_file_variables
Cleaning up project directory and file based variables
section_end:1722280802:cleanup_file_variables
ERROR: Job failed: exit code 1
build:tests-debian-meson-armhf has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/61654175):
int __n1 = (n1), __n2 = (n2); \
^~
../lib/xe/xe_eudebug.c:2185:2: note: in expansion of macro ‘igt_assert_eq’
igt_assert_eq(igt_ioctl(debugfd, DRM_XE_EUDEBUG_IOCTL_ACK_EVENT, &ack), 0);
^~~~~~~~~~~~~
../lib/xe/xe_eudebug.c:2177:34: warning: unused variable ‘ack’ [-Wunused-variable]
struct drm_xe_eudebug_ack_event ack = { 0, };
^~~
../lib/xe/xe_eudebug.c: In function ‘xe_eudebug_client_metadata_create’:
../lib/xe/xe_eudebug.c:2150:1: error: control reaches end of non-void function [-Werror=return-type]
}
^
cc1: some warnings being treated as errors
ninja: build stopped: subcommand failed.
section_end:1722280803:step_script
section_start:1722280803:cleanup_file_variables
Cleaning up project directory and file based variables
section_end:1722280803:cleanup_file_variables
ERROR: Job failed: exit code 1
build:tests-debian-meson-mips has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/61654177):
int __n1 = (n1), __n2 = (n2); \
^~
../lib/xe/xe_eudebug.c:2185:2: note: in expansion of macro ‘igt_assert_eq’
igt_assert_eq(igt_ioctl(debugfd, DRM_XE_EUDEBUG_IOCTL_ACK_EVENT, &ack), 0);
^~~~~~~~~~~~~
../lib/xe/xe_eudebug.c:2177:34: warning: unused variable ‘ack’ [-Wunused-variable]
struct drm_xe_eudebug_ack_event ack = { 0, };
^~~
../lib/xe/xe_eudebug.c: In function ‘xe_eudebug_client_metadata_create’:
../lib/xe/xe_eudebug.c:2150:1: error: control reaches end of non-void function [-Werror=return-type]
}
^
cc1: some warnings being treated as errors
ninja: build stopped: subcommand failed.
section_end:1722280804:step_script
section_start:1722280804:cleanup_file_variables
Cleaning up project directory and file based variables
section_end:1722280805:cleanup_file_variables
ERROR: Job failed: exit code 1
build:tests-debian-minimal has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/61654174):
int __n1 = (n1), __n2 = (n2); \
^~
../lib/xe/xe_eudebug.c:2185:2: note: in expansion of macro ‘igt_assert_eq’
igt_assert_eq(igt_ioctl(debugfd, DRM_XE_EUDEBUG_IOCTL_ACK_EVENT, &ack), 0);
^~~~~~~~~~~~~
../lib/xe/xe_eudebug.c:2177:34: warning: unused variable ‘ack’ [-Wunused-variable]
struct drm_xe_eudebug_ack_event ack = { 0, };
^~~
../lib/xe/xe_eudebug.c: In function ‘xe_eudebug_client_metadata_create’:
../lib/xe/xe_eudebug.c:2150:1: error: control reaches end of non-void function [-Werror=return-type]
}
^
cc1: some warnings being treated as errors
ninja: build stopped: subcommand failed.
section_end:1722280790:step_script
section_start:1722280790:cleanup_file_variables
Cleaning up project directory and file based variables
section_end:1722280791:cleanup_file_variables
ERROR: Job failed: exit code 1
build:tests-fedora has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/61654168):
737 | int __n1 = (n1), __n2 = (n2); \
| ^~
../lib/xe/xe_eudebug.c:2185:2: note: in expansion of macro ‘igt_assert_eq’
2185 | igt_assert_eq(igt_ioctl(debugfd, DRM_XE_EUDEBUG_IOCTL_ACK_EVENT, &ack), 0);
| ^~~~~~~~~~~~~
../lib/xe/xe_eudebug.c:2177:34: warning: unused variable ‘ack’ [-Wunused-variable]
2177 | struct drm_xe_eudebug_ack_event ack = { 0, };
| ^~~
../lib/xe/xe_eudebug.c: In function ‘xe_eudebug_client_metadata_create’:
../lib/xe/xe_eudebug.c:2150:1: error: control reaches end of non-void function [-Werror=return-type]
2150 | }
| ^
cc1: some warnings being treated as errors
ninja: build stopped: subcommand failed.
section_end:1722280798:step_script
section_start:1722280798:cleanup_file_variables
Cleaning up project directory and file based variables
section_end:1722280798:cleanup_file_variables
ERROR: Job failed: exit code 1
build:tests-fedora-clang has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/61654172):
if (flags & DRM_XE_EUDEBUG_EVENT_STATE_CHANGE)
^
../lib/xe/xe_eudebug.c:105:23: error: use of undeclared identifier 'DRM_XE_EUDEBUG_EVENT_NEED_ACK'
igt_assert(!(flags & DRM_XE_EUDEBUG_EVENT_NEED_ACK));
^
../lib/xe/xe_eudebug.c:112:11: error: incomplete definition of type 'struct drm_xe_eudebug_event'
switch (e->type) {
~^
../lib/xe/xe_eudebug.h:117:8: note: forward declaration of 'struct drm_xe_eudebug_event'
struct drm_xe_eudebug_event *
^
fatal error: too many errors emitted, stopping now [-ferror-limit=]
3 warnings and 20 errors generated.
ninja: build stopped: subcommand failed.
section_end:1722280804:step_script
section_start:1722280804:cleanup_file_variables
Cleaning up project directory and file based variables
section_end:1722280804:cleanup_file_variables
ERROR: Job failed: exit code 1
build:tests-fedora-no-libdrm-nouveau has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/61654171):
737 | int __n1 = (n1), __n2 = (n2); \
| ^~
../lib/xe/xe_eudebug.c:2185:2: note: in expansion of macro ‘igt_assert_eq’
2185 | igt_assert_eq(igt_ioctl(debugfd, DRM_XE_EUDEBUG_IOCTL_ACK_EVENT, &ack), 0);
| ^~~~~~~~~~~~~
../lib/xe/xe_eudebug.c:2177:34: warning: unused variable ‘ack’ [-Wunused-variable]
2177 | struct drm_xe_eudebug_ack_event ack = { 0, };
| ^~~
../lib/xe/xe_eudebug.c: In function ‘xe_eudebug_client_metadata_create’:
../lib/xe/xe_eudebug.c:2150:1: error: control reaches end of non-void function [-Werror=return-type]
2150 | }
| ^
cc1: some warnings being treated as errors
ninja: build stopped: subcommand failed.
section_end:1722280799:step_script
section_start:1722280799:cleanup_file_variables
Cleaning up project directory and file based variables
section_end:1722280801:cleanup_file_variables
ERROR: Job failed: exit code 1
build:tests-fedora-no-libunwind has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/61654169):
737 | int __n1 = (n1), __n2 = (n2); \
| ^~
../lib/xe/xe_eudebug.c:2185:2: note: in expansion of macro ‘igt_assert_eq’
2185 | igt_assert_eq(igt_ioctl(debugfd, DRM_XE_EUDEBUG_IOCTL_ACK_EVENT, &ack), 0);
| ^~~~~~~~~~~~~
../lib/xe/xe_eudebug.c:2177:34: warning: unused variable ‘ack’ [-Wunused-variable]
2177 | struct drm_xe_eudebug_ack_event ack = { 0, };
| ^~~
../lib/xe/xe_eudebug.c: In function ‘xe_eudebug_client_metadata_create’:
../lib/xe/xe_eudebug.c:2150:1: error: control reaches end of non-void function [-Werror=return-type]
2150 | }
| ^
cc1: some warnings being treated as errors
ninja: build stopped: subcommand failed.
section_end:1722280799:step_script
section_start:1722280799:cleanup_file_variables
Cleaning up project directory and file based variables
section_end:1722280800:cleanup_file_variables
ERROR: Job failed: exit code 1
build:tests-fedora-oldest-meson has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/61654170):
737 | int __n1 = (n1), __n2 = (n2); \
| ^~
../lib/xe/xe_eudebug.c:2185:2: note: in expansion of macro ‘igt_assert_eq’
2185 | igt_assert_eq(igt_ioctl(debugfd, DRM_XE_EUDEBUG_IOCTL_ACK_EVENT, &ack), 0);
| ^~~~~~~~~~~~~
../lib/xe/xe_eudebug.c:2177:34: warning: unused variable ‘ack’ [-Wunused-variable]
2177 | struct drm_xe_eudebug_ack_event ack = { 0, };
| ^~~
../lib/xe/xe_eudebug.c: In function ‘xe_eudebug_client_metadata_create’:
../lib/xe/xe_eudebug.c:2150:1: error: control reaches end of non-void function [-Werror=return-type]
2150 | }
| ^
cc1: some warnings being treated as errors
ninja: build stopped: subcommand failed.
section_end:1722280800:step_script
section_start:1722280800:cleanup_file_variables
Cleaning up project directory and file based variables
section_end:1722280801:cleanup_file_variables
ERROR: Job failed: exit code 1
== Logs ==
For more details see: https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/pipelines/1236035
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [PATCH 01/66] tests/xe_eudebug: Test eudebug connection
2024-07-29 16:00 ` [PATCH 01/66] tests/xe_eudebug: Test eudebug connection Christoph Manszewski
@ 2024-07-30 7:58 ` Zbigniew Kempczyński
2024-07-30 9:42 ` Manszewski, Christoph
0 siblings, 1 reply; 71+ messages in thread
From: Zbigniew Kempczyński @ 2024-07-30 7:58 UTC (permalink / raw)
To: Christoph Manszewski
Cc: igt-dev, Kamil Konieczny, Dominik Grzegorzek, Maciej Patelczyk,
Dominik Karol Piątkowski, Pawel Sikora, Andrzej Hajda,
Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun, Mika Kuoppala
On Mon, Jul 29, 2024 at 06:00:54PM +0200, Christoph Manszewski wrote:
> From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
>
> Add basic tests checking xe eudebug connection capability.
>
> Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
> Cc: Christoph Manszewski <christoph.manszewski@intel.com>
> ---
> tests/intel/xe_eudebug.c | 115 +++++++++++++++++++++++++++++++++++++++
> tests/meson.build | 1 +
> 2 files changed, 116 insertions(+)
> create mode 100644 tests/intel/xe_eudebug.c
>
> diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
> new file mode 100644
> index 000000000..2bd5a44f9
> --- /dev/null
> +++ b/tests/intel/xe_eudebug.c
> @@ -0,0 +1,115 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2023 Intel Corporation
> + */
> +
> +#include <xe_drm.h>
> +#include "igt.h"
> +
> +static int __debug_connect(int fd, int *debugfd, struct drm_xe_eudebug_connect *param)
> +{
> + int ret = 0;
> +
> + *debugfd = igt_ioctl(fd, DRM_IOCTL_XE_EUDEBUG_CONNECT, param);
On first glance it looks it won't compile at this point.
Christoph, may you reorder patches to make sure all of them
will compile in the series?
--
Zbigniew
> +
> + if (*debugfd < 0) {
> + ret = -errno;
> + igt_assume(ret != 0);
> + }
> +
> + errno = 0;
> + return ret;
> +}
> +
> +static void test_connect(int fd)
> +{
> + struct drm_xe_eudebug_connect param = {};
> + int debugfd, ret;
> + pid_t *pid;
> +
> + pid = mmap(NULL, sizeof(pid_t), PROT_WRITE,
> + MAP_SHARED | MAP_ANON, -1, 0);
> +
> + /* get fresh unrelated pid */
> + igt_fork(child, 1)
> + *pid = getpid();
> +
> + igt_waitchildren();
> + param.pid = *pid;
> + munmap(pid, sizeof(pid_t));
> +
> + ret = __debug_connect(fd, &debugfd, ¶m);
> + igt_assert(debugfd == -1);
> + igt_assert_eq(ret, param.pid ? -ENOENT : -EINVAL);
> +
> + param.pid = 0;
> + ret = __debug_connect(fd, &debugfd, ¶m);
> + igt_assert(debugfd == -1);
> + igt_assert_eq(ret, -EINVAL);
> +
> + param.pid = getpid();
> + param.version = -1;
> + ret = __debug_connect(fd, &debugfd, ¶m);
> + igt_assert(debugfd == -1);
> + igt_assert_eq(ret, -EINVAL);
> +
> + param.version = 0;
> + param.flags = ~0;
> + ret = __debug_connect(fd, &debugfd, ¶m);
> + igt_assert(debugfd == -1);
> + igt_assert_eq(ret, -EINVAL);
> +
> + param.flags = 0;
> + param.extensions = ~0;
> + ret = __debug_connect(fd, &debugfd, ¶m);
> + igt_assert(debugfd == -1);
> + igt_assert_eq(ret, -EINVAL);
> +
> + param.extensions = 0;
> + ret = __debug_connect(fd, &debugfd, ¶m);
> + igt_assert_neq(debugfd, -1);
> + igt_assert_eq(ret, 0);
> +
> + close(debugfd);
> +}
> +
> +static void test_close(int fd)
> +{
> + struct drm_xe_eudebug_connect param = { 0, };
> + int debug_fd1, debug_fd2;
> + int fd2;
> +
> + param.pid = getpid();
> +
> + igt_assert_eq(__debug_connect(fd, &debug_fd1, ¶m), 0);
> + igt_assert(debug_fd1 >= 0);
> + igt_assert_eq(__debug_connect(fd, &debug_fd2, ¶m), -EBUSY);
> + igt_assert_eq(debug_fd2, -1);
> +
> + close(debug_fd1);
> + fd2 = drm_open_driver(DRIVER_XE);
> +
> + igt_assert_eq(__debug_connect(fd2, &debug_fd2, ¶m), 0);
> + igt_assert(debug_fd2 >= 0);
> + close(fd2);
> + close(debug_fd2);
> + close(debug_fd1);
> +}
> +
> +igt_main
> +{
> + int fd;
> +
> + igt_fixture {
> + fd = drm_open_driver(DRIVER_XE);
> + }
> +
> + igt_subtest("basic-connect")
> + test_connect(fd);
> +
> + igt_subtest("basic-close")
> + test_close(fd);
> +
> + igt_fixture
> + drm_close_driver(fd);
> +}
> diff --git a/tests/meson.build b/tests/meson.build
> index e649466be..35bf8ed35 100644
> --- a/tests/meson.build
> +++ b/tests/meson.build
> @@ -279,6 +279,7 @@ intel_xe_progs = [
> 'xe_dma_buf_sync',
> 'xe_debugfs',
> 'xe_drm_fdinfo',
> + 'xe_eudebug',
> 'xe_evict',
> 'xe_evict_ccs',
> 'xe_exec_atomic',
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [PATCH 01/66] tests/xe_eudebug: Test eudebug connection
2024-07-30 7:58 ` Zbigniew Kempczyński
@ 2024-07-30 9:42 ` Manszewski, Christoph
0 siblings, 0 replies; 71+ messages in thread
From: Manszewski, Christoph @ 2024-07-30 9:42 UTC (permalink / raw)
To: Zbigniew Kempczyński
Cc: igt-dev, Kamil Konieczny, Dominik Grzegorzek, Maciej Patelczyk,
Dominik Karol Piątkowski, Pawel Sikora, Andrzej Hajda,
Kolanupaka Naveena, Mika Kuoppala, Gwan-gyeong Mun, Mika Kuoppala
Hi Zbigniew,
On 30.07.2024 09:58, Zbigniew Kempczyński wrote:
> On Mon, Jul 29, 2024 at 06:00:54PM +0200, Christoph Manszewski wrote:
>> From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
>>
>> Add basic tests checking xe eudebug connection capability.
>>
>> Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
>> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
>> Cc: Christoph Manszewski <christoph.manszewski@intel.com>
>> ---
>> tests/intel/xe_eudebug.c | 115 +++++++++++++++++++++++++++++++++++++++
>> tests/meson.build | 1 +
>> 2 files changed, 116 insertions(+)
>> create mode 100644 tests/intel/xe_eudebug.c
>>
>> diff --git a/tests/intel/xe_eudebug.c b/tests/intel/xe_eudebug.c
>> new file mode 100644
>> index 000000000..2bd5a44f9
>> --- /dev/null
>> +++ b/tests/intel/xe_eudebug.c
>> @@ -0,0 +1,115 @@
>> +// SPDX-License-Identifier: MIT
>> +/*
>> + * Copyright © 2023 Intel Corporation
>> + */
>> +
>> +#include <xe_drm.h>
>> +#include "igt.h"
>> +
>> +static int __debug_connect(int fd, int *debugfd, struct drm_xe_eudebug_connect *param)
>> +{
>> + int ret = 0;
>> +
>> + *debugfd = igt_ioctl(fd, DRM_IOCTL_XE_EUDEBUG_CONNECT, param);
>
> On first glance it looks it won't compile at this point.
Yes, haven't been doing format-patch for a while and missed a patch, my bad.
>
> Christoph, may you reorder patches to make sure all of them
> will compile in the series?
Sure, before I send all patches I make sure each individual one compiles.
Thanks,
Christoph
>
> --
> Zbigniew
>
>> +
>> + if (*debugfd < 0) {
>> + ret = -errno;
>> + igt_assume(ret != 0);
>> + }
>> +
>> + errno = 0;
>> + return ret;
>> +}
>> +
>> +static void test_connect(int fd)
>> +{
>> + struct drm_xe_eudebug_connect param = {};
>> + int debugfd, ret;
>> + pid_t *pid;
>> +
>> + pid = mmap(NULL, sizeof(pid_t), PROT_WRITE,
>> + MAP_SHARED | MAP_ANON, -1, 0);
>> +
>> + /* get fresh unrelated pid */
>> + igt_fork(child, 1)
>> + *pid = getpid();
>> +
>> + igt_waitchildren();
>> + param.pid = *pid;
>> + munmap(pid, sizeof(pid_t));
>> +
>> + ret = __debug_connect(fd, &debugfd, ¶m);
>> + igt_assert(debugfd == -1);
>> + igt_assert_eq(ret, param.pid ? -ENOENT : -EINVAL);
>> +
>> + param.pid = 0;
>> + ret = __debug_connect(fd, &debugfd, ¶m);
>> + igt_assert(debugfd == -1);
>> + igt_assert_eq(ret, -EINVAL);
>> +
>> + param.pid = getpid();
>> + param.version = -1;
>> + ret = __debug_connect(fd, &debugfd, ¶m);
>> + igt_assert(debugfd == -1);
>> + igt_assert_eq(ret, -EINVAL);
>> +
>> + param.version = 0;
>> + param.flags = ~0;
>> + ret = __debug_connect(fd, &debugfd, ¶m);
>> + igt_assert(debugfd == -1);
>> + igt_assert_eq(ret, -EINVAL);
>> +
>> + param.flags = 0;
>> + param.extensions = ~0;
>> + ret = __debug_connect(fd, &debugfd, ¶m);
>> + igt_assert(debugfd == -1);
>> + igt_assert_eq(ret, -EINVAL);
>> +
>> + param.extensions = 0;
>> + ret = __debug_connect(fd, &debugfd, ¶m);
>> + igt_assert_neq(debugfd, -1);
>> + igt_assert_eq(ret, 0);
>> +
>> + close(debugfd);
>> +}
>> +
>> +static void test_close(int fd)
>> +{
>> + struct drm_xe_eudebug_connect param = { 0, };
>> + int debug_fd1, debug_fd2;
>> + int fd2;
>> +
>> + param.pid = getpid();
>> +
>> + igt_assert_eq(__debug_connect(fd, &debug_fd1, ¶m), 0);
>> + igt_assert(debug_fd1 >= 0);
>> + igt_assert_eq(__debug_connect(fd, &debug_fd2, ¶m), -EBUSY);
>> + igt_assert_eq(debug_fd2, -1);
>> +
>> + close(debug_fd1);
>> + fd2 = drm_open_driver(DRIVER_XE);
>> +
>> + igt_assert_eq(__debug_connect(fd2, &debug_fd2, ¶m), 0);
>> + igt_assert(debug_fd2 >= 0);
>> + close(fd2);
>> + close(debug_fd2);
>> + close(debug_fd1);
>> +}
>> +
>> +igt_main
>> +{
>> + int fd;
>> +
>> + igt_fixture {
>> + fd = drm_open_driver(DRIVER_XE);
>> + }
>> +
>> + igt_subtest("basic-connect")
>> + test_connect(fd);
>> +
>> + igt_subtest("basic-close")
>> + test_close(fd);
>> +
>> + igt_fixture
>> + drm_close_driver(fd);
>> +}
>> diff --git a/tests/meson.build b/tests/meson.build
>> index e649466be..35bf8ed35 100644
>> --- a/tests/meson.build
>> +++ b/tests/meson.build
>> @@ -279,6 +279,7 @@ intel_xe_progs = [
>> 'xe_dma_buf_sync',
>> 'xe_debugfs',
>> 'xe_drm_fdinfo',
>> + 'xe_eudebug',
>> 'xe_evict',
>> 'xe_evict_ccs',
>> 'xe_exec_atomic',
>> --
>> 2.34.1
>>
^ permalink raw reply [flat|nested] 71+ messages in thread
end of thread, other threads:[~2024-07-30 9:42 UTC | newest]
Thread overview: 71+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-07-29 16:00 [PATCH 00/66] Test coverage for GPU debug support Christoph Manszewski
2024-07-29 16:00 ` [PATCH 01/66] tests/xe_eudebug: Test eudebug connection Christoph Manszewski
2024-07-30 7:58 ` Zbigniew Kempczyński
2024-07-30 9:42 ` Manszewski, Christoph
2024-07-29 16:00 ` [PATCH 02/66] lib/xe_eudebug: Introduce eu debug testing framework Christoph Manszewski
2024-07-29 16:00 ` [PATCH 03/66] lib/xe_eudebug: Allow client to wait for debugger Christoph Manszewski
2024-07-29 16:00 ` [PATCH 04/66] lib/xe_eudebug: Add exec_queue support Christoph Manszewski
2024-07-29 16:00 ` [PATCH 05/66] lib/xe_eudebug: Add attention events support Christoph Manszewski
2024-07-29 16:00 ` [PATCH 06/66] lib/xe_ioctl: Add wrapper with vm_bind_op extension parameter Christoph Manszewski
2024-07-29 16:01 ` [PATCH 07/66] lib/xe_eudebug: Add support for vm_bind events Christoph Manszewski
2024-07-29 16:01 ` [PATCH 08/66] lib/xe_eudebug: Add metadata support Christoph Manszewski
2024-07-29 16:01 ` [PATCH 09/66] lib/xe_eudebug: Add support for user fence acking Christoph Manszewski
2024-07-29 16:01 ` [PATCH 10/66] lib/xe_eudebug: Add support for dynamic debugger sysfs toggle Christoph Manszewski
2024-07-29 16:01 ` [PATCH 11/66] tests/xe_eudebug: Test open close events Christoph Manszewski
2024-07-29 16:01 ` [PATCH 12/66] tests/xe_eudebug: Exercise read_event ioctl Christoph Manszewski
2024-07-29 16:01 ` [PATCH 13/66] tests/xe_eudebug: Add vm events sanity check Christoph Manszewski
2024-07-29 16:01 ` [PATCH 14/66] tests/xe_eudebug: Race discovery against eudebug attach Christoph Manszewski
2024-07-29 16:01 ` [PATCH 15/66] tests/xe_eudebug: Add TEST/SUBTEST documentation Christoph Manszewski
2024-07-29 16:01 ` [PATCH 16/66] tests/xe_eudebug: Introduce basic exec_queue testing Christoph Manszewski
2024-07-29 16:01 ` [PATCH 17/66] tests/xe_eudebug: Include exec queues in discovery testing Christoph Manszewski
2024-07-29 16:01 ` [PATCH 18/66] tests/xe_eudebug: Add vm open/pread/pwrite basic tests Christoph Manszewski
2024-07-29 16:01 ` [PATCH 19/66] tests/xe_eudebug: Add basic vm-bind coverage Christoph Manszewski
2024-07-29 16:01 ` [PATCH 20/66] tests/xe_eudebug: Exercise debug metadata events sent to debugger Christoph Manszewski
2024-07-29 16:01 ` [PATCH 21/66] tests/xe_eudebug: Add support for dynamic debugger sysfs toggle Christoph Manszewski
2024-07-29 16:01 ` [PATCH 22/66] tests/xe_eudebug: Add coverage for sysfs debugger toggle Christoph Manszewski
2024-07-29 16:01 ` [PATCH 23/66] lib/xe_eudebug: Allow debugger to wait for client Christoph Manszewski
2024-07-29 16:01 ` [PATCH 24/66] tests/xe_eudebug: Add vm-bind discovery tests Christoph Manszewski
2024-07-29 16:01 ` [PATCH 25/66] tests/xe_eudebug: Add basic-vm-bind-metadata-discovery Christoph Manszewski
2024-07-29 16:01 ` [PATCH 26/66] tests/xe_eudebug: Add basic-vm-access-parameters test Christoph Manszewski
2024-07-29 16:01 ` [PATCH 27/66] lib/xe_eudebug: Add mutex for log events write Christoph Manszewski
2024-07-29 16:01 ` [PATCH 28/66] tests/xe_eudebug: Add basic-client-th test Christoph Manszewski
2024-07-29 16:01 ` [PATCH 29/66] tests/xe_eudebug: Added connect-user test Christoph Manszewski
2024-07-29 16:01 ` [PATCH 30/66] tests/xe_eudebug: Add discovery-race-vmbind subtest Christoph Manszewski
2024-07-29 16:01 ` [PATCH 31/66] tests/xe_eudebug: Add userptr variant of basic-vm-access test Christoph Manszewski
2024-07-29 16:01 ` [PATCH 32/66] tests/xe_eudebug: Add basic-vm-bind-ufence Christoph Manszewski
2024-07-29 16:01 ` [PATCH 33/66] tests/xe_eudebug: Add multigpu scenarios Christoph Manszewski
2024-07-29 16:01 ` [PATCH 34/66] tests/xe_eudebug: Add vm-bind-clear test Christoph Manszewski
2024-07-29 16:01 ` [PATCH 35/66] tests/xe_eudebug: Exercise lseek Christoph Manszewski
2024-07-29 16:01 ` [PATCH 36/66] tests/xe_eudebug: Test multiple bo sizes Christoph Manszewski
2024-07-29 16:01 ` [PATCH 37/66] lib/gpgpu_shader: Extend shader building library Christoph Manszewski
2024-07-29 16:01 ` [PATCH 38/66] tests/xe_exec_sip: Port tests for shaders and sip Christoph Manszewski
2024-07-29 16:01 ` [PATCH 39/66] tests/xe_exec_sip: Check if we reset due to unhandled attention Christoph Manszewski
2024-07-29 16:01 ` [PATCH 40/66] tests/xe_exec_sip: Check usercoredump for attentions Christoph Manszewski
2024-07-29 16:01 ` [PATCH 41/66] tests/xe_exec_sip: Add support for dynamic debugger sysfs toggle Christoph Manszewski
2024-07-29 16:01 ` [PATCH 42/66] tests/xe_exec_sip: Add breakpoint-writesip-twice test Christoph Manszewski
2024-07-29 16:01 ` [PATCH 43/66] tests/xe_exec_sip: Add sanity-after-timeout test Christoph Manszewski
2024-07-29 16:01 ` [PATCH 44/66] tests/xe_exec_sip: Add breakpoint-waitsip-heavy test Christoph Manszewski
2024-07-29 16:01 ` [PATCH 45/66] tests/xe_exec_sip: Add nodebug test cases Christoph Manszewski
2024-07-29 16:01 ` [PATCH 46/66] lib/gpgpu_shader: Add write_on_exception template Christoph Manszewski
2024-07-29 16:01 ` [PATCH 47/66] lib/gpgpu_shader: Add set/clear exception register (cr0.1) helpers Christoph Manszewski
2024-07-29 16:01 ` [PATCH 48/66] lib/intel_batchbuffer: Add helper to get pointer at specified offset Christoph Manszewski
2024-07-29 16:01 ` [PATCH 49/66] lib/gpgpu_shader: Allow enabling illegal opcode exceptions in shader Christoph Manszewski
2024-07-29 16:01 ` [PATCH 50/66] tests/xe_exec_sip: Rework invalid instruction tests Christoph Manszewski
2024-07-29 16:01 ` [PATCH 51/66] lib/intel_batchbuffer: Add support for long-running mode execution Christoph Manszewski
2024-07-29 16:01 ` [PATCH 52/66] tests/xe_eudebug_online: Debug client which runs workloads on EU Christoph Manszewski
2024-07-29 16:01 ` [PATCH 53/66] tests/xe_eudebug_online: Set dynamic breakpoint on interrupt-all Christoph Manszewski
2024-07-29 16:01 ` [PATCH 54/66] tests/xe_eudebug_online: Add support for dynamic debugger sysfs toggle Christoph Manszewski
2024-07-29 16:01 ` [PATCH 55/66] tests/xe_eudebug_online: Add tdctl-parameters test Christoph Manszewski
2024-07-29 16:01 ` [PATCH 56/66] tests/xe_eudebug_online: Add reset-with-attention test Christoph Manszewski
2024-07-29 16:01 ` [PATCH 57/66] lib/xe_eudebug: Expose xe_eudebug_connect Christoph Manszewski
2024-07-29 16:01 ` [PATCH 58/66] tests/xe_eudebug_online: Add interrupt-reconnect test Christoph Manszewski
2024-07-29 16:01 ` [PATCH 59/66] tests/xe_eudebug_online: Add single-step and single-step-one tests Christoph Manszewski
2024-07-29 16:01 ` [PATCH 60/66] tests/xe_eudebug_online: What if user does not set debug mode? Christoph Manszewski
2024-07-29 16:01 ` [PATCH 61/66] tests/xe_eudebug_online: Adds debugger-reopen test Christoph Manszewski
2024-07-29 16:01 ` [PATCH 62/66] tests/xe_eudebug_online: Add caching tests Christoph Manszewski
2024-07-29 16:01 ` [PATCH 63/66] tests/xe_eudebug_online: Add subtests w/o long running mode Christoph Manszewski
2024-07-29 16:01 ` [PATCH 64/66] tests/xe_eudebug_online: Add multisession test cases Christoph Manszewski
2024-07-29 16:01 ` [PATCH 65/66] tests/xe_eudebug_online: Check if eu debugger disables preemption timeout Christoph Manszewski
2024-07-29 16:01 ` [PATCH 66/66] tests/xe_live_ktest: Add xe_eudebug live test Christoph Manszewski
2024-07-29 19:18 ` ✗ Fi.CI.BUILD: failure for Test coverage for GPU debug support Patchwork
2024-07-29 19:21 ` ✗ GitLab.Pipeline: warning " Patchwork
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox