[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