summaryrefslogtreecommitdiff
path: root/tests/gem_evict_everything.c
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2013-08-29 21:44:28 +0200
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-08-29 21:44:28 +0200
commit8f5d54162086d9832bcd574af155e86a1a4d743f (patch)
tree4f052b4f73283854ceb6de1bc96880453ad12b2f /tests/gem_evict_everything.c
parent5fe116e913192d092d3d73872484a2136217d6f1 (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>
Diffstat (limited to 'tests/gem_evict_everything.c')
-rw-r--r--tests/gem_evict_everything.c166
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;