diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2013-08-29 21:44:28 +0200 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2013-08-29 21:44:28 +0200 |
commit | 8f5d54162086d9832bcd574af155e86a1a4d743f (patch) | |
tree | 4f052b4f73283854ceb6de1bc96880453ad12b2f | |
parent | 5fe116e913192d092d3d73872484a2136217d6f1 (diff) |
tests/gem_evict_everything: add swapping and forked subtests
Much better at hitting the list corruption here on my machines
than what we have thus far.
Note that somehow I just can't reproduce the bug any more. No idea
why. But I guess it's time to simply push this pile out.
v2: Limit threads and rounds to something reasonable.
v3: Use igt_permute_array to avoid EINVAL due to duplicated bo.
v4:
- Add a variant of the forked tests with multiple drm fds.
- Tune the swapped forked tests a bit to complete in a reasonable
amount of time.
v5: Add some memory pressure from the cpu by using cpu mmaps (which
directly hit shmem, so bypass gem completely).
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r-- | tests/gem_evict_everything.c | 166 |
1 files changed, 157 insertions, 9 deletions
diff --git a/tests/gem_evict_everything.c b/tests/gem_evict_everything.c index bf93e70d..63b2d464 100644 --- a/tests/gem_evict_everything.c +++ b/tests/gem_evict_everything.c @@ -118,6 +118,134 @@ copy(int fd, uint32_t dst, uint32_t src, uint32_t *all_bo, int n_bo, int error) free(obj); } +static void exchange_uint32_t(void *array, unsigned i, unsigned j) +{ + uint32_t *i_arr = array; + uint32_t i_tmp; + + i_tmp = i_arr[i]; + i_arr[i] = i_arr[j]; + i_arr[j] = i_tmp; +} + +#define min(a, b) ((a) < (b) ? (a) : (b)) + +#define INTERRUPTIBLE (1 << 0) +#define SWAPPING (1 << 1) +#define DUP_DRMFD (1 << 2) +#define MEMORY_PRESSURE (1 << 3) +#define ALL_FLAGS (INTERRUPTIBLE | SWAPPING | DUP_DRMFD | MEMORY_PRESSURE) + +static void forked_evictions(int fd, int size, int count, + unsigned flags) +{ + uint32_t *bo; + int n, pass, l; + int num_threads = sysconf(_SC_NPROCESSORS_ONLN); + int bo_count; + + igt_require((uint64_t)count * size / (1024 * 1024) < intel_get_total_ram_mb() * 9 / 10); + + if (flags & SWAPPING) { + igt_require(intel_get_total_ram_mb() / 4 < intel_get_total_swap_mb()); + bo_count = intel_get_total_ram_mb() * 11 / 10; + + if (bo_count < count) + bo_count = count; + } else + bo_count = count; + + bo = malloc(bo_count*sizeof(*bo)); + igt_assert(bo); + + for (n = 0; n < bo_count; n++) + bo[n] = gem_create(fd, size); + + igt_fork(i, min(count, num_threads * 4)) { + int realfd = fd; + int num_passes = flags & SWAPPING ? 10 : 100; + + /* Every fork should have a different permutation! */ + srand(i * 63); + + if (flags & INTERRUPTIBLE) + igt_fork_signal_helper(); + + igt_permute_array(bo, bo_count, exchange_uint32_t); + + if (flags & DUP_DRMFD) { + realfd = drm_open_any(); + + /* We can overwrite the bo array since we're forked. */ + for (l = 0; l < count; l++) { + uint32_t flink; + + flink = gem_flink(fd, bo[l]); + bo[l] = gem_open(realfd, flink); + } + + } + + for (pass = 0; pass < num_passes; pass++) { + copy(realfd, bo[0], bo[1], bo, count, 0); + + for (l = 0; l < count && (flags & MEMORY_PRESSURE); l++) { + uint32_t *base = gem_mmap__cpu(realfd, bo[l], + size, + PROT_READ | PROT_WRITE); + memset(base, 0, size); + munmap(base, size); + } + } + + if (flags & INTERRUPTIBLE) + igt_stop_signal_helper(); + + /* drmfd closing will take care of additional bo refs */ + if (flags & DUP_DRMFD) + close(realfd); + } + + igt_waitchildren(); + + for (n = 0; n < bo_count; n++) + gem_close(fd, bo[n]); + free(bo); +} + +static void swapping_evictions(int fd, int size, int count) +{ + uint32_t *bo; + int i, n, pass; + int bo_count; + + igt_require((uint64_t)count * size / (1024 * 1024) < intel_get_total_ram_mb() * 9 / 10); + + igt_require(intel_get_total_ram_mb() / 4 < intel_get_total_swap_mb()); + bo_count = intel_get_total_ram_mb() * 11 / 10; + + if (bo_count < count) + bo_count = count; + + bo = malloc(bo_count*sizeof(*bo)); + igt_assert(bo); + + for (n = 0; n < bo_count; n++) + bo[n] = gem_create(fd, size); + + for (i = 0; i < bo_count/32; i++) { + igt_permute_array(bo, bo_count, exchange_uint32_t); + + for (pass = 0; pass < 100; pass++) { + copy(fd, bo[0], bo[1], bo, count, 0); + } + } + + for (n = 0; n < bo_count; n++) + gem_close(fd, bo[n]); + free(bo); +} + static void minor_evictions(int fd, int size, int count) { uint32_t *bo, *sel; @@ -169,38 +297,58 @@ static void major_evictions(int fd, int size, int count) free(bo); } -int fd; - int main(int argc, char **argv) { - int size, count; + int size, count, fd; + size = count = 0; + fd = -1; igt_subtest_init(argc, argv); igt_skip_on_simulation(); - igt_fixture + igt_fixture { fd = drm_open_any(); - igt_subtest("minor-normal") { size = 1024 * 1024; count = 3*gem_aperture_size(fd) / size / 4; - minor_evictions(fd, size, count); } + for (unsigned flags = 0; flags < ALL_FLAGS + 1; flags++) { + igt_subtest_f("forked%s%s%s-%s", + flags & SWAPPING ? "-swapping" : "", + flags & DUP_DRMFD ? "-multifd" : "", + flags & MEMORY_PRESSURE ? "-mempressure" : "", + flags & INTERRUPTIBLE ? "interruptible" : "normal") { + forked_evictions(fd, size, count, flags); + } + } + + igt_subtest("swapping-normal") + swapping_evictions(fd, size, count); + + igt_subtest("minor-normal") + minor_evictions(fd, size, count); + igt_subtest("major-normal") { size = 3*gem_aperture_size(fd) / 4; count = 4; major_evictions(fd, size, count); } - igt_fork_signal_helper(); - igt_subtest("minor-interruptible") { + igt_fixture { size = 1024 * 1024; count = 3*gem_aperture_size(fd) / size / 4; - minor_evictions(fd, size, count); } + igt_fork_signal_helper(); + + igt_subtest("swapping-interruptible") + swapping_evictions(fd, size, count); + + igt_subtest("minor-interruptible") + minor_evictions(fd, size, count); + igt_subtest("major-interruptible") { size = 3*gem_aperture_size(fd) / 4; count = 4; |