Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / tools / perf / util / cpumap.c
1 #include "util.h"
2 #include <api/fs/fs.h>
3 #include "../perf.h"
4 #include "cpumap.h"
5 #include <assert.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8
9 static struct cpu_map *cpu_map__default_new(void)
10 {
11         struct cpu_map *cpus;
12         int nr_cpus;
13
14         nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
15         if (nr_cpus < 0)
16                 return NULL;
17
18         cpus = malloc(sizeof(*cpus) + nr_cpus * sizeof(int));
19         if (cpus != NULL) {
20                 int i;
21                 for (i = 0; i < nr_cpus; ++i)
22                         cpus->map[i] = i;
23
24                 cpus->nr = nr_cpus;
25         }
26
27         return cpus;
28 }
29
30 static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus)
31 {
32         size_t payload_size = nr_cpus * sizeof(int);
33         struct cpu_map *cpus = malloc(sizeof(*cpus) + payload_size);
34
35         if (cpus != NULL) {
36                 cpus->nr = nr_cpus;
37                 memcpy(cpus->map, tmp_cpus, payload_size);
38         }
39
40         return cpus;
41 }
42
43 struct cpu_map *cpu_map__read(FILE *file)
44 {
45         struct cpu_map *cpus = NULL;
46         int nr_cpus = 0;
47         int *tmp_cpus = NULL, *tmp;
48         int max_entries = 0;
49         int n, cpu, prev;
50         char sep;
51
52         sep = 0;
53         prev = -1;
54         for (;;) {
55                 n = fscanf(file, "%u%c", &cpu, &sep);
56                 if (n <= 0)
57                         break;
58                 if (prev >= 0) {
59                         int new_max = nr_cpus + cpu - prev - 1;
60
61                         if (new_max >= max_entries) {
62                                 max_entries = new_max + MAX_NR_CPUS / 2;
63                                 tmp = realloc(tmp_cpus, max_entries * sizeof(int));
64                                 if (tmp == NULL)
65                                         goto out_free_tmp;
66                                 tmp_cpus = tmp;
67                         }
68
69                         while (++prev < cpu)
70                                 tmp_cpus[nr_cpus++] = prev;
71                 }
72                 if (nr_cpus == max_entries) {
73                         max_entries += MAX_NR_CPUS;
74                         tmp = realloc(tmp_cpus, max_entries * sizeof(int));
75                         if (tmp == NULL)
76                                 goto out_free_tmp;
77                         tmp_cpus = tmp;
78                 }
79
80                 tmp_cpus[nr_cpus++] = cpu;
81                 if (n == 2 && sep == '-')
82                         prev = cpu;
83                 else
84                         prev = -1;
85                 if (n == 1 || sep == '\n')
86                         break;
87         }
88
89         if (nr_cpus > 0)
90                 cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
91         else
92                 cpus = cpu_map__default_new();
93 out_free_tmp:
94         free(tmp_cpus);
95         return cpus;
96 }
97
98 static struct cpu_map *cpu_map__read_all_cpu_map(void)
99 {
100         struct cpu_map *cpus = NULL;
101         FILE *onlnf;
102
103         onlnf = fopen("/sys/devices/system/cpu/online", "r");
104         if (!onlnf)
105                 return cpu_map__default_new();
106
107         cpus = cpu_map__read(onlnf);
108         fclose(onlnf);
109         return cpus;
110 }
111
112 struct cpu_map *cpu_map__new(const char *cpu_list)
113 {
114         struct cpu_map *cpus = NULL;
115         unsigned long start_cpu, end_cpu = 0;
116         char *p = NULL;
117         int i, nr_cpus = 0;
118         int *tmp_cpus = NULL, *tmp;
119         int max_entries = 0;
120
121         if (!cpu_list)
122                 return cpu_map__read_all_cpu_map();
123
124         if (!isdigit(*cpu_list))
125                 goto out;
126
127         while (isdigit(*cpu_list)) {
128                 p = NULL;
129                 start_cpu = strtoul(cpu_list, &p, 0);
130                 if (start_cpu >= INT_MAX
131                     || (*p != '\0' && *p != ',' && *p != '-'))
132                         goto invalid;
133
134                 if (*p == '-') {
135                         cpu_list = ++p;
136                         p = NULL;
137                         end_cpu = strtoul(cpu_list, &p, 0);
138
139                         if (end_cpu >= INT_MAX || (*p != '\0' && *p != ','))
140                                 goto invalid;
141
142                         if (end_cpu < start_cpu)
143                                 goto invalid;
144                 } else {
145                         end_cpu = start_cpu;
146                 }
147
148                 for (; start_cpu <= end_cpu; start_cpu++) {
149                         /* check for duplicates */
150                         for (i = 0; i < nr_cpus; i++)
151                                 if (tmp_cpus[i] == (int)start_cpu)
152                                         goto invalid;
153
154                         if (nr_cpus == max_entries) {
155                                 max_entries += MAX_NR_CPUS;
156                                 tmp = realloc(tmp_cpus, max_entries * sizeof(int));
157                                 if (tmp == NULL)
158                                         goto invalid;
159                                 tmp_cpus = tmp;
160                         }
161                         tmp_cpus[nr_cpus++] = (int)start_cpu;
162                 }
163                 if (*p)
164                         ++p;
165
166                 cpu_list = p;
167         }
168
169         if (nr_cpus > 0)
170                 cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
171         else
172                 cpus = cpu_map__default_new();
173 invalid:
174         free(tmp_cpus);
175 out:
176         return cpus;
177 }
178
179 size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp)
180 {
181         int i;
182         size_t printed = fprintf(fp, "%d cpu%s: ",
183                                  map->nr, map->nr > 1 ? "s" : "");
184         for (i = 0; i < map->nr; ++i)
185                 printed += fprintf(fp, "%s%d", i ? ", " : "", map->map[i]);
186
187         return printed + fprintf(fp, "\n");
188 }
189
190 struct cpu_map *cpu_map__dummy_new(void)
191 {
192         struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int));
193
194         if (cpus != NULL) {
195                 cpus->nr = 1;
196                 cpus->map[0] = -1;
197         }
198
199         return cpus;
200 }
201
202 void cpu_map__delete(struct cpu_map *map)
203 {
204         free(map);
205 }
206
207 int cpu_map__get_socket(struct cpu_map *map, int idx)
208 {
209         FILE *fp;
210         const char *mnt;
211         char path[PATH_MAX];
212         int cpu, ret;
213
214         if (idx > map->nr)
215                 return -1;
216
217         cpu = map->map[idx];
218
219         mnt = sysfs__mountpoint();
220         if (!mnt)
221                 return -1;
222
223         snprintf(path, PATH_MAX,
224                 "%s/devices/system/cpu/cpu%d/topology/physical_package_id",
225                 mnt, cpu);
226
227         fp = fopen(path, "r");
228         if (!fp)
229                 return -1;
230         ret = fscanf(fp, "%d", &cpu);
231         fclose(fp);
232         return ret == 1 ? cpu : -1;
233 }
234
235 static int cmp_ids(const void *a, const void *b)
236 {
237         return *(int *)a - *(int *)b;
238 }
239
240 static int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res,
241                               int (*f)(struct cpu_map *map, int cpu))
242 {
243         struct cpu_map *c;
244         int nr = cpus->nr;
245         int cpu, s1, s2;
246
247         /* allocate as much as possible */
248         c = calloc(1, sizeof(*c) + nr * sizeof(int));
249         if (!c)
250                 return -1;
251
252         for (cpu = 0; cpu < nr; cpu++) {
253                 s1 = f(cpus, cpu);
254                 for (s2 = 0; s2 < c->nr; s2++) {
255                         if (s1 == c->map[s2])
256                                 break;
257                 }
258                 if (s2 == c->nr) {
259                         c->map[c->nr] = s1;
260                         c->nr++;
261                 }
262         }
263         /* ensure we process id in increasing order */
264         qsort(c->map, c->nr, sizeof(int), cmp_ids);
265
266         *res = c;
267         return 0;
268 }
269
270 int cpu_map__get_core(struct cpu_map *map, int idx)
271 {
272         FILE *fp;
273         const char *mnt;
274         char path[PATH_MAX];
275         int cpu, ret, s;
276
277         if (idx > map->nr)
278                 return -1;
279
280         cpu = map->map[idx];
281
282         mnt = sysfs__mountpoint();
283         if (!mnt)
284                 return -1;
285
286         snprintf(path, PATH_MAX,
287                 "%s/devices/system/cpu/cpu%d/topology/core_id",
288                 mnt, cpu);
289
290         fp = fopen(path, "r");
291         if (!fp)
292                 return -1;
293         ret = fscanf(fp, "%d", &cpu);
294         fclose(fp);
295         if (ret != 1)
296                 return -1;
297
298         s = cpu_map__get_socket(map, idx);
299         if (s == -1)
300                 return -1;
301
302         /*
303          * encode socket in upper 16 bits
304          * core_id is relative to socket, and
305          * we need a global id. So we combine
306          * socket+ core id
307          */
308         return (s << 16) | (cpu & 0xffff);
309 }
310
311 int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp)
312 {
313         return cpu_map__build_map(cpus, sockp, cpu_map__get_socket);
314 }
315
316 int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep)
317 {
318         return cpu_map__build_map(cpus, corep, cpu_map__get_core);
319 }
320
321 /* setup simple routines to easily access node numbers given a cpu number */
322 static int get_max_num(char *path, int *max)
323 {
324         size_t num;
325         char *buf;
326         int err = 0;
327
328         if (filename__read_str(path, &buf, &num))
329                 return -1;
330
331         buf[num] = '\0';
332
333         /* start on the right, to find highest node num */
334         while (--num) {
335                 if ((buf[num] == ',') || (buf[num] == '-')) {
336                         num++;
337                         break;
338                 }
339         }
340         if (sscanf(&buf[num], "%d", max) < 1) {
341                 err = -1;
342                 goto out;
343         }
344
345         /* convert from 0-based to 1-based */
346         (*max)++;
347
348 out:
349         free(buf);
350         return err;
351 }
352
353 /* Determine highest possible cpu in the system for sparse allocation */
354 static void set_max_cpu_num(void)
355 {
356         const char *mnt;
357         char path[PATH_MAX];
358         int ret = -1;
359
360         /* set up default */
361         max_cpu_num = 4096;
362
363         mnt = sysfs__mountpoint();
364         if (!mnt)
365                 goto out;
366
367         /* get the highest possible cpu number for a sparse allocation */
368         ret = snprintf(path, PATH_MAX, "%s/devices/system/cpu/possible", mnt);
369         if (ret == PATH_MAX) {
370                 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
371                 goto out;
372         }
373
374         ret = get_max_num(path, &max_cpu_num);
375
376 out:
377         if (ret)
378                 pr_err("Failed to read max cpus, using default of %d\n", max_cpu_num);
379 }
380
381 /* Determine highest possible node in the system for sparse allocation */
382 static void set_max_node_num(void)
383 {
384         const char *mnt;
385         char path[PATH_MAX];
386         int ret = -1;
387
388         /* set up default */
389         max_node_num = 8;
390
391         mnt = sysfs__mountpoint();
392         if (!mnt)
393                 goto out;
394
395         /* get the highest possible cpu number for a sparse allocation */
396         ret = snprintf(path, PATH_MAX, "%s/devices/system/node/possible", mnt);
397         if (ret == PATH_MAX) {
398                 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
399                 goto out;
400         }
401
402         ret = get_max_num(path, &max_node_num);
403
404 out:
405         if (ret)
406                 pr_err("Failed to read max nodes, using default of %d\n", max_node_num);
407 }
408
409 static int init_cpunode_map(void)
410 {
411         int i;
412
413         set_max_cpu_num();
414         set_max_node_num();
415
416         cpunode_map = calloc(max_cpu_num, sizeof(int));
417         if (!cpunode_map) {
418                 pr_err("%s: calloc failed\n", __func__);
419                 return -1;
420         }
421
422         for (i = 0; i < max_cpu_num; i++)
423                 cpunode_map[i] = -1;
424
425         return 0;
426 }
427
428 int cpu__setup_cpunode_map(void)
429 {
430         struct dirent *dent1, *dent2;
431         DIR *dir1, *dir2;
432         unsigned int cpu, mem;
433         char buf[PATH_MAX];
434         char path[PATH_MAX];
435         const char *mnt;
436         int n;
437
438         /* initialize globals */
439         if (init_cpunode_map())
440                 return -1;
441
442         mnt = sysfs__mountpoint();
443         if (!mnt)
444                 return 0;
445
446         n = snprintf(path, PATH_MAX, "%s/devices/system/node", mnt);
447         if (n == PATH_MAX) {
448                 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
449                 return -1;
450         }
451
452         dir1 = opendir(path);
453         if (!dir1)
454                 return 0;
455
456         /* walk tree and setup map */
457         while ((dent1 = readdir(dir1)) != NULL) {
458                 if (dent1->d_type != DT_DIR || sscanf(dent1->d_name, "node%u", &mem) < 1)
459                         continue;
460
461                 n = snprintf(buf, PATH_MAX, "%s/%s", path, dent1->d_name);
462                 if (n == PATH_MAX) {
463                         pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
464                         continue;
465                 }
466
467                 dir2 = opendir(buf);
468                 if (!dir2)
469                         continue;
470                 while ((dent2 = readdir(dir2)) != NULL) {
471                         if (dent2->d_type != DT_LNK || sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
472                                 continue;
473                         cpunode_map[cpu] = mem;
474                 }
475                 closedir(dir2);
476         }
477         closedir(dir1);
478         return 0;
479 }