Commit a6360cc7 authored by Adrian Hunter's avatar Adrian Hunter Committed by Stefan Bader

perf intel-pt: Fix overlap detection to identify consecutive buffers correctly

BugLink: http://bugs.launchpad.net/bugs/1768429

commit 117db4b2 upstream.

Overlap detection was not not updating the buffer's 'consecutive' flag.
Marking buffers consecutive has the advantage that decoding begins from
the start of the buffer instead of the first PSB. Fix overlap detection
to identify consecutive buffers correctly.
Signed-off-by: default avatarAdrian Hunter <adrian.hunter@intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: stable@vger.kernel.org
Link: http://lkml.kernel.org/r/1520431349-30689-2-git-send-email-adrian.hunter@intel.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarJuerg Haefliger <juergh@canonical.com>
Signed-off-by: default avatarKleber Sacilotto de Souza <kleber.souza@canonical.com>
parent 915020bb
...@@ -2152,14 +2152,6 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder) ...@@ -2152,14 +2152,6 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder)
return &decoder->state; return &decoder->state;
} }
static bool intel_pt_at_psb(unsigned char *buf, size_t len)
{
if (len < INTEL_PT_PSB_LEN)
return false;
return memmem(buf, INTEL_PT_PSB_LEN, INTEL_PT_PSB_STR,
INTEL_PT_PSB_LEN);
}
/** /**
* intel_pt_next_psb - move buffer pointer to the start of the next PSB packet. * intel_pt_next_psb - move buffer pointer to the start of the next PSB packet.
* @buf: pointer to buffer pointer * @buf: pointer to buffer pointer
...@@ -2248,6 +2240,7 @@ static unsigned char *intel_pt_last_psb(unsigned char *buf, size_t len) ...@@ -2248,6 +2240,7 @@ static unsigned char *intel_pt_last_psb(unsigned char *buf, size_t len)
* @buf: buffer * @buf: buffer
* @len: size of buffer * @len: size of buffer
* @tsc: TSC value returned * @tsc: TSC value returned
* @rem: returns remaining size when TSC is found
* *
* Find a TSC packet in @buf and return the TSC value. This function assumes * Find a TSC packet in @buf and return the TSC value. This function assumes
* that @buf starts at a PSB and that PSB+ will contain TSC and so stops if a * that @buf starts at a PSB and that PSB+ will contain TSC and so stops if a
...@@ -2255,7 +2248,8 @@ static unsigned char *intel_pt_last_psb(unsigned char *buf, size_t len) ...@@ -2255,7 +2248,8 @@ static unsigned char *intel_pt_last_psb(unsigned char *buf, size_t len)
* *
* Return: %true if TSC is found, false otherwise. * Return: %true if TSC is found, false otherwise.
*/ */
static bool intel_pt_next_tsc(unsigned char *buf, size_t len, uint64_t *tsc) static bool intel_pt_next_tsc(unsigned char *buf, size_t len, uint64_t *tsc,
size_t *rem)
{ {
struct intel_pt_pkt packet; struct intel_pt_pkt packet;
int ret; int ret;
...@@ -2266,6 +2260,7 @@ static bool intel_pt_next_tsc(unsigned char *buf, size_t len, uint64_t *tsc) ...@@ -2266,6 +2260,7 @@ static bool intel_pt_next_tsc(unsigned char *buf, size_t len, uint64_t *tsc)
return false; return false;
if (packet.type == INTEL_PT_TSC) { if (packet.type == INTEL_PT_TSC) {
*tsc = packet.payload; *tsc = packet.payload;
*rem = len;
return true; return true;
} }
if (packet.type == INTEL_PT_PSBEND) if (packet.type == INTEL_PT_PSBEND)
...@@ -2316,6 +2311,8 @@ static int intel_pt_tsc_cmp(uint64_t tsc1, uint64_t tsc2) ...@@ -2316,6 +2311,8 @@ static int intel_pt_tsc_cmp(uint64_t tsc1, uint64_t tsc2)
* @len_a: size of first buffer * @len_a: size of first buffer
* @buf_b: second buffer * @buf_b: second buffer
* @len_b: size of second buffer * @len_b: size of second buffer
* @consecutive: returns true if there is data in buf_b that is consecutive
* to buf_a
* *
* If the trace contains TSC we can look at the last TSC of @buf_a and the * If the trace contains TSC we can look at the last TSC of @buf_a and the
* first TSC of @buf_b in order to determine if the buffers overlap, and then * first TSC of @buf_b in order to determine if the buffers overlap, and then
...@@ -2328,33 +2325,41 @@ static int intel_pt_tsc_cmp(uint64_t tsc1, uint64_t tsc2) ...@@ -2328,33 +2325,41 @@ static int intel_pt_tsc_cmp(uint64_t tsc1, uint64_t tsc2)
static unsigned char *intel_pt_find_overlap_tsc(unsigned char *buf_a, static unsigned char *intel_pt_find_overlap_tsc(unsigned char *buf_a,
size_t len_a, size_t len_a,
unsigned char *buf_b, unsigned char *buf_b,
size_t len_b) size_t len_b, bool *consecutive)
{ {
uint64_t tsc_a, tsc_b; uint64_t tsc_a, tsc_b;
unsigned char *p; unsigned char *p;
size_t len; size_t len, rem_a, rem_b;
p = intel_pt_last_psb(buf_a, len_a); p = intel_pt_last_psb(buf_a, len_a);
if (!p) if (!p)
return buf_b; /* No PSB in buf_a => no overlap */ return buf_b; /* No PSB in buf_a => no overlap */
len = len_a - (p - buf_a); len = len_a - (p - buf_a);
if (!intel_pt_next_tsc(p, len, &tsc_a)) { if (!intel_pt_next_tsc(p, len, &tsc_a, &rem_a)) {
/* The last PSB+ in buf_a is incomplete, so go back one more */ /* The last PSB+ in buf_a is incomplete, so go back one more */
len_a -= len; len_a -= len;
p = intel_pt_last_psb(buf_a, len_a); p = intel_pt_last_psb(buf_a, len_a);
if (!p) if (!p)
return buf_b; /* No full PSB+ => assume no overlap */ return buf_b; /* No full PSB+ => assume no overlap */
len = len_a - (p - buf_a); len = len_a - (p - buf_a);
if (!intel_pt_next_tsc(p, len, &tsc_a)) if (!intel_pt_next_tsc(p, len, &tsc_a, &rem_a))
return buf_b; /* No TSC in buf_a => assume no overlap */ return buf_b; /* No TSC in buf_a => assume no overlap */
} }
while (1) { while (1) {
/* Ignore PSB+ with no TSC */ /* Ignore PSB+ with no TSC */
if (intel_pt_next_tsc(buf_b, len_b, &tsc_b) && if (intel_pt_next_tsc(buf_b, len_b, &tsc_b, &rem_b)) {
intel_pt_tsc_cmp(tsc_a, tsc_b) < 0) int cmp = intel_pt_tsc_cmp(tsc_a, tsc_b);
/* Same TSC, so buffers are consecutive */
if (!cmp && rem_b >= rem_a) {
*consecutive = true;
return buf_b + len_b - (rem_b - rem_a);
}
if (cmp < 0)
return buf_b; /* tsc_a < tsc_b => no overlap */ return buf_b; /* tsc_a < tsc_b => no overlap */
}
if (!intel_pt_step_psb(&buf_b, &len_b)) if (!intel_pt_step_psb(&buf_b, &len_b))
return buf_b + len_b; /* No PSB in buf_b => no data */ return buf_b + len_b; /* No PSB in buf_b => no data */
...@@ -2368,6 +2373,8 @@ static unsigned char *intel_pt_find_overlap_tsc(unsigned char *buf_a, ...@@ -2368,6 +2373,8 @@ static unsigned char *intel_pt_find_overlap_tsc(unsigned char *buf_a,
* @buf_b: second buffer * @buf_b: second buffer
* @len_b: size of second buffer * @len_b: size of second buffer
* @have_tsc: can use TSC packets to detect overlap * @have_tsc: can use TSC packets to detect overlap
* @consecutive: returns true if there is data in buf_b that is consecutive
* to buf_a
* *
* When trace samples or snapshots are recorded there is the possibility that * When trace samples or snapshots are recorded there is the possibility that
* the data overlaps. Note that, for the purposes of decoding, data is only * the data overlaps. Note that, for the purposes of decoding, data is only
...@@ -2378,7 +2385,7 @@ static unsigned char *intel_pt_find_overlap_tsc(unsigned char *buf_a, ...@@ -2378,7 +2385,7 @@ static unsigned char *intel_pt_find_overlap_tsc(unsigned char *buf_a,
*/ */
unsigned char *intel_pt_find_overlap(unsigned char *buf_a, size_t len_a, unsigned char *intel_pt_find_overlap(unsigned char *buf_a, size_t len_a,
unsigned char *buf_b, size_t len_b, unsigned char *buf_b, size_t len_b,
bool have_tsc) bool have_tsc, bool *consecutive)
{ {
unsigned char *found; unsigned char *found;
...@@ -2390,7 +2397,8 @@ unsigned char *intel_pt_find_overlap(unsigned char *buf_a, size_t len_a, ...@@ -2390,7 +2397,8 @@ unsigned char *intel_pt_find_overlap(unsigned char *buf_a, size_t len_a,
return buf_b; /* No overlap */ return buf_b; /* No overlap */
if (have_tsc) { if (have_tsc) {
found = intel_pt_find_overlap_tsc(buf_a, len_a, buf_b, len_b); found = intel_pt_find_overlap_tsc(buf_a, len_a, buf_b, len_b,
consecutive);
if (found) if (found)
return found; return found;
} }
...@@ -2405,28 +2413,16 @@ unsigned char *intel_pt_find_overlap(unsigned char *buf_a, size_t len_a, ...@@ -2405,28 +2413,16 @@ unsigned char *intel_pt_find_overlap(unsigned char *buf_a, size_t len_a,
} }
/* Now len_b >= len_a */ /* Now len_b >= len_a */
if (len_b > len_a) {
/* The leftover buffer 'b' must start at a PSB */
while (!intel_pt_at_psb(buf_b + len_a, len_b - len_a)) {
if (!intel_pt_step_psb(&buf_a, &len_a))
return buf_b; /* No overlap */
}
}
while (1) { while (1) {
/* Potential overlap so check the bytes */ /* Potential overlap so check the bytes */
found = memmem(buf_a, len_a, buf_b, len_a); found = memmem(buf_a, len_a, buf_b, len_a);
if (found) if (found) {
*consecutive = true;
return buf_b + len_a; return buf_b + len_a;
}
/* Try again at next PSB in buffer 'a' */ /* Try again at next PSB in buffer 'a' */
if (!intel_pt_step_psb(&buf_a, &len_a)) if (!intel_pt_step_psb(&buf_a, &len_a))
return buf_b; /* No overlap */ return buf_b; /* No overlap */
/* The leftover buffer 'b' must start at a PSB */
while (!intel_pt_at_psb(buf_b + len_a, len_b - len_a)) {
if (!intel_pt_step_psb(&buf_a, &len_a))
return buf_b; /* No overlap */
}
} }
} }
...@@ -102,7 +102,7 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder); ...@@ -102,7 +102,7 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder);
unsigned char *intel_pt_find_overlap(unsigned char *buf_a, size_t len_a, unsigned char *intel_pt_find_overlap(unsigned char *buf_a, size_t len_a,
unsigned char *buf_b, size_t len_b, unsigned char *buf_b, size_t len_b,
bool have_tsc); bool have_tsc, bool *consecutive);
int intel_pt__strerror(int code, char *buf, size_t buflen); int intel_pt__strerror(int code, char *buf, size_t buflen);
......
...@@ -188,14 +188,17 @@ static void intel_pt_dump_event(struct intel_pt *pt, unsigned char *buf, ...@@ -188,14 +188,17 @@ static void intel_pt_dump_event(struct intel_pt *pt, unsigned char *buf,
static int intel_pt_do_fix_overlap(struct intel_pt *pt, struct auxtrace_buffer *a, static int intel_pt_do_fix_overlap(struct intel_pt *pt, struct auxtrace_buffer *a,
struct auxtrace_buffer *b) struct auxtrace_buffer *b)
{ {
bool consecutive = false;
void *start; void *start;
start = intel_pt_find_overlap(a->data, a->size, b->data, b->size, start = intel_pt_find_overlap(a->data, a->size, b->data, b->size,
pt->have_tsc); pt->have_tsc, &consecutive);
if (!start) if (!start)
return -EINVAL; return -EINVAL;
b->use_size = b->data + b->size - start; b->use_size = b->data + b->size - start;
b->use_data = start; b->use_data = start;
if (b->use_size && consecutive)
b->consecutive = true;
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment