]> git.karo-electronics.de Git - karo-tx-linux.git/blob - tools/perf/util/thread.c
b501848a8424cc2483232cba02520f5a95c8d140
[karo-tx-linux.git] / tools / perf / util / thread.c
1 #include "../perf.h"
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include "session.h"
6 #include "thread.h"
7 #include "util.h"
8 #include "debug.h"
9 #include "comm.h"
10
11 struct thread *thread__new(pid_t pid, pid_t tid)
12 {
13         char *comm_str;
14         struct comm *comm;
15         struct thread *thread = zalloc(sizeof(*thread));
16
17         if (thread != NULL) {
18                 thread->mg = map_groups__new();
19                 if (thread->mg == NULL)
20                         goto out_free;
21
22                 thread->pid_ = pid;
23                 thread->tid = tid;
24                 thread->ppid = -1;
25                 INIT_LIST_HEAD(&thread->comm_list);
26
27                 comm_str = malloc(32);
28                 if (!comm_str)
29                         goto err_thread;
30
31                 snprintf(comm_str, 32, ":%d", tid);
32                 comm = comm__new(comm_str, 0);
33                 free(comm_str);
34                 if (!comm)
35                         goto err_thread;
36
37                 list_add(&comm->list, &thread->comm_list);
38         }
39
40         return thread;
41
42 err_thread:
43         map_groups__delete(thread->mg);
44 out_free:
45         free(thread);
46         return NULL;
47 }
48
49 void thread__delete(struct thread *thread)
50 {
51         struct comm *comm, *tmp;
52
53         map_groups__put(thread->mg);
54         thread->mg = NULL;
55         list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) {
56                 list_del(&comm->list);
57                 comm__free(comm);
58         }
59
60         free(thread);
61 }
62
63 struct comm *thread__comm(const struct thread *thread)
64 {
65         if (list_empty(&thread->comm_list))
66                 return NULL;
67
68         return list_first_entry(&thread->comm_list, struct comm, list);
69 }
70
71 /* CHECKME: time should always be 0 if event aren't ordered */
72 int thread__set_comm(struct thread *thread, const char *str, u64 timestamp)
73 {
74         struct comm *new, *curr = thread__comm(thread);
75         int err;
76
77         /* Override latest entry if it had no specific time coverage */
78         if (!curr->start) {
79                 err = comm__override(curr, str, timestamp);
80                 if (err)
81                         return err;
82         } else {
83                 new = comm__new(str, timestamp);
84                 if (!new)
85                         return -ENOMEM;
86                 list_add(&new->list, &thread->comm_list);
87         }
88
89         thread->comm_set = true;
90
91         return 0;
92 }
93
94 const char *thread__comm_str(const struct thread *thread)
95 {
96         const struct comm *comm = thread__comm(thread);
97
98         if (!comm)
99                 return NULL;
100
101         return comm__str(comm);
102 }
103
104 /* CHECKME: it should probably better return the max comm len from its comm list */
105 int thread__comm_len(struct thread *thread)
106 {
107         if (!thread->comm_len) {
108                 const char *comm = thread__comm_str(thread);
109                 if (!comm)
110                         return 0;
111                 thread->comm_len = strlen(comm);
112         }
113
114         return thread->comm_len;
115 }
116
117 size_t thread__fprintf(struct thread *thread, FILE *fp)
118 {
119         return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) +
120                map_groups__fprintf(thread->mg, verbose, fp);
121 }
122
123 void thread__insert_map(struct thread *thread, struct map *map)
124 {
125         map_groups__fixup_overlappings(thread->mg, map, verbose, stderr);
126         map_groups__insert(thread->mg, map);
127 }
128
129 int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
130 {
131         int i, err;
132
133         if (parent->comm_set) {
134                 const char *comm = thread__comm_str(parent);
135                 if (!comm)
136                         return -ENOMEM;
137                 err = thread__set_comm(thread, comm, timestamp);
138                 if (err)
139                         return err;
140                 thread->comm_set = true;
141         }
142
143         for (i = 0; i < MAP__NR_TYPES; ++i)
144                 if (map_groups__clone(thread->mg, parent->mg, i) < 0)
145                         return -ENOMEM;
146
147         thread->ppid = parent->tid;
148
149         return 0;
150 }
151
152 void thread__find_cpumode_addr_location(struct thread *thread,
153                                         struct machine *machine,
154                                         enum map_type type, u64 addr,
155                                         struct addr_location *al)
156 {
157         size_t i;
158         const u8 const cpumodes[] = {
159                 PERF_RECORD_MISC_USER,
160                 PERF_RECORD_MISC_KERNEL,
161                 PERF_RECORD_MISC_GUEST_USER,
162                 PERF_RECORD_MISC_GUEST_KERNEL
163         };
164
165         for (i = 0; i < ARRAY_SIZE(cpumodes); i++) {
166                 thread__find_addr_location(thread, machine, cpumodes[i], type,
167                                            addr, al);
168                 if (al->map)
169                         break;
170         }
171 }