Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-block.git] / tools / perf / util / thread_map.c
CommitLineData
fd78260b 1#include <dirent.h>
0d37aa34
ACM
2#include <limits.h>
3#include <stdbool.h>
fd78260b
ACM
4#include <stdlib.h>
5#include <stdio.h>
0d37aa34
ACM
6#include <sys/types.h>
7#include <sys/stat.h>
8#include <unistd.h>
b52956c9
DA
9#include "strlist.h"
10#include <string.h>
fd78260b 11#include "thread_map.h"
04662523 12#include "util.h"
fd78260b
ACM
13
14/* Skip "." and ".." directories */
15static int filter(const struct dirent *dir)
16{
17 if (dir->d_name[0] == '.')
18 return 0;
19 else
20 return 1;
21}
22
9d7e8c3a
JO
23static struct thread_map *thread_map__realloc(struct thread_map *map, int nr)
24{
25 size_t size = sizeof(*map) + sizeof(pid_t) * nr;
26
27 return realloc(map, size);
28}
29
30#define thread_map__alloc(__nr) thread_map__realloc(NULL, __nr)
31
fd78260b
ACM
32struct thread_map *thread_map__new_by_pid(pid_t pid)
33{
34 struct thread_map *threads;
35 char name[256];
36 int items;
37 struct dirent **namelist = NULL;
38 int i;
39
40 sprintf(name, "/proc/%d/task", pid);
41 items = scandir(name, &namelist, filter, NULL);
42 if (items <= 0)
0d37aa34 43 return NULL;
fd78260b 44
9d7e8c3a 45 threads = thread_map__alloc(items);
fd78260b
ACM
46 if (threads != NULL) {
47 for (i = 0; i < items; i++)
e13798c7 48 thread_map__set_pid(threads, i, atoi(namelist[i]->d_name));
fd78260b
ACM
49 threads->nr = items;
50 }
51
52 for (i=0; i<items; i++)
74cf249d 53 zfree(&namelist[i]);
fd78260b
ACM
54 free(namelist);
55
56 return threads;
57}
58
59struct thread_map *thread_map__new_by_tid(pid_t tid)
60{
9d7e8c3a 61 struct thread_map *threads = thread_map__alloc(1);
fd78260b
ACM
62
63 if (threads != NULL) {
e13798c7
JO
64 thread_map__set_pid(threads, 0, tid);
65 threads->nr = 1;
fd78260b
ACM
66 }
67
68 return threads;
69}
70
0d37aa34
ACM
71struct thread_map *thread_map__new_by_uid(uid_t uid)
72{
73 DIR *proc;
74 int max_threads = 32, items, i;
75 char path[256];
76 struct dirent dirent, *next, **namelist = NULL;
9d7e8c3a
JO
77 struct thread_map *threads = thread_map__alloc(max_threads);
78
0d37aa34
ACM
79 if (threads == NULL)
80 goto out;
81
82 proc = opendir("/proc");
83 if (proc == NULL)
84 goto out_free_threads;
85
86 threads->nr = 0;
87
88 while (!readdir_r(proc, &dirent, &next) && next) {
89 char *end;
90 bool grow = false;
91 struct stat st;
92 pid_t pid = strtol(dirent.d_name, &end, 10);
93
94 if (*end) /* only interested in proper numerical dirents */
95 continue;
96
97 snprintf(path, sizeof(path), "/proc/%s", dirent.d_name);
98
99 if (stat(path, &st) != 0)
100 continue;
101
102 if (st.st_uid != uid)
103 continue;
104
105 snprintf(path, sizeof(path), "/proc/%d/task", pid);
106 items = scandir(path, &namelist, filter, NULL);
107 if (items <= 0)
108 goto out_free_closedir;
109
110 while (threads->nr + items >= max_threads) {
111 max_threads *= 2;
112 grow = true;
113 }
114
115 if (grow) {
116 struct thread_map *tmp;
117
118 tmp = realloc(threads, (sizeof(*threads) +
119 max_threads * sizeof(pid_t)));
120 if (tmp == NULL)
121 goto out_free_namelist;
122
123 threads = tmp;
124 }
125
e13798c7
JO
126 for (i = 0; i < items; i++) {
127 thread_map__set_pid(threads, threads->nr + i,
128 atoi(namelist[i]->d_name));
129 }
0d37aa34
ACM
130
131 for (i = 0; i < items; i++)
74cf249d 132 zfree(&namelist[i]);
0d37aa34
ACM
133 free(namelist);
134
135 threads->nr += items;
136 }
137
138out_closedir:
139 closedir(proc);
140out:
141 return threads;
142
143out_free_threads:
144 free(threads);
145 return NULL;
146
147out_free_namelist:
148 for (i = 0; i < items; i++)
74cf249d 149 zfree(&namelist[i]);
0d37aa34
ACM
150 free(namelist);
151
152out_free_closedir:
04662523 153 zfree(&threads);
0d37aa34
ACM
154 goto out_closedir;
155}
156
157struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid)
fd78260b
ACM
158{
159 if (pid != -1)
160 return thread_map__new_by_pid(pid);
0d37aa34
ACM
161
162 if (tid == -1 && uid != UINT_MAX)
163 return thread_map__new_by_uid(uid);
164
fd78260b
ACM
165 return thread_map__new_by_tid(tid);
166}
167
b52956c9
DA
168static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
169{
170 struct thread_map *threads = NULL, *nt;
171 char name[256];
172 int items, total_tasks = 0;
173 struct dirent **namelist = NULL;
174 int i, j = 0;
175 pid_t pid, prev_pid = INT_MAX;
176 char *end_ptr;
177 struct str_node *pos;
178 struct strlist *slist = strlist__new(false, pid_str);
179
180 if (!slist)
181 return NULL;
182
183 strlist__for_each(pos, slist) {
184 pid = strtol(pos->s, &end_ptr, 10);
185
186 if (pid == INT_MIN || pid == INT_MAX ||
187 (*end_ptr != '\0' && *end_ptr != ','))
188 goto out_free_threads;
189
190 if (pid == prev_pid)
191 continue;
192
193 sprintf(name, "/proc/%d/task", pid);
194 items = scandir(name, &namelist, filter, NULL);
195 if (items <= 0)
196 goto out_free_threads;
197
198 total_tasks += items;
9d7e8c3a 199 nt = thread_map__realloc(threads, total_tasks);
b52956c9 200 if (nt == NULL)
e8cdd947 201 goto out_free_namelist;
b52956c9
DA
202
203 threads = nt;
204
e8cdd947 205 for (i = 0; i < items; i++) {
e13798c7 206 thread_map__set_pid(threads, j++, atoi(namelist[i]->d_name));
74cf249d 207 zfree(&namelist[i]);
e8cdd947
FBH
208 }
209 threads->nr = total_tasks;
b52956c9 210 free(namelist);
b52956c9
DA
211 }
212
213out:
214 strlist__delete(slist);
215 return threads;
216
e8cdd947
FBH
217out_free_namelist:
218 for (i = 0; i < items; i++)
74cf249d 219 zfree(&namelist[i]);
e8cdd947
FBH
220 free(namelist);
221
b52956c9 222out_free_threads:
04662523 223 zfree(&threads);
b52956c9
DA
224 goto out;
225}
226
641556c9
ACM
227struct thread_map *thread_map__new_dummy(void)
228{
9d7e8c3a 229 struct thread_map *threads = thread_map__alloc(1);
641556c9
ACM
230
231 if (threads != NULL) {
e13798c7
JO
232 thread_map__set_pid(threads, 0, -1);
233 threads->nr = 1;
641556c9
ACM
234 }
235 return threads;
236}
237
b52956c9
DA
238static struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
239{
240 struct thread_map *threads = NULL, *nt;
241 int ntasks = 0;
242 pid_t tid, prev_tid = INT_MAX;
243 char *end_ptr;
244 struct str_node *pos;
245 struct strlist *slist;
246
247 /* perf-stat expects threads to be generated even if tid not given */
641556c9
ACM
248 if (!tid_str)
249 return thread_map__new_dummy();
b52956c9
DA
250
251 slist = strlist__new(false, tid_str);
252 if (!slist)
253 return NULL;
254
255 strlist__for_each(pos, slist) {
256 tid = strtol(pos->s, &end_ptr, 10);
257
258 if (tid == INT_MIN || tid == INT_MAX ||
259 (*end_ptr != '\0' && *end_ptr != ','))
260 goto out_free_threads;
261
262 if (tid == prev_tid)
263 continue;
264
265 ntasks++;
9d7e8c3a 266 nt = thread_map__realloc(threads, ntasks);
b52956c9
DA
267
268 if (nt == NULL)
269 goto out_free_threads;
270
271 threads = nt;
e13798c7
JO
272 thread_map__set_pid(threads, ntasks - 1, tid);
273 threads->nr = ntasks;
b52956c9
DA
274 }
275out:
276 return threads;
277
278out_free_threads:
04662523 279 zfree(&threads);
b52956c9
DA
280 goto out;
281}
282
283struct thread_map *thread_map__new_str(const char *pid, const char *tid,
284 uid_t uid)
285{
286 if (pid)
287 return thread_map__new_by_pid_str(pid);
288
289 if (!tid && uid != UINT_MAX)
290 return thread_map__new_by_uid(uid);
291
292 return thread_map__new_by_tid_str(tid);
293}
294
fd78260b
ACM
295void thread_map__delete(struct thread_map *threads)
296{
297 free(threads);
298}
9ae7d335
ACM
299
300size_t thread_map__fprintf(struct thread_map *threads, FILE *fp)
301{
302 int i;
303 size_t printed = fprintf(fp, "%d thread%s: ",
304 threads->nr, threads->nr > 1 ? "s" : "");
305 for (i = 0; i < threads->nr; ++i)
e13798c7 306 printed += fprintf(fp, "%s%d", i ? ", " : "", thread_map__pid(threads, i));
9ae7d335
ACM
307
308 return printed + fprintf(fp, "\n");
309}