xref: /linux/tools/perf/util/cpumap.c (revision 4413e16d9d21673bb5048a2e542f1aaa00015c2e)
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 }
204