drm/msm: Optimize adreno_show_object()

When the userspace tries to read the crashstate dump, the read side
implementation in the driver currently ascii85 encodes all the binary
buffers and it does this each time the read system call is called.
A userspace tool like cat typically does a page by page read and the
number of read calls depends on the size of the data captured by the
driver. This is certainly not desirable and does not scale well with
large captures.

This patch encodes the buffer only once in the read path. With this there
is an immediate >10X speed improvement in crashstate save time.

Signed-off-by: Sharat Masetty <smasetty@codeaurora.org>
Reviewed-by: Jordan Crouse <jcrouse@codeaurora.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>
This commit is contained in:
Sharat Masetty 2018-11-01 20:16:45 +05:30 committed by Rob Clark
parent 84c6127580
commit 1df4289d5b
2 changed files with 63 additions and 21 deletions

View File

@ -398,7 +398,7 @@ int adreno_gpu_state_get(struct msm_gpu *gpu, struct msm_gpu_state *state)
size = j + 1; size = j + 1;
if (size) { if (size) {
state->ring[i].data = kmalloc(size << 2, GFP_KERNEL); state->ring[i].data = kvmalloc(size << 2, GFP_KERNEL);
if (state->ring[i].data) { if (state->ring[i].data) {
memcpy(state->ring[i].data, gpu->rb[i]->start, size << 2); memcpy(state->ring[i].data, gpu->rb[i]->start, size << 2);
state->ring[i].data_size = size << 2; state->ring[i].data_size = size << 2;
@ -441,7 +441,7 @@ void adreno_gpu_state_destroy(struct msm_gpu_state *state)
int i; int i;
for (i = 0; i < ARRAY_SIZE(state->ring); i++) for (i = 0; i < ARRAY_SIZE(state->ring); i++)
kfree(state->ring[i].data); kvfree(state->ring[i].data);
for (i = 0; state->bos && i < state->nr_bos; i++) for (i = 0; state->bos && i < state->nr_bos; i++)
kvfree(state->bos[i].data); kvfree(state->bos[i].data);
@ -471,34 +471,74 @@ int adreno_gpu_state_put(struct msm_gpu_state *state)
#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) #if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP)
static void adreno_show_object(struct drm_printer *p, u32 *ptr, int len) static char *adreno_gpu_ascii85_encode(u32 *src, size_t len)
{ {
void *buf;
size_t buf_itr = 0, buffer_size;
char out[ASCII85_BUFSZ]; char out[ASCII85_BUFSZ];
long l, datalen, i; long l;
int i;
if (!ptr || !len) if (!src || !len)
return; return NULL;
l = ascii85_encode_len(len);
/* /*
* Only dump the non-zero part of the buffer - rarely will any data * Ascii85 outputs either a 5 byte string or a 1 byte string. So we
* completely fill the entire allocated size of the buffer * account for the worst case of 5 bytes per dword plus the 1 for '\0'
*/ */
for (datalen = 0, i = 0; i < len >> 2; i++) { buffer_size = (l * 5) + 1;
if (ptr[i])
datalen = (i << 2) + 1;
}
/* Skip printing the object if it is empty */ buf = kvmalloc(buffer_size, GFP_KERNEL);
if (datalen == 0) if (!buf)
return NULL;
for (i = 0; i < l; i++)
buf_itr += snprintf(buf + buf_itr, buffer_size - buf_itr, "%s",
ascii85_encode(src[i], out));
return buf;
}
/* len is expected to be in bytes */
static void adreno_show_object(struct drm_printer *p, void **ptr, int len,
bool *encoded)
{
if (!*ptr || !len)
return; return;
l = ascii85_encode_len(datalen); if (!*encoded) {
long datalen, i;
u32 *buf = *ptr;
/*
* Only dump the non-zero part of the buffer - rarely will
* any data completely fill the entire allocated size of
* the buffer.
*/
for (datalen = 0, i = 0; i < len >> 2; i++)
if (buf[i])
datalen = ((i + 1) << 2);
/*
* If we reach here, then the originally captured binary buffer
* will be replaced with the ascii85 encoded string
*/
*ptr = adreno_gpu_ascii85_encode(buf, datalen);
kvfree(buf);
*encoded = true;
}
if (!*ptr)
return;
drm_puts(p, " data: !!ascii85 |\n"); drm_puts(p, " data: !!ascii85 |\n");
drm_puts(p, " "); drm_puts(p, " ");
for (i = 0; i < l; i++) drm_puts(p, *ptr);
drm_puts(p, ascii85_encode(ptr[i], out));
drm_puts(p, "\n"); drm_puts(p, "\n");
} }
@ -530,8 +570,8 @@ void adreno_show(struct msm_gpu *gpu, struct msm_gpu_state *state,
drm_printf(p, " wptr: %d\n", state->ring[i].wptr); drm_printf(p, " wptr: %d\n", state->ring[i].wptr);
drm_printf(p, " size: %d\n", MSM_GPU_RINGBUFFER_SZ); drm_printf(p, " size: %d\n", MSM_GPU_RINGBUFFER_SZ);
adreno_show_object(p, state->ring[i].data, adreno_show_object(p, &state->ring[i].data,
state->ring[i].data_size); state->ring[i].data_size, &state->ring[i].encoded);
} }
if (state->bos) { if (state->bos) {
@ -542,8 +582,8 @@ void adreno_show(struct msm_gpu *gpu, struct msm_gpu_state *state,
state->bos[i].iova); state->bos[i].iova);
drm_printf(p, " size: %zd\n", state->bos[i].size); drm_printf(p, " size: %zd\n", state->bos[i].size);
adreno_show_object(p, state->bos[i].data, adreno_show_object(p, &state->bos[i].data,
state->bos[i].size); state->bos[i].size, &state->bos[i].encoded);
} }
} }

View File

@ -187,6 +187,7 @@ struct msm_gpu_state_bo {
u64 iova; u64 iova;
size_t size; size_t size;
void *data; void *data;
bool encoded;
}; };
struct msm_gpu_state { struct msm_gpu_state {
@ -201,6 +202,7 @@ struct msm_gpu_state {
u32 wptr; u32 wptr;
void *data; void *data;
int data_size; int data_size;
bool encoded;
} ring[MSM_GPU_MAX_RINGS]; } ring[MSM_GPU_MAX_RINGS];
int nr_registers; int nr_registers;