* [RFC v2 i-g-t] Auto-tuned dummyload + recursive batch
@ 2016-10-28 15:47 Abdiel Janulgue
2016-10-28 15:47 ` [PATCH 1/3] lib: add igt_dummyload Abdiel Janulgue
` (2 more replies)
0 siblings, 3 replies; 11+ messages in thread
From: Abdiel Janulgue @ 2016-10-28 15:47 UTC (permalink / raw)
To: intel-gfx
A lot of igt testcases need some GPU workload to make sure a race
window is big enough. Unfortunately having a fixed amount of
workload leads to spurious test failures or overtly long runtimes
on some fast/slow platforms. This library contains functionality
to submit GPU workloads that should consume exactly a specific
amount of time.
v2: Add recursive batch feature from Chris and use in gem_wait and
kms_flip. I've retained the previous auto-tuned dummy load
functions. Let me know if we need to drop those.
Abdiel Janulgue (3):
lib: add igt_dummyload
igt/gem_wait: Use new igt_spin_batch
igt/kms_flip: Use new igt_spin_batch
lib/Makefile.sources | 2 +
lib/igt.h | 1 +
lib/igt_dummyload.c | 613 +++++++++++++++++++++++++++
lib/igt_dummyload.h | 77 ++++
tests/gem_wait.c | 125 +-----
tests/kms_flip.c | 4 +-
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 1/3] lib: add igt_dummyload 2016-10-28 15:47 [RFC v2 i-g-t] Auto-tuned dummyload + recursive batch Abdiel Janulgue @ 2016-10-28 15:47 ` Abdiel Janulgue 2016-10-28 15:47 ` [PATCH 2/3] igt/gem_wait: Use new igt_spin_batch Abdiel Janulgue 2016-10-28 15:47 ` [PATCH 3/3] igt/kms_flip: " Abdiel Janulgue 2 siblings, 0 replies; 11+ messages in thread From: Abdiel Janulgue @ 2016-10-28 15:47 UTC (permalink / raw) To: intel-gfx; +Cc: Daniel Vetter Generalized from auto-tuned GPU dummy workload in gem_wait and kms_flip v2 : Add recursive batch feature from Chris Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com> --- lib/Makefile.sources | 2 + lib/igt.h | 1 + lib/igt_dummyload.c | 613 +++++++++++++++++++++++++++++++++++++++++++++++++++ lib/igt_dummyload.h | 77 +++++++ 4 files changed, 693 insertions(+) create mode 100644 lib/igt_dummyload.c create mode 100644 lib/igt_dummyload.h diff --git a/lib/Makefile.sources b/lib/Makefile.sources index e8e277b..7fc5ec2 100644 --- a/lib/Makefile.sources +++ b/lib/Makefile.sources @@ -75,6 +75,8 @@ lib_source_list = \ igt_draw.h \ igt_pm.c \ igt_pm.h \ + igt_dummyload.c \ + igt_dummyload.h \ uwildmat/uwildmat.h \ uwildmat/uwildmat.c \ $(NULL) diff --git a/lib/igt.h b/lib/igt.h index d751f24..a0028d5 100644 --- a/lib/igt.h +++ b/lib/igt.h @@ -32,6 +32,7 @@ #include "igt_core.h" #include "igt_debugfs.h" #include "igt_draw.h" +#include "igt_dummyload.h" #include "igt_fb.h" #include "igt_gt.h" #include "igt_kms.h" diff --git a/lib/igt_dummyload.c b/lib/igt_dummyload.c new file mode 100644 index 0000000..f7a64b7 --- /dev/null +++ b/lib/igt_dummyload.c @@ -0,0 +1,613 @@ +/* + * Copyright © 2016 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. + * + */ + +#include "igt.h" +#include "igt_dummyload.h" +#include <time.h> +#include <signal.h> +#include <sys/syscall.h> + +/** + * SECTION:igt_dummyload + * @short_description: Library for submitting GPU workloads + * @title: Dummyload + * @include: igt.h + * + * A lot of igt testcases need some GPU workload to make sure a race window is + * big enough. Unfortunately having a fixed amount of workload leads to + * spurious test failures or overtly long runtimes on some fast/slow platforms. + * This library contains functionality to submit GPU workloads that should + * consume exactly a specific amount of time. + */ + +#define USEC_PER_SEC 1000000L +#define NSEC_PER_SEC 1000000000L + +#define gettid() syscall(__NR_gettid) +#define sigev_notify_thread_id _sigev_un._tid + +#define LOCAL_I915_EXEC_BSD_SHIFT (13) +#define LOCAL_I915_EXEC_BSD_MASK (3 << LOCAL_I915_EXEC_BSD_SHIFT) + +#define ENGINE_MASK (I915_EXEC_RING_MASK | LOCAL_I915_EXEC_BSD_MASK) + + +/* Internal data structures to avoid having to pass tons of parameters + * around. */ +struct dummy_info { + drm_intel_bufmgr *bufmgr; + struct intel_batchbuffer *batch; + int drm_fd; + uint32_t buf_handle; + uint32_t buf_stride; + uint32_t buf_tiling; + int fb_width; + int fb_height; +}; + +static void blit_copy(struct intel_batchbuffer *batch, + drm_intel_bo *dst, drm_intel_bo *src, + unsigned int width, unsigned int height, + unsigned int dst_pitch, unsigned int src_pitch) +{ + BLIT_COPY_BATCH_START(0); + OUT_BATCH((3 << 24) | /* 32 bits */ + (0xcc << 16) | /* copy ROP */ + dst_pitch); + OUT_BATCH(0 << 16 | 0); + OUT_BATCH(height << 16 | width); + OUT_RELOC_FENCED(dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(0 << 16 | 0); + OUT_BATCH(src_pitch); + OUT_RELOC_FENCED(src, I915_GEM_DOMAIN_RENDER, 0, 0); + ADVANCE_BATCH(); + + if (batch->gen >= 6) { + BEGIN_BATCH(3, 0); + OUT_BATCH(XY_SETUP_CLIP_BLT_CMD); + OUT_BATCH(0); + OUT_BATCH(0); + ADVANCE_BATCH(); + } +} + +static void blit_fill(struct intel_batchbuffer *batch, drm_intel_bo *dst, + unsigned int width, unsigned int height) +{ + COLOR_BLIT_COPY_BATCH_START(COLOR_BLT_WRITE_ALPHA | + XY_COLOR_BLT_WRITE_RGB); + OUT_BATCH((3 << 24) | /* 32 Bit Color */ + (0xF0 << 16) | /* Raster OP copy background register */ + 0); /* Dest pitch is 0 */ + OUT_BATCH(0); + OUT_BATCH(width << 16 | + height); + OUT_RELOC_FENCED(dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(rand()); /* random pattern */ + ADVANCE_BATCH(); +} + +static int emit_dummy_load_blitcopy(struct dummy_info *d, int limit, int timeout) +{ + int i, ret = 0; + drm_intel_bo *src_bo, *dst_bo, *fb_bo; + struct intel_batchbuffer *batch = d->batch; + drm_intel_bufmgr *bufmgr = d->bufmgr; + + igt_require(bufmgr); + + src_bo = drm_intel_bo_alloc(bufmgr, "dummy_bo", 2048*2048*4, 4096); + igt_assert(src_bo); + + dst_bo = drm_intel_bo_alloc(bufmgr, "dummy_bo", 2048*2048*4, 4096); + igt_assert(dst_bo); + + fb_bo = gem_handle_to_libdrm_bo(bufmgr, d->drm_fd, "imported", + d->buf_handle); + igt_assert(fb_bo); + + for (i = 0; i < limit; i++) { + blit_copy(batch, dst_bo, src_bo, + 2048, 2048, + 2048*4, 2048*4); + igt_swap(src_bo, dst_bo); + } + blit_copy(batch, fb_bo, src_bo, + min(d->fb_width, 2048), min(d->fb_height, 2048), + d->buf_stride, 2048*4); + + intel_batchbuffer_flush(batch); + + if (timeout > 0) + ret = drm_intel_gem_bo_wait(fb_bo, timeout * NSEC_PER_SEC); + drm_intel_bo_unreference(src_bo); + drm_intel_bo_unreference(dst_bo); + drm_intel_bo_unreference(fb_bo); + + return ret; +} + +static int emit_dummy_load_blitfill(struct dummy_info *d, int limit, int timeout) +{ + int i, ret = 0; + struct intel_batchbuffer *batch = d->batch; + drm_intel_bufmgr *bufmgr = d->bufmgr; + drm_intel_bo *dst_bo = gem_handle_to_libdrm_bo(bufmgr, d->drm_fd, "", + d->buf_handle); + igt_require(bufmgr); + igt_assert(dst_bo); + + for (i = 0; i < limit; i++) { + blit_fill(batch, dst_bo, + min(d->fb_width, dst_bo->size/2), + min(d->fb_height, dst_bo->size/2)); + } + intel_batchbuffer_flush(batch); + + if (timeout > 0) + ret = drm_intel_gem_bo_wait(dst_bo, timeout * NSEC_PER_SEC); + drm_intel_bo_unreference(dst_bo); + + return ret; +} + +static int emit_dummy_load_rendercopy(struct dummy_info *d, int limit, int timeout) +{ + struct intel_batchbuffer *batch = d->batch; + drm_intel_bufmgr *bufmgr = d->bufmgr; + static uint32_t devid = 0; + igt_render_copyfunc_t copyfunc; + struct igt_buf sb[3], *src, *dst, *fb; + int i, ret = 0; + + igt_require(bufmgr); + + if (!devid) + devid = intel_get_drm_devid(d->drm_fd); + copyfunc = igt_get_render_copyfunc(devid); + if (copyfunc == NULL) + return emit_dummy_load_blitfill(d, limit, timeout); + + sb[0].bo = drm_intel_bo_alloc(bufmgr, "dummy_bo", 2048*2048*4, 4096); + igt_assert(sb[0].bo); + sb[0].size = sb[0].bo->size; + sb[0].tiling = I915_TILING_NONE; + sb[0].data = NULL; + sb[0].num_tiles = sb[0].bo->size; + sb[0].stride = 4 * 2048; + + sb[1].bo = drm_intel_bo_alloc(bufmgr, "dummy_bo", 2048*2048*4, 4096); + igt_assert(sb[1].bo); + sb[1].size = sb[1].bo->size; + sb[1].tiling = I915_TILING_NONE; + sb[1].data = NULL; + sb[1].num_tiles = sb[1].bo->size; + sb[1].stride = 4 * 2048; + + sb[2].bo = gem_handle_to_libdrm_bo(bufmgr, d->drm_fd, "imported", + d->buf_handle); + igt_assert(sb[2].bo); + sb[2].size = sb[2].bo->size; + sb[2].tiling = d->buf_tiling; + sb[2].data = NULL; + sb[2].num_tiles = sb[2].bo->size; + sb[2].stride = d->buf_stride; + + src = &sb[0]; + dst = &sb[1]; + fb = &sb[2]; + + for (i = 0; i < limit; i++) { + copyfunc(batch, NULL, + src, 0, 0, + 2048, 2048, + dst, 0, 0); + + igt_swap(src, dst); + } + copyfunc(batch, NULL, + src, 0, 0, + min(d->fb_width, 2048), min(d->fb_height, 2048), + fb, 0, 0); + intel_batchbuffer_flush(batch); + + if (timeout > 0) + ret = drm_intel_gem_bo_wait(fb->bo, timeout * NSEC_PER_SEC); + drm_intel_bo_unreference(sb[0].bo); + drm_intel_bo_unreference(sb[1].bo); + drm_intel_bo_unreference(sb[2].bo); + + return ret; +} + +static unsigned long gettime_us(void) +{ + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + + return ts.tv_sec * 1000000 + ts.tv_nsec / 1000; +} + +static int calibrate_dummy_load(struct dummy_info *d, + const char *ring_name, + int enough_work_in_seconds, + int (*emit)(struct dummy_info *d, int limit, int timeout)) +{ + unsigned long start; + int ops = 1; + + do { + unsigned long diff; + int ret; + start = gettime_us(); + ret = emit(d, ops, 10); + diff = gettime_us() - start; + + if (ret || diff / USEC_PER_SEC > enough_work_in_seconds) + break; + ops += ops; + } while (ops < 100000); + + igt_debug("%s dummy load calibrated: %d operations / second\n", + ring_name, ops); + + return ops; +} + +static void igt_dummy_load_blitcopy(struct dummy_info* d, int seconds) +{ + static int ops_per_sec = 0; + + if (ops_per_sec == 0) + ops_per_sec = calibrate_dummy_load(d, "bcs", seconds, + emit_dummy_load_blitcopy); + + emit_dummy_load_blitcopy(d, seconds * ops_per_sec, 0); +} + +static void igt_dummy_load_blitfill(struct dummy_info* d, int seconds) +{ + static int ops_per_sec = 0; + + if (ops_per_sec == 0) + ops_per_sec = calibrate_dummy_load(d, "bcs", seconds, + emit_dummy_load_blitfill); + + emit_dummy_load_blitfill(d, seconds * ops_per_sec, 0); +} + +static void igt_dummy_load_rendercopy(struct dummy_info* d, int seconds) +{ + static int ops_per_sec = 0; + + if (ops_per_sec == 0) + ops_per_sec = calibrate_dummy_load(d, "rcs", seconds, + emit_dummy_load_rendercopy); + + emit_dummy_load_rendercopy(d, seconds * ops_per_sec, 0); +} + +/** + * igt_calibrate_dummy_load: + * @bufmgr: the libdrm bufmgr + * @batch: the batchbuffer + * @drm_fd: the DRM file descriptor + * @buf_handle: handle of the destination buffer where the operation is applied. + * For IGT_DUMMY_BLIT_COPY and IGT_DUMMY_RENDER_COPY this + * is the destination buffer where final results are copied into + * @buf_stride: the stride of the buffer, ignored by IGT_DUMMY_BLIT_FILL + * @fb_width: width of the rectangle + * @fb_height: height of the rectangle + * @enough_work_in_seconds: time it takes to execute a GPU workload + * @method: Type of GPU workload + * + * This function returns the amount of operations a GPU workload executes in + * a specific amount of time. + */ +int igt_calibrate_dummy_load(drm_intel_bufmgr *bufmgr, + struct intel_batchbuffer *batch, + int drm_fd, + uint32_t buf_handle, + uint32_t buf_stride, + int fb_width, + int fb_height, + int enough_work_in_seconds, + enum igt_dummy_load_method method) +{ + struct dummy_info dummy_info = { + .bufmgr = bufmgr, + .batch = batch, + .drm_fd = drm_fd, + .buf_handle = buf_handle, + .buf_stride = buf_stride, + .fb_width = fb_width, + .fb_height = fb_height, + }; + + switch (method) { + case IGT_DUMMY_RENDER_COPY: + return calibrate_dummy_load(&dummy_info, "rcs", + enough_work_in_seconds, + emit_dummy_load_rendercopy); + case IGT_DUMMY_BLIT_COPY: + return calibrate_dummy_load(&dummy_info, "bcs", + enough_work_in_seconds, + emit_dummy_load_blitcopy); + case IGT_DUMMY_BLIT_FILL: + return calibrate_dummy_load(&dummy_info, "bcs", + enough_work_in_seconds, + emit_dummy_load_blitfill); + default: + igt_assert(false); + } +} + +/** + * igt_emit_dummy_load: + * @bufmgr: the libdrm bufmgr + * @batch: the batchbuffer + * @drm_fd: the DRM file descriptor + * @buf_handle: handle of the destination buffer where the operation is applied. + * For IGT_DUMMY_BLIT_COPY and IGT_DUMMY_RENDER_COPY this + * is the destination buffer where final results are copied into + * @buf_stride: the stride of the buffer, ignored by IGT_DUMMY_BLIT_FILL + * @fb_width: width of the rectangle + * @fb_height: height of the rectangle + * @iterations: manually specify the amount of operations that the dummy load + * executes. If less than 1, automatically determine the amount of + * iterations it takes to execute @enough_work_in_seconds + * seconds of GPU workload + * @enough_work_in_seconds: time it takes to execute a GPU workload. Ignored when + * auto-calibration is disabled (@iterations >= 1) + * @method: Type of GPU workload + * + * This functions submits a dummy workload to the GPU optionally auto-tuning it + * so the workload consumes a specific amount of time. + */ +void igt_emit_dummy_load(drm_intel_bufmgr *bufmgr, + struct intel_batchbuffer *batch, + int drm_fd, + uint32_t buf_handle, + uint32_t buf_stride, + int fb_width, + int fb_height, + int iterations, + int enough_work_in_seconds, + enum igt_dummy_load_method method) +{ + struct dummy_info dummy_info = { + .bufmgr = bufmgr, + .batch = batch, + .drm_fd = drm_fd, + .buf_handle = buf_handle, + .buf_stride = buf_stride, + .fb_width = fb_width, + .fb_height = fb_height, + }; + + switch (method) { + case IGT_DUMMY_RENDER_COPY: + iterations > 0 ? emit_dummy_load_rendercopy(&dummy_info, + iterations, 0): + igt_dummy_load_rendercopy(&dummy_info, enough_work_in_seconds); + break; + case IGT_DUMMY_BLIT_COPY: + iterations > 0 ? emit_dummy_load_blitcopy(&dummy_info, + iterations, 0): + igt_dummy_load_blitcopy(&dummy_info, enough_work_in_seconds); + break; + case IGT_DUMMY_BLIT_FILL: + iterations > 0 ? emit_dummy_load_blitfill(&dummy_info, + iterations, 0): + igt_dummy_load_blitfill(&dummy_info, enough_work_in_seconds); + break; + default: + igt_assert(false); + break; + } +} + +static uint32_t *batch; + +static uint32_t emit_recursive_batch(int fd, int engine) +{ + const int gen = intel_gen(intel_get_drm_devid(fd)); + struct drm_i915_gem_exec_object2 obj; + struct drm_i915_gem_relocation_entry reloc; + struct drm_i915_gem_execbuffer2 execbuf; + unsigned engines[16]; + unsigned nengine; + int i; + + nengine = 0; + if (engine < 0) { + for_each_engine(fd, engine) + if (engine) + engines[nengine++] = engine; + } else { + igt_require(gem_has_ring(fd, engine)); + engines[nengine++] = engine; + } + igt_require(nengine); + + memset(&execbuf, 0, sizeof(execbuf)); + execbuf.buffers_ptr = (uintptr_t)&obj; + execbuf.buffer_count = 1; + + memset(&obj, 0, sizeof(obj)); + obj.handle = gem_create(fd, 4096); + + obj.relocs_ptr = (uintptr_t)&reloc; + obj.relocation_count = 1; + memset(&reloc, 0, sizeof(reloc)); + + batch = gem_mmap__gtt(fd, obj.handle, 4096, PROT_WRITE); + gem_set_domain(fd, obj.handle, + I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); + + reloc.target_handle = obj.handle; /* recurse */ + reloc.presumed_offset = 0; + reloc.offset = sizeof(uint32_t); + reloc.delta = 0; + reloc.read_domains = I915_GEM_DOMAIN_COMMAND; + reloc.write_domain = 0; + + i = 0; + batch[i] = MI_BATCH_BUFFER_START; + if (gen >= 8) { + batch[i] |= 1 << 8 | 1; + batch[++i] = 0; + batch[++i] = 0; + } else if (gen >= 6) { + batch[i] |= 1 << 8; + batch[++i] = 0; + } else { + batch[i] |= 2 << 6; + batch[++i] = 0; + if (gen < 4) { + batch[i] |= 1; + reloc.delta = 1; + } + } + + for (i = 0; i < nengine; i++) { + execbuf.flags &= ~ENGINE_MASK; + execbuf.flags = engines[i]; + gem_execbuf(fd, &execbuf); + } + + return obj.handle; +} + +static void sigiter(int sig, siginfo_t *info, void *arg) +{ + *batch = MI_BATCH_BUFFER_END; + __sync_synchronize(); +} + +static timer_t setup_batch_exit_timer(int seconds) +{ + timer_t timer; + struct sigevent sev; + struct sigaction act; + struct itimerspec its; + + memset(&sev, 0, sizeof(sev)); + sev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID; + sev.sigev_notify_thread_id = gettid(); + sev.sigev_signo = SIGRTMIN + 1; + igt_assert(timer_create(CLOCK_MONOTONIC, &sev, &timer) == 0); + igt_assert(timer > 0); + + memset(&act, 0, sizeof(act)); + act.sa_sigaction = sigiter; + act.sa_flags = SA_SIGINFO; + igt_assert(sigaction(SIGRTMIN + 1, &act, NULL) == 0); + + memset(&its, 0, sizeof(its)); + its.it_value.tv_nsec = 0; + its.it_value.tv_sec = seconds; + igt_assert(timer_settime(timer, 0, &its, NULL) == 0); + + return timer; +} + +/** + * igt_spin_batch: + * @fd: open i915 drm file descriptor + * @seconds: amount of time in seconds the batch executes after terminating. + * If value is less than 0, execute batch forever. + * @engine: Ring to execute batch OR'd with execbuf flags. If value is -1 + * execute on all available rings. + * + * Start a recursive batch on a ring that terminates after an exact amount + * of time has elapsed. Immediately returns a #igt_spin_t that contains the + * gem handle that can be waited upon. The returned structure must be passed to + * igt_post_spin_batch() for post-processing. + * + * Returns: + * Structure with helper internal state for igt_post_spin_batch(). + */ +igt_spin_t igt_spin_batch(int fd, int seconds, int engine) +{ + timer_t timer; + uint32_t handle = emit_recursive_batch(fd, engine); + int64_t wait_timeout = 0; + igt_assert_eq(gem_wait(fd, handle, &wait_timeout), -ETIME); + + if (seconds < 1) { + if (seconds == 0) { + *batch = MI_BATCH_BUFFER_END; + __sync_synchronize(); + return (igt_spin_t){ handle, batch, 0}; + } + return (igt_spin_t){ handle, batch, 0 }; + } + timer = setup_batch_exit_timer(seconds); + + return (igt_spin_t){ handle, batch, timer }; +} + +/** + * igt_post_spin_batch: + * @fd: open i915 drm file descriptor + * @arg: spin batch state from igt_spin_batch() + * + * This function does the necessary post-processing after starting a recursive + * batch with igt_spin_batch(). + */ +void igt_post_spin_batch(int fd, igt_spin_t arg) +{ + if (arg.handle == 0) + return; + + if (arg.timer > 0) + timer_delete(arg.timer); + + gem_close(fd, arg.handle); + munmap(arg.batch, 4096); +} + + +/** + * igt_spin_batch_wait: + * @fd: open i915 drm file descriptor + * @seconds: amount of time in seconds the batch executes after terminating. + * If value is less than 0, execute batch forever. + * @engine: Ring to execute batch OR'd with execbuf flags. If value is less + * than 0, execute on all available rings. + * + * This is similar to igt_spin_batch(), but waits on the recursive batch to finish + * instead of returning right away. The function also does the necessary + * post-processing automatically if set to timeout. + */ +void igt_spin_batch_wait(int fd, int seconds, int engine) +{ + igt_spin_t spin = igt_spin_batch(fd, seconds, engine); + int64_t wait_timeout = (seconds + 0.5) * NSEC_PER_SEC; + igt_assert_eq(gem_wait(fd, spin.handle, &wait_timeout), 0); + + igt_post_spin_batch(fd, spin); +} diff --git a/lib/igt_dummyload.h b/lib/igt_dummyload.h new file mode 100644 index 0000000..4b4d2b6 --- /dev/null +++ b/lib/igt_dummyload.h @@ -0,0 +1,77 @@ +/* + * Copyright © 2016 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. + * + */ + +#ifndef __IGT_DUMMYLOAD_H__ +#define __IGT_DUMMYLOAD_H__ + +/** + * igt_dummy_load_method: + * @IGT_DUMMY_BLIT_FILL: Use blitter engine to fill a buffer with random color + * @IGT_DUMMY_BLIT_COPY: Use blitter engine to copy between buffers + * @IGT_DUMMY_RENDER_COPY: Use render engine to copy between buffers + * + * Method to generate a GPU dummy load + */ +enum igt_dummy_load_method { + IGT_DUMMY_BLIT_FILL, + IGT_DUMMY_BLIT_COPY, + IGT_DUMMY_RENDER_COPY, +}; + +int igt_calibrate_dummy_load(drm_intel_bufmgr *bufmgr, + struct intel_batchbuffer *batch, + int drm_fd, + uint32_t buf_handle, + uint32_t buf_stride, + int fb_width, + int fb_height, + int enough_work_in_seconds, + enum igt_dummy_load_method method); + +void igt_emit_dummy_load(drm_intel_bufmgr *bufmgr, + struct intel_batchbuffer *batch, + int drm_fd, + uint32_t buf_handle, + uint32_t buf_stride, + int fb_width, + int fb_height, + int iterations, + int enough_work_in_seconds, + enum igt_dummy_load_method method); + +typedef struct igt_spin { + unsigned handle; + uint32_t *batch; + timer_t timer; +} igt_spin_t; + + +igt_spin_t igt_spin_batch(int fd, int seconds, int engine); + +void igt_post_spin_batch(int fd, igt_spin_t arg); + +void igt_spin_batch_wait(int fd, int seconds, int engine); + + +#endif /* __IGT_DUMMYLOAD_H__ */ -- 2.7.0 _______________________________________________ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 2/3] igt/gem_wait: Use new igt_spin_batch 2016-10-28 15:47 [RFC v2 i-g-t] Auto-tuned dummyload + recursive batch Abdiel Janulgue 2016-10-28 15:47 ` [PATCH 1/3] lib: add igt_dummyload Abdiel Janulgue @ 2016-10-28 15:47 ` Abdiel Janulgue 2016-10-28 15:47 ` [PATCH 3/3] igt/kms_flip: " Abdiel Janulgue 2 siblings, 0 replies; 11+ messages in thread From: Abdiel Janulgue @ 2016-10-28 15:47 UTC (permalink / raw) To: intel-gfx; +Cc: Daniel Vetter Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com> --- tests/gem_wait.c | 125 ++++--------------------------------------------------- 1 file changed, 7 insertions(+), 118 deletions(-) diff --git a/tests/gem_wait.c b/tests/gem_wait.c index b4127de..630058c 100644 --- a/tests/gem_wait.c +++ b/tests/gem_wait.c @@ -27,18 +27,6 @@ #include "igt.h" -#include <signal.h> -#include <time.h> -#include <sys/syscall.h> - -#define gettid() syscall(__NR_gettid) -#define sigev_notify_thread_id _sigev_un._tid - -#define LOCAL_I915_EXEC_BSD_SHIFT (13) -#define LOCAL_I915_EXEC_BSD_MASK (3 << LOCAL_I915_EXEC_BSD_SHIFT) - -#define ENGINE_MASK (I915_EXEC_RING_MASK | LOCAL_I915_EXEC_BSD_MASK) - static int __gem_wait(int fd, struct drm_i915_gem_wait *w) { int err; @@ -75,14 +63,6 @@ static void invalid_buf(int fd) igt_assert_eq(__gem_wait(fd, &wait), -ENOENT); } -static uint32_t *batch; - -static void sigiter(int sig, siginfo_t *info, void *arg) -{ - *batch = MI_BATCH_BUFFER_END; - __sync_synchronize(); -} - #define MSEC_PER_SEC (1000) #define USEC_PER_SEC (1000 * MSEC_PER_SEC) #define NSEC_PER_SEC (1000 * USEC_PER_SEC) @@ -91,113 +71,26 @@ static void sigiter(int sig, siginfo_t *info, void *arg) #define HANG 2 static void basic(int fd, unsigned engine, unsigned flags) { - const int gen = intel_gen(intel_get_drm_devid(fd)); - struct drm_i915_gem_exec_object2 obj; - struct drm_i915_gem_relocation_entry reloc; - struct drm_i915_gem_execbuffer2 execbuf; struct drm_i915_gem_wait wait; - unsigned engines[16]; - unsigned nengine; - int i, timeout; - - nengine = 0; - if (engine == -1) { - for_each_engine(fd, engine) - if (engine) engines[nengine++] = engine; - } else { - igt_require(gem_has_ring(fd, engine)); - engines[nengine++] = engine; - } - igt_require(nengine); - - memset(&execbuf, 0, sizeof(execbuf)); - execbuf.buffers_ptr = (uintptr_t)&obj; - execbuf.buffer_count = 1; - - memset(&obj, 0, sizeof(obj)); - obj.handle = gem_create(fd, 4096); - - obj.relocs_ptr = (uintptr_t)&reloc; - obj.relocation_count = 1; - memset(&reloc, 0, sizeof(reloc)); - - batch = gem_mmap__gtt(fd, obj.handle, 4096, PROT_WRITE); - gem_set_domain(fd, obj.handle, - I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); - - reloc.target_handle = obj.handle; /* recurse */ - reloc.presumed_offset = 0; - reloc.offset = sizeof(uint32_t); - reloc.delta = 0; - reloc.read_domains = I915_GEM_DOMAIN_COMMAND; - reloc.write_domain = 0; - - i = 0; - batch[i] = MI_BATCH_BUFFER_START; - if (gen >= 8) { - batch[i] |= 1 << 8 | 1; - batch[++i] = 0; - batch[++i] = 0; - } else if (gen >= 6) { - batch[i] |= 1 << 8; - batch[++i] = 0; - } else { - batch[i] |= 2 << 6; - batch[++i] = 0; - if (gen < 4) { - batch[i] |= 1; - reloc.delta = 1; - } - } - - for (i = 0; i < nengine; i++) { - execbuf.flags &= ~ENGINE_MASK; - execbuf.flags |= engines[i]; - gem_execbuf(fd, &execbuf); - } + int wait_s = (flags == 0) ? 1 : 0; + wait_s = ((flags & HANG) == 0) ? wait_s : -1; + igt_spin_t spin = igt_spin_batch(fd, wait_s, engine); + int timeout; memset(&wait, 0, sizeof(wait)); - wait.bo_handle = obj.handle; - igt_assert_eq(__gem_wait(fd, &wait), -ETIME); + wait.bo_handle = spin.handle; if (flags & BUSY) { struct timespec tv; timeout = 120; - if ((flags & HANG) == 0) { - *batch = MI_BATCH_BUFFER_END; - __sync_synchronize(); + if ((flags & HANG) == 0) timeout = 1; - } memset(&tv, 0, sizeof(tv)); while (__gem_wait(fd, &wait) == -ETIME) igt_assert(igt_seconds_elapsed(&tv) < timeout); } else { - timer_t timer; - - if ((flags & HANG) == 0) { - struct sigevent sev; - struct sigaction act; - struct itimerspec its; - - memset(&sev, 0, sizeof(sev)); - sev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID; - sev.sigev_notify_thread_id = gettid(); - sev.sigev_signo = SIGRTMIN + 1; - igt_assert(timer_create(CLOCK_MONOTONIC, &sev, &timer) == 0); - - memset(&act, 0, sizeof(act)); - act.sa_sigaction = sigiter; - act.sa_flags = SA_SIGINFO; - igt_assert(sigaction(SIGRTMIN + 1, &act, NULL) == 0); - - memset(&its, 0, sizeof(its)); - its.it_value.tv_nsec = 0; - its.it_value.tv_sec = 1; - igt_assert(timer_settime(timer, 0, &its, NULL) == 0); - } - wait.timeout_ns = NSEC_PER_SEC / 2; /* 0.5s */ igt_assert_eq(__gem_wait(fd, &wait), -ETIME); igt_assert_eq_s64(wait.timeout_ns, 0); @@ -215,13 +108,9 @@ static void basic(int fd, unsigned engine, unsigned flags) wait.timeout_ns = 0; igt_assert_eq(__gem_wait(fd, &wait), 0); igt_assert(wait.timeout_ns == 0); - - if ((flags & HANG) == 0) - timer_delete(timer); } - gem_close(fd, obj.handle); - munmap(batch, 4096); + igt_post_spin_batch(fd, spin); } igt_main -- 2.7.0 _______________________________________________ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 3/3] igt/kms_flip: Use new igt_spin_batch 2016-10-28 15:47 [RFC v2 i-g-t] Auto-tuned dummyload + recursive batch Abdiel Janulgue 2016-10-28 15:47 ` [PATCH 1/3] lib: add igt_dummyload Abdiel Janulgue 2016-10-28 15:47 ` [PATCH 2/3] igt/gem_wait: Use new igt_spin_batch Abdiel Janulgue @ 2016-10-28 15:47 ` Abdiel Janulgue 2016-10-28 16:02 ` Ville Syrjälä 2 siblings, 1 reply; 11+ messages in thread From: Abdiel Janulgue @ 2016-10-28 15:47 UTC (permalink / raw) To: intel-gfx; +Cc: Daniel Vetter Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com> --- tests/kms_flip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/kms_flip.c b/tests/kms_flip.c index 9829b35..13cb262 100644 --- a/tests/kms_flip.c +++ b/tests/kms_flip.c @@ -866,10 +866,10 @@ static unsigned int run_test_step(struct test_output *o) o->current_fb_id = !o->current_fb_id; if (o->flags & TEST_WITH_DUMMY_BCS) - emit_dummy_load__bcs(o, 1); + igt_spin_batch_wait(drm_fd, 1, I915_EXEC_BLT); if (o->flags & TEST_WITH_DUMMY_RCS) - emit_dummy_load__rcs(o, 1); + igt_spin_batch_wait(drm_fd, 1, I915_EXEC_RENDER); if (o->flags & TEST_FB_RECREATE) recreate_fb(o); -- 2.7.0 _______________________________________________ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 3/3] igt/kms_flip: Use new igt_spin_batch 2016-10-28 15:47 ` [PATCH 3/3] igt/kms_flip: " Abdiel Janulgue @ 2016-10-28 16:02 ` Ville Syrjälä 2016-10-31 6:43 ` Abdiel Janulgue 2016-11-03 9:40 ` [PATCH v3 1/3] lib: add igt_dummyload Abdiel Janulgue 0 siblings, 2 replies; 11+ messages in thread From: Ville Syrjälä @ 2016-10-28 16:02 UTC (permalink / raw) To: Abdiel Janulgue; +Cc: Daniel Vetter, intel-gfx On Fri, Oct 28, 2016 at 06:47:26PM +0300, Abdiel Janulgue wrote: > Cc: Chris Wilson <chris@chris-wilson.co.uk> > Cc: Daniel Vetter <daniel.vetter@ffwll.ch> > Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com> > --- > tests/kms_flip.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/tests/kms_flip.c b/tests/kms_flip.c > index 9829b35..13cb262 100644 > --- a/tests/kms_flip.c > +++ b/tests/kms_flip.c > @@ -866,10 +866,10 @@ static unsigned int run_test_step(struct test_output *o) > o->current_fb_id = !o->current_fb_id; > > if (o->flags & TEST_WITH_DUMMY_BCS) > - emit_dummy_load__bcs(o, 1); > + igt_spin_batch_wait(drm_fd, 1, I915_EXEC_BLT); > > if (o->flags & TEST_WITH_DUMMY_RCS) > - emit_dummy_load__rcs(o, 1); > + igt_spin_batch_wait(drm_fd, 1, I915_EXEC_RENDER); NAK That's not going to add the required dependency between the load and the bo used by the test. > > if (o->flags & TEST_FB_RECREATE) > recreate_fb(o); > -- > 2.7.0 > > _______________________________________________ > Intel-gfx mailing list > Intel-gfx@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/intel-gfx -- Ville Syrjälä Intel OTC _______________________________________________ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 3/3] igt/kms_flip: Use new igt_spin_batch 2016-10-28 16:02 ` Ville Syrjälä @ 2016-10-31 6:43 ` Abdiel Janulgue 2016-11-03 9:40 ` [PATCH v3 1/3] lib: add igt_dummyload Abdiel Janulgue 1 sibling, 0 replies; 11+ messages in thread From: Abdiel Janulgue @ 2016-10-31 6:43 UTC (permalink / raw) To: Ville Syrjälä; +Cc: Daniel Vetter, intel-gfx On 10/28/2016 07:02 PM, Ville Syrjälä wrote: > On Fri, Oct 28, 2016 at 06:47:26PM +0300, Abdiel Janulgue wrote: >> Cc: Chris Wilson <chris@chris-wilson.co.uk> >> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> >> Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com> >> --- >> tests/kms_flip.c | 4 ++-- >> 1 file changed, 2 insertions(+), 2 deletions(-) >> >> diff --git a/tests/kms_flip.c b/tests/kms_flip.c >> index 9829b35..13cb262 100644 >> --- a/tests/kms_flip.c >> +++ b/tests/kms_flip.c >> @@ -866,10 +866,10 @@ static unsigned int run_test_step(struct test_output *o) >> o->current_fb_id = !o->current_fb_id; >> >> if (o->flags & TEST_WITH_DUMMY_BCS) >> - emit_dummy_load__bcs(o, 1); >> + igt_spin_batch_wait(drm_fd, 1, I915_EXEC_BLT); >> >> if (o->flags & TEST_WITH_DUMMY_RCS) >> - emit_dummy_load__rcs(o, 1); >> + igt_spin_batch_wait(drm_fd, 1, I915_EXEC_RENDER); > > NAK That's not going to add the required dependency between the load > and the bo used by the test. Right. For these cases would it be more straightforward to stick to the auto-tuned rendercopy/blit load operations on the bo instead of inserting a recursive batch on these situations? Any ideas? >> >> if (o->flags & TEST_FB_RECREATE) >> recreate_fb(o); >> -- >> 2.7.0 >> >> _______________________________________________ >> Intel-gfx mailing list >> Intel-gfx@lists.freedesktop.org >> https://lists.freedesktop.org/mailman/listinfo/intel-gfx > _______________________________________________ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 1/3] lib: add igt_dummyload 2016-10-28 16:02 ` Ville Syrjälä 2016-10-31 6:43 ` Abdiel Janulgue @ 2016-11-03 9:40 ` Abdiel Janulgue 2016-11-03 9:40 ` [PATCH v3 2/3] igt/gem_wait: Use new igt_spin_batch Abdiel Janulgue ` (2 more replies) 1 sibling, 3 replies; 11+ messages in thread From: Abdiel Janulgue @ 2016-11-03 9:40 UTC (permalink / raw) To: intel-gfx; +Cc: Daniel Vetter A lot of igt testcases need some GPU workload to make sure a race window is big enough. Unfortunately having a fixed amount of workload leads to spurious test failures or overtly long runtimes on some fast/slow platforms. This library contains functionality to submit GPU workloads that should consume exactly a specific amount of time. v2 : Add recursive batch feature from Chris v3 : Drop auto-tuned stuff. Add bo dependecy to recursive batch by adding a dummy reloc to the bo as suggested by Ville. Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com> --- lib/Makefile.sources | 2 + lib/igt.h | 1 + lib/igt_dummyload.c | 274 +++++++++++++++++++++++++++++++++++++++++++++++++++ lib/igt_dummyload.h | 42 ++++++++ 4 files changed, 319 insertions(+) create mode 100644 lib/igt_dummyload.c create mode 100644 lib/igt_dummyload.h diff --git a/lib/Makefile.sources b/lib/Makefile.sources index e8e277b..7fc5ec2 100644 --- a/lib/Makefile.sources +++ b/lib/Makefile.sources @@ -75,6 +75,8 @@ lib_source_list = \ igt_draw.h \ igt_pm.c \ igt_pm.h \ + igt_dummyload.c \ + igt_dummyload.h \ uwildmat/uwildmat.h \ uwildmat/uwildmat.c \ $(NULL) diff --git a/lib/igt.h b/lib/igt.h index d751f24..a0028d5 100644 --- a/lib/igt.h +++ b/lib/igt.h @@ -32,6 +32,7 @@ #include "igt_core.h" #include "igt_debugfs.h" #include "igt_draw.h" +#include "igt_dummyload.h" #include "igt_fb.h" #include "igt_gt.h" #include "igt_kms.h" diff --git a/lib/igt_dummyload.c b/lib/igt_dummyload.c new file mode 100644 index 0000000..d37a30b --- /dev/null +++ b/lib/igt_dummyload.c @@ -0,0 +1,274 @@ +/* + * Copyright © 2016 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. + * + */ + +#include "igt.h" +#include "igt_dummyload.h" +#include <time.h> +#include <signal.h> +#include <sys/syscall.h> + +/** + * SECTION:igt_dummyload + * @short_description: Library for submitting GPU workloads + * @title: Dummyload + * @include: igt.h + * + * A lot of igt testcases need some GPU workload to make sure a race window is + * big enough. Unfortunately having a fixed amount of workload leads to + * spurious test failures or overtly long runtimes on some fast/slow platforms. + * This library contains functionality to submit GPU workloads that should + * consume exactly a specific amount of time. + */ + +#define NSEC_PER_SEC 1000000000L + +#define gettid() syscall(__NR_gettid) +#define sigev_notify_thread_id _sigev_un._tid + +#define LOCAL_I915_EXEC_BSD_SHIFT (13) +#define LOCAL_I915_EXEC_BSD_MASK (3 << LOCAL_I915_EXEC_BSD_SHIFT) + +#define ENGINE_MASK (I915_EXEC_RING_MASK | LOCAL_I915_EXEC_BSD_MASK) + +static void +fill_object(struct drm_i915_gem_exec_object2 *obj, uint32_t gem_handle, + struct drm_i915_gem_relocation_entry *relocs, uint32_t count) +{ + memset(obj, 0, sizeof(*obj)); + obj->handle = gem_handle; + obj->relocation_count = count; + obj->relocs_ptr = (uintptr_t)relocs; +} + +static void +fill_reloc(struct drm_i915_gem_relocation_entry *reloc, + uint32_t gem_handle, uint32_t offset, + uint32_t read_domains, uint32_t write_domains) +{ + reloc->target_handle = gem_handle; + reloc->delta = 0; + reloc->offset = offset * sizeof(uint32_t); + reloc->presumed_offset = 0; + reloc->read_domains = read_domains; + reloc->write_domain = write_domains; +} + + +static uint32_t *batch; + +static uint32_t emit_recursive_batch(int fd, int engine, unsigned dep_handle) +{ + const int gen = intel_gen(intel_get_drm_devid(fd)); + struct drm_i915_gem_exec_object2 obj[2]; + struct drm_i915_gem_relocation_entry relocs[2]; + struct drm_i915_gem_execbuffer2 execbuf; + unsigned engines[16]; + unsigned nengine, handle; + int i = 0, reloc_count = 0, buf_count = 0; + + buf_count = 0; + nengine = 0; + if (engine < 0) { + for_each_engine(fd, engine) + if (engine) + engines[nengine++] = engine; + } else { + igt_require(gem_has_ring(fd, engine)); + engines[nengine++] = engine; + } + igt_require(nengine); + + memset(&execbuf, 0, sizeof(execbuf)); + memset(obj, 0, sizeof(obj)); + memset(relocs, 0, sizeof(relocs)); + + execbuf.buffers_ptr = (uintptr_t) obj; + handle = gem_create(fd, 4096); + batch = gem_mmap__gtt(fd, handle, 4096, PROT_WRITE); + gem_set_domain(fd, handle, + I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); + + if (dep_handle > 0) { + fill_object(&obj[buf_count], dep_handle, NULL, 0); + buf_count++; + + fill_reloc(&relocs[reloc_count], dep_handle, i, + I915_GEM_DOMAIN_COMMAND, 0); + batch[i++] = 0; /* reloc */ + reloc_count++; + batch[i++] = MI_NOOP; + } + + if (gen >= 8) { + batch[i++] = MI_BATCH_BUFFER_START | 1 << 8 | 1; + /* recurse */ + fill_reloc(&relocs[reloc_count], handle, i, + I915_GEM_DOMAIN_COMMAND, 0); + batch[i++] = 0; + batch[i++] = 0; + } else if (gen >= 6) { + batch[i++] = MI_BATCH_BUFFER_START | 1 << 8; + /* recurse */ + fill_reloc(&relocs[reloc_count], handle, i, + I915_GEM_DOMAIN_COMMAND, 0); + batch[i++] = 0; + } else { + batch[i++] = MI_BATCH_BUFFER_START | 2 << 6 | + (gen < 4) ? 1 : 0; + /* recurse */ + fill_reloc(&relocs[reloc_count], handle, i, + I915_GEM_DOMAIN_COMMAND, 0); + batch[i++] = 0; + if (gen < 4) + relocs[reloc_count].delta = 1; + } + reloc_count++; + + fill_object(&obj[buf_count], handle, relocs, reloc_count); + buf_count++; + + for (i = 0; i < nengine; i++) { + execbuf.flags &= ~ENGINE_MASK; + execbuf.flags = engines[i]; + execbuf.buffer_count = buf_count; + gem_execbuf(fd, &execbuf); + } + + return handle; +} + +static void sigiter(int sig, siginfo_t *info, void *arg) +{ + *batch = MI_BATCH_BUFFER_END; + __sync_synchronize(); +} + +static timer_t setup_batch_exit_timer(int64_t ns) +{ + timer_t timer; + struct sigevent sev; + struct sigaction act; + struct itimerspec its; + + memset(&sev, 0, sizeof(sev)); + sev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID; + sev.sigev_notify_thread_id = gettid(); + sev.sigev_signo = SIGRTMIN + 1; + igt_assert(timer_create(CLOCK_MONOTONIC, &sev, &timer) == 0); + igt_assert(timer > 0); + + memset(&act, 0, sizeof(act)); + act.sa_sigaction = sigiter; + act.sa_flags = SA_SIGINFO; + igt_assert(sigaction(SIGRTMIN + 1, &act, NULL) == 0); + + memset(&its, 0, sizeof(its)); + its.it_value.tv_sec = ns / NSEC_PER_SEC; + its.it_value.tv_nsec = ns % NSEC_PER_SEC; + igt_assert(timer_settime(timer, 0, &its, NULL) == 0); + + return timer; +} + +/** + * igt_spin_batch: + * @fd: open i915 drm file descriptor + * @ns: amount of time in nanoseconds the batch executes after terminating. + * If value is less than 0, execute batch forever. + * @engine: Ring to execute batch OR'd with execbuf flags. If value is less + * than 0, execute on all available rings. + * @dep_handle: handle to a buffer object dependency. If greater than 0, add a + * relocation entry to this buffer within the batch. + * + * Start a recursive batch on a ring that terminates after an exact amount + * of time has elapsed. Immediately returns a #igt_spin_t that contains the + * batch's handle that can be waited upon. The returned structure must be passed to + * igt_post_spin_batch() for post-processing. + * + * Returns: + * Structure with helper internal state for igt_post_spin_batch(). + */ +igt_spin_t igt_spin_batch(int fd, int64_t ns, int engine, unsigned dep_handle) +{ + timer_t timer; + uint32_t handle = emit_recursive_batch(fd, engine, dep_handle); + int64_t wait_timeout = 0; + igt_assert_eq(gem_wait(fd, handle, &wait_timeout), -ETIME); + + if (ns < 1) { + if (ns == 0) { + *batch = MI_BATCH_BUFFER_END; + __sync_synchronize(); + return (igt_spin_t){ handle, batch, 0}; + } + return (igt_spin_t){ handle, batch, 0 }; + } + timer = setup_batch_exit_timer(ns); + + return (igt_spin_t){ handle, batch, timer }; +} + +/** + * igt_post_spin_batch: + * @fd: open i915 drm file descriptor + * @arg: spin batch state from igt_spin_batch() + * + * This function does the necessary post-processing after starting a recursive + * batch with igt_spin_batch(). + */ +void igt_post_spin_batch(int fd, igt_spin_t arg) +{ + if (arg.handle == 0) + return; + + if (arg.timer > 0) + timer_delete(arg.timer); + + gem_close(fd, arg.handle); + munmap(arg.batch, 4096); +} + + +/** + * igt_spin_batch_wait: + * @fd: open i915 drm file descriptor + * @ns: amount of time in nanoseconds the batch executes after terminating. + * If value is less than 0, execute batch forever. + * @engine: ring to execute batch OR'd with execbuf flags. If value is less + * than 0, execute on all available rings. + * @dep_handle: handle to a buffer object dependency. If greater than 0, include + * this buffer on the wait dependency + * + * This is similar to igt_spin_batch(), but waits on the recursive batch to finish + * instead of returning right away. The function also does the necessary + * post-processing automatically if set to timeout. + */ +void igt_spin_batch_wait(int fd, int64_t ns, int engine, unsigned dep_handle) +{ + igt_spin_t spin = igt_spin_batch(fd, ns, engine, dep_handle); + int64_t wait_timeout = ns + (0.5 * NSEC_PER_SEC); + igt_assert_eq(gem_wait(fd, spin.handle, &wait_timeout), 0); + + igt_post_spin_batch(fd, spin); +} diff --git a/lib/igt_dummyload.h b/lib/igt_dummyload.h new file mode 100644 index 0000000..79ead2c --- /dev/null +++ b/lib/igt_dummyload.h @@ -0,0 +1,42 @@ +/* + * Copyright © 2016 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. + * + */ + +#ifndef __IGT_DUMMYLOAD_H__ +#define __IGT_DUMMYLOAD_H__ + +typedef struct igt_spin { + unsigned handle; + uint32_t *batch; + timer_t timer; +} igt_spin_t; + + +igt_spin_t igt_spin_batch(int fd, int64_t ns, int engine, unsigned dep_handle); + +void igt_post_spin_batch(int fd, igt_spin_t arg); + +void igt_spin_batch_wait(int fd, int64_t ns, int engine, unsigned dep_handle); + + +#endif /* __IGT_DUMMYLOAD_H__ */ -- 2.7.0 _______________________________________________ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 2/3] igt/gem_wait: Use new igt_spin_batch 2016-11-03 9:40 ` [PATCH v3 1/3] lib: add igt_dummyload Abdiel Janulgue @ 2016-11-03 9:40 ` Abdiel Janulgue 2016-11-03 9:40 ` [PATCH v3 3/3] igt/kms_flip: " Abdiel Janulgue 2016-11-03 14:38 ` [PATCH v3 1/3] lib: add igt_dummyload Ville Syrjälä 2 siblings, 0 replies; 11+ messages in thread From: Abdiel Janulgue @ 2016-11-03 9:40 UTC (permalink / raw) To: intel-gfx; +Cc: Daniel Vetter Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com> --- tests/gem_wait.c | 125 ++++--------------------------------------------------- 1 file changed, 7 insertions(+), 118 deletions(-) diff --git a/tests/gem_wait.c b/tests/gem_wait.c index b4127de..785bb14 100644 --- a/tests/gem_wait.c +++ b/tests/gem_wait.c @@ -27,18 +27,6 @@ #include "igt.h" -#include <signal.h> -#include <time.h> -#include <sys/syscall.h> - -#define gettid() syscall(__NR_gettid) -#define sigev_notify_thread_id _sigev_un._tid - -#define LOCAL_I915_EXEC_BSD_SHIFT (13) -#define LOCAL_I915_EXEC_BSD_MASK (3 << LOCAL_I915_EXEC_BSD_SHIFT) - -#define ENGINE_MASK (I915_EXEC_RING_MASK | LOCAL_I915_EXEC_BSD_MASK) - static int __gem_wait(int fd, struct drm_i915_gem_wait *w) { int err; @@ -75,14 +63,6 @@ static void invalid_buf(int fd) igt_assert_eq(__gem_wait(fd, &wait), -ENOENT); } -static uint32_t *batch; - -static void sigiter(int sig, siginfo_t *info, void *arg) -{ - *batch = MI_BATCH_BUFFER_END; - __sync_synchronize(); -} - #define MSEC_PER_SEC (1000) #define USEC_PER_SEC (1000 * MSEC_PER_SEC) #define NSEC_PER_SEC (1000 * USEC_PER_SEC) @@ -91,113 +71,26 @@ static void sigiter(int sig, siginfo_t *info, void *arg) #define HANG 2 static void basic(int fd, unsigned engine, unsigned flags) { - const int gen = intel_gen(intel_get_drm_devid(fd)); - struct drm_i915_gem_exec_object2 obj; - struct drm_i915_gem_relocation_entry reloc; - struct drm_i915_gem_execbuffer2 execbuf; struct drm_i915_gem_wait wait; - unsigned engines[16]; - unsigned nengine; - int i, timeout; - - nengine = 0; - if (engine == -1) { - for_each_engine(fd, engine) - if (engine) engines[nengine++] = engine; - } else { - igt_require(gem_has_ring(fd, engine)); - engines[nengine++] = engine; - } - igt_require(nengine); - - memset(&execbuf, 0, sizeof(execbuf)); - execbuf.buffers_ptr = (uintptr_t)&obj; - execbuf.buffer_count = 1; - - memset(&obj, 0, sizeof(obj)); - obj.handle = gem_create(fd, 4096); - - obj.relocs_ptr = (uintptr_t)&reloc; - obj.relocation_count = 1; - memset(&reloc, 0, sizeof(reloc)); - - batch = gem_mmap__gtt(fd, obj.handle, 4096, PROT_WRITE); - gem_set_domain(fd, obj.handle, - I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); - - reloc.target_handle = obj.handle; /* recurse */ - reloc.presumed_offset = 0; - reloc.offset = sizeof(uint32_t); - reloc.delta = 0; - reloc.read_domains = I915_GEM_DOMAIN_COMMAND; - reloc.write_domain = 0; - - i = 0; - batch[i] = MI_BATCH_BUFFER_START; - if (gen >= 8) { - batch[i] |= 1 << 8 | 1; - batch[++i] = 0; - batch[++i] = 0; - } else if (gen >= 6) { - batch[i] |= 1 << 8; - batch[++i] = 0; - } else { - batch[i] |= 2 << 6; - batch[++i] = 0; - if (gen < 4) { - batch[i] |= 1; - reloc.delta = 1; - } - } - - for (i = 0; i < nengine; i++) { - execbuf.flags &= ~ENGINE_MASK; - execbuf.flags |= engines[i]; - gem_execbuf(fd, &execbuf); - } + int wait_s = (flags == 0) ? NSEC_PER_SEC : 0; + wait_s = ((flags & HANG) == 0) ? wait_s : -1; + igt_spin_t spin = igt_spin_batch(fd, wait_s, engine, 0); + int timeout; memset(&wait, 0, sizeof(wait)); - wait.bo_handle = obj.handle; - igt_assert_eq(__gem_wait(fd, &wait), -ETIME); + wait.bo_handle = spin.handle; if (flags & BUSY) { struct timespec tv; timeout = 120; - if ((flags & HANG) == 0) { - *batch = MI_BATCH_BUFFER_END; - __sync_synchronize(); + if ((flags & HANG) == 0) timeout = 1; - } memset(&tv, 0, sizeof(tv)); while (__gem_wait(fd, &wait) == -ETIME) igt_assert(igt_seconds_elapsed(&tv) < timeout); } else { - timer_t timer; - - if ((flags & HANG) == 0) { - struct sigevent sev; - struct sigaction act; - struct itimerspec its; - - memset(&sev, 0, sizeof(sev)); - sev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID; - sev.sigev_notify_thread_id = gettid(); - sev.sigev_signo = SIGRTMIN + 1; - igt_assert(timer_create(CLOCK_MONOTONIC, &sev, &timer) == 0); - - memset(&act, 0, sizeof(act)); - act.sa_sigaction = sigiter; - act.sa_flags = SA_SIGINFO; - igt_assert(sigaction(SIGRTMIN + 1, &act, NULL) == 0); - - memset(&its, 0, sizeof(its)); - its.it_value.tv_nsec = 0; - its.it_value.tv_sec = 1; - igt_assert(timer_settime(timer, 0, &its, NULL) == 0); - } - wait.timeout_ns = NSEC_PER_SEC / 2; /* 0.5s */ igt_assert_eq(__gem_wait(fd, &wait), -ETIME); igt_assert_eq_s64(wait.timeout_ns, 0); @@ -215,13 +108,9 @@ static void basic(int fd, unsigned engine, unsigned flags) wait.timeout_ns = 0; igt_assert_eq(__gem_wait(fd, &wait), 0); igt_assert(wait.timeout_ns == 0); - - if ((flags & HANG) == 0) - timer_delete(timer); } - gem_close(fd, obj.handle); - munmap(batch, 4096); + igt_post_spin_batch(fd, spin); } igt_main -- 2.7.0 _______________________________________________ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 3/3] igt/kms_flip: Use new igt_spin_batch 2016-11-03 9:40 ` [PATCH v3 1/3] lib: add igt_dummyload Abdiel Janulgue 2016-11-03 9:40 ` [PATCH v3 2/3] igt/gem_wait: Use new igt_spin_batch Abdiel Janulgue @ 2016-11-03 9:40 ` Abdiel Janulgue 2016-11-03 14:38 ` [PATCH v3 1/3] lib: add igt_dummyload Ville Syrjälä 2 siblings, 0 replies; 11+ messages in thread From: Abdiel Janulgue @ 2016-11-03 9:40 UTC (permalink / raw) To: intel-gfx; +Cc: Daniel Vetter Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com> --- tests/kms_flip.c | 185 ++----------------------------------------------------- 1 file changed, 4 insertions(+), 181 deletions(-) diff --git a/tests/kms_flip.c b/tests/kms_flip.c index 6a1549e..79cb783 100644 --- a/tests/kms_flip.c +++ b/tests/kms_flip.c @@ -191,109 +191,6 @@ static unsigned long gettime_us(void) return ts.tv_sec * 1000000 + ts.tv_nsec / 1000; } -static int calibrate_dummy_load(struct test_output *o, - const char *ring_name, - int (*emit)(struct test_output *o, int limit, int timeout)) -{ - unsigned long start; - int ops = 1; - - start = gettime_us(); - - do { - unsigned long diff; - int ret; - - ret = emit(o, (ops+1)/2, 10); - diff = gettime_us() - start; - - if (ret || diff / USEC_PER_SEC >= 1) - break; - - ops += ops; - } while (ops < 100000); - - igt_debug("%s dummy load calibrated: %d operations / second\n", - ring_name, ops); - - return ops; -} - -static void blit_copy(drm_intel_bo *dst, drm_intel_bo *src, - unsigned int width, unsigned int height, - unsigned int dst_pitch, unsigned int src_pitch) -{ - BLIT_COPY_BATCH_START(0); - OUT_BATCH((3 << 24) | /* 32 bits */ - (0xcc << 16) | /* copy ROP */ - dst_pitch); - OUT_BATCH(0 << 16 | 0); - OUT_BATCH(height << 16 | width); - OUT_RELOC_FENCED(dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); - OUT_BATCH(0 << 16 | 0); - OUT_BATCH(src_pitch); - OUT_RELOC_FENCED(src, I915_GEM_DOMAIN_RENDER, 0, 0); - ADVANCE_BATCH(); - - if (batch->gen >= 6) { - BEGIN_BATCH(3, 0); - OUT_BATCH(XY_SETUP_CLIP_BLT_CMD); - OUT_BATCH(0); - OUT_BATCH(0); - ADVANCE_BATCH(); - } -} - -static int _emit_dummy_load__bcs(struct test_output *o, int limit, int timeout) -{ - int i, ret = 0; - drm_intel_bo *src_bo, *dst_bo, *fb_bo; - struct igt_fb *fb_info = &o->fb_info[o->current_fb_id]; - - igt_require(bufmgr); - - src_bo = drm_intel_bo_alloc(bufmgr, "dummy_bo", 2048*2048*4, 4096); - igt_assert(src_bo); - - dst_bo = drm_intel_bo_alloc(bufmgr, "dummy_bo", 2048*2048*4, 4096); - igt_assert(dst_bo); - - fb_bo = gem_handle_to_libdrm_bo(bufmgr, drm_fd, "imported", fb_info->gem_handle); - igt_assert(fb_bo); - - for (i = 0; i < limit; i++) { - blit_copy(dst_bo, src_bo, - 2048, 2048, - 2048*4, 2048*4); - - igt_swap(src_bo, dst_bo); - } - blit_copy(fb_bo, src_bo, - min(o->fb_width, 2048), min(o->fb_height, 2048), - fb_info->stride, 2048*4); - intel_batchbuffer_flush(batch); - - if (timeout > 0) - ret = drm_intel_gem_bo_wait(fb_bo, timeout * NSEC_PER_SEC); - - drm_intel_bo_unreference(src_bo); - drm_intel_bo_unreference(dst_bo); - drm_intel_bo_unreference(fb_bo); - - return ret; -} - -static void emit_dummy_load__bcs(struct test_output *o, int seconds) -{ - static int ops_per_sec; - - if (ops_per_sec == 0) - ops_per_sec = calibrate_dummy_load(o, "bcs", - _emit_dummy_load__bcs); - - _emit_dummy_load__bcs(o, seconds * ops_per_sec, 0); -} - static void emit_fence_stress(struct test_output *o) { const int num_fences = gem_available_fences(drm_fd); @@ -338,82 +235,6 @@ static void emit_fence_stress(struct test_output *o) free(exec); } -static int _emit_dummy_load__rcs(struct test_output *o, int limit, int timeout) -{ - const struct igt_fb *fb_info = &o->fb_info[o->current_fb_id]; - igt_render_copyfunc_t copyfunc; - struct igt_buf sb[3], *src, *dst, *fb; - int i, ret = 0; - - igt_require(bufmgr); - - copyfunc = igt_get_render_copyfunc(devid); - if (copyfunc == NULL) - return _emit_dummy_load__bcs(o, limit, timeout); - - sb[0].bo = drm_intel_bo_alloc(bufmgr, "dummy_bo", 2048*2048*4, 4096); - igt_assert(sb[0].bo); - sb[0].size = sb[0].bo->size; - sb[0].tiling = I915_TILING_NONE; - sb[0].data = NULL; - sb[0].num_tiles = sb[0].bo->size; - sb[0].stride = 4 * 2048; - - sb[1].bo = drm_intel_bo_alloc(bufmgr, "dummy_bo", 2048*2048*4, 4096); - igt_assert(sb[1].bo); - sb[1].size = sb[1].bo->size; - sb[1].tiling = I915_TILING_NONE; - sb[1].data = NULL; - sb[1].num_tiles = sb[1].bo->size; - sb[1].stride = 4 * 2048; - - sb[2].bo = gem_handle_to_libdrm_bo(bufmgr, drm_fd, "imported", fb_info->gem_handle); - igt_assert(sb[2].bo); - sb[2].size = sb[2].bo->size; - sb[2].tiling = fb_info->tiling; - sb[2].data = NULL; - sb[2].num_tiles = sb[2].bo->size; - sb[2].stride = fb_info->stride; - - src = &sb[0]; - dst = &sb[1]; - fb = &sb[2]; - - for (i = 0; i < limit; i++) { - copyfunc(batch, NULL, - src, 0, 0, - 2048, 2048, - dst, 0, 0); - - igt_swap(src, dst); - } - copyfunc(batch, NULL, - src, 0, 0, - min(o->fb_width, 2048), min(o->fb_height, 2048), - fb, 0, 0); - intel_batchbuffer_flush(batch); - - if (timeout > 0) - ret = drm_intel_gem_bo_wait(fb->bo, timeout * NSEC_PER_SEC); - - drm_intel_bo_unreference(sb[0].bo); - drm_intel_bo_unreference(sb[1].bo); - drm_intel_bo_unreference(sb[2].bo); - - return ret; -} - -static void emit_dummy_load__rcs(struct test_output *o, int seconds) -{ - static int ops_per_sec; - - if (ops_per_sec == 0) - ops_per_sec = calibrate_dummy_load(o, "rcs", - _emit_dummy_load__rcs); - - _emit_dummy_load__bcs(o, seconds * ops_per_sec, 0); -} - static void dpms_off_other_outputs(struct test_output *o) { int i, n; @@ -874,10 +695,12 @@ static unsigned int run_test_step(struct test_output *o) o->current_fb_id = !o->current_fb_id; if (o->flags & TEST_WITH_DUMMY_BCS) - emit_dummy_load__bcs(o, 1); + igt_spin_batch_wait(drm_fd, NSEC_PER_SEC, I915_EXEC_BLT, + o->fb_info[o->current_fb_id].gem_handle); if (o->flags & TEST_WITH_DUMMY_RCS) - emit_dummy_load__rcs(o, 1); + igt_spin_batch_wait(drm_fd, NSEC_PER_SEC, I915_EXEC_RENDER, + o->fb_info[o->current_fb_id].gem_handle); if (o->flags & TEST_FB_RECREATE) recreate_fb(o); -- 2.7.0 _______________________________________________ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v3 1/3] lib: add igt_dummyload 2016-11-03 9:40 ` [PATCH v3 1/3] lib: add igt_dummyload Abdiel Janulgue 2016-11-03 9:40 ` [PATCH v3 2/3] igt/gem_wait: Use new igt_spin_batch Abdiel Janulgue 2016-11-03 9:40 ` [PATCH v3 3/3] igt/kms_flip: " Abdiel Janulgue @ 2016-11-03 14:38 ` Ville Syrjälä 2016-11-04 7:57 ` Abdiel Janulgue 2 siblings, 1 reply; 11+ messages in thread From: Ville Syrjälä @ 2016-11-03 14:38 UTC (permalink / raw) To: Abdiel Janulgue; +Cc: Daniel Vetter, intel-gfx On Thu, Nov 03, 2016 at 11:40:36AM +0200, Abdiel Janulgue wrote: > A lot of igt testcases need some GPU workload to make sure a race > window is big enough. Unfortunately having a fixed amount of > workload leads to spurious test failures or overtly long runtimes > on some fast/slow platforms. This library contains functionality > to submit GPU workloads that should consume exactly a specific > amount of time. > > v2 : Add recursive batch feature from Chris > v3 : Drop auto-tuned stuff. Add bo dependecy to recursive batch > by adding a dummy reloc to the bo as suggested by Ville. > > Cc: Daniel Vetter <daniel.vetter@ffwll.ch> > Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> > Cc: Chris Wilson <chris@chris-wilson.co.uk> > Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com> > --- > lib/Makefile.sources | 2 + > lib/igt.h | 1 + > lib/igt_dummyload.c | 274 +++++++++++++++++++++++++++++++++++++++++++++++++++ > lib/igt_dummyload.h | 42 ++++++++ > 4 files changed, 319 insertions(+) > create mode 100644 lib/igt_dummyload.c > create mode 100644 lib/igt_dummyload.h > > diff --git a/lib/Makefile.sources b/lib/Makefile.sources > index e8e277b..7fc5ec2 100644 > --- a/lib/Makefile.sources > +++ b/lib/Makefile.sources > @@ -75,6 +75,8 @@ lib_source_list = \ > igt_draw.h \ > igt_pm.c \ > igt_pm.h \ > + igt_dummyload.c \ > + igt_dummyload.h \ > uwildmat/uwildmat.h \ > uwildmat/uwildmat.c \ > $(NULL) > diff --git a/lib/igt.h b/lib/igt.h > index d751f24..a0028d5 100644 > --- a/lib/igt.h > +++ b/lib/igt.h > @@ -32,6 +32,7 @@ > #include "igt_core.h" > #include "igt_debugfs.h" > #include "igt_draw.h" > +#include "igt_dummyload.h" > #include "igt_fb.h" > #include "igt_gt.h" > #include "igt_kms.h" > diff --git a/lib/igt_dummyload.c b/lib/igt_dummyload.c > new file mode 100644 > index 0000000..d37a30b > --- /dev/null > +++ b/lib/igt_dummyload.c > @@ -0,0 +1,274 @@ > +/* > + * Copyright © 2016 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. > + * > + */ > + > +#include "igt.h" > +#include "igt_dummyload.h" > +#include <time.h> > +#include <signal.h> > +#include <sys/syscall.h> > + > +/** > + * SECTION:igt_dummyload > + * @short_description: Library for submitting GPU workloads > + * @title: Dummyload > + * @include: igt.h > + * > + * A lot of igt testcases need some GPU workload to make sure a race window is > + * big enough. Unfortunately having a fixed amount of workload leads to > + * spurious test failures or overtly long runtimes on some fast/slow platforms. > + * This library contains functionality to submit GPU workloads that should > + * consume exactly a specific amount of time. > + */ > + > +#define NSEC_PER_SEC 1000000000L > + > +#define gettid() syscall(__NR_gettid) > +#define sigev_notify_thread_id _sigev_un._tid > + > +#define LOCAL_I915_EXEC_BSD_SHIFT (13) > +#define LOCAL_I915_EXEC_BSD_MASK (3 << LOCAL_I915_EXEC_BSD_SHIFT) > + > +#define ENGINE_MASK (I915_EXEC_RING_MASK | LOCAL_I915_EXEC_BSD_MASK) > + > +static void > +fill_object(struct drm_i915_gem_exec_object2 *obj, uint32_t gem_handle, > + struct drm_i915_gem_relocation_entry *relocs, uint32_t count) > +{ > + memset(obj, 0, sizeof(*obj)); > + obj->handle = gem_handle; > + obj->relocation_count = count; > + obj->relocs_ptr = (uintptr_t)relocs; > +} > + > +static void > +fill_reloc(struct drm_i915_gem_relocation_entry *reloc, > + uint32_t gem_handle, uint32_t offset, > + uint32_t read_domains, uint32_t write_domains) > +{ > + reloc->target_handle = gem_handle; > + reloc->delta = 0; > + reloc->offset = offset * sizeof(uint32_t); > + reloc->presumed_offset = 0; > + reloc->read_domains = read_domains; > + reloc->write_domain = write_domains; > +} > + > + > +static uint32_t *batch; > + > +static uint32_t emit_recursive_batch(int fd, int engine, unsigned dep_handle) > +{ > + const int gen = intel_gen(intel_get_drm_devid(fd)); > + struct drm_i915_gem_exec_object2 obj[2]; > + struct drm_i915_gem_relocation_entry relocs[2]; > + struct drm_i915_gem_execbuffer2 execbuf; > + unsigned engines[16]; > + unsigned nengine, handle; > + int i = 0, reloc_count = 0, buf_count = 0; > + > + buf_count = 0; > + nengine = 0; > + if (engine < 0) { > + for_each_engine(fd, engine) > + if (engine) > + engines[nengine++] = engine; > + } else { > + igt_require(gem_has_ring(fd, engine)); > + engines[nengine++] = engine; > + } > + igt_require(nengine); > + > + memset(&execbuf, 0, sizeof(execbuf)); > + memset(obj, 0, sizeof(obj)); > + memset(relocs, 0, sizeof(relocs)); > + > + execbuf.buffers_ptr = (uintptr_t) obj; > + handle = gem_create(fd, 4096); > + batch = gem_mmap__gtt(fd, handle, 4096, PROT_WRITE); > + gem_set_domain(fd, handle, > + I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); > + > + if (dep_handle > 0) { > + fill_object(&obj[buf_count], dep_handle, NULL, 0); > + buf_count++; > + > + fill_reloc(&relocs[reloc_count], dep_handle, i, > + I915_GEM_DOMAIN_COMMAND, 0); Don't we need this to be a write? A read shouldn't block any subsequent flip. > + batch[i++] = 0; /* reloc */ > + reloc_count++; > + batch[i++] = MI_NOOP; > + } > + > + if (gen >= 8) { > + batch[i++] = MI_BATCH_BUFFER_START | 1 << 8 | 1; > + /* recurse */ > + fill_reloc(&relocs[reloc_count], handle, i, > + I915_GEM_DOMAIN_COMMAND, 0); > + batch[i++] = 0; > + batch[i++] = 0; > + } else if (gen >= 6) { > + batch[i++] = MI_BATCH_BUFFER_START | 1 << 8; > + /* recurse */ > + fill_reloc(&relocs[reloc_count], handle, i, > + I915_GEM_DOMAIN_COMMAND, 0); > + batch[i++] = 0; > + } else { > + batch[i++] = MI_BATCH_BUFFER_START | 2 << 6 | > + (gen < 4) ? 1 : 0; > + /* recurse */ > + fill_reloc(&relocs[reloc_count], handle, i, > + I915_GEM_DOMAIN_COMMAND, 0); > + batch[i++] = 0; > + if (gen < 4) > + relocs[reloc_count].delta = 1; > + } > + reloc_count++; > + > + fill_object(&obj[buf_count], handle, relocs, reloc_count); > + buf_count++; > + > + for (i = 0; i < nengine; i++) { > + execbuf.flags &= ~ENGINE_MASK; > + execbuf.flags = engines[i]; > + execbuf.buffer_count = buf_count; > + gem_execbuf(fd, &execbuf); > + } > + > + return handle; > +} > + > +static void sigiter(int sig, siginfo_t *info, void *arg) > +{ > + *batch = MI_BATCH_BUFFER_END; > + __sync_synchronize(); > +} > + > +static timer_t setup_batch_exit_timer(int64_t ns) > +{ > + timer_t timer; > + struct sigevent sev; > + struct sigaction act; > + struct itimerspec its; > + > + memset(&sev, 0, sizeof(sev)); > + sev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID; > + sev.sigev_notify_thread_id = gettid(); > + sev.sigev_signo = SIGRTMIN + 1; > + igt_assert(timer_create(CLOCK_MONOTONIC, &sev, &timer) == 0); > + igt_assert(timer > 0); > + > + memset(&act, 0, sizeof(act)); > + act.sa_sigaction = sigiter; > + act.sa_flags = SA_SIGINFO; > + igt_assert(sigaction(SIGRTMIN + 1, &act, NULL) == 0); > + > + memset(&its, 0, sizeof(its)); > + its.it_value.tv_sec = ns / NSEC_PER_SEC; > + its.it_value.tv_nsec = ns % NSEC_PER_SEC; > + igt_assert(timer_settime(timer, 0, &its, NULL) == 0); > + > + return timer; > +} > + > +/** > + * igt_spin_batch: > + * @fd: open i915 drm file descriptor > + * @ns: amount of time in nanoseconds the batch executes after terminating. > + * If value is less than 0, execute batch forever. > + * @engine: Ring to execute batch OR'd with execbuf flags. If value is less > + * than 0, execute on all available rings. > + * @dep_handle: handle to a buffer object dependency. If greater than 0, add a > + * relocation entry to this buffer within the batch. > + * > + * Start a recursive batch on a ring that terminates after an exact amount > + * of time has elapsed. Immediately returns a #igt_spin_t that contains the > + * batch's handle that can be waited upon. The returned structure must be passed to > + * igt_post_spin_batch() for post-processing. > + * > + * Returns: > + * Structure with helper internal state for igt_post_spin_batch(). > + */ > +igt_spin_t igt_spin_batch(int fd, int64_t ns, int engine, unsigned dep_handle) > +{ > + timer_t timer; > + uint32_t handle = emit_recursive_batch(fd, engine, dep_handle); > + int64_t wait_timeout = 0; > + igt_assert_eq(gem_wait(fd, handle, &wait_timeout), -ETIME); > + > + if (ns < 1) { > + if (ns == 0) { > + *batch = MI_BATCH_BUFFER_END; > + __sync_synchronize(); > + return (igt_spin_t){ handle, batch, 0}; > + } Why the special handling for ==0 ? Wouldn't it just work if you let it go via the timer? > + return (igt_spin_t){ handle, batch, 0 }; > + } > + timer = setup_batch_exit_timer(ns); > + > + return (igt_spin_t){ handle, batch, timer }; > +} > + > +/** > + * igt_post_spin_batch: > + * @fd: open i915 drm file descriptor > + * @arg: spin batch state from igt_spin_batch() > + * > + * This function does the necessary post-processing after starting a recursive > + * batch with igt_spin_batch(). > + */ > +void igt_post_spin_batch(int fd, igt_spin_t arg) > +{ > + if (arg.handle == 0) > + return; > + > + if (arg.timer > 0) > + timer_delete(arg.timer); > + > + gem_close(fd, arg.handle); > + munmap(arg.batch, 4096); > +} > + > + > +/** > + * igt_spin_batch_wait: > + * @fd: open i915 drm file descriptor > + * @ns: amount of time in nanoseconds the batch executes after terminating. > + * If value is less than 0, execute batch forever. > + * @engine: ring to execute batch OR'd with execbuf flags. If value is less > + * than 0, execute on all available rings. > + * @dep_handle: handle to a buffer object dependency. If greater than 0, include > + * this buffer on the wait dependency > + * > + * This is similar to igt_spin_batch(), but waits on the recursive batch to finish > + * instead of returning right away. The function also does the necessary > + * post-processing automatically if set to timeout. > + */ > +void igt_spin_batch_wait(int fd, int64_t ns, int engine, unsigned dep_handle) > +{ > + igt_spin_t spin = igt_spin_batch(fd, ns, engine, dep_handle); > + int64_t wait_timeout = ns + (0.5 * NSEC_PER_SEC); > + igt_assert_eq(gem_wait(fd, spin.handle, &wait_timeout), 0); > + > + igt_post_spin_batch(fd, spin); > +} > diff --git a/lib/igt_dummyload.h b/lib/igt_dummyload.h > new file mode 100644 > index 0000000..79ead2c > --- /dev/null > +++ b/lib/igt_dummyload.h > @@ -0,0 +1,42 @@ > +/* > + * Copyright © 2016 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. > + * > + */ > + > +#ifndef __IGT_DUMMYLOAD_H__ > +#define __IGT_DUMMYLOAD_H__ > + > +typedef struct igt_spin { > + unsigned handle; > + uint32_t *batch; > + timer_t timer; > +} igt_spin_t; > + > + > +igt_spin_t igt_spin_batch(int fd, int64_t ns, int engine, unsigned dep_handle); > + > +void igt_post_spin_batch(int fd, igt_spin_t arg); > + > +void igt_spin_batch_wait(int fd, int64_t ns, int engine, unsigned dep_handle); > + > + > +#endif /* __IGT_DUMMYLOAD_H__ */ > -- > 2.7.0 -- Ville Syrjälä Intel OTC _______________________________________________ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v3 1/3] lib: add igt_dummyload 2016-11-03 14:38 ` [PATCH v3 1/3] lib: add igt_dummyload Ville Syrjälä @ 2016-11-04 7:57 ` Abdiel Janulgue 0 siblings, 0 replies; 11+ messages in thread From: Abdiel Janulgue @ 2016-11-04 7:57 UTC (permalink / raw) To: Ville Syrjälä; +Cc: Daniel Vetter, intel-gfx On 11/03/2016 04:38 PM, Ville Syrjälä wrote: > On Thu, Nov 03, 2016 at 11:40:36AM +0200, Abdiel Janulgue wrote: >> A lot of igt testcases need some GPU workload to make sure a race >> window is big enough. Unfortunately having a fixed amount of >> workload leads to spurious test failures or overtly long runtimes >> on some fast/slow platforms. This library contains functionality >> to submit GPU workloads that should consume exactly a specific >> amount of time. >> >> v2 : Add recursive batch feature from Chris >> v3 : Drop auto-tuned stuff. Add bo dependecy to recursive batch >> by adding a dummy reloc to the bo as suggested by Ville. >> >> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> >> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> >> Cc: Chris Wilson <chris@chris-wilson.co.uk> >> Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com> >> --- >> lib/Makefile.sources | 2 + >> lib/igt.h | 1 + >> lib/igt_dummyload.c | 274 +++++++++++++++++++++++++++++++++++++++++++++++++++ >> lib/igt_dummyload.h | 42 ++++++++ >> 4 files changed, 319 insertions(+) >> create mode 100644 lib/igt_dummyload.c >> create mode 100644 lib/igt_dummyload.h >> >> diff --git a/lib/Makefile.sources b/lib/Makefile.sources >> index e8e277b..7fc5ec2 100644 >> --- a/lib/Makefile.sources >> +++ b/lib/Makefile.sources >> @@ -75,6 +75,8 @@ lib_source_list = \ >> igt_draw.h \ >> igt_pm.c \ >> igt_pm.h \ >> + igt_dummyload.c \ >> + igt_dummyload.h \ >> uwildmat/uwildmat.h \ >> uwildmat/uwildmat.c \ >> $(NULL) >> diff --git a/lib/igt.h b/lib/igt.h >> index d751f24..a0028d5 100644 >> --- a/lib/igt.h >> +++ b/lib/igt.h >> @@ -32,6 +32,7 @@ >> #include "igt_core.h" >> #include "igt_debugfs.h" >> #include "igt_draw.h" >> +#include "igt_dummyload.h" >> #include "igt_fb.h" >> #include "igt_gt.h" >> #include "igt_kms.h" >> diff --git a/lib/igt_dummyload.c b/lib/igt_dummyload.c >> new file mode 100644 >> index 0000000..d37a30b >> --- /dev/null >> +++ b/lib/igt_dummyload.c >> @@ -0,0 +1,274 @@ >> +/* >> + * Copyright © 2016 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. >> + * >> + */ >> + >> +#include "igt.h" >> +#include "igt_dummyload.h" >> +#include <time.h> >> +#include <signal.h> >> +#include <sys/syscall.h> >> + >> +/** >> + * SECTION:igt_dummyload >> + * @short_description: Library for submitting GPU workloads >> + * @title: Dummyload >> + * @include: igt.h >> + * >> + * A lot of igt testcases need some GPU workload to make sure a race window is >> + * big enough. Unfortunately having a fixed amount of workload leads to >> + * spurious test failures or overtly long runtimes on some fast/slow platforms. >> + * This library contains functionality to submit GPU workloads that should >> + * consume exactly a specific amount of time. >> + */ >> + >> +#define NSEC_PER_SEC 1000000000L >> + >> +#define gettid() syscall(__NR_gettid) >> +#define sigev_notify_thread_id _sigev_un._tid >> + >> +#define LOCAL_I915_EXEC_BSD_SHIFT (13) >> +#define LOCAL_I915_EXEC_BSD_MASK (3 << LOCAL_I915_EXEC_BSD_SHIFT) >> + >> +#define ENGINE_MASK (I915_EXEC_RING_MASK | LOCAL_I915_EXEC_BSD_MASK) >> + >> +static void >> +fill_object(struct drm_i915_gem_exec_object2 *obj, uint32_t gem_handle, >> + struct drm_i915_gem_relocation_entry *relocs, uint32_t count) >> +{ >> + memset(obj, 0, sizeof(*obj)); >> + obj->handle = gem_handle; >> + obj->relocation_count = count; >> + obj->relocs_ptr = (uintptr_t)relocs; >> +} >> + >> +static void >> +fill_reloc(struct drm_i915_gem_relocation_entry *reloc, >> + uint32_t gem_handle, uint32_t offset, >> + uint32_t read_domains, uint32_t write_domains) >> +{ >> + reloc->target_handle = gem_handle; >> + reloc->delta = 0; >> + reloc->offset = offset * sizeof(uint32_t); >> + reloc->presumed_offset = 0; >> + reloc->read_domains = read_domains; >> + reloc->write_domain = write_domains; >> +} >> + >> + >> +static uint32_t *batch; >> + >> +static uint32_t emit_recursive_batch(int fd, int engine, unsigned dep_handle) >> +{ >> + const int gen = intel_gen(intel_get_drm_devid(fd)); >> + struct drm_i915_gem_exec_object2 obj[2]; >> + struct drm_i915_gem_relocation_entry relocs[2]; >> + struct drm_i915_gem_execbuffer2 execbuf; >> + unsigned engines[16]; >> + unsigned nengine, handle; >> + int i = 0, reloc_count = 0, buf_count = 0; >> + >> + buf_count = 0; >> + nengine = 0; >> + if (engine < 0) { >> + for_each_engine(fd, engine) >> + if (engine) >> + engines[nengine++] = engine; >> + } else { >> + igt_require(gem_has_ring(fd, engine)); >> + engines[nengine++] = engine; >> + } >> + igt_require(nengine); >> + >> + memset(&execbuf, 0, sizeof(execbuf)); >> + memset(obj, 0, sizeof(obj)); >> + memset(relocs, 0, sizeof(relocs)); >> + >> + execbuf.buffers_ptr = (uintptr_t) obj; >> + handle = gem_create(fd, 4096); >> + batch = gem_mmap__gtt(fd, handle, 4096, PROT_WRITE); >> + gem_set_domain(fd, handle, >> + I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); >> + >> + if (dep_handle > 0) { >> + fill_object(&obj[buf_count], dep_handle, NULL, 0); >> + buf_count++; >> + >> + fill_reloc(&relocs[reloc_count], dep_handle, i, >> + I915_GEM_DOMAIN_COMMAND, 0); > > Don't we need this to be a write? A read shouldn't block any subsequent > flip. Yep, missed that. I'll address this in v4 > >> + batch[i++] = 0; /* reloc */ >> + reloc_count++; >> + batch[i++] = MI_NOOP; >> + } >> + >> + if (gen >= 8) { >> + batch[i++] = MI_BATCH_BUFFER_START | 1 << 8 | 1; >> + /* recurse */ >> + fill_reloc(&relocs[reloc_count], handle, i, >> + I915_GEM_DOMAIN_COMMAND, 0); >> + batch[i++] = 0; >> + batch[i++] = 0; >> + } else if (gen >= 6) { >> + batch[i++] = MI_BATCH_BUFFER_START | 1 << 8; >> + /* recurse */ >> + fill_reloc(&relocs[reloc_count], handle, i, >> + I915_GEM_DOMAIN_COMMAND, 0); >> + batch[i++] = 0; >> + } else { >> + batch[i++] = MI_BATCH_BUFFER_START | 2 << 6 | >> + (gen < 4) ? 1 : 0; >> + /* recurse */ >> + fill_reloc(&relocs[reloc_count], handle, i, >> + I915_GEM_DOMAIN_COMMAND, 0); >> + batch[i++] = 0; >> + if (gen < 4) >> + relocs[reloc_count].delta = 1; >> + } >> + reloc_count++; >> + >> + fill_object(&obj[buf_count], handle, relocs, reloc_count); >> + buf_count++; >> + >> + for (i = 0; i < nengine; i++) { >> + execbuf.flags &= ~ENGINE_MASK; >> + execbuf.flags = engines[i]; >> + execbuf.buffer_count = buf_count; >> + gem_execbuf(fd, &execbuf); >> + } >> + >> + return handle; >> +} >> + >> +static void sigiter(int sig, siginfo_t *info, void *arg) >> +{ >> + *batch = MI_BATCH_BUFFER_END; >> + __sync_synchronize(); >> +} >> + >> +static timer_t setup_batch_exit_timer(int64_t ns) >> +{ >> + timer_t timer; >> + struct sigevent sev; >> + struct sigaction act; >> + struct itimerspec its; >> + >> + memset(&sev, 0, sizeof(sev)); >> + sev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID; >> + sev.sigev_notify_thread_id = gettid(); >> + sev.sigev_signo = SIGRTMIN + 1; >> + igt_assert(timer_create(CLOCK_MONOTONIC, &sev, &timer) == 0); >> + igt_assert(timer > 0); >> + >> + memset(&act, 0, sizeof(act)); >> + act.sa_sigaction = sigiter; >> + act.sa_flags = SA_SIGINFO; >> + igt_assert(sigaction(SIGRTMIN + 1, &act, NULL) == 0); >> + >> + memset(&its, 0, sizeof(its)); >> + its.it_value.tv_sec = ns / NSEC_PER_SEC; >> + its.it_value.tv_nsec = ns % NSEC_PER_SEC; >> + igt_assert(timer_settime(timer, 0, &its, NULL) == 0); >> + >> + return timer; >> +} >> + >> +/** >> + * igt_spin_batch: >> + * @fd: open i915 drm file descriptor >> + * @ns: amount of time in nanoseconds the batch executes after terminating. >> + * If value is less than 0, execute batch forever. >> + * @engine: Ring to execute batch OR'd with execbuf flags. If value is less >> + * than 0, execute on all available rings. >> + * @dep_handle: handle to a buffer object dependency. If greater than 0, add a >> + * relocation entry to this buffer within the batch. >> + * >> + * Start a recursive batch on a ring that terminates after an exact amount >> + * of time has elapsed. Immediately returns a #igt_spin_t that contains the >> + * batch's handle that can be waited upon. The returned structure must be passed to >> + * igt_post_spin_batch() for post-processing. >> + * >> + * Returns: >> + * Structure with helper internal state for igt_post_spin_batch(). >> + */ >> +igt_spin_t igt_spin_batch(int fd, int64_t ns, int engine, unsigned dep_handle) >> +{ >> + timer_t timer; >> + uint32_t handle = emit_recursive_batch(fd, engine, dep_handle); >> + int64_t wait_timeout = 0; >> + igt_assert_eq(gem_wait(fd, handle, &wait_timeout), -ETIME); >> + >> + if (ns < 1) { >> + if (ns == 0) { >> + *batch = MI_BATCH_BUFFER_END; >> + __sync_synchronize(); >> + return (igt_spin_t){ handle, batch, 0}; >> + } > > Why the special handling for ==0 ? Wouldn't it just work if you let it > go via the timer? > 0 is for timing-out right away. If we use the timer to break out on 0, by the time the function returns, it's not guaranteed that that the batch has terminated. >> + return (igt_spin_t){ handle, batch, 0 }; >> + } >> + timer = setup_batch_exit_timer(ns); >> + >> + return (igt_spin_t){ handle, batch, timer }; >> +} >> + >> +/** >> + * igt_post_spin_batch: >> + * @fd: open i915 drm file descriptor >> + * @arg: spin batch state from igt_spin_batch() >> + * >> + * This function does the necessary post-processing after starting a recursive >> + * batch with igt_spin_batch(). >> + */ >> +void igt_post_spin_batch(int fd, igt_spin_t arg) >> +{ >> + if (arg.handle == 0) >> + return; >> + >> + if (arg.timer > 0) >> + timer_delete(arg.timer); >> + >> + gem_close(fd, arg.handle); >> + munmap(arg.batch, 4096); >> +} >> + >> + >> +/** >> + * igt_spin_batch_wait: >> + * @fd: open i915 drm file descriptor >> + * @ns: amount of time in nanoseconds the batch executes after terminating. >> + * If value is less than 0, execute batch forever. >> + * @engine: ring to execute batch OR'd with execbuf flags. If value is less >> + * than 0, execute on all available rings. >> + * @dep_handle: handle to a buffer object dependency. If greater than 0, include >> + * this buffer on the wait dependency >> + * >> + * This is similar to igt_spin_batch(), but waits on the recursive batch to finish >> + * instead of returning right away. The function also does the necessary >> + * post-processing automatically if set to timeout. >> + */ >> +void igt_spin_batch_wait(int fd, int64_t ns, int engine, unsigned dep_handle) >> +{ >> + igt_spin_t spin = igt_spin_batch(fd, ns, engine, dep_handle); >> + int64_t wait_timeout = ns + (0.5 * NSEC_PER_SEC); >> + igt_assert_eq(gem_wait(fd, spin.handle, &wait_timeout), 0); >> + >> + igt_post_spin_batch(fd, spin); >> +} >> diff --git a/lib/igt_dummyload.h b/lib/igt_dummyload.h >> new file mode 100644 >> index 0000000..79ead2c >> --- /dev/null >> +++ b/lib/igt_dummyload.h >> @@ -0,0 +1,42 @@ >> +/* >> + * Copyright © 2016 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. >> + * >> + */ >> + >> +#ifndef __IGT_DUMMYLOAD_H__ >> +#define __IGT_DUMMYLOAD_H__ >> + >> +typedef struct igt_spin { >> + unsigned handle; >> + uint32_t *batch; >> + timer_t timer; >> +} igt_spin_t; >> + >> + >> +igt_spin_t igt_spin_batch(int fd, int64_t ns, int engine, unsigned dep_handle); >> + >> +void igt_post_spin_batch(int fd, igt_spin_t arg); >> + >> +void igt_spin_batch_wait(int fd, int64_t ns, int engine, unsigned dep_handle); >> + >> + >> +#endif /* __IGT_DUMMYLOAD_H__ */ >> -- >> 2.7.0 > _______________________________________________ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2016-11-04 7:57 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2016-10-28 15:47 [RFC v2 i-g-t] Auto-tuned dummyload + recursive batch Abdiel Janulgue 2016-10-28 15:47 ` [PATCH 1/3] lib: add igt_dummyload Abdiel Janulgue 2016-10-28 15:47 ` [PATCH 2/3] igt/gem_wait: Use new igt_spin_batch Abdiel Janulgue 2016-10-28 15:47 ` [PATCH 3/3] igt/kms_flip: " Abdiel Janulgue 2016-10-28 16:02 ` Ville Syrjälä 2016-10-31 6:43 ` Abdiel Janulgue 2016-11-03 9:40 ` [PATCH v3 1/3] lib: add igt_dummyload Abdiel Janulgue 2016-11-03 9:40 ` [PATCH v3 2/3] igt/gem_wait: Use new igt_spin_batch Abdiel Janulgue 2016-11-03 9:40 ` [PATCH v3 3/3] igt/kms_flip: " Abdiel Janulgue 2016-11-03 14:38 ` [PATCH v3 1/3] lib: add igt_dummyload Ville Syrjälä 2016-11-04 7:57 ` Abdiel Janulgue
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).