diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2019-03-28 12:31:28 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2019-03-29 08:28:10 +0000 |
commit | df371f8cda82d37ddb6beeafb3938d62cc5b9c68 (patch) | |
tree | b95505d16b9a646ae2e8b42e2b81d669d9ca645c | |
parent | df92af3b58b7806a66c6123c66c92998edfb0508 (diff) |
ugugpu
-rw-r--r-- | include/drm-uapi/ugpu.h | 70 | ||||
-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 |
4 files changed, 365 insertions, 1 deletions
diff --git a/include/drm-uapi/ugpu.h b/include/drm-uapi/ugpu.h index 1e713683..bd6d7ce9 100644 --- a/include/drm-uapi/ugpu.h +++ b/include/drm-uapi/ugpu.h @@ -17,4 +17,74 @@ struct ugpu_query { #define UGPU_IOCTL_SUBMIT _IO(UGPU_IOCTL_BASE, 2) +struct ugpu_cs_hdr { + __u8 cmd; +#define __UGPU_CS_NOP 0 + +#define __UGPU_CS_MAP 1 +#define __UGPU_CS_UNMAP 2 + +#define __UGPU_CS_WAIT 3 +#define __UGPU_CS_SIGNAL 4 +#define __UGPU_CS_WAKE 5 + +#define __UGPU_CS_SUBMIT 6 + __u8 len; + __u16 flags; +}; +#define __UGPU_CS_HDR(cmd, t, flags) { cmd, sizeof(t) / 4, flags } + +#define UGPU_CS_NOP __UGPU_CS_HDR(__UGPU_CS_NOP, struct ugpu_cs_hdr, 0) +#define UGPU_CS_UNPARK __UGPU_CS_HDR(__UGPU_CS_NOP, struct ugpu_cs_hdr, 1) +#define UGPU_CS_PARK __UGPU_CS_HDR(__UGPU_CS_NOP, struct ugpu_cs_hdr, 2) + +struct ugpu_cs_map { + struct ugpu_cs_hdr hdr; + __s32 fd; + __u64 iova; + __u64 offset; + __u64 length; +} __attribute__((packed)); +#define UGPU_CS_MAP __UGPU_CS_HDR(__UGPU_CS_MAP, struct ugpu_cs_map, 0) + +struct ugpu_cs_unmap { + struct ugpu_cs_hdr hdr; + __u64 iova; + __u64 length; +} __attribute__((packed)); +#define UGPU_CS_UNMAP __UGPU_CS_HDR(__UGPU_CS_UNMAP, struct ugpu_cs_unmap, 0) + +struct ugpu_cs_wait { + struct ugpu_cs_hdr hdr; + __u64 pointer; + __u64 value; +} __attribute__((packed)); +#define UGPU_CS_WAIT(flags) \ + __UGPU_CS_HDR(__UGPU_CS_WAIT, struct ugpu_cs_wait, flags) + +struct ugpu_cs_signal { + struct ugpu_cs_hdr hdr; + __u64 pointer; + __u64 value; +} __attribute__((packed)); +#define UGPU_CS_SIGNAL(flags) \ + __UGPU_CS_HDR(__UGPU_CS_SIGNAL, struct ugpu_cs_signal, flags) + +struct ugpu_cs_wake { + struct ugpu_cs_hdr hdr; + __u64 iova; + __u64 value; + __u64 cookie; +} __attribute__((packed)); +#define UGPU_CS_WAKE(flags) \ + __UGPU_CS_HDR(__UGPU_CS_WAKE, struct ugpu_cs_wake, flags) + +struct ugpu_cs_submit { + struct ugpu_cs_hdr hdr; + __u64 iova; + __u64 extensions; +} __attribute__((packed)); +#define UGPU_CS_SUBMIT(flags) \ + __UGPU_CS_HDR(__UGPU_CS_SUBMIT, struct ugpu_cs_submit, flags) + #endif 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))); + } +} |