6893eec693abad5ad8e5af88f1c8ee107c63e713
[linux-3.10.git] / tools / perf / util / cpumap.c
1 #include "util.h"
2 #include "../perf.h"
3 #include "cpumap.h"
4 #include <assert.h>
5 #include <stdio.h>
6
7 static struct cpu_map *cpu_map__default_new(void)
8 {
9         struct cpu_map *cpus;
10         int nr_cpus;
11
12         nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
13         if (nr_cpus < 0)
14                 return NULL;
15
16         cpus = malloc(sizeof(*cpus) + nr_cpus * sizeof(int));
17         if (cpus != NULL) {
18                 int i;
19                 for (i = 0; i < nr_cpus; ++i)
20                         cpus->map[i] = i;
21
22                 cpus->nr = nr_cpus;
23         }
24
25         return cpus;
26 }
27
28 static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus)
29 {
30         size_t payload_size = nr_cpus * sizeof(int);
31         struct cpu_map *cpus = malloc(sizeof(*cpus) + payload_size);
32
33         if (cpus != NULL) {
34                 cpus->nr = nr_cpus;
35                 memcpy(cpus->map, tmp_cpus, payload_size);
36         }
37
38         return cpus;
39 }
40
41 static struct cpu_map *cpu_map__read_all_cpu_map(void)
42 {
43         struct cpu_map *cpus = NULL;
44         FILE *onlnf;
45         int nr_cpus = 0;
46         int *tmp_cpus = NULL, *tmp;
47         int max_entries = 0;
48         int n, cpu, prev;
49         char sep;
50
51         onlnf = fopen("/sys/devices/system/cpu/online", "r");
52         if (!onlnf)
53                 return cpu_map__default_new();
54
55         sep = 0;
56         prev = -1;
57         for (;;) {
58                 n = fscanf(onlnf, "%u%c", &cpu, &sep);
59                 if (n <= 0)
60                         break;
61                 if (prev >= 0) {
62                         int new_max = nr_cpus + cpu - prev - 1;
63
64                         if (new_max >= max_entries) {
65                                 max_entries = new_max + MAX_NR_CPUS / 2;
66                                 tmp = realloc(tmp_cpus, max_entries * sizeof(int));
67                                 if (tmp == NULL)
68                                         goto out_free_tmp;
69                                 tmp_cpus = tmp;
70                         }
71
72                         while (++prev < cpu)
73                                 tmp_cpus[nr_cpus++] = prev;
74                 }
75                 if (nr_cpus == max_entries) {
76                         max_entries += MAX_NR_CPUS;
77                         tmp = realloc(tmp_cpus, max_entries * sizeof(int));
78                         if (tmp == NULL)
79                                 goto out_free_tmp;
80                         tmp_cpus = tmp;
81                 }
82
83                 tmp_cpus[nr_cpus++] = cpu;
84                 if (n == 2 && sep == '-')
85                         prev = cpu;
86                 else
87                         prev = -1;
88                 if (n == 1 || sep == '\n')
89                         break;
90         }
91
92         if (nr_cpus > 0)
93                 cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
94         else
95                 cpus = cpu_map__default_new();
96 out_free_tmp:
97         free(tmp_cpus);
98         fclose(onlnf);
99         return cpus;
100 }
101
102 struct cpu_map *cpu_map__new(const char *cpu_list)
103 {
104         struct cpu_map *cpus = NULL;
105         unsigned long start_cpu, end_cpu = 0;
106         char *p = NULL;
107         int i, nr_cpus = 0;
108         int *tmp_cpus = NULL, *tmp;
109         int max_entries = 0;
110
111         if (!cpu_list)
112                 return cpu_map__read_all_cpu_map();
113
114         if (!isdigit(*cpu_list))
115                 goto out;
116
117         while (isdigit(*cpu_list)) {
118                 p = NULL;
119                 start_cpu = strtoul(cpu_list, &p, 0);
120                 if (start_cpu >= INT_MAX
121                     || (*p != '\0' && *p != ',' && *p != '-'))
122                         goto invalid;
123
124                 if (*p == '-') {
125                         cpu_list = ++p;
126                         p = NULL;
127                         end_cpu = strtoul(cpu_list, &p, 0);
128
129                         if (end_cpu >= INT_MAX || (*p != '\0' && *p != ','))
130                                 goto invalid;
131
132                         if (end_cpu < start_cpu)
133                                 goto invalid;
134                 } else {
135                         end_cpu = start_cpu;
136                 }
137
138                 for (; start_cpu <= end_cpu; start_cpu++) {
139                         /* check for duplicates */
140                         for (i = 0; i < nr_cpus; i++)
141                                 if (tmp_cpus[i] == (int)start_cpu)
142                                         goto invalid;
143
144                         if (nr_cpus == max_entries) {
145                                 max_entries += MAX_NR_CPUS;
146                                 tmp = realloc(tmp_cpus, max_entries * sizeof(int));
147                                 if (tmp == NULL)
148                                         goto invalid;
149                                 tmp_cpus = tmp;
150                         }
151                         tmp_cpus[nr_cpus++] = (int)start_cpu;
152                 }
153                 if (*p)
154                         ++p;
155
156                 cpu_list = p;
157         }
158
159         if (nr_cpus > 0)
160                 cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
161         else
162                 cpus = cpu_map__default_new();
163 invalid:
164         free(tmp_cpus);
165 out:
166         return cpus;
167 }
168
169 struct cpu_map *cpu_map__dummy_new(void)
170 {
171         struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int));
172
173         if (cpus != NULL) {
174                 cpus->nr = 1;
175                 cpus->map[0] = -1;
176         }
177
178         return cpus;
179 }
180
181 void cpu_map__delete(struct cpu_map *map)
182 {
183         free(map);
184 }