Re: [Intel-gfx] [PATCH i-g-t 3/8] tests/i915/gem_exec_capture: Make the error decode a common helper

Matthew Brost
2021-10-29T02:39:25Z

On Thu, Oct 21, 2021 at 04:40:39PM -0700, John.C.Harrison@Intel.com wrote:
> From: John Harrison <John.C.Harrison@Intel.com>
>
> The decode of the error capture contents was happening in two
> different sub-tests with two very different pieces of code. One being
> much more extensive than the other (actually decodes and verifies the
> contents of the captured buffers rather than just the address). So,
> move the code into a common helper function and use that in both
> places.
>
> Signed-off-by: John Harrison <John.C.Harrison@Intel.com>

Reviewed-by: Matthew Brost <matthew.brost@intel.com>

> ---
> tests/i915/gem_exec_capture.c | 344 +++++++++++++++++-----------------
> 1 file changed, 170 insertions(+), 174 deletions(-)
>
> diff --git a/tests/i915/gem_exec_capture.c b/tests/i915/gem_exec_capture.c
> index 47ca64dd6..c85c198f7 100644
> --- a/tests/i915/gem_exec_capture.c
> +++ b/tests/i915/gem_exec_capture.c
> @@ -33,32 +33,175 @@
>
> IGT_TEST_DESCRIPTION("Check that we capture the user specified objects on a hang");
>
> -static void check_error_state(int dir, struct drm_i915_gem_exec_object2 *obj)
> +struct offset {
> + uint64_t addr;
> + unsigned long idx;
> + bool found;
> +};
> +
> +static unsigned long zlib_inflate(uint32_t **ptr, unsigned long len)
> +{
> + struct z_stream_s zstream;
> + void *out;
> +
> + memset(&zstream, 0, sizeof(zstream));
> +
> + zstream.next_in = (unsigned char *)*ptr;
> + zstream.avail_in = 4*len;
> +
> + if (inflateInit(&zstream) != Z_OK)
> + return 0;
> +
> + out = malloc(128*4096); /* approximate obj size */
> + zstream.next_out = out;
> + zstream.avail_out = 128*4096;
> +
> + do {
> + switch (inflate(&zstream, Z_SYNC_FLUSH)) {
> + case Z_STREAM_END:
> + goto end;
> + case Z_OK:
> + break;
> + default:
> + inflateEnd(&zstream);
> + return 0;
> + }
> +
> + if (zstream.avail_out)
> + break;
> +
> + out = realloc(out, 2*zstream.total_out);
> + if (out == NULL) {
> + inflateEnd(&zstream);
> + return 0;
> + }
> +
> + zstream.next_out = (unsigned char *)out + zstream.total_out;
> + zstream.avail_out = zstream.total_out;
> + } while (1);
> +end:
> + inflateEnd(&zstream);
> + free(*ptr);
> + *ptr = out;
> + return zstream.total_out / 4;
> +}
> +
> +static unsigned long
> +ascii85_decode(char *in, uint32_t **out, bool inflate, char **end)
> +{
> + unsigned long len = 0, size = 1024;
> +
> + *out = realloc(*out, sizeof(uint32_t)*size);
> + if (*out == NULL)
> + return 0;
> +
> + while (*in >= '!' && *in <= 'z') {
> + uint32_t v = 0;
> +
> + if (len == size) {
> + size *= 2;
> + *out = realloc(*out, sizeof(uint32_t)*size);
> + if (*out == NULL)
> + return 0;
> + }
> +
> + if (*in == 'z') {
> + in++;
> + } else {
> + v += in[0] - 33; v *= 85;
> + v += in[1] - 33; v *= 85;
> + v += in[2] - 33; v *= 85;
> + v += in[3] - 33; v *= 85;
> + v += in[4] - 33;
> + in += 5;
> + }
> + (*out)[len++] = v;
> + }
> + *end = in;
> +
> + if (!inflate)
> + return len;
> +
> + return zlib_inflate(out, len);
> +}
> +
> +static int check_error_state(int dir, struct offset *obj_offsets, int obj_count,
> + uint64_t obj_size, bool incremental)
> {
> char *error, *str;
> - bool found = false;
> + int blobs = 0;
>
> error = igt_sysfs_get(dir, "error");
> igt_sysfs_set(dir, "error", "Begone!");
> -
> igt_assert(error);
> igt_debug("%s\n", error);
>
> /* render ring --- user = 0x00000000 ffffd000 */
> - for (str = error; (str = strstr(str, "--- user = ")); str++) {
> + for (str = error; (str = strstr(str, "--- user = ")); ) {
> + uint32_t *data = NULL;
> uint64_t addr;
> - uint32_t hi, lo;
> + unsigned long i, sz;
> + unsigned long start;
> + unsigned long end;
>
> - igt_assert(sscanf(str, "--- user = 0x%x %x", &hi, &lo) == 2);
> - addr = hi;
> + if (strncmp(str, "--- user = 0x", 13))
> + break;
> + str += 13;
> + addr = strtoul(str, &str, 16);
> addr <<= 32;
> - addr |= lo;
> - igt_assert_eq_u64(addr, obj->offset);
> - found = true;
> + addr |= strtoul(str + 1, &str, 16);
> + igt_assert(*str++ == '\n');
> +
> + start = 0;
> + end = obj_count;
> + while (end > start) {
> + i = (end - start) / 2 + start;
> + if (obj_offsets[i].addr < addr)
> + start = i + 1;
> + else if (obj_offsets[i].addr > addr)
> + end = i;
> + else
> + break;
> + }
> + igt_assert(obj_offsets[i].addr == addr);
> + igt_assert(!obj_offsets[i].found);
> + obj_offsets[i].found = true;
> + igt_debug("offset:%"PRIx64", index:%ld\n",
> + addr, obj_offsets[i].idx);
> +
> + /* gtt_page_sizes = 0x00010000 */
> + if (strncmp(str, "gtt_page_sizes = 0x", 19) == 0) {
> + str += 19 + 8;
> + igt_assert(*str++ == '\n');
> + }
> +
> + if (!(*str == ':' || *str == '~'))
> + continue;
> +
> + igt_debug("blob:%.64s\n", str);
> + sz = ascii85_decode(str + 1, &data, *str == ':', &str);
> +
> + igt_assert_eq(4 * sz, obj_size);
> + igt_assert(*str++ == '\n');
> + str = strchr(str, '-');
> +
> + if (incremental) {
> + uint32_t expect;
> +
> + expect = obj_offsets[i].idx * obj_size;
> + for (i = 0; i < sz; i++)
> + igt_assert_eq(data[i], expect++);
> + } else {
> + for (i = 0; i < sz; i++)
> + igt_assert_eq(data[i], 0);
> + }
> +
> + blobs++;
> + free(data);
> }
>
> free(error);
> - igt_assert(found);
> + return blobs;
> }
>
> static void __capture1(int fd, int dir, uint64_t ahnd, const intel_ctx_t *ctx,
> @@ -73,6 +216,7 @@ static void __capture1(int fd, int dir, uint64_t ahnd, const intel_ctx_t *ctx,
> struct drm_i915_gem_relocation_entry reloc[2];
> struct drm_i915_gem_execbuffer2 execbuf;
> uint32_t *batch, *seqno;
> + struct offset offset;
> int i;
>
> memset(obj, 0, sizeof(obj));
> @@ -168,7 +312,10 @@ static void __capture1(int fd, int dir, uint64_t ahnd, const intel_ctx_t *ctx,
>
> /* Check that only the buffer we marked is reported in the error */
> igt_force_gpu_reset(fd);
> - check_error_state(dir, &obj[CAPTURE]);
> + memset(&offset, 0, sizeof(offset));
> + offset.addr = obj[CAPTURE].offset;
> + igt_assert_eq(check_error_state(dir, &offset, 1, target_size, false), 1);
> + igt_assert(offset.found);
>
> gem_sync(fd, obj[BATCH].handle);
>
> @@ -183,11 +330,12 @@ static void capture(int fd, int dir, const intel_ctx_t *ctx, unsigned ring)
> {
> uint32_t handle;
> uint64_t ahnd;
> + int obj_size = 4096;
>
> - handle = gem_create(fd, 4096);
> + handle = gem_create(fd, obj_size);
> ahnd = get_reloc_ahnd(fd, ctx->id);
>
> - __capture1(fd, dir, ahnd, ctx, ring, handle, 4096);
> + __capture1(fd, dir, ahnd, ctx, ring, handle, obj_size);
>
> gem_close(fd, handle);
> put_ahnd(ahnd);
> @@ -206,10 +354,8 @@ static int cmp(const void *A, const void *B)
> return 0;
> }
>
> -static struct offset {
> - uint64_t addr;
> - unsigned long idx;
> -} *__captureN(int fd, int dir, uint64_t ahnd, unsigned ring,
> +static struct offset *
> +__captureN(int fd, int dir, uint64_t ahnd, unsigned ring,
> unsigned int size, int count,
> unsigned int flags)
> #define INCREMENTAL 0x1
> @@ -357,98 +503,11 @@ static struct offset {
> return offsets;
> }
>
> -static unsigned long zlib_inflate(uint32_t **ptr, unsigned long len)
> -{
> - struct z_stream_s zstream;
> - void *out;
> -
> - memset(&zstream, 0, sizeof(zstream));
> -
> - zstream.next_in = (unsigned char *)*ptr;
> - zstream.avail_in = 4*len;
> -
> - if (inflateInit(&zstream) != Z_OK)
> - return 0;
> -
> - out = malloc(128*4096); /* approximate obj size */
> - zstream.next_out = out;
> - zstream.avail_out = 128*4096;
> -
> - do {
> - switch (inflate(&zstream, Z_SYNC_FLUSH)) {
> - case Z_STREAM_END:
> - goto end;
> - case Z_OK:
> - break;
> - default:
> - inflateEnd(&zstream);
> - return 0;
> - }
> -
> - if (zstream.avail_out)
> - break;
> -
> - out = realloc(out, 2*zstream.total_out);
> - if (out == NULL) {
> - inflateEnd(&zstream);
> - return 0;
> - }
> -
> - zstream.next_out = (unsigned char *)out + zstream.total_out;
> - zstream.avail_out = zstream.total_out;
> - } while (1);
> -end:
> - inflateEnd(&zstream);
> - free(*ptr);
> - *ptr = out;
> - return zstream.total_out / 4;
> -}
> -
> -static unsigned long
> -ascii85_decode(char *in, uint32_t **out, bool inflate, char **end)
> -{
> - unsigned long len = 0, size = 1024;
> -
> - *out = realloc(*out, sizeof(uint32_t)*size);
> - if (*out == NULL)
> - return 0;
> -
> - while (*in >= '!' && *in <= 'z') {
> - uint32_t v = 0;
> -
> - if (len == size) {
> - size *= 2;
> - *out = realloc(*out, sizeof(uint32_t)*size);
> - if (*out == NULL)
> - return 0;
> - }
> -
> - if (*in == 'z') {
> - in++;
> - } else {
> - v += in[0] - 33; v *= 85;
> - v += in[1] - 33; v *= 85;
> - v += in[2] - 33; v *= 85;
> - v += in[3] - 33; v *= 85;
> - v += in[4] - 33;
> - in += 5;
> - }
> - (*out)[len++] = v;
> - }
> - *end = in;
> -
> - if (!inflate)
> - return len;
> -
> - return zlib_inflate(out, len);
> -}
> -
> static void many(int fd, int dir, uint64_t size, unsigned int flags)
> {
> uint64_t ram, gtt, ahnd;
> unsigned long count, blobs;
> struct offset *offsets;
> - char *error, *str;
>
> gtt = gem_aperture_size(fd) / size;
> ram = (intel_get_avail_ram_mb() << 20) / size;
> @@ -463,75 +522,10 @@ static void many(int fd, int dir, uint64_t size, unsigned int flags)
>
> offsets = __captureN(fd, dir, ahnd, 0, size, count, flags);
>
> - error = igt_sysfs_get(dir, "error");
> - igt_sysfs_set(dir, "error", "Begone!");
> - igt_assert(error);
> -
> - blobs = 0;
> - /* render ring --- user = 0x00000000 ffffd000 */
> - str = strstr(error, "--- user = ");
> - while (str) {
> - uint32_t *data = NULL;
> - unsigned long i, sz;
> - uint64_t addr;
> -
> - if (strncmp(str, "--- user = 0x", 13))
> - break;
> -
> - str += 13;
> - addr = strtoul(str, &str, 16);
> - addr <<= 32;
> - addr |= strtoul(str + 1, &str, 16);
> - igt_assert(*str++ == '\n');
> -
> - /* gtt_page_sizes = 0x00010000 */
> - if (strncmp(str, "gtt_page_sizes = 0x", 19) == 0) {
> - str += 19 + 8;
> - igt_assert(*str++ == '\n');
> - }
> -
> - if (!(*str == ':' || *str == '~'))
> - continue;
> -
> - igt_debug("blob:%.64s\n", str);
> - sz = ascii85_decode(str + 1, &data, *str == ':', &str);
> - igt_assert_eq(4 * sz, size);
> - igt_assert(*str++ == '\n');
> - str = strchr(str, '-');
> -
> - if (flags & INCREMENTAL) {
> - unsigned long start = 0;
> - unsigned long end = count;
> - uint32_t expect;
> -
> - while (end > start) {
> - i = (end - start) / 2 + start;
> - if (offsets[i].addr < addr)
> - start = i + 1;
> - else if (offsets[i].addr > addr)
> - end = i;
> - else
> - break;
> - }
> - igt_assert(offsets[i].addr == addr);
> - igt_debug("offset:%"PRIx64", index:%ld\n",
> - addr, offsets[i].idx);
> -
> - expect = offsets[i].idx * size;
> - for (i = 0; i < sz; i++)
> - igt_assert_eq(data[i], expect++);
> - } else {
> - for (i = 0; i < sz; i++)
> - igt_assert_eq(data[i], 0);
> - }
> -
> - blobs++;
> - free(data);
> - }
> + blobs = check_error_state(dir, offsets, count, size, !!(flags & INCREMENTAL));
> igt_info("Captured %lu %"PRId64"-blobs out of a total of %lu\n",
> blobs, size >> 12, count);
>
> - free(error);
> free(offsets);
> put_ahnd(ahnd);
> }
> @@ -625,12 +619,14 @@ static void userptr(int fd, int dir)
> uint32_t handle;
> uint64_t ahnd;
> void *ptr;
> + int obj_size = 4096;
>
> - igt_assert(posix_memalign(&ptr, 4096, 4096) == 0);
> - igt_require(__gem_userptr(fd, ptr, 4096, 0, 0, &handle) == 0);
> + igt_assert(posix_memalign(&ptr, obj_size, obj_size) == 0);
> + memset(ptr, 0, obj_size);
> + igt_require(__gem_userptr(fd, ptr, obj_size, 0, 0, &handle) == 0);
> ahnd = get_reloc_ahnd(fd, ctx->id);
>
> - __capture1(fd, dir, ahnd, intel_ctx_0(fd), 0, handle, 4096);
> + __capture1(fd, dir, ahnd, intel_ctx_0(fd), 0, handle, obj_size);
>
> gem_close(fd, handle);
> put_ahnd(ahnd);
> --
> 2.25.1
>