[Intel-gfx] [PATCH i-g-t 2/4] tests/gem_pread: test reads from a bo not backed by struct page

Chris Wilson chris at chris-wilson.co.uk
Thu Oct 19 08:00:20 UTC 2017


Quoting Daniele Ceraolo Spurio (2017-10-12 23:30:42)
> Using an imported vgem bo we can test reads from an object not backed
> by struct page. These reads use different paths in the kernel.
> 
> While at it, extract some common code in an helper function and fix the
> src vs dst naming (they are the other way around).
> 
> Suggested-by: Chris Wilson <chris at chris-wilson.co.uk>
> Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio at intel.com>
> Cc: Chris Wilson <chris at chris-wilson.co.uk>
> ---
>  tests/gem_pread.c | 160 +++++++++++++++++++++++++++++++++++++-----------------
>  1 file changed, 111 insertions(+), 49 deletions(-)
> 
> diff --git a/tests/gem_pread.c b/tests/gem_pread.c
> index 39a46ed..89a9a5d 100644
> --- a/tests/gem_pread.c
> +++ b/tests/gem_pread.c
> @@ -26,6 +26,7 @@
>   */
>  
>  #include "igt.h"
> +#include "igt_vgem.h"
>  #include <unistd.h>
>  #include <stdlib.h>
>  #include <stdint.h>
> @@ -73,25 +74,91 @@ static const char *bytes_per_sec(char *buf, double v)
>         return buf;
>  }
>  
> +static void do_read_loop(int fd, const char *name, uint32_t handle,
> +                        uint32_t *dst, int size)
> +{
> +       int count;
> +       double usecs;
> +       char buf[100];
> +       const char* bps;
> +       unsigned i;
> +
> +       for (count = 1; count <= 1<<17; count <<= 1) {
> +               struct timeval start, end;
> +
> +               memset(dst, 0, size);
> +               gettimeofday(&start, NULL);
> +               do_gem_read(fd, handle, dst, size, count);
> +               gettimeofday(&end, NULL);
> +               usecs = elapsed(&start, &end, count);
> +               bps = bytes_per_sec(buf, size/usecs*1e6);
> +               igt_info("Time to %s pread %d bytes x %6d:      %7.3fµs, %s\n",
> +                        name, size, count, usecs, bps);
> +               fflush(stdout);
> +
> +               for (i = 0; i < size / 4096; i++)
> +                       igt_assert_eq(dst[i * 1024], i);
> +       }
> +}

Which of course shouldn't exist in a plain test. We have benchmarks/ to
cover this. (Linking each benchmark to its conformance test would be
useful.)

> +
> +static uint32_t create_i915_bo(int fd, uint64_t size)
> +{
> +       uint32_t handle = gem_create(fd, size);
> +       uint32_t *ptr;
> +       unsigned i;

igt_skip_on(overflows_type(size, size_t));

We have an interesting challenge here with u64 and 32b intptr_t.

> +
> +       ptr = gem_mmap__cpu(fd, handle, 0, size, PROT_WRITE);
> +       gem_set_domain(fd, handle, I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
> +       for (i = 0; i < size / 4096; i++)

for (size_t i = 0; i < size/4096; i++)

> +               ptr[i * 1024] = i;
> +       munmap(ptr, size);
> +       return handle;
> +}
> +
> +/*
> + * imported BOs are not backed by struct page and therefore the preads go
> + * through different driver paths compared to a normal bo
> + */
> +static uint32_t create_foreign_bo(int fd, uint64_t size)
> +{
> +       struct vgem_bo scratch;
> +       int vgem;
> +       uint32_t handle;
> +       uint32_t *ptr;
> +       unsigned i;
> +
> +       vgem = drm_open_driver(DRIVER_VGEM);
>  
> -uint32_t *src, dst;
> -int fd, count;
> +       scratch.width = 1024;
> +       scratch.height = size / 4096;
> +       scratch.bpp = 32;
> +       handle = vgem_create_and_import(vgem, &scratch, fd, NULL);
> +       igt_assert_eq(size, scratch.size);
> +
> +       ptr = vgem_mmap(vgem, &scratch, PROT_WRITE);
> +       for (i = 0; i < size / 4096; i++)
> +               ptr[i * 1024] = i;
> +       munmap(ptr, scratch.size);
> +
> +       close(vgem);
> +
> +       return handle;
> +}
>  
>  int main(int argc, char **argv)
>  {
> +       int fd;
> +       uint32_t *dst;
> +       uint32_t handle;
>         int object_size = 0;
> -       double usecs;
> -       char buf[100];
> -       const char* bps;
>         const struct {
> -               int level;
> -               const char *name;
> -       } cache[] = {
> -               { 0, "uncached" },
> -               { 1, "snoop" },
> -               { 2, "display" },
> -               { -1 },
> -       }, *c;
> +               const char *prefix;
> +               uint32_t (*bo_create)(int fd, uint64_t size);
> +       } modes[] = {
> +               { "", create_i915_bo },
> +               { "foreign-bo-", create_foreign_bo },
> +               { NULL, NULL }
> +       }, *m;
>  
>         igt_subtest_init(argc, argv);
>         igt_skip_on_simulation();
> @@ -104,49 +171,44 @@ int main(int argc, char **argv)
>  
>         igt_fixture {
>                 fd = drm_open_driver(DRIVER_INTEL);
> -
> -               dst = gem_create(fd, object_size);
> -               src = malloc(object_size);
> -       }
> -
> -       igt_subtest("basic") {
> -               for (count = 1; count <= 1<<17; count <<= 1) {
> -                       struct timeval start, end;
> -
> -                       gettimeofday(&start, NULL);
> -                       do_gem_read(fd, dst, src, object_size, count);
> -                       gettimeofday(&end, NULL);
> -                       usecs = elapsed(&start, &end, count);
> -                       bps = bytes_per_sec(buf, object_size/usecs*1e6);
> -                       igt_info("Time to pread %d bytes x %6d: %7.3fµs, %s\n",
> -                                object_size, count, usecs, bps);
> -                       fflush(stdout);
> -               }
> +               dst = malloc(object_size);
> +               igt_assert(dst);
>         }
>  
> -       for (c = cache; c->level != -1; c++) {
> -               igt_subtest(c->name) {
> -                       gem_set_caching(fd, dst, c->level);
> -
> -                       for (count = 1; count <= 1<<17; count <<= 1) {
> -                               struct timeval start, end;
> -
> -                               gettimeofday(&start, NULL);
> -                               do_gem_read(fd, dst, src, object_size, count);
> -                               gettimeofday(&end, NULL);
> -                               usecs = elapsed(&start, &end, count);
> -                               bps = bytes_per_sec(buf, object_size/usecs*1e6);
> -                               igt_info("Time to %s pread %d bytes x %6d:      %7.3fµs, %s\n",
> -                                        c->name, object_size, count, usecs, bps);
> -                               fflush(stdout);
> +       for (m = modes; m->bo_create != NULL; m++) {
> +               igt_subtest_group {
> +                       const struct {
> +                               int level;
> +                               const char *name;
> +                       } cache[] = {
> +                               { 0, "uncached" },
> +                               { 1, "snoop" },
> +                               { 2, "display" },
> +                               { -1 },
> +                       }, *c;
> +
> +                       igt_fixture
> +                               handle = m->bo_create(fd, object_size);
> +
> +                       igt_subtest_f("%sbasic", m->prefix)
> +                               do_read_loop(fd, "basic", handle, dst,
> +                                            object_size);
> +
> +                       for (c = cache; c->level != -1; c++) {
> +                               igt_subtest_f("%s%s", m->prefix, c->name) {
> +                                       gem_set_caching(fd, handle, c->level);
> +                                       do_read_loop(fd, c->name, handle, dst,
> +                                                    object_size);
> +                               }
>                         }

Oh dear. We need stateless tests as well, i.e. since the handle is
common the driver execution paths will vary depending upon the sequence
of subtests; and in particular running this by hand will give a
different result to CI running each subtest individually.
-Chris


More information about the Intel-gfx mailing list