diff options
-rw-r--r-- | tools/perf/Makefile.perf | 2 | ||||
-rw-r--r-- | tools/perf/builtin-trace.c | 4 | ||||
-rw-r--r-- | tools/perf/util/comm.c | 106 | ||||
-rw-r--r-- | tools/perf/util/comm.h | 20 | ||||
-rw-r--r-- | tools/perf/util/thread.c | 92 | ||||
-rw-r--r-- | tools/perf/util/thread.h | 3 |
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 | |||
273 | LIB_H += util/values.h | 273 | LIB_H += util/values.h |
274 | LIB_H += util/sort.h | 274 | LIB_H += util/sort.h |
275 | LIB_H += util/hist.h | 275 | LIB_H += util/hist.h |
276 | LIB_H += util/comm.h | ||
276 | LIB_H += util/thread.h | 277 | LIB_H += util/thread.h |
277 | LIB_H += util/thread_map.h | 278 | LIB_H += util/thread_map.h |
278 | LIB_H += util/trace-event.h | 279 | LIB_H += util/trace-event.h |
@@ -341,6 +342,7 @@ LIB_OBJS += $(OUTPUT)util/machine.o | |||
341 | LIB_OBJS += $(OUTPUT)util/map.o | 342 | LIB_OBJS += $(OUTPUT)util/map.o |
342 | LIB_OBJS += $(OUTPUT)util/pstack.o | 343 | LIB_OBJS += $(OUTPUT)util/pstack.o |
343 | LIB_OBJS += $(OUTPUT)util/session.o | 344 | LIB_OBJS += $(OUTPUT)util/session.o |
345 | LIB_OBJS += $(OUTPUT)util/comm.o | ||
344 | LIB_OBJS += $(OUTPUT)util/thread.o | 346 | LIB_OBJS += $(OUTPUT)util/thread.o |
345 | LIB_OBJS += $(OUTPUT)util/thread_map.o | 347 | LIB_OBJS += $(OUTPUT)util/thread_map.o |
346 | LIB_OBJS += $(OUTPUT)util/trace-event-parse.o | 348 | LIB_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 | |||
6 | struct comm_str { | ||
7 | char *str; | ||
8 | struct rb_node rb_node; | ||
9 | int ref; | ||
10 | }; | ||
11 | |||
12 | /* Should perhaps be moved to struct machine */ | ||
13 | static struct rb_root comm_str_root; | ||
14 | |||
15 | static void comm_str__get(struct comm_str *cs) | ||
16 | { | ||
17 | cs->ref++; | ||
18 | } | ||
19 | |||
20 | static 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 | |||
29 | static 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 | |||
46 | static 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 | |||
77 | struct 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 | |||
97 | void comm__free(struct comm *comm) | ||
98 | { | ||
99 | comm_str__put(comm->comm_str); | ||
100 | free(comm); | ||
101 | } | ||
102 | |||
103 | const 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 | |||
8 | struct comm_str; | ||
9 | |||
10 | struct comm { | ||
11 | struct comm_str *comm_str; | ||
12 | u64 start; | ||
13 | struct list_head list; | ||
14 | }; | ||
15 | |||
16 | void comm__free(struct comm *comm); | ||
17 | struct comm *comm__new(const char *str, u64 timestamp); | ||
18 | const 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 | ||
10 | struct thread *thread__new(pid_t pid, pid_t tid) | 11 | struct 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 | |||
39 | err_thread: | ||
40 | free(thread); | ||
41 | return NULL; | ||
25 | } | 42 | } |
26 | 43 | ||
27 | void thread__delete(struct thread *thread) | 44 | void 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 | ||
34 | int thread__set_comm(struct thread *thread, const char *comm, | 57 | static 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) { | 66 | int 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 | ||
49 | const char *thread__comm_str(const struct thread *thread) | 86 | const 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 */ | ||
54 | int thread__comm_len(struct thread *thread) | 97 | int 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 | ||
77 | int thread__fork(struct thread *thread, struct thread *parent, | 121 | int 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; |