Merge tag 'cgroup-for-6.0-rc2-fixes' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-block.git] / tools / perf / util / cpumap.c
CommitLineData
b2441318 1// SPDX-License-Identifier: GPL-2.0
cd0cfad7 2#include <api/fs/fs.h>
a12b51c4 3#include "cpumap.h"
5e51b0bb
ACM
4#include "debug.h"
5#include "event.h"
a12b51c4 6#include <assert.h>
76b31a29 7#include <dirent.h>
a12b51c4 8#include <stdio.h>
86ee6e18 9#include <stdlib.h>
f77b57ad 10#include <linux/bitmap.h>
f30a79b0 11#include "asm/bug.h"
a12b51c4 12
3052ba56 13#include <linux/ctype.h>
7f7c536f 14#include <linux/zalloc.h>
3d689ed6 15
6d18804b
IR
16static struct perf_cpu max_cpu_num;
17static struct perf_cpu max_present_cpu_num;
5ac76283 18static int max_node_num;
194a3a20
IR
19/**
20 * The numa node X as read from /sys/devices/system/node/nodeX indexed by the
21 * CPU number.
22 */
5ac76283
ACM
23static int *cpunode_map;
24
b2f10cd4
IR
25bool perf_record_cpu_map_data__test_bit(int i,
26 const struct perf_record_cpu_map_data *data)
27{
28 int bit_word32 = i / 32;
29 __u32 bit_mask32 = 1U << (i & 31);
30 int bit_word64 = i / 64;
31 __u64 bit_mask64 = ((__u64)1) << (i & 63);
32
33 return (data->mask32_data.long_size == 4)
34 ? (bit_word32 < data->mask32_data.nr) &&
35 (data->mask32_data.mask[bit_word32] & bit_mask32) != 0
36 : (bit_word64 < data->mask64_data.nr) &&
37 (data->mask64_data.mask[bit_word64] & bit_mask64) != 0;
38}
39
40/* Read ith mask value from data into the given 64-bit sized bitmap */
41static void perf_record_cpu_map_data__read_one_mask(const struct perf_record_cpu_map_data *data,
42 int i, unsigned long *bitmap)
43{
44#if __SIZEOF_LONG__ == 8
45 if (data->mask32_data.long_size == 4)
46 bitmap[0] = data->mask32_data.mask[i];
47 else
48 bitmap[0] = data->mask64_data.mask[i];
49#else
50 if (data->mask32_data.long_size == 4) {
51 bitmap[0] = data->mask32_data.mask[i];
52 bitmap[1] = 0;
53 } else {
54#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
55 bitmap[0] = (unsigned long)(data->mask64_data.mask[i] >> 32);
56 bitmap[1] = (unsigned long)data->mask64_data.mask[i];
57#else
58 bitmap[0] = (unsigned long)data->mask64_data.mask[i];
59 bitmap[1] = (unsigned long)(data->mask64_data.mask[i] >> 32);
60#endif
61 }
62#endif
63}
64static struct perf_cpu_map *cpu_map__from_entries(const struct perf_record_cpu_map_data *data)
f77b57ad 65{
f854839b 66 struct perf_cpu_map *map;
f77b57ad 67
b2f10cd4 68 map = perf_cpu_map__empty_new(data->cpus_data.nr);
f77b57ad
JO
69 if (map) {
70 unsigned i;
71
b2f10cd4 72 for (i = 0; i < data->cpus_data.nr; i++) {
15d2b995
JO
73 /*
74 * Special treatment for -1, which is not real cpu number,
75 * and we need to use (int) -1 to initialize map[i],
76 * otherwise it would become 65535.
77 */
b2f10cd4 78 if (data->cpus_data.cpu[i] == (u16) -1)
6d18804b 79 map->map[i].cpu = -1;
15d2b995 80 else
b2f10cd4 81 map->map[i].cpu = (int) data->cpus_data.cpu[i];
15d2b995 82 }
f77b57ad
JO
83 }
84
85 return map;
86}
87
b2f10cd4 88static struct perf_cpu_map *cpu_map__from_mask(const struct perf_record_cpu_map_data *data)
f77b57ad 89{
b2f10cd4
IR
90 DECLARE_BITMAP(local_copy, 64);
91 int weight = 0, mask_nr = data->mask32_data.nr;
f854839b 92 struct perf_cpu_map *map;
f77b57ad 93
b2f10cd4
IR
94 for (int i = 0; i < mask_nr; i++) {
95 perf_record_cpu_map_data__read_one_mask(data, i, local_copy);
96 weight += bitmap_weight(local_copy, 64);
97 }
f77b57ad 98
b2f10cd4
IR
99 map = perf_cpu_map__empty_new(weight);
100 if (!map)
101 return NULL;
102
103 for (int i = 0, j = 0; i < mask_nr; i++) {
104 int cpus_per_i = (i * data->mask32_data.long_size * BITS_PER_BYTE);
105 int cpu;
f77b57ad 106
b2f10cd4
IR
107 perf_record_cpu_map_data__read_one_mask(data, i, local_copy);
108 for_each_set_bit(cpu, local_copy, 64)
109 map->map[j++].cpu = cpu + cpus_per_i;
f77b57ad
JO
110 }
111 return map;
112
113}
114
b2f10cd4 115struct perf_cpu_map *cpu_map__new_data(const struct perf_record_cpu_map_data *data)
f77b57ad
JO
116{
117 if (data->type == PERF_CPU_MAP__CPUS)
b2f10cd4 118 return cpu_map__from_entries(data);
f77b57ad 119 else
b2f10cd4 120 return cpu_map__from_mask(data);
f77b57ad
JO
121}
122
f854839b 123size_t cpu_map__fprintf(struct perf_cpu_map *map, FILE *fp)
9ae7d335 124{
a24020e6
JO
125#define BUFSIZE 1024
126 char buf[BUFSIZE];
9ae7d335 127
a24020e6
JO
128 cpu_map__snprint(map, buf, sizeof(buf));
129 return fprintf(fp, "%s\n", buf);
130#undef BUFSIZE
9ae7d335
ACM
131}
132
315c0a1f 133struct perf_cpu_map *perf_cpu_map__empty_new(int nr)
2322f573 134{
f854839b 135 struct perf_cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int) * nr);
2322f573
JO
136
137 if (cpus != NULL) {
138 int i;
139
140 cpus->nr = nr;
141 for (i = 0; i < nr; i++)
6d18804b 142 cpus->map[i].cpu = -1;
2322f573 143
ec09a42a 144 refcount_set(&cpus->refcnt, 1);
2322f573
JO
145 }
146
147 return cpus;
148}
149
cea6575f
JC
150struct cpu_aggr_map *cpu_aggr_map__empty_new(int nr)
151{
ff523295 152 struct cpu_aggr_map *cpus = malloc(sizeof(*cpus) + sizeof(struct aggr_cpu_id) * nr);
cea6575f
JC
153
154 if (cpus != NULL) {
155 int i;
156
157 cpus->nr = nr;
158 for (i = 0; i < nr; i++)
51b826fa 159 cpus->map[i] = aggr_cpu_id__empty();
cea6575f
JC
160
161 refcount_set(&cpus->refcnt, 1);
162 }
163
164 return cpus;
165}
166
5d8cf721 167static int cpu__get_topology_int(int cpu, const char *name, int *value)
5ac59a8a 168{
5ac59a8a 169 char path[PATH_MAX];
5ac59a8a 170
86ee6e18 171 snprintf(path, PATH_MAX,
5d8cf721 172 "devices/system/cpu/cpu%d/topology/%s", cpu, name);
5ac59a8a 173
5d8cf721
ACM
174 return sysfs__read_int(path, value);
175}
193b6bd3 176
6d18804b 177int cpu__get_socket_id(struct perf_cpu cpu)
5d8cf721 178{
6d18804b 179 int value, ret = cpu__get_topology_int(cpu.cpu, "physical_package_id", &value);
5d8cf721 180 return ret ?: value;
193b6bd3
KL
181}
182
6d18804b 183struct aggr_cpu_id aggr_cpu_id__socket(struct perf_cpu cpu, void *data __maybe_unused)
193b6bd3 184{
51b826fa 185 struct aggr_cpu_id id = aggr_cpu_id__empty();
193b6bd3 186
4e90e5cc 187 id.socket = cpu__get_socket_id(cpu);
2760f5a1 188 return id;
5ac59a8a
SE
189}
190
5f50e15c 191static int aggr_cpu_id__cmp(const void *a_pointer, const void *b_pointer)
5ac59a8a 192{
2760f5a1
JC
193 struct aggr_cpu_id *a = (struct aggr_cpu_id *)a_pointer;
194 struct aggr_cpu_id *b = (struct aggr_cpu_id *)b_pointer;
195
8d4852b4 196 if (a->node != b->node)
fcd83a35 197 return a->node - b->node;
ba2ee166 198 else if (a->socket != b->socket)
1a270cb6 199 return a->socket - b->socket;
b9933817 200 else if (a->die != b->die)
ba2ee166 201 return a->die - b->die;
8d4852b4 202 else if (a->core != b->core)
b9933817 203 return a->core - b->core;
8d4852b4
JC
204 else
205 return a->thread - b->thread;
86ee6e18
SE
206}
207
5f50e15c
IR
208struct cpu_aggr_map *cpu_aggr_map__new(const struct perf_cpu_map *cpus,
209 aggr_cpu_id_get_t get_id,
210 void *data)
86ee6e18 211{
6d18804b
IR
212 int idx;
213 struct perf_cpu cpu;
5f50e15c 214 struct cpu_aggr_map *c = cpu_aggr_map__empty_new(cpus->nr);
5ac59a8a 215
86ee6e18 216 if (!c)
5f50e15c 217 return NULL;
5ac59a8a 218
91585846
JC
219 /* Reset size as it may only be partially filled */
220 c->nr = 0;
221
5f50e15c
IR
222 perf_cpu_map__for_each_cpu(cpu, idx, cpus) {
223 bool duplicate = false;
224 struct aggr_cpu_id cpu_id = get_id(cpu, data);
225
226 for (int j = 0; j < c->nr; j++) {
227 if (aggr_cpu_id__equal(&cpu_id, &c->map[j])) {
228 duplicate = true;
5ac59a8a 229 break;
5f50e15c 230 }
5ac59a8a 231 }
5f50e15c
IR
232 if (!duplicate) {
233 c->map[c->nr] = cpu_id;
86ee6e18 234 c->nr++;
5ac59a8a
SE
235 }
236 }
bd26bddf
IR
237 /* Trim. */
238 if (c->nr != cpus->nr) {
239 struct cpu_aggr_map *trimmed_c =
240 realloc(c,
241 sizeof(struct cpu_aggr_map) + sizeof(struct aggr_cpu_id) * c->nr);
242
243 if (trimmed_c)
244 c = trimmed_c;
245 }
86ee6e18 246 /* ensure we process id in increasing order */
5f50e15c
IR
247 qsort(c->map, c->nr, sizeof(struct aggr_cpu_id), aggr_cpu_id__cmp);
248
249 return c;
86ee6e18 250
5ac59a8a 251}
86ee6e18 252
6d18804b 253int cpu__get_die_id(struct perf_cpu cpu)
b74d8686 254{
6d18804b 255 int value, ret = cpu__get_topology_int(cpu.cpu, "die_id", &value);
b74d8686
KL
256
257 return ret ?: value;
258}
259
6d18804b 260struct aggr_cpu_id aggr_cpu_id__die(struct perf_cpu cpu, void *data)
db5742b6 261{
ca2c9b76
IR
262 struct aggr_cpu_id id;
263 int die;
db5742b6 264
4e90e5cc 265 die = cpu__get_die_id(cpu);
db5742b6 266 /* There is no die_id on legacy system. */
1a270cb6
JC
267 if (die == -1)
268 die = 0;
db5742b6
KL
269
270 /*
1a270cb6
JC
271 * die_id is relative to socket, so start
272 * with the socket ID and then add die to
273 * make a unique ID.
db5742b6 274 */
973aeb3c 275 id = aggr_cpu_id__socket(cpu, data);
51b826fa 276 if (aggr_cpu_id__is_empty(&id))
1a270cb6 277 return id;
db5742b6 278
ba2ee166 279 id.die = die;
2760f5a1 280 return id;
db5742b6
KL
281}
282
6d18804b 283int cpu__get_core_id(struct perf_cpu cpu)
12c08a9f 284{
6d18804b 285 int value, ret = cpu__get_topology_int(cpu.cpu, "core_id", &value);
5d8cf721 286 return ret ?: value;
193b6bd3
KL
287}
288
6d18804b 289struct aggr_cpu_id aggr_cpu_id__core(struct perf_cpu cpu, void *data)
193b6bd3 290{
ca2c9b76 291 struct aggr_cpu_id id;
4e90e5cc 292 int core = cpu__get_core_id(cpu);
193b6bd3 293
34794913 294 /* aggr_cpu_id__die returns a struct with socket and die set. */
973aeb3c 295 id = aggr_cpu_id__die(cpu, data);
51b826fa 296 if (aggr_cpu_id__is_empty(&id))
2760f5a1 297 return id;
12c08a9f
SE
298
299 /*
ba2ee166
JC
300 * core_id is relative to socket and die, we need a global id.
301 * So we combine the result from cpu_map__get_die with the core id
12c08a9f 302 */
ca2c9b76 303 id.core = core;
2760f5a1 304 return id;
ca2c9b76 305
12c08a9f
SE
306}
307
6d18804b 308struct aggr_cpu_id aggr_cpu_id__cpu(struct perf_cpu cpu, void *data)
34794913
IR
309{
310 struct aggr_cpu_id id;
311
312 /* aggr_cpu_id__core returns a struct with socket, die and core set. */
313 id = aggr_cpu_id__core(cpu, data);
314 if (aggr_cpu_id__is_empty(&id))
315 return id;
316
317 id.cpu = cpu;
318 return id;
319
320}
321
6d18804b 322struct aggr_cpu_id aggr_cpu_id__node(struct perf_cpu cpu, void *data __maybe_unused)
86895b48 323{
51b826fa 324 struct aggr_cpu_id id = aggr_cpu_id__empty();
2760f5a1 325
194a3a20 326 id.node = cpu__get_node(cpu);
ca2c9b76
IR
327 return id;
328}
329
7780c25b
DZ
330/* setup simple routines to easily access node numbers given a cpu number */
331static int get_max_num(char *path, int *max)
332{
333 size_t num;
334 char *buf;
335 int err = 0;
336
337 if (filename__read_str(path, &buf, &num))
338 return -1;
339
340 buf[num] = '\0';
341
342 /* start on the right, to find highest node num */
343 while (--num) {
344 if ((buf[num] == ',') || (buf[num] == '-')) {
345 num++;
346 break;
347 }
348 }
349 if (sscanf(&buf[num], "%d", max) < 1) {
350 err = -1;
351 goto out;
352 }
353
354 /* convert from 0-based to 1-based */
355 (*max)++;
356
357out:
358 free(buf);
359 return err;
360}
361
362/* Determine highest possible cpu in the system for sparse allocation */
363static void set_max_cpu_num(void)
364{
365 const char *mnt;
366 char path[PATH_MAX];
367 int ret = -1;
368
369 /* set up default */
6d18804b
IR
370 max_cpu_num.cpu = 4096;
371 max_present_cpu_num.cpu = 4096;
7780c25b
DZ
372
373 mnt = sysfs__mountpoint();
374 if (!mnt)
375 goto out;
376
377 /* get the highest possible cpu number for a sparse allocation */
f5b1f4e4 378 ret = snprintf(path, PATH_MAX, "%s/devices/system/cpu/possible", mnt);
d74b181a 379 if (ret >= PATH_MAX) {
7780c25b
DZ
380 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
381 goto out;
382 }
383
6d18804b 384 ret = get_max_num(path, &max_cpu_num.cpu);
92a7e127
JS
385 if (ret)
386 goto out;
387
388 /* get the highest present cpu number for a sparse allocation */
389 ret = snprintf(path, PATH_MAX, "%s/devices/system/cpu/present", mnt);
d74b181a 390 if (ret >= PATH_MAX) {
92a7e127
JS
391 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
392 goto out;
393 }
394
6d18804b 395 ret = get_max_num(path, &max_present_cpu_num.cpu);
7780c25b
DZ
396
397out:
398 if (ret)
6d18804b 399 pr_err("Failed to read max cpus, using default of %d\n", max_cpu_num.cpu);
7780c25b
DZ
400}
401
402/* Determine highest possible node in the system for sparse allocation */
403static void set_max_node_num(void)
404{
405 const char *mnt;
406 char path[PATH_MAX];
407 int ret = -1;
408
409 /* set up default */
410 max_node_num = 8;
411
412 mnt = sysfs__mountpoint();
413 if (!mnt)
414 goto out;
415
416 /* get the highest possible cpu number for a sparse allocation */
417 ret = snprintf(path, PATH_MAX, "%s/devices/system/node/possible", mnt);
d74b181a 418 if (ret >= PATH_MAX) {
7780c25b
DZ
419 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
420 goto out;
421 }
422
423 ret = get_max_num(path, &max_node_num);
424
425out:
426 if (ret)
427 pr_err("Failed to read max nodes, using default of %d\n", max_node_num);
428}
429
5ac76283
ACM
430int cpu__max_node(void)
431{
432 if (unlikely(!max_node_num))
433 set_max_node_num();
434
435 return max_node_num;
436}
437
6d18804b 438struct perf_cpu cpu__max_cpu(void)
5ac76283 439{
6d18804b 440 if (unlikely(!max_cpu_num.cpu))
5ac76283
ACM
441 set_max_cpu_num();
442
443 return max_cpu_num;
444}
445
6d18804b 446struct perf_cpu cpu__max_present_cpu(void)
92a7e127 447{
6d18804b 448 if (unlikely(!max_present_cpu_num.cpu))
92a7e127
JS
449 set_max_cpu_num();
450
451 return max_present_cpu_num;
452}
453
454
6d18804b 455int cpu__get_node(struct perf_cpu cpu)
5ac76283
ACM
456{
457 if (unlikely(cpunode_map == NULL)) {
458 pr_debug("cpu_map not initialized\n");
459 return -1;
460 }
461
6d18804b 462 return cpunode_map[cpu.cpu];
5ac76283
ACM
463}
464
7780c25b
DZ
465static int init_cpunode_map(void)
466{
467 int i;
468
469 set_max_cpu_num();
470 set_max_node_num();
471
6d18804b 472 cpunode_map = calloc(max_cpu_num.cpu, sizeof(int));
7780c25b
DZ
473 if (!cpunode_map) {
474 pr_err("%s: calloc failed\n", __func__);
475 return -1;
476 }
477
6d18804b 478 for (i = 0; i < max_cpu_num.cpu; i++)
7780c25b
DZ
479 cpunode_map[i] = -1;
480
481 return 0;
482}
483
484int cpu__setup_cpunode_map(void)
485{
486 struct dirent *dent1, *dent2;
487 DIR *dir1, *dir2;
488 unsigned int cpu, mem;
489 char buf[PATH_MAX];
490 char path[PATH_MAX];
491 const char *mnt;
492 int n;
493
494 /* initialize globals */
495 if (init_cpunode_map())
496 return -1;
497
498 mnt = sysfs__mountpoint();
499 if (!mnt)
500 return 0;
501
502 n = snprintf(path, PATH_MAX, "%s/devices/system/node", mnt);
d74b181a 503 if (n >= PATH_MAX) {
7780c25b
DZ
504 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
505 return -1;
506 }
507
508 dir1 = opendir(path);
509 if (!dir1)
510 return 0;
511
512 /* walk tree and setup map */
513 while ((dent1 = readdir(dir1)) != NULL) {
514 if (dent1->d_type != DT_DIR || sscanf(dent1->d_name, "node%u", &mem) < 1)
515 continue;
516
517 n = snprintf(buf, PATH_MAX, "%s/%s", path, dent1->d_name);
d74b181a 518 if (n >= PATH_MAX) {
7780c25b
DZ
519 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
520 continue;
521 }
522
523 dir2 = opendir(buf);
524 if (!dir2)
525 continue;
526 while ((dent2 = readdir(dir2)) != NULL) {
527 if (dent2->d_type != DT_LNK || sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
528 continue;
529 cpunode_map[cpu] = mem;
530 }
531 closedir(dir2);
532 }
533 closedir(dir1);
534 return 0;
535}
e632aa69 536
f854839b 537size_t cpu_map__snprint(struct perf_cpu_map *map, char *buf, size_t size)
a24020e6 538{
6d18804b 539 int i, start = -1;
a24020e6
JO
540 bool first = true;
541 size_t ret = 0;
542
543#define COMMA first ? "" : ","
544
545 for (i = 0; i < map->nr + 1; i++) {
6d18804b 546 struct perf_cpu cpu = { .cpu = INT_MAX };
a24020e6
JO
547 bool last = i == map->nr;
548
6d18804b
IR
549 if (!last)
550 cpu = map->map[i];
a24020e6
JO
551
552 if (start == -1) {
553 start = i;
554 if (last) {
555 ret += snprintf(buf + ret, size - ret,
556 "%s%d", COMMA,
6d18804b 557 map->map[i].cpu);
a24020e6 558 }
6d18804b 559 } else if (((i - start) != (cpu.cpu - map->map[start].cpu)) || last) {
a24020e6
JO
560 int end = i - 1;
561
562 if (start == end) {
563 ret += snprintf(buf + ret, size - ret,
564 "%s%d", COMMA,
6d18804b 565 map->map[start].cpu);
a24020e6
JO
566 } else {
567 ret += snprintf(buf + ret, size - ret,
568 "%s%d-%d", COMMA,
6d18804b 569 map->map[start].cpu, map->map[end].cpu);
a24020e6
JO
570 }
571 first = false;
572 start = i;
573 }
574 }
575
576#undef COMMA
577
deb83da1 578 pr_debug2("cpumask list: %s\n", buf);
a24020e6
JO
579 return ret;
580}
4400ac8a
NK
581
582static char hex_char(unsigned char val)
583{
584 if (val < 10)
585 return val + '0';
586 if (val < 16)
587 return val - 10 + 'a';
588 return '?';
589}
590
f854839b 591size_t cpu_map__snprint_mask(struct perf_cpu_map *map, char *buf, size_t size)
4400ac8a
NK
592{
593 int i, cpu;
594 char *ptr = buf;
595 unsigned char *bitmap;
6d18804b 596 struct perf_cpu last_cpu = perf_cpu_map__cpu(map, map->nr - 1);
4400ac8a 597
5f5e25f1
HZ
598 if (buf == NULL)
599 return 0;
600
6d18804b 601 bitmap = zalloc(last_cpu.cpu / 8 + 1);
4400ac8a
NK
602 if (bitmap == NULL) {
603 buf[0] = '\0';
604 return 0;
605 }
606
607 for (i = 0; i < map->nr; i++) {
6d18804b 608 cpu = perf_cpu_map__cpu(map, i).cpu;
4400ac8a
NK
609 bitmap[cpu / 8] |= 1 << (cpu % 8);
610 }
611
6d18804b 612 for (cpu = last_cpu.cpu / 4 * 4; cpu >= 0; cpu -= 4) {
4400ac8a
NK
613 unsigned char bits = bitmap[cpu / 8];
614
615 if (cpu % 8)
616 bits >>= 4;
617 else
618 bits &= 0xf;
619
620 *ptr++ = hex_char(bits);
621 if ((cpu % 32) == 0 && cpu > 0)
622 *ptr++ = ',';
623 }
624 *ptr = '\0';
625 free(bitmap);
626
627 buf[size - 1] = '\0';
628 return ptr - buf;
629}
f13de660 630
f854839b 631const struct perf_cpu_map *cpu_map__online(void) /* thread unsafe */
f13de660 632{
f854839b 633 static const struct perf_cpu_map *online = NULL;
f13de660
AB
634
635 if (!online)
9c3516d1 636 online = perf_cpu_map__new(NULL); /* from /sys/devices/system/cpu/online */
f13de660
AB
637
638 return online;
639}
fa265e59 640
3ac23d19 641bool aggr_cpu_id__equal(const struct aggr_cpu_id *a, const struct aggr_cpu_id *b)
fa265e59 642{
3ac23d19
IR
643 return a->thread == b->thread &&
644 a->node == b->node &&
645 a->socket == b->socket &&
646 a->die == b->die &&
34794913 647 a->core == b->core &&
6d18804b 648 a->cpu.cpu == b->cpu.cpu;
fa265e59
JC
649}
650
51b826fa 651bool aggr_cpu_id__is_empty(const struct aggr_cpu_id *a)
fa265e59 652{
51b826fa
IR
653 return a->thread == -1 &&
654 a->node == -1 &&
655 a->socket == -1 &&
656 a->die == -1 &&
34794913 657 a->core == -1 &&
6d18804b 658 a->cpu.cpu == -1;
fa265e59
JC
659}
660
51b826fa 661struct aggr_cpu_id aggr_cpu_id__empty(void)
fa265e59
JC
662{
663 struct aggr_cpu_id ret = {
8d4852b4 664 .thread = -1,
1a270cb6 665 .node = -1,
ba2ee166 666 .socket = -1,
b9933817 667 .die = -1,
34794913 668 .core = -1,
6d18804b 669 .cpu = (struct perf_cpu){ .cpu = -1 },
fa265e59
JC
670 };
671 return ret;
672}