diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/ugpu/meson.build | 2 | ||||
-rw-r--r-- | tests/ugpu/ugpu_basic.c | 80 | ||||
-rw-r--r-- | tests/ugpu/ugpu_latency.c | 214 |
3 files changed, 295 insertions, 1 deletions
diff --git a/tests/ugpu/meson.build b/tests/ugpu/meson.build index e9300575..d26734e4 100644 --- a/tests/ugpu/meson.build +++ b/tests/ugpu/meson.build @@ -1,6 +1,6 @@ ugpu_deps = test_deps -ugpu_progs = [ 'ugpu_basic' ] +ugpu_progs = [ 'ugpu_basic', 'ugpu_latency' ] foreach prog : ugpu_progs test_executables += executable(prog, prog + '.c', diff --git a/tests/ugpu/ugpu_basic.c b/tests/ugpu/ugpu_basic.c index 6d506b07..d2ea9c2d 100644 --- a/tests/ugpu/ugpu_basic.c +++ b/tests/ugpu/ugpu_basic.c @@ -1,3 +1,5 @@ +#include "ugpu.h" + #include "igt.h" #include "igt_core.h" @@ -6,6 +8,64 @@ static int ugpu_open(int i915) return igt_ioctl(i915, DRM_IOCTL_I915_UGPU, 0); } +static int __ugpu_get(int fd, struct ugpu_query *q) +{ + int err; + + err = 0; + if (igt_ioctl(fd, UGPU_IOCTL_GET, q)) { + err = -errno; + igt_assume(err); + } + + return err; +} + +static int __ugpu_set(int fd, struct ugpu_query *q) +{ + int err; + + err = 0; + if (igt_ioctl(fd, UGPU_IOCTL_SET, q)) { + err = -errno; + igt_assume(err); + } + + return err; +} + +static int __ugpu_set_command_ring(int fd, uint32_t sz) +{ + struct ugpu_query q = { + .property = 0, + .value = sz, + }; + + return __ugpu_set(fd, &q); +} + +static void ugpu_set_command_ring(int fd, uint32_t sz) +{ + igt_assert_eq(__ugpu_set_command_ring(fd, sz), 0); +} + +static void igt_ugpu_name(int i915) +{ + int fd = ugpu_open(i915); + char name[128]; + + struct ugpu_query q = { + .property = 0, + .value = to_user_pointer(name), + .length = sizeof(name), + }; + igt_assert_eq(__ugpu_get(fd, &q), 0); + + igt_info("ugpu queue '%s'\n", name); + + close(fd); +} + igt_main { int i915; @@ -15,4 +75,24 @@ igt_main { igt_subtest("openclose") close(ugpu_open(i915)); + + igt_subtest("name") + igt_ugpu_name(i915); + + igt_subtest("mmap") { + int fd = ugpu_open(i915); + void *ctl, *mem; + + ugpu_set_command_ring(fd, 4096); + + ctl = mmap(NULL, 4096, PROT_WRITE, MAP_PRIVATE, fd, 0); + igt_assert(ctl != MAP_FAILED); + munmap(ctl, 4096); + + mem = mmap(NULL, 4096, PROT_WRITE, MAP_PRIVATE, fd, 4096); + igt_assert(mem != MAP_FAILED); + munmap(mem, 4096); + + close(fd); + } } diff --git a/tests/ugpu/ugpu_latency.c b/tests/ugpu/ugpu_latency.c new file mode 100644 index 00000000..1d01427c --- /dev/null +++ b/tests/ugpu/ugpu_latency.c @@ -0,0 +1,214 @@ +#include "ugpu.h" + +#include "igt.h" +#include "igt_core.h" +#include "igt_device.h" +#include "igt_stats.h" + +static int ugpu_open(int i915) +{ + return igt_ioctl(i915, DRM_IOCTL_I915_UGPU, 0); +} + +struct ugpu_queue { + int fd; + struct { + uint32_t write; + uint32_t read; + } *ctl; + uint32_t *mem; + uint32_t size; +}; + +static int __ugpu_set(int fd, struct ugpu_query *q) +{ + int err; + + err = 0; + if (igt_ioctl(fd, UGPU_IOCTL_SET, q)) { + err = -errno; + igt_assume(err); + } + + return err; +} + +static int __ugpu_set_command_ring(int fd, uint32_t sz) +{ + struct ugpu_query q = { + .property = 0, + .value = sz, + }; + + return __ugpu_set(fd, &q); +} + +static void ugpu_set_command_ring(int fd, uint32_t sz) +{ + igt_assert_eq(__ugpu_set_command_ring(fd, sz), 0); +} + +static struct ugpu_queue *ugpu_queue_create(int fd) +{ + struct ugpu_queue *q; + + q = malloc(sizeof(*q)); + if (!q) + return NULL; + + q->fd = fd; + q->size = 64 << 10; + + ugpu_set_command_ring(fd, q->size); + + q->ctl = mmap(NULL, 4096, PROT_WRITE, MAP_PRIVATE, fd, 0); + igt_assert(q->ctl != MAP_FAILED); + + q->mem = mmap(NULL, q->size, PROT_WRITE, MAP_PRIVATE, fd, 4096); + igt_assert(q->mem != MAP_FAILED); + + igt_assert_eq(q->ctl->write, 0); + igt_assert_eq(q->ctl->read, 0); + + return q; +} + +static void ugpu_queue_destroy(struct ugpu_queue *q) +{ + close(q->fd); + free(q); +} + +static int i915_allocate_dmabuf(int i915, uint64_t sz) +{ + uint32_t handle; + int buf; + + handle = gem_create(i915, sz); + buf = prime_handle_to_fd_for_mmap(i915, handle); + gem_close(i915, handle); + + return buf; +} + +static void ugpu_queue_map(struct ugpu_queue *q, uint64_t addr, + int buf, uint64_t offset, uint64_t length) +{ + struct ugpu_cs_map pkt = { + .hdr = UGPU_CS_MAP, + .iova = addr, + .offset = offset, + .length = length, + .fd = buf, + }; + igt_assert(write(q->fd, &pkt, sizeof(pkt)) == sizeof(pkt)); +} + +static void ugpu_queue_unpark(struct ugpu_queue *q) +{ + struct ugpu_cs_hdr pkt = UGPU_CS_UNPARK; + igt_assert(write(q->fd, &pkt, sizeof(pkt)) == sizeof(pkt)); +} + +static void ugpu_queue_submit(struct ugpu_queue *q, uint64_t addr) +{ + struct ugpu_cs_submit pkt = { + .hdr = UGPU_CS_SUBMIT(0), + .iova = addr, + }; + igt_assert(write(q->fd, &pkt, sizeof(pkt)) == sizeof(pkt)); +} + +static double clockrate(int i915) +{ + int freq; + drm_i915_getparam_t gp = { + .value = &freq, + .param = I915_PARAM_CS_TIMESTAMP_FREQUENCY, + }; + igt_require(igt_ioctl(i915, DRM_IOCTL_I915_GETPARAM, &gp) == 0); + return freq; +} + +igt_main { + int i915; + + igt_fixture { + i915 = drm_open_driver(DRIVER_INTEL); + }; + + igt_subtest("write-execution-latency") { + const unsigned int mmio_base = 0x2000; + const unsigned int cs_timestamp = mmio_base + 0x358; + volatile uint32_t *timestamp; + uint32_t *cs, *result; + struct igt_mean submit, batch; + struct ugpu_queue *q; + double rcs_clock; + int handle; + + intel_register_access_init(igt_device_get_pci_device(i915), false, i915); + timestamp = + (volatile uint32_t *)((volatile char *)igt_global_mmio + cs_timestamp); + + rcs_clock = clockrate(i915); + igt_info("RCS timestamp clock: %.0fKHz, %.1fns\n", + rcs_clock / 1e3, 1e9 / rcs_clock); + rcs_clock = 1e9 / rcs_clock; + + q = ugpu_queue_create(ugpu_open(i915)); + + handle = i915_allocate_dmabuf(i915, 4096); + + result = mmap(NULL, 4096, PROT_WRITE, MAP_SHARED, handle, 0); + igt_assert(result != MAP_FAILED); + + cs = result; + *cs++ = 0x24 << 23 | 2; /* SRM */ + *cs++ = cs_timestamp; + *cs++ = 4096 - 8; + *cs++ = 0; + *cs++ = 0xa << 23; + + cs = result + 16; + *cs++ = 0x24 << 23 | 2; /* SRM */ + *cs++ = cs_timestamp; + *cs++ = 4096 - 4; + *cs++ = 0; + *cs++ = 0xa << 23; + + ugpu_queue_map(q, 0, handle, 0, 4096); + close(handle); + + igt_mean_init(&submit); + igt_mean_init(&batch); + + cs = result + 1024 - 2; + + ugpu_queue_unpark(q); + igt_until_timeout(2) { + uint32_t now; + + cs[1] = 0; + + now = *timestamp; + ugpu_queue_submit(q, 0); + ugpu_queue_submit(q, 64); + + while (!((volatile uint32_t *)cs)[1]) + ; + + igt_mean_add(&submit, (cs[0] - now) * rcs_clock); + igt_mean_add(&batch, (cs[1] - cs[0]) * rcs_clock); + } + ugpu_queue_destroy(q); + + igt_info("Submission latency: %.2f±%.2fus\n", + 1e-3 * igt_mean_get(&submit), + 1e-3 * sqrt(igt_mean_get_variance(&submit))); + + igt_info("Inter-batch latency: %.2f±%.2fus\n", + 1e-3 * igt_mean_get(&batch), + 1e-3 * sqrt(igt_mean_get_variance(&batch))); + } +} |