blob: 2b32ffa9ebdb188e8edeb31fc4176380d99b2337 [file] [log] [blame]
Paul Mackerrasa12b51c2010-03-10 20:36:09 +11001#include "util.h"
2#include "../perf.h"
3#include "cpumap.h"
4#include <assert.h>
5#include <stdio.h>
6
Arnaldo Carvalho de Melo60d567e2011-01-03 17:49:48 -02007static struct cpu_map *cpu_map__default_new(void)
Paul Mackerrasa12b51c2010-03-10 20:36:09 +11008{
Arnaldo Carvalho de Melo60d567e2011-01-03 17:49:48 -02009 struct cpu_map *cpus;
10 int nr_cpus;
Paul Mackerrasa12b51c2010-03-10 20:36:09 +110011
12 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
Arnaldo Carvalho de Melo60d567e2011-01-03 17:49:48 -020013 if (nr_cpus < 0)
14 return NULL;
Paul Mackerrasa12b51c2010-03-10 20:36:09 +110015
Arnaldo Carvalho de Melo60d567e2011-01-03 17:49:48 -020016 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;
Paul Mackerrasa12b51c2010-03-10 20:36:09 +110021
Arnaldo Carvalho de Melo60d567e2011-01-03 17:49:48 -020022 cpus->nr = nr_cpus;
23 }
24
25 return cpus;
Paul Mackerrasa12b51c2010-03-10 20:36:09 +110026}
27
Arnaldo Carvalho de Melo60d567e2011-01-03 17:49:48 -020028static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus)
Paul Mackerrasa12b51c2010-03-10 20:36:09 +110029{
Arnaldo Carvalho de Melo60d567e2011-01-03 17:49:48 -020030 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
Yan, Zheng7ae92e72012-09-10 15:53:50 +080041struct cpu_map *cpu_map__read(FILE *file)
Arnaldo Carvalho de Melo60d567e2011-01-03 17:49:48 -020042{
43 struct cpu_map *cpus = NULL;
Paul Mackerrasa12b51c2010-03-10 20:36:09 +110044 int nr_cpus = 0;
Arnaldo Carvalho de Melo60d567e2011-01-03 17:49:48 -020045 int *tmp_cpus = NULL, *tmp;
46 int max_entries = 0;
Paul Mackerrasa12b51c2010-03-10 20:36:09 +110047 int n, cpu, prev;
48 char sep;
49
Paul Mackerrasa12b51c2010-03-10 20:36:09 +110050 sep = 0;
51 prev = -1;
52 for (;;) {
Yan, Zheng7ae92e72012-09-10 15:53:50 +080053 n = fscanf(file, "%u%c", &cpu, &sep);
Paul Mackerrasa12b51c2010-03-10 20:36:09 +110054 if (n <= 0)
55 break;
56 if (prev >= 0) {
Arnaldo Carvalho de Melo60d567e2011-01-03 17:49:48 -020057 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
Paul Mackerrasa12b51c2010-03-10 20:36:09 +110067 while (++prev < cpu)
Arnaldo Carvalho de Melo60d567e2011-01-03 17:49:48 -020068 tmp_cpus[nr_cpus++] = prev;
Paul Mackerrasa12b51c2010-03-10 20:36:09 +110069 }
Arnaldo Carvalho de Melo60d567e2011-01-03 17:49:48 -020070 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;
Paul Mackerrasa12b51c2010-03-10 20:36:09 +110079 if (n == 2 && sep == '-')
80 prev = cpu;
81 else
82 prev = -1;
83 if (n == 1 || sep == '\n')
84 break;
85 }
Paul Mackerrasa12b51c2010-03-10 20:36:09 +110086
Arnaldo Carvalho de Melo60d567e2011-01-03 17:49:48 -020087 if (nr_cpus > 0)
88 cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
89 else
90 cpus = cpu_map__default_new();
91out_free_tmp:
92 free(tmp_cpus);
Yan, Zheng7ae92e72012-09-10 15:53:50 +080093 return cpus;
94}
95
96static 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);
Arnaldo Carvalho de Melo60d567e2011-01-03 17:49:48 -0200106 fclose(onlnf);
107 return cpus;
Paul Mackerrasa12b51c2010-03-10 20:36:09 +1100108}
Stephane Eranianc45c6ea2010-05-28 12:00:01 +0200109
Arnaldo Carvalho de Melo60d567e2011-01-03 17:49:48 -0200110struct cpu_map *cpu_map__new(const char *cpu_list)
Stephane Eranianc45c6ea2010-05-28 12:00:01 +0200111{
Arnaldo Carvalho de Melo60d567e2011-01-03 17:49:48 -0200112 struct cpu_map *cpus = NULL;
Stephane Eranianc45c6ea2010-05-28 12:00:01 +0200113 unsigned long start_cpu, end_cpu = 0;
114 char *p = NULL;
115 int i, nr_cpus = 0;
Arnaldo Carvalho de Melo60d567e2011-01-03 17:49:48 -0200116 int *tmp_cpus = NULL, *tmp;
117 int max_entries = 0;
Stephane Eranianc45c6ea2010-05-28 12:00:01 +0200118
119 if (!cpu_list)
Arnaldo Carvalho de Melo60d567e2011-01-03 17:49:48 -0200120 return cpu_map__read_all_cpu_map();
Stephane Eranianc45c6ea2010-05-28 12:00:01 +0200121
122 if (!isdigit(*cpu_list))
Arnaldo Carvalho de Melo60d567e2011-01-03 17:49:48 -0200123 goto out;
Stephane Eranianc45c6ea2010-05-28 12:00:01 +0200124
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++)
Arnaldo Carvalho de Melo60d567e2011-01-03 17:49:48 -0200149 if (tmp_cpus[i] == (int)start_cpu)
Stephane Eranianc45c6ea2010-05-28 12:00:01 +0200150 goto invalid;
151
Arnaldo Carvalho de Melo60d567e2011-01-03 17:49:48 -0200152 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;
Stephane Eranianc45c6ea2010-05-28 12:00:01 +0200160 }
161 if (*p)
162 ++p;
163
164 cpu_list = p;
165 }
Stephane Eranianc45c6ea2010-05-28 12:00:01 +0200166
Arnaldo Carvalho de Melo60d567e2011-01-03 17:49:48 -0200167 if (nr_cpus > 0)
168 cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
169 else
170 cpus = cpu_map__default_new();
Stephane Eranianc45c6ea2010-05-28 12:00:01 +0200171invalid:
Arnaldo Carvalho de Melo60d567e2011-01-03 17:49:48 -0200172 free(tmp_cpus);
173out:
174 return cpus;
175}
176
Arnaldo Carvalho de Melo9ae7d332012-01-19 14:07:23 -0200177size_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
Arnaldo Carvalho de Melo60d567e2011-01-03 17:49:48 -0200188struct 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;
Stephane Eranianc45c6ea2010-05-28 12:00:01 +0200198}
Arnaldo Carvalho de Melo915fce22011-01-14 16:19:12 -0200199
200void cpu_map__delete(struct cpu_map *map)
201{
202 free(map);
203}