tests/gem_evict_everything: add swapping and forked subtests
authorDaniel Vetter <daniel.vetter@ffwll.ch>
Thu, 29 Aug 2013 19:44:28 +0000 (21:44 +0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Thu, 29 Aug 2013 19:44:28 +0000 (21:44 +0200)
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>
tests/gem_evict_everything.c

index bf93e70..63b2d46 100644 (file)
@@ -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;