aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2013-09-11 10:56:44 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2013-11-04 10:13:53 -0500
commit1902efe7f626fdebe1520f5ff11f1309ec506708 (patch)
treedbdc3c6f80aece6dfb35e2eaee6eb96a0ead5e4b
parent162f0befda3becc2cc9f44075fccc030e55baec1 (diff)
perf tools: Add new COMM infrastructure
This new COMM infrastructure provides two features: 1) It keeps track of all comms lifecycle for a given thread. This way we can associate a timeframe to any thread COMM, as long as PERF_SAMPLE_TIME samples are joined to COMM and fork events. As a result we should have more precise COMM sorted hists with seperated entries for pre and post exec time after a fork. 2) It also makes sure that a given COMM string is not duplicated but rather shared among the threads that refer to it. This way the threads COMM can be compared against pointer values from the sort infrastructure. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Tested-by: Jiri Olsa <jolsa@redhat.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: David Ahern <dsahern@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/n/tip-hwjf70b2wve9m2kosxiq8bb3@git.kernel.org [ Rename some accessor functions ] Signed-off-by: Namhyung Kim <namhyung@kernel.org> [ Use __ as separator for class__method for private comm_str methods ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/Makefile.perf2
-rw-r--r--tools/perf/builtin-trace.c4
-rw-r--r--tools/perf/util/comm.c106
-rw-r--r--tools/perf/util/comm.h20
-rw-r--r--tools/perf/util/thread.c92
-rw-r--r--tools/perf/util/thread.h3
6 files changed, 200 insertions, 27 deletions
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index bc7cfa18a1e3..cb52bdb755c7 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -273,6 +273,7 @@ LIB_H += util/color.h
273LIB_H += util/values.h 273LIB_H += util/values.h
274LIB_H += util/sort.h 274LIB_H += util/sort.h
275LIB_H += util/hist.h 275LIB_H += util/hist.h
276LIB_H += util/comm.h
276LIB_H += util/thread.h 277LIB_H += util/thread.h
277LIB_H += util/thread_map.h 278LIB_H += util/thread_map.h
278LIB_H += util/trace-event.h 279LIB_H += util/trace-event.h
@@ -341,6 +342,7 @@ LIB_OBJS += $(OUTPUT)util/machine.o
341LIB_OBJS += $(OUTPUT)util/map.o 342LIB_OBJS += $(OUTPUT)util/map.o
342LIB_OBJS += $(OUTPUT)util/pstack.o 343LIB_OBJS += $(OUTPUT)util/pstack.o
343LIB_OBJS += $(OUTPUT)util/session.o 344LIB_OBJS += $(OUTPUT)util/session.o
345LIB_OBJS += $(OUTPUT)util/comm.o
344LIB_OBJS += $(OUTPUT)util/thread.o 346LIB_OBJS += $(OUTPUT)util/thread.o
345LIB_OBJS += $(OUTPUT)util/thread_map.o 347LIB_OBJS += $(OUTPUT)util/thread_map.o
346LIB_OBJS += $(OUTPUT)util/trace-event-parse.o 348LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 95d639212d98..b3e57dc64546 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -1114,7 +1114,7 @@ static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thre
1114 1114
1115 if (trace->multiple_threads) { 1115 if (trace->multiple_threads) {
1116 if (trace->show_comm) 1116 if (trace->show_comm)
1117 printed += fprintf(fp, "%.14s/", thread->comm); 1117 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
1118 printed += fprintf(fp, "%d ", thread->tid); 1118 printed += fprintf(fp, "%d ", thread->tid);
1119 } 1119 }
1120 1120
@@ -1986,7 +1986,7 @@ static int trace__fprintf_one_thread(struct thread *thread, void *priv)
1986 else if (ratio > 5.0) 1986 else if (ratio > 5.0)
1987 color = PERF_COLOR_YELLOW; 1987 color = PERF_COLOR_YELLOW;
1988 1988
1989 printed += color_fprintf(fp, color, "%20s", thread->comm); 1989 printed += color_fprintf(fp, color, "%20s", thread__comm_str(thread));
1990 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events); 1990 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
1991 printed += color_fprintf(fp, color, "%5.1f%%", ratio); 1991 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1992 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms); 1992 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
diff --git a/tools/perf/util/comm.c b/tools/perf/util/comm.c
new file mode 100644
index 000000000000..8b3ac9f0207f
--- /dev/null
+++ b/tools/perf/util/comm.c
@@ -0,0 +1,106 @@
1#include "comm.h"
2#include "util.h"
3#include <stdlib.h>
4#include <stdio.h>
5
6struct comm_str {
7 char *str;
8 struct rb_node rb_node;
9 int ref;
10};
11
12/* Should perhaps be moved to struct machine */
13static struct rb_root comm_str_root;
14
15static void comm_str__get(struct comm_str *cs)
16{
17 cs->ref++;
18}
19
20static void comm_str__put(struct comm_str *cs)
21{
22 if (!--cs->ref) {
23 rb_erase(&cs->rb_node, &comm_str_root);
24 free(cs->str);
25 free(cs);
26 }
27}
28
29static struct comm_str *comm_str__alloc(const char *str)
30{
31 struct comm_str *cs;
32
33 cs = zalloc(sizeof(*cs));
34 if (!cs)
35 return NULL;
36
37 cs->str = strdup(str);
38 if (!cs->str) {
39 free(cs);
40 return NULL;
41 }
42
43 return cs;
44}
45
46static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root)
47{
48 struct rb_node **p = &root->rb_node;
49 struct rb_node *parent = NULL;
50 struct comm_str *iter, *new;
51 int cmp;
52
53 while (*p != NULL) {
54 parent = *p;
55 iter = rb_entry(parent, struct comm_str, rb_node);
56
57 cmp = strcmp(str, iter->str);
58 if (!cmp)
59 return iter;
60
61 if (cmp < 0)
62 p = &(*p)->rb_left;
63 else
64 p = &(*p)->rb_right;
65 }
66
67 new = comm_str__alloc(str);
68 if (!new)
69 return NULL;
70
71 rb_link_node(&new->rb_node, parent, p);
72 rb_insert_color(&new->rb_node, root);
73
74 return new;
75}
76
77struct comm *comm__new(const char *str, u64 timestamp)
78{
79 struct comm *comm = zalloc(sizeof(*comm));
80
81 if (!comm)
82 return NULL;
83
84 comm->start = timestamp;
85
86 comm->comm_str = comm_str__findnew(str, &comm_str_root);
87 if (!comm->comm_str) {
88 free(comm);
89 return NULL;
90 }
91
92 comm_str__get(comm->comm_str);
93
94 return comm;
95}
96
97void comm__free(struct comm *comm)
98{
99 comm_str__put(comm->comm_str);
100 free(comm);
101}
102
103const char *comm__str(const struct comm *comm)
104{
105 return comm->comm_str->str;
106}
diff --git a/tools/perf/util/comm.h b/tools/perf/util/comm.h
new file mode 100644
index 000000000000..f62d215bede2
--- /dev/null
+++ b/tools/perf/util/comm.h
@@ -0,0 +1,20 @@
1#ifndef __PERF_COMM_H
2#define __PERF_COMM_H
3
4#include "../perf.h"
5#include <linux/rbtree.h>
6#include <linux/list.h>
7
8struct comm_str;
9
10struct comm {
11 struct comm_str *comm_str;
12 u64 start;
13 struct list_head list;
14};
15
16void comm__free(struct comm *comm);
17struct comm *comm__new(const char *str, u64 timestamp);
18const char *comm__str(const struct comm *comm);
19
20#endif /* __PERF_COMM_H */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 0ea73fe383f5..15c53c2e109e 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -6,9 +6,12 @@
6#include "thread.h" 6#include "thread.h"
7#include "util.h" 7#include "util.h"
8#include "debug.h" 8#include "debug.h"
9#include "comm.h"
9 10
10struct thread *thread__new(pid_t pid, pid_t tid) 11struct thread *thread__new(pid_t pid, pid_t tid)
11{ 12{
13 char *comm_str;
14 struct comm *comm;
12 struct thread *thread = zalloc(sizeof(*thread)); 15 struct thread *thread = zalloc(sizeof(*thread));
13 16
14 if (thread != NULL) { 17 if (thread != NULL) {
@@ -16,47 +19,88 @@ struct thread *thread__new(pid_t pid, pid_t tid)
16 thread->pid_ = pid; 19 thread->pid_ = pid;
17 thread->tid = tid; 20 thread->tid = tid;
18 thread->ppid = -1; 21 thread->ppid = -1;
19 thread->comm = malloc(32); 22 INIT_LIST_HEAD(&thread->comm_list);
20 if (thread->comm) 23
21 snprintf(thread->comm, 32, ":%d", thread->tid); 24 comm_str = malloc(32);
25 if (!comm_str)
26 goto err_thread;
27
28 snprintf(comm_str, 32, ":%d", tid);
29 comm = comm__new(comm_str, 0);
30 free(comm_str);
31 if (!comm)
32 goto err_thread;
33
34 list_add(&comm->list, &thread->comm_list);
22 } 35 }
23 36
24 return thread; 37 return thread;
38
39err_thread:
40 free(thread);
41 return NULL;
25} 42}
26 43
27void thread__delete(struct thread *thread) 44void thread__delete(struct thread *thread)
28{ 45{
46 struct comm *comm, *tmp;
47
29 map_groups__exit(&thread->mg); 48 map_groups__exit(&thread->mg);
30 free(thread->comm); 49 list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) {
50 list_del(&comm->list);
51 comm__free(comm);
52 }
53
31 free(thread); 54 free(thread);
32} 55}
33 56
34int thread__set_comm(struct thread *thread, const char *comm, 57static struct comm *thread__comm(const struct thread *thread)
35 u64 timestamp __maybe_unused)
36{ 58{
37 int err; 59 if (list_empty(&thread->comm_list))
60 return NULL;
38 61
39 if (thread->comm) 62 return list_first_entry(&thread->comm_list, struct comm, list);
40 free(thread->comm); 63}
41 thread->comm = strdup(comm); 64
42 err = thread->comm == NULL ? -ENOMEM : 0; 65/* CHECKME: time should always be 0 if event aren't ordered */
43 if (!err) { 66int thread__set_comm(struct thread *thread, const char *str, u64 timestamp)
44 thread->comm_set = true; 67{
68 struct comm *new, *curr = thread__comm(thread);
69
70 /* Override latest entry if it had no specific time coverage */
71 if (!curr->start) {
72 list_del(&curr->list);
73 comm__free(curr);
45 } 74 }
46 return err; 75
76 new = comm__new(str, timestamp);
77 if (!new)
78 return -ENOMEM;
79
80 list_add(&new->list, &thread->comm_list);
81 thread->comm_set = true;
82
83 return 0;
47} 84}
48 85
49const char *thread__comm_str(const struct thread *thread) 86const char *thread__comm_str(const struct thread *thread)
50{ 87{
51 return thread->comm; 88 const struct comm *comm = thread__comm(thread);
89
90 if (!comm)
91 return NULL;
92
93 return comm__str(comm);
52} 94}
53 95
96/* CHECKME: it should probably better return the max comm len from its comm list */
54int thread__comm_len(struct thread *thread) 97int thread__comm_len(struct thread *thread)
55{ 98{
56 if (!thread->comm_len) { 99 if (!thread->comm_len) {
57 if (!thread->comm) 100 const char *comm = thread__comm_str(thread);
101 if (!comm)
58 return 0; 102 return 0;
59 thread->comm_len = strlen(thread->comm); 103 thread->comm_len = strlen(comm);
60 } 104 }
61 105
62 return thread->comm_len; 106 return thread->comm_len;
@@ -74,17 +118,17 @@ void thread__insert_map(struct thread *thread, struct map *map)
74 map_groups__insert(&thread->mg, map); 118 map_groups__insert(&thread->mg, map);
75} 119}
76 120
77int thread__fork(struct thread *thread, struct thread *parent, 121int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
78 u64 timestamp __maybe_unused)
79{ 122{
80 int i; 123 int i, err;
81 124
82 if (parent->comm_set) { 125 if (parent->comm_set) {
83 if (thread->comm) 126 const char *comm = thread__comm_str(parent);
84 free(thread->comm); 127 if (!comm)
85 thread->comm = strdup(parent->comm);
86 if (!thread->comm)
87 return -ENOMEM; 128 return -ENOMEM;
129 err = thread__set_comm(thread, comm, timestamp);
130 if (!err)
131 return err;
88 thread->comm_set = true; 132 thread->comm_set = true;
89 } 133 }
90 134
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 4e9724270a64..8702c6b4163a 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -2,6 +2,7 @@
2#define __PERF_THREAD_H 2#define __PERF_THREAD_H
3 3
4#include <linux/rbtree.h> 4#include <linux/rbtree.h>
5#include <linux/list.h>
5#include <unistd.h> 6#include <unistd.h>
6#include <sys/types.h> 7#include <sys/types.h>
7#include "symbol.h" 8#include "symbol.h"
@@ -18,7 +19,7 @@ struct thread {
18 char shortname[3]; 19 char shortname[3];
19 bool comm_set; 20 bool comm_set;
20 bool dead; /* if set thread has exited */ 21 bool dead; /* if set thread has exited */
21 char *comm; 22 struct list_head comm_list;
22 int comm_len; 23 int comm_len;
23 24
24 void *priv; 25 void *priv;