Quoting Tvrtko Ursulin (2021-01-25 10:20:15) > > On 22/01/2021 21:49, Chris Wilson wrote: > > We store every client name, pid and runtime under sysfs. Better check > > that matches with the actual client. > > > > Signed-off-by: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx> > > --- > > lib/igt_sysfs.c | 36 +++ > > lib/igt_sysfs.h | 3 + > > tests/Makefile.sources | 3 + > > tests/i915/sysfs_clients.c | 450 +++++++++++++++++++++++++++++++++++++ > > tests/meson.build | 1 + > > 5 files changed, 493 insertions(+) > > create mode 100644 tests/i915/sysfs_clients.c > > > > diff --git a/lib/igt_sysfs.c b/lib/igt_sysfs.c > > index 6aafe5349..e734143ba 100644 > > --- a/lib/igt_sysfs.c > > +++ b/lib/igt_sysfs.c > > @@ -378,6 +378,42 @@ uint32_t igt_sysfs_get_u32(int dir, const char *attr) > > return result; > > } > > > > +/** > > + * igt_sysfs_get_u64: > > + * @dir: directory for the device from igt_sysfs_open() > > + * @attr: name of the sysfs node to open > > + * > > + * Convenience wrapper to read a unsigned 64bit integer from a sysfs file. > > + * > > + * Returns: > > + * The value read. > > + */ > > +uint64_t igt_sysfs_get_u64(int dir, const char *attr) > > +{ > > + uint64_t result; > > + > > + if (igt_sysfs_scanf(dir, attr, "%"PRIu64, &result) != 1) > > + return 0; > > + > > + return result; > > +} > > + > > +/** > > + * igt_sysfs_set_u64: > > + * @dir: directory for the device from igt_sysfs_open() > > + * @attr: name of the sysfs node to open > > + * @value: value to set > > + * > > + * Convenience wrapper to write a unsigned 64bit integer to a sysfs file. > > + * > > + * Returns: > > + * True if successfully written > > + */ > > +bool igt_sysfs_set_u64(int dir, const char *attr, uint64_t value) > > +{ > > + return igt_sysfs_printf(dir, attr, "%"PRIu64, value) > 0; > > +} > > + > > /** > > * igt_sysfs_set_u32: > > * @dir: directory for the device from igt_sysfs_open() > > diff --git a/lib/igt_sysfs.h b/lib/igt_sysfs.h > > index 64935a5ca..56741a0a3 100644 > > --- a/lib/igt_sysfs.h > > +++ b/lib/igt_sysfs.h > > @@ -47,6 +47,9 @@ int igt_sysfs_printf(int dir, const char *attr, const char *fmt, ...) > > uint32_t igt_sysfs_get_u32(int dir, const char *attr); > > bool igt_sysfs_set_u32(int dir, const char *attr, uint32_t value); > > > > +uint64_t igt_sysfs_get_u64(int dir, const char *attr); > > +bool igt_sysfs_set_u64(int dir, const char *attr, uint64_t value); > > + > > bool igt_sysfs_get_boolean(int dir, const char *attr); > > bool igt_sysfs_set_boolean(int dir, const char *attr, bool value); > > > > diff --git a/tests/Makefile.sources b/tests/Makefile.sources > > index 1c227e750..3f663fe7e 100644 > > --- a/tests/Makefile.sources > > +++ b/tests/Makefile.sources > > @@ -114,6 +114,9 @@ TESTS_progs = \ > > TESTS_progs += api_intel_bb > > api_intel_bb_SOURCES = i915/api_intel_bb.c > > > > +TESTS_progs += sysfs_clients > > +sysfs_clients_SOURCES = i915/sysfs_clients.c > > + > > TESTS_progs += sysfs_defaults > > sysfs_defaults_SOURCES = i915/sysfs_defaults.c > > > > diff --git a/tests/i915/sysfs_clients.c b/tests/i915/sysfs_clients.c > > new file mode 100644 > > index 000000000..a77adec6d > > --- /dev/null > > +++ b/tests/i915/sysfs_clients.c > > @@ -0,0 +1,450 @@ > > +/* SPDX-License-Identifier: MIT */ > > +/* > > + * Copyright © 2021 Intel Corporation > > + */ > > + > > +#include <ctype.h> > > +#include <dirent.h> > > +#include <errno.h> > > +#include <fcntl.h> > > +#include <inttypes.h> > > +#include <sys/stat.h> > > +#include <sys/types.h> > > +#include <unistd.h> > > + > > +#include "drmtest.h" > > +#include "i915/gem.h" > > +#include "i915/gem_context.h" > > +#include "i915/gem_engine_topology.h" > > +#include "igt_aux.h" > > +#include "igt_dummyload.h" > > +#include "igt_sysfs.h" > > +#include "ioctl_wrappers.h" > > + > > +static void pidname(int i915, int clients) > > +{ > > + struct dirent *de; > > + int sv[2], rv[2]; > > + char buf[280]; > > + int me = -1; > > + long count; > > + pid_t pid; > > + DIR *dir; > > + int len; > > + > > + dir = fdopendir(dup(clients)); > > + igt_assert(dir); > > + rewinddir(dir); > > + > > + count = 0; > > + while ((de = readdir(dir))) { > > + if (!isdigit(de->d_name[0])) > > + continue; > > + > > + snprintf(buf, sizeof(buf), "%s/name", de->d_name); > > + len = igt_sysfs_read(clients, buf, buf, sizeof(buf)); > > + igt_assert_f(len > 0, "failed to open '%s/name'\n", de->d_name); > > + buf[len - 1] = '\0'; > > + igt_debug("%s: %s\n", de->d_name, buf); > > + > > + /* Ignore closed clients created by drm_driver_open() */ > > + if (*buf == '<') > > + continue; > > + > > + close(me); > > + me = openat(clients, de->d_name, O_DIRECTORY | O_RDONLY); > > + count++; > > + } > > + closedir(dir); > > + > > + /* We expect there to be only the single client (us) running */ > > + igt_assert_eq(count, 1); > > + igt_assert(me >= 0); > > + > > + len = igt_sysfs_read(me, "name", buf, sizeof(buf)); > > + igt_assert(len > 0); > > + buf[len - 1] = '\0'; > > We could add a helper like igt_syfs_str or something since this repeats > a lot but not important straight away. -> strterm() > > > + > > + igt_info("My name: %s\n", buf); > > + igt_assert(strcmp(buf, igt_test_name()) == 0); > > + > > + igt_assert(pipe(sv) == 0); > > + igt_assert(pipe(rv) == 0); > > + > > + /* If give our fd to someone else, they take over ownership of client */ > > + igt_fork(child, 1) { > > + read(sv[0], &pid, sizeof(pid)); > > + > > + gem_context_destroy(i915, gem_context_create(i915)); > > + > > + pid = getpid(); > > + write(rv[1], &pid, sizeof(pid)); > > + } > > + close(sv[0]); > > + close(rv[1]); > > + > > + /* Child exists, but not yet running, we still own the client */ > > + len = igt_sysfs_read(me, "pid", buf, sizeof(buf)); > > + igt_assert(len > 0); > > + buf[len - 1] = '\0'; > > + > > + pid = getpid(); > > + igt_info("My pid: %s\n", buf); > > + igt_assert_eq(atoi(buf), pid); > > + > > + /* Release and wait for the child */ > > + igt_assert_eq(write(sv[1], &pid, sizeof(pid)), sizeof(pid)); > > + igt_assert_eq(read(rv[0], &pid, sizeof(pid)), sizeof(pid)); > > + > > + /* Now child owns the client and pid should be updated to match */ > > + len = igt_sysfs_read(me, "pid", buf, sizeof(buf)); > > + igt_assert(len > 0); > > + buf[len - 1] = '\0'; > > + > > + igt_info("New pid: %s\n", buf); > > + igt_assert_eq(atoi(buf), pid); > > + igt_waitchildren(); > > + > > + /* Child has definitely gone, but the client should remain */ > > + len = igt_sysfs_read(me, "pid", buf, sizeof(buf)); > > + igt_assert(len > 0); > > + buf[len - 1] = '\0'; > > + > > + igt_info("Old pid: %s\n", buf); > > + igt_assert_eq(atoi(buf), pid); > > "Old pid" as in pid of the child which exited. Do we have a IGT helper > to cross check what the child sent via pipe matches what fork said? Or > what waitpid reported as exited. For the sake of the test, you can just scroll back and check ;) > Also, would it revert back to parent pid if parent did one context > create at this point? Could be worth checking if so. I added such a test. > > + > > + close(sv[1]); > > + close(rv[0]); > > + close(me); > > +} > > + > > +static long count_clients(int clients) > > +{ > > + struct dirent *de; > > + long count = 0; > > + char buf[280]; > > + DIR *dir; > > + > > + dir = fdopendir(dup(clients)); > > + igt_assert(dir); > > + rewinddir(dir); > > + > > + while ((de = readdir(dir))) { > > + int len; > > + > > + if (!isdigit(de->d_name[0])) > > + continue; > > + > > + snprintf(buf, sizeof(buf), "%s/name", de->d_name); > > + len = igt_sysfs_read(clients, buf, buf, sizeof(buf)); > > + if (len < 0) > > + continue; > > + > > + count += *buf != '<'; > > + } > > + closedir(dir); > > + > > + return count; > > +} > > + > > +static void create(int i915, int clients) > > +{ > > + int fd[16]; > > + > > + /* Each new open("/dev/dri/cardN") is a new client */ > > + igt_assert_eq(count_clients(clients), 1); > > + for (int i = 0; i < ARRAY_SIZE(fd); i++) { > > + fd[i] = gem_reopen_driver(i915); > > + igt_assert_eq(count_clients(clients), i + 2); > > + } > > + > > + for (int i = 0; i < ARRAY_SIZE(fd); i++) > > + close(fd[i]); > > + > > + /* Cleanup delayed behind rcu */ > > + igt_until_timeout(30) { > > + usleep(0); > > Intention to yield? If you think that's more likely to work :) > > > + if (count_clients(clients) == 1) > > + break; > > + usleep(10000); > > + } > > + igt_assert_eq(count_clients(clients), 1); > > A variant which closes a single random client and does a cross check in > every loop iteration could be useful then opens a new client checking > id's are unique. Can be added later. One not-recycling test coming up. > > + delay = -500000; /* 500us slack */ > > + memset(old, 0, sizeof(old)); > > + for (int pass = 0; pass < 5; pass++) { > > + delay += measured_usleep(1000); > > + igt_debug("delay: %'"PRIu64"ns\n", delay); > > + > > + /* Check that we accumulate the runtime, while active */ > > + igt_assert_eq(read_runtime(me, active), 1); > > + igt_info("active1[%d]: %'"PRIu64"ns\n", pass, active[e->class]); > > + igt_assert(active[e->class] > old[e->class]); /* monotonic */ > > + igt_assert(active[e->class] > delay); /* within reason */ > > Sending greetings to GuC soon. Will need to emit a high prio pulse to > preempt the spinner, maybe, no, probably won't be enough. Exactly. The GuC falls far short of what we need atm. A pulse from every sysfs read() and wait for pulse completion before returning? What happens for non-preemptible workloads? > > + delay = -500000; /* 500us slack */ > > + memset(old, 0, sizeof(old)); > > + for (int pass = 0; pass < 5; pass++) { > > + delay += measured_usleep(1000); > > + igt_debug("delay: %'"PRIu64"ns\n", delay); > > + > > + /* Check that we accumulate the runtime, while active */ > > + igt_assert_eq(read_runtime(me, active), expect); > > + for (int i = 0; i < ARRAY_SIZE(active); i++) { > > + if (!active[i]) > > + continue; > > Don't you want do skip based on the bitmap in classes here? Although the > assert on expect will catch failures to account some class already so > optional I guess. Bitmap came afterwards, and indeed it should have replaced the !active[i]. -Chris _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx