* [PATCH i-g-t] tests/gem_shrink: Exercise OOM and other routes to shrinking in reasonable time
@ 2019-01-04 15:37 Tvrtko Ursulin
2019-01-07 11:01 ` [igt-dev] " Petri Latvala
` (2 more replies)
0 siblings, 3 replies; 12+ messages in thread
From: Tvrtko Ursulin @ 2019-01-04 15:37 UTC (permalink / raw)
To: igt-dev; +Cc: Intel-gfx
From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
A set of subtests which exercises different paths to our shrinker code
(including the OOM killer) in predictable and reasonable time budget.
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
lib/igt_core.c | 19 ++
lib/igt_core.h | 1 +
tests/i915/gem_shrink.c | 399 ++++++++++++++++++++++++++
tests/intel-ci/blacklist.txt | 1 +
tests/intel-ci/fast-feedback.testlist | 3 +
5 files changed, 423 insertions(+)
diff --git a/lib/igt_core.c b/lib/igt_core.c
index 50d6008f6c82..351da0b4e020 100644
--- a/lib/igt_core.c
+++ b/lib/igt_core.c
@@ -1685,6 +1685,25 @@ void igt_stop_helper(struct igt_helper_process *proc)
assert(helper_was_alive(proc, status));
}
+/**
+ * igt_try_stop_helper:
+ * @proc: #igt_helper_process structure
+ *
+ * Terminates a helper process if it is still running and returns true, or false
+ * if the process wasn't running.
+ */
+bool igt_try_stop_helper(struct igt_helper_process *proc)
+{
+ int status;
+
+ /* failure here means the pid is already dead and so waiting is safe */
+ kill(proc->pid, proc->use_SIGKILL ? SIGKILL : SIGTERM);
+
+ status = igt_wait_helper(proc);
+
+ return helper_was_alive(proc, status);
+}
+
static void children_exit_handler(int sig)
{
int status;
diff --git a/lib/igt_core.h b/lib/igt_core.h
index 6f8c3852a686..ed5ceebf1205 100644
--- a/lib/igt_core.h
+++ b/lib/igt_core.h
@@ -795,6 +795,7 @@ bool __igt_fork_helper(struct igt_helper_process *proc);
for (; __igt_fork_helper(proc); exit(0))
int igt_wait_helper(struct igt_helper_process *proc);
void igt_stop_helper(struct igt_helper_process *proc);
+bool igt_try_stop_helper(struct igt_helper_process *proc);
/* exit handler code */
diff --git a/tests/i915/gem_shrink.c b/tests/i915/gem_shrink.c
index c8e05814ee70..7c002de0ef1f 100644
--- a/tests/i915/gem_shrink.c
+++ b/tests/i915/gem_shrink.c
@@ -26,6 +26,10 @@
*
* Exercise the shrinker by overallocating GEM objects
*/
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
#include "igt.h"
#include "igt_gt.h"
@@ -366,6 +370,376 @@ static void reclaim(unsigned engine, int timeout)
close(fd);
}
+static unsigned long get_meminfo(const char *info, const char *tag)
+{
+ const char *str;
+ unsigned long val;
+
+ str = strstr(info, tag);
+ if (str && sscanf(str + strlen(tag), " %lu", &val) == 1)
+ return val >> 10;
+
+ igt_warn("Unrecognised /proc/meminfo field: '%s'\n", tag);
+ return 0;
+}
+
+static unsigned long get_avail_ram_mb(void)
+{
+ int fd;
+ int ret;
+ char buf[4096];
+ unsigned long ram;
+
+ fd = open("/proc/meminfo", O_RDONLY);
+ igt_assert_fd(fd);
+
+ ret = read(fd, buf, sizeof(buf));
+ igt_assert(ret >= 0);
+
+ close(fd);
+
+ ram = get_meminfo(buf, "MemAvailable:");
+ ram += get_meminfo(buf, "Buffers:");
+ ram += get_meminfo(buf, "Cached:");
+ ram += get_meminfo(buf, "SwapCached:");
+
+ return ram;
+}
+
+struct test {
+#define TEST_BO (1)
+#define TEST_USERPTR (2)
+ unsigned int flags;
+ int fd;
+};
+
+static uint32_t __get_pages(int fd, unsigned long alloc)
+{
+ uint32_t handle = gem_create(fd, alloc);
+
+ gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, 0);
+ gem_madvise(fd, handle, I915_MADV_DONTNEED);
+
+ return handle;
+}
+
+struct test_obj {
+ void *ptr;
+ uint32_t handle;
+};
+
+#define PAGE_SIZE 4096
+static void
+__get_userptr(int fd, struct test_obj *obj, unsigned long sz)
+{
+ struct local_i915_gem_userptr userptr = { };
+ void *ptr;
+
+ igt_assert_eq(sz & 4095, 0);
+
+ ptr = mmap(NULL, sz, PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ assert(ptr != MAP_FAILED);
+
+ for (size_t page = 0; page < sz; page += PAGE_SIZE)
+ *(volatile uint32_t *)((unsigned char *)ptr + page) = 0;
+
+ userptr.user_size = sz;
+ userptr.user_ptr = to_user_pointer(ptr);
+ do_ioctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
+
+ gem_set_domain(fd, userptr.handle, I915_GEM_DOMAIN_GTT, 0);
+ gem_madvise(fd, userptr.handle, I915_MADV_DONTNEED);
+
+ obj->ptr = ptr;
+ obj->handle = userptr.handle;
+}
+
+/*
+ * Use a specific way of using up memory until we are below a certain threshold.
+ */
+static void *mempressure(void *arg)
+{
+ const unsigned int free_threshold_mb = 256;
+ struct test_obj *list = NULL;
+ struct test *test = arg;
+ const unsigned int sz_mb = 2;
+ const unsigned int sz = sz_mb << 20;
+ unsigned int n = 0, max = 0;
+ unsigned int blocks;
+
+ for (;;) {
+ unsigned long ram_mb = get_avail_ram_mb();
+
+ if (!list) {
+ /*
+ * On first pass estimate how many sz_mb sized blocks
+ * we could need to use up all RAM.
+ */
+ blocks = ram_mb / sz_mb;
+ list = calloc(blocks, sizeof(*list));
+ igt_assert(list);
+ } else if (ram_mb < free_threshold_mb) {
+ /* Limit the working set once under the threshold. */
+ blocks = max + 1;
+ }
+
+ /* Free the oldest block once the working set wrapped. */
+ if (list[n].ptr || list[n].handle) {
+ if (test->flags & TEST_USERPTR) {
+ munmap(list[n].ptr, sz);
+ gem_close(test->fd, list[n].handle);
+ } else if (test->flags & TEST_BO) {
+ gem_close(test->fd, list[n].handle);
+ } else {
+ munmap(list[n].ptr, sz);
+ }
+ }
+
+ /*
+ * Allocate memory blocks and record the current working set
+ * size.
+ */
+ if (test->flags & TEST_BO) {
+ list[n].handle = __get_pages(test->fd, sz);
+ } else if (test->flags & TEST_USERPTR) {
+ __get_userptr(test->fd, &list[n], sz);
+ } else {
+ list[n].ptr = mmap(NULL, sz, PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ assert(list[n].ptr != MAP_FAILED);
+
+ madvise(list[n].ptr, sz, MADV_HUGEPAGE);
+
+ for (size_t page = 0; page < sz; page += PAGE_SIZE)
+ *(volatile uint32_t *)((unsigned char *)list[n].ptr + page) = 0;
+ }
+
+ if (n > max)
+ max = n;
+
+ n++;
+
+ /*
+ * Start freeing the oldest and reallocating once maximum
+ * working set size has been reached.
+ */
+ if (n >= blocks)
+ n = 0;
+ }
+
+ return NULL;
+}
+
+static void oom_adjust(const char *score)
+{
+ int fd;
+
+ fd = open("/proc/self/oom_score_adj", O_WRONLY);
+ igt_assert_fd(fd);
+ igt_assert(write(fd, score, sizeof(score)) == sizeof(score));
+ close(fd);
+}
+
+static void trigger_oom(void)
+{
+ const char *cmd = "f";
+ int fd;
+
+ fd = open("/proc/sysrq-trigger", O_WRONLY);
+ igt_assert_fd(fd);
+ igt_assert(write(fd, cmd, sizeof(cmd)) == sizeof(cmd));
+ close(fd);
+}
+
+static bool has_sysrq_trigger(void)
+{
+ int fd;
+
+ fd = open("/proc/sysrq-trigger", O_WRONLY);
+ close(fd);
+
+ return fd >= 0;
+}
+
+/*
+ * Exercise different paths to our shrinker code, including OOM, in predictable
+ * and reasonable time budget.
+ */
+static void reclaim_oom(unsigned int flags, unsigned int passes)
+{
+ unsigned int count = 0;
+
+ oom_adjust("-1000");
+
+ do {
+ struct igt_helper_process gem_child = { .use_SIGKILL = true };
+ struct igt_helper_process mem_child = { .use_SIGKILL = true };
+ struct igt_helper_process eb_child = { .use_SIGKILL = true };
+ struct igt_helper_process drop_child = { .use_SIGKILL = true };
+
+ igt_debug("Iteration %u...\n", ++count);
+
+ /*
+ * Apply either anon backed or shmem backed memory pressure
+ * to the amount to use up almost all available RAM.
+ */
+ igt_fork_helper(&mem_child) {
+ struct test test = { };
+
+ if ((flags & (TEST_BO | TEST_USERPTR)) ==
+ (TEST_BO | TEST_USERPTR))
+ test.flags = TEST_BO;
+
+ /* Sacrifice the memory hog if it comes to that. */
+ oom_adjust("500");
+
+ if (test.flags == TEST_BO) {
+ test.fd = drm_open_driver_render(DRIVER_INTEL);
+ igt_require_gem(test.fd);
+ }
+
+ mempressure(&test);
+
+ if (test.flags == TEST_BO)
+ close(test.fd);
+ }
+
+ /*
+ * Apply either userptr backed or shmem backed memory pressure
+ * to the amount to use up almost all available RAM.
+ */
+ igt_fork_helper(&gem_child) {
+ struct test test = { .flags = flags };
+
+ if ((flags & (TEST_BO | TEST_USERPTR)) ==
+ (TEST_BO | TEST_USERPTR))
+ test.flags = TEST_USERPTR;
+
+ /* Sacrifice the memory hog if it comes to that. */
+ oom_adjust("500");
+
+ test.fd = drm_open_driver_render(DRIVER_INTEL);
+ igt_require_gem(test.fd);
+
+ mempressure(&test);
+
+ close(test.fd);
+ }
+
+ /*
+ * Apply an execbuf load to exercise the request allocation and
+ * direct reclaim from this path.
+ *
+ * Occasionaly sync with execution and pause for a little bit to
+ * avoid hogging to much from this client.
+ */
+ igt_fork_helper(&eb_child) {
+ struct test test = { .flags = flags };
+ const uint32_t bbe = MI_BATCH_BUFFER_END;
+ struct drm_i915_gem_exec_object2 obj = { };
+ struct drm_i915_gem_execbuffer2 execbuf = { };
+
+ execbuf.buffers_ptr = to_user_pointer(&obj);
+ execbuf.buffer_count = 1;
+
+ test.fd = drm_open_driver_render(DRIVER_INTEL);
+ igt_require_gem(test.fd);
+
+ for (;;) {
+ unsigned long eb = 0;
+ struct timespec ts = { };
+ unsigned long start;
+
+ igt_nsec_elapsed(&ts);
+ start = igt_nsec_elapsed(&ts) / 1e6;
+
+ for (;;) {
+ unsigned long now;
+
+ obj.handle = gem_create(test.fd, 4096);
+ gem_write(test.fd, obj.handle, 0, &bbe,
+ sizeof(bbe));
+ gem_execbuf(test.fd, &execbuf);
+ eb++;
+ now = igt_nsec_elapsed(&ts) / 1e6;
+ if (now > (start + 1000)) {
+ gem_sync(test.fd, obj.handle);
+ if (now > (start + 2000)) {
+ gem_close(test.fd,
+ obj.handle);
+ break;
+ }
+ }
+ gem_close(test.fd, obj.handle);
+ }
+
+ igt_debug("%lu execbufs\n", eb);
+ usleep(500e3);
+ }
+
+ close(test.fd);
+ }
+
+ /*
+ * Manually drop cached with the DROP_ACTIVE flag set every now
+ * and then in order to exercise this path as well.
+ */
+ igt_fork_helper(&drop_child) {
+ int fd;
+
+ fd = drm_open_driver(DRIVER_INTEL);
+ igt_require_gem(fd);
+
+ for (;;) {
+ usleep(334e3);
+ igt_debug("Dropping caches...\n");
+ igt_drop_caches_set(fd, DROP_ACTIVE);
+ }
+
+ close(fd);
+ }
+
+ /*
+ * When memory pressure clients have managed to use up all
+ * available RAM, let them run for a brief moment yet and then
+ * manually trigger the OOM condition.
+ */
+ for (unsigned long ram_mb = 0;
+ (ram_mb = get_avail_ram_mb()) > 512;) {
+ int status;
+ pid_t pid;
+
+ igt_debug("[%u] %lu MiB free\n", count, ram_mb);
+
+ pid = waitpid(mem_child.pid, &status, WNOHANG);
+ if (pid)
+ break;
+
+ pid = waitpid(gem_child.pid, &status, WNOHANG);
+ if (pid)
+ break;
+
+ pid = waitpid(eb_child.pid, &status, WNOHANG);
+ igt_assert_eq(pid, 0);
+
+ pid = waitpid(drop_child.pid, &status, WNOHANG);
+ igt_assert_eq(pid, 0);
+
+ sleep(1);
+ }
+
+ igt_debug("Triggering OOM...\n");
+ trigger_oom();
+
+ sleep(1);
+
+ igt_try_stop_helper(&mem_child);
+ igt_try_stop_helper(&gem_child);
+ igt_stop_helper(&eb_child);
+ igt_stop_helper(&drop_child);
+ } while (count < passes);
+}
+
igt_main
{
const struct test {
@@ -432,6 +806,31 @@ igt_main
igt_subtest("reclaim")
reclaim(I915_EXEC_DEFAULT, 2);
+ igt_subtest_group {
+ struct {
+ const char *name;
+ unsigned int flags;
+ unsigned int passes;
+ } *p, passes[] = {
+ { "reclaims-and-oom-basic", TEST_BO, 1 },
+ { "reclaims-and-oom", TEST_BO, 3 },
+ { "reclaims-and-oom-userptr-basic", TEST_USERPTR, 1 },
+ { "reclaims-and-oom-userptr", TEST_USERPTR, 3 },
+ { "reclaims-and-oom-both-basic", TEST_BO | TEST_USERPTR, 1 },
+ { "reclaims-and-oom-both", TEST_BO | TEST_USERPTR, 3 },
+ { NULL, 0, 0 },
+ };
+
+ igt_fixture {
+ igt_require(has_sysrq_trigger());
+ }
+
+ for (p = passes; p->name; p++) {
+ igt_subtest(p->name)
+ reclaim_oom(p->flags, p->passes);
+ }
+ }
+
for(const struct test *t = tests; t->name; t++) {
for(const struct mode *m = modes; m->suffix; m++) {
igt_subtest_f("%s%s", t->name, m->suffix)
diff --git a/tests/intel-ci/blacklist.txt b/tests/intel-ci/blacklist.txt
index 73d127603d28..d76a4b3b1c71 100644
--- a/tests/intel-ci/blacklist.txt
+++ b/tests/intel-ci/blacklist.txt
@@ -60,6 +60,7 @@ igt@gem_ring_sync_copy(@.*)?
igt@gem_ring_sync_loop(@.*)?
igt@gem_seqno_wrap(@.*)?
igt@gem_shrink@(?!reclaim$).*
+igt@gem_shrink@(?!reclaims-and-oom).*
igt@gem_softpin@.*(hang|S4).*
igt@gem_spin_batch(@.*)?
igt@gem_stolen@.*hibernate.*
diff --git a/tests/intel-ci/fast-feedback.testlist b/tests/intel-ci/fast-feedback.testlist
index 6d42792c67f7..0df7cc2fd9fd 100644
--- a/tests/intel-ci/fast-feedback.testlist
+++ b/tests/intel-ci/fast-feedback.testlist
@@ -124,6 +124,9 @@ igt@gem_ringfill@basic-default
igt@gem_ringfill@basic-default-interruptible
igt@gem_ringfill@basic-default-forked
igt@gem_ringfill@basic-default-fd
+igt@gem_shrink@reclaims-and-oom-basic
+igt@gem_shrink@reclaims-and-oom-userptr-basic
+igt@gem_shrink@reclaims-and-oom-both-basic
igt@gem_sync@basic-all
igt@gem_sync@basic-each
igt@gem_sync@basic-many-each
--
2.19.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [igt-dev] [PATCH i-g-t] tests/gem_shrink: Exercise OOM and other routes to shrinking in reasonable time
2019-01-04 15:37 [PATCH i-g-t] tests/gem_shrink: Exercise OOM and other routes to shrinking in reasonable time Tvrtko Ursulin
@ 2019-01-07 11:01 ` Petri Latvala
2019-01-07 11:12 ` Tvrtko Ursulin
2019-01-07 12:27 ` Michał Winiarski
2019-01-07 17:36 ` [PATCH i-g-t v2] " Tvrtko Ursulin
2 siblings, 1 reply; 12+ messages in thread
From: Petri Latvala @ 2019-01-07 11:01 UTC (permalink / raw)
To: Tvrtko Ursulin; +Cc: igt-dev, Intel-gfx
On Fri, Jan 04, 2019 at 03:37:09PM +0000, Tvrtko Ursulin wrote:
> diff --git a/tests/intel-ci/blacklist.txt b/tests/intel-ci/blacklist.txt
> index 73d127603d28..d76a4b3b1c71 100644
> --- a/tests/intel-ci/blacklist.txt
> +++ b/tests/intel-ci/blacklist.txt
> @@ -60,6 +60,7 @@ igt@gem_ring_sync_copy(@.*)?
> igt@gem_ring_sync_loop(@.*)?
> igt@gem_seqno_wrap(@.*)?
> igt@gem_shrink@(?!reclaim$).*
> +igt@gem_shrink@(?!reclaims-and-oom).*
> igt@gem_softpin@.*(hang|S4).*
> igt@gem_spin_batch(@.*)?
> igt@gem_stolen@.*hibernate.*
In case you didn't notice: The first gem_shrink line removes the
reclaims-and-oom* subtests, and the second line (the one you added)
then removes the 'reclaim' subtest, resulting in all gem_shrink
subtests blacklisted.
--
Petri Latvala
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [igt-dev] [PATCH i-g-t] tests/gem_shrink: Exercise OOM and other routes to shrinking in reasonable time
2019-01-07 11:01 ` [igt-dev] " Petri Latvala
@ 2019-01-07 11:12 ` Tvrtko Ursulin
2019-01-07 11:28 ` Petri Latvala
0 siblings, 1 reply; 12+ messages in thread
From: Tvrtko Ursulin @ 2019-01-07 11:12 UTC (permalink / raw)
To: igt-dev, Intel-gfx, Tvrtko Ursulin
On 07/01/2019 11:01, Petri Latvala wrote:
> On Fri, Jan 04, 2019 at 03:37:09PM +0000, Tvrtko Ursulin wrote:
>> diff --git a/tests/intel-ci/blacklist.txt b/tests/intel-ci/blacklist.txt
>> index 73d127603d28..d76a4b3b1c71 100644
>> --- a/tests/intel-ci/blacklist.txt
>> +++ b/tests/intel-ci/blacklist.txt
>> @@ -60,6 +60,7 @@ igt@gem_ring_sync_copy(@.*)?
>> igt@gem_ring_sync_loop(@.*)?
>> igt@gem_seqno_wrap(@.*)?
>> igt@gem_shrink@(?!reclaim$).*
>> +igt@gem_shrink@(?!reclaims-and-oom).*
>> igt@gem_softpin@.*(hang|S4).*
>> igt@gem_spin_batch(@.*)?
>> igt@gem_stolen@.*hibernate.*
>
>
> In case you didn't notice: The first gem_shrink line removes the
> reclaims-and-oom* subtests, and the second line (the one you added)
> then removes the 'reclaim' subtest, resulting in all gem_shrink
> subtests blacklisted.
No I haven't thank you. Interestingly the reclaim subtest still did run.
Okay, but in essence should this work then:
igt@gem_shrink@(?!reclaim).*
To blacklist everything apart from reclaims and reclaims-and-oom.* subtests?
Regards,
Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [igt-dev] [PATCH i-g-t] tests/gem_shrink: Exercise OOM and other routes to shrinking in reasonable time
2019-01-07 11:12 ` Tvrtko Ursulin
@ 2019-01-07 11:28 ` Petri Latvala
2019-01-07 17:33 ` Tvrtko Ursulin
0 siblings, 1 reply; 12+ messages in thread
From: Petri Latvala @ 2019-01-07 11:28 UTC (permalink / raw)
To: Tvrtko Ursulin; +Cc: igt-dev, Intel-gfx
On Mon, Jan 07, 2019 at 11:12:30AM +0000, Tvrtko Ursulin wrote:
>
> On 07/01/2019 11:01, Petri Latvala wrote:
> > On Fri, Jan 04, 2019 at 03:37:09PM +0000, Tvrtko Ursulin wrote:
> > > diff --git a/tests/intel-ci/blacklist.txt b/tests/intel-ci/blacklist.txt
> > > index 73d127603d28..d76a4b3b1c71 100644
> > > --- a/tests/intel-ci/blacklist.txt
> > > +++ b/tests/intel-ci/blacklist.txt
> > > @@ -60,6 +60,7 @@ igt@gem_ring_sync_copy(@.*)?
> > > igt@gem_ring_sync_loop(@.*)?
> > > igt@gem_seqno_wrap(@.*)?
> > > igt@gem_shrink@(?!reclaim$).*
> > > +igt@gem_shrink@(?!reclaims-and-oom).*
> > > igt@gem_softpin@.*(hang|S4).*
> > > igt@gem_spin_batch(@.*)?
> > > igt@gem_stolen@.*hibernate.*
> >
> >
> > In case you didn't notice: The first gem_shrink line removes the
> > reclaims-and-oom* subtests, and the second line (the one you added)
> > then removes the 'reclaim' subtest, resulting in all gem_shrink
> > subtests blacklisted.
>
> No I haven't thank you. Interestingly the reclaim subtest still did run.
https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2185/shards-all.html
it's NOTRUN on all machines on patched IGT.
> Okay, but in essence should this work then:
>
> igt@gem_shrink@(?!reclaim).*
>
> To blacklist everything apart from reclaims and reclaims-and-oom.*
> subtests?
Yeah that looks correct.
--
Petri Latvala
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [igt-dev] [PATCH i-g-t] tests/gem_shrink: Exercise OOM and other routes to shrinking in reasonable time
2019-01-04 15:37 [PATCH i-g-t] tests/gem_shrink: Exercise OOM and other routes to shrinking in reasonable time Tvrtko Ursulin
2019-01-07 11:01 ` [igt-dev] " Petri Latvala
@ 2019-01-07 12:27 ` Michał Winiarski
2019-01-07 12:31 ` Chris Wilson
2019-01-07 17:36 ` [PATCH i-g-t v2] " Tvrtko Ursulin
2 siblings, 1 reply; 12+ messages in thread
From: Michał Winiarski @ 2019-01-07 12:27 UTC (permalink / raw)
To: Tvrtko Ursulin; +Cc: igt-dev, Intel-gfx
On Fri, Jan 04, 2019 at 03:37:09PM +0000, Tvrtko Ursulin wrote:
> From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>
> A set of subtests which exercises different paths to our shrinker code
> (including the OOM killer) in predictable and reasonable time budget.
>
> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> ---
> lib/igt_core.c | 19 ++
> lib/igt_core.h | 1 +
> tests/i915/gem_shrink.c | 399 ++++++++++++++++++++++++++
> tests/intel-ci/blacklist.txt | 1 +
> tests/intel-ci/fast-feedback.testlist | 3 +
> 5 files changed, 423 insertions(+)
[snip]
> diff --git a/tests/i915/gem_shrink.c b/tests/i915/gem_shrink.c
> index c8e05814ee70..7c002de0ef1f 100644
> --- a/tests/i915/gem_shrink.c
> +++ b/tests/i915/gem_shrink.c
> @@ -26,6 +26,10 @@
> *
> * Exercise the shrinker by overallocating GEM objects
> */
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/wait.h>
> +#include <fcntl.h>
>
> #include "igt.h"
> #include "igt_gt.h"
> @@ -366,6 +370,376 @@ static void reclaim(unsigned engine, int timeout)
> close(fd);
> }
>
> +static unsigned long get_meminfo(const char *info, const char *tag)
> +{
> + const char *str;
> + unsigned long val;
> +
> + str = strstr(info, tag);
> + if (str && sscanf(str + strlen(tag), " %lu", &val) == 1)
> + return val >> 10;
> +
> + igt_warn("Unrecognised /proc/meminfo field: '%s'\n", tag);
> + return 0;
> +}
> +
> +static unsigned long get_avail_ram_mb(void)
> +{
> + int fd;
> + int ret;
> + char buf[4096];
> + unsigned long ram;
> +
> + fd = open("/proc/meminfo", O_RDONLY);
> + igt_assert_fd(fd);
> +
> + ret = read(fd, buf, sizeof(buf));
> + igt_assert(ret >= 0);
> +
> + close(fd);
> +
> + ram = get_meminfo(buf, "MemAvailable:");
> + ram += get_meminfo(buf, "Buffers:");
> + ram += get_meminfo(buf, "Cached:");
> + ram += get_meminfo(buf, "SwapCached:");
> +
> + return ram;
> +}
What's wrong with ones from intel_os.c?
-Michał
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [igt-dev] [PATCH i-g-t] tests/gem_shrink: Exercise OOM and other routes to shrinking in reasonable time
2019-01-07 12:27 ` Michał Winiarski
@ 2019-01-07 12:31 ` Chris Wilson
2019-01-07 12:52 ` Tvrtko Ursulin
0 siblings, 1 reply; 12+ messages in thread
From: Chris Wilson @ 2019-01-07 12:31 UTC (permalink / raw)
To: Michał Winiarski, Tvrtko Ursulin; +Cc: igt-dev, Intel-gfx
Quoting Michał Winiarski (2019-01-07 12:27:07)
> On Fri, Jan 04, 2019 at 03:37:09PM +0000, Tvrtko Ursulin wrote:
> > From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> >
> > A set of subtests which exercises different paths to our shrinker code
> > (including the OOM killer) in predictable and reasonable time budget.
> >
> > Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> > ---
> > lib/igt_core.c | 19 ++
> > lib/igt_core.h | 1 +
> > tests/i915/gem_shrink.c | 399 ++++++++++++++++++++++++++
> > tests/intel-ci/blacklist.txt | 1 +
> > tests/intel-ci/fast-feedback.testlist | 3 +
> > 5 files changed, 423 insertions(+)
>
> [snip]
>
> > diff --git a/tests/i915/gem_shrink.c b/tests/i915/gem_shrink.c
> > index c8e05814ee70..7c002de0ef1f 100644
> > --- a/tests/i915/gem_shrink.c
> > +++ b/tests/i915/gem_shrink.c
> > @@ -26,6 +26,10 @@
> > *
> > * Exercise the shrinker by overallocating GEM objects
> > */
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <sys/wait.h>
> > +#include <fcntl.h>
> >
> > #include "igt.h"
> > #include "igt_gt.h"
> > @@ -366,6 +370,376 @@ static void reclaim(unsigned engine, int timeout)
> > close(fd);
> > }
> >
> > +static unsigned long get_meminfo(const char *info, const char *tag)
> > +{
> > + const char *str;
> > + unsigned long val;
> > +
> > + str = strstr(info, tag);
> > + if (str && sscanf(str + strlen(tag), " %lu", &val) == 1)
> > + return val >> 10;
> > +
> > + igt_warn("Unrecognised /proc/meminfo field: '%s'\n", tag);
> > + return 0;
> > +}
> > +
> > +static unsigned long get_avail_ram_mb(void)
> > +{
> > + int fd;
> > + int ret;
> > + char buf[4096];
> > + unsigned long ram;
> > +
> > + fd = open("/proc/meminfo", O_RDONLY);
> > + igt_assert_fd(fd);
> > +
> > + ret = read(fd, buf, sizeof(buf));
> > + igt_assert(ret >= 0);
> > +
> > + close(fd);
> > +
> > + ram = get_meminfo(buf, "MemAvailable:");
> > + ram += get_meminfo(buf, "Buffers:");
> > + ram += get_meminfo(buf, "Cached:");
> > + ram += get_meminfo(buf, "SwapCached:");
> > +
> > + return ram;
> > +}
>
> What's wrong with ones from intel_os.c?
They pull in both an i915 and mm purge, which iirc, had to be avoided
here.
-Chris
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [igt-dev] [PATCH i-g-t] tests/gem_shrink: Exercise OOM and other routes to shrinking in reasonable time
2019-01-07 12:31 ` Chris Wilson
@ 2019-01-07 12:52 ` Tvrtko Ursulin
2019-01-07 12:56 ` Chris Wilson
0 siblings, 1 reply; 12+ messages in thread
From: Tvrtko Ursulin @ 2019-01-07 12:52 UTC (permalink / raw)
To: Chris Wilson, Michał Winiarski; +Cc: igt-dev, Intel-gfx
On 07/01/2019 12:31, Chris Wilson wrote:
> Quoting Michał Winiarski (2019-01-07 12:27:07)
>> On Fri, Jan 04, 2019 at 03:37:09PM +0000, Tvrtko Ursulin wrote:
>>> From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>>>
>>> A set of subtests which exercises different paths to our shrinker code
>>> (including the OOM killer) in predictable and reasonable time budget.
>>>
>>> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>>> ---
>>> lib/igt_core.c | 19 ++
>>> lib/igt_core.h | 1 +
>>> tests/i915/gem_shrink.c | 399 ++++++++++++++++++++++++++
>>> tests/intel-ci/blacklist.txt | 1 +
>>> tests/intel-ci/fast-feedback.testlist | 3 +
>>> 5 files changed, 423 insertions(+)
>>
>> [snip]
>>
>>> diff --git a/tests/i915/gem_shrink.c b/tests/i915/gem_shrink.c
>>> index c8e05814ee70..7c002de0ef1f 100644
>>> --- a/tests/i915/gem_shrink.c
>>> +++ b/tests/i915/gem_shrink.c
>>> @@ -26,6 +26,10 @@
>>> *
>>> * Exercise the shrinker by overallocating GEM objects
>>> */
>>> +#include <sys/types.h>
>>> +#include <sys/stat.h>
>>> +#include <sys/wait.h>
>>> +#include <fcntl.h>
>>>
>>> #include "igt.h"
>>> #include "igt_gt.h"
>>> @@ -366,6 +370,376 @@ static void reclaim(unsigned engine, int timeout)
>>> close(fd);
>>> }
>>>
>>> +static unsigned long get_meminfo(const char *info, const char *tag)
>>> +{
>>> + const char *str;
>>> + unsigned long val;
>>> +
>>> + str = strstr(info, tag);
>>> + if (str && sscanf(str + strlen(tag), " %lu", &val) == 1)
>>> + return val >> 10;
>>> +
>>> + igt_warn("Unrecognised /proc/meminfo field: '%s'\n", tag);
>>> + return 0;
>>> +}
>>> +
>>> +static unsigned long get_avail_ram_mb(void)
>>> +{
>>> + int fd;
>>> + int ret;
>>> + char buf[4096];
>>> + unsigned long ram;
>>> +
>>> + fd = open("/proc/meminfo", O_RDONLY);
>>> + igt_assert_fd(fd);
>>> +
>>> + ret = read(fd, buf, sizeof(buf));
>>> + igt_assert(ret >= 0);
>>> +
>>> + close(fd);
>>> +
>>> + ram = get_meminfo(buf, "MemAvailable:");
>>> + ram += get_meminfo(buf, "Buffers:");
>>> + ram += get_meminfo(buf, "Cached:");
>>> + ram += get_meminfo(buf, "SwapCached:");
>>> +
>>> + return ram;
>>> +}
>>
>> What's wrong with ones from intel_os.c?
>
> They pull in both an i915 and mm purge, which iirc, had to be avoided
> here.
Yep. I can sense a suggestion of adding a lighter weight version to the
library now.. :)
Regards,
Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [igt-dev] [PATCH i-g-t] tests/gem_shrink: Exercise OOM and other routes to shrinking in reasonable time
2019-01-07 12:52 ` Tvrtko Ursulin
@ 2019-01-07 12:56 ` Chris Wilson
0 siblings, 0 replies; 12+ messages in thread
From: Chris Wilson @ 2019-01-07 12:56 UTC (permalink / raw)
To: Michał Winiarski, Tvrtko Ursulin; +Cc: igt-dev, Intel-gfx
Quoting Tvrtko Ursulin (2019-01-07 12:52:28)
>
> On 07/01/2019 12:31, Chris Wilson wrote:
> > Quoting Michał Winiarski (2019-01-07 12:27:07)
> >> On Fri, Jan 04, 2019 at 03:37:09PM +0000, Tvrtko Ursulin wrote:
> >>> From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> >>>
> >>> A set of subtests which exercises different paths to our shrinker code
> >>> (including the OOM killer) in predictable and reasonable time budget.
> >>>
> >>> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> >>> ---
> >>> lib/igt_core.c | 19 ++
> >>> lib/igt_core.h | 1 +
> >>> tests/i915/gem_shrink.c | 399 ++++++++++++++++++++++++++
> >>> tests/intel-ci/blacklist.txt | 1 +
> >>> tests/intel-ci/fast-feedback.testlist | 3 +
> >>> 5 files changed, 423 insertions(+)
> >>
> >> [snip]
> >>
> >>> diff --git a/tests/i915/gem_shrink.c b/tests/i915/gem_shrink.c
> >>> index c8e05814ee70..7c002de0ef1f 100644
> >>> --- a/tests/i915/gem_shrink.c
> >>> +++ b/tests/i915/gem_shrink.c
> >>> @@ -26,6 +26,10 @@
> >>> *
> >>> * Exercise the shrinker by overallocating GEM objects
> >>> */
> >>> +#include <sys/types.h>
> >>> +#include <sys/stat.h>
> >>> +#include <sys/wait.h>
> >>> +#include <fcntl.h>
> >>>
> >>> #include "igt.h"
> >>> #include "igt_gt.h"
> >>> @@ -366,6 +370,376 @@ static void reclaim(unsigned engine, int timeout)
> >>> close(fd);
> >>> }
> >>>
> >>> +static unsigned long get_meminfo(const char *info, const char *tag)
> >>> +{
> >>> + const char *str;
> >>> + unsigned long val;
> >>> +
> >>> + str = strstr(info, tag);
> >>> + if (str && sscanf(str + strlen(tag), " %lu", &val) == 1)
> >>> + return val >> 10;
> >>> +
> >>> + igt_warn("Unrecognised /proc/meminfo field: '%s'\n", tag);
> >>> + return 0;
> >>> +}
> >>> +
> >>> +static unsigned long get_avail_ram_mb(void)
> >>> +{
> >>> + int fd;
> >>> + int ret;
> >>> + char buf[4096];
> >>> + unsigned long ram;
> >>> +
> >>> + fd = open("/proc/meminfo", O_RDONLY);
> >>> + igt_assert_fd(fd);
> >>> +
> >>> + ret = read(fd, buf, sizeof(buf));
> >>> + igt_assert(ret >= 0);
> >>> +
> >>> + close(fd);
> >>> +
> >>> + ram = get_meminfo(buf, "MemAvailable:");
> >>> + ram += get_meminfo(buf, "Buffers:");
> >>> + ram += get_meminfo(buf, "Cached:");
> >>> + ram += get_meminfo(buf, "SwapCached:");
> >>> +
> >>> + return ram;
> >>> +}
> >>
> >> What's wrong with ones from intel_os.c?
> >
> > They pull in both an i915 and mm purge, which iirc, had to be avoided
> > here.
>
> Yep. I can sense a suggestion of adding a lighter weight version to the
> library now.. :)
Nah, I refrained because I hope for the same leniency (many times over).
Anyway, the third user has to refactor ;)
To serendipity,
-Chris
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [igt-dev] [PATCH i-g-t] tests/gem_shrink: Exercise OOM and other routes to shrinking in reasonable time
2019-01-07 11:28 ` Petri Latvala
@ 2019-01-07 17:33 ` Tvrtko Ursulin
0 siblings, 0 replies; 12+ messages in thread
From: Tvrtko Ursulin @ 2019-01-07 17:33 UTC (permalink / raw)
To: igt-dev, Intel-gfx, Tvrtko Ursulin
On 07/01/2019 11:28, Petri Latvala wrote:
> On Mon, Jan 07, 2019 at 11:12:30AM +0000, Tvrtko Ursulin wrote:
>>
>> On 07/01/2019 11:01, Petri Latvala wrote:
>>> On Fri, Jan 04, 2019 at 03:37:09PM +0000, Tvrtko Ursulin wrote:
>>>> diff --git a/tests/intel-ci/blacklist.txt b/tests/intel-ci/blacklist.txt
>>>> index 73d127603d28..d76a4b3b1c71 100644
>>>> --- a/tests/intel-ci/blacklist.txt
>>>> +++ b/tests/intel-ci/blacklist.txt
>>>> @@ -60,6 +60,7 @@ igt@gem_ring_sync_copy(@.*)?
>>>> igt@gem_ring_sync_loop(@.*)?
>>>> igt@gem_seqno_wrap(@.*)?
>>>> igt@gem_shrink@(?!reclaim$).*
>>>> +igt@gem_shrink@(?!reclaims-and-oom).*
>>>> igt@gem_softpin@.*(hang|S4).*
>>>> igt@gem_spin_batch(@.*)?
>>>> igt@gem_stolen@.*hibernate.*
>>>
>>>
>>> In case you didn't notice: The first gem_shrink line removes the
>>> reclaims-and-oom* subtests, and the second line (the one you added)
>>> then removes the 'reclaim' subtest, resulting in all gem_shrink
>>> subtests blacklisted.
>>
>> No I haven't thank you. Interestingly the reclaim subtest still did run.
>
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2185/shards-all.html
> it's NOTRUN on all machines on patched IGT.
My fail while looking at the pages.. I saw the test mentioned in the
list but fail to spot that was only because it was run in the baseline. :I
>> Okay, but in essence should this work then:
>>
>> igt@gem_shrink@(?!reclaim).*
>>
>> To blacklist everything apart from reclaims and reclaims-and-oom.*
>> subtests?
>
> Yeah that looks correct.
Thanks, I'll send a v2 shortly.
Regards,
Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH i-g-t v2] tests/gem_shrink: Exercise OOM and other routes to shrinking in reasonable time
2019-01-04 15:37 [PATCH i-g-t] tests/gem_shrink: Exercise OOM and other routes to shrinking in reasonable time Tvrtko Ursulin
2019-01-07 11:01 ` [igt-dev] " Petri Latvala
2019-01-07 12:27 ` Michał Winiarski
@ 2019-01-07 17:36 ` Tvrtko Ursulin
2019-01-07 18:22 ` [PATCH i-g-t v3] " Tvrtko Ursulin
2 siblings, 1 reply; 12+ messages in thread
From: Tvrtko Ursulin @ 2019-01-07 17:36 UTC (permalink / raw)
To: igt-dev; +Cc: Intel-gfx
From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
A set of subtests which exercises different paths to our shrinker code
(including the OOM killer) in predictable and reasonable time budget.
v2:
* Fix blacklist regexp. (Petri Latvala)
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
lib/igt_core.c | 19 ++
lib/igt_core.h | 1 +
tests/i915/gem_shrink.c | 399 ++++++++++++++++++++++++++
tests/intel-ci/blacklist.txt | 2 +-
tests/intel-ci/fast-feedback.testlist | 3 +
5 files changed, 423 insertions(+), 1 deletion(-)
diff --git a/lib/igt_core.c b/lib/igt_core.c
index 50d6008f6c82..351da0b4e020 100644
--- a/lib/igt_core.c
+++ b/lib/igt_core.c
@@ -1685,6 +1685,25 @@ void igt_stop_helper(struct igt_helper_process *proc)
assert(helper_was_alive(proc, status));
}
+/**
+ * igt_try_stop_helper:
+ * @proc: #igt_helper_process structure
+ *
+ * Terminates a helper process if it is still running and returns true, or false
+ * if the process wasn't running.
+ */
+bool igt_try_stop_helper(struct igt_helper_process *proc)
+{
+ int status;
+
+ /* failure here means the pid is already dead and so waiting is safe */
+ kill(proc->pid, proc->use_SIGKILL ? SIGKILL : SIGTERM);
+
+ status = igt_wait_helper(proc);
+
+ return helper_was_alive(proc, status);
+}
+
static void children_exit_handler(int sig)
{
int status;
diff --git a/lib/igt_core.h b/lib/igt_core.h
index 6f8c3852a686..ed5ceebf1205 100644
--- a/lib/igt_core.h
+++ b/lib/igt_core.h
@@ -795,6 +795,7 @@ bool __igt_fork_helper(struct igt_helper_process *proc);
for (; __igt_fork_helper(proc); exit(0))
int igt_wait_helper(struct igt_helper_process *proc);
void igt_stop_helper(struct igt_helper_process *proc);
+bool igt_try_stop_helper(struct igt_helper_process *proc);
/* exit handler code */
diff --git a/tests/i915/gem_shrink.c b/tests/i915/gem_shrink.c
index c8e05814ee70..7c002de0ef1f 100644
--- a/tests/i915/gem_shrink.c
+++ b/tests/i915/gem_shrink.c
@@ -26,6 +26,10 @@
*
* Exercise the shrinker by overallocating GEM objects
*/
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
#include "igt.h"
#include "igt_gt.h"
@@ -366,6 +370,376 @@ static void reclaim(unsigned engine, int timeout)
close(fd);
}
+static unsigned long get_meminfo(const char *info, const char *tag)
+{
+ const char *str;
+ unsigned long val;
+
+ str = strstr(info, tag);
+ if (str && sscanf(str + strlen(tag), " %lu", &val) == 1)
+ return val >> 10;
+
+ igt_warn("Unrecognised /proc/meminfo field: '%s'\n", tag);
+ return 0;
+}
+
+static unsigned long get_avail_ram_mb(void)
+{
+ int fd;
+ int ret;
+ char buf[4096];
+ unsigned long ram;
+
+ fd = open("/proc/meminfo", O_RDONLY);
+ igt_assert_fd(fd);
+
+ ret = read(fd, buf, sizeof(buf));
+ igt_assert(ret >= 0);
+
+ close(fd);
+
+ ram = get_meminfo(buf, "MemAvailable:");
+ ram += get_meminfo(buf, "Buffers:");
+ ram += get_meminfo(buf, "Cached:");
+ ram += get_meminfo(buf, "SwapCached:");
+
+ return ram;
+}
+
+struct test {
+#define TEST_BO (1)
+#define TEST_USERPTR (2)
+ unsigned int flags;
+ int fd;
+};
+
+static uint32_t __get_pages(int fd, unsigned long alloc)
+{
+ uint32_t handle = gem_create(fd, alloc);
+
+ gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, 0);
+ gem_madvise(fd, handle, I915_MADV_DONTNEED);
+
+ return handle;
+}
+
+struct test_obj {
+ void *ptr;
+ uint32_t handle;
+};
+
+#define PAGE_SIZE 4096
+static void
+__get_userptr(int fd, struct test_obj *obj, unsigned long sz)
+{
+ struct local_i915_gem_userptr userptr = { };
+ void *ptr;
+
+ igt_assert_eq(sz & 4095, 0);
+
+ ptr = mmap(NULL, sz, PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ assert(ptr != MAP_FAILED);
+
+ for (size_t page = 0; page < sz; page += PAGE_SIZE)
+ *(volatile uint32_t *)((unsigned char *)ptr + page) = 0;
+
+ userptr.user_size = sz;
+ userptr.user_ptr = to_user_pointer(ptr);
+ do_ioctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
+
+ gem_set_domain(fd, userptr.handle, I915_GEM_DOMAIN_GTT, 0);
+ gem_madvise(fd, userptr.handle, I915_MADV_DONTNEED);
+
+ obj->ptr = ptr;
+ obj->handle = userptr.handle;
+}
+
+/*
+ * Use a specific way of using up memory until we are below a certain threshold.
+ */
+static void *mempressure(void *arg)
+{
+ const unsigned int free_threshold_mb = 256;
+ struct test_obj *list = NULL;
+ struct test *test = arg;
+ const unsigned int sz_mb = 2;
+ const unsigned int sz = sz_mb << 20;
+ unsigned int n = 0, max = 0;
+ unsigned int blocks;
+
+ for (;;) {
+ unsigned long ram_mb = get_avail_ram_mb();
+
+ if (!list) {
+ /*
+ * On first pass estimate how many sz_mb sized blocks
+ * we could need to use up all RAM.
+ */
+ blocks = ram_mb / sz_mb;
+ list = calloc(blocks, sizeof(*list));
+ igt_assert(list);
+ } else if (ram_mb < free_threshold_mb) {
+ /* Limit the working set once under the threshold. */
+ blocks = max + 1;
+ }
+
+ /* Free the oldest block once the working set wrapped. */
+ if (list[n].ptr || list[n].handle) {
+ if (test->flags & TEST_USERPTR) {
+ munmap(list[n].ptr, sz);
+ gem_close(test->fd, list[n].handle);
+ } else if (test->flags & TEST_BO) {
+ gem_close(test->fd, list[n].handle);
+ } else {
+ munmap(list[n].ptr, sz);
+ }
+ }
+
+ /*
+ * Allocate memory blocks and record the current working set
+ * size.
+ */
+ if (test->flags & TEST_BO) {
+ list[n].handle = __get_pages(test->fd, sz);
+ } else if (test->flags & TEST_USERPTR) {
+ __get_userptr(test->fd, &list[n], sz);
+ } else {
+ list[n].ptr = mmap(NULL, sz, PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ assert(list[n].ptr != MAP_FAILED);
+
+ madvise(list[n].ptr, sz, MADV_HUGEPAGE);
+
+ for (size_t page = 0; page < sz; page += PAGE_SIZE)
+ *(volatile uint32_t *)((unsigned char *)list[n].ptr + page) = 0;
+ }
+
+ if (n > max)
+ max = n;
+
+ n++;
+
+ /*
+ * Start freeing the oldest and reallocating once maximum
+ * working set size has been reached.
+ */
+ if (n >= blocks)
+ n = 0;
+ }
+
+ return NULL;
+}
+
+static void oom_adjust(const char *score)
+{
+ int fd;
+
+ fd = open("/proc/self/oom_score_adj", O_WRONLY);
+ igt_assert_fd(fd);
+ igt_assert(write(fd, score, sizeof(score)) == sizeof(score));
+ close(fd);
+}
+
+static void trigger_oom(void)
+{
+ const char *cmd = "f";
+ int fd;
+
+ fd = open("/proc/sysrq-trigger", O_WRONLY);
+ igt_assert_fd(fd);
+ igt_assert(write(fd, cmd, sizeof(cmd)) == sizeof(cmd));
+ close(fd);
+}
+
+static bool has_sysrq_trigger(void)
+{
+ int fd;
+
+ fd = open("/proc/sysrq-trigger", O_WRONLY);
+ close(fd);
+
+ return fd >= 0;
+}
+
+/*
+ * Exercise different paths to our shrinker code, including OOM, in predictable
+ * and reasonable time budget.
+ */
+static void reclaim_oom(unsigned int flags, unsigned int passes)
+{
+ unsigned int count = 0;
+
+ oom_adjust("-1000");
+
+ do {
+ struct igt_helper_process gem_child = { .use_SIGKILL = true };
+ struct igt_helper_process mem_child = { .use_SIGKILL = true };
+ struct igt_helper_process eb_child = { .use_SIGKILL = true };
+ struct igt_helper_process drop_child = { .use_SIGKILL = true };
+
+ igt_debug("Iteration %u...\n", ++count);
+
+ /*
+ * Apply either anon backed or shmem backed memory pressure
+ * to the amount to use up almost all available RAM.
+ */
+ igt_fork_helper(&mem_child) {
+ struct test test = { };
+
+ if ((flags & (TEST_BO | TEST_USERPTR)) ==
+ (TEST_BO | TEST_USERPTR))
+ test.flags = TEST_BO;
+
+ /* Sacrifice the memory hog if it comes to that. */
+ oom_adjust("500");
+
+ if (test.flags == TEST_BO) {
+ test.fd = drm_open_driver_render(DRIVER_INTEL);
+ igt_require_gem(test.fd);
+ }
+
+ mempressure(&test);
+
+ if (test.flags == TEST_BO)
+ close(test.fd);
+ }
+
+ /*
+ * Apply either userptr backed or shmem backed memory pressure
+ * to the amount to use up almost all available RAM.
+ */
+ igt_fork_helper(&gem_child) {
+ struct test test = { .flags = flags };
+
+ if ((flags & (TEST_BO | TEST_USERPTR)) ==
+ (TEST_BO | TEST_USERPTR))
+ test.flags = TEST_USERPTR;
+
+ /* Sacrifice the memory hog if it comes to that. */
+ oom_adjust("500");
+
+ test.fd = drm_open_driver_render(DRIVER_INTEL);
+ igt_require_gem(test.fd);
+
+ mempressure(&test);
+
+ close(test.fd);
+ }
+
+ /*
+ * Apply an execbuf load to exercise the request allocation and
+ * direct reclaim from this path.
+ *
+ * Occasionaly sync with execution and pause for a little bit to
+ * avoid hogging to much from this client.
+ */
+ igt_fork_helper(&eb_child) {
+ struct test test = { .flags = flags };
+ const uint32_t bbe = MI_BATCH_BUFFER_END;
+ struct drm_i915_gem_exec_object2 obj = { };
+ struct drm_i915_gem_execbuffer2 execbuf = { };
+
+ execbuf.buffers_ptr = to_user_pointer(&obj);
+ execbuf.buffer_count = 1;
+
+ test.fd = drm_open_driver_render(DRIVER_INTEL);
+ igt_require_gem(test.fd);
+
+ for (;;) {
+ unsigned long eb = 0;
+ struct timespec ts = { };
+ unsigned long start;
+
+ igt_nsec_elapsed(&ts);
+ start = igt_nsec_elapsed(&ts) / 1e6;
+
+ for (;;) {
+ unsigned long now;
+
+ obj.handle = gem_create(test.fd, 4096);
+ gem_write(test.fd, obj.handle, 0, &bbe,
+ sizeof(bbe));
+ gem_execbuf(test.fd, &execbuf);
+ eb++;
+ now = igt_nsec_elapsed(&ts) / 1e6;
+ if (now > (start + 1000)) {
+ gem_sync(test.fd, obj.handle);
+ if (now > (start + 2000)) {
+ gem_close(test.fd,
+ obj.handle);
+ break;
+ }
+ }
+ gem_close(test.fd, obj.handle);
+ }
+
+ igt_debug("%lu execbufs\n", eb);
+ usleep(500e3);
+ }
+
+ close(test.fd);
+ }
+
+ /*
+ * Manually drop cached with the DROP_ACTIVE flag set every now
+ * and then in order to exercise this path as well.
+ */
+ igt_fork_helper(&drop_child) {
+ int fd;
+
+ fd = drm_open_driver(DRIVER_INTEL);
+ igt_require_gem(fd);
+
+ for (;;) {
+ usleep(334e3);
+ igt_debug("Dropping caches...\n");
+ igt_drop_caches_set(fd, DROP_ACTIVE);
+ }
+
+ close(fd);
+ }
+
+ /*
+ * When memory pressure clients have managed to use up all
+ * available RAM, let them run for a brief moment yet and then
+ * manually trigger the OOM condition.
+ */
+ for (unsigned long ram_mb = 0;
+ (ram_mb = get_avail_ram_mb()) > 512;) {
+ int status;
+ pid_t pid;
+
+ igt_debug("[%u] %lu MiB free\n", count, ram_mb);
+
+ pid = waitpid(mem_child.pid, &status, WNOHANG);
+ if (pid)
+ break;
+
+ pid = waitpid(gem_child.pid, &status, WNOHANG);
+ if (pid)
+ break;
+
+ pid = waitpid(eb_child.pid, &status, WNOHANG);
+ igt_assert_eq(pid, 0);
+
+ pid = waitpid(drop_child.pid, &status, WNOHANG);
+ igt_assert_eq(pid, 0);
+
+ sleep(1);
+ }
+
+ igt_debug("Triggering OOM...\n");
+ trigger_oom();
+
+ sleep(1);
+
+ igt_try_stop_helper(&mem_child);
+ igt_try_stop_helper(&gem_child);
+ igt_stop_helper(&eb_child);
+ igt_stop_helper(&drop_child);
+ } while (count < passes);
+}
+
igt_main
{
const struct test {
@@ -432,6 +806,31 @@ igt_main
igt_subtest("reclaim")
reclaim(I915_EXEC_DEFAULT, 2);
+ igt_subtest_group {
+ struct {
+ const char *name;
+ unsigned int flags;
+ unsigned int passes;
+ } *p, passes[] = {
+ { "reclaims-and-oom-basic", TEST_BO, 1 },
+ { "reclaims-and-oom", TEST_BO, 3 },
+ { "reclaims-and-oom-userptr-basic", TEST_USERPTR, 1 },
+ { "reclaims-and-oom-userptr", TEST_USERPTR, 3 },
+ { "reclaims-and-oom-both-basic", TEST_BO | TEST_USERPTR, 1 },
+ { "reclaims-and-oom-both", TEST_BO | TEST_USERPTR, 3 },
+ { NULL, 0, 0 },
+ };
+
+ igt_fixture {
+ igt_require(has_sysrq_trigger());
+ }
+
+ for (p = passes; p->name; p++) {
+ igt_subtest(p->name)
+ reclaim_oom(p->flags, p->passes);
+ }
+ }
+
for(const struct test *t = tests; t->name; t++) {
for(const struct mode *m = modes; m->suffix; m++) {
igt_subtest_f("%s%s", t->name, m->suffix)
diff --git a/tests/intel-ci/blacklist.txt b/tests/intel-ci/blacklist.txt
index 73d127603d28..b6e302db381e 100644
--- a/tests/intel-ci/blacklist.txt
+++ b/tests/intel-ci/blacklist.txt
@@ -59,7 +59,7 @@ igt@gem_ringfill@(?!.*basic).*
igt@gem_ring_sync_copy(@.*)?
igt@gem_ring_sync_loop(@.*)?
igt@gem_seqno_wrap(@.*)?
-igt@gem_shrink@(?!reclaim$).*
+igt@gem_shrink@(?!reclaim).*
igt@gem_softpin@.*(hang|S4).*
igt@gem_spin_batch(@.*)?
igt@gem_stolen@.*hibernate.*
diff --git a/tests/intel-ci/fast-feedback.testlist b/tests/intel-ci/fast-feedback.testlist
index 6d42792c67f7..0df7cc2fd9fd 100644
--- a/tests/intel-ci/fast-feedback.testlist
+++ b/tests/intel-ci/fast-feedback.testlist
@@ -124,6 +124,9 @@ igt@gem_ringfill@basic-default
igt@gem_ringfill@basic-default-interruptible
igt@gem_ringfill@basic-default-forked
igt@gem_ringfill@basic-default-fd
+igt@gem_shrink@reclaims-and-oom-basic
+igt@gem_shrink@reclaims-and-oom-userptr-basic
+igt@gem_shrink@reclaims-and-oom-both-basic
igt@gem_sync@basic-all
igt@gem_sync@basic-each
igt@gem_sync@basic-many-each
--
2.19.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH i-g-t v3] tests/gem_shrink: Exercise OOM and other routes to shrinking in reasonable time
2019-01-07 17:36 ` [PATCH i-g-t v2] " Tvrtko Ursulin
@ 2019-01-07 18:22 ` Tvrtko Ursulin
2019-01-08 10:57 ` Chris Wilson
0 siblings, 1 reply; 12+ messages in thread
From: Tvrtko Ursulin @ 2019-01-07 18:22 UTC (permalink / raw)
To: igt-dev; +Cc: Intel-gfx
From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
A set of subtests which exercises different paths to our shrinker code
(including the OOM killer) in predictable and reasonable time budget.
v2:
* Fix blacklist regexp. (Petri Latvala)
v3:
* Skip userptr test if not userptr support.
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
lib/igt_core.c | 19 ++
lib/igt_core.h | 1 +
tests/i915/gem_shrink.c | 401 ++++++++++++++++++++++++++
tests/intel-ci/blacklist.txt | 2 +-
tests/intel-ci/fast-feedback.testlist | 3 +
5 files changed, 425 insertions(+), 1 deletion(-)
diff --git a/lib/igt_core.c b/lib/igt_core.c
index 50d6008f6c82..351da0b4e020 100644
--- a/lib/igt_core.c
+++ b/lib/igt_core.c
@@ -1685,6 +1685,25 @@ void igt_stop_helper(struct igt_helper_process *proc)
assert(helper_was_alive(proc, status));
}
+/**
+ * igt_try_stop_helper:
+ * @proc: #igt_helper_process structure
+ *
+ * Terminates a helper process if it is still running and returns true, or false
+ * if the process wasn't running.
+ */
+bool igt_try_stop_helper(struct igt_helper_process *proc)
+{
+ int status;
+
+ /* failure here means the pid is already dead and so waiting is safe */
+ kill(proc->pid, proc->use_SIGKILL ? SIGKILL : SIGTERM);
+
+ status = igt_wait_helper(proc);
+
+ return helper_was_alive(proc, status);
+}
+
static void children_exit_handler(int sig)
{
int status;
diff --git a/lib/igt_core.h b/lib/igt_core.h
index 6f8c3852a686..ed5ceebf1205 100644
--- a/lib/igt_core.h
+++ b/lib/igt_core.h
@@ -795,6 +795,7 @@ bool __igt_fork_helper(struct igt_helper_process *proc);
for (; __igt_fork_helper(proc); exit(0))
int igt_wait_helper(struct igt_helper_process *proc);
void igt_stop_helper(struct igt_helper_process *proc);
+bool igt_try_stop_helper(struct igt_helper_process *proc);
/* exit handler code */
diff --git a/tests/i915/gem_shrink.c b/tests/i915/gem_shrink.c
index c8e05814ee70..3d48cbebc2f9 100644
--- a/tests/i915/gem_shrink.c
+++ b/tests/i915/gem_shrink.c
@@ -26,6 +26,10 @@
*
* Exercise the shrinker by overallocating GEM objects
*/
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
#include "igt.h"
#include "igt_gt.h"
@@ -366,6 +370,378 @@ static void reclaim(unsigned engine, int timeout)
close(fd);
}
+static unsigned long get_meminfo(const char *info, const char *tag)
+{
+ const char *str;
+ unsigned long val;
+
+ str = strstr(info, tag);
+ if (str && sscanf(str + strlen(tag), " %lu", &val) == 1)
+ return val >> 10;
+
+ igt_warn("Unrecognised /proc/meminfo field: '%s'\n", tag);
+ return 0;
+}
+
+static unsigned long get_avail_ram_mb(void)
+{
+ int fd;
+ int ret;
+ char buf[4096];
+ unsigned long ram;
+
+ fd = open("/proc/meminfo", O_RDONLY);
+ igt_assert_fd(fd);
+
+ ret = read(fd, buf, sizeof(buf));
+ igt_assert(ret >= 0);
+
+ close(fd);
+
+ ram = get_meminfo(buf, "MemAvailable:");
+ ram += get_meminfo(buf, "Buffers:");
+ ram += get_meminfo(buf, "Cached:");
+ ram += get_meminfo(buf, "SwapCached:");
+
+ return ram;
+}
+
+struct test {
+#define TEST_BO (1)
+#define TEST_USERPTR (2)
+ unsigned int flags;
+ int fd;
+};
+
+static uint32_t __get_pages(int fd, unsigned long alloc)
+{
+ uint32_t handle = gem_create(fd, alloc);
+
+ gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, 0);
+ gem_madvise(fd, handle, I915_MADV_DONTNEED);
+
+ return handle;
+}
+
+struct test_obj {
+ void *ptr;
+ uint32_t handle;
+};
+
+#define PAGE_SIZE 4096
+static void
+__get_userptr(int fd, struct test_obj *obj, unsigned long sz)
+{
+ struct local_i915_gem_userptr userptr = { };
+ void *ptr;
+
+ igt_assert_eq(sz & 4095, 0);
+
+ ptr = mmap(NULL, sz, PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ assert(ptr != MAP_FAILED);
+
+ for (size_t page = 0; page < sz; page += PAGE_SIZE)
+ *(volatile uint32_t *)((unsigned char *)ptr + page) = 0;
+
+ userptr.user_size = sz;
+ userptr.user_ptr = to_user_pointer(ptr);
+ do_ioctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
+
+ gem_set_domain(fd, userptr.handle, I915_GEM_DOMAIN_GTT, 0);
+ gem_madvise(fd, userptr.handle, I915_MADV_DONTNEED);
+
+ obj->ptr = ptr;
+ obj->handle = userptr.handle;
+}
+
+/*
+ * Use a specific way of using up memory until we are below a certain threshold.
+ */
+static void *mempressure(void *arg)
+{
+ const unsigned int free_threshold_mb = 256;
+ struct test_obj *list = NULL;
+ struct test *test = arg;
+ const unsigned int sz_mb = 2;
+ const unsigned int sz = sz_mb << 20;
+ unsigned int n = 0, max = 0;
+ unsigned int blocks;
+
+ for (;;) {
+ unsigned long ram_mb = get_avail_ram_mb();
+
+ if (!list) {
+ /*
+ * On first pass estimate how many sz_mb sized blocks
+ * we could need to use up all RAM.
+ */
+ blocks = ram_mb / sz_mb;
+ list = calloc(blocks, sizeof(*list));
+ igt_assert(list);
+ } else if (ram_mb < free_threshold_mb) {
+ /* Limit the working set once under the threshold. */
+ blocks = max + 1;
+ }
+
+ /* Free the oldest block once the working set wrapped. */
+ if (list[n].ptr || list[n].handle) {
+ if (test->flags & TEST_USERPTR) {
+ munmap(list[n].ptr, sz);
+ gem_close(test->fd, list[n].handle);
+ } else if (test->flags & TEST_BO) {
+ gem_close(test->fd, list[n].handle);
+ } else {
+ munmap(list[n].ptr, sz);
+ }
+ }
+
+ /*
+ * Allocate memory blocks and record the current working set
+ * size.
+ */
+ if (test->flags & TEST_BO) {
+ list[n].handle = __get_pages(test->fd, sz);
+ } else if (test->flags & TEST_USERPTR) {
+ __get_userptr(test->fd, &list[n], sz);
+ } else {
+ list[n].ptr = mmap(NULL, sz, PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ assert(list[n].ptr != MAP_FAILED);
+
+ madvise(list[n].ptr, sz, MADV_HUGEPAGE);
+
+ for (size_t page = 0; page < sz; page += PAGE_SIZE)
+ *(volatile uint32_t *)((unsigned char *)list[n].ptr + page) = 0;
+ }
+
+ if (n > max)
+ max = n;
+
+ n++;
+
+ /*
+ * Start freeing the oldest and reallocating once maximum
+ * working set size has been reached.
+ */
+ if (n >= blocks)
+ n = 0;
+ }
+
+ return NULL;
+}
+
+static void oom_adjust(const char *score)
+{
+ int fd;
+
+ fd = open("/proc/self/oom_score_adj", O_WRONLY);
+ igt_assert_fd(fd);
+ igt_assert(write(fd, score, sizeof(score)) == sizeof(score));
+ close(fd);
+}
+
+static void trigger_oom(void)
+{
+ const char *cmd = "f";
+ int fd;
+
+ fd = open("/proc/sysrq-trigger", O_WRONLY);
+ igt_assert_fd(fd);
+ igt_assert(write(fd, cmd, sizeof(cmd)) == sizeof(cmd));
+ close(fd);
+}
+
+static bool has_sysrq_trigger(void)
+{
+ int fd;
+
+ fd = open("/proc/sysrq-trigger", O_WRONLY);
+ close(fd);
+
+ return fd >= 0;
+}
+
+/*
+ * Exercise different paths to our shrinker code, including OOM, in predictable
+ * and reasonable time budget.
+ */
+static void reclaim_oom(unsigned int flags, unsigned int passes)
+{
+ unsigned int count = 0;
+
+ igt_require(!(flags & TEST_USERPTR) || has_userptr());
+
+ oom_adjust("-1000");
+
+ do {
+ struct igt_helper_process gem_child = { .use_SIGKILL = true };
+ struct igt_helper_process mem_child = { .use_SIGKILL = true };
+ struct igt_helper_process eb_child = { .use_SIGKILL = true };
+ struct igt_helper_process drop_child = { .use_SIGKILL = true };
+
+ igt_debug("Iteration %u...\n", ++count);
+
+ /*
+ * Apply either anon backed or shmem backed memory pressure
+ * to the amount to use up almost all available RAM.
+ */
+ igt_fork_helper(&mem_child) {
+ struct test test = { };
+
+ if ((flags & (TEST_BO | TEST_USERPTR)) ==
+ (TEST_BO | TEST_USERPTR))
+ test.flags = TEST_BO;
+
+ /* Sacrifice the memory hog if it comes to that. */
+ oom_adjust("500");
+
+ if (test.flags == TEST_BO) {
+ test.fd = drm_open_driver_render(DRIVER_INTEL);
+ igt_require_gem(test.fd);
+ }
+
+ mempressure(&test);
+
+ if (test.flags == TEST_BO)
+ close(test.fd);
+ }
+
+ /*
+ * Apply either userptr backed or shmem backed memory pressure
+ * to the amount to use up almost all available RAM.
+ */
+ igt_fork_helper(&gem_child) {
+ struct test test = { .flags = flags };
+
+ if ((flags & (TEST_BO | TEST_USERPTR)) ==
+ (TEST_BO | TEST_USERPTR))
+ test.flags = TEST_USERPTR;
+
+ /* Sacrifice the memory hog if it comes to that. */
+ oom_adjust("500");
+
+ test.fd = drm_open_driver_render(DRIVER_INTEL);
+ igt_require_gem(test.fd);
+
+ mempressure(&test);
+
+ close(test.fd);
+ }
+
+ /*
+ * Apply an execbuf load to exercise the request allocation and
+ * direct reclaim from this path.
+ *
+ * Occasionaly sync with execution and pause for a little bit to
+ * avoid hogging to much from this client.
+ */
+ igt_fork_helper(&eb_child) {
+ struct test test = { .flags = flags };
+ const uint32_t bbe = MI_BATCH_BUFFER_END;
+ struct drm_i915_gem_exec_object2 obj = { };
+ struct drm_i915_gem_execbuffer2 execbuf = { };
+
+ execbuf.buffers_ptr = to_user_pointer(&obj);
+ execbuf.buffer_count = 1;
+
+ test.fd = drm_open_driver_render(DRIVER_INTEL);
+ igt_require_gem(test.fd);
+
+ for (;;) {
+ unsigned long eb = 0;
+ struct timespec ts = { };
+ unsigned long start;
+
+ igt_nsec_elapsed(&ts);
+ start = igt_nsec_elapsed(&ts) / 1e6;
+
+ for (;;) {
+ unsigned long now;
+
+ obj.handle = gem_create(test.fd, 4096);
+ gem_write(test.fd, obj.handle, 0, &bbe,
+ sizeof(bbe));
+ gem_execbuf(test.fd, &execbuf);
+ eb++;
+ now = igt_nsec_elapsed(&ts) / 1e6;
+ if (now > (start + 1000)) {
+ gem_sync(test.fd, obj.handle);
+ if (now > (start + 2000)) {
+ gem_close(test.fd,
+ obj.handle);
+ break;
+ }
+ }
+ gem_close(test.fd, obj.handle);
+ }
+
+ igt_debug("%lu execbufs\n", eb);
+ usleep(500e3);
+ }
+
+ close(test.fd);
+ }
+
+ /*
+ * Manually drop cached with the DROP_ACTIVE flag set every now
+ * and then in order to exercise this path as well.
+ */
+ igt_fork_helper(&drop_child) {
+ int fd;
+
+ fd = drm_open_driver(DRIVER_INTEL);
+ igt_require_gem(fd);
+
+ for (;;) {
+ usleep(334e3);
+ igt_debug("Dropping caches...\n");
+ igt_drop_caches_set(fd, DROP_ACTIVE);
+ }
+
+ close(fd);
+ }
+
+ /*
+ * When memory pressure clients have managed to use up all
+ * available RAM, let them run for a brief moment yet and then
+ * manually trigger the OOM condition.
+ */
+ for (unsigned long ram_mb = 0;
+ (ram_mb = get_avail_ram_mb()) > 512;) {
+ int status;
+ pid_t pid;
+
+ igt_debug("[%u] %lu MiB free\n", count, ram_mb);
+
+ pid = waitpid(mem_child.pid, &status, WNOHANG);
+ if (pid)
+ break;
+
+ pid = waitpid(gem_child.pid, &status, WNOHANG);
+ if (pid)
+ break;
+
+ pid = waitpid(eb_child.pid, &status, WNOHANG);
+ igt_assert_eq(pid, 0);
+
+ pid = waitpid(drop_child.pid, &status, WNOHANG);
+ igt_assert_eq(pid, 0);
+
+ sleep(1);
+ }
+
+ igt_debug("Triggering OOM...\n");
+ trigger_oom();
+
+ sleep(1);
+
+ igt_try_stop_helper(&mem_child);
+ igt_try_stop_helper(&gem_child);
+ igt_stop_helper(&eb_child);
+ igt_stop_helper(&drop_child);
+ } while (count < passes);
+}
+
igt_main
{
const struct test {
@@ -432,6 +808,31 @@ igt_main
igt_subtest("reclaim")
reclaim(I915_EXEC_DEFAULT, 2);
+ igt_subtest_group {
+ struct {
+ const char *name;
+ unsigned int flags;
+ unsigned int passes;
+ } *p, passes[] = {
+ { "reclaims-and-oom-basic", TEST_BO, 1 },
+ { "reclaims-and-oom", TEST_BO, 3 },
+ { "reclaims-and-oom-userptr-basic", TEST_USERPTR, 1 },
+ { "reclaims-and-oom-userptr", TEST_USERPTR, 3 },
+ { "reclaims-and-oom-both-basic", TEST_BO | TEST_USERPTR, 1 },
+ { "reclaims-and-oom-both", TEST_BO | TEST_USERPTR, 3 },
+ { NULL, 0, 0 },
+ };
+
+ igt_fixture {
+ igt_require(has_sysrq_trigger());
+ }
+
+ for (p = passes; p->name; p++) {
+ igt_subtest(p->name)
+ reclaim_oom(p->flags, p->passes);
+ }
+ }
+
for(const struct test *t = tests; t->name; t++) {
for(const struct mode *m = modes; m->suffix; m++) {
igt_subtest_f("%s%s", t->name, m->suffix)
diff --git a/tests/intel-ci/blacklist.txt b/tests/intel-ci/blacklist.txt
index 73d127603d28..b6e302db381e 100644
--- a/tests/intel-ci/blacklist.txt
+++ b/tests/intel-ci/blacklist.txt
@@ -59,7 +59,7 @@ igt@gem_ringfill@(?!.*basic).*
igt@gem_ring_sync_copy(@.*)?
igt@gem_ring_sync_loop(@.*)?
igt@gem_seqno_wrap(@.*)?
-igt@gem_shrink@(?!reclaim$).*
+igt@gem_shrink@(?!reclaim).*
igt@gem_softpin@.*(hang|S4).*
igt@gem_spin_batch(@.*)?
igt@gem_stolen@.*hibernate.*
diff --git a/tests/intel-ci/fast-feedback.testlist b/tests/intel-ci/fast-feedback.testlist
index 6d42792c67f7..0df7cc2fd9fd 100644
--- a/tests/intel-ci/fast-feedback.testlist
+++ b/tests/intel-ci/fast-feedback.testlist
@@ -124,6 +124,9 @@ igt@gem_ringfill@basic-default
igt@gem_ringfill@basic-default-interruptible
igt@gem_ringfill@basic-default-forked
igt@gem_ringfill@basic-default-fd
+igt@gem_shrink@reclaims-and-oom-basic
+igt@gem_shrink@reclaims-and-oom-userptr-basic
+igt@gem_shrink@reclaims-and-oom-both-basic
igt@gem_sync@basic-all
igt@gem_sync@basic-each
igt@gem_sync@basic-many-each
--
2.19.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH i-g-t v3] tests/gem_shrink: Exercise OOM and other routes to shrinking in reasonable time
2019-01-07 18:22 ` [PATCH i-g-t v3] " Tvrtko Ursulin
@ 2019-01-08 10:57 ` Chris Wilson
0 siblings, 0 replies; 12+ messages in thread
From: Chris Wilson @ 2019-01-08 10:57 UTC (permalink / raw)
To: Tvrtko Ursulin, igt-dev; +Cc: Intel-gfx
Quoting Tvrtko Ursulin (2019-01-07 18:22:44)
> From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>
> A set of subtests which exercises different paths to our shrinker code
> (including the OOM killer) in predictable and reasonable time budget.
>
> v2:
> * Fix blacklist regexp. (Petri Latvala)
>
> v3:
> * Skip userptr test if not userptr support.
>
> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> ---
> lib/igt_core.c | 19 ++
> lib/igt_core.h | 1 +
> tests/i915/gem_shrink.c | 401 ++++++++++++++++++++++++++
> tests/intel-ci/blacklist.txt | 2 +-
> tests/intel-ci/fast-feedback.testlist | 3 +
> 5 files changed, 425 insertions(+), 1 deletion(-)
>
> diff --git a/lib/igt_core.c b/lib/igt_core.c
> index 50d6008f6c82..351da0b4e020 100644
> --- a/lib/igt_core.c
> +++ b/lib/igt_core.c
> @@ -1685,6 +1685,25 @@ void igt_stop_helper(struct igt_helper_process *proc)
> assert(helper_was_alive(proc, status));
> }
>
> +/**
> + * igt_try_stop_helper:
> + * @proc: #igt_helper_process structure
> + *
> + * Terminates a helper process if it is still running and returns true, or false
> + * if the process wasn't running.
> + */
> +bool igt_try_stop_helper(struct igt_helper_process *proc)
> +{
> + int status;
> +
> + /* failure here means the pid is already dead and so waiting is safe */
> + kill(proc->pid, proc->use_SIGKILL ? SIGKILL : SIGTERM);
> +
> + status = igt_wait_helper(proc);
> +
> + return helper_was_alive(proc, status);
> +}
> +
> static void children_exit_handler(int sig)
> {
> int status;
> diff --git a/lib/igt_core.h b/lib/igt_core.h
> index 6f8c3852a686..ed5ceebf1205 100644
> --- a/lib/igt_core.h
> +++ b/lib/igt_core.h
> @@ -795,6 +795,7 @@ bool __igt_fork_helper(struct igt_helper_process *proc);
> for (; __igt_fork_helper(proc); exit(0))
> int igt_wait_helper(struct igt_helper_process *proc);
> void igt_stop_helper(struct igt_helper_process *proc);
> +bool igt_try_stop_helper(struct igt_helper_process *proc);
>
> /* exit handler code */
>
> diff --git a/tests/i915/gem_shrink.c b/tests/i915/gem_shrink.c
> index c8e05814ee70..3d48cbebc2f9 100644
> --- a/tests/i915/gem_shrink.c
> +++ b/tests/i915/gem_shrink.c
> @@ -26,6 +26,10 @@
> *
> * Exercise the shrinker by overallocating GEM objects
> */
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/wait.h>
> +#include <fcntl.h>
>
> #include "igt.h"
> #include "igt_gt.h"
> @@ -366,6 +370,378 @@ static void reclaim(unsigned engine, int timeout)
> close(fd);
> }
>
> +static unsigned long get_meminfo(const char *info, const char *tag)
> +{
> + const char *str;
> + unsigned long val;
> +
> + str = strstr(info, tag);
> + if (str && sscanf(str + strlen(tag), " %lu", &val) == 1)
> + return val >> 10;
> +
> + igt_warn("Unrecognised /proc/meminfo field: '%s'\n", tag);
> + return 0;
> +}
> +
> +static unsigned long get_avail_ram_mb(void)
> +{
> + int fd;
> + int ret;
> + char buf[4096];
> + unsigned long ram;
> +
> + fd = open("/proc/meminfo", O_RDONLY);
> + igt_assert_fd(fd);
> +
> + ret = read(fd, buf, sizeof(buf));
> + igt_assert(ret >= 0);
> +
> + close(fd);
> +
> + ram = get_meminfo(buf, "MemAvailable:");
> + ram += get_meminfo(buf, "Buffers:");
> + ram += get_meminfo(buf, "Cached:");
> + ram += get_meminfo(buf, "SwapCached:");
> +
> + return ram;
> +}
> +
> +struct test {
> +#define TEST_BO (1)
> +#define TEST_USERPTR (2)
> + unsigned int flags;
> + int fd;
> +};
> +
> +static uint32_t __get_pages(int fd, unsigned long alloc)
> +{
> + uint32_t handle = gem_create(fd, alloc);
> +
> + gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, 0);
Only needs DOMAIN_CPU for us to call get_pages() and then avoids
excessive clflushing on !llc. (mempressure path, so I'm not sure if you
want to argue about exercising the clflush paths against mempressure.
I'd hope gem_shrink already covers that elsewhere...)
> + gem_madvise(fd, handle, I915_MADV_DONTNEED);
> +
> + return handle;
> +}
> +/*
> + * Use a specific way of using up memory until we are below a certain threshold.
> + */
> +static void *mempressure(void *arg)
> +{
> + const unsigned int free_threshold_mb = 256;
> + struct test_obj *list = NULL;
> + struct test *test = arg;
> + const unsigned int sz_mb = 2;
> + const unsigned int sz = sz_mb << 20;
> + unsigned int n = 0, max = 0;
> + unsigned int blocks;
> +
> + for (;;) {
> + unsigned long ram_mb = get_avail_ram_mb();
...
> + /*
> + * Allocate memory blocks and record the current working set
> + * size.
> + */
> + if (test->flags & TEST_BO) {
> + list[n].handle = __get_pages(test->fd, sz);
Under discussion is that in using gem_create() our bo are accounted by
Cached: in /proc/meminfo. That is we never _appear_ to decrease
avail_ram_mb when for TEST_BO. One hack for drm-tip (since we now mark
shmemfs objects as unevictable) would be to use
ram -= get_meminfo(buf, "Unevictable:");
-Chris
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2019-01-08 10:57 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-01-04 15:37 [PATCH i-g-t] tests/gem_shrink: Exercise OOM and other routes to shrinking in reasonable time Tvrtko Ursulin
2019-01-07 11:01 ` [igt-dev] " Petri Latvala
2019-01-07 11:12 ` Tvrtko Ursulin
2019-01-07 11:28 ` Petri Latvala
2019-01-07 17:33 ` Tvrtko Ursulin
2019-01-07 12:27 ` Michał Winiarski
2019-01-07 12:31 ` Chris Wilson
2019-01-07 12:52 ` Tvrtko Ursulin
2019-01-07 12:56 ` Chris Wilson
2019-01-07 17:36 ` [PATCH i-g-t v2] " Tvrtko Ursulin
2019-01-07 18:22 ` [PATCH i-g-t v3] " Tvrtko Ursulin
2019-01-08 10:57 ` Chris Wilson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox