diff options
-rw-r--r-- | benchmarks/.gitignore | 1 | ||||
-rw-r--r-- | benchmarks/Makefile.am | 4 | ||||
-rw-r--r-- | benchmarks/Makefile.sources | 1 | ||||
-rw-r--r-- | benchmarks/gem_exec_trace.c | 257 | ||||
-rw-r--r-- | benchmarks/generate_trace.c | 271 |
5 files changed, 534 insertions, 0 deletions
diff --git a/benchmarks/.gitignore b/benchmarks/.gitignore index f5e55aa0..8c39636b 100644 --- a/benchmarks/.gitignore +++ b/benchmarks/.gitignore @@ -1,6 +1,7 @@ gem_create gem_exec_ctx gem_exec_nop +gem_exec_trace gem_mmap gem_prw gem_userptr_benchmark diff --git a/benchmarks/Makefile.am b/benchmarks/Makefile.am index e042dd17..5bacd52e 100644 --- a/benchmarks/Makefile.am +++ b/benchmarks/Makefile.am @@ -4,3 +4,7 @@ include Makefile.sources AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib AM_CFLAGS = $(DRM_CFLAGS) $(CWARNFLAGS) $(CAIRO_CFLAGS) $(LIBUNWIND_CFLAGS) LDADD = $(top_builddir)/lib/libintel_tools.la $(DRM_LIBS) $(PCIACCESS_LIBS) $(CAIRO_LIBS) $(LIBUNWIND_LIBS) -lm + +noinst_LTLIBRARIES = generate_trace.la +generate_trace_la_LDFLAGS = -module -avoid-version -no-undefined +generate_trace_la_LIBADD = -ldl diff --git a/benchmarks/Makefile.sources b/benchmarks/Makefile.sources index 48ea77c8..8f324046 100644 --- a/benchmarks/Makefile.sources +++ b/benchmarks/Makefile.sources @@ -6,6 +6,7 @@ bin_PROGRAMS = \ gem_create \ gem_exec_ctx \ gem_exec_nop \ + gem_exec_trace \ gem_mmap \ gem_prw \ gem_userptr_benchmark \ diff --git a/benchmarks/gem_exec_trace.c b/benchmarks/gem_exec_trace.c new file mode 100644 index 00000000..a9e3eff1 --- /dev/null +++ b/benchmarks/gem_exec_trace.c @@ -0,0 +1,257 @@ +/* + * Copyright © 2011 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <time.h> + +#include "drm.h" +#include "ioctl_wrappers.h" +#include "drmtest.h" +#include "intel_io.h" +#include "igt_stats.h" + +enum { + ADD_BO = 0, + DEL_BO, + EXEC, +}; + +struct trace_add_bo { + uint32_t handle; + uint64_t size; +} __attribute__((packed)); + +struct trace_del_bo { + uint32_t handle; +} __attribute__((packed)); + +struct trace_exec { + uint32_t object_count; + uint64_t flags; +} __attribute__((packed)); +struct trace_exec_object { + uint32_t handle; + uint32_t relocation_count; + uint64_t alignment; + uint64_t flags; + uint64_t rsvd1; + uint64_t rsvd2; +} __attribute__((packed)); +struct trace_exec_relocation { + uint32_t target_handle; + uint32_t delta; + uint64_t offset; + uint32_t read_domains; + uint32_t write_domain; +} __attribute__((packed)); + +static double elapsed(const struct timespec *start, const struct timespec *end) +{ + return 1e3*(end->tv_sec - start->tv_sec) + 1e-6*(end->tv_nsec - start->tv_nsec); +} + +int fd; + +struct bo { + uint32_t handle; + uint64_t offset; + + struct drm_i915_gem_relocation_entry *relocs; + uint32_t max_relocs; +} *bo, **offsets; +int num_bo; + +struct drm_i915_gem_exec_object2 *exec_objects; +int max_objects; + +static void *add_bo(void *ptr) +{ + struct trace_add_bo *t = ptr; + uint32_t bb = 0xa << 23; + + if (t->handle > num_bo) { + num_bo = (t->handle + 4095) & -4096; + bo = realloc(bo, sizeof(*bo)*num_bo); + } + + bo[t->handle].handle = gem_create(fd, t->size); + gem_write(fd, bo[t->handle].handle, 0, &bb, sizeof(bb)); + + return t + 1; +} + +static void *del_bo(void *ptr) +{ + struct trace_del_bo *t = ptr; + + gem_close(fd, bo[t->handle].handle); + bo[t->handle].handle = 0; + + free(bo[t->handle].relocs); + bo[t->handle].relocs = NULL; + bo[t->handle].max_relocs = 0; + + return t + 1; +} + +static void *exec(void *ptr) +{ + struct trace_exec *t = ptr; + struct drm_i915_gem_execbuffer2 eb; + uint32_t i, j; + + memset(&eb, 0, sizeof(eb)); + eb.buffer_count = t->object_count; + eb.flags = t->flags & ~I915_EXEC_RING_MASK; + + if (t->object_count > max_objects) { + free(exec_objects); + free(offsets); + + max_objects = ALIGN(t->object_count, 4096); + + exec_objects = malloc(max_objects*sizeof(*exec_objects)); + offsets = malloc(max_objects*sizeof(*offsets)); + } + eb.buffers_ptr = (uintptr_t)exec_objects; + + ptr = t + 1; + for (i = 0; i < t->object_count; i++) { + struct drm_i915_gem_relocation_entry *relocs; + struct trace_exec_object *to = ptr; + ptr = to + 1; + + offsets[i] = &bo[to->handle]; + + exec_objects[i].handle = bo[to->handle].handle; + exec_objects[i].offset = bo[to->handle].offset; + exec_objects[i].alignment = to->alignment; + exec_objects[i].flags = to->flags; + exec_objects[i].rsvd1 = to->rsvd1; + exec_objects[i].rsvd2 = to->rsvd2; + + exec_objects[i].relocation_count = to->relocation_count; + if (!to->relocation_count) + continue; + + if (to->relocation_count > bo[to->handle].max_relocs) { + free(bo[to->handle].relocs); + + bo[to->handle].max_relocs = ALIGN(to->relocation_count, 128); + bo[to->handle].relocs = malloc(sizeof(*bo[to->handle].relocs)*bo[to->handle].max_relocs); + } + relocs = bo[to->handle].relocs; + exec_objects[i].relocs_ptr = (uintptr_t)relocs; + + for (j = 0; j < to->relocation_count; j++) { + struct trace_exec_relocation *tr = ptr; + ptr = tr + 1; + + if (t->flags & I915_EXEC_HANDLE_LUT) { + uint32_t handle; + + relocs[j].target_handle = tr->target_handle; + + handle = exec_objects[tr->target_handle].handle; + relocs[j].presumed_offset = bo[handle].offset; + } else { + relocs[j].target_handle = bo[tr->target_handle].handle; + relocs[j].presumed_offset = bo[tr->target_handle].offset; + } + relocs[j].delta = tr->delta; + relocs[j].offset = tr->offset; + relocs[j].read_domains = tr->read_domains; + relocs[j].write_domain = tr->write_domain; + } + } + + gem_execbuf(fd, &eb); + + for (i = 0; i < t->object_count; i++) + offsets[i]->offset = exec_objects[i].offset; + + return ptr; +} + +static void replay(const char *filename) +{ + struct timespec t_start, t_end; + struct stat st; + uint8_t *ptr, *end; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return; + + if (fstat(fd, &st) < 0) + return; + + ptr = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + close(fd); + + end = ptr + st.st_size; + fd = drm_open_any(); + + clock_gettime(CLOCK_MONOTONIC, &t_start); + do { + switch (*ptr++) { + case ADD_BO: + ptr = add_bo(ptr); + break; + case DEL_BO: + ptr = del_bo(ptr); + break; + case EXEC: + ptr = exec(ptr); + break; + } + } while (ptr < end); + clock_gettime(CLOCK_MONOTONIC, &t_end); + close(fd); + + printf("%s: %.3f\n", filename, elapsed(&t_start, &t_end)); +} + +int main(int argc, char **argv) +{ + int i; + + for (i = 1; i < argc; i++) + replay(argv[i]); + + return 0; +} diff --git a/benchmarks/generate_trace.c b/benchmarks/generate_trace.c new file mode 100644 index 00000000..81c3eef7 --- /dev/null +++ b/benchmarks/generate_trace.c @@ -0,0 +1,271 @@ +/* + * Copyright © 2015 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#define _GNU_SOURCE /* for RTLD_NEXT */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <stdbool.h> +#include <stdarg.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <errno.h> +#include <sys/mman.h> +#include <dlfcn.h> +#include <i915_drm.h> + +#include "intel_aub.h" +#include "intel_chipset.h" + +static int (*libc_close)(int fd); +static int (*libc_ioctl)(int fd, unsigned long request, void *argp); + +static int drm_fd = -1; +static FILE *file; + +#define DRM_MAJOR 226 + +enum { + ADD_BO = 0, + DEL_BO, + EXEC, +}; + +struct trace_add_bo { + uint8_t cmd; + uint32_t handle; + uint64_t size; +} __attribute__((packed)); +struct trace_del_bo { + uint8_t cmd; + uint32_t handle; +}__attribute__((packed)); + +struct trace_exec { + uint8_t cmd; + uint32_t object_count; + uint64_t flags; +}__attribute__((packed)); + +struct trace_exec_object { + uint32_t handle; + uint32_t relocation_count; + uint64_t alignment; + uint64_t flags; + uint64_t rsvd1; + uint64_t rsvd2; +}__attribute__((packed)); + +struct trace_exec_relocation { + uint32_t target_handle; + uint32_t delta; + uint64_t offset; + uint32_t read_domains; + uint32_t write_domain; +}__attribute__((packed)); + +static void __attribute__ ((format(__printf__, 2, 3))) +fail_if(int cond, const char *format, ...) +{ + va_list args; + + if (!cond) + return; + + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + + exit(1); +} + +static void +trace_exec(int fd, const struct drm_i915_gem_execbuffer2 *execbuffer2) +{ + const struct drm_i915_gem_exec_object2 *exec_objects = + (struct drm_i915_gem_exec_object2 *)(uintptr_t)execbuffer2->buffers_ptr; + + { + struct trace_exec t = { + EXEC, execbuffer2->buffer_count, execbuffer2->flags + }; + fwrite(&t, sizeof(t), 1, file); + } + + for (uint32_t i = 0; i < execbuffer2->buffer_count; i++) { + const struct drm_i915_gem_exec_object2 *obj = &exec_objects[i]; + const struct drm_i915_gem_relocation_entry *relocs = + (struct drm_i915_gem_relocation_entry *)(uintptr_t)obj->relocs_ptr; + { + struct trace_exec_object t = { + obj->handle, + obj->relocation_count, + obj->alignment, + obj->flags, + obj->rsvd1, + obj->rsvd2 + }; + fwrite(&t, sizeof(t), 1, file); + } + for (uint32_t j = 0; j < obj->relocation_count; j++) { + struct trace_exec_relocation t = { + relocs[j].target_handle, + relocs[j].delta, + relocs[j].offset, + relocs[j].read_domains, + relocs[j].write_domain, + }; + fwrite(&t, sizeof(t), 1, file); + } + } + + fflush(file); +} + +static void +trace_add(uint32_t handle, uint64_t size) +{ + struct trace_add_bo t = { ADD_BO, handle, size }; + fwrite(&t, sizeof(t), 1, file); +} + +static void +trace_del(uint32_t handle) +{ + struct trace_del_bo t = { DEL_BO, handle }; + fwrite(&t, sizeof(t), 1, file); +} + +int +close(int fd) +{ + if (fd == drm_fd) + drm_fd = -1; + + return libc_close(fd); +} + +int +ioctl(int fd, unsigned long request, ...) +{ + va_list args; + void *argp; + int ret; + + va_start(args, request); + argp = va_arg(args, void *); + va_end(args); + + if (_IOC_TYPE(request) == DRM_IOCTL_BASE && drm_fd != fd) { + char filename[80]; + if (file) + fclose(file); + sprintf(filename, "/tmp/trace.%d", fd); + file = fopen(filename, "w+"); + drm_fd = fd; + } + + if (fd == drm_fd) { + switch (request) { + case DRM_IOCTL_I915_GEM_EXECBUFFER: { + return libc_ioctl(fd, request, argp); + } + + case DRM_IOCTL_I915_GEM_EXECBUFFER2: { + trace_exec(fd, argp); + return libc_ioctl(fd, request, argp); + } + + case DRM_IOCTL_I915_GEM_CREATE: { + struct drm_i915_gem_create *create = argp; + + ret = libc_ioctl(fd, request, argp); + if (ret == 0) + trace_add(create->handle, create->size); + + return ret; + } + + case DRM_IOCTL_I915_GEM_USERPTR: { + struct drm_i915_gem_userptr *userptr = argp; + + ret = libc_ioctl(fd, request, argp); + if (ret == 0) + trace_add(userptr->handle, userptr->user_size); + return ret; + } + + case DRM_IOCTL_GEM_CLOSE: { + struct drm_gem_close *close = argp; + + trace_del(close->handle); + + return libc_ioctl(fd, request, argp); + } + + case DRM_IOCTL_GEM_OPEN: { + struct drm_gem_open *open = argp; + + ret = libc_ioctl(fd, request, argp); + if (ret == 0) + trace_add(open->handle, open->size); + + return ret; + } + + case DRM_IOCTL_PRIME_FD_TO_HANDLE: { + struct drm_prime_handle *prime = argp; + + ret = libc_ioctl(fd, request, argp); + if (ret == 0) { + off_t size; + + size = lseek(prime->fd, 0, SEEK_END); + fail_if(size == -1, "failed to get prime bo size\n"); + trace_add(prime->handle, size); + } + + return ret; + } + + default: + return libc_ioctl(fd, request, argp); + } + } else { + return libc_ioctl(fd, request, argp); + } +} + +static void __attribute__ ((constructor)) +init(void) +{ + libc_close = dlsym(RTLD_NEXT, "close"); + libc_ioctl = dlsym(RTLD_NEXT, "ioctl"); + fail_if(libc_close == NULL || libc_ioctl == NULL, + "failed to get libc ioctl or close\n"); +} |