Skip to content

Commit

Permalink
perf session: Fix loading of compressed data split across adjacent re…
Browse files Browse the repository at this point in the history
…cords

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>
  • Loading branch information
Alexey Budankov authored and Arnaldo Carvalho de Melo committed Jul 23, 2019
1 parent 146540f commit 872c8ee
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 10 deletions.
22 changes: 14 additions & 8 deletions tools/perf/util/session.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,27 @@ static int perf_session__process_compressed_event(struct perf_session *session,
void *src;
size_t decomp_size, src_size;
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;

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);
if (decomp == MAP_FAILED) {
pr_err("Couldn't allocate memory for decompression\n");
return -1;
}

decomp->file_pos = file_offset;
decomp->mmap_len = mmap_len;
decomp->head = 0;

if (decomp_last) {
decomp_last_rem = decomp_last->size - decomp_last->head;
if (decomp_last_rem) {
memcpy(decomp->data, &(decomp_last->data[decomp_last->head]), decomp_last_rem);
decomp->size = decomp_last_rem;
}
Expand All @@ -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->data[decomp_last_rem]), decomp_len - decomp_last_rem);
if (!decomp_size) {
munmap(decomp, sizeof(struct decomp) + decomp_len);
munmap(decomp, mmap_len);
pr_err("Couldn't decompress data\n");
return -1;
}
Expand Down Expand Up @@ -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)
{
struct decomp *next, *decomp;
size_t decomp_len;
size_t mmap_len;
next = session->decomp;
decomp_len = session->header.env.comp_mmap_len;
do {
decomp = next;
if (decomp == NULL)
break;
next = decomp->next;
munmap(decomp, decomp_len + sizeof(struct decomp));
mmap_len = decomp->mmap_len;
munmap(decomp, mmap_len);
} while (1);
}

Expand Down
1 change: 1 addition & 0 deletions tools/perf/util/session.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ struct perf_session {
struct decomp {
struct decomp *next;
u64 file_pos;
size_t mmap_len;
u64 head;
size_t size;
char data[];
Expand Down
4 changes: 2 additions & 2 deletions tools/perf/util/zstd.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ size_t zstd_decompress_stream(struct zstd_data *data, void *src, size_t src_size
while (input.pos < input.size) {
ret = ZSTD_decompressStream(data->dstream, &output, &input);
if (ZSTD_isError(ret)) {
pr_err("failed to decompress (B): %ld -> %ld : %s\n",
src_size, output.size, ZSTD_getErrorName(ret));
pr_err("failed to decompress (B): %ld -> %ld, dst_size %ld : %s\n",
src_size, output.size, dst_size, ZSTD_getErrorName(ret));
break;
}
output.dst = dst + output.pos;
Expand Down

0 comments on commit 872c8ee

Please sign in to comment.