diff options
-rw-r--r-- | tests/gem_busy.c | 263 |
1 files changed, 157 insertions, 106 deletions
diff --git a/tests/gem_busy.c b/tests/gem_busy.c index 2b88270b..4ba23241 100644 --- a/tests/gem_busy.c +++ b/tests/gem_busy.c @@ -21,10 +21,16 @@ * IN THE SOFTWARE. */ +#include <sched.h> +#include <signal.h> +#include <sys/ioctl.h> + #include "igt.h" #include "igt_rand.h" +#include "igt_vgem.h" #define LOCAL_EXEC_NO_RELOC (1<<11) +#define PAGE_ALIGN(x) ALIGN(x, 4096) /* Exercise the busy-ioctl, ensuring the ABI is never broken */ IGT_TEST_DESCRIPTION("Basic check of busy-ioctl ABI."); @@ -59,80 +65,6 @@ static void __gem_busy(int fd, *read = busy.busy >> 16; } -static uint32_t busy_blt(int fd) -{ - const int gen = intel_gen(intel_get_drm_devid(fd)); - const int has_64bit_reloc = gen >= 8; - struct drm_i915_gem_execbuffer2 execbuf; - struct drm_i915_gem_exec_object2 object[2]; - struct drm_i915_gem_relocation_entry reloc[200], *r; - uint32_t *map; - int factor = 100; - int i = 0; - - memset(object, 0, sizeof(object)); - object[0].handle = gem_create(fd, 1024*1024); - object[1].handle = gem_create(fd, 4096); - - r = memset(reloc, 0, sizeof(reloc)); - map = gem_mmap__cpu(fd, object[1].handle, 0, 4096, PROT_WRITE); - gem_set_domain(fd, object[1].handle, - I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU); - -#define COPY_BLT_CMD (2<<29|0x53<<22|0x6) -#define BLT_WRITE_ALPHA (1<<21) -#define BLT_WRITE_RGB (1<<20) - while (factor--) { - /* XY_SRC_COPY */ - map[i++] = COPY_BLT_CMD | BLT_WRITE_ALPHA | BLT_WRITE_RGB; - if (has_64bit_reloc) - map[i-1] += 2; - map[i++] = 0xcc << 16 | 1 << 25 | 1 << 24 | (4*1024); - map[i++] = 0; - map[i++] = 256 << 16 | 1024; - - r->offset = i * sizeof(uint32_t); - r->target_handle = object[0].handle; - r->read_domains = I915_GEM_DOMAIN_RENDER; - r->write_domain = I915_GEM_DOMAIN_RENDER; - r++; - map[i++] = 0; - if (has_64bit_reloc) - map[i++] = 0; - - map[i++] = 0; - map[i++] = 4096; - - r->offset = i * sizeof(uint32_t); - r->target_handle = object[0].handle; - r->read_domains = I915_GEM_DOMAIN_RENDER; - r->write_domain = 0; - r++; - map[i++] = 0; - if (has_64bit_reloc) - map[i++] = 0; - } - map[i++] = MI_BATCH_BUFFER_END; - igt_assert(i <= 4096/sizeof(uint32_t)); - igt_assert(r - reloc <= ARRAY_SIZE(reloc)); - munmap(map, 4096); - - object[1].relocs_ptr = to_user_pointer(reloc); - object[1].relocation_count = r - reloc; - - memset(&execbuf, 0, sizeof(execbuf)); - execbuf.buffers_ptr = to_user_pointer(object); - execbuf.buffer_count = 2; - if (gen >= 6) - execbuf.flags = I915_EXEC_BLT; - gem_execbuf(fd, &execbuf); - igt_assert(gem_bo_busy(fd, object[0].handle)); - - igt_debug("Created busy handle %d\n", object[0].handle); - gem_close(fd, object[1].handle); - return object[0].handle; -} - static bool exec_noop(int fd, uint32_t *handles, unsigned ring, @@ -167,6 +99,7 @@ static bool still_busy(int fd, uint32_t handle) static void semaphore(int fd, unsigned ring, uint32_t flags) { uint32_t bbe = MI_BATCH_BUFFER_END; + igt_spin_t *spin; uint32_t handle[3]; uint32_t read, write; uint32_t active; @@ -179,7 +112,8 @@ static void semaphore(int fd, unsigned ring, uint32_t flags) gem_write(fd, handle[BATCH], 0, &bbe, sizeof(bbe)); /* Create a long running batch which we can use to hog the GPU */ - handle[BUSY] = busy_blt(fd); + handle[BUSY] = gem_create(fd, 4096); + spin = igt_spin_batch_new(fd, 0, ring, handle[BUSY]); /* Queue a batch after the busy, it should block and remain "busy" */ igt_assert(exec_noop(fd, handle, ring | flags, false)); @@ -208,6 +142,7 @@ static void semaphore(int fd, unsigned ring, uint32_t flags) /* Check that our long batch was long enough */ igt_assert(still_busy(fd, handle[BUSY])); + igt_spin_batch_free(fd, spin); /* And make sure it becomes idle again */ gem_sync(fd, handle[TEST]); @@ -364,47 +299,146 @@ static void xchg_u32(void *array, unsigned i, unsigned j) u32[j] = tmp; } +struct cork { + int device; + uint32_t handle; + uint32_t fence; +}; + +static void plug(int fd, struct cork *c) +{ + struct vgem_bo bo; + int dmabuf; + + c->device = drm_open_driver(DRIVER_VGEM); + + bo.width = bo.height = 1; + bo.bpp = 4; + vgem_create(c->device, &bo); + c->fence = vgem_fence_attach(c->device, &bo, VGEM_FENCE_WRITE); + + dmabuf = prime_handle_to_fd(c->device, bo.handle); + c->handle = prime_fd_to_handle(fd, dmabuf); + close(dmabuf); +} + +static void unplug(struct cork *c) +{ + vgem_fence_signal(c->device, c->fence); + close(c->device); +} + +static void alarm_handler(int sig) +{ +} + +static int __execbuf(int fd, struct drm_i915_gem_execbuffer2 *execbuf) +{ + return ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, execbuf); +} + +static unsigned int measure_ring_size(int fd) +{ + struct sigaction sa = { .sa_handler = alarm_handler }; + struct drm_i915_gem_exec_object2 obj[2]; + struct drm_i915_gem_execbuffer2 execbuf; + const uint32_t bbe = MI_BATCH_BUFFER_END; + unsigned int count, last; + struct itimerval itv; + struct cork c; + + memset(obj, 0, sizeof(obj)); + obj[1].handle = gem_create(fd, 4096); + gem_write(fd, obj[1].handle, 0, &bbe, sizeof(bbe)); + + memset(&execbuf, 0, sizeof(execbuf)); + execbuf.buffers_ptr = to_user_pointer(obj + 1); + execbuf.buffer_count = 1; + gem_execbuf(fd, &execbuf); + gem_sync(fd, obj[1].handle); + + plug(fd, &c); + obj[0].handle = c.handle; + + execbuf.buffers_ptr = to_user_pointer(obj); + execbuf.buffer_count = 2; + + sigaction(SIGALRM, &sa, NULL); + itv.it_interval.tv_sec = 0; + itv.it_interval.tv_usec = 100; + itv.it_value.tv_sec = 0; + itv.it_value.tv_usec = 1000; + setitimer(ITIMER_REAL, &itv, NULL); + + last = -1; + count = 0; + do { + if (__execbuf(fd, &execbuf) == 0) { + count++; + continue; + } + + if (last == count) + break; + + last = count; + } while (1); + + memset(&itv, 0, sizeof(itv)); + setitimer(ITIMER_REAL, &itv, NULL); + + unplug(&c); + gem_close(fd, obj[1].handle); + gem_quiescent_gpu(fd); + + return count; +} + static void close_race(int fd) { -#define N_HANDLES 4096 - const int ncpus = sysconf(_SC_NPROCESSORS_ONLN); - uint32_t *handles; + const unsigned int ncpus = sysconf(_SC_NPROCESSORS_ONLN); + const unsigned int nhandles = measure_ring_size(fd) / 2; + unsigned int engines[16], nengine; unsigned long *control; - unsigned long count = 0; + uint32_t *handles; int i; - intel_require_memory(N_HANDLES, 4096, CHECK_RAM); + igt_require(ncpus > 1); + intel_require_memory(nhandles, 4096, CHECK_RAM); - /* One thread spawning work and randomly closing fd. + /* + * One thread spawning work and randomly closing handles. * One background thread per cpu checking busyness. */ + nengine = 0; + for_each_engine(fd, i) + engines[nengine++] = i; + igt_require(nengine); + control = mmap(NULL, 4096, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); igt_assert(control != MAP_FAILED); - handles = mmap(NULL, N_HANDLES*sizeof(*handles), + handles = mmap(NULL, PAGE_ALIGN(nhandles*sizeof(*handles)), PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); igt_assert(handles != MAP_FAILED); - for (i = 0; i < N_HANDLES; i++) { - handles[i] = gem_create(fd, 4096); - } - - igt_fork(child, ncpus) { + igt_fork(child, ncpus - 1) { struct drm_i915_gem_busy busy; - uint32_t indirection[N_HANDLES]; + uint32_t indirection[nhandles]; + unsigned long count = 0; - for (i = 0; i < N_HANDLES; i++) + for (i = 0; i < nhandles; i++) indirection[i] = i; hars_petruska_f54_1_random_perturb(child); memset(&busy, 0, sizeof(busy)); do { - igt_permute_array(indirection, N_HANDLES, xchg_u32); + igt_permute_array(indirection, nhandles, xchg_u32); __sync_synchronize(); - for (i = 0; i < N_HANDLES; i++) { - busy.handle = indirection[handles[i]]; + for (i = 0; i < nhandles; i++) { + busy.handle = handles[indirection[i]]; /* Check that the busy computation doesn't * explode in the face of random gem_close(). */ @@ -414,30 +448,47 @@ static void close_race(int fd) } while(*(volatile long *)control == 0); igt_debug("child[%d]: count = %lu\n", child, count); - control[child] = count; + control[child + 1] = count; } - igt_until_timeout(20) { - int j = rand() % N_HANDLES; + igt_fork(child, 1) { + struct sched_param rt = {.sched_priority = 99 }; + igt_spin_t *spin[nhandles]; + unsigned long count = 0; + + igt_assert(sched_setscheduler(getpid(), SCHED_RR, &rt) == 0); + + for (i = 0; i < nhandles; i++) { + spin[i] = igt_spin_batch_new(fd, 0, + engines[rand() % nengine], 0); + handles[i] = spin[i]->handle; + } - gem_close(fd, handles[j]); + igt_until_timeout(20) { + for (i = 0; i < nhandles; i++) { + igt_spin_batch_free(fd, spin[i]); + spin[i] = igt_spin_batch_new(fd, 0, + engines[rand() % nengine], + 0); + handles[i] = spin[i]->handle; + __sync_synchronize(); + } + count += nhandles; + } + control[0] = count; __sync_synchronize(); - handles[j] = busy_blt(fd); - count++; + for (i = 0; i < nhandles; i++) + igt_spin_batch_free(fd, spin[i]); } - control[0] = 1; igt_waitchildren(); - for (i = 0; i < ncpus; i++) - control[ncpus + 1] += control[i + 1]; + for (i = 0; i < ncpus - 1; i++) + control[ncpus] += control[i + 1]; igt_info("Total execs %lu, busy-ioctls %lu\n", - count, control[ncpus + 1] * N_HANDLES); - - for (i = 0; i < N_HANDLES; i++) - gem_close(fd, handles[i]); + control[0], control[ncpus] * nhandles); - munmap(handles, N_HANDLES * sizeof(*handles)); + munmap(handles, PAGE_ALIGN(nhandles * sizeof(*handles))); munmap(control, 4096); gem_quiescent_gpu(fd); |