2009-08-14 18:21:53 +08:00
|
|
|
#include "../perf.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.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"
|
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)
|
|
|
|
{
|
|
|
|
struct thread *leader;
|
|
|
|
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 {
|
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
|
|
|
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;
|
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);
|
2015-12-12 06:11:23 +08:00
|
|
|
atomic_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
|
|
|
{
|
2013-09-11 22:56:44 +08:00
|
|
|
struct comm *comm, *tmp;
|
|
|
|
|
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;
|
|
|
|
}
|
2013-09-11 22:56:44 +08:00
|
|
|
list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) {
|
|
|
|
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)
|
|
|
|
atomic_inc(&thread->refcnt);
|
2015-03-03 09:21:35 +08:00
|
|
|
return thread;
|
|
|
|
}
|
|
|
|
|
|
|
|
void thread__put(struct thread *thread)
|
|
|
|
{
|
2015-04-07 22:59:50 +08:00
|
|
|
if (thread && atomic_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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-01-14 23:37:14 +08:00
|
|
|
int err;
|
2013-09-11 22:56:44 +08:00
|
|
|
|
2014-11-11 22:16:41 +08:00
|
|
|
/* Override the default :tid entry */
|
|
|
|
if (!thread->comm_set) {
|
2014-07-31 14:00:44 +08:00
|
|
|
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
|
|
|
{
|
2014-04-10 02:54:29 +08:00
|
|
|
int err;
|
2009-08-14 18:21:53 +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);
|
|
|
|
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_);
|
|
|
|
}
|