[Intel-gfx] [PATCH i-g-t v3] tests/gem_shrink: Exercise OOM and other routes to shrinking in reasonable time

Chris Wilson chris at chris-wilson.co.uk
Tue Jan 8 10:57:37 UTC 2019


Quoting Tvrtko Ursulin (2019-01-07 18:22:44)
> From: Tvrtko Ursulin <tvrtko.ursulin at 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 at 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


More information about the Intel-gfx mailing list