mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-30 22:26:55 +00:00
perf thread-stack: Add thread_stack__br_sample_late()
Add a thread stack function to create a branch stack for hardware events where the sample records get created some time after the event occurred. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Jiri Olsa <jolsa@redhat.com> Link: http://lore.kernel.org/lkml/20200429150751.12570-7-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
6cd2cbfc68
commit
3749e0bbde
2 changed files with 107 additions and 0 deletions
|
@ -645,6 +645,110 @@ void thread_stack__br_sample(struct thread *thread, int cpu,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Start of user space branch entries */
|
||||||
|
static bool us_start(struct branch_entry *be, u64 kernel_start, bool *start)
|
||||||
|
{
|
||||||
|
if (!*start)
|
||||||
|
*start = be->to && be->to < kernel_start;
|
||||||
|
|
||||||
|
return *start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start of branch entries after the ip fell in between 2 branches, or user
|
||||||
|
* space branch entries.
|
||||||
|
*/
|
||||||
|
static bool ks_start(struct branch_entry *be, u64 sample_ip, u64 kernel_start,
|
||||||
|
bool *start, struct branch_entry *nb)
|
||||||
|
{
|
||||||
|
if (!*start) {
|
||||||
|
*start = (nb && sample_ip >= be->to && sample_ip <= nb->from) ||
|
||||||
|
be->from < kernel_start ||
|
||||||
|
(be->to && be->to < kernel_start);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hardware sample records, created some time after the event occurred, need to
|
||||||
|
* have subsequent addresses removed from the branch stack.
|
||||||
|
*/
|
||||||
|
void thread_stack__br_sample_late(struct thread *thread, int cpu,
|
||||||
|
struct branch_stack *dst, unsigned int sz,
|
||||||
|
u64 ip, u64 kernel_start)
|
||||||
|
{
|
||||||
|
struct thread_stack *ts = thread__stack(thread, cpu);
|
||||||
|
struct branch_entry *d, *s, *spos, *ssz;
|
||||||
|
struct branch_stack *src;
|
||||||
|
unsigned int nr = 0;
|
||||||
|
bool start = false;
|
||||||
|
|
||||||
|
dst->nr = 0;
|
||||||
|
|
||||||
|
if (!ts)
|
||||||
|
return;
|
||||||
|
|
||||||
|
src = ts->br_stack_rb;
|
||||||
|
if (!src->nr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
spos = &src->entries[ts->br_stack_pos];
|
||||||
|
ssz = &src->entries[ts->br_stack_sz];
|
||||||
|
|
||||||
|
d = &dst->entries[0];
|
||||||
|
s = spos;
|
||||||
|
|
||||||
|
if (ip < kernel_start) {
|
||||||
|
/*
|
||||||
|
* User space sample: start copying branch entries when the
|
||||||
|
* branch is in user space.
|
||||||
|
*/
|
||||||
|
for (s = spos; s < ssz && nr < sz; s++) {
|
||||||
|
if (us_start(s, kernel_start, &start)) {
|
||||||
|
*d++ = *s;
|
||||||
|
nr += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src->nr >= ts->br_stack_sz) {
|
||||||
|
for (s = &src->entries[0]; s < spos && nr < sz; s++) {
|
||||||
|
if (us_start(s, kernel_start, &start)) {
|
||||||
|
*d++ = *s;
|
||||||
|
nr += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
struct branch_entry *nb = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Kernel space sample: start copying branch entries when the ip
|
||||||
|
* falls in between 2 branches (or the branch is in user space
|
||||||
|
* because then the start must have been missed).
|
||||||
|
*/
|
||||||
|
for (s = spos; s < ssz && nr < sz; s++) {
|
||||||
|
if (ks_start(s, ip, kernel_start, &start, nb)) {
|
||||||
|
*d++ = *s;
|
||||||
|
nr += 1;
|
||||||
|
}
|
||||||
|
nb = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src->nr >= ts->br_stack_sz) {
|
||||||
|
for (s = &src->entries[0]; s < spos && nr < sz; s++) {
|
||||||
|
if (ks_start(s, ip, kernel_start, &start, nb)) {
|
||||||
|
*d++ = *s;
|
||||||
|
nr += 1;
|
||||||
|
}
|
||||||
|
nb = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dst->nr = nr;
|
||||||
|
}
|
||||||
|
|
||||||
struct call_return_processor *
|
struct call_return_processor *
|
||||||
call_return_processor__new(int (*process)(struct call_return *cr, u64 *parent_db_id, void *data),
|
call_return_processor__new(int (*process)(struct call_return *cr, u64 *parent_db_id, void *data),
|
||||||
void *data)
|
void *data)
|
||||||
|
|
|
@ -91,6 +91,9 @@ void thread_stack__sample_late(struct thread *thread, int cpu,
|
||||||
u64 kernel_start);
|
u64 kernel_start);
|
||||||
void thread_stack__br_sample(struct thread *thread, int cpu,
|
void thread_stack__br_sample(struct thread *thread, int cpu,
|
||||||
struct branch_stack *dst, unsigned int sz);
|
struct branch_stack *dst, unsigned int sz);
|
||||||
|
void thread_stack__br_sample_late(struct thread *thread, int cpu,
|
||||||
|
struct branch_stack *dst, unsigned int sz,
|
||||||
|
u64 sample_ip, u64 kernel_start);
|
||||||
int thread_stack__flush(struct thread *thread);
|
int thread_stack__flush(struct thread *thread);
|
||||||
void thread_stack__free(struct thread *thread);
|
void thread_stack__free(struct thread *thread);
|
||||||
size_t thread_stack__depth(struct thread *thread, int cpu);
|
size_t thread_stack__depth(struct thread *thread, int cpu);
|
||||||
|
|
Loading…
Reference in a new issue