]> Pileus Git - ~andy/linux/blob - tools/perf/util/cpumap.c
Merge tag 'disintegrate-sh-20121009' of git://git.infradead.org/users/dhowells/linux...
[~andy/linux] / 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 struct cpu_map *cpu_map__read(FILE *file)
42 {
43         struct cpu_map *cpus = NULL;
44         int nr_cpus = 0;
45         int *tmp_cpus = NULL, *tmp;
46         int max_entries = 0;
47         int n, cpu, prev;
48         char sep;
49
50         sep = 0;
51         prev = -1;
52         for (;;) {
53                 n = fscanf(file, "%u%c", &cpu, &sep);
54                 if (n <= 0)
55                         break;
56                 if (prev >= 0) {
57                         int new_max = nr_cpus + cpu - prev - 1;
58
59                         if (new_max >= max_entries) {
60                                 max_entries = new_max + MAX_NR_CPUS / 2;
61                                 tmp = realloc(tmp_cpus, max_entries * sizeof(int));
62                                 if (tmp == NULL)
63                                         goto out_free_tmp;
64                                 tmp_cpus = tmp;
65                         }
66
67                         while (++prev < cpu)
68                                 tmp_cpus[nr_cpus++] = prev;
69                 }
70                 if (nr_cpus == max_entries) {
71                         max_entries += MAX_NR_CPUS;
72                         tmp = realloc(tmp_cpus, max_entries * sizeof(int));
73                         if (tmp == NULL)
74                                 goto out_free_tmp;
75                         tmp_cpus = tmp;
76                 }
77
78                 tmp_cpus[nr_cpus++] = cpu;
79                 if (n == 2 && sep == '-')
80                         prev = cpu;
81                 else
82                         prev = -1;
83                 if (n == 1 || sep == '\n')
84                         break;
85         }
86
87         if (nr_cpus > 0)
88                 cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
89         else
90                 cpus = cpu_map__default_new();
91 out_free_tmp:
92         free(tmp_cpus);
93         return cpus;
94 }
95
96 static struct cpu_map *cpu_map__read_all_cpu_map(void)
97 {
98         struct cpu_map *cpus = NULL;
99         FILE *onlnf;
100
101         onlnf = fopen("/sys/devices/system/cpu/online", "r");
102         if (!onlnf)
103                 return cpu_map__default_new();
104
105         cpus = cpu_map__read(onlnf);
106         fclose(onlnf);
107         return cpus;
108 }
109
110 struct cpu_map *cpu_map__new(const char *cpu_list)
111 {
112         struct cpu_map *cpus = NULL;
113         unsigned long start_cpu, end_cpu = 0;
114         char *p = NULL;
115         int i, nr_cpus = 0;
116         int *tmp_cpus = NULL, *tmp;
117         int max_entries = 0;
118
119         if (!cpu_list)
120                 return cpu_map__read_all_cpu_map();
121
122         if (!isdigit(*cpu_list))
123                 goto out;
124
125         while (isdigit(*cpu_list)) {
126                 p = NULL;
127                 start_cpu = strtoul(cpu_list, &p, 0);
128                 if (start_cpu >= INT_MAX
129                     || (*p != '\0' && *p != ',' && *p != '-'))
130                         goto invalid;
131
132                 if (*p == '-') {
133                         cpu_list = ++p;
134                         p = NULL;
135                         end_cpu = strtoul(cpu_list, &p, 0);
136
137                         if (end_cpu >= INT_MAX || (*p != '\0' && *p != ','))
138                                 goto invalid;
139
140                         if (end_cpu < start_cpu)
141                                 goto invalid;
142                 } else {
143                         end_cpu = start_cpu;
144                 }
145
146                 for (; start_cpu <= end_cpu; start_cpu++) {
147                         /* check for duplicates */
148                         for (i = 0; i < nr_cpus; i++)
149                                 if (tmp_cpus[i] == (int)start_cpu)
150                                         goto invalid;
151
152                         if (nr_cpus == max_entries) {
153                                 max_entries += MAX_NR_CPUS;
154                                 tmp = realloc(tmp_cpus, max_entries * sizeof(int));
155                                 if (tmp == NULL)
156                                         goto invalid;
157                                 tmp_cpus = tmp;
158                         }
159                         tmp_cpus[nr_cpus++] = (int)start_cpu;
160                 }
161                 if (*p)
162                         ++p;
163
164                 cpu_list = p;
165         }
166
167         if (nr_cpus > 0)
168                 cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
169         else
170                 cpus = cpu_map__default_new();
171 invalid:
172         free(tmp_cpus);
173 out:
174         return cpus;
175 }
176
177 size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp)
178 {
179         int i;
180         size_t printed = fprintf(fp, "%d cpu%s: ",
181                                  map->nr, map->nr > 1 ? "s" : "");
182         for (i = 0; i < map->nr; ++i)
183                 printed += fprintf(fp, "%s%d", i ? ", " : "", map->map[i]);
184
185         return printed + fprintf(fp, "\n");
186 }
187
188 struct cpu_map *cpu_map__dummy_new(void)
189 {
190         struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int));
191
192         if (cpus != NULL) {
193                 cpus->nr = 1;
194                 cpus->map[0] = -1;
195         }
196
197         return cpus;
198 }
199
200 void cpu_map__delete(struct cpu_map *map)
201 {
202         free(map);
203 }