2012-12-08 03:39:39 +07:00
|
|
|
#include "callchain.h"
|
2012-10-07 02:26:02 +07:00
|
|
|
#include "debug.h"
|
|
|
|
#include "event.h"
|
2012-12-08 03:39:39 +07:00
|
|
|
#include "evsel.h"
|
|
|
|
#include "hist.h"
|
2012-10-07 01:43:20 +07:00
|
|
|
#include "machine.h"
|
|
|
|
#include "map.h"
|
2012-12-08 03:39:39 +07:00
|
|
|
#include "sort.h"
|
2012-11-09 21:32:52 +07:00
|
|
|
#include "strlist.h"
|
2012-10-07 01:43:20 +07:00
|
|
|
#include "thread.h"
|
2014-07-23 18:23:00 +07:00
|
|
|
#include "vdso.h"
|
2012-10-07 01:43:20 +07:00
|
|
|
#include <stdbool.h>
|
2013-12-11 19:15:00 +07:00
|
|
|
#include <symbol/kallsyms.h>
|
2012-12-08 03:39:39 +07:00
|
|
|
#include "unwind.h"
|
perf callchain: Support handling complete branch stacks as histograms
Currently branch stacks can be only shown as edge histograms for
individual branches. I never found this display particularly useful.
This implements an alternative mode that creates histograms over
complete branch traces, instead of individual branches, similar to how
normal callgraphs are handled. This is done by putting it in front of
the normal callgraph and then using the normal callgraph histogram
infrastructure to unify them.
This way in complex functions we can understand the control flow that
lead to a particular sample, and may even see some control flow in the
caller for short functions.
Example (simplified, of course for such simple code this is usually not
needed), please run this after the whole patchkit is in, as at this
point in the patch order there is no --branch-history, that will be
added in a patch after this one:
tcall.c:
volatile a = 10000, b = 100000, c;
__attribute__((noinline)) f2()
{
c = a / b;
}
__attribute__((noinline)) f1()
{
f2();
f2();
}
main()
{
int i;
for (i = 0; i < 1000000; i++)
f1();
}
% perf record -b -g ./tsrc/tcall
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.044 MB perf.data (~1923 samples) ]
% perf report --no-children --branch-history
...
54.91% tcall.c:6 [.] f2 tcall
|
|--65.53%-- f2 tcall.c:5
| |
| |--70.83%-- f1 tcall.c:11
| | f1 tcall.c:10
| | main tcall.c:18
| | main tcall.c:18
| | main tcall.c:17
| | main tcall.c:17
| | f1 tcall.c:13
| | f1 tcall.c:13
| | f2 tcall.c:7
| | f2 tcall.c:5
| | f1 tcall.c:12
| | f1 tcall.c:12
| | f2 tcall.c:7
| | f2 tcall.c:5
| | f1 tcall.c:11
| |
| --29.17%-- f1 tcall.c:12
| f1 tcall.c:12
| f2 tcall.c:7
| f2 tcall.c:5
| f1 tcall.c:11
| f1 tcall.c:10
| main tcall.c:18
| main tcall.c:18
| main tcall.c:17
| main tcall.c:17
| f1 tcall.c:13
| f1 tcall.c:13
| f2 tcall.c:7
| f2 tcall.c:5
| f1 tcall.c:12
The default output is unchanged.
This is only implemented in perf report, no change to record or anywhere
else.
This adds the basic code to report:
- add a new "branch" option to the -g option parser to enable this mode
- when the flag is set include the LBR into the callstack in machine.c.
The rest of the history code is unchanged and doesn't know the
difference between LBR entry and normal call entry.
- detect overlaps with the callchain
- remove small loop duplicates in the LBR
Current limitations:
- The LBR flags (mispredict etc.) are not shown in the history
and LBR entries have no special marker.
- It would be nice if annotate marked the LBR entries somehow
(e.g. with arrows)
v2: Various fixes.
v3: Merge further patches into this one. Fix white space.
v4: Improve manpage. Address review feedback.
v5: Rename functions. Better error message without -g. Fix crash without
-b.
v6: Rebase
v7: Rebase. Use NO_ENTRY in memset.
v8: Port to latest tip. Move add_callchain_ip to separate
patch. Skip initial entries in callchain. Minor cleanups.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: http://lkml.kernel.org/r/1415844328-4884-3-git-send-email-andi@firstfloor.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2014-11-13 09:05:20 +07:00
|
|
|
#include "linux/hash.h"
|
2012-10-07 01:43:20 +07:00
|
|
|
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
static void __machine__remove_thread(struct machine *machine, struct thread *th, bool lock);
|
|
|
|
|
perf machine: Add missing dsos->root rbtree root initialization
A segfault happens on 'perf test hists_link' because we end up using a
struct machines on the stack, and then machines__init() was not
initializing the newly introduced rb_root, just the existing list_head.
When we introduced struct dsos, to group the two ways to store dsos,
i.e. the linked list and the rbtree, we didn't turned the initialization
done in:
machines__init(machines->host) ->
machine__init() ->
INIT_LIST_HEAD
into a dsos__init() to keep on initializing the list_head but _as well_
initializing the rb_root, oops.
All worked because outside perf-test we probably zalloc the whole thing
which ends up initializing it in to NULL.
So the problem looks contained to 'perf test' that uses it on stack,
etc.
Reported-by: Jiri Olsa <jolsa@redhat.com>
Acked-by: Waiman Long <Waiman.Long@hp.com>,
Cc: Adrian Hunter <adrian.hunter@intel.com>,
Cc: Don Zickus <dzickus@redhat.com>
Cc: Douglas Hatch <doug.hatch@hp.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Scott J Norton <scott.norton@hp.com>
Cc: Waiman Long <Waiman.Long@hp.com>,
Link: http://lkml.kernel.org/r/20141014180353.GF3198@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2014-10-15 01:07:48 +07:00
|
|
|
static void dsos__init(struct dsos *dsos)
|
|
|
|
{
|
|
|
|
INIT_LIST_HEAD(&dsos->head);
|
|
|
|
dsos->root = RB_ROOT;
|
2015-06-02 01:40:01 +07:00
|
|
|
pthread_rwlock_init(&dsos->lock, NULL);
|
perf machine: Add missing dsos->root rbtree root initialization
A segfault happens on 'perf test hists_link' because we end up using a
struct machines on the stack, and then machines__init() was not
initializing the newly introduced rb_root, just the existing list_head.
When we introduced struct dsos, to group the two ways to store dsos,
i.e. the linked list and the rbtree, we didn't turned the initialization
done in:
machines__init(machines->host) ->
machine__init() ->
INIT_LIST_HEAD
into a dsos__init() to keep on initializing the list_head but _as well_
initializing the rb_root, oops.
All worked because outside perf-test we probably zalloc the whole thing
which ends up initializing it in to NULL.
So the problem looks contained to 'perf test' that uses it on stack,
etc.
Reported-by: Jiri Olsa <jolsa@redhat.com>
Acked-by: Waiman Long <Waiman.Long@hp.com>,
Cc: Adrian Hunter <adrian.hunter@intel.com>,
Cc: Don Zickus <dzickus@redhat.com>
Cc: Douglas Hatch <doug.hatch@hp.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Scott J Norton <scott.norton@hp.com>
Cc: Waiman Long <Waiman.Long@hp.com>,
Link: http://lkml.kernel.org/r/20141014180353.GF3198@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2014-10-15 01:07:48 +07:00
|
|
|
}
|
|
|
|
|
2012-11-09 21:32:52 +07:00
|
|
|
int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
|
|
|
|
{
|
2015-12-08 09:25:44 +07:00
|
|
|
memset(machine, 0, sizeof(*machine));
|
2014-10-22 03:29:02 +07:00
|
|
|
map_groups__init(&machine->kmaps, machine);
|
2012-11-09 21:32:52 +07:00
|
|
|
RB_CLEAR_NODE(&machine->rb_node);
|
2015-05-28 23:06:42 +07:00
|
|
|
dsos__init(&machine->dsos);
|
2012-11-09 21:32:52 +07:00
|
|
|
|
|
|
|
machine->threads = RB_ROOT;
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
pthread_rwlock_init(&machine->threads_lock, NULL);
|
2012-11-09 21:32:52 +07:00
|
|
|
INIT_LIST_HEAD(&machine->dead_threads);
|
|
|
|
machine->last_match = NULL;
|
|
|
|
|
2014-07-23 18:23:00 +07:00
|
|
|
machine->vdso_info = NULL;
|
2015-09-09 22:25:00 +07:00
|
|
|
machine->env = NULL;
|
2014-07-23 18:23:00 +07:00
|
|
|
|
2012-11-09 21:32:52 +07:00
|
|
|
machine->pid = pid;
|
|
|
|
|
2013-08-08 18:32:20 +07:00
|
|
|
machine->symbol_filter = NULL;
|
2014-01-07 19:47:19 +07:00
|
|
|
machine->id_hdr_size = 0;
|
2014-07-31 13:00:45 +07:00
|
|
|
machine->comm_exec = false;
|
2014-08-16 02:08:39 +07:00
|
|
|
machine->kernel_start = 0;
|
2013-08-08 18:32:20 +07:00
|
|
|
|
2015-12-09 09:11:33 +07:00
|
|
|
memset(machine->vmlinux_maps, 0, sizeof(machine->vmlinux_maps));
|
|
|
|
|
2012-11-09 21:32:52 +07:00
|
|
|
machine->root_dir = strdup(root_dir);
|
|
|
|
if (machine->root_dir == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
if (pid != HOST_KERNEL_ID) {
|
2014-07-14 17:02:25 +07:00
|
|
|
struct thread *thread = machine__findnew_thread(machine, -1,
|
2013-08-27 15:23:03 +07:00
|
|
|
pid);
|
2012-11-09 21:32:52 +07:00
|
|
|
char comm[64];
|
|
|
|
|
|
|
|
if (thread == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
snprintf(comm, sizeof(comm), "[guest/%d]", pid);
|
2013-09-11 21:18:24 +07:00
|
|
|
thread__set_comm(thread, comm, 0);
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
thread__put(thread);
|
2012-11-09 21:32:52 +07:00
|
|
|
}
|
|
|
|
|
2014-07-22 20:17:25 +07:00
|
|
|
machine->current_tid = NULL;
|
|
|
|
|
2012-11-09 21:32:52 +07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-29 02:13:00 +07:00
|
|
|
struct machine *machine__new_host(void)
|
|
|
|
{
|
|
|
|
struct machine *machine = malloc(sizeof(*machine));
|
|
|
|
|
|
|
|
if (machine != NULL) {
|
|
|
|
machine__init(machine, "", HOST_KERNEL_ID);
|
|
|
|
|
|
|
|
if (machine__create_kernel_maps(machine) < 0)
|
|
|
|
goto out_delete;
|
|
|
|
}
|
|
|
|
|
|
|
|
return machine;
|
|
|
|
out_delete:
|
|
|
|
free(machine);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-06-02 21:53:26 +07:00
|
|
|
static void dsos__purge(struct dsos *dsos)
|
2012-11-09 21:32:52 +07:00
|
|
|
{
|
|
|
|
struct dso *pos, *n;
|
|
|
|
|
2015-06-02 01:40:01 +07:00
|
|
|
pthread_rwlock_wrlock(&dsos->lock);
|
|
|
|
|
2014-09-30 03:07:28 +07:00
|
|
|
list_for_each_entry_safe(pos, n, &dsos->head, node) {
|
2014-10-01 00:36:15 +07:00
|
|
|
RB_CLEAR_NODE(&pos->rb_node);
|
2015-11-13 16:48:30 +07:00
|
|
|
pos->root = NULL;
|
2015-06-02 21:53:26 +07:00
|
|
|
list_del_init(&pos->node);
|
|
|
|
dso__put(pos);
|
2012-11-09 21:32:52 +07:00
|
|
|
}
|
2015-06-02 01:40:01 +07:00
|
|
|
|
|
|
|
pthread_rwlock_unlock(&dsos->lock);
|
2015-06-02 21:53:26 +07:00
|
|
|
}
|
2015-06-02 01:40:01 +07:00
|
|
|
|
2015-06-02 21:53:26 +07:00
|
|
|
static void dsos__exit(struct dsos *dsos)
|
|
|
|
{
|
|
|
|
dsos__purge(dsos);
|
2015-06-02 01:40:01 +07:00
|
|
|
pthread_rwlock_destroy(&dsos->lock);
|
2012-11-09 21:32:52 +07:00
|
|
|
}
|
|
|
|
|
2012-12-08 03:39:39 +07:00
|
|
|
void machine__delete_threads(struct machine *machine)
|
|
|
|
{
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
struct rb_node *nd;
|
2012-12-08 03:39:39 +07:00
|
|
|
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
pthread_rwlock_wrlock(&machine->threads_lock);
|
|
|
|
nd = rb_first(&machine->threads);
|
2012-12-08 03:39:39 +07:00
|
|
|
while (nd) {
|
|
|
|
struct thread *t = rb_entry(nd, struct thread, rb_node);
|
|
|
|
|
|
|
|
nd = rb_next(nd);
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
__machine__remove_thread(machine, t, false);
|
2012-12-08 03:39:39 +07:00
|
|
|
}
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
pthread_rwlock_unlock(&machine->threads_lock);
|
2012-12-08 03:39:39 +07:00
|
|
|
}
|
|
|
|
|
2012-11-09 21:32:52 +07:00
|
|
|
void machine__exit(struct machine *machine)
|
|
|
|
{
|
2015-11-18 13:40:24 +07:00
|
|
|
machine__destroy_kernel_maps(machine);
|
2012-11-09 21:32:52 +07:00
|
|
|
map_groups__exit(&machine->kmaps);
|
2015-06-02 01:40:01 +07:00
|
|
|
dsos__exit(&machine->dsos);
|
perf machine: Fix up vdso methods names
To make it consistent with the other dso lifetime routines.
For instance:
struct dso *vdso__new(struct machine *machine, const char *short_name,
const char *long_name)
Becomes:
struct dso *machine__addnew_vdso(struct machine *machine, const
char *short_name, const char *long_name)
Because:
1) There is no 'struct vdso' for us to have vdso__ prefixed routines.
2) Because it will not really just create a new instance of 'struct
dso', it'll call dso__new() but it will also insert it into the
DSO's list/rbtree, and we have a method name for that: 'addnew',
just like we have dsos__addnew().
3) So it is really a 'struct machine' operation, it is the first
argument, etc.
This way the place where this is used gets consistent:
if (vdso) {
pgoff = 0;
- dso = vdso__dso_findnew(machine, thread);
+ dso = machine__findnew_vdso(machine, thread);
} else
dso = machine__findnew_dso(machine, filename);
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: http://lkml.kernel.org/n/tip-r3w3tvh8exm9xfz3p4tz9qbz@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-05-29 21:54:08 +07:00
|
|
|
machine__exit_vdso(machine);
|
2013-12-27 03:41:15 +07:00
|
|
|
zfree(&machine->root_dir);
|
2014-07-22 20:17:25 +07:00
|
|
|
zfree(&machine->current_tid);
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
pthread_rwlock_destroy(&machine->threads_lock);
|
2012-11-09 21:32:52 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
void machine__delete(struct machine *machine)
|
|
|
|
{
|
|
|
|
machine__exit(machine);
|
|
|
|
free(machine);
|
|
|
|
}
|
|
|
|
|
2012-12-19 05:15:48 +07:00
|
|
|
void machines__init(struct machines *machines)
|
|
|
|
{
|
|
|
|
machine__init(&machines->host, "", HOST_KERNEL_ID);
|
|
|
|
machines->guests = RB_ROOT;
|
2013-08-08 18:32:20 +07:00
|
|
|
machines->symbol_filter = NULL;
|
2012-12-19 05:15:48 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
void machines__exit(struct machines *machines)
|
|
|
|
{
|
|
|
|
machine__exit(&machines->host);
|
|
|
|
/* XXX exit guest */
|
|
|
|
}
|
|
|
|
|
|
|
|
struct machine *machines__add(struct machines *machines, pid_t pid,
|
2012-11-09 21:32:52 +07:00
|
|
|
const char *root_dir)
|
|
|
|
{
|
2012-12-19 05:15:48 +07:00
|
|
|
struct rb_node **p = &machines->guests.rb_node;
|
2012-11-09 21:32:52 +07:00
|
|
|
struct rb_node *parent = NULL;
|
|
|
|
struct machine *pos, *machine = malloc(sizeof(*machine));
|
|
|
|
|
|
|
|
if (machine == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (machine__init(machine, root_dir, pid) != 0) {
|
|
|
|
free(machine);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-08-08 18:32:20 +07:00
|
|
|
machine->symbol_filter = machines->symbol_filter;
|
|
|
|
|
2012-11-09 21:32:52 +07:00
|
|
|
while (*p != NULL) {
|
|
|
|
parent = *p;
|
|
|
|
pos = rb_entry(parent, struct machine, rb_node);
|
|
|
|
if (pid < pos->pid)
|
|
|
|
p = &(*p)->rb_left;
|
|
|
|
else
|
|
|
|
p = &(*p)->rb_right;
|
|
|
|
}
|
|
|
|
|
|
|
|
rb_link_node(&machine->rb_node, parent, p);
|
2012-12-19 05:15:48 +07:00
|
|
|
rb_insert_color(&machine->rb_node, &machines->guests);
|
2012-11-09 21:32:52 +07:00
|
|
|
|
|
|
|
return machine;
|
|
|
|
}
|
|
|
|
|
2013-08-08 18:32:20 +07:00
|
|
|
void machines__set_symbol_filter(struct machines *machines,
|
|
|
|
symbol_filter_t symbol_filter)
|
|
|
|
{
|
|
|
|
struct rb_node *nd;
|
|
|
|
|
|
|
|
machines->symbol_filter = symbol_filter;
|
|
|
|
machines->host.symbol_filter = symbol_filter;
|
|
|
|
|
|
|
|
for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
|
|
|
|
struct machine *machine = rb_entry(nd, struct machine, rb_node);
|
|
|
|
|
|
|
|
machine->symbol_filter = symbol_filter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-31 13:00:45 +07:00
|
|
|
void machines__set_comm_exec(struct machines *machines, bool comm_exec)
|
|
|
|
{
|
|
|
|
struct rb_node *nd;
|
|
|
|
|
|
|
|
machines->host.comm_exec = comm_exec;
|
|
|
|
|
|
|
|
for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
|
|
|
|
struct machine *machine = rb_entry(nd, struct machine, rb_node);
|
|
|
|
|
|
|
|
machine->comm_exec = comm_exec;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-19 05:15:48 +07:00
|
|
|
struct machine *machines__find(struct machines *machines, pid_t pid)
|
2012-11-09 21:32:52 +07:00
|
|
|
{
|
2012-12-19 05:15:48 +07:00
|
|
|
struct rb_node **p = &machines->guests.rb_node;
|
2012-11-09 21:32:52 +07:00
|
|
|
struct rb_node *parent = NULL;
|
|
|
|
struct machine *machine;
|
|
|
|
struct machine *default_machine = NULL;
|
|
|
|
|
2012-12-19 05:15:48 +07:00
|
|
|
if (pid == HOST_KERNEL_ID)
|
|
|
|
return &machines->host;
|
|
|
|
|
2012-11-09 21:32:52 +07:00
|
|
|
while (*p != NULL) {
|
|
|
|
parent = *p;
|
|
|
|
machine = rb_entry(parent, struct machine, rb_node);
|
|
|
|
if (pid < machine->pid)
|
|
|
|
p = &(*p)->rb_left;
|
|
|
|
else if (pid > machine->pid)
|
|
|
|
p = &(*p)->rb_right;
|
|
|
|
else
|
|
|
|
return machine;
|
|
|
|
if (!machine->pid)
|
|
|
|
default_machine = machine;
|
|
|
|
}
|
|
|
|
|
|
|
|
return default_machine;
|
|
|
|
}
|
|
|
|
|
2012-12-19 05:15:48 +07:00
|
|
|
struct machine *machines__findnew(struct machines *machines, pid_t pid)
|
2012-11-09 21:32:52 +07:00
|
|
|
{
|
|
|
|
char path[PATH_MAX];
|
|
|
|
const char *root_dir = "";
|
|
|
|
struct machine *machine = machines__find(machines, pid);
|
|
|
|
|
|
|
|
if (machine && (machine->pid == pid))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if ((pid != HOST_KERNEL_ID) &&
|
|
|
|
(pid != DEFAULT_GUEST_KERNEL_ID) &&
|
|
|
|
(symbol_conf.guestmount)) {
|
|
|
|
sprintf(path, "%s/%d", symbol_conf.guestmount, pid);
|
|
|
|
if (access(path, R_OK)) {
|
|
|
|
static struct strlist *seen;
|
|
|
|
|
|
|
|
if (!seen)
|
2015-07-20 22:13:34 +07:00
|
|
|
seen = strlist__new(NULL, NULL);
|
2012-11-09 21:32:52 +07:00
|
|
|
|
|
|
|
if (!strlist__has_entry(seen, path)) {
|
|
|
|
pr_err("Can't access file %s\n", path);
|
|
|
|
strlist__add(seen, path);
|
|
|
|
}
|
|
|
|
machine = NULL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
root_dir = path;
|
|
|
|
}
|
|
|
|
|
|
|
|
machine = machines__add(machines, pid, root_dir);
|
|
|
|
out:
|
|
|
|
return machine;
|
|
|
|
}
|
|
|
|
|
2012-12-19 05:15:48 +07:00
|
|
|
void machines__process_guests(struct machines *machines,
|
|
|
|
machine__process_t process, void *data)
|
2012-11-09 21:32:52 +07:00
|
|
|
{
|
|
|
|
struct rb_node *nd;
|
|
|
|
|
2012-12-19 05:15:48 +07:00
|
|
|
for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
|
2012-11-09 21:32:52 +07:00
|
|
|
struct machine *pos = rb_entry(nd, struct machine, rb_node);
|
|
|
|
process(pos, data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
char *machine__mmap_name(struct machine *machine, char *bf, size_t size)
|
|
|
|
{
|
|
|
|
if (machine__is_host(machine))
|
|
|
|
snprintf(bf, size, "[%s]", "kernel.kallsyms");
|
|
|
|
else if (machine__is_default_guest(machine))
|
|
|
|
snprintf(bf, size, "[%s]", "guest.kernel.kallsyms");
|
|
|
|
else {
|
|
|
|
snprintf(bf, size, "[%s.%d]", "guest.kernel.kallsyms",
|
|
|
|
machine->pid);
|
|
|
|
}
|
|
|
|
|
|
|
|
return bf;
|
|
|
|
}
|
|
|
|
|
2012-12-19 05:15:48 +07:00
|
|
|
void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)
|
2012-11-09 21:32:52 +07:00
|
|
|
{
|
|
|
|
struct rb_node *node;
|
|
|
|
struct machine *machine;
|
|
|
|
|
2012-12-19 05:15:48 +07:00
|
|
|
machines->host.id_hdr_size = id_hdr_size;
|
|
|
|
|
|
|
|
for (node = rb_first(&machines->guests); node; node = rb_next(node)) {
|
2012-11-09 21:32:52 +07:00
|
|
|
machine = rb_entry(node, struct machine, rb_node);
|
|
|
|
machine->id_hdr_size = id_hdr_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-16 15:07:13 +07:00
|
|
|
static void machine__update_thread_pid(struct machine *machine,
|
|
|
|
struct thread *th, pid_t pid)
|
|
|
|
{
|
|
|
|
struct thread *leader;
|
|
|
|
|
|
|
|
if (pid == th->pid_ || pid == -1 || th->pid_ != -1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
th->pid_ = pid;
|
|
|
|
|
|
|
|
if (th->pid_ == th->tid)
|
|
|
|
return;
|
|
|
|
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
leader = __machine__findnew_thread(machine, th->pid_, th->pid_);
|
2014-07-16 15:07:13 +07:00
|
|
|
if (!leader)
|
|
|
|
goto out_err;
|
|
|
|
|
|
|
|
if (!leader->mg)
|
2014-10-22 03:29:02 +07:00
|
|
|
leader->mg = map_groups__new(machine);
|
2014-07-16 15:07:13 +07:00
|
|
|
|
|
|
|
if (!leader->mg)
|
|
|
|
goto out_err;
|
|
|
|
|
|
|
|
if (th->mg == leader->mg)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (th->mg) {
|
|
|
|
/*
|
|
|
|
* Maps are created from MMAP events which provide the pid and
|
|
|
|
* tid. Consequently there never should be any maps on a thread
|
|
|
|
* with an unknown pid. Just print an error if there are.
|
|
|
|
*/
|
|
|
|
if (!map_groups__empty(th->mg))
|
|
|
|
pr_err("Discarding thread maps for %d:%d\n",
|
|
|
|
th->pid_, th->tid);
|
2015-05-20 06:07:14 +07:00
|
|
|
map_groups__put(th->mg);
|
2014-07-16 15:07:13 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
th->mg = map_groups__get(leader->mg);
|
2015-12-12 05:11:23 +07:00
|
|
|
out_put:
|
|
|
|
thread__put(leader);
|
2014-07-16 15:07:13 +07:00
|
|
|
return;
|
|
|
|
out_err:
|
|
|
|
pr_err("Failed to join map groups for %d:%d\n", th->pid_, th->tid);
|
2015-12-12 05:11:23 +07:00
|
|
|
goto out_put;
|
2014-07-16 15:07:13 +07:00
|
|
|
}
|
|
|
|
|
2015-12-12 05:11:23 +07:00
|
|
|
/*
|
|
|
|
* Caller must eventually drop thread->refcnt returned with a successfull
|
|
|
|
* lookup/new thread inserted.
|
|
|
|
*/
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
static struct thread *____machine__findnew_thread(struct machine *machine,
|
|
|
|
pid_t pid, pid_t tid,
|
|
|
|
bool create)
|
2012-10-07 01:43:20 +07:00
|
|
|
{
|
|
|
|
struct rb_node **p = &machine->threads.rb_node;
|
|
|
|
struct rb_node *parent = NULL;
|
|
|
|
struct thread *th;
|
|
|
|
|
|
|
|
/*
|
2013-07-04 20:20:31 +07:00
|
|
|
* Front-end cache - TID lookups come in blocks,
|
2012-10-07 01:43:20 +07:00
|
|
|
* so most of the time we dont have to look up
|
|
|
|
* the full rbtree:
|
|
|
|
*/
|
2014-07-16 15:07:13 +07:00
|
|
|
th = machine->last_match;
|
2015-03-03 08:21:35 +07:00
|
|
|
if (th != NULL) {
|
|
|
|
if (th->tid == tid) {
|
|
|
|
machine__update_thread_pid(machine, th, pid);
|
2015-12-12 05:11:23 +07:00
|
|
|
return thread__get(th);
|
2015-03-03 08:21:35 +07:00
|
|
|
}
|
|
|
|
|
2015-05-12 04:08:12 +07:00
|
|
|
machine->last_match = NULL;
|
2013-08-26 20:00:19 +07:00
|
|
|
}
|
2012-10-07 01:43:20 +07:00
|
|
|
|
|
|
|
while (*p != NULL) {
|
|
|
|
parent = *p;
|
|
|
|
th = rb_entry(parent, struct thread, rb_node);
|
|
|
|
|
2013-07-04 20:20:31 +07:00
|
|
|
if (th->tid == tid) {
|
2015-05-12 04:08:12 +07:00
|
|
|
machine->last_match = th;
|
2014-07-16 15:07:13 +07:00
|
|
|
machine__update_thread_pid(machine, th, pid);
|
2015-12-12 05:11:23 +07:00
|
|
|
return thread__get(th);
|
2012-10-07 01:43:20 +07:00
|
|
|
}
|
|
|
|
|
2013-07-04 20:20:31 +07:00
|
|
|
if (tid < th->tid)
|
2012-10-07 01:43:20 +07:00
|
|
|
p = &(*p)->rb_left;
|
|
|
|
else
|
|
|
|
p = &(*p)->rb_right;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!create)
|
|
|
|
return NULL;
|
|
|
|
|
2013-08-26 20:00:19 +07:00
|
|
|
th = thread__new(pid, tid);
|
2012-10-07 01:43:20 +07:00
|
|
|
if (th != NULL) {
|
|
|
|
rb_link_node(&th->rb_node, parent, p);
|
|
|
|
rb_insert_color(&th->rb_node, &machine->threads);
|
2014-04-10 01:54:29 +07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We have to initialize map_groups separately
|
|
|
|
* after rb tree is updated.
|
|
|
|
*
|
|
|
|
* The reason is that we call machine__findnew_thread
|
|
|
|
* within thread__init_map_groups to find the thread
|
|
|
|
* leader and that would screwed the rb tree.
|
|
|
|
*/
|
2014-07-16 14:19:44 +07:00
|
|
|
if (thread__init_map_groups(th, machine)) {
|
2015-05-26 01:23:05 +07:00
|
|
|
rb_erase_init(&th->rb_node, &machine->threads);
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
RB_CLEAR_NODE(&th->rb_node);
|
2015-12-12 05:11:23 +07:00
|
|
|
thread__put(th);
|
2014-04-10 01:54:29 +07:00
|
|
|
return NULL;
|
2014-07-16 14:19:44 +07:00
|
|
|
}
|
2015-03-03 08:21:35 +07:00
|
|
|
/*
|
|
|
|
* It is now in the rbtree, get a ref
|
|
|
|
*/
|
|
|
|
thread__get(th);
|
2015-05-12 04:08:12 +07:00
|
|
|
machine->last_match = th;
|
2012-10-07 01:43:20 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
return th;
|
|
|
|
}
|
|
|
|
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid, pid_t tid)
|
|
|
|
{
|
|
|
|
return ____machine__findnew_thread(machine, pid, tid, true);
|
|
|
|
}
|
|
|
|
|
2013-08-27 15:23:03 +07:00
|
|
|
struct thread *machine__findnew_thread(struct machine *machine, pid_t pid,
|
|
|
|
pid_t tid)
|
2012-10-07 01:43:20 +07:00
|
|
|
{
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
struct thread *th;
|
|
|
|
|
|
|
|
pthread_rwlock_wrlock(&machine->threads_lock);
|
2015-12-12 05:11:23 +07:00
|
|
|
th = __machine__findnew_thread(machine, pid, tid);
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
pthread_rwlock_unlock(&machine->threads_lock);
|
|
|
|
return th;
|
2012-10-07 01:43:20 +07:00
|
|
|
}
|
|
|
|
|
2014-03-14 21:00:03 +07:00
|
|
|
struct thread *machine__find_thread(struct machine *machine, pid_t pid,
|
|
|
|
pid_t tid)
|
2012-10-07 01:43:20 +07:00
|
|
|
{
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
struct thread *th;
|
|
|
|
pthread_rwlock_rdlock(&machine->threads_lock);
|
2015-12-12 05:11:23 +07:00
|
|
|
th = ____machine__findnew_thread(machine, pid, tid, false);
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
pthread_rwlock_unlock(&machine->threads_lock);
|
|
|
|
return th;
|
2012-10-07 01:43:20 +07:00
|
|
|
}
|
2012-10-07 02:26:02 +07:00
|
|
|
|
2014-07-31 13:00:45 +07:00
|
|
|
struct comm *machine__thread_exec_comm(struct machine *machine,
|
|
|
|
struct thread *thread)
|
|
|
|
{
|
|
|
|
if (machine->comm_exec)
|
|
|
|
return thread__exec_comm(thread);
|
|
|
|
else
|
|
|
|
return thread__comm(thread);
|
|
|
|
}
|
|
|
|
|
2013-09-11 21:18:24 +07:00
|
|
|
int machine__process_comm_event(struct machine *machine, union perf_event *event,
|
|
|
|
struct perf_sample *sample)
|
2012-10-07 02:26:02 +07:00
|
|
|
{
|
2013-08-27 15:23:03 +07:00
|
|
|
struct thread *thread = machine__findnew_thread(machine,
|
|
|
|
event->comm.pid,
|
|
|
|
event->comm.tid);
|
2014-07-31 13:00:44 +07:00
|
|
|
bool exec = event->header.misc & PERF_RECORD_MISC_COMM_EXEC;
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
int err = 0;
|
2012-10-07 02:26:02 +07:00
|
|
|
|
2014-07-31 13:00:45 +07:00
|
|
|
if (exec)
|
|
|
|
machine->comm_exec = true;
|
|
|
|
|
2012-10-07 02:26:02 +07:00
|
|
|
if (dump_trace)
|
|
|
|
perf_event__fprintf_comm(event, stdout);
|
|
|
|
|
2014-07-31 13:00:44 +07:00
|
|
|
if (thread == NULL ||
|
|
|
|
__thread__set_comm(thread, event->comm.comm, sample->time, exec)) {
|
2012-10-07 02:26:02 +07:00
|
|
|
dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
err = -1;
|
2012-10-07 02:26:02 +07:00
|
|
|
}
|
|
|
|
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
thread__put(thread);
|
|
|
|
|
|
|
|
return err;
|
2012-10-07 02:26:02 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
int machine__process_lost_event(struct machine *machine __maybe_unused,
|
2013-09-11 21:18:24 +07:00
|
|
|
union perf_event *event, struct perf_sample *sample __maybe_unused)
|
2012-10-07 02:26:02 +07:00
|
|
|
{
|
|
|
|
dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
|
|
|
|
event->lost.id, event->lost.lost);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-05-11 02:13:15 +07:00
|
|
|
int machine__process_lost_samples_event(struct machine *machine __maybe_unused,
|
|
|
|
union perf_event *event, struct perf_sample *sample)
|
|
|
|
{
|
|
|
|
dump_printf(": id:%" PRIu64 ": lost samples :%" PRIu64 "\n",
|
|
|
|
sample->id, event->lost_samples.lost);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
perf machine: Fix up some more method names
Calling the function 'machine__new_module' implies a new 'module' will
be allocated, when in fact what is returned is a 'struct map' instance,
that not necessarily will be instantiated, as if one already exists with
the given module name, it will be returned instead.
So be consistent with other "find and if not there, create" like
functions, like machine__findnew_thread, machine__findnew_dso, etc, and
rename it to machine__findnew_module_map(), that in turn will call
machine__findnew_module_dso().
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: http://lkml.kernel.org/n/tip-acv830vd3hwww2ih5vjtbmu3@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-06-01 22:01:02 +07:00
|
|
|
static struct dso *machine__findnew_module_dso(struct machine *machine,
|
|
|
|
struct kmod_path *m,
|
|
|
|
const char *filename)
|
2015-02-13 04:10:52 +07:00
|
|
|
{
|
|
|
|
struct dso *dso;
|
|
|
|
|
2015-06-02 01:40:01 +07:00
|
|
|
pthread_rwlock_wrlock(&machine->dsos.lock);
|
|
|
|
|
|
|
|
dso = __dsos__find(&machine->dsos, m->name, true);
|
2015-02-13 04:10:52 +07:00
|
|
|
if (!dso) {
|
2015-06-02 01:40:01 +07:00
|
|
|
dso = __dsos__addnew(&machine->dsos, m->name);
|
2015-02-13 04:10:52 +07:00
|
|
|
if (dso == NULL)
|
2015-06-02 01:40:01 +07:00
|
|
|
goto out_unlock;
|
2015-02-13 04:10:52 +07:00
|
|
|
|
|
|
|
if (machine__is_host(machine))
|
|
|
|
dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
|
|
|
|
else
|
|
|
|
dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
|
|
|
|
|
|
|
|
/* _KMODULE_COMP should be next to _KMODULE */
|
2015-02-17 23:29:57 +07:00
|
|
|
if (m->kmod && m->comp)
|
2015-02-13 04:10:52 +07:00
|
|
|
dso->symtab_type++;
|
2015-02-17 23:29:57 +07:00
|
|
|
|
|
|
|
dso__set_short_name(dso, strdup(m->name), true);
|
|
|
|
dso__set_long_name(dso, strdup(filename), true);
|
2015-02-13 04:10:52 +07:00
|
|
|
}
|
|
|
|
|
2015-06-02 21:53:26 +07:00
|
|
|
dso__get(dso);
|
2015-06-02 01:40:01 +07:00
|
|
|
out_unlock:
|
|
|
|
pthread_rwlock_unlock(&machine->dsos.lock);
|
2015-02-13 04:10:52 +07:00
|
|
|
return dso;
|
|
|
|
}
|
|
|
|
|
2015-04-30 21:37:29 +07:00
|
|
|
int machine__process_aux_event(struct machine *machine __maybe_unused,
|
|
|
|
union perf_event *event)
|
|
|
|
{
|
|
|
|
if (dump_trace)
|
|
|
|
perf_event__fprintf_aux(event, stdout);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-04-30 21:37:30 +07:00
|
|
|
int machine__process_itrace_start_event(struct machine *machine __maybe_unused,
|
|
|
|
union perf_event *event)
|
|
|
|
{
|
|
|
|
if (dump_trace)
|
|
|
|
perf_event__fprintf_itrace_start(event, stdout);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-07-21 16:44:03 +07:00
|
|
|
int machine__process_switch_event(struct machine *machine __maybe_unused,
|
|
|
|
union perf_event *event)
|
|
|
|
{
|
|
|
|
if (dump_trace)
|
|
|
|
perf_event__fprintf_switch(event, stdout);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
perf machine: Adjust dso->long_name for offline module
Something unexpected may happen if copy statically linked perf to a
production environment:
# ./perf probe -m ./mymodule.ko my_func
[mymodule] with build id 326ab42550ef3d24944f53c817533728367effeb not found, continuing without symbols
Failed to find symbol my_func in /home/wangnan/kmodule/mymodule.ko
Error: Failed to add events.
# ./perf buildid-cache -a ./mymodule.ko
# ./perf probe -m ./mymodule.ko my_func
Added new event:
probe:my_func (on my_func in /home/wangnan/kmodule/mymodule.ko)
You can now use it in all perf tools, such as:
perf record -e probe:my_func -aR sleep 1
Where:
# ldd ./perf
not a dynamic executable
# strace -e open ./perf probe -m ./mymodule.ko my_func
...
open("/home/wangnan/kmodule/mymodule.ko", O_RDONLY) = 3
open("/home/wangnan/kmodule/../lib64/elfutils/libebl_x86_64.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
...
open("/lib64/tls/libebl_x86_64.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/lib64/libebl_x86_64.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib64/tls/libebl_x86_64.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib64/libebl_x86_64.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("[mymodule]", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/home/wangnan/.debug/.build-id/32/6ab42550ef3d24944f53c817533728367effeb", O_RDONLY) = -1 ENOENT (No such file or directory)
open("[mymodule]", O_RDONLY) = -1 ENOENT (No such file or directory)
In the above example, probe fails before we put the module into
buildid-cache. However, user would expect it success in both case
because perf is able to find probe points actually.
The reason is because perf won't utilize module's full path if it failed
to open debuginfo. In:
convert_to_probe_trace_events ->
find_probe_trace_events_from_map ->
get_target_map ->
kernel_get_module_map ->
machine__findnew_module_map ->
map_groups__find_by_name
map_groups__find_by_name() is able to find the map of that module, but
this information is found from /proc/module before it knows the real
path of the offline module. Therefore, the map->dso->long_name is set to
something like '[mymodule]', which prevent dso__load() find the real
path of the module file.
In another aspect, if dso__load() can get the offline module through
buildid cache, it can read symble table from that ko. Even if debuginfo
is not available, 'perf probe' can success if the '.symtab' can be
found.
This patch improves machine__findnew_module_map(): when dso->long_name
is leading with '[' (doesn't find path of module when parsing
/proc/modules), fixes it by dso__set_long_name(), so following
dso__load() is possible to find the symbol table.
This patch won't interfere with buildid matching. Here is the test
result:
# ./perf probe -m ./mymodule.ko my_func
Added new event:
probe:my_func (on my_func in /home/wangnan/kmodule/mymodule.ko)
You can now use it in all perf tools, such as:
perf record -e probe:my_func -aR sleep 1
# ./perf probe -d '*'
Removed event: probe:my_func
# mv ./mymodule.{ko,.bak}
# mv ./moduleb.ko mymodule.ko
# ./perf probe -m ./mymodule.ko my_func
/home/wangnan/kmodule/mymodule.ko with build id 326ab42550ef3d24944f53c817533728367effeb not found, continuing without symbols
Failed to find symbol my_func in /home/wangnan/kmodule/mymodule.ko
Error: Failed to add events.
# ./perf probe -v -m ./mymodule.ko my_func
probe-definition(0): my_func
symbol:my_func file:(null) line:0 offset:0 return:0 lazy:(null)
0 arguments
Could not open debuginfo. Try to use symbols.
symsrc__init: build id mismatch for /home/wangnan/kmodule/mymodule.ko.
/home/wangnan/kmodule/mymodule.ko with build id 326ab42550ef3d24944f53c817533728367effeb not found, continuing without symbols
Failed to find symbol my_func in /home/wangnan/kmodule/mymodule.ko
Error: Failed to add events. Reason: No such file or directory (Code: -2)
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1448510397-187965-1-git-send-email-wangnan0@huawei.com
[ Renamed adjust_dso_long_name() do dso__adjust_kmod_long_name() ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-11-26 10:59:57 +07:00
|
|
|
static void dso__adjust_kmod_long_name(struct dso *dso, const char *filename)
|
|
|
|
{
|
|
|
|
const char *dup_filename;
|
|
|
|
|
|
|
|
if (!filename || !dso || !dso->long_name)
|
|
|
|
return;
|
|
|
|
if (dso->long_name[0] != '[')
|
|
|
|
return;
|
|
|
|
if (!strchr(filename, '/'))
|
|
|
|
return;
|
|
|
|
|
|
|
|
dup_filename = strdup(filename);
|
|
|
|
if (!dup_filename)
|
|
|
|
return;
|
|
|
|
|
2015-12-07 09:36:25 +07:00
|
|
|
dso__set_long_name(dso, dup_filename, true);
|
perf machine: Adjust dso->long_name for offline module
Something unexpected may happen if copy statically linked perf to a
production environment:
# ./perf probe -m ./mymodule.ko my_func
[mymodule] with build id 326ab42550ef3d24944f53c817533728367effeb not found, continuing without symbols
Failed to find symbol my_func in /home/wangnan/kmodule/mymodule.ko
Error: Failed to add events.
# ./perf buildid-cache -a ./mymodule.ko
# ./perf probe -m ./mymodule.ko my_func
Added new event:
probe:my_func (on my_func in /home/wangnan/kmodule/mymodule.ko)
You can now use it in all perf tools, such as:
perf record -e probe:my_func -aR sleep 1
Where:
# ldd ./perf
not a dynamic executable
# strace -e open ./perf probe -m ./mymodule.ko my_func
...
open("/home/wangnan/kmodule/mymodule.ko", O_RDONLY) = 3
open("/home/wangnan/kmodule/../lib64/elfutils/libebl_x86_64.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
...
open("/lib64/tls/libebl_x86_64.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/lib64/libebl_x86_64.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib64/tls/libebl_x86_64.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib64/libebl_x86_64.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("[mymodule]", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/home/wangnan/.debug/.build-id/32/6ab42550ef3d24944f53c817533728367effeb", O_RDONLY) = -1 ENOENT (No such file or directory)
open("[mymodule]", O_RDONLY) = -1 ENOENT (No such file or directory)
In the above example, probe fails before we put the module into
buildid-cache. However, user would expect it success in both case
because perf is able to find probe points actually.
The reason is because perf won't utilize module's full path if it failed
to open debuginfo. In:
convert_to_probe_trace_events ->
find_probe_trace_events_from_map ->
get_target_map ->
kernel_get_module_map ->
machine__findnew_module_map ->
map_groups__find_by_name
map_groups__find_by_name() is able to find the map of that module, but
this information is found from /proc/module before it knows the real
path of the offline module. Therefore, the map->dso->long_name is set to
something like '[mymodule]', which prevent dso__load() find the real
path of the module file.
In another aspect, if dso__load() can get the offline module through
buildid cache, it can read symble table from that ko. Even if debuginfo
is not available, 'perf probe' can success if the '.symtab' can be
found.
This patch improves machine__findnew_module_map(): when dso->long_name
is leading with '[' (doesn't find path of module when parsing
/proc/modules), fixes it by dso__set_long_name(), so following
dso__load() is possible to find the symbol table.
This patch won't interfere with buildid matching. Here is the test
result:
# ./perf probe -m ./mymodule.ko my_func
Added new event:
probe:my_func (on my_func in /home/wangnan/kmodule/mymodule.ko)
You can now use it in all perf tools, such as:
perf record -e probe:my_func -aR sleep 1
# ./perf probe -d '*'
Removed event: probe:my_func
# mv ./mymodule.{ko,.bak}
# mv ./moduleb.ko mymodule.ko
# ./perf probe -m ./mymodule.ko my_func
/home/wangnan/kmodule/mymodule.ko with build id 326ab42550ef3d24944f53c817533728367effeb not found, continuing without symbols
Failed to find symbol my_func in /home/wangnan/kmodule/mymodule.ko
Error: Failed to add events.
# ./perf probe -v -m ./mymodule.ko my_func
probe-definition(0): my_func
symbol:my_func file:(null) line:0 offset:0 return:0 lazy:(null)
0 arguments
Could not open debuginfo. Try to use symbols.
symsrc__init: build id mismatch for /home/wangnan/kmodule/mymodule.ko.
/home/wangnan/kmodule/mymodule.ko with build id 326ab42550ef3d24944f53c817533728367effeb not found, continuing without symbols
Failed to find symbol my_func in /home/wangnan/kmodule/mymodule.ko
Error: Failed to add events. Reason: No such file or directory (Code: -2)
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1448510397-187965-1-git-send-email-wangnan0@huawei.com
[ Renamed adjust_dso_long_name() do dso__adjust_kmod_long_name() ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-11-26 10:59:57 +07:00
|
|
|
}
|
|
|
|
|
perf machine: Fix up some more method names
Calling the function 'machine__new_module' implies a new 'module' will
be allocated, when in fact what is returned is a 'struct map' instance,
that not necessarily will be instantiated, as if one already exists with
the given module name, it will be returned instead.
So be consistent with other "find and if not there, create" like
functions, like machine__findnew_thread, machine__findnew_dso, etc, and
rename it to machine__findnew_module_map(), that in turn will call
machine__findnew_module_dso().
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: http://lkml.kernel.org/n/tip-acv830vd3hwww2ih5vjtbmu3@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-06-01 22:01:02 +07:00
|
|
|
struct map *machine__findnew_module_map(struct machine *machine, u64 start,
|
|
|
|
const char *filename)
|
2012-12-08 03:39:39 +07:00
|
|
|
{
|
2015-02-17 23:29:57 +07:00
|
|
|
struct map *map = NULL;
|
2015-11-18 13:40:35 +07:00
|
|
|
struct dso *dso = NULL;
|
2015-02-17 23:29:57 +07:00
|
|
|
struct kmod_path m;
|
2012-12-08 03:39:39 +07:00
|
|
|
|
2015-02-17 23:29:57 +07:00
|
|
|
if (kmod_path__parse_name(&m, filename))
|
2012-12-08 03:39:39 +07:00
|
|
|
return NULL;
|
|
|
|
|
2015-02-17 23:31:18 +07:00
|
|
|
map = map_groups__find_by_name(&machine->kmaps, MAP__FUNCTION,
|
|
|
|
m.name);
|
perf machine: Adjust dso->long_name for offline module
Something unexpected may happen if copy statically linked perf to a
production environment:
# ./perf probe -m ./mymodule.ko my_func
[mymodule] with build id 326ab42550ef3d24944f53c817533728367effeb not found, continuing without symbols
Failed to find symbol my_func in /home/wangnan/kmodule/mymodule.ko
Error: Failed to add events.
# ./perf buildid-cache -a ./mymodule.ko
# ./perf probe -m ./mymodule.ko my_func
Added new event:
probe:my_func (on my_func in /home/wangnan/kmodule/mymodule.ko)
You can now use it in all perf tools, such as:
perf record -e probe:my_func -aR sleep 1
Where:
# ldd ./perf
not a dynamic executable
# strace -e open ./perf probe -m ./mymodule.ko my_func
...
open("/home/wangnan/kmodule/mymodule.ko", O_RDONLY) = 3
open("/home/wangnan/kmodule/../lib64/elfutils/libebl_x86_64.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
...
open("/lib64/tls/libebl_x86_64.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/lib64/libebl_x86_64.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib64/tls/libebl_x86_64.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib64/libebl_x86_64.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("[mymodule]", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/home/wangnan/.debug/.build-id/32/6ab42550ef3d24944f53c817533728367effeb", O_RDONLY) = -1 ENOENT (No such file or directory)
open("[mymodule]", O_RDONLY) = -1 ENOENT (No such file or directory)
In the above example, probe fails before we put the module into
buildid-cache. However, user would expect it success in both case
because perf is able to find probe points actually.
The reason is because perf won't utilize module's full path if it failed
to open debuginfo. In:
convert_to_probe_trace_events ->
find_probe_trace_events_from_map ->
get_target_map ->
kernel_get_module_map ->
machine__findnew_module_map ->
map_groups__find_by_name
map_groups__find_by_name() is able to find the map of that module, but
this information is found from /proc/module before it knows the real
path of the offline module. Therefore, the map->dso->long_name is set to
something like '[mymodule]', which prevent dso__load() find the real
path of the module file.
In another aspect, if dso__load() can get the offline module through
buildid cache, it can read symble table from that ko. Even if debuginfo
is not available, 'perf probe' can success if the '.symtab' can be
found.
This patch improves machine__findnew_module_map(): when dso->long_name
is leading with '[' (doesn't find path of module when parsing
/proc/modules), fixes it by dso__set_long_name(), so following
dso__load() is possible to find the symbol table.
This patch won't interfere with buildid matching. Here is the test
result:
# ./perf probe -m ./mymodule.ko my_func
Added new event:
probe:my_func (on my_func in /home/wangnan/kmodule/mymodule.ko)
You can now use it in all perf tools, such as:
perf record -e probe:my_func -aR sleep 1
# ./perf probe -d '*'
Removed event: probe:my_func
# mv ./mymodule.{ko,.bak}
# mv ./moduleb.ko mymodule.ko
# ./perf probe -m ./mymodule.ko my_func
/home/wangnan/kmodule/mymodule.ko with build id 326ab42550ef3d24944f53c817533728367effeb not found, continuing without symbols
Failed to find symbol my_func in /home/wangnan/kmodule/mymodule.ko
Error: Failed to add events.
# ./perf probe -v -m ./mymodule.ko my_func
probe-definition(0): my_func
symbol:my_func file:(null) line:0 offset:0 return:0 lazy:(null)
0 arguments
Could not open debuginfo. Try to use symbols.
symsrc__init: build id mismatch for /home/wangnan/kmodule/mymodule.ko.
/home/wangnan/kmodule/mymodule.ko with build id 326ab42550ef3d24944f53c817533728367effeb not found, continuing without symbols
Failed to find symbol my_func in /home/wangnan/kmodule/mymodule.ko
Error: Failed to add events. Reason: No such file or directory (Code: -2)
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1448510397-187965-1-git-send-email-wangnan0@huawei.com
[ Renamed adjust_dso_long_name() do dso__adjust_kmod_long_name() ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-11-26 10:59:57 +07:00
|
|
|
if (map) {
|
|
|
|
/*
|
|
|
|
* If the map's dso is an offline module, give dso__load()
|
|
|
|
* a chance to find the file path of that module by fixing
|
|
|
|
* long_name.
|
|
|
|
*/
|
|
|
|
dso__adjust_kmod_long_name(map->dso, filename);
|
2015-02-17 23:31:18 +07:00
|
|
|
goto out;
|
perf machine: Adjust dso->long_name for offline module
Something unexpected may happen if copy statically linked perf to a
production environment:
# ./perf probe -m ./mymodule.ko my_func
[mymodule] with build id 326ab42550ef3d24944f53c817533728367effeb not found, continuing without symbols
Failed to find symbol my_func in /home/wangnan/kmodule/mymodule.ko
Error: Failed to add events.
# ./perf buildid-cache -a ./mymodule.ko
# ./perf probe -m ./mymodule.ko my_func
Added new event:
probe:my_func (on my_func in /home/wangnan/kmodule/mymodule.ko)
You can now use it in all perf tools, such as:
perf record -e probe:my_func -aR sleep 1
Where:
# ldd ./perf
not a dynamic executable
# strace -e open ./perf probe -m ./mymodule.ko my_func
...
open("/home/wangnan/kmodule/mymodule.ko", O_RDONLY) = 3
open("/home/wangnan/kmodule/../lib64/elfutils/libebl_x86_64.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
...
open("/lib64/tls/libebl_x86_64.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/lib64/libebl_x86_64.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib64/tls/libebl_x86_64.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib64/libebl_x86_64.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("[mymodule]", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/home/wangnan/.debug/.build-id/32/6ab42550ef3d24944f53c817533728367effeb", O_RDONLY) = -1 ENOENT (No such file or directory)
open("[mymodule]", O_RDONLY) = -1 ENOENT (No such file or directory)
In the above example, probe fails before we put the module into
buildid-cache. However, user would expect it success in both case
because perf is able to find probe points actually.
The reason is because perf won't utilize module's full path if it failed
to open debuginfo. In:
convert_to_probe_trace_events ->
find_probe_trace_events_from_map ->
get_target_map ->
kernel_get_module_map ->
machine__findnew_module_map ->
map_groups__find_by_name
map_groups__find_by_name() is able to find the map of that module, but
this information is found from /proc/module before it knows the real
path of the offline module. Therefore, the map->dso->long_name is set to
something like '[mymodule]', which prevent dso__load() find the real
path of the module file.
In another aspect, if dso__load() can get the offline module through
buildid cache, it can read symble table from that ko. Even if debuginfo
is not available, 'perf probe' can success if the '.symtab' can be
found.
This patch improves machine__findnew_module_map(): when dso->long_name
is leading with '[' (doesn't find path of module when parsing
/proc/modules), fixes it by dso__set_long_name(), so following
dso__load() is possible to find the symbol table.
This patch won't interfere with buildid matching. Here is the test
result:
# ./perf probe -m ./mymodule.ko my_func
Added new event:
probe:my_func (on my_func in /home/wangnan/kmodule/mymodule.ko)
You can now use it in all perf tools, such as:
perf record -e probe:my_func -aR sleep 1
# ./perf probe -d '*'
Removed event: probe:my_func
# mv ./mymodule.{ko,.bak}
# mv ./moduleb.ko mymodule.ko
# ./perf probe -m ./mymodule.ko my_func
/home/wangnan/kmodule/mymodule.ko with build id 326ab42550ef3d24944f53c817533728367effeb not found, continuing without symbols
Failed to find symbol my_func in /home/wangnan/kmodule/mymodule.ko
Error: Failed to add events.
# ./perf probe -v -m ./mymodule.ko my_func
probe-definition(0): my_func
symbol:my_func file:(null) line:0 offset:0 return:0 lazy:(null)
0 arguments
Could not open debuginfo. Try to use symbols.
symsrc__init: build id mismatch for /home/wangnan/kmodule/mymodule.ko.
/home/wangnan/kmodule/mymodule.ko with build id 326ab42550ef3d24944f53c817533728367effeb not found, continuing without symbols
Failed to find symbol my_func in /home/wangnan/kmodule/mymodule.ko
Error: Failed to add events. Reason: No such file or directory (Code: -2)
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1448510397-187965-1-git-send-email-wangnan0@huawei.com
[ Renamed adjust_dso_long_name() do dso__adjust_kmod_long_name() ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-11-26 10:59:57 +07:00
|
|
|
}
|
2015-02-17 23:31:18 +07:00
|
|
|
|
perf machine: Fix up some more method names
Calling the function 'machine__new_module' implies a new 'module' will
be allocated, when in fact what is returned is a 'struct map' instance,
that not necessarily will be instantiated, as if one already exists with
the given module name, it will be returned instead.
So be consistent with other "find and if not there, create" like
functions, like machine__findnew_thread, machine__findnew_dso, etc, and
rename it to machine__findnew_module_map(), that in turn will call
machine__findnew_module_dso().
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: http://lkml.kernel.org/n/tip-acv830vd3hwww2ih5vjtbmu3@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-06-01 22:01:02 +07:00
|
|
|
dso = machine__findnew_module_dso(machine, &m, filename);
|
2015-02-17 23:29:57 +07:00
|
|
|
if (dso == NULL)
|
|
|
|
goto out;
|
|
|
|
|
2012-12-08 03:39:39 +07:00
|
|
|
map = map__new2(start, dso, MAP__FUNCTION);
|
|
|
|
if (map == NULL)
|
2015-02-17 23:29:57 +07:00
|
|
|
goto out;
|
2012-12-08 03:39:39 +07:00
|
|
|
|
|
|
|
map_groups__insert(&machine->kmaps, map);
|
2015-02-17 23:29:57 +07:00
|
|
|
|
2015-11-18 13:40:20 +07:00
|
|
|
/* Put the map here because map_groups__insert alread got it */
|
|
|
|
map__put(map);
|
2015-02-17 23:29:57 +07:00
|
|
|
out:
|
2015-11-18 13:40:35 +07:00
|
|
|
/* put the dso here, corresponding to machine__findnew_module_dso */
|
|
|
|
dso__put(dso);
|
2015-02-17 23:29:57 +07:00
|
|
|
free(m.name);
|
2012-12-08 03:39:39 +07:00
|
|
|
return map;
|
|
|
|
}
|
|
|
|
|
2012-12-19 05:15:48 +07:00
|
|
|
size_t machines__fprintf_dsos(struct machines *machines, FILE *fp)
|
2012-12-08 03:39:39 +07:00
|
|
|
{
|
|
|
|
struct rb_node *nd;
|
2015-05-28 23:06:42 +07:00
|
|
|
size_t ret = __dsos__fprintf(&machines->host.dsos.head, fp);
|
2012-12-08 03:39:39 +07:00
|
|
|
|
2012-12-19 05:15:48 +07:00
|
|
|
for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
|
2012-12-08 03:39:39 +07:00
|
|
|
struct machine *pos = rb_entry(nd, struct machine, rb_node);
|
2015-05-28 23:06:42 +07:00
|
|
|
ret += __dsos__fprintf(&pos->dsos.head, fp);
|
2012-12-08 03:39:39 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-09-30 03:07:28 +07:00
|
|
|
size_t machine__fprintf_dsos_buildid(struct machine *m, FILE *fp,
|
2012-12-08 03:39:39 +07:00
|
|
|
bool (skip)(struct dso *dso, int parm), int parm)
|
|
|
|
{
|
2015-05-28 23:06:42 +07:00
|
|
|
return __dsos__fprintf_buildid(&m->dsos.head, fp, skip, parm);
|
2012-12-08 03:39:39 +07:00
|
|
|
}
|
|
|
|
|
2012-12-19 05:15:48 +07:00
|
|
|
size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp,
|
2012-12-08 03:39:39 +07:00
|
|
|
bool (skip)(struct dso *dso, int parm), int parm)
|
|
|
|
{
|
|
|
|
struct rb_node *nd;
|
2012-12-19 05:15:48 +07:00
|
|
|
size_t ret = machine__fprintf_dsos_buildid(&machines->host, fp, skip, parm);
|
2012-12-08 03:39:39 +07:00
|
|
|
|
2012-12-19 05:15:48 +07:00
|
|
|
for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
|
2012-12-08 03:39:39 +07:00
|
|
|
struct machine *pos = rb_entry(nd, struct machine, rb_node);
|
|
|
|
ret += machine__fprintf_dsos_buildid(pos, fp, skip, parm);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
size_t printed = 0;
|
2015-09-30 21:54:04 +07:00
|
|
|
struct dso *kdso = machine__kernel_map(machine)->dso;
|
2012-12-08 03:39:39 +07:00
|
|
|
|
|
|
|
if (kdso->has_build_id) {
|
|
|
|
char filename[PATH_MAX];
|
|
|
|
if (dso__build_id_filename(kdso, filename, sizeof(filename)))
|
|
|
|
printed += fprintf(fp, "[0] %s\n", filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < vmlinux_path__nr_entries; ++i)
|
|
|
|
printed += fprintf(fp, "[%d] %s\n",
|
|
|
|
i + kdso->has_build_id, vmlinux_path[i]);
|
|
|
|
|
|
|
|
return printed;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t machine__fprintf(struct machine *machine, FILE *fp)
|
|
|
|
{
|
|
|
|
size_t ret = 0;
|
|
|
|
struct rb_node *nd;
|
|
|
|
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
pthread_rwlock_rdlock(&machine->threads_lock);
|
|
|
|
|
2012-12-08 03:39:39 +07:00
|
|
|
for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) {
|
|
|
|
struct thread *pos = rb_entry(nd, struct thread, rb_node);
|
|
|
|
|
|
|
|
ret += thread__fprintf(pos, fp);
|
|
|
|
}
|
|
|
|
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
pthread_rwlock_unlock(&machine->threads_lock);
|
|
|
|
|
2012-12-08 03:39:39 +07:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct dso *machine__get_kernel(struct machine *machine)
|
|
|
|
{
|
|
|
|
const char *vmlinux_name = NULL;
|
|
|
|
struct dso *kernel;
|
|
|
|
|
|
|
|
if (machine__is_host(machine)) {
|
|
|
|
vmlinux_name = symbol_conf.vmlinux_name;
|
|
|
|
if (!vmlinux_name)
|
|
|
|
vmlinux_name = "[kernel.kallsyms]";
|
|
|
|
|
2015-05-28 22:40:55 +07:00
|
|
|
kernel = machine__findnew_kernel(machine, vmlinux_name,
|
|
|
|
"[kernel]", DSO_TYPE_KERNEL);
|
2012-12-08 03:39:39 +07:00
|
|
|
} else {
|
|
|
|
char bf[PATH_MAX];
|
|
|
|
|
|
|
|
if (machine__is_default_guest(machine))
|
|
|
|
vmlinux_name = symbol_conf.default_guest_vmlinux_name;
|
|
|
|
if (!vmlinux_name)
|
|
|
|
vmlinux_name = machine__mmap_name(machine, bf,
|
|
|
|
sizeof(bf));
|
|
|
|
|
2015-05-28 22:40:55 +07:00
|
|
|
kernel = machine__findnew_kernel(machine, vmlinux_name,
|
|
|
|
"[guest.kernel]",
|
|
|
|
DSO_TYPE_GUEST_KERNEL);
|
2012-12-08 03:39:39 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (kernel != NULL && (!kernel->has_build_id))
|
|
|
|
dso__read_running_kernel_build_id(kernel, machine);
|
|
|
|
|
|
|
|
return kernel;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct process_args {
|
|
|
|
u64 start;
|
|
|
|
};
|
|
|
|
|
2014-01-29 21:14:38 +07:00
|
|
|
static void machine__get_kallsyms_filename(struct machine *machine, char *buf,
|
|
|
|
size_t bufsz)
|
|
|
|
{
|
|
|
|
if (machine__is_default_guest(machine))
|
|
|
|
scnprintf(buf, bufsz, "%s", symbol_conf.default_guest_kallsyms);
|
|
|
|
else
|
|
|
|
scnprintf(buf, bufsz, "%s/proc/kallsyms", machine->root_dir);
|
|
|
|
}
|
|
|
|
|
2014-06-17 01:32:09 +07:00
|
|
|
const char *ref_reloc_sym_names[] = {"_text", "_stext", NULL};
|
|
|
|
|
|
|
|
/* Figure out the start address of kernel map from /proc/kallsyms.
|
|
|
|
* Returns the name of the start symbol in *symbol_name. Pass in NULL as
|
|
|
|
* symbol_name if it's not that important.
|
|
|
|
*/
|
2014-08-16 02:08:38 +07:00
|
|
|
static u64 machine__get_running_kernel_start(struct machine *machine,
|
|
|
|
const char **symbol_name)
|
2012-12-08 03:39:39 +07:00
|
|
|
{
|
2014-01-29 21:14:38 +07:00
|
|
|
char filename[PATH_MAX];
|
2014-06-17 01:32:09 +07:00
|
|
|
int i;
|
|
|
|
const char *name;
|
|
|
|
u64 addr = 0;
|
2012-12-08 03:39:39 +07:00
|
|
|
|
2014-01-29 21:14:38 +07:00
|
|
|
machine__get_kallsyms_filename(machine, filename, PATH_MAX);
|
2012-12-08 03:39:39 +07:00
|
|
|
|
|
|
|
if (symbol__restricted_filename(filename, "/proc/kallsyms"))
|
|
|
|
return 0;
|
|
|
|
|
2014-06-17 01:32:09 +07:00
|
|
|
for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) {
|
|
|
|
addr = kallsyms__get_function_start(filename, name);
|
|
|
|
if (addr)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (symbol_name)
|
|
|
|
*symbol_name = name;
|
2012-12-08 03:39:39 +07:00
|
|
|
|
2014-06-17 01:32:09 +07:00
|
|
|
return addr;
|
2012-12-08 03:39:39 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
|
|
|
|
{
|
|
|
|
enum map_type type;
|
2014-08-16 02:08:38 +07:00
|
|
|
u64 start = machine__get_running_kernel_start(machine, NULL);
|
2012-12-08 03:39:39 +07:00
|
|
|
|
2015-12-09 09:11:33 +07:00
|
|
|
/* In case of renewal the kernel map, destroy previous one */
|
|
|
|
machine__destroy_kernel_maps(machine);
|
|
|
|
|
2012-12-08 03:39:39 +07:00
|
|
|
for (type = 0; type < MAP__NR_TYPES; ++type) {
|
|
|
|
struct kmap *kmap;
|
2015-09-30 21:08:58 +07:00
|
|
|
struct map *map;
|
2012-12-08 03:39:39 +07:00
|
|
|
|
|
|
|
machine->vmlinux_maps[type] = map__new2(start, kernel, type);
|
|
|
|
if (machine->vmlinux_maps[type] == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
machine->vmlinux_maps[type]->map_ip =
|
|
|
|
machine->vmlinux_maps[type]->unmap_ip =
|
|
|
|
identity__map_ip;
|
2015-09-30 21:54:04 +07:00
|
|
|
map = __machine__kernel_map(machine, type);
|
2015-09-30 21:08:58 +07:00
|
|
|
kmap = map__kmap(map);
|
2015-04-07 15:22:45 +07:00
|
|
|
if (!kmap)
|
|
|
|
return -1;
|
|
|
|
|
2012-12-08 03:39:39 +07:00
|
|
|
kmap->kmaps = &machine->kmaps;
|
2015-09-30 21:08:58 +07:00
|
|
|
map_groups__insert(&machine->kmaps, map);
|
2012-12-08 03:39:39 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void machine__destroy_kernel_maps(struct machine *machine)
|
|
|
|
{
|
|
|
|
enum map_type type;
|
|
|
|
|
|
|
|
for (type = 0; type < MAP__NR_TYPES; ++type) {
|
|
|
|
struct kmap *kmap;
|
2015-09-30 21:54:04 +07:00
|
|
|
struct map *map = __machine__kernel_map(machine, type);
|
2012-12-08 03:39:39 +07:00
|
|
|
|
2015-09-30 21:08:58 +07:00
|
|
|
if (map == NULL)
|
2012-12-08 03:39:39 +07:00
|
|
|
continue;
|
|
|
|
|
2015-09-30 21:08:58 +07:00
|
|
|
kmap = map__kmap(map);
|
|
|
|
map_groups__remove(&machine->kmaps, map);
|
2015-04-07 15:22:45 +07:00
|
|
|
if (kmap && kmap->ref_reloc_sym) {
|
2012-12-08 03:39:39 +07:00
|
|
|
/*
|
|
|
|
* ref_reloc_sym is shared among all maps, so free just
|
|
|
|
* on one of them.
|
|
|
|
*/
|
|
|
|
if (type == MAP__FUNCTION) {
|
2013-12-27 03:41:15 +07:00
|
|
|
zfree((char **)&kmap->ref_reloc_sym->name);
|
|
|
|
zfree(&kmap->ref_reloc_sym);
|
|
|
|
} else
|
|
|
|
kmap->ref_reloc_sym = NULL;
|
2012-12-08 03:39:39 +07:00
|
|
|
}
|
|
|
|
|
2015-11-18 13:40:22 +07:00
|
|
|
map__put(machine->vmlinux_maps[type]);
|
2012-12-08 03:39:39 +07:00
|
|
|
machine->vmlinux_maps[type] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-19 05:15:48 +07:00
|
|
|
int machines__create_guest_kernel_maps(struct machines *machines)
|
2012-12-08 03:39:39 +07:00
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
struct dirent **namelist = NULL;
|
|
|
|
int i, items = 0;
|
|
|
|
char path[PATH_MAX];
|
|
|
|
pid_t pid;
|
|
|
|
char *endp;
|
|
|
|
|
|
|
|
if (symbol_conf.default_guest_vmlinux_name ||
|
|
|
|
symbol_conf.default_guest_modules ||
|
|
|
|
symbol_conf.default_guest_kallsyms) {
|
|
|
|
machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (symbol_conf.guestmount) {
|
|
|
|
items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
|
|
|
|
if (items <= 0)
|
|
|
|
return -ENOENT;
|
|
|
|
for (i = 0; i < items; i++) {
|
|
|
|
if (!isdigit(namelist[i]->d_name[0])) {
|
|
|
|
/* Filter out . and .. */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10);
|
|
|
|
if ((*endp != '\0') ||
|
|
|
|
(endp == namelist[i]->d_name) ||
|
|
|
|
(errno == ERANGE)) {
|
|
|
|
pr_debug("invalid directory (%s). Skipping.\n",
|
|
|
|
namelist[i]->d_name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
sprintf(path, "%s/%s/proc/kallsyms",
|
|
|
|
symbol_conf.guestmount,
|
|
|
|
namelist[i]->d_name);
|
|
|
|
ret = access(path, R_OK);
|
|
|
|
if (ret) {
|
|
|
|
pr_debug("Can't access file %s\n", path);
|
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
machines__create_kernel_maps(machines, pid);
|
|
|
|
}
|
|
|
|
failure:
|
|
|
|
free(namelist);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-12-19 05:15:48 +07:00
|
|
|
void machines__destroy_kernel_maps(struct machines *machines)
|
2012-12-08 03:39:39 +07:00
|
|
|
{
|
2012-12-19 05:15:48 +07:00
|
|
|
struct rb_node *next = rb_first(&machines->guests);
|
|
|
|
|
|
|
|
machine__destroy_kernel_maps(&machines->host);
|
2012-12-08 03:39:39 +07:00
|
|
|
|
|
|
|
while (next) {
|
|
|
|
struct machine *pos = rb_entry(next, struct machine, rb_node);
|
|
|
|
|
|
|
|
next = rb_next(&pos->rb_node);
|
2012-12-19 05:15:48 +07:00
|
|
|
rb_erase(&pos->rb_node, &machines->guests);
|
2012-12-08 03:39:39 +07:00
|
|
|
machine__delete(pos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-19 05:15:48 +07:00
|
|
|
int machines__create_kernel_maps(struct machines *machines, pid_t pid)
|
2012-12-08 03:39:39 +07:00
|
|
|
{
|
|
|
|
struct machine *machine = machines__findnew(machines, pid);
|
|
|
|
|
|
|
|
if (machine == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return machine__create_kernel_maps(machine);
|
|
|
|
}
|
|
|
|
|
|
|
|
int machine__load_kallsyms(struct machine *machine, const char *filename,
|
|
|
|
enum map_type type, symbol_filter_t filter)
|
|
|
|
{
|
2015-09-30 21:54:04 +07:00
|
|
|
struct map *map = machine__kernel_map(machine);
|
2012-12-08 03:39:39 +07:00
|
|
|
int ret = dso__load_kallsyms(map->dso, filename, map, filter);
|
|
|
|
|
|
|
|
if (ret > 0) {
|
|
|
|
dso__set_loaded(map->dso, type);
|
|
|
|
/*
|
|
|
|
* Since /proc/kallsyms will have multiple sessions for the
|
|
|
|
* kernel, with modules between them, fixup the end of all
|
|
|
|
* sections.
|
|
|
|
*/
|
|
|
|
__map_groups__fixup_end(&machine->kmaps, type);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
|
|
|
|
symbol_filter_t filter)
|
|
|
|
{
|
2015-09-30 21:54:04 +07:00
|
|
|
struct map *map = machine__kernel_map(machine);
|
2012-12-08 03:39:39 +07:00
|
|
|
int ret = dso__load_vmlinux_path(map->dso, map, filter);
|
|
|
|
|
2013-08-07 18:38:47 +07:00
|
|
|
if (ret > 0)
|
2012-12-08 03:39:39 +07:00
|
|
|
dso__set_loaded(map->dso, type);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void map_groups__fixup_end(struct map_groups *mg)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < MAP__NR_TYPES; ++i)
|
|
|
|
__map_groups__fixup_end(mg, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *get_kernel_version(const char *root_dir)
|
|
|
|
{
|
|
|
|
char version[PATH_MAX];
|
|
|
|
FILE *file;
|
|
|
|
char *name, *tmp;
|
|
|
|
const char *prefix = "Linux version ";
|
|
|
|
|
|
|
|
sprintf(version, "%s/proc/version", root_dir);
|
|
|
|
file = fopen(version, "r");
|
|
|
|
if (!file)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
version[0] = '\0';
|
|
|
|
tmp = fgets(version, sizeof(version), file);
|
|
|
|
fclose(file);
|
|
|
|
|
|
|
|
name = strstr(version, prefix);
|
|
|
|
if (!name)
|
|
|
|
return NULL;
|
|
|
|
name += strlen(prefix);
|
|
|
|
tmp = strchr(name, ' ');
|
|
|
|
if (tmp)
|
|
|
|
*tmp = '\0';
|
|
|
|
|
|
|
|
return strdup(name);
|
|
|
|
}
|
|
|
|
|
2015-02-13 04:20:01 +07:00
|
|
|
static bool is_kmod_dso(struct dso *dso)
|
|
|
|
{
|
|
|
|
return dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
|
|
|
|
dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int map_groups__set_module_path(struct map_groups *mg, const char *path,
|
|
|
|
struct kmod_path *m)
|
|
|
|
{
|
|
|
|
struct map *map;
|
|
|
|
char *long_name;
|
|
|
|
|
|
|
|
map = map_groups__find_by_name(mg, MAP__FUNCTION, m->name);
|
|
|
|
if (map == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
long_name = strdup(path);
|
|
|
|
if (long_name == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
dso__set_long_name(map->dso, long_name, true);
|
|
|
|
dso__kernel_module_get_build_id(map->dso, "");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Full name could reveal us kmod compression, so
|
|
|
|
* we need to update the symtab_type if needed.
|
|
|
|
*/
|
|
|
|
if (m->comp && is_kmod_dso(map->dso))
|
|
|
|
map->dso->symtab_type++;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-12-08 03:39:39 +07:00
|
|
|
static int map_groups__set_modules_path_dir(struct map_groups *mg,
|
2014-04-27 00:17:55 +07:00
|
|
|
const char *dir_name, int depth)
|
2012-12-08 03:39:39 +07:00
|
|
|
{
|
|
|
|
struct dirent *dent;
|
|
|
|
DIR *dir = opendir(dir_name);
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (!dir) {
|
|
|
|
pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((dent = readdir(dir)) != NULL) {
|
|
|
|
char path[PATH_MAX];
|
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
/*sshfs might return bad dent->d_type, so we have to stat*/
|
|
|
|
snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name);
|
|
|
|
if (stat(path, &st))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (S_ISDIR(st.st_mode)) {
|
|
|
|
if (!strcmp(dent->d_name, ".") ||
|
|
|
|
!strcmp(dent->d_name, ".."))
|
|
|
|
continue;
|
|
|
|
|
2014-04-27 00:17:55 +07:00
|
|
|
/* Do not follow top-level source and build symlinks */
|
|
|
|
if (depth == 0) {
|
|
|
|
if (!strcmp(dent->d_name, "source") ||
|
|
|
|
!strcmp(dent->d_name, "build"))
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = map_groups__set_modules_path_dir(mg, path,
|
|
|
|
depth + 1);
|
2012-12-08 03:39:39 +07:00
|
|
|
if (ret < 0)
|
|
|
|
goto out;
|
|
|
|
} else {
|
2015-02-13 04:20:01 +07:00
|
|
|
struct kmod_path m;
|
2012-12-08 03:39:39 +07:00
|
|
|
|
2015-02-13 04:20:01 +07:00
|
|
|
ret = kmod_path__parse_name(&m, dent->d_name);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
2014-11-04 08:14:27 +07:00
|
|
|
|
2015-02-13 04:20:01 +07:00
|
|
|
if (m.kmod)
|
|
|
|
ret = map_groups__set_module_path(mg, path, &m);
|
2014-11-04 08:14:27 +07:00
|
|
|
|
2015-02-13 04:20:01 +07:00
|
|
|
free(m.name);
|
2012-12-08 03:39:39 +07:00
|
|
|
|
2015-02-13 04:20:01 +07:00
|
|
|
if (ret)
|
2012-12-08 03:39:39 +07:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
closedir(dir);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int machine__set_modules_path(struct machine *machine)
|
|
|
|
{
|
|
|
|
char *version;
|
|
|
|
char modules_path[PATH_MAX];
|
|
|
|
|
|
|
|
version = get_kernel_version(machine->root_dir);
|
|
|
|
if (!version)
|
|
|
|
return -1;
|
|
|
|
|
2014-04-27 00:17:55 +07:00
|
|
|
snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s",
|
2012-12-08 03:39:39 +07:00
|
|
|
machine->root_dir, version);
|
|
|
|
free(version);
|
|
|
|
|
2014-04-27 00:17:55 +07:00
|
|
|
return map_groups__set_modules_path_dir(&machine->kmaps, modules_path, 0);
|
2012-12-08 03:39:39 +07:00
|
|
|
}
|
|
|
|
|
2013-10-08 15:45:48 +07:00
|
|
|
static int machine__create_module(void *arg, const char *name, u64 start)
|
2012-12-08 03:39:39 +07:00
|
|
|
{
|
2013-10-08 15:45:48 +07:00
|
|
|
struct machine *machine = arg;
|
2012-12-08 03:39:39 +07:00
|
|
|
struct map *map;
|
2013-10-08 15:45:48 +07:00
|
|
|
|
perf machine: Fix up some more method names
Calling the function 'machine__new_module' implies a new 'module' will
be allocated, when in fact what is returned is a 'struct map' instance,
that not necessarily will be instantiated, as if one already exists with
the given module name, it will be returned instead.
So be consistent with other "find and if not there, create" like
functions, like machine__findnew_thread, machine__findnew_dso, etc, and
rename it to machine__findnew_module_map(), that in turn will call
machine__findnew_module_dso().
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: http://lkml.kernel.org/n/tip-acv830vd3hwww2ih5vjtbmu3@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-06-01 22:01:02 +07:00
|
|
|
map = machine__findnew_module_map(machine, start, name);
|
2013-10-08 15:45:48 +07:00
|
|
|
if (map == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
dso__kernel_module_get_build_id(map->dso, machine->root_dir);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int machine__create_modules(struct machine *machine)
|
|
|
|
{
|
2012-12-08 03:39:39 +07:00
|
|
|
const char *modules;
|
|
|
|
char path[PATH_MAX];
|
|
|
|
|
2013-09-22 17:22:09 +07:00
|
|
|
if (machine__is_default_guest(machine)) {
|
2012-12-08 03:39:39 +07:00
|
|
|
modules = symbol_conf.default_guest_modules;
|
2013-09-22 17:22:09 +07:00
|
|
|
} else {
|
|
|
|
snprintf(path, PATH_MAX, "%s/proc/modules", machine->root_dir);
|
2012-12-08 03:39:39 +07:00
|
|
|
modules = path;
|
|
|
|
}
|
|
|
|
|
2013-09-22 17:22:09 +07:00
|
|
|
if (symbol__restricted_filename(modules, "/proc/modules"))
|
2012-12-08 03:39:39 +07:00
|
|
|
return -1;
|
|
|
|
|
2013-10-08 15:45:48 +07:00
|
|
|
if (modules__parse(modules, machine, machine__create_module))
|
2012-12-08 03:39:39 +07:00
|
|
|
return -1;
|
|
|
|
|
2013-10-08 15:45:48 +07:00
|
|
|
if (!machine__set_modules_path(machine))
|
|
|
|
return 0;
|
2012-12-08 03:39:39 +07:00
|
|
|
|
2013-10-08 15:45:48 +07:00
|
|
|
pr_debug("Problems setting modules path maps, continuing anyway...\n");
|
2012-12-08 03:39:39 +07:00
|
|
|
|
2013-07-16 03:27:53 +07:00
|
|
|
return 0;
|
2012-12-08 03:39:39 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
int machine__create_kernel_maps(struct machine *machine)
|
|
|
|
{
|
|
|
|
struct dso *kernel = machine__get_kernel(machine);
|
2014-01-29 21:14:39 +07:00
|
|
|
const char *name;
|
2014-08-16 02:08:38 +07:00
|
|
|
u64 addr = machine__get_running_kernel_start(machine, &name);
|
2015-11-18 13:40:33 +07:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!addr || kernel == NULL)
|
2014-01-29 21:14:39 +07:00
|
|
|
return -1;
|
2012-12-08 03:39:39 +07:00
|
|
|
|
2015-11-18 13:40:33 +07:00
|
|
|
ret = __machine__create_kernel_maps(machine, kernel);
|
|
|
|
dso__put(kernel);
|
|
|
|
if (ret < 0)
|
2012-12-08 03:39:39 +07:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
|
|
|
|
if (machine__is_host(machine))
|
|
|
|
pr_debug("Problems creating module maps, "
|
|
|
|
"continuing anyway...\n");
|
|
|
|
else
|
|
|
|
pr_debug("Problems creating module maps for guest %d, "
|
|
|
|
"continuing anyway...\n", machine->pid);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now that we have all the maps created, just set the ->end of them:
|
|
|
|
*/
|
|
|
|
map_groups__fixup_end(&machine->kmaps);
|
2014-01-29 21:14:39 +07:00
|
|
|
|
|
|
|
if (maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, name,
|
|
|
|
addr)) {
|
|
|
|
machine__destroy_kernel_maps(machine);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-12-08 03:39:39 +07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-07 02:26:02 +07:00
|
|
|
static void machine__set_kernel_mmap_len(struct machine *machine,
|
|
|
|
union perf_event *event)
|
|
|
|
{
|
2012-11-07 14:27:10 +07:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < MAP__NR_TYPES; i++) {
|
|
|
|
machine->vmlinux_maps[i]->start = event->mmap.start;
|
|
|
|
machine->vmlinux_maps[i]->end = (event->mmap.start +
|
|
|
|
event->mmap.len);
|
|
|
|
/*
|
|
|
|
* Be a bit paranoid here, some perf.data file came with
|
|
|
|
* a zero sized synthesized MMAP event for the kernel.
|
|
|
|
*/
|
|
|
|
if (machine->vmlinux_maps[i]->end == 0)
|
|
|
|
machine->vmlinux_maps[i]->end = ~0ULL;
|
|
|
|
}
|
2012-10-07 02:26:02 +07:00
|
|
|
}
|
|
|
|
|
2013-08-07 18:38:51 +07:00
|
|
|
static bool machine__uses_kcore(struct machine *machine)
|
|
|
|
{
|
|
|
|
struct dso *dso;
|
|
|
|
|
2015-05-28 23:06:42 +07:00
|
|
|
list_for_each_entry(dso, &machine->dsos.head, node) {
|
2013-08-07 18:38:51 +07:00
|
|
|
if (dso__is_kcore(dso))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-10-07 02:26:02 +07:00
|
|
|
static int machine__process_kernel_mmap_event(struct machine *machine,
|
|
|
|
union perf_event *event)
|
|
|
|
{
|
|
|
|
struct map *map;
|
|
|
|
char kmmap_prefix[PATH_MAX];
|
|
|
|
enum dso_kernel_type kernel_type;
|
|
|
|
bool is_kernel_mmap;
|
|
|
|
|
2013-08-07 18:38:51 +07:00
|
|
|
/* If we have maps from kcore then we do not need or want any others */
|
|
|
|
if (machine__uses_kcore(machine))
|
|
|
|
return 0;
|
|
|
|
|
2012-10-07 02:26:02 +07:00
|
|
|
machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix));
|
|
|
|
if (machine__is_host(machine))
|
|
|
|
kernel_type = DSO_TYPE_KERNEL;
|
|
|
|
else
|
|
|
|
kernel_type = DSO_TYPE_GUEST_KERNEL;
|
|
|
|
|
|
|
|
is_kernel_mmap = memcmp(event->mmap.filename,
|
|
|
|
kmmap_prefix,
|
|
|
|
strlen(kmmap_prefix) - 1) == 0;
|
|
|
|
if (event->mmap.filename[0] == '/' ||
|
|
|
|
(!is_kernel_mmap && event->mmap.filename[0] == '[')) {
|
perf machine: Fix up some more method names
Calling the function 'machine__new_module' implies a new 'module' will
be allocated, when in fact what is returned is a 'struct map' instance,
that not necessarily will be instantiated, as if one already exists with
the given module name, it will be returned instead.
So be consistent with other "find and if not there, create" like
functions, like machine__findnew_thread, machine__findnew_dso, etc, and
rename it to machine__findnew_module_map(), that in turn will call
machine__findnew_module_dso().
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: http://lkml.kernel.org/n/tip-acv830vd3hwww2ih5vjtbmu3@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-06-01 22:01:02 +07:00
|
|
|
map = machine__findnew_module_map(machine, event->mmap.start,
|
|
|
|
event->mmap.filename);
|
2012-10-07 02:26:02 +07:00
|
|
|
if (map == NULL)
|
|
|
|
goto out_problem;
|
|
|
|
|
|
|
|
map->end = map->start + event->mmap.len;
|
|
|
|
} else if (is_kernel_mmap) {
|
|
|
|
const char *symbol_name = (event->mmap.filename +
|
|
|
|
strlen(kmmap_prefix));
|
|
|
|
/*
|
|
|
|
* Should be there already, from the build-id table in
|
|
|
|
* the header.
|
|
|
|
*/
|
perf tools: Fix build-id matching on vmlinux
There's a problem on finding correct kernel symbols when perf report
runs on a different kernel. Although a part of the problem was solved
by the prior commit 0a7e6d1b6844 ("perf tools: Check recorded kernel
version when finding vmlinux"), there's a remaining problem still.
When perf records samples, it synthesizes the kernel map using
machine__mmap_name() and ref_reloc_sym like "[kernel.kallsyms]_text".
You can easily see it using 'perf report -D' command.
After finishing record, it goes through the recorded events to find
maps/dsos actually used. And then record build-id info of them.
During this process, it needs to load symbols in a dso and it'd call
dso__load_vmlinux_path() since the default value of the symbol_conf.
try_vmlinux_path is true. However it changes dso->long_name to a real
path of the vmlinux file (e.g. /lib/modules/3.16.4/build/vmlinux) if one
is running on a custom kernel.
It resulted in that perf report reads the build-id of the vmlinux, but
cannot use it since it only knows about the [kernel.kallsyms] map. It
then falls back to possible vmlinux paths by using the recorded kernel
version (in case of a recent version) or a running kernel silently.
Even with the recent tools, this still has a possibility of breaking
the result. As the build directory is a symbolic link, if one built a
new kernel in the same directory with different source/config, the old
link to vmlinux will point the new file. So it's absolutely needed to
use build-id when finding a kernel image.
In this patch, it's now changed to try to search a kernel dso in the
existing dso list which was constructed during build-id table parsing
so it'll always have a build-id. If not found, search "[kernel.kallsyms]".
Before:
$ perf report
# Children Self Command Shared Object Symbol
# ........ ........ ....... ................. ...............................
#
72.15% 0.00% swapper [kernel.kallsyms] [k] set_curr_task_rt
72.15% 0.00% swapper [kernel.kallsyms] [k] native_calibrate_tsc
72.15% 0.00% swapper [kernel.kallsyms] [k] tsc_refine_calibration_work
71.87% 71.87% swapper [kernel.kallsyms] [k] module_finalize
...
After (for the same perf.data):
72.15% 0.00% swapper vmlinux [k] cpu_startup_entry
72.15% 0.00% swapper vmlinux [k] arch_cpu_idle
72.15% 0.00% swapper vmlinux [k] default_idle
71.87% 71.87% swapper vmlinux [k] native_safe_halt
...
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Ingo Molnar <mingo@kernel.org>
Link: http://lkml.kernel.org/r/20140924073356.GB1962@gmail.com
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung.kim@lge.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1415063674-17206-8-git-send-email-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2014-11-04 08:14:33 +07:00
|
|
|
struct dso *kernel = NULL;
|
|
|
|
struct dso *dso;
|
|
|
|
|
2015-06-02 01:40:01 +07:00
|
|
|
pthread_rwlock_rdlock(&machine->dsos.lock);
|
|
|
|
|
2015-05-28 23:06:42 +07:00
|
|
|
list_for_each_entry(dso, &machine->dsos.head, node) {
|
2015-06-03 15:52:21 +07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The cpumode passed to is_kernel_module is not the
|
|
|
|
* cpumode of *this* event. If we insist on passing
|
|
|
|
* correct cpumode to is_kernel_module, we should
|
|
|
|
* record the cpumode when we adding this dso to the
|
|
|
|
* linked list.
|
|
|
|
*
|
|
|
|
* However we don't really need passing correct
|
|
|
|
* cpumode. We know the correct cpumode must be kernel
|
|
|
|
* mode (if not, we should not link it onto kernel_dsos
|
|
|
|
* list).
|
|
|
|
*
|
|
|
|
* Therefore, we pass PERF_RECORD_MISC_CPUMODE_UNKNOWN.
|
|
|
|
* is_kernel_module() treats it as a kernel cpumode.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!dso->kernel ||
|
|
|
|
is_kernel_module(dso->long_name,
|
|
|
|
PERF_RECORD_MISC_CPUMODE_UNKNOWN))
|
perf tools: Fix build-id matching on vmlinux
There's a problem on finding correct kernel symbols when perf report
runs on a different kernel. Although a part of the problem was solved
by the prior commit 0a7e6d1b6844 ("perf tools: Check recorded kernel
version when finding vmlinux"), there's a remaining problem still.
When perf records samples, it synthesizes the kernel map using
machine__mmap_name() and ref_reloc_sym like "[kernel.kallsyms]_text".
You can easily see it using 'perf report -D' command.
After finishing record, it goes through the recorded events to find
maps/dsos actually used. And then record build-id info of them.
During this process, it needs to load symbols in a dso and it'd call
dso__load_vmlinux_path() since the default value of the symbol_conf.
try_vmlinux_path is true. However it changes dso->long_name to a real
path of the vmlinux file (e.g. /lib/modules/3.16.4/build/vmlinux) if one
is running on a custom kernel.
It resulted in that perf report reads the build-id of the vmlinux, but
cannot use it since it only knows about the [kernel.kallsyms] map. It
then falls back to possible vmlinux paths by using the recorded kernel
version (in case of a recent version) or a running kernel silently.
Even with the recent tools, this still has a possibility of breaking
the result. As the build directory is a symbolic link, if one built a
new kernel in the same directory with different source/config, the old
link to vmlinux will point the new file. So it's absolutely needed to
use build-id when finding a kernel image.
In this patch, it's now changed to try to search a kernel dso in the
existing dso list which was constructed during build-id table parsing
so it'll always have a build-id. If not found, search "[kernel.kallsyms]".
Before:
$ perf report
# Children Self Command Shared Object Symbol
# ........ ........ ....... ................. ...............................
#
72.15% 0.00% swapper [kernel.kallsyms] [k] set_curr_task_rt
72.15% 0.00% swapper [kernel.kallsyms] [k] native_calibrate_tsc
72.15% 0.00% swapper [kernel.kallsyms] [k] tsc_refine_calibration_work
71.87% 71.87% swapper [kernel.kallsyms] [k] module_finalize
...
After (for the same perf.data):
72.15% 0.00% swapper vmlinux [k] cpu_startup_entry
72.15% 0.00% swapper vmlinux [k] arch_cpu_idle
72.15% 0.00% swapper vmlinux [k] default_idle
71.87% 71.87% swapper vmlinux [k] native_safe_halt
...
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Ingo Molnar <mingo@kernel.org>
Link: http://lkml.kernel.org/r/20140924073356.GB1962@gmail.com
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung.kim@lge.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1415063674-17206-8-git-send-email-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2014-11-04 08:14:33 +07:00
|
|
|
continue;
|
|
|
|
|
2015-06-03 15:52:21 +07:00
|
|
|
|
perf tools: Fix build-id matching on vmlinux
There's a problem on finding correct kernel symbols when perf report
runs on a different kernel. Although a part of the problem was solved
by the prior commit 0a7e6d1b6844 ("perf tools: Check recorded kernel
version when finding vmlinux"), there's a remaining problem still.
When perf records samples, it synthesizes the kernel map using
machine__mmap_name() and ref_reloc_sym like "[kernel.kallsyms]_text".
You can easily see it using 'perf report -D' command.
After finishing record, it goes through the recorded events to find
maps/dsos actually used. And then record build-id info of them.
During this process, it needs to load symbols in a dso and it'd call
dso__load_vmlinux_path() since the default value of the symbol_conf.
try_vmlinux_path is true. However it changes dso->long_name to a real
path of the vmlinux file (e.g. /lib/modules/3.16.4/build/vmlinux) if one
is running on a custom kernel.
It resulted in that perf report reads the build-id of the vmlinux, but
cannot use it since it only knows about the [kernel.kallsyms] map. It
then falls back to possible vmlinux paths by using the recorded kernel
version (in case of a recent version) or a running kernel silently.
Even with the recent tools, this still has a possibility of breaking
the result. As the build directory is a symbolic link, if one built a
new kernel in the same directory with different source/config, the old
link to vmlinux will point the new file. So it's absolutely needed to
use build-id when finding a kernel image.
In this patch, it's now changed to try to search a kernel dso in the
existing dso list which was constructed during build-id table parsing
so it'll always have a build-id. If not found, search "[kernel.kallsyms]".
Before:
$ perf report
# Children Self Command Shared Object Symbol
# ........ ........ ....... ................. ...............................
#
72.15% 0.00% swapper [kernel.kallsyms] [k] set_curr_task_rt
72.15% 0.00% swapper [kernel.kallsyms] [k] native_calibrate_tsc
72.15% 0.00% swapper [kernel.kallsyms] [k] tsc_refine_calibration_work
71.87% 71.87% swapper [kernel.kallsyms] [k] module_finalize
...
After (for the same perf.data):
72.15% 0.00% swapper vmlinux [k] cpu_startup_entry
72.15% 0.00% swapper vmlinux [k] arch_cpu_idle
72.15% 0.00% swapper vmlinux [k] default_idle
71.87% 71.87% swapper vmlinux [k] native_safe_halt
...
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Ingo Molnar <mingo@kernel.org>
Link: http://lkml.kernel.org/r/20140924073356.GB1962@gmail.com
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung.kim@lge.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1415063674-17206-8-git-send-email-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2014-11-04 08:14:33 +07:00
|
|
|
kernel = dso;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-06-02 01:40:01 +07:00
|
|
|
pthread_rwlock_unlock(&machine->dsos.lock);
|
|
|
|
|
perf tools: Fix build-id matching on vmlinux
There's a problem on finding correct kernel symbols when perf report
runs on a different kernel. Although a part of the problem was solved
by the prior commit 0a7e6d1b6844 ("perf tools: Check recorded kernel
version when finding vmlinux"), there's a remaining problem still.
When perf records samples, it synthesizes the kernel map using
machine__mmap_name() and ref_reloc_sym like "[kernel.kallsyms]_text".
You can easily see it using 'perf report -D' command.
After finishing record, it goes through the recorded events to find
maps/dsos actually used. And then record build-id info of them.
During this process, it needs to load symbols in a dso and it'd call
dso__load_vmlinux_path() since the default value of the symbol_conf.
try_vmlinux_path is true. However it changes dso->long_name to a real
path of the vmlinux file (e.g. /lib/modules/3.16.4/build/vmlinux) if one
is running on a custom kernel.
It resulted in that perf report reads the build-id of the vmlinux, but
cannot use it since it only knows about the [kernel.kallsyms] map. It
then falls back to possible vmlinux paths by using the recorded kernel
version (in case of a recent version) or a running kernel silently.
Even with the recent tools, this still has a possibility of breaking
the result. As the build directory is a symbolic link, if one built a
new kernel in the same directory with different source/config, the old
link to vmlinux will point the new file. So it's absolutely needed to
use build-id when finding a kernel image.
In this patch, it's now changed to try to search a kernel dso in the
existing dso list which was constructed during build-id table parsing
so it'll always have a build-id. If not found, search "[kernel.kallsyms]".
Before:
$ perf report
# Children Self Command Shared Object Symbol
# ........ ........ ....... ................. ...............................
#
72.15% 0.00% swapper [kernel.kallsyms] [k] set_curr_task_rt
72.15% 0.00% swapper [kernel.kallsyms] [k] native_calibrate_tsc
72.15% 0.00% swapper [kernel.kallsyms] [k] tsc_refine_calibration_work
71.87% 71.87% swapper [kernel.kallsyms] [k] module_finalize
...
After (for the same perf.data):
72.15% 0.00% swapper vmlinux [k] cpu_startup_entry
72.15% 0.00% swapper vmlinux [k] arch_cpu_idle
72.15% 0.00% swapper vmlinux [k] default_idle
71.87% 71.87% swapper vmlinux [k] native_safe_halt
...
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Ingo Molnar <mingo@kernel.org>
Link: http://lkml.kernel.org/r/20140924073356.GB1962@gmail.com
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung.kim@lge.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1415063674-17206-8-git-send-email-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2014-11-04 08:14:33 +07:00
|
|
|
if (kernel == NULL)
|
2015-05-29 21:31:12 +07:00
|
|
|
kernel = machine__findnew_dso(machine, kmmap_prefix);
|
2012-10-07 02:26:02 +07:00
|
|
|
if (kernel == NULL)
|
|
|
|
goto out_problem;
|
|
|
|
|
|
|
|
kernel->kernel = kernel_type;
|
2015-06-02 21:53:26 +07:00
|
|
|
if (__machine__create_kernel_maps(machine, kernel) < 0) {
|
|
|
|
dso__put(kernel);
|
2012-10-07 02:26:02 +07:00
|
|
|
goto out_problem;
|
2015-06-02 21:53:26 +07:00
|
|
|
}
|
2012-10-07 02:26:02 +07:00
|
|
|
|
2014-11-18 11:30:28 +07:00
|
|
|
if (strstr(kernel->long_name, "vmlinux"))
|
|
|
|
dso__set_short_name(kernel, "[kernel.vmlinux]", false);
|
2014-11-04 08:14:34 +07:00
|
|
|
|
2012-10-07 02:26:02 +07:00
|
|
|
machine__set_kernel_mmap_len(machine, event);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Avoid using a zero address (kptr_restrict) for the ref reloc
|
|
|
|
* symbol. Effectively having zero here means that at record
|
|
|
|
* time /proc/sys/kernel/kptr_restrict was non zero.
|
|
|
|
*/
|
|
|
|
if (event->mmap.pgoff != 0) {
|
|
|
|
maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
|
|
|
|
symbol_name,
|
|
|
|
event->mmap.pgoff);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (machine__is_default_guest(machine)) {
|
|
|
|
/*
|
|
|
|
* preload dso of guest kernel and modules
|
|
|
|
*/
|
2015-09-30 21:54:04 +07:00
|
|
|
dso__load(kernel, machine__kernel_map(machine), NULL);
|
2012-10-07 02:26:02 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
out_problem:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-08-21 17:10:25 +07:00
|
|
|
int machine__process_mmap2_event(struct machine *machine,
|
2013-09-11 21:18:24 +07:00
|
|
|
union perf_event *event,
|
|
|
|
struct perf_sample *sample __maybe_unused)
|
2013-08-21 17:10:25 +07:00
|
|
|
{
|
|
|
|
u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
|
|
|
|
struct thread *thread;
|
|
|
|
struct map *map;
|
|
|
|
enum map_type type;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (dump_trace)
|
|
|
|
perf_event__fprintf_mmap2(event, stdout);
|
|
|
|
|
|
|
|
if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
|
|
|
|
cpumode == PERF_RECORD_MISC_KERNEL) {
|
|
|
|
ret = machine__process_kernel_mmap_event(machine, event);
|
|
|
|
if (ret < 0)
|
|
|
|
goto out_problem;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
thread = machine__findnew_thread(machine, event->mmap2.pid,
|
2014-02-26 22:45:27 +07:00
|
|
|
event->mmap2.tid);
|
2013-08-21 17:10:25 +07:00
|
|
|
if (thread == NULL)
|
|
|
|
goto out_problem;
|
|
|
|
|
|
|
|
if (event->header.misc & PERF_RECORD_MISC_MMAP_DATA)
|
|
|
|
type = MAP__VARIABLE;
|
|
|
|
else
|
|
|
|
type = MAP__FUNCTION;
|
|
|
|
|
2014-07-22 20:17:53 +07:00
|
|
|
map = map__new(machine, event->mmap2.start,
|
2013-08-21 17:10:25 +07:00
|
|
|
event->mmap2.len, event->mmap2.pgoff,
|
|
|
|
event->mmap2.pid, event->mmap2.maj,
|
|
|
|
event->mmap2.min, event->mmap2.ino,
|
|
|
|
event->mmap2.ino_generation,
|
2014-05-20 02:13:49 +07:00
|
|
|
event->mmap2.prot,
|
|
|
|
event->mmap2.flags,
|
2014-07-22 20:18:00 +07:00
|
|
|
event->mmap2.filename, type, thread);
|
2013-08-21 17:10:25 +07:00
|
|
|
|
|
|
|
if (map == NULL)
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
goto out_problem_map;
|
2013-08-21 17:10:25 +07:00
|
|
|
|
|
|
|
thread__insert_map(thread, map);
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
thread__put(thread);
|
2015-05-26 02:59:56 +07:00
|
|
|
map__put(map);
|
2013-08-21 17:10:25 +07:00
|
|
|
return 0;
|
|
|
|
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
out_problem_map:
|
|
|
|
thread__put(thread);
|
2013-08-21 17:10:25 +07:00
|
|
|
out_problem:
|
|
|
|
dump_printf("problem processing PERF_RECORD_MMAP2, skipping event.\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-11 21:18:24 +07:00
|
|
|
int machine__process_mmap_event(struct machine *machine, union perf_event *event,
|
|
|
|
struct perf_sample *sample __maybe_unused)
|
2012-10-07 02:26:02 +07:00
|
|
|
{
|
|
|
|
u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
|
|
|
|
struct thread *thread;
|
|
|
|
struct map *map;
|
2013-01-24 22:10:40 +07:00
|
|
|
enum map_type type;
|
2012-10-07 02:26:02 +07:00
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (dump_trace)
|
|
|
|
perf_event__fprintf_mmap(event, stdout);
|
|
|
|
|
|
|
|
if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
|
|
|
|
cpumode == PERF_RECORD_MISC_KERNEL) {
|
|
|
|
ret = machine__process_kernel_mmap_event(machine, event);
|
|
|
|
if (ret < 0)
|
|
|
|
goto out_problem;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-08-27 15:23:03 +07:00
|
|
|
thread = machine__findnew_thread(machine, event->mmap.pid,
|
2014-02-26 22:45:27 +07:00
|
|
|
event->mmap.tid);
|
2012-10-07 02:26:02 +07:00
|
|
|
if (thread == NULL)
|
|
|
|
goto out_problem;
|
2013-01-24 22:10:40 +07:00
|
|
|
|
|
|
|
if (event->header.misc & PERF_RECORD_MISC_MMAP_DATA)
|
|
|
|
type = MAP__VARIABLE;
|
|
|
|
else
|
|
|
|
type = MAP__FUNCTION;
|
|
|
|
|
2014-07-22 20:17:53 +07:00
|
|
|
map = map__new(machine, event->mmap.start,
|
2012-10-07 02:26:02 +07:00
|
|
|
event->mmap.len, event->mmap.pgoff,
|
2014-05-20 02:13:49 +07:00
|
|
|
event->mmap.pid, 0, 0, 0, 0, 0, 0,
|
2013-08-21 17:10:25 +07:00
|
|
|
event->mmap.filename,
|
2014-07-22 20:18:00 +07:00
|
|
|
type, thread);
|
2013-01-24 22:10:40 +07:00
|
|
|
|
2012-10-07 02:26:02 +07:00
|
|
|
if (map == NULL)
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
goto out_problem_map;
|
2012-10-07 02:26:02 +07:00
|
|
|
|
|
|
|
thread__insert_map(thread, map);
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
thread__put(thread);
|
2015-05-26 02:59:56 +07:00
|
|
|
map__put(map);
|
2012-10-07 02:26:02 +07:00
|
|
|
return 0;
|
|
|
|
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
out_problem_map:
|
|
|
|
thread__put(thread);
|
2012-10-07 02:26:02 +07:00
|
|
|
out_problem:
|
|
|
|
dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
static void __machine__remove_thread(struct machine *machine, struct thread *th, bool lock)
|
2013-08-14 21:49:27 +07:00
|
|
|
{
|
2015-03-03 08:21:35 +07:00
|
|
|
if (machine->last_match == th)
|
2015-05-12 04:08:12 +07:00
|
|
|
machine->last_match = NULL;
|
2015-03-03 08:21:35 +07:00
|
|
|
|
2015-05-16 01:32:55 +07:00
|
|
|
BUG_ON(atomic_read(&th->refcnt) == 0);
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
if (lock)
|
|
|
|
pthread_rwlock_wrlock(&machine->threads_lock);
|
2015-05-26 01:23:05 +07:00
|
|
|
rb_erase_init(&th->rb_node, &machine->threads);
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
RB_CLEAR_NODE(&th->rb_node);
|
2013-08-14 21:49:27 +07:00
|
|
|
/*
|
2015-03-03 08:21:35 +07:00
|
|
|
* Move it first to the dead_threads list, then drop the reference,
|
|
|
|
* if this is the last reference, then the thread__delete destructor
|
|
|
|
* will be called and we will remove it from the dead_threads list.
|
2013-08-14 21:49:27 +07:00
|
|
|
*/
|
|
|
|
list_add_tail(&th->node, &machine->dead_threads);
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
if (lock)
|
|
|
|
pthread_rwlock_unlock(&machine->threads_lock);
|
2015-03-03 08:21:35 +07:00
|
|
|
thread__put(th);
|
2013-08-14 21:49:27 +07:00
|
|
|
}
|
|
|
|
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
void machine__remove_thread(struct machine *machine, struct thread *th)
|
|
|
|
{
|
|
|
|
return __machine__remove_thread(machine, th, true);
|
|
|
|
}
|
|
|
|
|
2013-09-11 21:18:24 +07:00
|
|
|
int machine__process_fork_event(struct machine *machine, union perf_event *event,
|
|
|
|
struct perf_sample *sample)
|
2012-10-07 02:26:02 +07:00
|
|
|
{
|
2014-03-14 21:00:03 +07:00
|
|
|
struct thread *thread = machine__find_thread(machine,
|
|
|
|
event->fork.pid,
|
|
|
|
event->fork.tid);
|
2013-08-27 15:23:03 +07:00
|
|
|
struct thread *parent = machine__findnew_thread(machine,
|
|
|
|
event->fork.ppid,
|
|
|
|
event->fork.ptid);
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
int err = 0;
|
2012-10-07 02:26:02 +07:00
|
|
|
|
2015-08-19 21:29:20 +07:00
|
|
|
if (dump_trace)
|
|
|
|
perf_event__fprintf_task(event, stdout);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* There may be an existing thread that is not actually the parent,
|
|
|
|
* either because we are processing events out of order, or because the
|
|
|
|
* (fork) event that would have removed the thread was lost. Assume the
|
|
|
|
* latter case and continue on as best we can.
|
|
|
|
*/
|
|
|
|
if (parent->pid_ != (pid_t)event->fork.ppid) {
|
|
|
|
dump_printf("removing erroneous parent thread %d/%d\n",
|
|
|
|
parent->pid_, parent->tid);
|
|
|
|
machine__remove_thread(machine, parent);
|
|
|
|
thread__put(parent);
|
|
|
|
parent = machine__findnew_thread(machine, event->fork.ppid,
|
|
|
|
event->fork.ptid);
|
|
|
|
}
|
|
|
|
|
2013-08-14 21:49:27 +07:00
|
|
|
/* if a thread currently exists for the thread id remove it */
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
if (thread != NULL) {
|
2013-08-14 21:49:27 +07:00
|
|
|
machine__remove_thread(machine, thread);
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
thread__put(thread);
|
|
|
|
}
|
2013-08-14 21:49:27 +07:00
|
|
|
|
2013-08-27 15:23:03 +07:00
|
|
|
thread = machine__findnew_thread(machine, event->fork.pid,
|
|
|
|
event->fork.tid);
|
2012-10-07 02:26:02 +07:00
|
|
|
|
|
|
|
if (thread == NULL || parent == NULL ||
|
2013-09-11 21:18:24 +07:00
|
|
|
thread__fork(thread, parent, sample->time) < 0) {
|
2012-10-07 02:26:02 +07:00
|
|
|
dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
err = -1;
|
2012-10-07 02:26:02 +07:00
|
|
|
}
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
thread__put(thread);
|
|
|
|
thread__put(parent);
|
2012-10-07 02:26:02 +07:00
|
|
|
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
return err;
|
2012-10-07 02:26:02 +07:00
|
|
|
}
|
|
|
|
|
2013-09-11 21:18:24 +07:00
|
|
|
int machine__process_exit_event(struct machine *machine, union perf_event *event,
|
|
|
|
struct perf_sample *sample __maybe_unused)
|
2012-10-07 02:26:02 +07:00
|
|
|
{
|
2014-03-14 21:00:03 +07:00
|
|
|
struct thread *thread = machine__find_thread(machine,
|
|
|
|
event->fork.pid,
|
|
|
|
event->fork.tid);
|
2012-10-07 02:26:02 +07:00
|
|
|
|
|
|
|
if (dump_trace)
|
|
|
|
perf_event__fprintf_task(event, stdout);
|
|
|
|
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
if (thread != NULL) {
|
2013-08-14 21:49:27 +07:00
|
|
|
thread__exited(thread);
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
thread__put(thread);
|
|
|
|
}
|
2012-10-07 02:26:02 +07:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-11 21:18:24 +07:00
|
|
|
int machine__process_event(struct machine *machine, union perf_event *event,
|
|
|
|
struct perf_sample *sample)
|
2012-10-07 02:26:02 +07:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
switch (event->header.type) {
|
|
|
|
case PERF_RECORD_COMM:
|
2013-09-11 21:18:24 +07:00
|
|
|
ret = machine__process_comm_event(machine, event, sample); break;
|
2012-10-07 02:26:02 +07:00
|
|
|
case PERF_RECORD_MMAP:
|
2013-09-11 21:18:24 +07:00
|
|
|
ret = machine__process_mmap_event(machine, event, sample); break;
|
2013-08-21 17:10:25 +07:00
|
|
|
case PERF_RECORD_MMAP2:
|
2013-09-11 21:18:24 +07:00
|
|
|
ret = machine__process_mmap2_event(machine, event, sample); break;
|
2012-10-07 02:26:02 +07:00
|
|
|
case PERF_RECORD_FORK:
|
2013-09-11 21:18:24 +07:00
|
|
|
ret = machine__process_fork_event(machine, event, sample); break;
|
2012-10-07 02:26:02 +07:00
|
|
|
case PERF_RECORD_EXIT:
|
2013-09-11 21:18:24 +07:00
|
|
|
ret = machine__process_exit_event(machine, event, sample); break;
|
2012-10-07 02:26:02 +07:00
|
|
|
case PERF_RECORD_LOST:
|
2013-09-11 21:18:24 +07:00
|
|
|
ret = machine__process_lost_event(machine, event, sample); break;
|
2015-04-30 21:37:29 +07:00
|
|
|
case PERF_RECORD_AUX:
|
|
|
|
ret = machine__process_aux_event(machine, event); break;
|
2015-04-30 21:37:30 +07:00
|
|
|
case PERF_RECORD_ITRACE_START:
|
2015-06-29 18:27:45 +07:00
|
|
|
ret = machine__process_itrace_start_event(machine, event); break;
|
2015-05-11 02:13:15 +07:00
|
|
|
case PERF_RECORD_LOST_SAMPLES:
|
|
|
|
ret = machine__process_lost_samples_event(machine, event, sample); break;
|
2015-07-21 16:44:03 +07:00
|
|
|
case PERF_RECORD_SWITCH:
|
|
|
|
case PERF_RECORD_SWITCH_CPU_WIDE:
|
|
|
|
ret = machine__process_switch_event(machine, event); break;
|
2012-10-07 02:26:02 +07:00
|
|
|
default:
|
|
|
|
ret = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2012-12-08 03:39:39 +07:00
|
|
|
|
2012-12-07 12:48:05 +07:00
|
|
|
static bool symbol__match_regex(struct symbol *sym, regex_t *regex)
|
2012-12-08 03:39:39 +07:00
|
|
|
{
|
2012-12-07 12:48:05 +07:00
|
|
|
if (sym->name && !regexec(regex, sym->name, 0, NULL, 0))
|
2012-12-08 03:39:39 +07:00
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-10-23 22:50:25 +07:00
|
|
|
static void ip__resolve_ams(struct thread *thread,
|
2012-12-08 03:39:39 +07:00
|
|
|
struct addr_map_symbol *ams,
|
|
|
|
u64 ip)
|
|
|
|
{
|
|
|
|
struct addr_location al;
|
|
|
|
|
|
|
|
memset(&al, 0, sizeof(al));
|
2014-03-12 02:16:49 +07:00
|
|
|
/*
|
|
|
|
* We cannot use the header.misc hint to determine whether a
|
|
|
|
* branch stack address is user, kernel, guest, hypervisor.
|
|
|
|
* Branches may straddle the kernel/user/hypervisor boundaries.
|
|
|
|
* Thus, we have to try consecutively until we find a match
|
|
|
|
* or else, the symbol is unknown
|
|
|
|
*/
|
2014-10-23 22:50:25 +07:00
|
|
|
thread__find_cpumode_addr_location(thread, MAP__FUNCTION, ip, &al);
|
2012-12-08 03:39:39 +07:00
|
|
|
|
|
|
|
ams->addr = ip;
|
|
|
|
ams->al_addr = al.addr;
|
|
|
|
ams->sym = al.sym;
|
|
|
|
ams->map = al.map;
|
|
|
|
}
|
|
|
|
|
2014-10-23 22:50:25 +07:00
|
|
|
static void ip__resolve_data(struct thread *thread,
|
2013-01-24 22:10:35 +07:00
|
|
|
u8 m, struct addr_map_symbol *ams, u64 addr)
|
|
|
|
{
|
|
|
|
struct addr_location al;
|
|
|
|
|
|
|
|
memset(&al, 0, sizeof(al));
|
|
|
|
|
2014-10-23 22:50:25 +07:00
|
|
|
thread__find_addr_location(thread, m, MAP__VARIABLE, addr, &al);
|
2014-08-21 10:25:11 +07:00
|
|
|
if (al.map == NULL) {
|
|
|
|
/*
|
|
|
|
* some shared data regions have execute bit set which puts
|
|
|
|
* their mapping in the MAP__FUNCTION type array.
|
|
|
|
* Check there as a fallback option before dropping the sample.
|
|
|
|
*/
|
2014-10-23 22:50:25 +07:00
|
|
|
thread__find_addr_location(thread, m, MAP__FUNCTION, addr, &al);
|
2014-08-21 10:25:11 +07:00
|
|
|
}
|
|
|
|
|
2013-01-24 22:10:35 +07:00
|
|
|
ams->addr = addr;
|
|
|
|
ams->al_addr = al.addr;
|
|
|
|
ams->sym = al.sym;
|
|
|
|
ams->map = al.map;
|
|
|
|
}
|
|
|
|
|
2014-01-22 23:05:06 +07:00
|
|
|
struct mem_info *sample__resolve_mem(struct perf_sample *sample,
|
|
|
|
struct addr_location *al)
|
2013-01-24 22:10:35 +07:00
|
|
|
{
|
|
|
|
struct mem_info *mi = zalloc(sizeof(*mi));
|
|
|
|
|
|
|
|
if (!mi)
|
|
|
|
return NULL;
|
|
|
|
|
2014-10-23 22:50:25 +07:00
|
|
|
ip__resolve_ams(al->thread, &mi->iaddr, sample->ip);
|
|
|
|
ip__resolve_data(al->thread, al->cpumode, &mi->daddr, sample->addr);
|
2013-01-24 22:10:35 +07:00
|
|
|
mi->data_src.val = sample->data_src;
|
|
|
|
|
|
|
|
return mi;
|
|
|
|
}
|
|
|
|
|
2014-11-13 09:05:19 +07:00
|
|
|
static int add_callchain_ip(struct thread *thread,
|
|
|
|
struct symbol **parent,
|
|
|
|
struct addr_location *root_al,
|
2015-03-30 15:11:00 +07:00
|
|
|
u8 *cpumode,
|
2014-11-13 09:05:19 +07:00
|
|
|
u64 ip)
|
|
|
|
{
|
|
|
|
struct addr_location al;
|
|
|
|
|
|
|
|
al.filtered = 0;
|
|
|
|
al.sym = NULL;
|
2015-03-30 15:11:00 +07:00
|
|
|
if (!cpumode) {
|
perf callchain: Support handling complete branch stacks as histograms
Currently branch stacks can be only shown as edge histograms for
individual branches. I never found this display particularly useful.
This implements an alternative mode that creates histograms over
complete branch traces, instead of individual branches, similar to how
normal callgraphs are handled. This is done by putting it in front of
the normal callgraph and then using the normal callgraph histogram
infrastructure to unify them.
This way in complex functions we can understand the control flow that
lead to a particular sample, and may even see some control flow in the
caller for short functions.
Example (simplified, of course for such simple code this is usually not
needed), please run this after the whole patchkit is in, as at this
point in the patch order there is no --branch-history, that will be
added in a patch after this one:
tcall.c:
volatile a = 10000, b = 100000, c;
__attribute__((noinline)) f2()
{
c = a / b;
}
__attribute__((noinline)) f1()
{
f2();
f2();
}
main()
{
int i;
for (i = 0; i < 1000000; i++)
f1();
}
% perf record -b -g ./tsrc/tcall
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.044 MB perf.data (~1923 samples) ]
% perf report --no-children --branch-history
...
54.91% tcall.c:6 [.] f2 tcall
|
|--65.53%-- f2 tcall.c:5
| |
| |--70.83%-- f1 tcall.c:11
| | f1 tcall.c:10
| | main tcall.c:18
| | main tcall.c:18
| | main tcall.c:17
| | main tcall.c:17
| | f1 tcall.c:13
| | f1 tcall.c:13
| | f2 tcall.c:7
| | f2 tcall.c:5
| | f1 tcall.c:12
| | f1 tcall.c:12
| | f2 tcall.c:7
| | f2 tcall.c:5
| | f1 tcall.c:11
| |
| --29.17%-- f1 tcall.c:12
| f1 tcall.c:12
| f2 tcall.c:7
| f2 tcall.c:5
| f1 tcall.c:11
| f1 tcall.c:10
| main tcall.c:18
| main tcall.c:18
| main tcall.c:17
| main tcall.c:17
| f1 tcall.c:13
| f1 tcall.c:13
| f2 tcall.c:7
| f2 tcall.c:5
| f1 tcall.c:12
The default output is unchanged.
This is only implemented in perf report, no change to record or anywhere
else.
This adds the basic code to report:
- add a new "branch" option to the -g option parser to enable this mode
- when the flag is set include the LBR into the callstack in machine.c.
The rest of the history code is unchanged and doesn't know the
difference between LBR entry and normal call entry.
- detect overlaps with the callchain
- remove small loop duplicates in the LBR
Current limitations:
- The LBR flags (mispredict etc.) are not shown in the history
and LBR entries have no special marker.
- It would be nice if annotate marked the LBR entries somehow
(e.g. with arrows)
v2: Various fixes.
v3: Merge further patches into this one. Fix white space.
v4: Improve manpage. Address review feedback.
v5: Rename functions. Better error message without -g. Fix crash without
-b.
v6: Rebase
v7: Rebase. Use NO_ENTRY in memset.
v8: Port to latest tip. Move add_callchain_ip to separate
patch. Skip initial entries in callchain. Minor cleanups.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: http://lkml.kernel.org/r/1415844328-4884-3-git-send-email-andi@firstfloor.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2014-11-13 09:05:20 +07:00
|
|
|
thread__find_cpumode_addr_location(thread, MAP__FUNCTION,
|
|
|
|
ip, &al);
|
2015-03-30 15:11:00 +07:00
|
|
|
} else {
|
2014-12-02 22:06:53 +07:00
|
|
|
if (ip >= PERF_CONTEXT_MAX) {
|
|
|
|
switch (ip) {
|
|
|
|
case PERF_CONTEXT_HV:
|
2015-03-30 15:11:00 +07:00
|
|
|
*cpumode = PERF_RECORD_MISC_HYPERVISOR;
|
2014-12-02 22:06:53 +07:00
|
|
|
break;
|
|
|
|
case PERF_CONTEXT_KERNEL:
|
2015-03-30 15:11:00 +07:00
|
|
|
*cpumode = PERF_RECORD_MISC_KERNEL;
|
2014-12-02 22:06:53 +07:00
|
|
|
break;
|
|
|
|
case PERF_CONTEXT_USER:
|
2015-03-30 15:11:00 +07:00
|
|
|
*cpumode = PERF_RECORD_MISC_USER;
|
2014-12-02 22:06:53 +07:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
pr_debug("invalid callchain context: "
|
|
|
|
"%"PRId64"\n", (s64) ip);
|
|
|
|
/*
|
|
|
|
* It seems the callchain is corrupted.
|
|
|
|
* Discard all.
|
|
|
|
*/
|
|
|
|
callchain_cursor_reset(&callchain_cursor);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2015-03-30 15:11:00 +07:00
|
|
|
thread__find_addr_location(thread, *cpumode, MAP__FUNCTION,
|
|
|
|
ip, &al);
|
2014-12-02 22:06:53 +07:00
|
|
|
}
|
|
|
|
|
2014-11-13 09:05:19 +07:00
|
|
|
if (al.sym != NULL) {
|
|
|
|
if (sort__has_parent && !*parent &&
|
|
|
|
symbol__match_regex(al.sym, &parent_regex))
|
|
|
|
*parent = al.sym;
|
|
|
|
else if (have_ignore_callees && root_al &&
|
|
|
|
symbol__match_regex(al.sym, &ignore_callees_regex)) {
|
|
|
|
/* Treat this symbol as the root,
|
|
|
|
forgetting its callees. */
|
|
|
|
*root_al = al;
|
|
|
|
callchain_cursor_reset(&callchain_cursor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-26 14:08:20 +07:00
|
|
|
if (symbol_conf.hide_unresolved && al.sym == NULL)
|
|
|
|
return 0;
|
2014-11-13 09:05:21 +07:00
|
|
|
return callchain_cursor_append(&callchain_cursor, al.addr, al.map, al.sym);
|
2014-11-13 09:05:19 +07:00
|
|
|
}
|
|
|
|
|
2014-01-22 23:15:36 +07:00
|
|
|
struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
|
|
|
|
struct addr_location *al)
|
2012-12-08 03:39:39 +07:00
|
|
|
{
|
|
|
|
unsigned int i;
|
2014-01-22 23:15:36 +07:00
|
|
|
const struct branch_stack *bs = sample->branch_stack;
|
|
|
|
struct branch_info *bi = calloc(bs->nr, sizeof(struct branch_info));
|
2012-12-08 03:39:39 +07:00
|
|
|
|
|
|
|
if (!bi)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
for (i = 0; i < bs->nr; i++) {
|
2014-10-23 22:50:25 +07:00
|
|
|
ip__resolve_ams(al->thread, &bi[i].to, bs->entries[i].to);
|
|
|
|
ip__resolve_ams(al->thread, &bi[i].from, bs->entries[i].from);
|
2012-12-08 03:39:39 +07:00
|
|
|
bi[i].flags = bs->entries[i].flags;
|
|
|
|
}
|
|
|
|
return bi;
|
|
|
|
}
|
|
|
|
|
perf callchain: Support handling complete branch stacks as histograms
Currently branch stacks can be only shown as edge histograms for
individual branches. I never found this display particularly useful.
This implements an alternative mode that creates histograms over
complete branch traces, instead of individual branches, similar to how
normal callgraphs are handled. This is done by putting it in front of
the normal callgraph and then using the normal callgraph histogram
infrastructure to unify them.
This way in complex functions we can understand the control flow that
lead to a particular sample, and may even see some control flow in the
caller for short functions.
Example (simplified, of course for such simple code this is usually not
needed), please run this after the whole patchkit is in, as at this
point in the patch order there is no --branch-history, that will be
added in a patch after this one:
tcall.c:
volatile a = 10000, b = 100000, c;
__attribute__((noinline)) f2()
{
c = a / b;
}
__attribute__((noinline)) f1()
{
f2();
f2();
}
main()
{
int i;
for (i = 0; i < 1000000; i++)
f1();
}
% perf record -b -g ./tsrc/tcall
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.044 MB perf.data (~1923 samples) ]
% perf report --no-children --branch-history
...
54.91% tcall.c:6 [.] f2 tcall
|
|--65.53%-- f2 tcall.c:5
| |
| |--70.83%-- f1 tcall.c:11
| | f1 tcall.c:10
| | main tcall.c:18
| | main tcall.c:18
| | main tcall.c:17
| | main tcall.c:17
| | f1 tcall.c:13
| | f1 tcall.c:13
| | f2 tcall.c:7
| | f2 tcall.c:5
| | f1 tcall.c:12
| | f1 tcall.c:12
| | f2 tcall.c:7
| | f2 tcall.c:5
| | f1 tcall.c:11
| |
| --29.17%-- f1 tcall.c:12
| f1 tcall.c:12
| f2 tcall.c:7
| f2 tcall.c:5
| f1 tcall.c:11
| f1 tcall.c:10
| main tcall.c:18
| main tcall.c:18
| main tcall.c:17
| main tcall.c:17
| f1 tcall.c:13
| f1 tcall.c:13
| f2 tcall.c:7
| f2 tcall.c:5
| f1 tcall.c:12
The default output is unchanged.
This is only implemented in perf report, no change to record or anywhere
else.
This adds the basic code to report:
- add a new "branch" option to the -g option parser to enable this mode
- when the flag is set include the LBR into the callstack in machine.c.
The rest of the history code is unchanged and doesn't know the
difference between LBR entry and normal call entry.
- detect overlaps with the callchain
- remove small loop duplicates in the LBR
Current limitations:
- The LBR flags (mispredict etc.) are not shown in the history
and LBR entries have no special marker.
- It would be nice if annotate marked the LBR entries somehow
(e.g. with arrows)
v2: Various fixes.
v3: Merge further patches into this one. Fix white space.
v4: Improve manpage. Address review feedback.
v5: Rename functions. Better error message without -g. Fix crash without
-b.
v6: Rebase
v7: Rebase. Use NO_ENTRY in memset.
v8: Port to latest tip. Move add_callchain_ip to separate
patch. Skip initial entries in callchain. Minor cleanups.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: http://lkml.kernel.org/r/1415844328-4884-3-git-send-email-andi@firstfloor.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2014-11-13 09:05:20 +07:00
|
|
|
#define CHASHSZ 127
|
|
|
|
#define CHASHBITS 7
|
|
|
|
#define NO_ENTRY 0xff
|
|
|
|
|
|
|
|
#define PERF_MAX_BRANCH_DEPTH 127
|
|
|
|
|
|
|
|
/* Remove loops. */
|
|
|
|
static int remove_loops(struct branch_entry *l, int nr)
|
|
|
|
{
|
|
|
|
int i, j, off;
|
|
|
|
unsigned char chash[CHASHSZ];
|
|
|
|
|
|
|
|
memset(chash, NO_ENTRY, sizeof(chash));
|
|
|
|
|
|
|
|
BUG_ON(PERF_MAX_BRANCH_DEPTH > 255);
|
|
|
|
|
|
|
|
for (i = 0; i < nr; i++) {
|
|
|
|
int h = hash_64(l[i].from, CHASHBITS) % CHASHSZ;
|
|
|
|
|
|
|
|
/* no collision handling for now */
|
|
|
|
if (chash[h] == NO_ENTRY) {
|
|
|
|
chash[h] = i;
|
|
|
|
} else if (l[chash[h]].from == l[i].from) {
|
|
|
|
bool is_loop = true;
|
|
|
|
/* check if it is a real loop */
|
|
|
|
off = 0;
|
|
|
|
for (j = chash[h]; j < i && i + off < nr; j++, off++)
|
|
|
|
if (l[j].from != l[i + off].from) {
|
|
|
|
is_loop = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (is_loop) {
|
|
|
|
memmove(l + i, l + i + off,
|
|
|
|
(nr - (i + off)) * sizeof(*l));
|
|
|
|
nr -= off;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nr;
|
|
|
|
}
|
|
|
|
|
2015-01-06 01:23:05 +07:00
|
|
|
/*
|
|
|
|
* Recolve LBR callstack chain sample
|
|
|
|
* Return:
|
|
|
|
* 1 on success get LBR callchain information
|
|
|
|
* 0 no available LBR callchain information, should try fp
|
|
|
|
* negative error code on other errors.
|
|
|
|
*/
|
|
|
|
static int resolve_lbr_callchain_sample(struct thread *thread,
|
|
|
|
struct perf_sample *sample,
|
|
|
|
struct symbol **parent,
|
|
|
|
struct addr_location *root_al,
|
|
|
|
int max_stack)
|
2012-12-08 03:39:39 +07:00
|
|
|
{
|
2015-01-06 01:23:05 +07:00
|
|
|
struct ip_callchain *chain = sample->callchain;
|
|
|
|
int chain_nr = min(max_stack, (int)chain->nr);
|
2015-03-30 15:11:00 +07:00
|
|
|
u8 cpumode = PERF_RECORD_MISC_USER;
|
2015-01-06 01:23:05 +07:00
|
|
|
int i, j, err;
|
|
|
|
u64 ip;
|
|
|
|
|
|
|
|
for (i = 0; i < chain_nr; i++) {
|
|
|
|
if (chain->ips[i] == PERF_CONTEXT_USER)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* LBR only affects the user callchain */
|
|
|
|
if (i != chain_nr) {
|
|
|
|
struct branch_stack *lbr_stack = sample->branch_stack;
|
|
|
|
int lbr_nr = lbr_stack->nr;
|
|
|
|
/*
|
|
|
|
* LBR callstack can only get user call chain.
|
|
|
|
* The mix_chain_nr is kernel call chain
|
|
|
|
* number plus LBR user call chain number.
|
|
|
|
* i is kernel call chain number,
|
|
|
|
* 1 is PERF_CONTEXT_USER,
|
|
|
|
* lbr_nr + 1 is the user call chain number.
|
|
|
|
* For details, please refer to the comments
|
|
|
|
* in callchain__printf
|
|
|
|
*/
|
|
|
|
int mix_chain_nr = i + 1 + lbr_nr + 1;
|
|
|
|
|
|
|
|
if (mix_chain_nr > PERF_MAX_STACK_DEPTH + PERF_MAX_BRANCH_DEPTH) {
|
|
|
|
pr_warning("corrupted callchain. skipping...\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (j = 0; j < mix_chain_nr; j++) {
|
|
|
|
if (callchain_param.order == ORDER_CALLEE) {
|
|
|
|
if (j < i + 1)
|
|
|
|
ip = chain->ips[j];
|
|
|
|
else if (j > i + 1)
|
|
|
|
ip = lbr_stack->entries[j - i - 2].from;
|
|
|
|
else
|
|
|
|
ip = lbr_stack->entries[0].to;
|
|
|
|
} else {
|
|
|
|
if (j < lbr_nr)
|
|
|
|
ip = lbr_stack->entries[lbr_nr - j - 1].from;
|
|
|
|
else if (j > lbr_nr)
|
|
|
|
ip = chain->ips[i + 1 - (j - lbr_nr)];
|
|
|
|
else
|
|
|
|
ip = lbr_stack->entries[0].to;
|
|
|
|
}
|
|
|
|
|
2015-03-30 15:11:00 +07:00
|
|
|
err = add_callchain_ip(thread, parent, root_al, &cpumode, ip);
|
2015-01-06 01:23:05 +07:00
|
|
|
if (err)
|
|
|
|
return (err < 0) ? err : 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int thread__resolve_callchain_sample(struct thread *thread,
|
|
|
|
struct perf_evsel *evsel,
|
|
|
|
struct perf_sample *sample,
|
|
|
|
struct symbol **parent,
|
|
|
|
struct addr_location *root_al,
|
|
|
|
int max_stack)
|
|
|
|
{
|
|
|
|
struct branch_stack *branch = sample->branch_stack;
|
|
|
|
struct ip_callchain *chain = sample->callchain;
|
perf report: Add --max-stack option to limit callchain stack scan
When callgraph data was included in the perf data file, it may take a
long time to scan all those data and merge them together especially if
the stored callchains are long and the perf data file itself is large,
like a Gbyte or so.
The callchain stack is currently limited to PERF_MAX_STACK_DEPTH (127).
This is a large value. Usually the callgraph data that developers are
most interested in are the first few levels, the rests are usually not
looked at.
This patch adds a new --max-stack option to perf-report to limit the
depth of callchain stack data to look at to reduce the time it takes for
perf-report to finish its processing. It trades the presence of trailing
stack information with faster speed.
The following table shows the elapsed time of doing perf-report on a
perf.data file of size 985,531,828 bytes.
--max_stack Elapsed Time Output data size
----------- ------------ ----------------
not set 88.0s 124,422,651
64 87.5s 116,303,213
32 87.2s 112,023,804
16 86.6s 94,326,380
8 59.9s 33,697,248
4 40.7s 10,116,637
-g none 27.1s 2,555,810
Signed-off-by: Waiman Long <Waiman.Long@hp.com>
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Aswin Chandramouleeswaran <aswin@hp.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Scott J Norton <scott.norton@hp.com>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1382107129-2010-4-git-send-email-Waiman.Long@hp.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2013-10-18 21:38:48 +07:00
|
|
|
int chain_nr = min(max_stack, (int)chain->nr);
|
2015-03-30 15:11:00 +07:00
|
|
|
u8 cpumode = PERF_RECORD_MISC_USER;
|
2014-12-02 22:06:53 +07:00
|
|
|
int i, j, err;
|
perf callchain: Support handling complete branch stacks as histograms
Currently branch stacks can be only shown as edge histograms for
individual branches. I never found this display particularly useful.
This implements an alternative mode that creates histograms over
complete branch traces, instead of individual branches, similar to how
normal callgraphs are handled. This is done by putting it in front of
the normal callgraph and then using the normal callgraph histogram
infrastructure to unify them.
This way in complex functions we can understand the control flow that
lead to a particular sample, and may even see some control flow in the
caller for short functions.
Example (simplified, of course for such simple code this is usually not
needed), please run this after the whole patchkit is in, as at this
point in the patch order there is no --branch-history, that will be
added in a patch after this one:
tcall.c:
volatile a = 10000, b = 100000, c;
__attribute__((noinline)) f2()
{
c = a / b;
}
__attribute__((noinline)) f1()
{
f2();
f2();
}
main()
{
int i;
for (i = 0; i < 1000000; i++)
f1();
}
% perf record -b -g ./tsrc/tcall
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.044 MB perf.data (~1923 samples) ]
% perf report --no-children --branch-history
...
54.91% tcall.c:6 [.] f2 tcall
|
|--65.53%-- f2 tcall.c:5
| |
| |--70.83%-- f1 tcall.c:11
| | f1 tcall.c:10
| | main tcall.c:18
| | main tcall.c:18
| | main tcall.c:17
| | main tcall.c:17
| | f1 tcall.c:13
| | f1 tcall.c:13
| | f2 tcall.c:7
| | f2 tcall.c:5
| | f1 tcall.c:12
| | f1 tcall.c:12
| | f2 tcall.c:7
| | f2 tcall.c:5
| | f1 tcall.c:11
| |
| --29.17%-- f1 tcall.c:12
| f1 tcall.c:12
| f2 tcall.c:7
| f2 tcall.c:5
| f1 tcall.c:11
| f1 tcall.c:10
| main tcall.c:18
| main tcall.c:18
| main tcall.c:17
| main tcall.c:17
| f1 tcall.c:13
| f1 tcall.c:13
| f2 tcall.c:7
| f2 tcall.c:5
| f1 tcall.c:12
The default output is unchanged.
This is only implemented in perf report, no change to record or anywhere
else.
This adds the basic code to report:
- add a new "branch" option to the -g option parser to enable this mode
- when the flag is set include the LBR into the callstack in machine.c.
The rest of the history code is unchanged and doesn't know the
difference between LBR entry and normal call entry.
- detect overlaps with the callchain
- remove small loop duplicates in the LBR
Current limitations:
- The LBR flags (mispredict etc.) are not shown in the history
and LBR entries have no special marker.
- It would be nice if annotate marked the LBR entries somehow
(e.g. with arrows)
v2: Various fixes.
v3: Merge further patches into this one. Fix white space.
v4: Improve manpage. Address review feedback.
v5: Rename functions. Better error message without -g. Fix crash without
-b.
v6: Rebase
v7: Rebase. Use NO_ENTRY in memset.
v8: Port to latest tip. Move add_callchain_ip to separate
patch. Skip initial entries in callchain. Minor cleanups.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: http://lkml.kernel.org/r/1415844328-4884-3-git-send-email-andi@firstfloor.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2014-11-13 09:05:20 +07:00
|
|
|
int skip_idx = -1;
|
|
|
|
int first_call = 0;
|
|
|
|
|
2015-01-06 01:23:05 +07:00
|
|
|
callchain_cursor_reset(&callchain_cursor);
|
|
|
|
|
|
|
|
if (has_branch_callstack(evsel)) {
|
|
|
|
err = resolve_lbr_callchain_sample(thread, sample, parent,
|
|
|
|
root_al, max_stack);
|
|
|
|
if (err)
|
|
|
|
return (err < 0) ? err : 0;
|
|
|
|
}
|
|
|
|
|
perf callchain: Support handling complete branch stacks as histograms
Currently branch stacks can be only shown as edge histograms for
individual branches. I never found this display particularly useful.
This implements an alternative mode that creates histograms over
complete branch traces, instead of individual branches, similar to how
normal callgraphs are handled. This is done by putting it in front of
the normal callgraph and then using the normal callgraph histogram
infrastructure to unify them.
This way in complex functions we can understand the control flow that
lead to a particular sample, and may even see some control flow in the
caller for short functions.
Example (simplified, of course for such simple code this is usually not
needed), please run this after the whole patchkit is in, as at this
point in the patch order there is no --branch-history, that will be
added in a patch after this one:
tcall.c:
volatile a = 10000, b = 100000, c;
__attribute__((noinline)) f2()
{
c = a / b;
}
__attribute__((noinline)) f1()
{
f2();
f2();
}
main()
{
int i;
for (i = 0; i < 1000000; i++)
f1();
}
% perf record -b -g ./tsrc/tcall
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.044 MB perf.data (~1923 samples) ]
% perf report --no-children --branch-history
...
54.91% tcall.c:6 [.] f2 tcall
|
|--65.53%-- f2 tcall.c:5
| |
| |--70.83%-- f1 tcall.c:11
| | f1 tcall.c:10
| | main tcall.c:18
| | main tcall.c:18
| | main tcall.c:17
| | main tcall.c:17
| | f1 tcall.c:13
| | f1 tcall.c:13
| | f2 tcall.c:7
| | f2 tcall.c:5
| | f1 tcall.c:12
| | f1 tcall.c:12
| | f2 tcall.c:7
| | f2 tcall.c:5
| | f1 tcall.c:11
| |
| --29.17%-- f1 tcall.c:12
| f1 tcall.c:12
| f2 tcall.c:7
| f2 tcall.c:5
| f1 tcall.c:11
| f1 tcall.c:10
| main tcall.c:18
| main tcall.c:18
| main tcall.c:17
| main tcall.c:17
| f1 tcall.c:13
| f1 tcall.c:13
| f2 tcall.c:7
| f2 tcall.c:5
| f1 tcall.c:12
The default output is unchanged.
This is only implemented in perf report, no change to record or anywhere
else.
This adds the basic code to report:
- add a new "branch" option to the -g option parser to enable this mode
- when the flag is set include the LBR into the callstack in machine.c.
The rest of the history code is unchanged and doesn't know the
difference between LBR entry and normal call entry.
- detect overlaps with the callchain
- remove small loop duplicates in the LBR
Current limitations:
- The LBR flags (mispredict etc.) are not shown in the history
and LBR entries have no special marker.
- It would be nice if annotate marked the LBR entries somehow
(e.g. with arrows)
v2: Various fixes.
v3: Merge further patches into this one. Fix white space.
v4: Improve manpage. Address review feedback.
v5: Rename functions. Better error message without -g. Fix crash without
-b.
v6: Rebase
v7: Rebase. Use NO_ENTRY in memset.
v8: Port to latest tip. Move add_callchain_ip to separate
patch. Skip initial entries in callchain. Minor cleanups.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: http://lkml.kernel.org/r/1415844328-4884-3-git-send-email-andi@firstfloor.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2014-11-13 09:05:20 +07:00
|
|
|
/*
|
|
|
|
* Based on DWARF debug information, some architectures skip
|
|
|
|
* a callchain entry saved by the kernel.
|
|
|
|
*/
|
|
|
|
if (chain->nr < PERF_MAX_STACK_DEPTH)
|
|
|
|
skip_idx = arch_skip_callchain_idx(thread, chain);
|
2012-12-08 03:39:39 +07:00
|
|
|
|
perf callchain: Support handling complete branch stacks as histograms
Currently branch stacks can be only shown as edge histograms for
individual branches. I never found this display particularly useful.
This implements an alternative mode that creates histograms over
complete branch traces, instead of individual branches, similar to how
normal callgraphs are handled. This is done by putting it in front of
the normal callgraph and then using the normal callgraph histogram
infrastructure to unify them.
This way in complex functions we can understand the control flow that
lead to a particular sample, and may even see some control flow in the
caller for short functions.
Example (simplified, of course for such simple code this is usually not
needed), please run this after the whole patchkit is in, as at this
point in the patch order there is no --branch-history, that will be
added in a patch after this one:
tcall.c:
volatile a = 10000, b = 100000, c;
__attribute__((noinline)) f2()
{
c = a / b;
}
__attribute__((noinline)) f1()
{
f2();
f2();
}
main()
{
int i;
for (i = 0; i < 1000000; i++)
f1();
}
% perf record -b -g ./tsrc/tcall
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.044 MB perf.data (~1923 samples) ]
% perf report --no-children --branch-history
...
54.91% tcall.c:6 [.] f2 tcall
|
|--65.53%-- f2 tcall.c:5
| |
| |--70.83%-- f1 tcall.c:11
| | f1 tcall.c:10
| | main tcall.c:18
| | main tcall.c:18
| | main tcall.c:17
| | main tcall.c:17
| | f1 tcall.c:13
| | f1 tcall.c:13
| | f2 tcall.c:7
| | f2 tcall.c:5
| | f1 tcall.c:12
| | f1 tcall.c:12
| | f2 tcall.c:7
| | f2 tcall.c:5
| | f1 tcall.c:11
| |
| --29.17%-- f1 tcall.c:12
| f1 tcall.c:12
| f2 tcall.c:7
| f2 tcall.c:5
| f1 tcall.c:11
| f1 tcall.c:10
| main tcall.c:18
| main tcall.c:18
| main tcall.c:17
| main tcall.c:17
| f1 tcall.c:13
| f1 tcall.c:13
| f2 tcall.c:7
| f2 tcall.c:5
| f1 tcall.c:12
The default output is unchanged.
This is only implemented in perf report, no change to record or anywhere
else.
This adds the basic code to report:
- add a new "branch" option to the -g option parser to enable this mode
- when the flag is set include the LBR into the callstack in machine.c.
The rest of the history code is unchanged and doesn't know the
difference between LBR entry and normal call entry.
- detect overlaps with the callchain
- remove small loop duplicates in the LBR
Current limitations:
- The LBR flags (mispredict etc.) are not shown in the history
and LBR entries have no special marker.
- It would be nice if annotate marked the LBR entries somehow
(e.g. with arrows)
v2: Various fixes.
v3: Merge further patches into this one. Fix white space.
v4: Improve manpage. Address review feedback.
v5: Rename functions. Better error message without -g. Fix crash without
-b.
v6: Rebase
v7: Rebase. Use NO_ENTRY in memset.
v8: Port to latest tip. Move add_callchain_ip to separate
patch. Skip initial entries in callchain. Minor cleanups.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: http://lkml.kernel.org/r/1415844328-4884-3-git-send-email-andi@firstfloor.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2014-11-13 09:05:20 +07:00
|
|
|
/*
|
|
|
|
* Add branches to call stack for easier browsing. This gives
|
|
|
|
* more context for a sample than just the callers.
|
|
|
|
*
|
|
|
|
* This uses individual histograms of paths compared to the
|
|
|
|
* aggregated histograms the normal LBR mode uses.
|
|
|
|
*
|
|
|
|
* Limitations for now:
|
|
|
|
* - No extra filters
|
|
|
|
* - No annotations (should annotate somehow)
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (branch && callchain_param.branch_callstack) {
|
|
|
|
int nr = min(max_stack, (int)branch->nr);
|
|
|
|
struct branch_entry be[nr];
|
|
|
|
|
|
|
|
if (branch->nr > PERF_MAX_BRANCH_DEPTH) {
|
|
|
|
pr_warning("corrupted branch chain. skipping...\n");
|
|
|
|
goto check_calls;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < nr; i++) {
|
|
|
|
if (callchain_param.order == ORDER_CALLEE) {
|
|
|
|
be[i] = branch->entries[i];
|
|
|
|
/*
|
|
|
|
* Check for overlap into the callchain.
|
|
|
|
* The return address is one off compared to
|
|
|
|
* the branch entry. To adjust for this
|
|
|
|
* assume the calling instruction is not longer
|
|
|
|
* than 8 bytes.
|
|
|
|
*/
|
|
|
|
if (i == skip_idx ||
|
|
|
|
chain->ips[first_call] >= PERF_CONTEXT_MAX)
|
|
|
|
first_call++;
|
|
|
|
else if (be[i].from < chain->ips[first_call] &&
|
|
|
|
be[i].from >= chain->ips[first_call] - 8)
|
|
|
|
first_call++;
|
|
|
|
} else
|
|
|
|
be[i] = branch->entries[branch->nr - i - 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
nr = remove_loops(be, nr);
|
|
|
|
|
|
|
|
for (i = 0; i < nr; i++) {
|
|
|
|
err = add_callchain_ip(thread, parent, root_al,
|
2015-03-30 15:11:00 +07:00
|
|
|
NULL, be[i].to);
|
perf callchain: Support handling complete branch stacks as histograms
Currently branch stacks can be only shown as edge histograms for
individual branches. I never found this display particularly useful.
This implements an alternative mode that creates histograms over
complete branch traces, instead of individual branches, similar to how
normal callgraphs are handled. This is done by putting it in front of
the normal callgraph and then using the normal callgraph histogram
infrastructure to unify them.
This way in complex functions we can understand the control flow that
lead to a particular sample, and may even see some control flow in the
caller for short functions.
Example (simplified, of course for such simple code this is usually not
needed), please run this after the whole patchkit is in, as at this
point in the patch order there is no --branch-history, that will be
added in a patch after this one:
tcall.c:
volatile a = 10000, b = 100000, c;
__attribute__((noinline)) f2()
{
c = a / b;
}
__attribute__((noinline)) f1()
{
f2();
f2();
}
main()
{
int i;
for (i = 0; i < 1000000; i++)
f1();
}
% perf record -b -g ./tsrc/tcall
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.044 MB perf.data (~1923 samples) ]
% perf report --no-children --branch-history
...
54.91% tcall.c:6 [.] f2 tcall
|
|--65.53%-- f2 tcall.c:5
| |
| |--70.83%-- f1 tcall.c:11
| | f1 tcall.c:10
| | main tcall.c:18
| | main tcall.c:18
| | main tcall.c:17
| | main tcall.c:17
| | f1 tcall.c:13
| | f1 tcall.c:13
| | f2 tcall.c:7
| | f2 tcall.c:5
| | f1 tcall.c:12
| | f1 tcall.c:12
| | f2 tcall.c:7
| | f2 tcall.c:5
| | f1 tcall.c:11
| |
| --29.17%-- f1 tcall.c:12
| f1 tcall.c:12
| f2 tcall.c:7
| f2 tcall.c:5
| f1 tcall.c:11
| f1 tcall.c:10
| main tcall.c:18
| main tcall.c:18
| main tcall.c:17
| main tcall.c:17
| f1 tcall.c:13
| f1 tcall.c:13
| f2 tcall.c:7
| f2 tcall.c:5
| f1 tcall.c:12
The default output is unchanged.
This is only implemented in perf report, no change to record or anywhere
else.
This adds the basic code to report:
- add a new "branch" option to the -g option parser to enable this mode
- when the flag is set include the LBR into the callstack in machine.c.
The rest of the history code is unchanged and doesn't know the
difference between LBR entry and normal call entry.
- detect overlaps with the callchain
- remove small loop duplicates in the LBR
Current limitations:
- The LBR flags (mispredict etc.) are not shown in the history
and LBR entries have no special marker.
- It would be nice if annotate marked the LBR entries somehow
(e.g. with arrows)
v2: Various fixes.
v3: Merge further patches into this one. Fix white space.
v4: Improve manpage. Address review feedback.
v5: Rename functions. Better error message without -g. Fix crash without
-b.
v6: Rebase
v7: Rebase. Use NO_ENTRY in memset.
v8: Port to latest tip. Move add_callchain_ip to separate
patch. Skip initial entries in callchain. Minor cleanups.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: http://lkml.kernel.org/r/1415844328-4884-3-git-send-email-andi@firstfloor.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2014-11-13 09:05:20 +07:00
|
|
|
if (!err)
|
|
|
|
err = add_callchain_ip(thread, parent, root_al,
|
2015-03-30 15:11:00 +07:00
|
|
|
NULL, be[i].from);
|
perf callchain: Support handling complete branch stacks as histograms
Currently branch stacks can be only shown as edge histograms for
individual branches. I never found this display particularly useful.
This implements an alternative mode that creates histograms over
complete branch traces, instead of individual branches, similar to how
normal callgraphs are handled. This is done by putting it in front of
the normal callgraph and then using the normal callgraph histogram
infrastructure to unify them.
This way in complex functions we can understand the control flow that
lead to a particular sample, and may even see some control flow in the
caller for short functions.
Example (simplified, of course for such simple code this is usually not
needed), please run this after the whole patchkit is in, as at this
point in the patch order there is no --branch-history, that will be
added in a patch after this one:
tcall.c:
volatile a = 10000, b = 100000, c;
__attribute__((noinline)) f2()
{
c = a / b;
}
__attribute__((noinline)) f1()
{
f2();
f2();
}
main()
{
int i;
for (i = 0; i < 1000000; i++)
f1();
}
% perf record -b -g ./tsrc/tcall
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.044 MB perf.data (~1923 samples) ]
% perf report --no-children --branch-history
...
54.91% tcall.c:6 [.] f2 tcall
|
|--65.53%-- f2 tcall.c:5
| |
| |--70.83%-- f1 tcall.c:11
| | f1 tcall.c:10
| | main tcall.c:18
| | main tcall.c:18
| | main tcall.c:17
| | main tcall.c:17
| | f1 tcall.c:13
| | f1 tcall.c:13
| | f2 tcall.c:7
| | f2 tcall.c:5
| | f1 tcall.c:12
| | f1 tcall.c:12
| | f2 tcall.c:7
| | f2 tcall.c:5
| | f1 tcall.c:11
| |
| --29.17%-- f1 tcall.c:12
| f1 tcall.c:12
| f2 tcall.c:7
| f2 tcall.c:5
| f1 tcall.c:11
| f1 tcall.c:10
| main tcall.c:18
| main tcall.c:18
| main tcall.c:17
| main tcall.c:17
| f1 tcall.c:13
| f1 tcall.c:13
| f2 tcall.c:7
| f2 tcall.c:5
| f1 tcall.c:12
The default output is unchanged.
This is only implemented in perf report, no change to record or anywhere
else.
This adds the basic code to report:
- add a new "branch" option to the -g option parser to enable this mode
- when the flag is set include the LBR into the callstack in machine.c.
The rest of the history code is unchanged and doesn't know the
difference between LBR entry and normal call entry.
- detect overlaps with the callchain
- remove small loop duplicates in the LBR
Current limitations:
- The LBR flags (mispredict etc.) are not shown in the history
and LBR entries have no special marker.
- It would be nice if annotate marked the LBR entries somehow
(e.g. with arrows)
v2: Various fixes.
v3: Merge further patches into this one. Fix white space.
v4: Improve manpage. Address review feedback.
v5: Rename functions. Better error message without -g. Fix crash without
-b.
v6: Rebase
v7: Rebase. Use NO_ENTRY in memset.
v8: Port to latest tip. Move add_callchain_ip to separate
patch. Skip initial entries in callchain. Minor cleanups.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: http://lkml.kernel.org/r/1415844328-4884-3-git-send-email-andi@firstfloor.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2014-11-13 09:05:20 +07:00
|
|
|
if (err == -EINVAL)
|
|
|
|
break;
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
chain_nr -= nr;
|
|
|
|
}
|
|
|
|
|
|
|
|
check_calls:
|
2015-09-25 20:15:48 +07:00
|
|
|
if (chain->nr > PERF_MAX_STACK_DEPTH && (int)chain->nr > max_stack) {
|
2012-12-08 03:39:39 +07:00
|
|
|
pr_warning("corrupted callchain. skipping...\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
perf callchain: Support handling complete branch stacks as histograms
Currently branch stacks can be only shown as edge histograms for
individual branches. I never found this display particularly useful.
This implements an alternative mode that creates histograms over
complete branch traces, instead of individual branches, similar to how
normal callgraphs are handled. This is done by putting it in front of
the normal callgraph and then using the normal callgraph histogram
infrastructure to unify them.
This way in complex functions we can understand the control flow that
lead to a particular sample, and may even see some control flow in the
caller for short functions.
Example (simplified, of course for such simple code this is usually not
needed), please run this after the whole patchkit is in, as at this
point in the patch order there is no --branch-history, that will be
added in a patch after this one:
tcall.c:
volatile a = 10000, b = 100000, c;
__attribute__((noinline)) f2()
{
c = a / b;
}
__attribute__((noinline)) f1()
{
f2();
f2();
}
main()
{
int i;
for (i = 0; i < 1000000; i++)
f1();
}
% perf record -b -g ./tsrc/tcall
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.044 MB perf.data (~1923 samples) ]
% perf report --no-children --branch-history
...
54.91% tcall.c:6 [.] f2 tcall
|
|--65.53%-- f2 tcall.c:5
| |
| |--70.83%-- f1 tcall.c:11
| | f1 tcall.c:10
| | main tcall.c:18
| | main tcall.c:18
| | main tcall.c:17
| | main tcall.c:17
| | f1 tcall.c:13
| | f1 tcall.c:13
| | f2 tcall.c:7
| | f2 tcall.c:5
| | f1 tcall.c:12
| | f1 tcall.c:12
| | f2 tcall.c:7
| | f2 tcall.c:5
| | f1 tcall.c:11
| |
| --29.17%-- f1 tcall.c:12
| f1 tcall.c:12
| f2 tcall.c:7
| f2 tcall.c:5
| f1 tcall.c:11
| f1 tcall.c:10
| main tcall.c:18
| main tcall.c:18
| main tcall.c:17
| main tcall.c:17
| f1 tcall.c:13
| f1 tcall.c:13
| f2 tcall.c:7
| f2 tcall.c:5
| f1 tcall.c:12
The default output is unchanged.
This is only implemented in perf report, no change to record or anywhere
else.
This adds the basic code to report:
- add a new "branch" option to the -g option parser to enable this mode
- when the flag is set include the LBR into the callstack in machine.c.
The rest of the history code is unchanged and doesn't know the
difference between LBR entry and normal call entry.
- detect overlaps with the callchain
- remove small loop duplicates in the LBR
Current limitations:
- The LBR flags (mispredict etc.) are not shown in the history
and LBR entries have no special marker.
- It would be nice if annotate marked the LBR entries somehow
(e.g. with arrows)
v2: Various fixes.
v3: Merge further patches into this one. Fix white space.
v4: Improve manpage. Address review feedback.
v5: Rename functions. Better error message without -g. Fix crash without
-b.
v6: Rebase
v7: Rebase. Use NO_ENTRY in memset.
v8: Port to latest tip. Move add_callchain_ip to separate
patch. Skip initial entries in callchain. Minor cleanups.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: http://lkml.kernel.org/r/1415844328-4884-3-git-send-email-andi@firstfloor.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2014-11-13 09:05:20 +07:00
|
|
|
for (i = first_call; i < chain_nr; i++) {
|
2012-12-08 03:39:39 +07:00
|
|
|
u64 ip;
|
|
|
|
|
|
|
|
if (callchain_param.order == ORDER_CALLEE)
|
2014-06-25 22:49:03 +07:00
|
|
|
j = i;
|
2012-12-08 03:39:39 +07:00
|
|
|
else
|
2014-06-25 22:49:03 +07:00
|
|
|
j = chain->nr - i - 1;
|
|
|
|
|
|
|
|
#ifdef HAVE_SKIP_CALLCHAIN_IDX
|
|
|
|
if (j == skip_idx)
|
|
|
|
continue;
|
|
|
|
#endif
|
|
|
|
ip = chain->ips[j];
|
2012-12-08 03:39:39 +07:00
|
|
|
|
2015-03-30 15:11:00 +07:00
|
|
|
err = add_callchain_ip(thread, parent, root_al, &cpumode, ip);
|
2012-12-08 03:39:39 +07:00
|
|
|
|
|
|
|
if (err)
|
2014-12-02 22:06:53 +07:00
|
|
|
return (err < 0) ? err : 0;
|
2012-12-08 03:39:39 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int unwind_entry(struct unwind_entry *entry, void *arg)
|
|
|
|
{
|
|
|
|
struct callchain_cursor *cursor = arg;
|
2015-11-26 14:08:20 +07:00
|
|
|
|
|
|
|
if (symbol_conf.hide_unresolved && entry->sym == NULL)
|
|
|
|
return 0;
|
2012-12-08 03:39:39 +07:00
|
|
|
return callchain_cursor_append(cursor, entry->ip,
|
|
|
|
entry->map, entry->sym);
|
|
|
|
}
|
|
|
|
|
2014-10-24 01:26:17 +07:00
|
|
|
int thread__resolve_callchain(struct thread *thread,
|
|
|
|
struct perf_evsel *evsel,
|
|
|
|
struct perf_sample *sample,
|
|
|
|
struct symbol **parent,
|
|
|
|
struct addr_location *root_al,
|
|
|
|
int max_stack)
|
2012-12-08 03:39:39 +07:00
|
|
|
{
|
2015-01-06 01:23:05 +07:00
|
|
|
int ret = thread__resolve_callchain_sample(thread, evsel,
|
|
|
|
sample, parent,
|
|
|
|
root_al, max_stack);
|
2012-12-08 03:39:39 +07:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
/* Can we do dwarf post unwind? */
|
|
|
|
if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) &&
|
|
|
|
(evsel->attr.sample_type & PERF_SAMPLE_STACK_USER)))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Bail out if nothing was captured. */
|
|
|
|
if ((!sample->user_regs.regs) ||
|
|
|
|
(!sample->user_stack.size))
|
|
|
|
return 0;
|
|
|
|
|
2014-10-24 02:42:19 +07:00
|
|
|
return unwind__get_entries(unwind_entry, &callchain_cursor,
|
2014-01-07 19:47:25 +07:00
|
|
|
thread, sample, max_stack);
|
2012-12-08 03:39:39 +07:00
|
|
|
|
|
|
|
}
|
2013-09-29 02:12:58 +07:00
|
|
|
|
|
|
|
int machine__for_each_thread(struct machine *machine,
|
|
|
|
int (*fn)(struct thread *thread, void *p),
|
|
|
|
void *priv)
|
|
|
|
{
|
|
|
|
struct rb_node *nd;
|
|
|
|
struct thread *thread;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) {
|
|
|
|
thread = rb_entry(nd, struct thread, rb_node);
|
|
|
|
rc = fn(thread, priv);
|
|
|
|
if (rc != 0)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
list_for_each_entry(thread, &machine->dead_threads, node) {
|
|
|
|
rc = fn(thread, priv);
|
|
|
|
if (rc != 0)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
2013-11-11 21:28:02 +07:00
|
|
|
|
2015-05-29 20:33:30 +07:00
|
|
|
int machines__for_each_thread(struct machines *machines,
|
|
|
|
int (*fn)(struct thread *thread, void *p),
|
|
|
|
void *priv)
|
|
|
|
{
|
|
|
|
struct rb_node *nd;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
rc = machine__for_each_thread(&machines->host, fn, priv);
|
|
|
|
if (rc != 0)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
|
|
|
|
struct machine *machine = rb_entry(nd, struct machine, rb_node);
|
|
|
|
|
|
|
|
rc = machine__for_each_thread(machine, fn, priv);
|
|
|
|
if (rc != 0)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2013-11-11 21:36:12 +07:00
|
|
|
int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool,
|
2013-11-13 02:46:16 +07:00
|
|
|
struct target *target, struct thread_map *threads,
|
2015-06-17 20:51:11 +07:00
|
|
|
perf_event__handler_t process, bool data_mmap,
|
|
|
|
unsigned int proc_map_timeout)
|
2013-11-11 21:28:02 +07:00
|
|
|
{
|
2013-11-13 02:46:16 +07:00
|
|
|
if (target__has_task(target))
|
2015-06-17 20:51:11 +07:00
|
|
|
return perf_event__synthesize_thread_map(tool, threads, process, machine, data_mmap, proc_map_timeout);
|
2013-11-13 02:46:16 +07:00
|
|
|
else if (target__has_cpu(target))
|
2015-06-17 20:51:11 +07:00
|
|
|
return perf_event__synthesize_threads(tool, process, machine, data_mmap, proc_map_timeout);
|
2013-11-11 21:28:02 +07:00
|
|
|
/* command specified */
|
|
|
|
return 0;
|
|
|
|
}
|
2014-07-22 20:17:25 +07:00
|
|
|
|
|
|
|
pid_t machine__get_current_tid(struct machine *machine, int cpu)
|
|
|
|
{
|
|
|
|
if (cpu < 0 || cpu >= MAX_NR_CPUS || !machine->current_tid)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return machine->current_tid[cpu];
|
|
|
|
}
|
|
|
|
|
|
|
|
int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,
|
|
|
|
pid_t tid)
|
|
|
|
{
|
|
|
|
struct thread *thread;
|
|
|
|
|
|
|
|
if (cpu < 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (!machine->current_tid) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
machine->current_tid = calloc(MAX_NR_CPUS, sizeof(pid_t));
|
|
|
|
if (!machine->current_tid)
|
|
|
|
return -ENOMEM;
|
|
|
|
for (i = 0; i < MAX_NR_CPUS; i++)
|
|
|
|
machine->current_tid[i] = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cpu >= MAX_NR_CPUS) {
|
|
|
|
pr_err("Requested CPU %d too large. ", cpu);
|
|
|
|
pr_err("Consider raising MAX_NR_CPUS\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
machine->current_tid[cpu] = tid;
|
|
|
|
|
|
|
|
thread = machine__findnew_thread(machine, pid, tid);
|
|
|
|
if (!thread)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
thread->cpu = cpu;
|
perf machine: Protect the machine->threads with a rwlock
In addition to using refcounts for the struct thread lifetime
management, we need to protect access to machine->threads from
concurrent access.
That happens in 'perf top', where a thread processes events, inserting
and deleting entries from that rb_tree while another thread decays
hist_entries, that end up dropping references and ultimately deleting
threads from the rb_tree and releasing its resources when no further
hist_entry (or other data structures, like in 'perf sched') references
it.
So the rule is the same for refcounts + protected trees in the kernel,
get the tree lock, find object, bump the refcount, drop the tree lock,
return, use object, drop the refcount if no more use of it is needed,
keep it if storing it in some other data structure, drop when releasing
that data structure.
I.e. pair "t = machine__find(new)_thread()" with a "thread__put(t)", and
"perf_event__preprocess_sample(&al)" with "addr_location__put(&al)".
The addr_location__put() one is because as we return references to
several data structures, we may end up adding more reference counting
for the other data structures and then we'll drop it at
addr_location__put() time.
Acked-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-bs9rt4n0jw3hi9f3zxyy3xln@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-07 06:43:22 +07:00
|
|
|
thread__put(thread);
|
2014-07-22 20:17:25 +07:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2014-08-16 02:08:39 +07:00
|
|
|
|
|
|
|
int machine__get_kernel_start(struct machine *machine)
|
|
|
|
{
|
2015-09-30 21:54:04 +07:00
|
|
|
struct map *map = machine__kernel_map(machine);
|
2014-08-16 02:08:39 +07:00
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The only addresses above 2^63 are kernel addresses of a 64-bit
|
|
|
|
* kernel. Note that addresses are unsigned so that on a 32-bit system
|
|
|
|
* all addresses including kernel addresses are less than 2^32. In
|
|
|
|
* that case (32-bit system), if the kernel mapping is unknown, all
|
|
|
|
* addresses will be assumed to be in user space - see
|
|
|
|
* machine__kernel_ip().
|
|
|
|
*/
|
|
|
|
machine->kernel_start = 1ULL << 63;
|
|
|
|
if (map) {
|
|
|
|
err = map__load(map, machine->symbol_filter);
|
|
|
|
if (map->start)
|
|
|
|
machine->kernel_start = map->start;
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
2015-05-29 21:31:12 +07:00
|
|
|
|
|
|
|
struct dso *machine__findnew_dso(struct machine *machine, const char *filename)
|
|
|
|
{
|
2015-06-02 01:40:01 +07:00
|
|
|
return dsos__findnew(&machine->dsos, filename);
|
2015-05-29 21:31:12 +07:00
|
|
|
}
|
2015-07-23 02:14:29 +07:00
|
|
|
|
|
|
|
char *machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
|
|
|
|
{
|
|
|
|
struct machine *machine = vmachine;
|
|
|
|
struct map *map;
|
|
|
|
struct symbol *sym = map_groups__find_symbol(&machine->kmaps, MAP__FUNCTION, *addrp, &map, NULL);
|
|
|
|
|
|
|
|
if (sym == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
*modp = __map__is_kmodule(map) ? (char *)map->dso->short_name : NULL;
|
|
|
|
*addrp = map->unmap_ip(map, sym->start);
|
|
|
|
return sym->name;
|
|
|
|
}
|