hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/tools/perf/util/cpumap.c
....@@ -1,8 +1,8 @@
11 // SPDX-License-Identifier: GPL-2.0
2
-#include "util.h"
32 #include <api/fs/fs.h>
4
-#include "../perf.h"
53 #include "cpumap.h"
4
+#include "debug.h"
5
+#include "event.h"
66 #include <assert.h>
77 #include <dirent.h>
88 #include <stdio.h>
....@@ -10,197 +10,19 @@
1010 #include <linux/bitmap.h>
1111 #include "asm/bug.h"
1212
13
-#include "sane_ctype.h"
13
+#include <linux/ctype.h>
14
+#include <linux/zalloc.h>
1415
1516 static int max_cpu_num;
1617 static int max_present_cpu_num;
1718 static int max_node_num;
1819 static int *cpunode_map;
1920
20
-static struct cpu_map *cpu_map__default_new(void)
21
+static struct perf_cpu_map *cpu_map__from_entries(struct cpu_map_entries *cpus)
2122 {
22
- struct cpu_map *cpus;
23
- int nr_cpus;
23
+ struct perf_cpu_map *map;
2424
25
- nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
26
- if (nr_cpus < 0)
27
- return NULL;
28
-
29
- cpus = malloc(sizeof(*cpus) + nr_cpus * sizeof(int));
30
- if (cpus != NULL) {
31
- int i;
32
- for (i = 0; i < nr_cpus; ++i)
33
- cpus->map[i] = i;
34
-
35
- cpus->nr = nr_cpus;
36
- refcount_set(&cpus->refcnt, 1);
37
- }
38
-
39
- return cpus;
40
-}
41
-
42
-static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus)
43
-{
44
- size_t payload_size = nr_cpus * sizeof(int);
45
- struct cpu_map *cpus = malloc(sizeof(*cpus) + payload_size);
46
-
47
- if (cpus != NULL) {
48
- cpus->nr = nr_cpus;
49
- memcpy(cpus->map, tmp_cpus, payload_size);
50
- refcount_set(&cpus->refcnt, 1);
51
- }
52
-
53
- return cpus;
54
-}
55
-
56
-struct cpu_map *cpu_map__read(FILE *file)
57
-{
58
- struct cpu_map *cpus = NULL;
59
- int nr_cpus = 0;
60
- int *tmp_cpus = NULL, *tmp;
61
- int max_entries = 0;
62
- int n, cpu, prev;
63
- char sep;
64
-
65
- sep = 0;
66
- prev = -1;
67
- for (;;) {
68
- n = fscanf(file, "%u%c", &cpu, &sep);
69
- if (n <= 0)
70
- break;
71
- if (prev >= 0) {
72
- int new_max = nr_cpus + cpu - prev - 1;
73
-
74
- if (new_max >= max_entries) {
75
- max_entries = new_max + MAX_NR_CPUS / 2;
76
- tmp = realloc(tmp_cpus, max_entries * sizeof(int));
77
- if (tmp == NULL)
78
- goto out_free_tmp;
79
- tmp_cpus = tmp;
80
- }
81
-
82
- while (++prev < cpu)
83
- tmp_cpus[nr_cpus++] = prev;
84
- }
85
- if (nr_cpus == max_entries) {
86
- max_entries += MAX_NR_CPUS;
87
- tmp = realloc(tmp_cpus, max_entries * sizeof(int));
88
- if (tmp == NULL)
89
- goto out_free_tmp;
90
- tmp_cpus = tmp;
91
- }
92
-
93
- tmp_cpus[nr_cpus++] = cpu;
94
- if (n == 2 && sep == '-')
95
- prev = cpu;
96
- else
97
- prev = -1;
98
- if (n == 1 || sep == '\n')
99
- break;
100
- }
101
-
102
- if (nr_cpus > 0)
103
- cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
104
- else
105
- cpus = cpu_map__default_new();
106
-out_free_tmp:
107
- free(tmp_cpus);
108
- return cpus;
109
-}
110
-
111
-static struct cpu_map *cpu_map__read_all_cpu_map(void)
112
-{
113
- struct cpu_map *cpus = NULL;
114
- FILE *onlnf;
115
-
116
- onlnf = fopen("/sys/devices/system/cpu/online", "r");
117
- if (!onlnf)
118
- return cpu_map__default_new();
119
-
120
- cpus = cpu_map__read(onlnf);
121
- fclose(onlnf);
122
- return cpus;
123
-}
124
-
125
-struct cpu_map *cpu_map__new(const char *cpu_list)
126
-{
127
- struct cpu_map *cpus = NULL;
128
- unsigned long start_cpu, end_cpu = 0;
129
- char *p = NULL;
130
- int i, nr_cpus = 0;
131
- int *tmp_cpus = NULL, *tmp;
132
- int max_entries = 0;
133
-
134
- if (!cpu_list)
135
- return cpu_map__read_all_cpu_map();
136
-
137
- /*
138
- * must handle the case of empty cpumap to cover
139
- * TOPOLOGY header for NUMA nodes with no CPU
140
- * ( e.g., because of CPU hotplug)
141
- */
142
- if (!isdigit(*cpu_list) && *cpu_list != '\0')
143
- goto out;
144
-
145
- while (isdigit(*cpu_list)) {
146
- p = NULL;
147
- start_cpu = strtoul(cpu_list, &p, 0);
148
- if (start_cpu >= INT_MAX
149
- || (*p != '\0' && *p != ',' && *p != '-'))
150
- goto invalid;
151
-
152
- if (*p == '-') {
153
- cpu_list = ++p;
154
- p = NULL;
155
- end_cpu = strtoul(cpu_list, &p, 0);
156
-
157
- if (end_cpu >= INT_MAX || (*p != '\0' && *p != ','))
158
- goto invalid;
159
-
160
- if (end_cpu < start_cpu)
161
- goto invalid;
162
- } else {
163
- end_cpu = start_cpu;
164
- }
165
-
166
- for (; start_cpu <= end_cpu; start_cpu++) {
167
- /* check for duplicates */
168
- for (i = 0; i < nr_cpus; i++)
169
- if (tmp_cpus[i] == (int)start_cpu)
170
- goto invalid;
171
-
172
- if (nr_cpus == max_entries) {
173
- max_entries += MAX_NR_CPUS;
174
- tmp = realloc(tmp_cpus, max_entries * sizeof(int));
175
- if (tmp == NULL)
176
- goto invalid;
177
- tmp_cpus = tmp;
178
- }
179
- tmp_cpus[nr_cpus++] = (int)start_cpu;
180
- }
181
- if (*p)
182
- ++p;
183
-
184
- cpu_list = p;
185
- }
186
-
187
- if (nr_cpus > 0)
188
- cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
189
- else if (*cpu_list != '\0')
190
- cpus = cpu_map__default_new();
191
- else
192
- cpus = cpu_map__dummy_new();
193
-invalid:
194
- free(tmp_cpus);
195
-out:
196
- return cpus;
197
-}
198
-
199
-static struct cpu_map *cpu_map__from_entries(struct cpu_map_entries *cpus)
200
-{
201
- struct cpu_map *map;
202
-
203
- map = cpu_map__empty_new(cpus->nr);
25
+ map = perf_cpu_map__empty_new(cpus->nr);
20426 if (map) {
20527 unsigned i;
20628
....@@ -220,14 +42,14 @@
22042 return map;
22143 }
22244
223
-static struct cpu_map *cpu_map__from_mask(struct cpu_map_mask *mask)
45
+static struct perf_cpu_map *cpu_map__from_mask(struct perf_record_record_cpu_map *mask)
22446 {
225
- struct cpu_map *map;
47
+ struct perf_cpu_map *map;
22648 int nr, nbits = mask->nr * mask->long_size * BITS_PER_BYTE;
22749
22850 nr = bitmap_weight(mask->mask, nbits);
22951
230
- map = cpu_map__empty_new(nr);
52
+ map = perf_cpu_map__empty_new(nr);
23153 if (map) {
23254 int cpu, i = 0;
23355
....@@ -238,15 +60,15 @@
23860
23961 }
24062
241
-struct cpu_map *cpu_map__new_data(struct cpu_map_data *data)
63
+struct perf_cpu_map *cpu_map__new_data(struct perf_record_cpu_map_data *data)
24264 {
24365 if (data->type == PERF_CPU_MAP__CPUS)
24466 return cpu_map__from_entries((struct cpu_map_entries *)data->data);
24567 else
246
- return cpu_map__from_mask((struct cpu_map_mask *)data->data);
68
+ return cpu_map__from_mask((struct perf_record_record_cpu_map *)data->data);
24769 }
24870
249
-size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp)
71
+size_t cpu_map__fprintf(struct perf_cpu_map *map, FILE *fp)
25072 {
25173 #define BUFSIZE 1024
25274 char buf[BUFSIZE];
....@@ -256,22 +78,9 @@
25678 #undef BUFSIZE
25779 }
25880
259
-struct cpu_map *cpu_map__dummy_new(void)
81
+struct perf_cpu_map *perf_cpu_map__empty_new(int nr)
26082 {
261
- struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int));
262
-
263
- if (cpus != NULL) {
264
- cpus->nr = 1;
265
- cpus->map[0] = -1;
266
- refcount_set(&cpus->refcnt, 1);
267
- }
268
-
269
- return cpus;
270
-}
271
-
272
-struct cpu_map *cpu_map__empty_new(int nr)
273
-{
274
- struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int) * nr);
83
+ struct perf_cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int) * nr);
27584
27685 if (cpus != NULL) {
27786 int i;
....@@ -284,28 +93,6 @@
28493 }
28594
28695 return cpus;
287
-}
288
-
289
-static void cpu_map__delete(struct cpu_map *map)
290
-{
291
- if (map) {
292
- WARN_ONCE(refcount_read(&map->refcnt) != 0,
293
- "cpu_map refcnt unbalanced\n");
294
- free(map);
295
- }
296
-}
297
-
298
-struct cpu_map *cpu_map__get(struct cpu_map *map)
299
-{
300
- if (map)
301
- refcount_inc(&map->refcnt);
302
- return map;
303
-}
304
-
305
-void cpu_map__put(struct cpu_map *map)
306
-{
307
- if (map && refcount_dec_and_test(&map->refcnt))
308
- cpu_map__delete(map);
30996 }
31097
31198 static int cpu__get_topology_int(int cpu, const char *name, int *value)
....@@ -324,7 +111,7 @@
324111 return ret ?: value;
325112 }
326113
327
-int cpu_map__get_socket(struct cpu_map *map, int idx, void *data __maybe_unused)
114
+int cpu_map__get_socket(struct perf_cpu_map *map, int idx, void *data __maybe_unused)
328115 {
329116 int cpu;
330117
....@@ -341,11 +128,11 @@
341128 return *(int *)a - *(int *)b;
342129 }
343130
344
-int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res,
345
- int (*f)(struct cpu_map *map, int cpu, void *data),
131
+int cpu_map__build_map(struct perf_cpu_map *cpus, struct perf_cpu_map **res,
132
+ int (*f)(struct perf_cpu_map *map, int cpu, void *data),
346133 void *data)
347134 {
348
- struct cpu_map *c;
135
+ struct perf_cpu_map *c;
349136 int nr = cpus->nr;
350137 int cpu, s1, s2;
351138
....@@ -373,15 +160,60 @@
373160 return 0;
374161 }
375162
163
+int cpu_map__get_die_id(int cpu)
164
+{
165
+ int value, ret = cpu__get_topology_int(cpu, "die_id", &value);
166
+
167
+ return ret ?: value;
168
+}
169
+
170
+int cpu_map__get_die(struct perf_cpu_map *map, int idx, void *data)
171
+{
172
+ int cpu, die_id, s;
173
+
174
+ if (idx > map->nr)
175
+ return -1;
176
+
177
+ cpu = map->map[idx];
178
+
179
+ die_id = cpu_map__get_die_id(cpu);
180
+ /* There is no die_id on legacy system. */
181
+ if (die_id == -1)
182
+ die_id = 0;
183
+
184
+ s = cpu_map__get_socket(map, idx, data);
185
+ if (s == -1)
186
+ return -1;
187
+
188
+ /*
189
+ * Encode socket in bit range 15:8
190
+ * die_id is relative to socket, and
191
+ * we need a global id. So we combine
192
+ * socket + die id
193
+ */
194
+ if (WARN_ONCE(die_id >> 8, "The die id number is too big.\n"))
195
+ return -1;
196
+
197
+ if (WARN_ONCE(s >> 8, "The socket id number is too big.\n"))
198
+ return -1;
199
+
200
+ return (s << 8) | (die_id & 0xff);
201
+}
202
+
376203 int cpu_map__get_core_id(int cpu)
377204 {
378205 int value, ret = cpu__get_topology_int(cpu, "core_id", &value);
379206 return ret ?: value;
380207 }
381208
382
-int cpu_map__get_core(struct cpu_map *map, int idx, void *data)
209
+int cpu_map__get_node_id(int cpu)
383210 {
384
- int cpu, s;
211
+ return cpu__get_node(cpu);
212
+}
213
+
214
+int cpu_map__get_core(struct perf_cpu_map *map, int idx, void *data)
215
+{
216
+ int cpu, s_die;
385217
386218 if (idx > map->nr)
387219 return -1;
....@@ -390,27 +222,50 @@
390222
391223 cpu = cpu_map__get_core_id(cpu);
392224
393
- s = cpu_map__get_socket(map, idx, data);
394
- if (s == -1)
225
+ /* s_die is the combination of socket + die id */
226
+ s_die = cpu_map__get_die(map, idx, data);
227
+ if (s_die == -1)
395228 return -1;
396229
397230 /*
398
- * encode socket in upper 16 bits
399
- * core_id is relative to socket, and
231
+ * encode socket in bit range 31:24
232
+ * encode die id in bit range 23:16
233
+ * core_id is relative to socket and die,
400234 * we need a global id. So we combine
401
- * socket+ core id
235
+ * socket + die id + core id
402236 */
403
- return (s << 16) | (cpu & 0xffff);
237
+ if (WARN_ONCE(cpu >> 16, "The core id number is too big.\n"))
238
+ return -1;
239
+
240
+ return (s_die << 16) | (cpu & 0xffff);
404241 }
405242
406
-int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp)
243
+int cpu_map__get_node(struct perf_cpu_map *map, int idx, void *data __maybe_unused)
244
+{
245
+ if (idx < 0 || idx >= map->nr)
246
+ return -1;
247
+
248
+ return cpu_map__get_node_id(map->map[idx]);
249
+}
250
+
251
+int cpu_map__build_socket_map(struct perf_cpu_map *cpus, struct perf_cpu_map **sockp)
407252 {
408253 return cpu_map__build_map(cpus, sockp, cpu_map__get_socket, NULL);
409254 }
410255
411
-int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep)
256
+int cpu_map__build_die_map(struct perf_cpu_map *cpus, struct perf_cpu_map **diep)
257
+{
258
+ return cpu_map__build_map(cpus, diep, cpu_map__get_die, NULL);
259
+}
260
+
261
+int cpu_map__build_core_map(struct perf_cpu_map *cpus, struct perf_cpu_map **corep)
412262 {
413263 return cpu_map__build_map(cpus, corep, cpu_map__get_core, NULL);
264
+}
265
+
266
+int cpu_map__build_node_map(struct perf_cpu_map *cpus, struct perf_cpu_map **numap)
267
+{
268
+ return cpu_map__build_map(cpus, numap, cpu_map__get_node, NULL);
414269 }
415270
416271 /* setup simple routines to easily access node numbers given a cpu number */
....@@ -620,29 +475,17 @@
620475 return 0;
621476 }
622477
623
-bool cpu_map__has(struct cpu_map *cpus, int cpu)
478
+bool cpu_map__has(struct perf_cpu_map *cpus, int cpu)
624479 {
625
- return cpu_map__idx(cpus, cpu) != -1;
480
+ return perf_cpu_map__idx(cpus, cpu) != -1;
626481 }
627482
628
-int cpu_map__idx(struct cpu_map *cpus, int cpu)
629
-{
630
- int i;
631
-
632
- for (i = 0; i < cpus->nr; ++i) {
633
- if (cpus->map[i] == cpu)
634
- return i;
635
- }
636
-
637
- return -1;
638
-}
639
-
640
-int cpu_map__cpu(struct cpu_map *cpus, int idx)
483
+int cpu_map__cpu(struct perf_cpu_map *cpus, int idx)
641484 {
642485 return cpus->map[idx];
643486 }
644487
645
-size_t cpu_map__snprint(struct cpu_map *map, char *buf, size_t size)
488
+size_t cpu_map__snprint(struct perf_cpu_map *map, char *buf, size_t size)
646489 {
647490 int i, cpu, start = -1;
648491 bool first = true;
....@@ -681,7 +524,7 @@
681524
682525 #undef COMMA
683526
684
- pr_debug("cpumask list: %s\n", buf);
527
+ pr_debug2("cpumask list: %s\n", buf);
685528 return ret;
686529 }
687530
....@@ -694,7 +537,7 @@
694537 return '?';
695538 }
696539
697
-size_t cpu_map__snprint_mask(struct cpu_map *map, char *buf, size_t size)
540
+size_t cpu_map__snprint_mask(struct perf_cpu_map *map, char *buf, size_t size)
698541 {
699542 int i, cpu;
700543 char *ptr = buf;
....@@ -733,3 +576,13 @@
733576 buf[size - 1] = '\0';
734577 return ptr - buf;
735578 }
579
+
580
+const struct perf_cpu_map *cpu_map__online(void) /* thread unsafe */
581
+{
582
+ static const struct perf_cpu_map *online = NULL;
583
+
584
+ if (!online)
585
+ online = perf_cpu_map__new(NULL); /* from /sys/devices/system/cpu/online */
586
+
587
+ return online;
588
+}