diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2018-02-27 16:02:37 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2018-03-15 17:47:41 +0000 |
commit | 821f110241d7537a1c873c71ad5fd7cc2cfc756d (patch) | |
tree | f3dab30d6cffa738f099d1eeec10be205d97cbfe | |
parent | 081586fff7b1b5002ce4410ac3544d262809e39f (diff) |
rrulrrul
-rw-r--r-- | benchmarks/.gitignore | 1 | ||||
-rw-r--r-- | benchmarks/Makefile.am | 5 | ||||
-rw-r--r-- | benchmarks/Makefile.sources | 1 | ||||
-rw-r--r-- | benchmarks/benchmarks.h | 11 | ||||
-rw-r--r-- | benchmarks/calibration.c | 125 | ||||
-rw-r--r-- | benchmarks/calibration.h | 45 | ||||
-rw-r--r-- | benchmarks/gem.c | 226 | ||||
-rw-r--r-- | benchmarks/gem.h | 53 | ||||
-rw-r--r-- | benchmarks/host.c | 378 | ||||
-rw-r--r-- | benchmarks/rrul.c | 735 | ||||
-rw-r--r-- | benchmarks/rrul.yaml | 17 | ||||
-rw-r--r-- | benchmarks/yaml_utils.c | 113 | ||||
-rw-r--r-- | benchmarks/yaml_utils.h | 14 | ||||
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | lib/i915/gem_context.c | 4 |
15 files changed, 1726 insertions, 3 deletions
diff --git a/benchmarks/.gitignore b/benchmarks/.gitignore index 56daa1fd..92348229 100644 --- a/benchmarks/.gitignore +++ b/benchmarks/.gitignore @@ -20,4 +20,5 @@ intel_upload_blit_large_map intel_upload_blit_small kms_vblank prime_lookup +rrul vgem_mmap diff --git a/benchmarks/Makefile.am b/benchmarks/Makefile.am index 055e4c3a..458d0e5a 100644 --- a/benchmarks/Makefile.am +++ b/benchmarks/Makefile.am @@ -15,6 +15,7 @@ AM_CPPFLAGS = \ AM_CFLAGS = -I$(top_srcdir)/include/drm-uapi \ $(DRM_CFLAGS) $(CWARNFLAGS) $(CAIRO_CFLAGS) $(LIBUNWIND_CFLAGS) \ + $(YAML_CFLAGS) \ $(WERROR_CFLAGS) -D_GNU_SOURCE LDADD = $(top_builddir)/lib/libintel_tools.la @@ -28,6 +29,10 @@ gem_syslatency_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS) gem_syslatency_LDADD = $(LDADD) -lpthread -lrt gem_wsim_LDADD = $(LDADD) $(top_builddir)/lib/libigt_perf.la -lpthread +rrul_SOURCES = host.c rrul.c calibration.c gem.c yaml_utils.c +rrul_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS) +rrul_LDADD = $(LDADD) $(YAML_LIBS) -lpthread -lrt + EXTRA_DIST= \ README \ meson.build \ diff --git a/benchmarks/Makefile.sources b/benchmarks/Makefile.sources index d150035a..eec586dc 100644 --- a/benchmarks/Makefile.sources +++ b/benchmarks/Makefile.sources @@ -17,6 +17,7 @@ benchmarks_prog_list = \ gem_wsim \ kms_vblank \ prime_lookup \ + rrul \ vgem_mmap \ $(NULL) diff --git a/benchmarks/benchmarks.h b/benchmarks/benchmarks.h new file mode 100644 index 00000000..45fe848b --- /dev/null +++ b/benchmarks/benchmarks.h @@ -0,0 +1,11 @@ +#ifndef BENCHMARKS_H +#define BENCHMARKS_H + +#include <stdio.h> + +typedef int (*benchmark_fn_t)(int, int); + +int rrul(int config, int results); + +#endif /* BENCHMARKS_H */ + diff --git a/benchmarks/calibration.c b/benchmarks/calibration.c new file mode 100644 index 00000000..fc29e474 --- /dev/null +++ b/benchmarks/calibration.c @@ -0,0 +1,125 @@ +#include <assert.h> +#include <time.h> +#include <yaml.h> + +#include "calibration.h" +#include "gem.h" + +#include "i915_drm.h" + +#define MI_ARB_CHECK (0x05 << 23) +#define MI_BATCH_BUFFER_END (0x0a << 23) + +uint32_t calibration_batch(int fd, unsigned long size) +{ + uint32_t handle, *batch; + unsigned long n; + + size = ALIGN(size, 4096); + handle = gem_create(fd, size); + + batch = gem_mmap(fd, handle, 0, size, PROT_WRITE, 0); + for (n = 0; n < size/sizeof(*batch) - 1; n++) + batch[n] = MI_ARB_CHECK; + batch[n] = MI_BATCH_BUFFER_END; + munmap(batch, size); + + return handle; +} + +static double elapsed(const struct timespec *start, const struct timespec *end) +{ + return (end->tv_sec - start->tv_sec) + + (end->tv_nsec - start->tv_nsec) / 1e9; +} + +struct calibration calibrate_nops(int fd, + unsigned long target_us, + unsigned int tolerance_pct) +{ + struct drm_i915_gem_exec_object2 obj = {}; + struct drm_i915_gem_execbuffer2 eb = { + .buffer_count = 1, .buffers_ptr = (uintptr_t)&obj + }; + struct timespec t_0, t_end; + unsigned int loops = 17; + long size, last_size; + + clock_gettime(CLOCK_MONOTONIC, &t_0); + + size = 256 * 1024; + do { + struct timespec t_start; + + obj.handle = calibration_batch(fd, size); + + gem_execbuf(fd, &eb); + gem_wait(fd, obj.handle, NULL); + + clock_gettime(CLOCK_MONOTONIC, &t_start); + for (int loop = 0; loop < loops; loop++) + gem_execbuf(fd, &eb); + gem_wait(fd, obj.handle, NULL); + clock_gettime(CLOCK_MONOTONIC, &t_end); + + gem_close(fd, obj.handle); + + last_size = size; + size = loops * size / elapsed(&t_start, &t_end) / 1e6 * target_us; + size = ALIGN(size, sizeof(uint32_t)); + } while (elapsed(&t_0, &t_end) < 5 || + abs(size - last_size) > ((size + last_size) * tolerance_pct / 200)); + + + return (struct calibration){ target_us, (size + last_size)/2 }; +} + +static uint64_t node_to_u64(yaml_node_t *node) +{ + assert(node->type == YAML_SCALAR_NODE); + return strtoull((const char *)node->data.scalar.value, NULL, 0); +} + +int parse_calibration(yaml_document_t *doc, + yaml_node_t *node, + struct calibration *calibration) +{ + calibration->duration = 1000; /* 1ms baseline by default */ + + switch (node->type) { + default: + case YAML_NO_NODE: + case YAML_SEQUENCE_NODE: + return -1; + + case YAML_SCALAR_NODE: + calibration->bytes = node_to_u64(node); + break; + + case YAML_MAPPING_NODE: + for (yaml_node_pair_t *it = node->data.mapping.pairs.start; + it < node->data.mapping.pairs.top; + it++) { + yaml_node_t *key, *value; + + key = yaml_document_get_node(doc, it->key); + value = yaml_document_get_node(doc, it->value); + + if (!strcmp(key->data.scalar.value, "duration")) { + calibration->duration = node_to_u64(value); + } else if (!strcmp(key->data.scalar.value, "bytes")) { + calibration->bytes = node_to_u64(value); + } else { + printf("Unknown calibration field: %s\n", + key->data.scalar.value); + return -1; + } + } + break; + } + + if (!calibration->bytes || !calibration->duration) + return -1; + + return 0; +} diff --git a/benchmarks/calibration.h b/benchmarks/calibration.h new file mode 100644 index 00000000..0e53364e --- /dev/null +++ b/benchmarks/calibration.h @@ -0,0 +1,45 @@ +#ifndef CALIBRATION_H +#define CALIBRATION_H + +#include <stdint.h> + +#ifndef ALIGN +#define ALIGN(x, y) (((x) + (y) - 1) & -(y)) +#endif + +struct yaml_document_s; +struct yaml_node_s; + +struct calibration { + unsigned long duration; + unsigned long bytes; +}; + +int parse_calibration(struct yaml_document_s *doc, + struct yaml_node_s *node, + struct calibration *calibration); + +struct calibration +calibrate_nops(int fd, + unsigned long target_us, + unsigned int tolerance_pct); + +static inline unsigned long +calibrated_batch_size(const struct calibration *c, + unsigned long duration_us) +{ + return ALIGN(duration_us * c->bytes / c->duration, sizeof(uint32_t)); +} + +static inline unsigned long +calibrated_batch_offset(const struct calibration *c, + unsigned long duration_us, + unsigned long batch_size) +{ + /* BUG_ON(calibrated_batch_size(c, duration_us) > batch_size); */ + return (batch_size - calibrated_batch_size(c, duration_us) - 8) & -64; +} + +uint32_t calibration_batch(int fd, unsigned long size); + +#endif /* CALIBRATION_H */ diff --git a/benchmarks/gem.c b/benchmarks/gem.c new file mode 100644 index 00000000..2c162af3 --- /dev/null +++ b/benchmarks/gem.c @@ -0,0 +1,226 @@ +#include <errno.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/syscall.h> +#include <time.h> + +#include "gem.h" + +#include "i915_drm.h" + +#define MSEC_PER_SEC (1000) +#define USEC_PER_SEC (1000 * MSEC_PER_SEC) +#define NSEC_PER_SEC (1000 * USEC_PER_SEC) + +static inline long __sys_ioctl(int fd, unsigned long cmd, void *arg) +{ + long result; + +#if defined(__linux__) && defined(__GNUC__) && defined (__x86_64__) + __asm__ __volatile__ + ("syscall" + : "=a" (result) + : "0" (__NR_ioctl), "D" (fd), "S" (cmd), "d" (arg) + : "cc", "rcx", "r11", "memory"); +#else + result = ioctl(fd, cmd, arg); + if (result == -1) + result = -errno; +#endif + + return result; +} + +static inline long sys_ioctl(int fd, unsigned long cmd, void *arg) +{ + long result; + + do { + result = __sys_ioctl(fd, cmd, arg); + } while (result == -EINTR || result == -EAGAIN); + + return result; +} + +static int __gem_create(int fd, uint64_t size, uint32_t *handle) +{ + struct drm_i915_gem_create create = { + .size = size, + }; + int err; + + err = sys_ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create); + if (err) + return err; + + *handle = create.handle; + return 0; +} + +uint32_t gem_create(int fd, uint64_t size) +{ + uint32_t handle = 0; + + __gem_create(fd, size, &handle); + + return handle; +} + +void *gem_mmap(int fd, uint32_t handle, + uint64_t offset, uint64_t size, + unsigned prot, unsigned int flags) +{ + struct drm_i915_gem_mmap arg = { + .handle = handle, + .offset = offset, + .size = size, + .flags = flags, + }; + + if (sys_ioctl(fd, DRM_IOCTL_I915_GEM_MMAP, &arg)) + return 0; + + return (void *)(uintptr_t)arg.addr_ptr; +} + +static int __gem_context_create(int fd, uint32_t *ctx) +{ + struct drm_i915_gem_context_create create = {}; + int err; + + err =sys_ioctl(fd, DRM_IOCTL_I915_GEM_CONTEXT_CREATE, &create); + if (err) + return err; + + *ctx = create.ctx_id; + return 0; +} + +uint32_t gem_context_create(int fd) +{ + uint32_t ctx = 0; + + __gem_context_create(fd, &ctx); + + return ctx; +} + +static int __gem_context_set_param(int fd, struct drm_i915_gem_context_param *p) +{ + return sys_ioctl(fd, DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM, p); +} + +int gem_context_set_priority(int fd, uint32_t ctx, int prio) +{ + struct drm_i915_gem_context_param p = { + .ctx_id = ctx, + .param = I915_CONTEXT_PARAM_PRIORITY, + .value = prio, + }; + + return __gem_context_set_param(fd, &p); +} + +int gem_execbuf(int fd, struct drm_i915_gem_execbuffer2 *execbuf) +{ + return sys_ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, execbuf); +} + +int gem_execbuf_wr(int fd, struct drm_i915_gem_execbuffer2 *execbuf) +{ + return sys_ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, execbuf); +} + +int gem_wait(int fd, uint32_t handle, int64_t *timeout_ns) +{ + struct drm_i915_gem_wait wait = { + .bo_handle = handle, + .timeout_ns = timeout_ns ? *timeout_ns : -1, + }; + int err; + + err = sys_ioctl(fd, DRM_IOCTL_I915_GEM_WAIT, &wait); + + if (timeout_ns) + *timeout_ns = wait.timeout_ns; + + return err; +} + +void gem_close(int fd, uint32_t handle) +{ + sys_ioctl(fd, DRM_IOCTL_GEM_CLOSE, &handle); +} + +static int __syncobj_create(int fd, uint32_t *handle, uint32_t flags) +{ + struct drm_syncobj_create create = { + .flags = flags, + }; + int err; + + err = sys_ioctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &create); + if (err) + return err; + + *handle = create.handle; + return 0; +} + +struct syncobj *syncobj_create(int fd) +{ + struct syncobj *f; + + f = malloc(sizeof(*f)); + if (!f) + return NULL; + + f->ref = 1; + if (__syncobj_create(fd, &f->handle, 0)) { + free(f); + return NULL; + } + + return f; +} + +static int __syncobj_wait(int fd, struct drm_syncobj_wait *arg) +{ + return sys_ioctl(fd, DRM_IOCTL_SYNCOBJ_WAIT, arg); +} + +static uint64_t abs_time_ns(long sec, long nsec) +{ + struct timespec tv; + + clock_gettime(CLOCK_MONOTONIC, &tv); + + tv.tv_sec += sec; + tv.tv_nsec += nsec; + if (tv.tv_nsec >= NSEC_PER_SEC) { + tv.tv_sec++; + tv.tv_nsec -= NSEC_PER_SEC; + } + + return (uint64_t)tv.tv_sec * NSEC_PER_SEC + tv.tv_nsec; +} + +int syncobj_wait(int fd, struct syncobj *f) +{ + struct drm_syncobj_wait wait = { + .handles = (uintptr_t)&f->handle, + .count_handles = 1, + }; + int err = 0; + if (__syncobj_wait(fd, &wait)) { + wait.timeout_nsec = abs_time_ns(120, 0); + err = __syncobj_wait(fd, &wait); + } + return err; +} + +void __syncobj_free(int fd, struct syncobj *f) +{ + sys_ioctl(fd, DRM_IOCTL_SYNCOBJ_DESTROY, &f->handle); + free(f); +} diff --git a/benchmarks/gem.h b/benchmarks/gem.h new file mode 100644 index 00000000..cf1d35ad --- /dev/null +++ b/benchmarks/gem.h @@ -0,0 +1,53 @@ +#ifndef GEM_H +#define GEM_H + +#include <stdint.h> +#include <sys/mman.h> + +uint32_t gem_create(int fd, uint64_t size); + +void *gem_mmap(int fd, uint32_t handle, + uint64_t offset, uint64_t size, + unsigned prot, unsigned int flags); + +uint32_t gem_context_create(int fd); +int gem_context_set_priority(int fd, uint32_t ctx, int prio); + +struct drm_i915_gem_execbuffer2; +int gem_execbuf(int fd, struct drm_i915_gem_execbuffer2 *execbuf); +int gem_execbuf_wr(int fd, struct drm_i915_gem_execbuffer2 *execbuf); + +int gem_wait(int fd, uint32_t handle, int64_t *timeout_ns); + +static inline int gem_sync(int fd, uint32_t handle) +{ + return gem_wait(fd, handle, 0); +} + +void gem_close(int fd, uint32_t handle); + +struct syncobj { + unsigned int ref; + uint32_t handle; +}; + +struct syncobj *syncobj_create(int fd); + +static inline struct syncobj *syncobj_get(struct syncobj *f) +{ + __sync_fetch_and_add(&f->ref, 1); + return f; +} + +void __syncobj_free(int fd, struct syncobj *f); +static inline void syncobj_put(int fd, struct syncobj *f) +{ + if (__sync_sub_and_fetch(&f->ref, 1)) + return; + + __syncobj_free(fd, f); +} + +int syncobj_wait(int fd, struct syncobj *f); + +#endif /* GEM_H */ diff --git a/benchmarks/host.c b/benchmarks/host.c new file mode 100644 index 00000000..357002d0 --- /dev/null +++ b/benchmarks/host.c @@ -0,0 +1,378 @@ +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include <unistd.h> +#include <wait.h> +#include <yaml.h> + +#include "benchmarks.h" +#include "yaml_utils.h" + +static const unsigned char __machines__[] = +"# machine layout\n" +"machine: &bdw\n" +" address: 192.168.1.216\n" +" command: hostname\n" +"\n" +; + +struct host { + const char *name; + pid_t pid; + int config; + int results; +}; + +struct state { + yaml_parser_t parser; + + struct config { + struct host *host; + unsigned int nhost; + } config; +}; + +static int parse_config(yaml_document_t *doc, struct config *config) +{ + if (!yaml_document_get_root_node(doc)) + return 0; + + return 0; +} + +static int fanout_write(void *data, unsigned char *buffer, size_t size) +{ + struct state *st = data; + + for (unsigned int n = 0; n < st->config.nhost; n++) { + if (write(st->config.host[n].config, buffer, size) < 0) + return 0; + } + + return 1; +} + +static int fanout(struct state *st) +{ + yaml_emitter_t emitter; + yaml_event_t ev; + int depth = 0; + + yaml_emitter_initialize(&emitter); + yaml_emitter_set_output(&emitter, fanout_write, st); + + yaml_stream_start_event_initialize(&ev, YAML_UTF8_ENCODING); + if (!yaml_emitter_emit(&emitter, &ev)) + return -1; + + yaml_document_start_event_initialize(&ev, NULL, NULL, NULL, 0); + if (!yaml_emitter_emit(&emitter, &ev)) + return -1; + + do { + if (!yaml_parser_parse(&st->parser, &ev)) { + yaml_print_parser_error(&st->parser, stderr); + return -1; + } + + if (!yaml_emitter_emit(&emitter, &ev)) + return -1; + + switch (ev.type) { + case YAML_NO_EVENT: + case YAML_ALIAS_EVENT: + case YAML_SCALAR_EVENT: + break; + + default: + case YAML_STREAM_START_EVENT: + case YAML_STREAM_END_EVENT: + case YAML_DOCUMENT_START_EVENT: + case YAML_DOCUMENT_END_EVENT: + abort(); + break; + + case YAML_SEQUENCE_START_EVENT: + case YAML_MAPPING_START_EVENT: + depth++; + break; + + case YAML_SEQUENCE_END_EVENT: + case YAML_MAPPING_END_EVENT: + --depth; + break; + } + } while (depth); + + yaml_document_end_event_initialize(&ev, 0); + yaml_emitter_emit(&emitter, &ev); + + yaml_stream_end_event_initialize(&ev); + yaml_emitter_emit(&emitter, &ev); + + yaml_emitter_flush(&emitter); + yaml_emitter_delete(&emitter); + + return 0; +} + +static benchmark_fn_t lookup_benchmark(const char *name) +{ + if (!strcmp(name, "rrul")) + return rrul; + + return NULL; +} + +static pid_t setup_localhost(struct host *host, benchmark_fn_t fn) +{ + int link_config[2], link_results[2]; + pid_t pid; + + pipe(link_config); + pipe(link_results); + + switch ((pid = fork())) { + case -1: + return -1; + + case 0: + close(link_config[1]); + close(link_results[0]); + exit(fn(link_config[0], link_results[1])); + + default: + break; + } + + host->config = link_config[1]; + close(link_config[0]); + + host->results = link_results[0]; + close(link_results[1]); + + host->pid = pid; + + return pid; +} + +static pid_t setup_remote(struct host *host, const char *test) +{ + return -1; +} + +static int setup_test(struct state *st) +{ + yaml_event_t ev; + benchmark_fn_t fn; + const char *s; + + if (!yaml_parser_parse(&st->parser, &ev)) + return EXIT_FAILURE; + + switch (ev.type) { + case YAML_SCALAR_EVENT: + break; + + default: + return EXIT_FAILURE; + } + + s = (const char *)ev.data.scalar.value; + fn = lookup_benchmark(s); + if (!fn) { + fprintf(stderr, "unknown test: %s\n", ev.data.scalar.value); + return EXIT_FAILURE; + } + + for (unsigned int n = 0; n < st->config.nhost; n++) { + struct host *host = &st->config.host[0]; + + if (!host->name) { + if (setup_localhost(host, fn) < 0) + return EXIT_FAILURE; + } else { + if (setup_remote(host, s) < 0) + return EXIT_FAILURE; + } + } + + yaml_event_delete(&ev); + return EXIT_SUCCESS; +} + +static int parse_root(struct state *st) +{ + yaml_event_t ev; + const char *s; + bool done = false; + int ret = EXIT_FAILURE; + + do { + if (!yaml_parser_parse(&st->parser, &ev)) + goto err; + + switch (ev.type) { + case YAML_MAPPING_END_EVENT: + ret = EXIT_SUCCESS; + goto out; + + case YAML_SCALAR_EVENT: + break; + + default: + goto err; + } + + if (done) + goto err; + + s = (char *)ev.data.scalar.value; + if (!strcmp(s, "test")) { + if (setup_test(st)) + goto err; + } else if (!strcmp(s, "config")) { + if (fanout(st)) + goto err; + done = true; + } else if (!strcmp(s, "results")) { + } else { + fprintf(stderr, "Unknown root key: %s\n", s); + goto err; + } + + yaml_event_delete(&ev); + } while (1); + +out: + for(unsigned n = 0; n < st->config.nhost; n++) + close(st->config.host[n].config); + + /* wait for tests to complete */ + for(unsigned n = 0; n < st->config.nhost; n++) { + int status, err; + + do { + err = 0; + if (waitpid(st->config.host[n].pid, &status, 0) < 0) + err = -errno; + } while (err == -EINTR); + } + return ret; + +err: + for(unsigned n = 0; n < st->config.nhost; n++) + kill(st->config.host[n].pid, SIGKILL); + goto out; +} + +static int parse_doc(struct state *st) +{ + yaml_event_t ev; + + do { + if (!yaml_parser_parse(&st->parser, &ev)) + return EXIT_FAILURE; + + switch (ev.type) { + case YAML_DOCUMENT_END_EVENT: + return EXIT_SUCCESS; + + case YAML_MAPPING_START_EVENT: + break; + + default: + return EXIT_FAILURE; + } + yaml_event_delete(&ev); + + if (parse_root(st)) + return EXIT_FAILURE; + } while (1); +} + +static int parse_stream(struct state *st) +{ + yaml_event_t ev; + + if (!yaml_parser_parse(&st->parser, &ev)) + return EXIT_FAILURE; + + assert(ev.type == YAML_STREAM_START_EVENT); + yaml_event_delete(&ev); + + do { + if (!yaml_parser_parse(&st->parser, &ev)) + return EXIT_FAILURE; + + switch (ev.type) { + case YAML_DOCUMENT_START_EVENT: + break; + + case YAML_STREAM_END_EVENT: + return EXIT_SUCCESS; + + default: + return EXIT_FAILURE; + } + yaml_event_delete(&ev); + + if (parse_doc(st)) + return EXIT_FAILURE; + } while (1); + + return 0; +} + +static int load_machines(struct state *st, const char *filename) +{ + yaml_document_t doc; + int fd; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return EXIT_FAILURE; + + if (yaml_load_document(fd, &doc)) + return EXIT_FAILURE; + + if (parse_config(&doc, &st->config)) + return EXIT_FAILURE; + + yaml_document_delete(&doc); + + return 0; +} + +int main(int argc, char **argv) +{ + struct state st = {}; + + if (argc == 2) { + benchmark_fn_t fn; + + fn = lookup_benchmark(argv[1]); + if (!fn) { + fprintf(stderr, "unknown benchmark: %s\n", argv[1]); + return 1; + } + + return fn(0, 1); + } + + if (0) { + if (load_machines(&st, "machines")) + return EXIT_FAILURE; + } + + if (!st.config.nhost) { + st.config.host = calloc(1, sizeof(*st.config.host)); + st.config.nhost++; + } + + yaml_parser_initialize(&st.parser); + yaml_parser_set_input(&st.parser, yaml_read_fd, 0); + + exit(parse_stream(&st)); +} diff --git a/benchmarks/rrul.c b/benchmarks/rrul.c new file mode 100644 index 00000000..1ea9c611 --- /dev/null +++ b/benchmarks/rrul.c @@ -0,0 +1,735 @@ +#include <errno.h> +#include <fcntl.h> +#include <pciaccess.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/signal.h> +#include <sys/mman.h> +#include <sys/wait.h> +#include <unistd.h> +#include <yaml.h> +#include <assert.h> + +#include "drm.h" +#include "i915_drm.h" + +#include "benchmarks.h" +#include "calibration.h" +#include "gem.h" +#include "yaml_utils.h" + +#define MSEC_PER_SEC (1000) +#define USEC_PER_SEC (1000 * MSEC_PER_SEC) +#define NSEC_PER_SEC (1000 * USEC_PER_SEC) + +#define MI_NOOP (0x00 << 23) +#define MI_ARB_CHECK (0x05 << 23) +#define MI_BATCH_BUFFER_END (0x0a << 23) +#define MI_STORE_DWORD_IMM (0x20 << 23) +#define MI_STORE_REG_MEM (0x24 << 23) +#define MI_BATCH_BUFFER_START (0x31 << 23) + +#define RCS_TIMESTAMP (0x2000 + 0x358) + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) +#define READ_ONCE(x) (*(volatile typeof(x) *)(&(x))) +#define ALIGN(x, y) (((x) + (y) - 1) & -(y)) + +struct probe_thread { + pthread_t thread; + struct probe_thread *next; + + int i915; + int priority; + + unsigned long clk_freq; + void *mmio; +}; + +struct client_thread { + pthread_t thread; + struct client_thread *next; + + int i915; + int id; + + int priority; + + uint32_t work; + unsigned long duration; + + struct flip_thread *flip; + enum vsync { NOFLIP, ASYNC, DOUBLE, TRIPLE } vsync; +}; + +struct flip_thread { + pthread_t thread; + pthread_mutex_t lock; + pthread_cond_t cond; + + int i915; + uint32_t work; + unsigned long duration; + int priority; + + int nclients; + struct syncobj **syncobj[2]; + struct drm_i915_gem_exec_fence *array; + unsigned int serial; +}; + +struct state { + const char *device; + struct calibration calibration; + + unsigned int n_clients; + unsigned long max_duration; + + struct probe_thread *probes; + struct client_thread *clients; + struct flip_thread *flip; +}; + +static double elapsed(const struct timespec *start, const struct timespec *end) +{ + return (end->tv_sec - start->tv_sec) + + (end->tv_nsec - start->tv_nsec) / 1e9; +} + +static int pageflip(int fd, uint32_t fence) +{ + union drm_wait_vblank vbl = {}; + + vbl.request.type = _DRM_VBLANK_RELATIVE; + vbl.request.type |= _DRM_VBLANK_NEXTONMISS; + vbl.request.type |= _DRM_VBLANK_SIGNAL; + + return ioctl(fd, DRM_IOCTL_WAIT_VBLANK, &vbl); +} + +static void *flip_thread(void *arg) +{ + struct flip_thread *f = arg; + struct drm_i915_gem_exec_object2 obj = { + .handle = f->work, + }; + struct drm_i915_gem_execbuffer2 eb = { + .batch_start_offset = f->duration, + .buffers_ptr = (uintptr_t)&obj, + .buffer_count = 1, + .flags = I915_EXEC_NO_RELOC, + .rsvd1 = gem_context_create(f->i915), + }; + struct timespec t[2]; + + /* + * Once every frame, gather up all the completed work, + * pretend to copy the object into our backbuffer and queue + * a flip. + */ + + eb.cliprects_ptr = (uintptr_t)f->array; + eb.flags |= I915_EXEC_FENCE_ARRAY | I915_EXEC_FENCE_OUT; + gem_context_set_priority(f->i915, eb.rsvd1, f->priority); + + clock_gettime(CLOCK_MONOTONIC, &t[1]); + do { + struct syncobj **tmp; + char events[1024]; + int fence; + int ret; + + pthread_mutex_lock(&f->lock); + + tmp = f->syncobj[0]; + f->syncobj[0] = f->syncobj[1]; + f->syncobj[1] = tmp; + + f->serial++; + pthread_cond_broadcast(&f->cond); + + pthread_mutex_unlock(&f->lock); + + eb.num_cliprects = 0; + for (int n = 0; n < f->nclients; n++) { + if (!tmp[n]) + continue; + + f->array[eb.num_cliprects++].handle = tmp[n]->handle; + } + gem_execbuf_wr(f->i915, &eb); + + fence = eb.rsvd2 >> 32; + + ret = pageflip(f->i915, fence); + close(fence); + + for (int n = 0; n < f->nclients; n++) { + if (!tmp[n]) + continue; + + syncobj_put(f->i915, tmp[n]); + tmp[n] = NULL; + } + + if (ret == 0) { + read(f->i915, events, sizeof(events)); + } else { + struct timespec tv; + int remaining_us; + + gem_sync(f->i915, f->work); + + clock_gettime(CLOCK_MONOTONIC, &tv); + remaining_us = 16*1000 - elapsed(&t[1], &tv)*1e6; + while (remaining_us < 0) + remaining_us += 16*1000; + usleep(remaining_us); + } + + t[0] = t[1]; + clock_gettime(CLOCK_MONOTONIC, &t[1]); + + printf("Flip elapsed: %.2fms\n", elapsed(&t[0], &t[1])*1e3); + } while (1); + + return NULL; +} + +static void start_flip_thread(struct flip_thread *f, + int i915, int nclients, + uint32_t work, unsigned long size, + struct calibration *calibration) +{ + f->i915 = i915; + f->nclients = nclients; + + f->work = work; + f->duration = calibrated_batch_offset(calibration, f->duration, size); + + f->syncobj[0] = calloc(nclients, sizeof(*f->syncobj[0])); + f->syncobj[1] = calloc(nclients, sizeof(*f->syncobj[1])); + + f->array = malloc(nclients * sizeof(*f->array)); + for (int n = 0; n < nclients; n++) + f->array[n].flags = I915_EXEC_FENCE_WAIT; + + pthread_create(&f->thread, NULL, flip_thread, f); +} + +static unsigned int wait_for_flip(struct flip_thread *flip) +{ + unsigned int serial; + + serial = flip->serial; + do + pthread_cond_wait(&flip->cond, &flip->lock); + while (serial == flip->serial); + + return flip->serial; +} + +static void *client_thread(void *arg) +{ + struct client_thread *c = arg; + struct drm_i915_gem_exec_fence fence_array = { + .flags = I915_EXEC_FENCE_SIGNAL, + }; + struct drm_i915_gem_exec_object2 obj = { + .handle = c->work, + }; + struct drm_i915_gem_execbuffer2 eb = { + .buffers_ptr = (uintptr_t)&obj, + .buffer_count = 1, + .batch_start_offset = c->duration, + .flags = I915_EXEC_FENCE_ARRAY | I915_EXEC_NO_RELOC, + .cliprects_ptr = (uintptr_t)&fence_array, + .num_cliprects = 1, + .rsvd1 = gem_context_create(c->i915), + }; + struct flip_thread *flip = c->flip; + const enum vsync vsync = flip ? c->vsync : NOFLIP; + struct syncobj *syncobj[2] = {}; + unsigned int seqno = 0; + int i915 = c->i915; + + gem_context_set_priority(i915, eb.rsvd1, c->priority); + + while (1) { + struct syncobj *f = syncobj_create(i915), *old; + + fence_array.handle = f->handle; + gem_execbuf(i915, &eb); + + if (vsync != NOFLIP) { + pthread_mutex_lock(&flip->lock); + old = flip->syncobj[0][c->id]; + while (vsync == TRIPLE && old) { + wait_for_flip(flip); + old = flip->syncobj[0][c->id]; + } + if (!old) + flip->syncobj[0][c->id] = syncobj_get(f); + if (vsync == DOUBLE) + wait_for_flip(flip); + pthread_mutex_unlock(&flip->lock); + } + + old = syncobj[seqno % ARRAY_SIZE(syncobj)]; + syncobj[seqno % ARRAY_SIZE(syncobj)] = f; + seqno++; + + if (old) { + syncobj_wait(i915, old); + syncobj_put(i915, old); + } + } + + return NULL; +} + +static void start_client_thread(struct client_thread *c, + int i915, struct flip_thread *flip, + uint32_t work, unsigned long size, + struct calibration *calibration) +{ + c->i915 = i915; + c->flip = flip; + + c->work = work; + c->duration = calibrated_batch_offset(calibration, c->duration, size); + + pthread_create(&c->thread, NULL, client_thread, c); +} + +static int wakeref_get(void) +{ + return open("/sys/kernel/debug/dri/0/i915_forcewake_user", O_RDONLY); +} + +static void wakeref_put(int fw) +{ + close(fw); +} + +static void *probe_thread(void *arg) +{ + struct probe_thread *probe = arg; + struct drm_i915_gem_exec_object2 obj = { + .handle = gem_create(probe->i915, 4096), + }; + struct drm_i915_gem_execbuffer2 eb = { + .buffers_ptr = (uintptr_t)&obj, + .buffer_count = 1, + .flags = I915_EXEC_NO_RELOC, + .rsvd1 = gem_context_create(probe->i915), + }; + uint32_t *timestamp = (uint32_t *)((char *)probe->mmio + RCS_TIMESTAMP); + uint32_t *batch; + + gem_context_set_priority(probe->i915, eb.rsvd1, probe->priority); + + batch = gem_mmap(probe->i915, obj.handle, + 0, 4096, PROT_WRITE, I915_MMAP_WC); + *batch = MI_BATCH_BUFFER_END; + gem_execbuf(probe->i915, &eb); + + batch[16] = MI_STORE_REG_MEM | 2; + batch[17] = RCS_TIMESTAMP; + batch[18] = obj.offset; + batch[19] = obj.offset >> 32; + batch[20] = MI_BATCH_BUFFER_END; + + obj.flags = EXEC_OBJECT_PINNED; + eb.batch_start_offset = 16 * sizeof(*batch); + + do { + unsigned latency; + int fw; + + fw = wakeref_get(); + latency = -READ_ONCE(*timestamp); + gem_execbuf(probe->i915, &eb); + wakeref_put(fw); + + gem_sync(probe->i915, obj.handle); + + latency += READ_ONCE(batch[0]); + printf("Probe latency: %dus\n", + (int)((uint64_t)latency * USEC_PER_SEC / probe->clk_freq)); + + usleep(100000); + } while (1); + + return NULL; +} + +static void rtprio(pthread_attr_t *attr, int prio) +{ +#ifdef PTHREAD_EXPLICIT_SCHED + struct sched_param param = { .sched_priority = 99 }; + + pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED); + pthread_attr_setschedpolicy(attr, SCHED_FIFO); + pthread_attr_setschedparam(attr, ¶m); +#endif +} + +static void start_probe_thread(struct probe_thread *probe, + int i915, void *mmio, unsigned long clk_freq) +{ + pthread_attr_t attr; + + probe->i915 = i915; + probe->mmio = mmio; + probe->clk_freq = clk_freq; + + pthread_attr_init(&attr); + rtprio(&attr, 99); + + pthread_create(&probe->thread, NULL, probe_thread, probe); +} + +static void *ioremap(int i915) +{ + struct pci_device *pci_dev; + void *mmio = NULL; + + pci_system_init(); + + pci_dev = pci_device_find_by_slot(0, 0, 2, 0); + if (!pci_dev) + return NULL; + + pci_device_probe(pci_dev); + pci_device_map_range(pci_dev, + pci_dev->regions[0].base_addr, + 2 << 20, + PCI_DEV_MAP_FLAG_WRITABLE, + &mmio); + + return mmio; +} + +static unsigned long measure_clk_freq(void *mmio) +{ + uint32_t *timestamp = (uint32_t *)((char *)mmio + RCS_TIMESTAMP); + struct timespec t_0, t_1; + unsigned long c_0, c_1; + int fw; + + fw = wakeref_get(); + + c_0 = READ_ONCE(*timestamp); + clock_gettime(CLOCK_MONOTONIC, &t_0); + c_0 += READ_ONCE(*timestamp); + + usleep(10000); + + c_1 = READ_ONCE(*timestamp); + clock_gettime(CLOCK_MONOTONIC, &t_1); + c_1 += READ_ONCE(*timestamp); + + wakeref_put(fw); + + return (c_1 - c_0) / (2 * elapsed(&t_0, &t_1)); +} + +struct keymap { + const char *key; + int (*fn)(yaml_document_t *, yaml_node_t *, struct state *); +}; + +static int set_device(yaml_document_t *doc, + yaml_node_t *node, + struct state *st) +{ + assert(node->type == YAML_SCALAR_NODE); + st->device = node->data.scalar.value; + return 0; +} + +static int set_calibration(yaml_document_t *doc, + yaml_node_t *node, + struct state *st) +{ + return parse_calibration(doc, node, &st->calibration); +} + +static uint64_t node_to_u64(yaml_node_t *node) +{ + assert(node->type == YAML_SCALAR_NODE); + return strtoull((const char *)node->data.scalar.value, NULL, 0); +} + +static int32_t node_to_s32(yaml_node_t *node) +{ + assert(node->type == YAML_SCALAR_NODE); + return strtol((const char *)node->data.scalar.value, NULL, 0); +} + +static int add_probe(yaml_document_t *doc, + yaml_node_t *node, + struct state *st) +{ + struct probe_thread *probe; + + probe = calloc(1, sizeof(*probe)); + if (!probe) + return -ENOMEM; + + switch (node->type) { + default: + case YAML_SEQUENCE_NODE: + return -1; + + case YAML_SCALAR_NODE: + case YAML_NO_NODE: + break; + + case YAML_MAPPING_NODE: + for (yaml_node_pair_t *it = node->data.mapping.pairs.start; + it < node->data.mapping.pairs.top; + it++) { + yaml_node_t *key, *value; + + key = yaml_document_get_node(doc, it->key); + value = yaml_document_get_node(doc, it->value); + + if (!strcmp(key->data.scalar.value, "priority")) { + probe->priority = node_to_s32(value); + } else { + printf("Unknown probe field: %s, value %s\n", + key->data.scalar.value, + value->data.scalar.value); + return -ENOENT; + } + } + break; + } + + probe->next = st->probes; + st->probes = probe; + + return 0; +} + +static int set_flip(yaml_document_t *doc, + yaml_node_t *node, + struct state *st) +{ + struct flip_thread *flip; + + if (st->flip) + return -EBUSY; + + flip = calloc(1, sizeof(*flip)); + if (!flip) + return -ENOMEM; + + pthread_mutex_init(&flip->lock, NULL); + pthread_cond_init(&flip->cond, NULL); + + switch (node->type) { + default: + case YAML_SEQUENCE_NODE: + return -1; + + case YAML_SCALAR_NODE: + case YAML_NO_NODE: + break; + + case YAML_MAPPING_NODE: + for (yaml_node_pair_t *it = node->data.mapping.pairs.start; + it < node->data.mapping.pairs.top; + it++) { + yaml_node_t *key, *value; + + key = yaml_document_get_node(doc, it->key); + value = yaml_document_get_node(doc, it->value); + + if (!strcmp(key->data.scalar.value, "priority")) { + flip->priority = node_to_s32(value); + } else if (!strcmp(key->data.scalar.value, "duration")) { + flip->duration = node_to_u64(value); + } else { + printf("Unknown flip field: %s, value %s\n", + key->data.scalar.value, + value->data.scalar.value); + return -ENOENT; + } + } + break; + } + + st->flip = flip; + if (flip->duration > st->max_duration) + st->max_duration = flip->duration; + + return 0; +} + +static int add_clients(yaml_document_t *doc, + yaml_node_t *node, + struct state *st) +{ + unsigned long count = 1; + uint64_t duration = 0; + unsigned int vsync = 0; + int priority = 0; + + switch (node->type) { + default: + case YAML_SEQUENCE_NODE: + for (yaml_node_item_t *it = node->data.sequence.items.start; + it < node->data.sequence.items.top; + it++) + add_clients(doc, yaml_document_get_node(doc, *it), st); + return 0; + + case YAML_SCALAR_NODE: + case YAML_NO_NODE: + return 0; + + case YAML_MAPPING_NODE: + for (yaml_node_pair_t *it = node->data.mapping.pairs.start; + it < node->data.mapping.pairs.top; + it++) { + yaml_node_t *key, *value; + + key = yaml_document_get_node(doc, it->key); + value = yaml_document_get_node(doc, it->value); + + if (!strcmp(key->data.scalar.value, "priority")) { + priority = node_to_s32(value); + } else if (!strcmp(key->data.scalar.value, "duration")) { + duration = node_to_u64(value); + } else if (!strcmp(key->data.scalar.value, "count")) { + count = node_to_u64(value); + } else if (!strcmp(key->data.scalar.value, "vsync")) { + vsync = node_to_u64(value); + } else { + printf("Unknown client field: %s, value %s\n", + key->data.scalar.value, + value->data.scalar.value); + return -ENOENT; + } + } + break; + } + + for (unsigned long n = 0; n < count; n++) { + struct client_thread *client; + + client = calloc(1, sizeof(*client)); + if (!client) + return -ENOMEM; + + client->duration = duration; + client->priority = priority; + client->vsync = vsync; + + client->next = st->clients; + st->clients = client; + client->id = st->n_clients++; + } + + if (duration > st->max_duration) + st->max_duration = duration; + + return 0; +} + +static int parse_config(yaml_document_t *doc, struct state *st) +{ + static const struct keymap keymap[] = { + { "calibration", set_calibration }, + { "clients", add_clients }, + { "flip", set_flip }, + { "device", set_device }, + { "probe", add_probe }, + }; + yaml_node_t *node = yaml_document_get_root_node(doc); + + if (!node) + return 0; + + if (node->type != YAML_MAPPING_NODE) + return -1; + + for (yaml_node_pair_t *it = node->data.mapping.pairs.start; + it < node->data.mapping.pairs.top; it++) { + yaml_node_t *key = yaml_document_get_node(doc, it->key); + yaml_node_t *value = yaml_document_get_node(doc, it->value); + for (int n = 0; n < ARRAY_SIZE(keymap); n++) { + const struct keymap *k = &keymap[n]; + + if (strcmp(k->key, key->data.scalar.value)) + continue; + + k->fn(doc, value, st); + break; + } + } + + return 0; +} + +static int execute(struct state *st) +{ + unsigned long size; + unsigned long clk_freq; + uint32_t work; + void *mmio; + int i915; + + i915 = open(st->device, O_RDWR); + if (i915 < 0) + return 77; + + if (st->calibration.bytes == 0) + st->calibration = calibrate_nops(i915, 1000, 1); + + size = calibrated_batch_size(&st->calibration, st->max_duration); + size = size ? ALIGN(size, 4096) : 4096; + work = calibration_batch(i915, size); + + mmio = ioremap(i915); + if (!mmio) { + fprintf(stderr, "No mmio :(\n"); + return 77; + } + clk_freq = measure_clk_freq(mmio); + + if (st->flip) + start_flip_thread(st->flip, i915, st->n_clients, + work, size, &st->calibration); + + for (struct probe_thread *p = st->probes; p; p = p->next) + start_probe_thread(p, i915, mmio, clk_freq); + + for (struct client_thread *c = st->clients; c; c = c->next) + start_client_thread(c, i915, st->flip, + work, size, &st->calibration); + + pause(); + return 0; +} + +int rrul(int config, int results) +{ + struct state st = { .device = "/dev/dri/card0" }; + yaml_document_t doc; + + if (yaml_load_document(config, &doc)) + return EXIT_FAILURE; + + if (parse_config(&doc, &st)) + return EXIT_FAILURE; + + return execute(&st); +} diff --git a/benchmarks/rrul.yaml b/benchmarks/rrul.yaml new file mode 100644 index 00000000..ae96a98a --- /dev/null +++ b/benchmarks/rrul.yaml @@ -0,0 +1,17 @@ +test: rrul +config: + device: /dev/dri/card0 + calibration: {duration: 1000, bytes: 704878} + probe: + clients: + - duration: 2000 # microseconds, single background task + - duration: 200 # 5000fps in microseconds + vsync: 3 # triple buffered + count: 64 + - duration: 200 + vsync: 1 # async flips + flip: + duration: 250 # 400fps in microseconds (approx. fullscreen composite) +#results: +# - machine: +# date: diff --git a/benchmarks/yaml_utils.c b/benchmarks/yaml_utils.c new file mode 100644 index 00000000..a1a0a0d4 --- /dev/null +++ b/benchmarks/yaml_utils.c @@ -0,0 +1,113 @@ +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <unistd.h> + +#include "yaml_utils.h" + +void yaml_print_parser_error(yaml_parser_t *parser, FILE *stream) +{ + switch (parser->error) { + case YAML_MEMORY_ERROR: + fprintf(stderr, "Memory error: Not enough memory for parsing\n"); + break; + + case YAML_READER_ERROR: + if (parser->problem_value != -1) { + fprintf(stderr, "Reader error: %s: #%X at %zd\n", parser->problem, + parser->problem_value, parser->problem_offset); + } else { + fprintf(stderr, "Reader error: %s at %zd\n", parser->problem, + parser->problem_offset); + } + break; + + case YAML_SCANNER_ERROR: + if (parser->context) { + fprintf(stderr, "Scanner error: %s at line %lu, column %lu\n" + "%s at line %lu, column %lu\n", parser->context, + parser->context_mark.line+1, parser->context_mark.column+1, + parser->problem, parser->problem_mark.line+1, + parser->problem_mark.column+1); + } else { + fprintf(stderr, "Scanner error: %s at line %lu, column %lu\n", + parser->problem, parser->problem_mark.line+1, + parser->problem_mark.column+1); + } + break; + + case YAML_PARSER_ERROR: + if (parser->context) { + fprintf(stderr, "Parser error: %s at line %lu, column %lu\n" + "%s at line %lu, column %lu\n", parser->context, + parser->context_mark.line+1, parser->context_mark.column+1, + parser->problem, parser->problem_mark.line+1, + parser->problem_mark.column+1); + } else { + fprintf(stderr, "Parser error: %s at line %lu, column %lu\n", + parser->problem, parser->problem_mark.line+1, + parser->problem_mark.column+1); + } + break; + + default: + /* Couldn't happen. */ + fprintf(stderr, "Internal error\n"); + break; + } +} + +int yaml_read_fd(void *data, unsigned char *buffer, size_t size, size_t *out) +{ + int fd = (intptr_t)data; + ssize_t ret; + + ret = read(fd, buffer, size); + if (ret < 0) + return 0; + + *out = ret; + return 1; +} + +int yaml_write_fd(void *data, unsigned char *buffer, size_t size) +{ + int fd = (intptr_t)data; + size_t total = 0; + ssize_t ret; + + do { + ret = write(fd, buffer + total, size - total); + if (ret < 0) + ret = -errno; + if (ret == -EINTR || ret == -EAGAIN) + continue; + if (ret <= 0) + return 0; + + total += ret; + } while (total != size); + + return 1; +} + +int yaml_load_document(int fd, yaml_document_t *doc) +{ + yaml_parser_t parser; + int err = 0; + + if (!yaml_parser_initialize(&parser)) { + fprintf(stderr, "Failed to initialize YAML parser\n"); + return -1; + } + + yaml_parser_set_input(&parser, yaml_read_fd, (void *)(intptr_t)fd); + + if (!yaml_parser_load(&parser, doc)) { + yaml_print_parser_error(&parser, stderr); + err = -1; + } + + yaml_parser_delete(&parser); + return err; +} diff --git a/benchmarks/yaml_utils.h b/benchmarks/yaml_utils.h new file mode 100644 index 00000000..19d0be81 --- /dev/null +++ b/benchmarks/yaml_utils.h @@ -0,0 +1,14 @@ +#ifndef YAML_UTILS_H +#define YAML_UTILS_H + +#include <stdio.h> +#include <yaml.h> + +void yaml_print_parser_error(yaml_parser_t *parser, FILE *stream); + +int yaml_read_fd(void *data, unsigned char *buffer, size_t size, size_t *out); +int yaml_write_fd(void *data, unsigned char *buffer, size_t size); + +int yaml_load_document(int fd, yaml_document_t *doc); + +#endif /* YAML_UTILS_H */ diff --git a/configure.ac b/configure.ac index c5ee78bb..88da8eed 100644 --- a/configure.ac +++ b/configure.ac @@ -126,6 +126,7 @@ PKG_CHECK_MODULES(KMOD, [libkmod]) PKG_CHECK_MODULES(PROCPS, [libprocps]) PKG_CHECK_MODULES(LIBUNWIND, [libunwind]) PKG_CHECK_MODULES(VALGRIND, [valgrind], [have_valgrind=yes], [have_valgrind=no]) +PKG_CHECK_MODULES(YAML, [yaml-0.1]) if test x$have_valgrind = xyes; then AC_DEFINE(HAVE_VALGRIND, 1, [Enable valgrind annotation support.]) diff --git a/lib/i915/gem_context.c b/lib/i915/gem_context.c index 02cf2ccf..afba5075 100644 --- a/lib/i915/gem_context.c +++ b/lib/i915/gem_context.c @@ -234,8 +234,6 @@ void gem_context_require_bannable(int fd) igt_require(has_ban_period || has_bannable); } -#define DRM_I915_CONTEXT_PARAM_PRIORITY 0x6 - /** * __gem_context_set_priority: * @fd: open i915 drm file descriptor @@ -255,7 +253,7 @@ int __gem_context_set_priority(int fd, uint32_t ctx_id, int prio) memset(&p, 0, sizeof(p)); p.ctx_id = ctx_id; p.size = 0; - p.param = DRM_I915_CONTEXT_PARAM_PRIORITY; + p.param = I915_CONTEXT_PARAM_PRIORITY; p.value = prio; return __gem_context_set_param(fd, &p); |