perf session: Fix loading of compressed data split across adjacent records
Fix decompression failure found during the loading of compressed trace collected on larger scale systems (>48 cores). The error happened due to lack of decompression space for a mmaped buffer data chunk split across adjacent PERF_RECORD_COMPRESSED records. $ perf report -i bt.16384.data --stats failed to decompress (B): 63869 -> 0 : Destination buffer is too small user stack dump failure Can't parse sample, err = -14 0x2637e436 [0x4080]: failed to process type: 9 Error: failed to process sample $ perf test 71 71: Zstd perf.data compression/decompression : Ok Signed-off-by: Alexey Budankov <alexey.budankov@linux.intel.com> Acked-by: Jiri Olsa <jolsa@kernel.org> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Link: http://lkml.kernel.org/r/4d839e1b-9c48-89c4-9702-a12217420611@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
146540fb54
commit
872c8ee8f0
|
@ -36,10 +36,16 @@ static int perf_session__process_compressed_event(struct perf_session *session,
|
||||||
void *src;
|
void *src;
|
||||||
size_t decomp_size, src_size;
|
size_t decomp_size, src_size;
|
||||||
u64 decomp_last_rem = 0;
|
u64 decomp_last_rem = 0;
|
||||||
size_t decomp_len = session->header.env.comp_mmap_len;
|
size_t mmap_len, decomp_len = session->header.env.comp_mmap_len;
|
||||||
struct decomp *decomp, *decomp_last = session->decomp_last;
|
struct decomp *decomp, *decomp_last = session->decomp_last;
|
||||||
|
|
||||||
decomp = mmap(NULL, sizeof(struct decomp) + decomp_len, PROT_READ|PROT_WRITE,
|
if (decomp_last) {
|
||||||
|
decomp_last_rem = decomp_last->size - decomp_last->head;
|
||||||
|
decomp_len += decomp_last_rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
mmap_len = sizeof(struct decomp) + decomp_len;
|
||||||
|
decomp = mmap(NULL, mmap_len, PROT_READ|PROT_WRITE,
|
||||||
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
|
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
|
||||||
if (decomp == MAP_FAILED) {
|
if (decomp == MAP_FAILED) {
|
||||||
pr_err("Couldn't allocate memory for decompression\n");
|
pr_err("Couldn't allocate memory for decompression\n");
|
||||||
|
@ -47,10 +53,10 @@ static int perf_session__process_compressed_event(struct perf_session *session,
|
||||||
}
|
}
|
||||||
|
|
||||||
decomp->file_pos = file_offset;
|
decomp->file_pos = file_offset;
|
||||||
|
decomp->mmap_len = mmap_len;
|
||||||
decomp->head = 0;
|
decomp->head = 0;
|
||||||
|
|
||||||
if (decomp_last) {
|
if (decomp_last_rem) {
|
||||||
decomp_last_rem = decomp_last->size - decomp_last->head;
|
|
||||||
memcpy(decomp->data, &(decomp_last->data[decomp_last->head]), decomp_last_rem);
|
memcpy(decomp->data, &(decomp_last->data[decomp_last->head]), decomp_last_rem);
|
||||||
decomp->size = decomp_last_rem;
|
decomp->size = decomp_last_rem;
|
||||||
}
|
}
|
||||||
|
@ -61,7 +67,7 @@ static int perf_session__process_compressed_event(struct perf_session *session,
|
||||||
decomp_size = zstd_decompress_stream(&(session->zstd_data), src, src_size,
|
decomp_size = zstd_decompress_stream(&(session->zstd_data), src, src_size,
|
||||||
&(decomp->data[decomp_last_rem]), decomp_len - decomp_last_rem);
|
&(decomp->data[decomp_last_rem]), decomp_len - decomp_last_rem);
|
||||||
if (!decomp_size) {
|
if (!decomp_size) {
|
||||||
munmap(decomp, sizeof(struct decomp) + decomp_len);
|
munmap(decomp, mmap_len);
|
||||||
pr_err("Couldn't decompress data\n");
|
pr_err("Couldn't decompress data\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -255,15 +261,15 @@ static void perf_session__delete_threads(struct perf_session *session)
|
||||||
static void perf_session__release_decomp_events(struct perf_session *session)
|
static void perf_session__release_decomp_events(struct perf_session *session)
|
||||||
{
|
{
|
||||||
struct decomp *next, *decomp;
|
struct decomp *next, *decomp;
|
||||||
size_t decomp_len;
|
size_t mmap_len;
|
||||||
next = session->decomp;
|
next = session->decomp;
|
||||||
decomp_len = session->header.env.comp_mmap_len;
|
|
||||||
do {
|
do {
|
||||||
decomp = next;
|
decomp = next;
|
||||||
if (decomp == NULL)
|
if (decomp == NULL)
|
||||||
break;
|
break;
|
||||||
next = decomp->next;
|
next = decomp->next;
|
||||||
munmap(decomp, decomp_len + sizeof(struct decomp));
|
mmap_len = decomp->mmap_len;
|
||||||
|
munmap(decomp, mmap_len);
|
||||||
} while (1);
|
} while (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@ struct perf_session {
|
||||||
struct decomp {
|
struct decomp {
|
||||||
struct decomp *next;
|
struct decomp *next;
|
||||||
u64 file_pos;
|
u64 file_pos;
|
||||||
|
size_t mmap_len;
|
||||||
u64 head;
|
u64 head;
|
||||||
size_t size;
|
size_t size;
|
||||||
char data[];
|
char data[];
|
||||||
|
|
|
@ -99,8 +99,8 @@ size_t zstd_decompress_stream(struct zstd_data *data, void *src, size_t src_size
|
||||||
while (input.pos < input.size) {
|
while (input.pos < input.size) {
|
||||||
ret = ZSTD_decompressStream(data->dstream, &output, &input);
|
ret = ZSTD_decompressStream(data->dstream, &output, &input);
|
||||||
if (ZSTD_isError(ret)) {
|
if (ZSTD_isError(ret)) {
|
||||||
pr_err("failed to decompress (B): %ld -> %ld : %s\n",
|
pr_err("failed to decompress (B): %ld -> %ld, dst_size %ld : %s\n",
|
||||||
src_size, output.size, ZSTD_getErrorName(ret));
|
src_size, output.size, dst_size, ZSTD_getErrorName(ret));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
output.dst = dst + output.pos;
|
output.dst = dst + output.pos;
|
||||||
|
|
Loading…
Reference in New Issue