2009-08-14 18:21:53 +08:00
|
|
|
#include "../perf.h"
|
2017-04-18 21:46:11 +08:00
|
|
|
#include <errno.h>
|
2009-08-14 18:21:53 +08:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2017-04-17 22:39:06 +08:00
|
|
|
#include <linux/kernel.h>
|
2009-12-14 05:50:28 +08:00
|
|
|
#include "session.h"
|
2009-08-14 18:21:53 +08:00
|
|
|
#include "thread.h"
|
2014-10-30 22:09:42 +08:00
|
|
|
#include "thread-stack.h"
|
2009-08-14 18:21:53 +08:00
|
|
|
#include "util.h"
|
2009-08-18 23:04:03 +08:00
|
|
|
#include "debug.h"
|
perf tools: Add PERF_RECORD_NAMESPACES to include namespaces related info
Introduce a new option to record PERF_RECORD_NAMESPACES events emitted
by the kernel when fork, clone, setns or unshare are invoked. And update
perf-record documentation with the new option to record namespace
events.
Committer notes:
Combined it with a later patch to allow printing it via 'perf report -D'
and be able to test the feature introduced in this patch. Had to move
here also perf_ns__name(), that was introduced in another later patch.
Also used PRIu64 and PRIx64 to fix the build in some enfironments wrt:
util/event.c:1129:39: error: format '%lx' expects argument of type 'long unsigned int', but argument 6 has type 'long long unsigned int' [-Werror=format=]
ret += fprintf(fp, "%u/%s: %lu/0x%lx%s", idx
^
Testing it:
# perf record --namespaces -a
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 1.083 MB perf.data (423 samples) ]
#
# perf report -D
<SNIP>
3 2028902078892 0x115140 [0xa0]: PERF_RECORD_NAMESPACES 14783/14783 - nr_namespaces: 7
[0/net: 3/0xf0000081, 1/uts: 3/0xeffffffe, 2/ipc: 3/0xefffffff, 3/pid: 3/0xeffffffc,
4/user: 3/0xeffffffd, 5/mnt: 3/0xf0000000, 6/cgroup: 3/0xeffffffb]
0x1151e0 [0x30]: event: 9
.
. ... raw event: size 48 bytes
. 0000: 09 00 00 00 02 00 30 00 c4 71 82 68 0c 7f 00 00 ......0..q.h....
. 0010: a9 39 00 00 a9 39 00 00 94 28 fe 63 d8 01 00 00 .9...9...(.c....
. 0020: 03 00 00 00 00 00 00 00 ce c4 02 00 00 00 00 00 ................
<SNIP>
NAMESPACES events: 1
<SNIP>
#
Signed-off-by: Hari Bathini <hbathini@linux.vnet.ibm.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com>
Cc: Aravinda Prasad <aravinda@linux.vnet.ibm.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Sargun Dhillon <sargun@sargun.me>
Cc: Steven Rostedt <rostedt@goodmis.org>
Link: http://lkml.kernel.org/r/148891930386.25309.18412039920746995488.stgit@hbathini.in.ibm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2017-03-08 04:41:43 +08:00
|
|
|
#include "namespaces.h"
|
2013-09-11 22:56:44 +08:00
|
|
|
#include "comm.h"
|
2014-10-06 08:46:00 +08:00
|
|
|
#include "unwind.h"
|
2009-08-14 18:21:53 +08:00
|
|
|
|
2016-04-26 23:32:50 +08:00
|
|
|
#include <api/fs/fs.h>
|
|
|
|
|
2014-04-10 02:54:29 +08:00
|
|
|
int thread__init_map_groups(struct thread *thread, struct machine *machine)
|
|
|
|
{
|
|
|
|
pid_t pid = thread->pid_;
|
|
|
|
|
2014-07-14 18:02:25 +08:00
|
|
|
if (pid == thread->tid || pid == -1) {
|
2014-10-22 04:29:02 +08:00
|
|
|
thread->mg = map_groups__new(machine);
|
2014-04-10 02:54:29 +08:00
|
|
|
} else {
|
2016-10-03 22:07:24 +08:00
|
|
|
struct thread *leader = __machine__findnew_thread(machine, pid, pid);
|
2015-12-12 06:11:23 +08:00
|
|
|
if (leader) {
|
2014-04-10 02:54:29 +08:00
|
|
|
thread->mg = map_groups__get(leader->mg);
|
2015-12-12 06:11:23 +08:00
|
|
|
thread__put(leader);
|
|
|
|
}
|
2014-04-10 02:54:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return thread->mg ? 0 : -1;
|
|
|
|
}
|
|
|
|
|
2013-08-26 21:00:19 +08:00
|
|
|
struct thread *thread__new(pid_t pid, pid_t tid)
|
2009-08-14 18:21:53 +08:00
|
|
|
{
|
2013-09-11 22:56:44 +08:00
|
|
|
char *comm_str;
|
|
|
|
struct comm *comm;
|
2013-10-23 06:01:31 +08:00
|
|
|
struct thread *thread = zalloc(sizeof(*thread));
|
2009-08-14 18:21:53 +08:00
|
|
|
|
2013-10-23 06:01:31 +08:00
|
|
|
if (thread != NULL) {
|
|
|
|
thread->pid_ = pid;
|
|
|
|
thread->tid = tid;
|
|
|
|
thread->ppid = -1;
|
2014-07-22 21:17:24 +08:00
|
|
|
thread->cpu = -1;
|
perf tools: Add PERF_RECORD_NAMESPACES to include namespaces related info
Introduce a new option to record PERF_RECORD_NAMESPACES events emitted
by the kernel when fork, clone, setns or unshare are invoked. And update
perf-record documentation with the new option to record namespace
events.
Committer notes:
Combined it with a later patch to allow printing it via 'perf report -D'
and be able to test the feature introduced in this patch. Had to move
here also perf_ns__name(), that was introduced in another later patch.
Also used PRIu64 and PRIx64 to fix the build in some enfironments wrt:
util/event.c:1129:39: error: format '%lx' expects argument of type 'long unsigned int', but argument 6 has type 'long long unsigned int' [-Werror=format=]
ret += fprintf(fp, "%u/%s: %lu/0x%lx%s", idx
^
Testing it:
# perf record --namespaces -a
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 1.083 MB perf.data (423 samples) ]
#
# perf report -D
<SNIP>
3 2028902078892 0x115140 [0xa0]: PERF_RECORD_NAMESPACES 14783/14783 - nr_namespaces: 7
[0/net: 3/0xf0000081, 1/uts: 3/0xeffffffe, 2/ipc: 3/0xefffffff, 3/pid: 3/0xeffffffc,
4/user: 3/0xeffffffd, 5/mnt: 3/0xf0000000, 6/cgroup: 3/0xeffffffb]
0x1151e0 [0x30]: event: 9
.
. ... raw event: size 48 bytes
. 0000: 09 00 00 00 02 00 30 00 c4 71 82 68 0c 7f 00 00 ......0..q.h....
. 0010: a9 39 00 00 a9 39 00 00 94 28 fe 63 d8 01 00 00 .9...9...(.c....
. 0020: 03 00 00 00 00 00 00 00 ce c4 02 00 00 00 00 00 ................
<SNIP>
NAMESPACES events: 1
<SNIP>
#
Signed-off-by: Hari Bathini <hbathini@linux.vnet.ibm.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com>
Cc: Aravinda Prasad <aravinda@linux.vnet.ibm.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Sargun Dhillon <sargun@sargun.me>
Cc: Steven Rostedt <rostedt@goodmis.org>
Link: http://lkml.kernel.org/r/148891930386.25309.18412039920746995488.stgit@hbathini.in.ibm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2017-03-08 04:41:43 +08:00
|
|
|
INIT_LIST_HEAD(&thread->namespaces_list);
|
2013-09-11 22:56:44 +08:00
|
|
|
INIT_LIST_HEAD(&thread->comm_list);
|
|
|
|
|
|
|
|
comm_str = malloc(32);
|
|
|
|
if (!comm_str)
|
|
|
|
goto err_thread;
|
|
|
|
|
|
|
|
snprintf(comm_str, 32, ":%d", tid);
|
2014-07-31 14:00:44 +08:00
|
|
|
comm = comm__new(comm_str, 0, false);
|
2013-09-11 22:56:44 +08:00
|
|
|
free(comm_str);
|
|
|
|
if (!comm)
|
|
|
|
goto err_thread;
|
|
|
|
|
|
|
|
list_add(&comm->list, &thread->comm_list);
|
2017-02-21 23:35:02 +08:00
|
|
|
refcount_set(&thread->refcnt, 1);
|
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 07:43:22 +08:00
|
|
|
RB_CLEAR_NODE(&thread->rb_node);
|
2009-08-14 18:21:53 +08:00
|
|
|
}
|
|
|
|
|
2013-10-23 06:01:31 +08:00
|
|
|
return thread;
|
2013-09-11 22:56:44 +08:00
|
|
|
|
|
|
|
err_thread:
|
|
|
|
free(thread);
|
|
|
|
return NULL;
|
2009-08-14 18:21:53 +08:00
|
|
|
}
|
|
|
|
|
2013-10-23 06:01:31 +08:00
|
|
|
void thread__delete(struct thread *thread)
|
2010-07-31 05:28:42 +08:00
|
|
|
{
|
perf tools: Add PERF_RECORD_NAMESPACES to include namespaces related info
Introduce a new option to record PERF_RECORD_NAMESPACES events emitted
by the kernel when fork, clone, setns or unshare are invoked. And update
perf-record documentation with the new option to record namespace
events.
Committer notes:
Combined it with a later patch to allow printing it via 'perf report -D'
and be able to test the feature introduced in this patch. Had to move
here also perf_ns__name(), that was introduced in another later patch.
Also used PRIu64 and PRIx64 to fix the build in some enfironments wrt:
util/event.c:1129:39: error: format '%lx' expects argument of type 'long unsigned int', but argument 6 has type 'long long unsigned int' [-Werror=format=]
ret += fprintf(fp, "%u/%s: %lu/0x%lx%s", idx
^
Testing it:
# perf record --namespaces -a
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 1.083 MB perf.data (423 samples) ]
#
# perf report -D
<SNIP>
3 2028902078892 0x115140 [0xa0]: PERF_RECORD_NAMESPACES 14783/14783 - nr_namespaces: 7
[0/net: 3/0xf0000081, 1/uts: 3/0xeffffffe, 2/ipc: 3/0xefffffff, 3/pid: 3/0xeffffffc,
4/user: 3/0xeffffffd, 5/mnt: 3/0xf0000000, 6/cgroup: 3/0xeffffffb]
0x1151e0 [0x30]: event: 9
.
. ... raw event: size 48 bytes
. 0000: 09 00 00 00 02 00 30 00 c4 71 82 68 0c 7f 00 00 ......0..q.h....
. 0010: a9 39 00 00 a9 39 00 00 94 28 fe 63 d8 01 00 00 .9...9...(.c....
. 0020: 03 00 00 00 00 00 00 00 ce c4 02 00 00 00 00 00 ................
<SNIP>
NAMESPACES events: 1
<SNIP>
#
Signed-off-by: Hari Bathini <hbathini@linux.vnet.ibm.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com>
Cc: Aravinda Prasad <aravinda@linux.vnet.ibm.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Sargun Dhillon <sargun@sargun.me>
Cc: Steven Rostedt <rostedt@goodmis.org>
Link: http://lkml.kernel.org/r/148891930386.25309.18412039920746995488.stgit@hbathini.in.ibm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2017-03-08 04:41:43 +08:00
|
|
|
struct namespaces *namespaces, *tmp_namespaces;
|
|
|
|
struct comm *comm, *tmp_comm;
|
2013-09-11 22:56:44 +08: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 07:43:22 +08:00
|
|
|
BUG_ON(!RB_EMPTY_NODE(&thread->rb_node));
|
|
|
|
|
2014-10-30 22:09:42 +08:00
|
|
|
thread_stack__free(thread);
|
|
|
|
|
2014-07-16 15:19:43 +08:00
|
|
|
if (thread->mg) {
|
|
|
|
map_groups__put(thread->mg);
|
|
|
|
thread->mg = NULL;
|
|
|
|
}
|
perf tools: Add PERF_RECORD_NAMESPACES to include namespaces related info
Introduce a new option to record PERF_RECORD_NAMESPACES events emitted
by the kernel when fork, clone, setns or unshare are invoked. And update
perf-record documentation with the new option to record namespace
events.
Committer notes:
Combined it with a later patch to allow printing it via 'perf report -D'
and be able to test the feature introduced in this patch. Had to move
here also perf_ns__name(), that was introduced in another later patch.
Also used PRIu64 and PRIx64 to fix the build in some enfironments wrt:
util/event.c:1129:39: error: format '%lx' expects argument of type 'long unsigned int', but argument 6 has type 'long long unsigned int' [-Werror=format=]
ret += fprintf(fp, "%u/%s: %lu/0x%lx%s", idx
^
Testing it:
# perf record --namespaces -a
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 1.083 MB perf.data (423 samples) ]
#
# perf report -D
<SNIP>
3 2028902078892 0x115140 [0xa0]: PERF_RECORD_NAMESPACES 14783/14783 - nr_namespaces: 7
[0/net: 3/0xf0000081, 1/uts: 3/0xeffffffe, 2/ipc: 3/0xefffffff, 3/pid: 3/0xeffffffc,
4/user: 3/0xeffffffd, 5/mnt: 3/0xf0000000, 6/cgroup: 3/0xeffffffb]
0x1151e0 [0x30]: event: 9
.
. ... raw event: size 48 bytes
. 0000: 09 00 00 00 02 00 30 00 c4 71 82 68 0c 7f 00 00 ......0..q.h....
. 0010: a9 39 00 00 a9 39 00 00 94 28 fe 63 d8 01 00 00 .9...9...(.c....
. 0020: 03 00 00 00 00 00 00 00 ce c4 02 00 00 00 00 00 ................
<SNIP>
NAMESPACES events: 1
<SNIP>
#
Signed-off-by: Hari Bathini <hbathini@linux.vnet.ibm.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com>
Cc: Aravinda Prasad <aravinda@linux.vnet.ibm.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Sargun Dhillon <sargun@sargun.me>
Cc: Steven Rostedt <rostedt@goodmis.org>
Link: http://lkml.kernel.org/r/148891930386.25309.18412039920746995488.stgit@hbathini.in.ibm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2017-03-08 04:41:43 +08:00
|
|
|
list_for_each_entry_safe(namespaces, tmp_namespaces,
|
|
|
|
&thread->namespaces_list, list) {
|
|
|
|
list_del(&namespaces->list);
|
|
|
|
namespaces__free(namespaces);
|
|
|
|
}
|
|
|
|
list_for_each_entry_safe(comm, tmp_comm, &thread->comm_list, list) {
|
2013-09-11 22:56:44 +08:00
|
|
|
list_del(&comm->list);
|
|
|
|
comm__free(comm);
|
|
|
|
}
|
2014-10-06 08:46:00 +08:00
|
|
|
unwind__finish_access(thread);
|
2013-09-11 22:56:44 +08:00
|
|
|
|
2013-10-23 06:01:31 +08:00
|
|
|
free(thread);
|
2010-07-31 05:28:42 +08:00
|
|
|
}
|
|
|
|
|
2015-03-03 09:21:35 +08:00
|
|
|
struct thread *thread__get(struct thread *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 07:43:22 +08:00
|
|
|
if (thread)
|
2017-02-21 23:35:02 +08:00
|
|
|
refcount_inc(&thread->refcnt);
|
2015-03-03 09:21:35 +08:00
|
|
|
return thread;
|
|
|
|
}
|
|
|
|
|
|
|
|
void thread__put(struct thread *thread)
|
|
|
|
{
|
2017-02-21 23:35:02 +08:00
|
|
|
if (thread && refcount_dec_and_test(&thread->refcnt)) {
|
2015-12-12 06:11:23 +08:00
|
|
|
/*
|
|
|
|
* Remove it from the dead_threads list, as last reference
|
|
|
|
* is gone.
|
|
|
|
*/
|
2015-03-03 09:21:35 +08:00
|
|
|
list_del_init(&thread->node);
|
|
|
|
thread__delete(thread);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
perf tools: Add PERF_RECORD_NAMESPACES to include namespaces related info
Introduce a new option to record PERF_RECORD_NAMESPACES events emitted
by the kernel when fork, clone, setns or unshare are invoked. And update
perf-record documentation with the new option to record namespace
events.
Committer notes:
Combined it with a later patch to allow printing it via 'perf report -D'
and be able to test the feature introduced in this patch. Had to move
here also perf_ns__name(), that was introduced in another later patch.
Also used PRIu64 and PRIx64 to fix the build in some enfironments wrt:
util/event.c:1129:39: error: format '%lx' expects argument of type 'long unsigned int', but argument 6 has type 'long long unsigned int' [-Werror=format=]
ret += fprintf(fp, "%u/%s: %lu/0x%lx%s", idx
^
Testing it:
# perf record --namespaces -a
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 1.083 MB perf.data (423 samples) ]
#
# perf report -D
<SNIP>
3 2028902078892 0x115140 [0xa0]: PERF_RECORD_NAMESPACES 14783/14783 - nr_namespaces: 7
[0/net: 3/0xf0000081, 1/uts: 3/0xeffffffe, 2/ipc: 3/0xefffffff, 3/pid: 3/0xeffffffc,
4/user: 3/0xeffffffd, 5/mnt: 3/0xf0000000, 6/cgroup: 3/0xeffffffb]
0x1151e0 [0x30]: event: 9
.
. ... raw event: size 48 bytes
. 0000: 09 00 00 00 02 00 30 00 c4 71 82 68 0c 7f 00 00 ......0..q.h....
. 0010: a9 39 00 00 a9 39 00 00 94 28 fe 63 d8 01 00 00 .9...9...(.c....
. 0020: 03 00 00 00 00 00 00 00 ce c4 02 00 00 00 00 00 ................
<SNIP>
NAMESPACES events: 1
<SNIP>
#
Signed-off-by: Hari Bathini <hbathini@linux.vnet.ibm.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com>
Cc: Aravinda Prasad <aravinda@linux.vnet.ibm.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Sargun Dhillon <sargun@sargun.me>
Cc: Steven Rostedt <rostedt@goodmis.org>
Link: http://lkml.kernel.org/r/148891930386.25309.18412039920746995488.stgit@hbathini.in.ibm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2017-03-08 04:41:43 +08:00
|
|
|
struct namespaces *thread__namespaces(const struct thread *thread)
|
|
|
|
{
|
|
|
|
if (list_empty(&thread->namespaces_list))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return list_first_entry(&thread->namespaces_list, struct namespaces, list);
|
|
|
|
}
|
|
|
|
|
|
|
|
int thread__set_namespaces(struct thread *thread, u64 timestamp,
|
|
|
|
struct namespaces_event *event)
|
|
|
|
{
|
|
|
|
struct namespaces *new, *curr = thread__namespaces(thread);
|
|
|
|
|
|
|
|
new = namespaces__new(event);
|
|
|
|
if (!new)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
list_add(&new->list, &thread->namespaces_list);
|
|
|
|
|
|
|
|
if (timestamp && curr) {
|
|
|
|
/*
|
|
|
|
* setns syscall must have changed few or all the namespaces
|
|
|
|
* of this thread. Update end time for the namespaces
|
|
|
|
* previously used.
|
|
|
|
*/
|
|
|
|
curr = list_next_entry(new, list);
|
|
|
|
curr->end_time = timestamp;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-13 15:28:57 +08:00
|
|
|
struct comm *thread__comm(const struct thread *thread)
|
2009-08-14 18:21:53 +08:00
|
|
|
{
|
2013-09-11 22:56:44 +08:00
|
|
|
if (list_empty(&thread->comm_list))
|
|
|
|
return NULL;
|
2010-02-26 23:08:34 +08:00
|
|
|
|
2013-09-11 22:56:44 +08:00
|
|
|
return list_first_entry(&thread->comm_list, struct comm, list);
|
|
|
|
}
|
|
|
|
|
2014-07-31 14:00:44 +08:00
|
|
|
struct comm *thread__exec_comm(const struct thread *thread)
|
|
|
|
{
|
|
|
|
struct comm *comm, *last = NULL;
|
|
|
|
|
|
|
|
list_for_each_entry(comm, &thread->comm_list, list) {
|
|
|
|
if (comm->exec)
|
|
|
|
return comm;
|
|
|
|
last = comm;
|
|
|
|
}
|
|
|
|
|
|
|
|
return last;
|
|
|
|
}
|
|
|
|
|
|
|
|
int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp,
|
|
|
|
bool exec)
|
2013-09-11 22:56:44 +08:00
|
|
|
{
|
|
|
|
struct comm *new, *curr = thread__comm(thread);
|
|
|
|
|
2014-11-11 22:16:41 +08:00
|
|
|
/* Override the default :tid entry */
|
|
|
|
if (!thread->comm_set) {
|
2016-10-03 22:07:24 +08:00
|
|
|
int err = comm__override(curr, str, timestamp, exec);
|
2014-01-14 23:37:14 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
2013-11-16 09:02:09 +08:00
|
|
|
} else {
|
2014-07-31 14:00:44 +08:00
|
|
|
new = comm__new(str, timestamp, exec);
|
2013-11-16 09:02:09 +08:00
|
|
|
if (!new)
|
|
|
|
return -ENOMEM;
|
|
|
|
list_add(&new->list, &thread->comm_list);
|
2014-10-06 08:46:01 +08:00
|
|
|
|
|
|
|
if (exec)
|
|
|
|
unwind__flush_access(thread);
|
2010-02-26 23:08:34 +08:00
|
|
|
}
|
2013-09-11 22:56:44 +08:00
|
|
|
|
|
|
|
thread->comm_set = true;
|
|
|
|
|
|
|
|
return 0;
|
2009-08-14 18:21:53 +08:00
|
|
|
}
|
|
|
|
|
2016-04-26 23:32:50 +08:00
|
|
|
int thread__set_comm_from_proc(struct thread *thread)
|
|
|
|
{
|
|
|
|
char path[64];
|
|
|
|
char *comm = NULL;
|
|
|
|
size_t sz;
|
|
|
|
int err = -1;
|
|
|
|
|
|
|
|
if (!(snprintf(path, sizeof(path), "%d/task/%d/comm",
|
|
|
|
thread->pid_, thread->tid) >= (int)sizeof(path)) &&
|
|
|
|
procfs__read_str(path, &comm, &sz) == 0) {
|
|
|
|
comm[sz - 1] = '\0';
|
|
|
|
err = thread__set_comm(thread, comm, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2013-09-11 20:46:56 +08:00
|
|
|
const char *thread__comm_str(const struct thread *thread)
|
|
|
|
{
|
2013-09-11 22:56:44 +08:00
|
|
|
const struct comm *comm = thread__comm(thread);
|
|
|
|
|
|
|
|
if (!comm)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return comm__str(comm);
|
2013-09-11 20:46:56 +08:00
|
|
|
}
|
|
|
|
|
2013-09-11 22:56:44 +08:00
|
|
|
/* CHECKME: it should probably better return the max comm len from its comm list */
|
2013-10-23 06:01:31 +08:00
|
|
|
int thread__comm_len(struct thread *thread)
|
perf tools: Bind callchains to the first sort dimension column
Currently, the callchains are displayed using a constant left
margin. So depending on the current sort dimension
configuration, callchains may appear to be well attached to the
first sort dimension column field which is mostly the case,
except when the first dimension of sorting is done by comm,
because these are right aligned.
This patch binds the callchain to the first letter in the first
column, whatever type of column it is (dso, comm, symbol).
Before:
0.80% perf [k] __lock_acquire
__lock_acquire
lock_acquire
|
|--58.33%-- _spin_lock
| |
| |--28.57%-- inotify_should_send_event
| | fsnotify
| | __fsnotify_parent
After:
0.80% perf [k] __lock_acquire
__lock_acquire
lock_acquire
|
|--58.33%-- _spin_lock
| |
| |--28.57%-- inotify_should_send_event
| | fsnotify
| | __fsnotify_parent
Also, for clarity, we don't put anymore the callchain as is but:
- If we have a top level ancestor in the callchain, start it
with a first ascii hook.
Before:
0.80% perf [kernel] [k] __lock_acquire
__lock_acquire
lock_acquire
|
|--58.33%-- _spin_lock
| |
| |--28.57%-- inotify_should_send_event
| | fsnotify
[..] [..]
After:
0.80% perf [kernel] [k] __lock_acquire
|
--- __lock_acquire
lock_acquire
|
|--58.33%-- _spin_lock
| |
| |--28.57%-- inotify_should_send_event
| | fsnotify
[..] [..]
- Otherwise, if we have several top level ancestors, then
display these like we did before:
1.69% Xorg
|
|--21.21%-- vread_hpet
| 0x7fffd85b46fc
| 0x7fffd85b494d
| 0x7f4fafb4e54d
|
|--15.15%-- exaOffscreenAlloc
|
|--9.09%-- I830WaitLpRing
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Anton Blanchard <anton@samba.org>
LKML-Reference: <1256246604-17156-2-git-send-email-fweisbec@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2009-10-23 05:23:23 +08:00
|
|
|
{
|
2013-10-23 06:01:31 +08:00
|
|
|
if (!thread->comm_len) {
|
2013-09-11 22:56:44 +08:00
|
|
|
const char *comm = thread__comm_str(thread);
|
|
|
|
if (!comm)
|
perf tools: Bind callchains to the first sort dimension column
Currently, the callchains are displayed using a constant left
margin. So depending on the current sort dimension
configuration, callchains may appear to be well attached to the
first sort dimension column field which is mostly the case,
except when the first dimension of sorting is done by comm,
because these are right aligned.
This patch binds the callchain to the first letter in the first
column, whatever type of column it is (dso, comm, symbol).
Before:
0.80% perf [k] __lock_acquire
__lock_acquire
lock_acquire
|
|--58.33%-- _spin_lock
| |
| |--28.57%-- inotify_should_send_event
| | fsnotify
| | __fsnotify_parent
After:
0.80% perf [k] __lock_acquire
__lock_acquire
lock_acquire
|
|--58.33%-- _spin_lock
| |
| |--28.57%-- inotify_should_send_event
| | fsnotify
| | __fsnotify_parent
Also, for clarity, we don't put anymore the callchain as is but:
- If we have a top level ancestor in the callchain, start it
with a first ascii hook.
Before:
0.80% perf [kernel] [k] __lock_acquire
__lock_acquire
lock_acquire
|
|--58.33%-- _spin_lock
| |
| |--28.57%-- inotify_should_send_event
| | fsnotify
[..] [..]
After:
0.80% perf [kernel] [k] __lock_acquire
|
--- __lock_acquire
lock_acquire
|
|--58.33%-- _spin_lock
| |
| |--28.57%-- inotify_should_send_event
| | fsnotify
[..] [..]
- Otherwise, if we have several top level ancestors, then
display these like we did before:
1.69% Xorg
|
|--21.21%-- vread_hpet
| 0x7fffd85b46fc
| 0x7fffd85b494d
| 0x7f4fafb4e54d
|
|--15.15%-- exaOffscreenAlloc
|
|--9.09%-- I830WaitLpRing
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Anton Blanchard <anton@samba.org>
LKML-Reference: <1256246604-17156-2-git-send-email-fweisbec@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2009-10-23 05:23:23 +08:00
|
|
|
return 0;
|
2013-09-11 22:56:44 +08:00
|
|
|
thread->comm_len = strlen(comm);
|
perf tools: Bind callchains to the first sort dimension column
Currently, the callchains are displayed using a constant left
margin. So depending on the current sort dimension
configuration, callchains may appear to be well attached to the
first sort dimension column field which is mostly the case,
except when the first dimension of sorting is done by comm,
because these are right aligned.
This patch binds the callchain to the first letter in the first
column, whatever type of column it is (dso, comm, symbol).
Before:
0.80% perf [k] __lock_acquire
__lock_acquire
lock_acquire
|
|--58.33%-- _spin_lock
| |
| |--28.57%-- inotify_should_send_event
| | fsnotify
| | __fsnotify_parent
After:
0.80% perf [k] __lock_acquire
__lock_acquire
lock_acquire
|
|--58.33%-- _spin_lock
| |
| |--28.57%-- inotify_should_send_event
| | fsnotify
| | __fsnotify_parent
Also, for clarity, we don't put anymore the callchain as is but:
- If we have a top level ancestor in the callchain, start it
with a first ascii hook.
Before:
0.80% perf [kernel] [k] __lock_acquire
__lock_acquire
lock_acquire
|
|--58.33%-- _spin_lock
| |
| |--28.57%-- inotify_should_send_event
| | fsnotify
[..] [..]
After:
0.80% perf [kernel] [k] __lock_acquire
|
--- __lock_acquire
lock_acquire
|
|--58.33%-- _spin_lock
| |
| |--28.57%-- inotify_should_send_event
| | fsnotify
[..] [..]
- Otherwise, if we have several top level ancestors, then
display these like we did before:
1.69% Xorg
|
|--21.21%-- vread_hpet
| 0x7fffd85b46fc
| 0x7fffd85b494d
| 0x7f4fafb4e54d
|
|--15.15%-- exaOffscreenAlloc
|
|--9.09%-- I830WaitLpRing
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Anton Blanchard <anton@samba.org>
LKML-Reference: <1256246604-17156-2-git-send-email-fweisbec@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2009-10-23 05:23:23 +08:00
|
|
|
}
|
|
|
|
|
2013-10-23 06:01:31 +08:00
|
|
|
return thread->comm_len;
|
perf tools: Bind callchains to the first sort dimension column
Currently, the callchains are displayed using a constant left
margin. So depending on the current sort dimension
configuration, callchains may appear to be well attached to the
first sort dimension column field which is mostly the case,
except when the first dimension of sorting is done by comm,
because these are right aligned.
This patch binds the callchain to the first letter in the first
column, whatever type of column it is (dso, comm, symbol).
Before:
0.80% perf [k] __lock_acquire
__lock_acquire
lock_acquire
|
|--58.33%-- _spin_lock
| |
| |--28.57%-- inotify_should_send_event
| | fsnotify
| | __fsnotify_parent
After:
0.80% perf [k] __lock_acquire
__lock_acquire
lock_acquire
|
|--58.33%-- _spin_lock
| |
| |--28.57%-- inotify_should_send_event
| | fsnotify
| | __fsnotify_parent
Also, for clarity, we don't put anymore the callchain as is but:
- If we have a top level ancestor in the callchain, start it
with a first ascii hook.
Before:
0.80% perf [kernel] [k] __lock_acquire
__lock_acquire
lock_acquire
|
|--58.33%-- _spin_lock
| |
| |--28.57%-- inotify_should_send_event
| | fsnotify
[..] [..]
After:
0.80% perf [kernel] [k] __lock_acquire
|
--- __lock_acquire
lock_acquire
|
|--58.33%-- _spin_lock
| |
| |--28.57%-- inotify_should_send_event
| | fsnotify
[..] [..]
- Otherwise, if we have several top level ancestors, then
display these like we did before:
1.69% Xorg
|
|--21.21%-- vread_hpet
| 0x7fffd85b46fc
| 0x7fffd85b494d
| 0x7f4fafb4e54d
|
|--15.15%-- exaOffscreenAlloc
|
|--9.09%-- I830WaitLpRing
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Anton Blanchard <anton@samba.org>
LKML-Reference: <1256246604-17156-2-git-send-email-fweisbec@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2009-10-23 05:23:23 +08:00
|
|
|
}
|
|
|
|
|
2012-12-08 04:39:39 +08:00
|
|
|
size_t thread__fprintf(struct thread *thread, FILE *fp)
|
2009-12-12 00:50:36 +08:00
|
|
|
{
|
2013-09-11 20:46:56 +08:00
|
|
|
return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) +
|
2014-07-15 05:46:47 +08:00
|
|
|
map_groups__fprintf(thread->mg, fp);
|
2009-08-14 18:21:53 +08:00
|
|
|
}
|
|
|
|
|
2016-06-03 11:33:13 +08:00
|
|
|
int thread__insert_map(struct thread *thread, struct map *map)
|
2009-09-29 01:48:46 +08:00
|
|
|
{
|
2016-06-03 11:33:13 +08:00
|
|
|
int ret;
|
|
|
|
|
2016-07-04 20:16:22 +08:00
|
|
|
ret = unwind__prepare_access(thread, map, NULL);
|
2016-06-03 11:33:13 +08:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2014-07-15 05:46:47 +08:00
|
|
|
map_groups__fixup_overlappings(thread->mg, map, stderr);
|
2014-03-22 04:57:01 +08:00
|
|
|
map_groups__insert(thread->mg, map);
|
2016-06-03 11:33:13 +08:00
|
|
|
|
|
|
|
return 0;
|
2009-08-14 18:21:53 +08:00
|
|
|
}
|
|
|
|
|
2016-07-04 20:16:23 +08:00
|
|
|
static int __thread__prepare_access(struct thread *thread)
|
|
|
|
{
|
|
|
|
bool initialized = false;
|
|
|
|
int i, err = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < MAP__NR_TYPES; ++i) {
|
|
|
|
struct maps *maps = &thread->mg->maps[i];
|
|
|
|
struct map *map;
|
|
|
|
|
|
|
|
pthread_rwlock_rdlock(&maps->lock);
|
|
|
|
|
|
|
|
for (map = maps__first(maps); map; map = map__next(map)) {
|
|
|
|
err = unwind__prepare_access(thread, map, &initialized);
|
|
|
|
if (err || initialized)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_rwlock_unlock(&maps->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int thread__prepare_access(struct thread *thread)
|
|
|
|
{
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
if (symbol_conf.use_callchain)
|
|
|
|
err = __thread__prepare_access(thread);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2014-04-10 02:54:29 +08:00
|
|
|
static int thread__clone_map_groups(struct thread *thread,
|
|
|
|
struct thread *parent)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* This is new thread, we share map groups for process. */
|
|
|
|
if (thread->pid_ == parent->pid_)
|
2016-07-04 20:16:23 +08:00
|
|
|
return thread__prepare_access(thread);
|
2014-04-10 02:54:29 +08:00
|
|
|
|
2015-08-19 22:29:19 +08:00
|
|
|
if (thread->mg == parent->mg) {
|
|
|
|
pr_debug("broken map groups on thread %d/%d parent %d/%d\n",
|
|
|
|
thread->pid_, thread->tid, parent->pid_, parent->tid);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-04-10 02:54:29 +08:00
|
|
|
/* But this one is new process, copy maps. */
|
|
|
|
for (i = 0; i < MAP__NR_TYPES; ++i)
|
2016-07-04 20:16:23 +08:00
|
|
|
if (map_groups__clone(thread, parent->mg, i) < 0)
|
2014-04-10 02:54:29 +08:00
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-11 22:56:44 +08:00
|
|
|
int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
|
2009-11-28 02:29:20 +08:00
|
|
|
{
|
2010-02-20 09:02:07 +08:00
|
|
|
if (parent->comm_set) {
|
2013-09-11 22:56:44 +08:00
|
|
|
const char *comm = thread__comm_str(parent);
|
2016-10-03 22:07:24 +08:00
|
|
|
int err;
|
2013-09-11 22:56:44 +08:00
|
|
|
if (!comm)
|
2010-02-20 09:02:07 +08:00
|
|
|
return -ENOMEM;
|
2013-09-11 22:56:44 +08:00
|
|
|
err = thread__set_comm(thread, comm, timestamp);
|
2013-12-11 12:35:38 +08:00
|
|
|
if (err)
|
2013-09-11 22:56:44 +08:00
|
|
|
return err;
|
2010-02-20 09:02:07 +08:00
|
|
|
}
|
2009-08-14 18:21:53 +08:00
|
|
|
|
2013-10-23 06:01:31 +08:00
|
|
|
thread->ppid = parent->tid;
|
2014-04-10 02:54:29 +08:00
|
|
|
return thread__clone_map_groups(thread, parent);
|
2009-08-14 18:21:53 +08:00
|
|
|
}
|
2014-03-12 03:16:49 +08:00
|
|
|
|
|
|
|
void thread__find_cpumode_addr_location(struct thread *thread,
|
|
|
|
enum map_type type, u64 addr,
|
|
|
|
struct addr_location *al)
|
|
|
|
{
|
|
|
|
size_t i;
|
2016-04-25 17:47:54 +08:00
|
|
|
const u8 cpumodes[] = {
|
2014-03-12 03:16:49 +08:00
|
|
|
PERF_RECORD_MISC_USER,
|
|
|
|
PERF_RECORD_MISC_KERNEL,
|
|
|
|
PERF_RECORD_MISC_GUEST_USER,
|
|
|
|
PERF_RECORD_MISC_GUEST_KERNEL
|
|
|
|
};
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(cpumodes); i++) {
|
2014-10-23 23:50:25 +08:00
|
|
|
thread__find_addr_location(thread, cpumodes[i], type, addr, al);
|
2014-03-12 03:16:49 +08:00
|
|
|
if (al->map)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-05-24 08:52:24 +08:00
|
|
|
|
|
|
|
struct thread *thread__main_thread(struct machine *machine, struct thread *thread)
|
|
|
|
{
|
|
|
|
if (thread->pid_ == thread->tid)
|
|
|
|
return thread__get(thread);
|
|
|
|
|
|
|
|
if (thread->pid_ == -1)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return machine__find_thread(machine, thread->pid_, thread->pid_);
|
|
|
|
}
|