#include <ctype.h>
 #include <limits.h>
 
-struct perf_cpu_map *perf_cpu_map__dummy_new(void)
+static struct perf_cpu_map *perf_cpu_map__alloc(int nr_cpus)
 {
-       struct perf_cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int));
+       struct perf_cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(struct perf_cpu) * nr_cpus);
 
        if (cpus != NULL) {
-               cpus->nr = 1;
-               cpus->map[0] = -1;
+               cpus->nr = nr_cpus;
                refcount_set(&cpus->refcnt, 1);
+
        }
+       return cpus;
+}
+
+struct perf_cpu_map *perf_cpu_map__dummy_new(void)
+{
+       struct perf_cpu_map *cpus = perf_cpu_map__alloc(1);
+
+       if (cpus)
+               cpus->map[0].cpu = -1;
 
        return cpus;
 }
        if (nr_cpus < 0)
                return NULL;
 
-       cpus = malloc(sizeof(*cpus) + nr_cpus * sizeof(int));
+       cpus = perf_cpu_map__alloc(nr_cpus);
        if (cpus != NULL) {
                int i;
 
                for (i = 0; i < nr_cpus; ++i)
-                       cpus->map[i] = i;
-
-               cpus->nr = nr_cpus;
-               refcount_set(&cpus->refcnt, 1);
+                       cpus->map[i].cpu = i;
        }
 
        return cpus;
        return cpu_map__default_new();
 }
 
-static int cmp_int(const void *a, const void *b)
+
+static int cmp_cpu(const void *a, const void *b)
 {
-       return *(const int *)a - *(const int*)b;
+       const struct perf_cpu *cpu_a = a, *cpu_b = b;
+
+       return cpu_a->cpu - cpu_b->cpu;
 }
 
-static struct perf_cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus)
+static struct perf_cpu_map *cpu_map__trim_new(int nr_cpus, const struct perf_cpu *tmp_cpus)
 {
-       size_t payload_size = nr_cpus * sizeof(int);
-       struct perf_cpu_map *cpus = malloc(sizeof(*cpus) + payload_size);
+       size_t payload_size = nr_cpus * sizeof(struct perf_cpu);
+       struct perf_cpu_map *cpus = perf_cpu_map__alloc(nr_cpus);
        int i, j;
 
        if (cpus != NULL) {
                memcpy(cpus->map, tmp_cpus, payload_size);
-               qsort(cpus->map, nr_cpus, sizeof(int), cmp_int);
+               qsort(cpus->map, nr_cpus, sizeof(struct perf_cpu), cmp_cpu);
                /* Remove dups */
                j = 0;
                for (i = 0; i < nr_cpus; i++) {
-                       if (i == 0 || cpus->map[i] != cpus->map[i - 1])
-                               cpus->map[j++] = cpus->map[i];
+                       if (i == 0 || cpus->map[i].cpu != cpus->map[i - 1].cpu)
+                               cpus->map[j++].cpu = cpus->map[i].cpu;
                }
                cpus->nr = j;
                assert(j <= nr_cpus);
-               refcount_set(&cpus->refcnt, 1);
        }
-
        return cpus;
 }
 
 {
        struct perf_cpu_map *cpus = NULL;
        int nr_cpus = 0;
-       int *tmp_cpus = NULL, *tmp;
+       struct perf_cpu *tmp_cpus = NULL, *tmp;
        int max_entries = 0;
        int n, cpu, prev;
        char sep;
 
                        if (new_max >= max_entries) {
                                max_entries = new_max + MAX_NR_CPUS / 2;
-                               tmp = realloc(tmp_cpus, max_entries * sizeof(int));
+                               tmp = realloc(tmp_cpus, max_entries * sizeof(struct perf_cpu));
                                if (tmp == NULL)
                                        goto out_free_tmp;
                                tmp_cpus = tmp;
                        }
 
                        while (++prev < cpu)
-                               tmp_cpus[nr_cpus++] = prev;
+                               tmp_cpus[nr_cpus++].cpu = prev;
                }
                if (nr_cpus == max_entries) {
                        max_entries += MAX_NR_CPUS;
-                       tmp = realloc(tmp_cpus, max_entries * sizeof(int));
+                       tmp = realloc(tmp_cpus, max_entries * sizeof(struct perf_cpu));
                        if (tmp == NULL)
                                goto out_free_tmp;
                        tmp_cpus = tmp;
                }
 
-               tmp_cpus[nr_cpus++] = cpu;
+               tmp_cpus[nr_cpus++].cpu = cpu;
                if (n == 2 && sep == '-')
                        prev = cpu;
                else
        unsigned long start_cpu, end_cpu = 0;
        char *p = NULL;
        int i, nr_cpus = 0;
-       int *tmp_cpus = NULL, *tmp;
+       struct perf_cpu *tmp_cpus = NULL, *tmp;
        int max_entries = 0;
 
        if (!cpu_list)
                for (; start_cpu <= end_cpu; start_cpu++) {
                        /* check for duplicates */
                        for (i = 0; i < nr_cpus; i++)
-                               if (tmp_cpus[i] == (int)start_cpu)
+                               if (tmp_cpus[i].cpu == (int)start_cpu)
                                        goto invalid;
 
                        if (nr_cpus == max_entries) {
                                max_entries += MAX_NR_CPUS;
-                               tmp = realloc(tmp_cpus, max_entries * sizeof(int));
+                               tmp = realloc(tmp_cpus, max_entries * sizeof(struct perf_cpu));
                                if (tmp == NULL)
                                        goto invalid;
                                tmp_cpus = tmp;
                        }
-                       tmp_cpus[nr_cpus++] = (int)start_cpu;
+                       tmp_cpus[nr_cpus++].cpu = (int)start_cpu;
                }
                if (*p)
                        ++p;
        return cpus;
 }
 
-int perf_cpu_map__cpu(const struct perf_cpu_map *cpus, int idx)
+struct perf_cpu perf_cpu_map__cpu(const struct perf_cpu_map *cpus, int idx)
 {
+       struct perf_cpu result = {
+               .cpu = -1
+       };
+
        if (cpus && idx < cpus->nr)
                return cpus->map[idx];
 
-       return -1;
+       return result;
 }
 
 int perf_cpu_map__nr(const struct perf_cpu_map *cpus)
 
 bool perf_cpu_map__empty(const struct perf_cpu_map *map)
 {
-       return map ? map->map[0] == -1 : true;
+       return map ? map->map[0].cpu == -1 : true;
 }
 
-int perf_cpu_map__idx(const struct perf_cpu_map *cpus, int cpu)
+int perf_cpu_map__idx(const struct perf_cpu_map *cpus, struct perf_cpu cpu)
 {
        int low, high;
 
        low = 0;
        high = cpus->nr;
        while (low < high) {
-               int idx = (low + high) / 2,
-                   cpu_at_idx = cpus->map[idx];
+               int idx = (low + high) / 2;
+               struct perf_cpu cpu_at_idx = cpus->map[idx];
 
-               if (cpu_at_idx == cpu)
+               if (cpu_at_idx.cpu == cpu.cpu)
                        return idx;
 
-               if (cpu_at_idx > cpu)
+               if (cpu_at_idx.cpu > cpu.cpu)
                        high = idx;
                else
                        low = idx + 1;
        return -1;
 }
 
-bool perf_cpu_map__has(const struct perf_cpu_map *cpus, int cpu)
+bool perf_cpu_map__has(const struct perf_cpu_map *cpus, struct perf_cpu cpu)
 {
        return perf_cpu_map__idx(cpus, cpu) != -1;
 }
 
-int perf_cpu_map__max(struct perf_cpu_map *map)
+struct perf_cpu perf_cpu_map__max(struct perf_cpu_map *map)
 {
+       struct perf_cpu result = {
+               .cpu = -1
+       };
+
        // cpu_map__trim_new() qsort()s it, cpu_map__default_new() sorts it as well.
-       return map->nr > 0 ? map->map[map->nr - 1] : -1;
+       return map->nr > 0 ? map->map[map->nr - 1] : result;
 }
 
 /*
 struct perf_cpu_map *perf_cpu_map__merge(struct perf_cpu_map *orig,
                                         struct perf_cpu_map *other)
 {
-       int *tmp_cpus;
+       struct perf_cpu *tmp_cpus;
        int tmp_len;
        int i, j, k;
        struct perf_cpu_map *merged;
        if (!other)
                return orig;
        if (orig->nr == other->nr &&
-           !memcmp(orig->map, other->map, orig->nr * sizeof(int)))
+           !memcmp(orig->map, other->map, orig->nr * sizeof(struct perf_cpu)))
                return orig;
 
        tmp_len = orig->nr + other->nr;
-       tmp_cpus = malloc(tmp_len * sizeof(int));
+       tmp_cpus = malloc(tmp_len * sizeof(struct perf_cpu));
        if (!tmp_cpus)
                return NULL;
 
        /* Standard merge algorithm from wikipedia */
        i = j = k = 0;
        while (i < orig->nr && j < other->nr) {
-               if (orig->map[i] <= other->map[j]) {
-                       if (orig->map[i] == other->map[j])
+               if (orig->map[i].cpu <= other->map[j].cpu) {
+                       if (orig->map[i].cpu == other->map[j].cpu)
                                j++;
                        tmp_cpus[k++] = orig->map[i++];
                } else
 
 
 static int
 perf_evlist__mmap_cb_mmap(struct perf_mmap *map, struct perf_mmap_param *mp,
-                         int output, int cpu)
+                         int output, struct perf_cpu cpu)
 {
        return perf_mmap__mmap(map, mp, output, cpu);
 }
               int idx, struct perf_mmap_param *mp, int cpu_idx,
               int thread, int *_output, int *_output_overwrite)
 {
-       int evlist_cpu = perf_cpu_map__cpu(evlist->cpus, cpu_idx);
+       struct perf_cpu evlist_cpu = perf_cpu_map__cpu(evlist->cpus, cpu_idx);
        struct perf_evsel *evsel;
        int revent;
 
 
 
 static int
 sys_perf_event_open(struct perf_event_attr *attr,
-                   pid_t pid, int cpu, int group_fd,
+                   pid_t pid, struct perf_cpu cpu, int group_fd,
                    unsigned long flags)
 {
-       return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
+       return syscall(__NR_perf_event_open, attr, pid, cpu.cpu, group_fd, flags);
 }
 
 static int get_group_fd(struct perf_evsel *evsel, int cpu_map_idx, int thread, int *group_fd)
 int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus,
                     struct perf_thread_map *threads)
 {
-       int cpu, idx, thread, err = 0;
+       struct perf_cpu cpu;
+       int idx, thread, err = 0;
 
        if (cpus == NULL) {
                static struct perf_cpu_map *empty_cpu_map;
                for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
                        int *fd = FD(evsel, idx, thread);
                        struct perf_mmap *map;
-                       int cpu = perf_cpu_map__cpu(evsel->cpus, idx);
+                       struct perf_cpu cpu = perf_cpu_map__cpu(evsel->cpus, idx);
 
                        if (fd == NULL || *fd < 0)
                                continue;
 
 
 #include <linux/refcount.h>
 
+/** A wrapper around a CPU to avoid confusion with the perf_cpu_map's map's indices. */
+struct perf_cpu {
+       int cpu;
+};
+
 /**
  * A sized, reference counted, sorted array of integers representing CPU
  * numbers. This is commonly used to capture which CPUs a PMU is associated
        /** Length of the map array. */
        int             nr;
        /** The CPU values. */
-       int             map[];
+       struct perf_cpu map[];
 };
 
 #ifndef MAX_NR_CPUS
 #define MAX_NR_CPUS    2048
 #endif
 
-int perf_cpu_map__idx(const struct perf_cpu_map *cpus, int cpu);
+int perf_cpu_map__idx(const struct perf_cpu_map *cpus, struct perf_cpu cpu);
 
 #endif /* __LIBPERF_INTERNAL_CPUMAP_H */
 
 
 #include <linux/list.h>
 #include <api/fd/array.h>
+#include <internal/cpumap.h>
 #include <internal/evsel.h>
 
 #define PERF_EVLIST__HLIST_BITS 8
 typedef struct perf_mmap*
 (*perf_evlist_mmap__cb_get_t)(struct perf_evlist*, bool, int);
 typedef int
-(*perf_evlist_mmap__cb_mmap_t)(struct perf_mmap*, struct perf_mmap_param*, int, int);
+(*perf_evlist_mmap__cb_mmap_t)(struct perf_mmap*, struct perf_mmap_param*, int, struct perf_cpu);
 
 struct perf_evlist_mmap_ops {
        perf_evlist_mmap__cb_idx_t      idx;
 
 #include <linux/perf_event.h>
 #include <stdbool.h>
 #include <sys/types.h>
+#include <internal/cpumap.h>
 
-struct perf_cpu_map;
 struct perf_thread_map;
 struct xyarray;
 
        * queue number.
        */
        int                      idx;
-       int                      cpu;
+       struct perf_cpu          cpu;
        pid_t                    tid;
 
        /* Holds total ID period value for PERF_SAMPLE_READ processing. */
 
 #include <linux/refcount.h>
 #include <linux/types.h>
 #include <stdbool.h>
+#include <internal/cpumap.h>
 
 /* perf sample has 16 bits size limit */
 #define PERF_SAMPLE_MAX_SIZE (1 << 16)
        void                    *base;
        int                      mask;
        int                      fd;
-       int                      cpu;
+       struct perf_cpu          cpu;
        refcount_t               refcnt;
        u64                      prev;
        u64                      start;
 void perf_mmap__init(struct perf_mmap *map, struct perf_mmap *prev,
                     bool overwrite, libperf_unmap_cb_t unmap_cb);
 int perf_mmap__mmap(struct perf_mmap *map, struct perf_mmap_param *mp,
-                   int fd, int cpu);
+                   int fd, struct perf_cpu cpu);
 void perf_mmap__munmap(struct perf_mmap *map);
 void perf_mmap__get(struct perf_mmap *map);
 void perf_mmap__put(struct perf_mmap *map);
 
 #define __LIBPERF_CPUMAP_H
 
 #include <perf/core.h>
+#include <perf/cpumap.h>
 #include <stdio.h>
 #include <stdbool.h>
 
-struct perf_cpu_map;
-
 LIBPERF_API struct perf_cpu_map *perf_cpu_map__dummy_new(void);
 LIBPERF_API struct perf_cpu_map *perf_cpu_map__default_new(void);
 LIBPERF_API struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list);
 LIBPERF_API struct perf_cpu_map *perf_cpu_map__merge(struct perf_cpu_map *orig,
                                                     struct perf_cpu_map *other);
 LIBPERF_API void perf_cpu_map__put(struct perf_cpu_map *map);
-LIBPERF_API int perf_cpu_map__cpu(const struct perf_cpu_map *cpus, int idx);
+LIBPERF_API struct perf_cpu perf_cpu_map__cpu(const struct perf_cpu_map *cpus, int idx);
 LIBPERF_API int perf_cpu_map__nr(const struct perf_cpu_map *cpus);
 LIBPERF_API bool perf_cpu_map__empty(const struct perf_cpu_map *map);
-LIBPERF_API int perf_cpu_map__max(struct perf_cpu_map *map);
-LIBPERF_API bool perf_cpu_map__has(const struct perf_cpu_map *map, int cpu);
+LIBPERF_API struct perf_cpu perf_cpu_map__max(struct perf_cpu_map *map);
+LIBPERF_API bool perf_cpu_map__has(const struct perf_cpu_map *map, struct perf_cpu cpu);
 
 #define perf_cpu_map__for_each_cpu(cpu, idx, cpus)             \
        for ((idx) = 0, (cpu) = perf_cpu_map__cpu(cpus, idx);   \
 
 }
 
 int perf_mmap__mmap(struct perf_mmap *map, struct perf_mmap_param *mp,
-                   int fd, int cpu)
+                   int fd, struct perf_cpu cpu)
 {
        map->prev = 0;
        map->mask = mp->mask;
 
        struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL);
 
        /* Set option of each CPU we have */
-       for (i = 0; i < cpu__max_cpu(); i++) {
-               if (!perf_cpu_map__has(event_cpus, i) ||
-                   !perf_cpu_map__has(online_cpus, i))
+       for (i = 0; i < cpu__max_cpu().cpu; i++) {
+               struct perf_cpu cpu = { .cpu = i, };
+
+               if (!perf_cpu_map__has(event_cpus, cpu) ||
+                   !perf_cpu_map__has(online_cpus, cpu))
                        continue;
 
                if (option & BIT(ETM_OPT_CTXTID)) {
 
        /* cpu map is not empty, we have specific CPUs to work with */
        if (!perf_cpu_map__empty(event_cpus)) {
-               for (i = 0; i < cpu__max_cpu(); i++) {
-                       if (!perf_cpu_map__has(event_cpus, i) ||
-                           !perf_cpu_map__has(online_cpus, i))
+               for (i = 0; i < cpu__max_cpu().cpu; i++) {
+                       struct perf_cpu cpu = { .cpu = i, };
+
+                       if (!perf_cpu_map__has(event_cpus, cpu) ||
+                           !perf_cpu_map__has(online_cpus, cpu))
                                continue;
 
                        if (cs_etm_is_ete(itr, i))
                }
        } else {
                /* get configuration for all CPUs in the system */
-               for (i = 0; i < cpu__max_cpu(); i++) {
-                       if (!perf_cpu_map__has(online_cpus, i))
+               for (i = 0; i < cpu__max_cpu().cpu; i++) {
+                       struct perf_cpu cpu = { .cpu = i, };
+
+                       if (!perf_cpu_map__has(online_cpus, cpu))
                                continue;
 
                        if (cs_etm_is_ete(itr, i))
        } else {
                /* Make sure all specified CPUs are online */
                for (i = 0; i < perf_cpu_map__nr(event_cpus); i++) {
-                       if (perf_cpu_map__has(event_cpus, i) &&
-                           !perf_cpu_map__has(online_cpus, i))
+                       struct perf_cpu cpu = { .cpu = i, };
+
+                       if (perf_cpu_map__has(event_cpus, cpu) &&
+                           !perf_cpu_map__has(online_cpus, cpu))
                                return -EINVAL;
                }
 
 
        offset = CS_ETM_SNAPSHOT + 1;
 
-       for (i = 0; i < cpu__max_cpu() && offset < priv_size; i++)
-               if (perf_cpu_map__has(cpu_map, i))
+       for (i = 0; i < cpu__max_cpu().cpu && offset < priv_size; i++) {
+               struct perf_cpu cpu = { .cpu = i, };
+
+               if (perf_cpu_map__has(cpu_map, cpu))
                        cs_etm_get_metadata(i, &offset, itr, info);
+       }
 
        perf_cpu_map__put(online_cpus);
 
 
                 * The cpumap should cover all CPUs. Otherwise, some CPUs may
                 * not support some events or have different event IDs.
                 */
-               if (pmu->cpus->nr != cpu__max_cpu())
+               if (pmu->cpus->nr != cpu__max_cpu().cpu)
                        return NULL;
 
                return perf_pmu__find_map(pmu);
 
 
                if (!noaffinity) {
                        CPU_ZERO(&cpuset);
-                       CPU_SET(cpu->map[i % cpu->nr], &cpuset);
+                       CPU_SET(perf_cpu_map__cpu(cpu, i % perf_cpu_map__nr(cpu)).cpu, &cpuset);
 
                        ret = pthread_attr_setaffinity_np(&thread_attr, sizeof(cpu_set_t), &cpuset);
                        if (ret)
 
 
                if (!noaffinity) {
                        CPU_ZERO(&cpuset);
-                       CPU_SET(cpu->map[i % cpu->nr], &cpuset);
+                       CPU_SET(perf_cpu_map__cpu(cpu, i % perf_cpu_map__nr(cpu)).cpu, &cpuset);
 
                        ret = pthread_attr_setaffinity_np(&thread_attr, sizeof(cpu_set_t), &cpuset);
                        if (ret)
 
                        goto errmem;
 
                CPU_ZERO(&cpuset);
-               CPU_SET(cpu->map[i % cpu->nr], &cpuset);
+               CPU_SET(perf_cpu_map__cpu(cpu, i % perf_cpu_map__nr(cpu)).cpu, &cpuset);
 
                ret = pthread_attr_setaffinity_np(&thread_attr, sizeof(cpu_set_t), &cpuset);
                if (ret)
 
                        worker[i].futex = &global_futex;
 
                CPU_ZERO(&cpuset);
-               CPU_SET(cpu->map[i % cpu->nr], &cpuset);
+               CPU_SET(perf_cpu_map__cpu(cpu, i % perf_cpu_map__nr(cpu)).cpu, &cpuset);
 
                if (pthread_attr_setaffinity_np(&thread_attr, sizeof(cpu_set_t), &cpuset))
                        err(EXIT_FAILURE, "pthread_attr_setaffinity_np");
 
        /* create and block all threads */
        for (i = 0; i < params.nthreads; i++) {
                CPU_ZERO(&cpuset);
-               CPU_SET(cpu->map[i % cpu->nr], &cpuset);
+               CPU_SET(perf_cpu_map__cpu(cpu, i % perf_cpu_map__nr(cpu)).cpu, &cpuset);
 
                if (pthread_attr_setaffinity_np(&thread_attr, sizeof(cpu_set_t), &cpuset))
                        err(EXIT_FAILURE, "pthread_attr_setaffinity_np");
 
        /* create and block all threads */
        for (i = 0; i < params.nthreads; i++) {
                CPU_ZERO(&cpuset);
-               CPU_SET(cpu->map[i % cpu->nr], &cpuset);
+               CPU_SET(perf_cpu_map__cpu(cpu, i % perf_cpu_map__nr(cpu)).cpu, &cpuset);
 
                if (pthread_attr_setaffinity_np(&thread_attr, sizeof(cpu_set_t), &cpuset))
                        err(EXIT_FAILURE, "pthread_attr_setaffinity_np");
 
        /* create and block all threads */
        for (i = 0; i < params.nthreads; i++) {
                CPU_ZERO(&cpuset);
-               CPU_SET(cpu->map[i % cpu->nr], &cpuset);
+               CPU_SET(perf_cpu_map__cpu(cpu, i % perf_cpu_map__nr(cpu)).cpu, &cpuset);
 
                if (pthread_attr_setaffinity_np(&thread_attr, sizeof(cpu_set_t), &cpuset))
                        err(EXIT_FAILURE, "pthread_attr_setaffinity_np");
 
 {
        struct numa_node *n;
        unsigned long **nodes;
-       int node, cpu, idx;
+       int node, idx;
+       struct perf_cpu cpu;
        int *cpu2node;
 
        if (c2c.node_info > 2)
        if (!cpu2node)
                return -ENOMEM;
 
-       for (cpu = 0; cpu < c2c.cpus_cnt; cpu++)
-               cpu2node[cpu] = -1;
+       for (idx = 0; idx < c2c.cpus_cnt; idx++)
+               cpu2node[idx] = -1;
 
        c2c.cpu2node = cpu2node;
 
                        continue;
 
                perf_cpu_map__for_each_cpu(cpu, idx, map) {
-                       set_bit(cpu, set);
+                       set_bit(cpu.cpu, set);
 
-                       if (WARN_ONCE(cpu2node[cpu] != -1, "node/cpu topology bug"))
+                       if (WARN_ONCE(cpu2node[cpu.cpu] != -1, "node/cpu topology bug"))
                                return -EINVAL;
 
-                       cpu2node[cpu] = node;
+                       cpu2node[cpu.cpu] = node;
                }
        }
 
 
        int ret;
        int last_cpu;
 
-       last_cpu = perf_cpu_map__cpu(cpumap, cpumap->nr - 1);
+       last_cpu = perf_cpu_map__cpu(cpumap, cpumap->nr - 1).cpu;
        mask_size = last_cpu / 4 + 2; /* one more byte for EOS */
        mask_size += last_cpu / 32; /* ',' is needed for every 32th cpus */
 
 
        int ret = evsel__process_alloc_event(evsel, sample);
 
        if (!ret) {
-               int node1 = cpu__get_node(sample->cpu),
+               int node1 = cpu__get_node((struct perf_cpu){.cpu = sample->cpu}),
                    node2 = evsel__intval(evsel, sample, "node");
 
                if (node1 != node2)
 
        symbol__init(NULL);
 
        if (rec->opts.affinity != PERF_AFFINITY_SYS) {
-               rec->affinity_mask.nbits = cpu__max_cpu();
+               rec->affinity_mask.nbits = cpu__max_cpu().cpu;
                rec->affinity_mask.bits = bitmap_zalloc(rec->affinity_mask.nbits);
                if (!rec->affinity_mask.bits) {
                        pr_err("Failed to allocate thread mask for %zd cpus\n", rec->affinity_mask.nbits);
 
 
 struct perf_sched_map {
        DECLARE_BITMAP(comp_cpus_mask, MAX_CPUS);
-       int                     *comp_cpus;
+       struct perf_cpu         *comp_cpus;
        bool                     comp;
        struct perf_thread_map *color_pids;
        const char              *color_pids_str;
  * Track the current task - that way we can know whether there's any
  * weird events, such as a task being switched away that is not current.
  */
-       int              max_cpu;
+       struct perf_cpu  max_cpu;
        u32              curr_pid[MAX_CPUS];
        struct thread    *curr_thread[MAX_CPUS];
        char             next_shortname1;
        int new_shortname;
        u64 timestamp0, timestamp = sample->time;
        s64 delta;
-       int i, this_cpu = sample->cpu;
+       int i;
+       struct perf_cpu this_cpu = {
+               .cpu = sample->cpu,
+       };
        int cpus_nr;
        bool new_cpu = false;
        const char *color = PERF_COLOR_NORMAL;
        char stimestamp[32];
 
-       BUG_ON(this_cpu >= MAX_CPUS || this_cpu < 0);
+       BUG_ON(this_cpu.cpu >= MAX_CPUS || this_cpu.cpu < 0);
 
-       if (this_cpu > sched->max_cpu)
+       if (this_cpu.cpu > sched->max_cpu.cpu)
                sched->max_cpu = this_cpu;
 
        if (sched->map.comp) {
                cpus_nr = bitmap_weight(sched->map.comp_cpus_mask, MAX_CPUS);
-               if (!test_and_set_bit(this_cpu, sched->map.comp_cpus_mask)) {
+               if (!test_and_set_bit(this_cpu.cpu, sched->map.comp_cpus_mask)) {
                        sched->map.comp_cpus[cpus_nr++] = this_cpu;
                        new_cpu = true;
                }
        } else
-               cpus_nr = sched->max_cpu;
+               cpus_nr = sched->max_cpu.cpu;
 
-       timestamp0 = sched->cpu_last_switched[this_cpu];
-       sched->cpu_last_switched[this_cpu] = timestamp;
+       timestamp0 = sched->cpu_last_switched[this_cpu.cpu];
+       sched->cpu_last_switched[this_cpu.cpu] = timestamp;
        if (timestamp0)
                delta = timestamp - timestamp0;
        else
                return -1;
        }
 
-       sched->curr_thread[this_cpu] = thread__get(sched_in);
+       sched->curr_thread[this_cpu.cpu] = thread__get(sched_in);
 
        printf("  ");
 
        }
 
        for (i = 0; i < cpus_nr; i++) {
-               int cpu = sched->map.comp ? sched->map.comp_cpus[i] : i;
-               struct thread *curr_thread = sched->curr_thread[cpu];
+               struct perf_cpu cpu = {
+                       .cpu = sched->map.comp ? sched->map.comp_cpus[i].cpu : i,
+               };
+               struct thread *curr_thread = sched->curr_thread[cpu.cpu];
                struct thread_runtime *curr_tr;
                const char *pid_color = color;
                const char *cpu_color = color;
                if (sched->map.color_cpus && perf_cpu_map__has(sched->map.color_cpus, cpu))
                        cpu_color = COLOR_CPUS;
 
-               if (cpu != this_cpu)
+               if (cpu.cpu != this_cpu.cpu)
                        color_fprintf(stdout, color, " ");
                else
                        color_fprintf(stdout, cpu_color, "*");
 
-               if (sched->curr_thread[cpu]) {
-                       curr_tr = thread__get_runtime(sched->curr_thread[cpu]);
+               if (sched->curr_thread[cpu.cpu]) {
+                       curr_tr = thread__get_runtime(sched->curr_thread[cpu.cpu]);
                        if (curr_tr == NULL) {
                                thread__put(sched_in);
                                return -1;
 
 static void timehist_header(struct perf_sched *sched)
 {
-       u32 ncpus = sched->max_cpu + 1;
+       u32 ncpus = sched->max_cpu.cpu + 1;
        u32 i, j;
 
        printf("%15s %6s ", "time", "cpu");
        struct thread_runtime *tr = thread__priv(thread);
        const char *next_comm = evsel__strval(evsel, sample, "next_comm");
        const u32 next_pid = evsel__intval(evsel, sample, "next_pid");
-       u32 max_cpus = sched->max_cpu + 1;
+       u32 max_cpus = sched->max_cpu.cpu + 1;
        char tstr[64];
        char nstr[30];
        u64 wait_time;
        timestamp__scnprintf_usec(sample->time, tstr, sizeof(tstr));
        printf("%15s [%04d] ", tstr, sample->cpu);
        if (sched->show_cpu_visual)
-               printf(" %*s ", sched->max_cpu + 1, "");
+               printf(" %*s ", sched->max_cpu.cpu + 1, "");
 
        printf(" %-*s ", comm_width, timehist_get_commstr(thread));
 
 {
        struct thread *thread;
        char tstr[64];
-       u32 max_cpus = sched->max_cpu + 1;
+       u32 max_cpus;
        u32 ocpu, dcpu;
 
        if (sched->summary_only)
                return;
 
-       max_cpus = sched->max_cpu + 1;
+       max_cpus = sched->max_cpu.cpu + 1;
        ocpu = evsel__intval(evsel, sample, "orig_cpu");
        dcpu = evsel__intval(evsel, sample, "dest_cpu");
 
 
        printf("    Total scheduling time (msec): ");
        print_sched_time(hist_time, 2);
-       printf(" (x %d)\n", sched->max_cpu);
+       printf(" (x %d)\n", sched->max_cpu.cpu);
 }
 
 typedef int (*sched_handler)(struct perf_tool *tool,
 {
        struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
        int err = 0;
-       int this_cpu = sample->cpu;
+       struct perf_cpu this_cpu = {
+               .cpu = sample->cpu,
+       };
 
-       if (this_cpu > sched->max_cpu)
+       if (this_cpu.cpu > sched->max_cpu.cpu)
                sched->max_cpu = this_cpu;
 
        if (evsel->handler != NULL) {
                goto out;
 
        /* pre-allocate struct for per-CPU idle stats */
-       sched->max_cpu = session->header.env.nr_cpus_online;
-       if (sched->max_cpu == 0)
-               sched->max_cpu = 4;
-       if (init_idle_threads(sched->max_cpu))
+       sched->max_cpu.cpu = session->header.env.nr_cpus_online;
+       if (sched->max_cpu.cpu == 0)
+               sched->max_cpu.cpu = 4;
+       if (init_idle_threads(sched->max_cpu.cpu))
                goto out;
 
        /* summary_only implies summary option, but don't overwrite summary if set */
 {
        struct perf_cpu_map *map;
 
-       sched->max_cpu  = sysconf(_SC_NPROCESSORS_CONF);
+       sched->max_cpu.cpu  = sysconf(_SC_NPROCESSORS_CONF);
 
        if (sched->map.comp) {
-               sched->map.comp_cpus = zalloc(sched->max_cpu * sizeof(int));
+               sched->map.comp_cpus = zalloc(sched->max_cpu.cpu * sizeof(int));
                if (!sched->map.comp_cpus)
                        return -1;
        }
 
 static void __process_stat(struct evsel *counter, u64 tstamp)
 {
        int nthreads = perf_thread_map__nr(counter->core.threads);
-       int idx, cpu, thread;
+       int idx, thread;
+       struct perf_cpu cpu;
        static int header_printed;
 
        if (counter->core.system_wide)
                        counts = perf_counts(counter->counts, idx, thread);
 
                        printf("%3d %8d %15" PRIu64 " %15" PRIu64 " %15" PRIu64 " %15" PRIu64 " %s\n",
-                               cpu,
+                               cpu.cpu,
                                perf_thread_map__pid(counter->core.threads, thread),
                                counts->val,
                                counts->ena,
 
                return false;
 
        for (int i = 0; i < a->core.cpus->nr; i++) {
-               if (a->core.cpus->map[i] != b->core.cpus->map[i])
+               if (a->core.cpus->map[i].cpu != b->core.cpus->map[i].cpu)
                        return false;
        }
 
                                   struct perf_counts_values *count)
 {
        struct perf_sample_id *sid = SID(counter, cpu_map_idx, thread);
-       int cpu = perf_cpu_map__cpu(evsel__cpus(counter), cpu_map_idx);
+       struct perf_cpu cpu = perf_cpu_map__cpu(evsel__cpus(counter), cpu_map_idx);
 
        return perf_event__synthesize_stat(NULL, cpu, thread, sid->id, count,
                                           process_synthesized_event, NULL);
                        fprintf(stat_config.output,
                                "%s: %d: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
                                        evsel__name(counter),
-                                       perf_cpu_map__cpu(evsel__cpus(counter), cpu_map_idx),
+                                       perf_cpu_map__cpu(evsel__cpus(counter),
+                                                         cpu_map_idx).cpu,
                                        count->val, count->ena, count->run);
                }
        }
 };
 
 static struct aggr_cpu_id perf_stat__get_socket(struct perf_stat_config *config __maybe_unused,
-                                               int cpu)
+                                               struct perf_cpu cpu)
 {
        return aggr_cpu_id__socket(cpu, /*data=*/NULL);
 }
 
 static struct aggr_cpu_id perf_stat__get_die(struct perf_stat_config *config __maybe_unused,
-                                            int cpu)
+                                            struct perf_cpu cpu)
 {
        return aggr_cpu_id__die(cpu, /*data=*/NULL);
 }
 
 static struct aggr_cpu_id perf_stat__get_core(struct perf_stat_config *config __maybe_unused,
-                                             int cpu)
+                                             struct perf_cpu cpu)
 {
        return aggr_cpu_id__core(cpu, /*data=*/NULL);
 }
 
 static struct aggr_cpu_id perf_stat__get_node(struct perf_stat_config *config __maybe_unused,
-                                             int cpu)
+                                             struct perf_cpu cpu)
 {
        return aggr_cpu_id__node(cpu, /*data=*/NULL);
 }
 
 static struct aggr_cpu_id perf_stat__get_aggr(struct perf_stat_config *config,
-                                             aggr_get_id_t get_id, int cpu)
+                                             aggr_get_id_t get_id, struct perf_cpu cpu)
 {
        struct aggr_cpu_id id = aggr_cpu_id__empty();
 
-       if (aggr_cpu_id__is_empty(&config->cpus_aggr_map->map[cpu]))
-               config->cpus_aggr_map->map[cpu] = get_id(config, cpu);
+       if (aggr_cpu_id__is_empty(&config->cpus_aggr_map->map[cpu.cpu]))
+               config->cpus_aggr_map->map[cpu.cpu] = get_id(config, cpu);
 
-       id = config->cpus_aggr_map->map[cpu];
+       id = config->cpus_aggr_map->map[cpu.cpu];
        return id;
 }
 
 static struct aggr_cpu_id perf_stat__get_socket_cached(struct perf_stat_config *config,
-                                                      int cpu)
+                                                      struct perf_cpu cpu)
 {
        return perf_stat__get_aggr(config, perf_stat__get_socket, cpu);
 }
 
 static struct aggr_cpu_id perf_stat__get_die_cached(struct perf_stat_config *config,
-                                                   int cpu)
+                                                   struct perf_cpu cpu)
 {
        return perf_stat__get_aggr(config, perf_stat__get_die, cpu);
 }
 
 static struct aggr_cpu_id perf_stat__get_core_cached(struct perf_stat_config *config,
-                                                    int cpu)
+                                                    struct perf_cpu cpu)
 {
        return perf_stat__get_aggr(config, perf_stat__get_core, cpu);
 }
 
 static struct aggr_cpu_id perf_stat__get_node_cached(struct perf_stat_config *config,
-                                                    int cpu)
+                                                    struct perf_cpu cpu)
 {
        return perf_stat__get_aggr(config, perf_stat__get_node, cpu);
 }
         * taking the highest cpu number to be the size of
         * the aggregation translate cpumap.
         */
-       nr = perf_cpu_map__max(evsel_list->core.cpus);
+       nr = perf_cpu_map__max(evsel_list->core.cpus).cpu;
        stat_config.cpus_aggr_map = cpu_aggr_map__empty_new(nr + 1);
        return stat_config.cpus_aggr_map ? 0 : -ENOMEM;
 }
        stat_config.cpus_aggr_map = NULL;
 }
 
-static struct aggr_cpu_id perf_env__get_socket_aggr_by_cpu(int cpu, void *data)
+static struct aggr_cpu_id perf_env__get_socket_aggr_by_cpu(struct perf_cpu cpu, void *data)
 {
        struct perf_env *env = data;
        struct aggr_cpu_id id = aggr_cpu_id__empty();
 
-       if (cpu != -1)
-               id.socket = env->cpu[cpu].socket_id;
+       if (cpu.cpu != -1)
+               id.socket = env->cpu[cpu.cpu].socket_id;
 
        return id;
 }
 
-static struct aggr_cpu_id perf_env__get_die_aggr_by_cpu(int cpu, void *data)
+static struct aggr_cpu_id perf_env__get_die_aggr_by_cpu(struct perf_cpu cpu, void *data)
 {
        struct perf_env *env = data;
        struct aggr_cpu_id id = aggr_cpu_id__empty();
 
-       if (cpu != -1) {
+       if (cpu.cpu != -1) {
                /*
                 * die_id is relative to socket, so start
                 * with the socket ID and then add die to
                 * make a unique ID.
                 */
-               id.socket = env->cpu[cpu].socket_id;
-               id.die = env->cpu[cpu].die_id;
+               id.socket = env->cpu[cpu.cpu].socket_id;
+               id.die = env->cpu[cpu.cpu].die_id;
        }
 
        return id;
 }
 
-static struct aggr_cpu_id perf_env__get_core_aggr_by_cpu(int cpu, void *data)
+static struct aggr_cpu_id perf_env__get_core_aggr_by_cpu(struct perf_cpu cpu, void *data)
 {
        struct perf_env *env = data;
        struct aggr_cpu_id id = aggr_cpu_id__empty();
 
-       if (cpu != -1) {
+       if (cpu.cpu != -1) {
                /*
                 * core_id is relative to socket and die,
                 * we need a global id. So we set
                 * socket, die id and core id
                 */
-               id.socket = env->cpu[cpu].socket_id;
-               id.die = env->cpu[cpu].die_id;
-               id.core = env->cpu[cpu].core_id;
+               id.socket = env->cpu[cpu.cpu].socket_id;
+               id.die = env->cpu[cpu.cpu].die_id;
+               id.core = env->cpu[cpu.cpu].core_id;
        }
 
        return id;
 }
 
-static struct aggr_cpu_id perf_env__get_node_aggr_by_cpu(int cpu, void *data)
+static struct aggr_cpu_id perf_env__get_node_aggr_by_cpu(struct perf_cpu cpu, void *data)
 {
        struct aggr_cpu_id id = aggr_cpu_id__empty();
 
 }
 
 static struct aggr_cpu_id perf_stat__get_socket_file(struct perf_stat_config *config __maybe_unused,
-                                                    int cpu)
+                                                    struct perf_cpu cpu)
 {
        return perf_env__get_socket_aggr_by_cpu(cpu, &perf_stat.session->header.env);
 }
 static struct aggr_cpu_id perf_stat__get_die_file(struct perf_stat_config *config __maybe_unused,
-                                                 int cpu)
+                                                 struct perf_cpu cpu)
 {
        return perf_env__get_die_aggr_by_cpu(cpu, &perf_stat.session->header.env);
 }
 
 static struct aggr_cpu_id perf_stat__get_core_file(struct perf_stat_config *config __maybe_unused,
-                                                  int cpu)
+                                                  struct perf_cpu cpu)
 {
        return perf_env__get_core_aggr_by_cpu(cpu, &perf_stat.session->header.env);
 }
 
 static struct aggr_cpu_id perf_stat__get_node_file(struct perf_stat_config *config __maybe_unused,
-                                                  int cpu)
+                                                  struct perf_cpu cpu)
 {
        return perf_env__get_node_aggr_by_cpu(cpu, &perf_stat.session->header.env);
 }
 
 
 #define WRITE_ASS(field, fmt) __WRITE_ASS(field, fmt, attr->field)
 
-static int store_event(struct perf_event_attr *attr, pid_t pid, int cpu,
+static int store_event(struct perf_event_attr *attr, pid_t pid, struct perf_cpu cpu,
                       int fd, int group_fd, unsigned long flags)
 {
        FILE *file;
        /* syscall arguments */
        __WRITE_ASS(fd,       "d", fd);
        __WRITE_ASS(group_fd, "d", group_fd);
-       __WRITE_ASS(cpu,      "d", cpu);
+       __WRITE_ASS(cpu,      "d", cpu.cpu);
        __WRITE_ASS(pid,      "d", pid);
        __WRITE_ASS(flags,   "lu", flags);
 
        return 0;
 }
 
-void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu,
+void test_attr__open(struct perf_event_attr *attr, pid_t pid, struct perf_cpu cpu,
                     int fd, int group_fd, unsigned long flags)
 {
        int errno_saved = errno;
 
 
        if (map && bm) {
                for (i = 0; i < map->nr; i++)
-                       set_bit(map->map[i], bm);
+                       set_bit(map->map[i].cpu, bm);
        }
 
        if (map)
 
        TEST_ASSERT_VAL("wrong nr",  map->nr == 20);
 
        for (i = 0; i < 20; i++) {
-               TEST_ASSERT_VAL("wrong cpu", map->map[i] == i);
+               TEST_ASSERT_VAL("wrong cpu", map->map[i].cpu == i);
        }
 
        perf_cpu_map__put(map);
 
        map = cpu_map__new_data(data);
        TEST_ASSERT_VAL("wrong nr",  map->nr == 2);
-       TEST_ASSERT_VAL("wrong cpu", map->map[0] == 1);
-       TEST_ASSERT_VAL("wrong cpu", map->map[1] == 256);
+       TEST_ASSERT_VAL("wrong cpu", map->map[0].cpu == 1);
+       TEST_ASSERT_VAL("wrong cpu", map->map[1].cpu == 256);
        TEST_ASSERT_VAL("wrong refcnt", refcount_read(&map->refcnt) == 1);
        perf_cpu_map__put(map);
        return 0;
 
        TEST_ASSERT_VAL("wrong id", ev->id == 123);
        TEST_ASSERT_VAL("wrong type", ev->type == PERF_EVENT_UPDATE__CPUS);
        TEST_ASSERT_VAL("wrong cpus", map->nr == 3);
-       TEST_ASSERT_VAL("wrong cpus", map->map[0] == 1);
-       TEST_ASSERT_VAL("wrong cpus", map->map[1] == 2);
-       TEST_ASSERT_VAL("wrong cpus", map->map[2] == 3);
+       TEST_ASSERT_VAL("wrong cpus", map->map[0].cpu == 1);
+       TEST_ASSERT_VAL("wrong cpus", map->map[1].cpu == 2);
+       TEST_ASSERT_VAL("wrong cpus", map->map[2].cpu == 3);
        perf_cpu_map__put(map);
        return 0;
 }
 
 
        if (map && bm) {
                for (i = 0; i < map->nr; i++) {
-                       set_bit(map->map[i], bm);
+                       set_bit(map->map[i].cpu, bm);
                }
        }
 
 
        }
 
        CPU_ZERO(&cpu_set);
-       CPU_SET(cpus->map[0], &cpu_set);
+       CPU_SET(cpus->map[0].cpu, &cpu_set);
        sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
        if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
                pr_debug("sched_setaffinity() failed on CPU %d: %s ",
-                        cpus->map[0], str_error_r(errno, sbuf, sizeof(sbuf)));
+                        cpus->map[0].cpu, str_error_r(errno, sbuf, sizeof(sbuf)));
                goto out_free_cpus;
        }
 
 
 static int test__openat_syscall_event_on_all_cpus(struct test_suite *test __maybe_unused,
                                                  int subtest __maybe_unused)
 {
-       int err = -1, fd, idx, cpu;
+       int err = -1, fd, idx;
+       struct perf_cpu cpu;
        struct perf_cpu_map *cpus;
        struct evsel *evsel;
        unsigned int nr_openat_calls = 111, i;
                 * without CPU_ALLOC. 1024 cpus in 2010 still seems
                 * a reasonable upper limit tho :-)
                 */
-               if (cpu >= CPU_SETSIZE) {
-                       pr_debug("Ignoring CPU %d\n", cpu);
+               if (cpu.cpu >= CPU_SETSIZE) {
+                       pr_debug("Ignoring CPU %d\n", cpu.cpu);
                        continue;
                }
 
-               CPU_SET(cpu, &cpu_set);
+               CPU_SET(cpu.cpu, &cpu_set);
                if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
                        pr_debug("sched_setaffinity() failed on CPU %d: %s ",
-                                cpu,
+                                cpu.cpu,
                                 str_error_r(errno, sbuf, sizeof(sbuf)));
                        goto out_close_fd;
                }
                        fd = openat(0, "/etc/passwd", O_RDONLY);
                        close(fd);
                }
-               CPU_CLR(cpu, &cpu_set);
+               CPU_CLR(cpu.cpu, &cpu_set);
        }
 
        evsel->core.cpus = perf_cpu_map__get(cpus);
        perf_cpu_map__for_each_cpu(cpu, idx, cpus) {
                unsigned int expected;
 
-               if (cpu >= CPU_SETSIZE)
+               if (cpu.cpu >= CPU_SETSIZE)
                        continue;
 
                if (evsel__read_on_cpu(evsel, idx, 0) < 0) {
                expected = nr_openat_calls + idx;
                if (perf_counts(evsel->counts, idx, 0)->val != expected) {
                        pr_debug("evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n",
-                                expected, cpu, perf_counts(evsel->counts, idx, 0)->val);
+                                expected, cpu.cpu, perf_counts(evsel->counts, idx, 0)->val);
                        err = -1;
                }
        }
 
        count.run = 300;
 
        TEST_ASSERT_VAL("failed to synthesize stat_config",
-               !perf_event__synthesize_stat(NULL, 1, 2, 3, &count, process_stat_event, NULL));
+                       !perf_event__synthesize_stat(NULL, (struct perf_cpu){.cpu = 1}, 2, 3,
+                                                    &count, process_stat_event, NULL));
 
        return 0;
 }
 
        TEST_ASSERT_VAL("Session header CPU map not set", session->header.env.cpu);
 
        for (i = 0; i < session->header.env.nr_cpus_avail; i++) {
-               if (!perf_cpu_map__has(map, i))
+               struct perf_cpu cpu = { .cpu = i };
+
+               if (!perf_cpu_map__has(map, cpu))
                        continue;
                pr_debug("CPU %d, core %d, socket %d\n", i,
                         session->header.env.cpu[i].core_id,
        // Test that CPU ID contains socket, die, core and CPU
        for (i = 0; i < map->nr; i++) {
                id = aggr_cpu_id__cpu(perf_cpu_map__cpu(map, i), NULL);
-               TEST_ASSERT_VAL("Cpu map - CPU ID doesn't match", map->map[i] == id.cpu);
+               TEST_ASSERT_VAL("Cpu map - CPU ID doesn't match", map->map[i].cpu == id.cpu.cpu);
 
                TEST_ASSERT_VAL("Cpu map - Core ID doesn't match",
-                       session->header.env.cpu[map->map[i]].core_id == id.core);
+                       session->header.env.cpu[map->map[i].cpu].core_id == id.core);
                TEST_ASSERT_VAL("Cpu map - Socket ID doesn't match",
-                       session->header.env.cpu[map->map[i]].socket_id == id.socket);
+                       session->header.env.cpu[map->map[i].cpu].socket_id == id.socket);
 
                TEST_ASSERT_VAL("Cpu map - Die ID doesn't match",
-                       session->header.env.cpu[map->map[i]].die_id == id.die);
+                       session->header.env.cpu[map->map[i].cpu].die_id == id.die);
                TEST_ASSERT_VAL("Cpu map - Node ID is set", id.node == -1);
                TEST_ASSERT_VAL("Cpu map - Thread is set", id.thread == -1);
        }
        for (i = 0; i < map->nr; i++) {
                id = aggr_cpu_id__core(perf_cpu_map__cpu(map, i), NULL);
                TEST_ASSERT_VAL("Core map - Core ID doesn't match",
-                       session->header.env.cpu[map->map[i]].core_id == id.core);
+                       session->header.env.cpu[map->map[i].cpu].core_id == id.core);
 
                TEST_ASSERT_VAL("Core map - Socket ID doesn't match",
-                       session->header.env.cpu[map->map[i]].socket_id == id.socket);
+                       session->header.env.cpu[map->map[i].cpu].socket_id == id.socket);
 
                TEST_ASSERT_VAL("Core map - Die ID doesn't match",
-                       session->header.env.cpu[map->map[i]].die_id == id.die);
+                       session->header.env.cpu[map->map[i].cpu].die_id == id.die);
                TEST_ASSERT_VAL("Core map - Node ID is set", id.node == -1);
                TEST_ASSERT_VAL("Core map - Thread is set", id.thread == -1);
        }
        for (i = 0; i < map->nr; i++) {
                id = aggr_cpu_id__die(perf_cpu_map__cpu(map, i), NULL);
                TEST_ASSERT_VAL("Die map - Socket ID doesn't match",
-                       session->header.env.cpu[map->map[i]].socket_id == id.socket);
+                       session->header.env.cpu[map->map[i].cpu].socket_id == id.socket);
 
                TEST_ASSERT_VAL("Die map - Die ID doesn't match",
-                       session->header.env.cpu[map->map[i]].die_id == id.die);
+                       session->header.env.cpu[map->map[i].cpu].die_id == id.die);
 
                TEST_ASSERT_VAL("Die map - Node ID is set", id.node == -1);
                TEST_ASSERT_VAL("Die map - Core is set", id.core == -1);
-               TEST_ASSERT_VAL("Die map - CPU is set", id.cpu == -1);
+               TEST_ASSERT_VAL("Die map - CPU is set", id.cpu.cpu == -1);
                TEST_ASSERT_VAL("Die map - Thread is set", id.thread == -1);
        }
 
        for (i = 0; i < map->nr; i++) {
                id = aggr_cpu_id__socket(perf_cpu_map__cpu(map, i), NULL);
                TEST_ASSERT_VAL("Socket map - Socket ID doesn't match",
-                       session->header.env.cpu[map->map[i]].socket_id == id.socket);
+                       session->header.env.cpu[map->map[i].cpu].socket_id == id.socket);
 
                TEST_ASSERT_VAL("Socket map - Node ID is set", id.node == -1);
                TEST_ASSERT_VAL("Socket map - Die ID is set", id.die == -1);
                TEST_ASSERT_VAL("Socket map - Core is set", id.core == -1);
-               TEST_ASSERT_VAL("Socket map - CPU is set", id.cpu == -1);
+               TEST_ASSERT_VAL("Socket map - CPU is set", id.cpu.cpu == -1);
                TEST_ASSERT_VAL("Socket map - Thread is set", id.thread == -1);
        }
 
                TEST_ASSERT_VAL("Node map - Socket is set", id.socket == -1);
                TEST_ASSERT_VAL("Node map - Die ID is set", id.die == -1);
                TEST_ASSERT_VAL("Node map - Core is set", id.core == -1);
-               TEST_ASSERT_VAL("Node map - CPU is set", id.cpu == -1);
+               TEST_ASSERT_VAL("Node map - CPU is set", id.cpu.cpu == -1);
                TEST_ASSERT_VAL("Node map - Thread is set", id.thread == -1);
        }
        perf_session__delete(session);
 
 
 static int get_cpu_set_size(void)
 {
-       int sz = cpu__max_cpu() + 8 - 1;
+       int sz = cpu__max_cpu().cpu + 8 - 1;
        /*
         * sched_getaffinity doesn't like masks smaller than the kernel.
         * Hopefully that's big enough.
 
        mm->prev = 0;
        mm->idx = mp->idx;
        mm->tid = mp->tid;
-       mm->cpu = mp->cpu;
+       mm->cpu = mp->cpu.cpu;
 
        if (!mp->len) {
                mm->base = NULL;
                else
                        mp->tid = -1;
        } else {
-               mp->cpu = -1;
+               mp->cpu.cpu = -1;
                mp->tid = perf_thread_map__pid(evlist->core.threads, idx);
        }
 }
        if (!queue->set) {
                queue->set = true;
                queue->tid = buffer->tid;
-               queue->cpu = buffer->cpu;
+               queue->cpu = buffer->cpu.cpu;
        }
 
        buffer->buffer_nr = queues->next_buffer_nr++;
        return 0;
 }
 
-static bool filter_cpu(struct perf_session *session, int cpu)
+static bool filter_cpu(struct perf_session *session, struct perf_cpu cpu)
 {
        unsigned long *cpu_bitmap = session->itrace_synth_opts->cpu_bitmap;
 
-       return cpu_bitmap && cpu != -1 && !test_bit(cpu, cpu_bitmap);
+       return cpu_bitmap && cpu.cpu != -1 && !test_bit(cpu.cpu, cpu_bitmap);
 }
 
 static int auxtrace_queues__add_buffer(struct auxtrace_queues *queues,
        struct auxtrace_buffer buffer = {
                .pid = -1,
                .tid = event->auxtrace.tid,
-               .cpu = event->auxtrace.cpu,
+               .cpu = { event->auxtrace.cpu },
                .data_offset = data_offset,
                .offset = event->auxtrace.offset,
                .reference = event->auxtrace.reference,
 
 #include <linux/list.h>
 #include <linux/perf_event.h>
 #include <linux/types.h>
+#include <internal/cpumap.h>
 #include <asm/bitsperlong.h>
 #include <asm/barrier.h>
 
        size_t                  size;
        pid_t                   pid;
        pid_t                   tid;
-       int                     cpu;
+       struct perf_cpu         cpu;
        void                    *data;
        off_t                   data_offset;
        void                    *mmap_addr;
        int             prot;
        int             idx;
        pid_t           tid;
-       int             cpu;
+       struct perf_cpu cpu;
 };
 
 /**
 
                    filter_type == BPERF_FILTER_TGID)
                        key = evsel->core.threads->map[i].pid;
                else if (filter_type == BPERF_FILTER_CPU)
-                       key = evsel->core.cpus->map[i];
+                       key = evsel->core.cpus->map[i].cpu;
                else
                        break;
 
 
        num_cpu = all_cpu_map->nr;
        for (i = 0; i < num_cpu; i++) {
-               cpu = all_cpu_map->map[i];
+               cpu = all_cpu_map->map[i].cpu;
                bperf_trigger_reading(evsel->bperf_leader_prog_fd, cpu);
        }
        return 0;
 static int bperf__read(struct evsel *evsel)
 {
        struct bperf_follower_bpf *skel = evsel->follower_skel;
-       __u32 num_cpu_bpf = cpu__max_cpu();
+       __u32 num_cpu_bpf = cpu__max_cpu().cpu;
        struct bpf_perf_event_value values[num_cpu_bpf];
        int reading_map_fd, err = 0;
        __u32 i;
        reading_map_fd = bpf_map__fd(skel->maps.accum_readings);
 
        for (i = 0; i < bpf_map__max_entries(skel->maps.accum_readings); i++) {
+               struct perf_cpu entry;
                __u32 cpu;
 
                err = bpf_map_lookup_elem(reading_map_fd, &i, values);
                case BPERF_FILTER_GLOBAL:
                        assert(i == 0);
 
-                       perf_cpu_map__for_each_cpu(cpu, j, all_cpu_map) {
+                       perf_cpu_map__for_each_cpu(entry, j, all_cpu_map) {
+                               cpu = entry.cpu;
                                perf_counts(evsel->counts, cpu, 0)->val = values[cpu].counter;
                                perf_counts(evsel->counts, cpu, 0)->ena = values[cpu].enabled;
                                perf_counts(evsel->counts, cpu, 0)->run = values[cpu].running;
                        }
                        break;
                case BPERF_FILTER_CPU:
-                       cpu = evsel->core.cpus->map[i];
+                       cpu = evsel->core.cpus->map[i].cpu;
                        perf_counts(evsel->counts, i, 0)->val = values[cpu].counter;
                        perf_counts(evsel->counts, i, 0)->ena = values[cpu].enabled;
                        perf_counts(evsel->counts, i, 0)->run = values[cpu].running;
 
        struct cgroup *cgrp, *leader_cgrp;
        __u32 i, cpu;
        __u32 nr_cpus = evlist->core.all_cpus->nr;
-       int total_cpus = cpu__max_cpu();
+       int total_cpus = cpu__max_cpu().cpu;
        int map_size, map_fd;
        int prog_fd, err;
 
                        for (cpu = 0; cpu < nr_cpus; cpu++) {
                                int fd = FD(evsel, cpu);
                                __u32 idx = evsel->core.idx * total_cpus +
-                                       evlist->core.all_cpus->map[cpu];
+                                       evlist->core.all_cpus->map[cpu].cpu;
 
                                err = bpf_map_update_elem(map_fd, &idx, &fd,
                                                          BPF_ANY);
        int prog_fd = bpf_program__fd(skel->progs.trigger_read);
 
        for (i = 0; i < nr_cpus; i++) {
-               cpu = evlist->core.all_cpus->map[i];
+               cpu = evlist->core.all_cpus->map[i].cpu;
                bperf_trigger_reading(prog_fd, cpu);
        }
 
 {
        struct evlist *evlist = evsel->evlist;
        int i, cpu, nr_cpus = evlist->core.all_cpus->nr;
-       int total_cpus = cpu__max_cpu();
+       int total_cpus = cpu__max_cpu().cpu;
        struct perf_counts_values *counts;
        struct bpf_perf_event_value *values;
        int reading_map_fd, err = 0;
                }
 
                for (i = 0; i < nr_cpus; i++) {
-                       cpu = evlist->core.all_cpus->map[i];
+                       cpu = evlist->core.all_cpus->map[i].cpu;
 
                        counts = perf_counts(evsel->counts, i, 0);
                        counts->val = values[cpu].counter;
 
                fd = bpf_map__fd(skel->maps.cpu_filter);
 
                for (i = 0; i < ncpus; i++) {
-                       cpu = perf_cpu_map__cpu(ftrace->evlist->core.cpus, i);
+                       cpu = perf_cpu_map__cpu(ftrace->evlist->core.cpus, i).cpu;
                        bpf_map_update_elem(fd, &cpu, &val, BPF_ANY);
                }
        }
        int i, fd, err;
        u32 idx;
        u64 *hist;
-       int ncpus = cpu__max_cpu();
+       int ncpus = cpu__max_cpu().cpu;
 
        fd = bpf_map__fd(skel->maps.latency);
 
 
 #include <linux/ctype.h>
 #include <linux/zalloc.h>
 
-static int max_cpu_num;
-static int max_present_cpu_num;
+static struct perf_cpu max_cpu_num;
+static struct perf_cpu max_present_cpu_num;
 static int max_node_num;
 /**
  * The numa node X as read from /sys/devices/system/node/nodeX indexed by the
                         * otherwise it would become 65535.
                         */
                        if (cpus->cpu[i] == (u16) -1)
-                               map->map[i] = -1;
+                               map->map[i].cpu = -1;
                        else
-                               map->map[i] = (int) cpus->cpu[i];
+                               map->map[i].cpu = (int) cpus->cpu[i];
                }
        }
 
                int cpu, i = 0;
 
                for_each_set_bit(cpu, mask->mask, nbits)
-                       map->map[i++] = cpu;
+                       map->map[i++].cpu = cpu;
        }
        return map;
 
 
                cpus->nr = nr;
                for (i = 0; i < nr; i++)
-                       cpus->map[i] = -1;
+                       cpus->map[i].cpu = -1;
 
                refcount_set(&cpus->refcnt, 1);
        }
        return sysfs__read_int(path, value);
 }
 
-int cpu__get_socket_id(int cpu)
+int cpu__get_socket_id(struct perf_cpu cpu)
 {
-       int value, ret = cpu__get_topology_int(cpu, "physical_package_id", &value);
+       int value, ret = cpu__get_topology_int(cpu.cpu, "physical_package_id", &value);
        return ret ?: value;
 }
 
-struct aggr_cpu_id aggr_cpu_id__socket(int cpu, void *data __maybe_unused)
+struct aggr_cpu_id aggr_cpu_id__socket(struct perf_cpu cpu, void *data __maybe_unused)
 {
        struct aggr_cpu_id id = aggr_cpu_id__empty();
 
                                       aggr_cpu_id_get_t get_id,
                                       void *data)
 {
-       int cpu, idx;
+       int idx;
+       struct perf_cpu cpu;
        struct cpu_aggr_map *c = cpu_aggr_map__empty_new(cpus->nr);
 
        if (!c)
 
 }
 
-int cpu__get_die_id(int cpu)
+int cpu__get_die_id(struct perf_cpu cpu)
 {
-       int value, ret = cpu__get_topology_int(cpu, "die_id", &value);
+       int value, ret = cpu__get_topology_int(cpu.cpu, "die_id", &value);
 
        return ret ?: value;
 }
 
-struct aggr_cpu_id aggr_cpu_id__die(int cpu, void *data)
+struct aggr_cpu_id aggr_cpu_id__die(struct perf_cpu cpu, void *data)
 {
        struct aggr_cpu_id id;
        int die;
        return id;
 }
 
-int cpu__get_core_id(int cpu)
+int cpu__get_core_id(struct perf_cpu cpu)
 {
-       int value, ret = cpu__get_topology_int(cpu, "core_id", &value);
+       int value, ret = cpu__get_topology_int(cpu.cpu, "core_id", &value);
        return ret ?: value;
 }
 
-struct aggr_cpu_id aggr_cpu_id__core(int cpu, void *data)
+struct aggr_cpu_id aggr_cpu_id__core(struct perf_cpu cpu, void *data)
 {
        struct aggr_cpu_id id;
        int core = cpu__get_core_id(cpu);
 
 }
 
-struct aggr_cpu_id aggr_cpu_id__cpu(int cpu, void *data)
+struct aggr_cpu_id aggr_cpu_id__cpu(struct perf_cpu cpu, void *data)
 {
        struct aggr_cpu_id id;
 
 
 }
 
-struct aggr_cpu_id aggr_cpu_id__node(int cpu, void *data __maybe_unused)
+struct aggr_cpu_id aggr_cpu_id__node(struct perf_cpu cpu, void *data __maybe_unused)
 {
        struct aggr_cpu_id id = aggr_cpu_id__empty();
 
        int ret = -1;
 
        /* set up default */
-       max_cpu_num = 4096;
-       max_present_cpu_num = 4096;
+       max_cpu_num.cpu = 4096;
+       max_present_cpu_num.cpu = 4096;
 
        mnt = sysfs__mountpoint();
        if (!mnt)
                goto out;
        }
 
-       ret = get_max_num(path, &max_cpu_num);
+       ret = get_max_num(path, &max_cpu_num.cpu);
        if (ret)
                goto out;
 
                goto out;
        }
 
-       ret = get_max_num(path, &max_present_cpu_num);
+       ret = get_max_num(path, &max_present_cpu_num.cpu);
 
 out:
        if (ret)
-               pr_err("Failed to read max cpus, using default of %d\n", max_cpu_num);
+               pr_err("Failed to read max cpus, using default of %d\n", max_cpu_num.cpu);
 }
 
 /* Determine highest possible node in the system for sparse allocation */
        return max_node_num;
 }
 
-int cpu__max_cpu(void)
+struct perf_cpu cpu__max_cpu(void)
 {
-       if (unlikely(!max_cpu_num))
+       if (unlikely(!max_cpu_num.cpu))
                set_max_cpu_num();
 
        return max_cpu_num;
 }
 
-int cpu__max_present_cpu(void)
+struct perf_cpu cpu__max_present_cpu(void)
 {
-       if (unlikely(!max_present_cpu_num))
+       if (unlikely(!max_present_cpu_num.cpu))
                set_max_cpu_num();
 
        return max_present_cpu_num;
 }
 
 
-int cpu__get_node(int cpu)
+int cpu__get_node(struct perf_cpu cpu)
 {
        if (unlikely(cpunode_map == NULL)) {
                pr_debug("cpu_map not initialized\n");
                return -1;
        }
 
-       return cpunode_map[cpu];
+       return cpunode_map[cpu.cpu];
 }
 
 static int init_cpunode_map(void)
        set_max_cpu_num();
        set_max_node_num();
 
-       cpunode_map = calloc(max_cpu_num, sizeof(int));
+       cpunode_map = calloc(max_cpu_num.cpu, sizeof(int));
        if (!cpunode_map) {
                pr_err("%s: calloc failed\n", __func__);
                return -1;
        }
 
-       for (i = 0; i < max_cpu_num; i++)
+       for (i = 0; i < max_cpu_num.cpu; i++)
                cpunode_map[i] = -1;
 
        return 0;
 
 size_t cpu_map__snprint(struct perf_cpu_map *map, char *buf, size_t size)
 {
-       int i, cpu, start = -1;
+       int i, start = -1;
        bool first = true;
        size_t ret = 0;
 
 #define COMMA first ? "" : ","
 
        for (i = 0; i < map->nr + 1; i++) {
+               struct perf_cpu cpu = { .cpu = INT_MAX };
                bool last = i == map->nr;
 
-               cpu = last ? INT_MAX : map->map[i];
+               if (!last)
+                       cpu = map->map[i];
 
                if (start == -1) {
                        start = i;
                        if (last) {
                                ret += snprintf(buf + ret, size - ret,
                                                "%s%d", COMMA,
-                                               map->map[i]);
+                                               map->map[i].cpu);
                        }
-               } else if (((i - start) != (cpu - map->map[start])) || last) {
+               } else if (((i - start) != (cpu.cpu - map->map[start].cpu)) || last) {
                        int end = i - 1;
 
                        if (start == end) {
                                ret += snprintf(buf + ret, size - ret,
                                                "%s%d", COMMA,
-                                               map->map[start]);
+                                               map->map[start].cpu);
                        } else {
                                ret += snprintf(buf + ret, size - ret,
                                                "%s%d-%d", COMMA,
-                                               map->map[start], map->map[end]);
+                                               map->map[start].cpu, map->map[end].cpu);
                        }
                        first = false;
                        start = i;
        int i, cpu;
        char *ptr = buf;
        unsigned char *bitmap;
-       int last_cpu = perf_cpu_map__cpu(map, map->nr - 1);
+       struct perf_cpu last_cpu = perf_cpu_map__cpu(map, map->nr - 1);
 
        if (buf == NULL)
                return 0;
 
-       bitmap = zalloc(last_cpu / 8 + 1);
+       bitmap = zalloc(last_cpu.cpu / 8 + 1);
        if (bitmap == NULL) {
                buf[0] = '\0';
                return 0;
        }
 
        for (i = 0; i < map->nr; i++) {
-               cpu = perf_cpu_map__cpu(map, i);
+               cpu = perf_cpu_map__cpu(map, i).cpu;
                bitmap[cpu / 8] |= 1 << (cpu % 8);
        }
 
-       for (cpu = last_cpu / 4 * 4; cpu >= 0; cpu -= 4) {
+       for (cpu = last_cpu.cpu / 4 * 4; cpu >= 0; cpu -= 4) {
                unsigned char bits = bitmap[cpu / 8];
 
                if (cpu % 8)
                a->socket == b->socket &&
                a->die == b->die &&
                a->core == b->core &&
-               a->cpu == b->cpu;
+               a->cpu.cpu == b->cpu.cpu;
 }
 
 bool aggr_cpu_id__is_empty(const struct aggr_cpu_id *a)
                a->socket == -1 &&
                a->die == -1 &&
                a->core == -1 &&
-               a->cpu == -1;
+               a->cpu.cpu == -1;
 }
 
 struct aggr_cpu_id aggr_cpu_id__empty(void)
                .socket = -1,
                .die = -1,
                .core = -1,
-               .cpu = -1
+               .cpu = (struct perf_cpu){ .cpu = -1 },
        };
        return ret;
 }
 
        /** The core id as read from /sys/devices/system/cpu/cpuX/topology/core_id. */
        int core;
        /** CPU aggregation, note there is one CPU for each SMT thread. */
-       int cpu;
+       struct perf_cpu cpu;
 };
 
 /** A collection of aggr_cpu_id values, the "built" version is sorted and uniqued. */
 int cpu__setup_cpunode_map(void);
 
 int cpu__max_node(void);
-int cpu__max_cpu(void);
-int cpu__max_present_cpu(void);
+struct perf_cpu cpu__max_cpu(void);
+struct perf_cpu cpu__max_present_cpu(void);
 /**
  * cpu__get_node - Returns the numa node X as read from
  * /sys/devices/system/node/nodeX for the given CPU.
  */
-int cpu__get_node(int cpu);
+int cpu__get_node(struct perf_cpu cpu);
 /**
  * cpu__get_socket_id - Returns the socket number as read from
  * /sys/devices/system/cpu/cpuX/topology/physical_package_id for the given CPU.
  */
-int cpu__get_socket_id(int cpu);
+int cpu__get_socket_id(struct perf_cpu cpu);
 /**
  * cpu__get_die_id - Returns the die id as read from
  * /sys/devices/system/cpu/cpuX/topology/die_id for the given CPU.
  */
-int cpu__get_die_id(int cpu);
+int cpu__get_die_id(struct perf_cpu cpu);
 /**
  * cpu__get_core_id - Returns the core id as read from
  * /sys/devices/system/cpu/cpuX/topology/core_id for the given CPU.
  */
-int cpu__get_core_id(int cpu);
+int cpu__get_core_id(struct perf_cpu cpu);
 
 /**
  * cpu_aggr_map__empty_new - Create a cpu_aggr_map of size nr with every entry
  */
 struct cpu_aggr_map *cpu_aggr_map__empty_new(int nr);
 
-typedef struct aggr_cpu_id (*aggr_cpu_id_get_t)(int cpu, void *data);
+typedef struct aggr_cpu_id (*aggr_cpu_id_get_t)(struct perf_cpu cpu, void *data);
 
 /**
  * cpu_aggr_map__new - Create a cpu_aggr_map with an aggr_cpu_id for each cpu in
  * the socket for cpu. The function signature is compatible with
  * aggr_cpu_id_get_t.
  */
-struct aggr_cpu_id aggr_cpu_id__socket(int cpu, void *data);
+struct aggr_cpu_id aggr_cpu_id__socket(struct perf_cpu cpu, void *data);
 /**
  * aggr_cpu_id__die - Create an aggr_cpu_id with the die and socket populated
  * with the die and socket for cpu. The function signature is compatible with
  * aggr_cpu_id_get_t.
  */
-struct aggr_cpu_id aggr_cpu_id__die(int cpu, void *data);
+struct aggr_cpu_id aggr_cpu_id__die(struct perf_cpu cpu, void *data);
 /**
  * aggr_cpu_id__core - Create an aggr_cpu_id with the core, die and socket
  * populated with the core, die and socket for cpu. The function signature is
  * compatible with aggr_cpu_id_get_t.
  */
-struct aggr_cpu_id aggr_cpu_id__core(int cpu, void *data);
+struct aggr_cpu_id aggr_cpu_id__core(struct perf_cpu cpu, void *data);
 /**
  * aggr_cpu_id__core - Create an aggr_cpu_id with the cpu, core, die and socket
  * populated with the cpu, core, die and socket for cpu. The function signature
  * is compatible with aggr_cpu_id_get_t.
  */
-struct aggr_cpu_id aggr_cpu_id__cpu(int cpu, void *data);
+struct aggr_cpu_id aggr_cpu_id__cpu(struct perf_cpu cpu, void *data);
 /**
  * aggr_cpu_id__node - Create an aggr_cpu_id with the numa node populated for
  * cpu. The function signature is compatible with aggr_cpu_id_get_t.
  */
-struct aggr_cpu_id aggr_cpu_id__node(int cpu, void *data);
+struct aggr_cpu_id aggr_cpu_id__node(struct perf_cpu cpu, void *data);
 
 #endif /* __PERF_CPUMAP_H */
 
        struct perf_cpu_map *map;
        bool has_die = has_die_topology();
 
-       ncpus = cpu__max_present_cpu();
+       ncpus = cpu__max_present_cpu().cpu;
 
        /* build online CPU map */
        map = perf_cpu_map__new(NULL);
        tp->core_cpus_list = addr;
 
        for (i = 0; i < nr; i++) {
-               if (!perf_cpu_map__has(map, i))
+               if (!perf_cpu_map__has(map, (struct perf_cpu){ .cpu = i }))
                        continue;
 
                ret = build_cpu_topology(tp, i);
        tp->nr = nr;
 
        for (i = 0; i < nr; i++) {
-               if (load_numa_node(&tp->nodes[i], node_map->map[i])) {
+               if (load_numa_node(&tp->nodes[i], node_map->map[i].cpu)) {
                        numa_topology__delete(tp);
                        tp = NULL;
                        break;
 
 
 int perf_env__read_cpu_topology_map(struct perf_env *env)
 {
-       int cpu, nr_cpus;
+       int idx, nr_cpus;
 
        if (env->cpu != NULL)
                return 0;
 
        if (env->nr_cpus_avail == 0)
-               env->nr_cpus_avail = cpu__max_present_cpu();
+               env->nr_cpus_avail = cpu__max_present_cpu().cpu;
 
        nr_cpus = env->nr_cpus_avail;
        if (nr_cpus == -1)
        if (env->cpu == NULL)
                return -ENOMEM;
 
-       for (cpu = 0; cpu < nr_cpus; ++cpu) {
-               env->cpu[cpu].core_id   = cpu__get_core_id(cpu);
-               env->cpu[cpu].socket_id = cpu__get_socket_id(cpu);
-               env->cpu[cpu].die_id    = cpu__get_die_id(cpu);
+       for (idx = 0; idx < nr_cpus; ++idx) {
+               struct perf_cpu cpu = { .cpu = idx };
+
+               env->cpu[idx].core_id   = cpu__get_core_id(cpu);
+               env->cpu[idx].socket_id = cpu__get_socket_id(cpu);
+               env->cpu[idx].die_id    = cpu__get_die_id(cpu);
        }
 
        env->nr_cpus_avail = nr_cpus;
 static int perf_env__read_nr_cpus_avail(struct perf_env *env)
 {
        if (env->nr_cpus_avail == 0)
-               env->nr_cpus_avail = cpu__max_present_cpu();
+               env->nr_cpus_avail = cpu__max_present_cpu().cpu;
 
        return env->nr_cpus_avail ? 0 : -ENOENT;
 }
        return env->pmu_mappings;
 }
 
-int perf_env__numa_node(struct perf_env *env, int cpu)
+int perf_env__numa_node(struct perf_env *env, struct perf_cpu cpu)
 {
        if (!env->nr_numa_map) {
                struct numa_node *nn;
 
                for (i = 0; i < env->nr_numa_nodes; i++) {
                        nn = &env->numa_nodes[i];
-                       nr = max(nr, perf_cpu_map__max(nn->map));
+                       nr = max(nr, perf_cpu_map__max(nn->map).cpu);
                }
 
                nr++;
                env->nr_numa_map = nr;
 
                for (i = 0; i < env->nr_numa_nodes; i++) {
-                       int tmp, j;
+                       struct perf_cpu tmp;
+                       int j;
 
                        nn = &env->numa_nodes[i];
-                       perf_cpu_map__for_each_cpu(j, tmp, nn->map)
-                               env->numa_map[j] = i;
+                       perf_cpu_map__for_each_cpu(tmp, j, nn->map)
+                               env->numa_map[tmp.cpu] = i;
                }
        }
 
-       return cpu >= 0 && cpu < env->nr_numa_map ? env->numa_map[cpu] : -1;
+       return cpu.cpu >= 0 && cpu.cpu < env->nr_numa_map ? env->numa_map[cpu.cpu] : -1;
 }
 
 
 #include <linux/types.h>
 #include <linux/rbtree.h>
+#include "cpumap.h"
 #include "rwsem.h"
 
 struct perf_cpu_map;
 bool perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node);
 struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id);
 
-int perf_env__numa_node(struct perf_env *env, int cpu);
+int perf_env__numa_node(struct perf_env *env, struct perf_cpu cpu);
 #endif /* __PERF_ENV_H */
 
                .cpu_map_idx = 0,
                .evlist_cpu_map_idx = 0,
                .evlist_cpu_map_nr = perf_cpu_map__nr(evlist->core.all_cpus),
-               .cpu = -1,
+               .cpu = (struct perf_cpu){ .cpu = -1},
                .affinity = affinity,
        };
 
        if (itr.affinity) {
                itr.cpu = perf_cpu_map__cpu(evlist->core.all_cpus, 0);
-               affinity__set(itr.affinity, itr.cpu);
+               affinity__set(itr.affinity, itr.cpu.cpu);
                itr.cpu_map_idx = perf_cpu_map__idx(itr.evsel->core.cpus, itr.cpu);
                /*
                 * If this CPU isn't in the evsel's cpu map then advance through
                        perf_cpu_map__cpu(evlist_cpu_itr->container->core.all_cpus,
                                          evlist_cpu_itr->evlist_cpu_map_idx);
                if (evlist_cpu_itr->affinity)
-                       affinity__set(evlist_cpu_itr->affinity, evlist_cpu_itr->cpu);
+                       affinity__set(evlist_cpu_itr->affinity, evlist_cpu_itr->cpu.cpu);
                evlist_cpu_itr->cpu_map_idx =
                        perf_cpu_map__idx(evlist_cpu_itr->evsel->core.cpus,
                                          evlist_cpu_itr->cpu);
 
 static int
 perf_evlist__mmap_cb_mmap(struct perf_mmap *_map, struct perf_mmap_param *_mp,
-                         int output, int cpu)
+                         int output, struct perf_cpu cpu)
 {
        struct mmap *map = container_of(_map, struct mmap, core);
        struct mmap_params *mp = container_of(_mp, struct mmap_params, core);
 
        /** The number of CPU map entries in evlist->core.all_cpus. */
        int evlist_cpu_map_nr;
        /** The current CPU of the iterator. */
-       int cpu;
+       struct perf_cpu cpu;
        /** If present, used to set the affinity when switching between CPUs. */
        struct affinity *affinity;
 };
 
 static int evsel__match_other_cpu(struct evsel *evsel, struct evsel *other,
                                  int cpu_map_idx)
 {
-       int cpu;
+       struct perf_cpu cpu;
 
        cpu = perf_cpu_map__cpu(evsel->core.cpus, cpu_map_idx);
        return perf_cpu_map__idx(other->core.cpus, cpu);
                        test_attr__ready();
 
                        pr_debug2_peo("sys_perf_event_open: pid %d  cpu %d  group_fd %d  flags %#lx",
-                               pid, cpus->map[idx], group_fd, evsel->open_flags);
+                               pid, cpus->map[idx].cpu, group_fd, evsel->open_flags);
 
-                       fd = sys_perf_event_open(&evsel->core.attr, pid, cpus->map[idx],
+                       fd = sys_perf_event_open(&evsel->core.attr, pid, cpus->map[idx].cpu,
                                                group_fd, evsel->open_flags);
 
                        FD(evsel, idx, thread) = fd;
 
                return smt_on() > 0 ? 1.0 : 0.0;
 
        if (!strcmp("#num_cpus", literal))
-               return cpu__max_present_cpu();
+               return cpu__max_present_cpu().cpu;
 
        /*
         * Assume that topology strings are consistent, such as CPUs "0-1"
 
        u32 nrc, nra;
        int ret;
 
-       nrc = cpu__max_present_cpu();
+       nrc = cpu__max_present_cpu().cpu;
 
        nr = sysconf(_SC_NPROCESSORS_ONLN);
        if (nr < 0)
        u32 nr, cpu;
        u16 level;
 
-       nr = cpu__max_cpu();
+       nr = cpu__max_cpu().cpu;
 
        for (cpu = 0; cpu < nr; cpu++) {
                for (level = 0; level < MAX_CACHE_LVL; level++) {
 static int write_cache(struct feat_fd *ff,
                       struct evlist *evlist __maybe_unused)
 {
-       u32 max_caches = cpu__max_cpu() * MAX_CACHE_LVL;
+       u32 max_caches = cpu__max_cpu().cpu * MAX_CACHE_LVL;
        struct cpu_cache_level caches[max_caches];
        u32 cnt = 0, i, version = 1;
        int ret;
 
        }
 }
 
-static int perf_mmap__aio_bind(struct mmap *map, int idx, int cpu, int affinity)
+static int perf_mmap__aio_bind(struct mmap *map, int idx, struct perf_cpu cpu, int affinity)
 {
        void *data;
        size_t mmap_len;
 }
 
 static int perf_mmap__aio_bind(struct mmap *map __maybe_unused, int idx __maybe_unused,
-               int cpu __maybe_unused, int affinity __maybe_unused)
+               struct perf_cpu cpu __maybe_unused, int affinity __maybe_unused)
 {
        return 0;
 }
 
 static void build_node_mask(int node, struct mmap_cpu_mask *mask)
 {
-       int c, cpu, nr_cpus;
+       int idx, nr_cpus;
+       struct perf_cpu cpu;
        const struct perf_cpu_map *cpu_map = NULL;
 
        cpu_map = cpu_map__online();
                return;
 
        nr_cpus = perf_cpu_map__nr(cpu_map);
-       for (c = 0; c < nr_cpus; c++) {
-               cpu = cpu_map->map[c]; /* map c index to online cpu index */
+       for (idx = 0; idx < nr_cpus; idx++) {
+               cpu = cpu_map->map[idx]; /* map c index to online cpu index */
                if (cpu__get_node(cpu) == node)
-                       set_bit(cpu, mask->bits);
+                       set_bit(cpu.cpu, mask->bits);
        }
 }
 
 static int perf_mmap__setup_affinity_mask(struct mmap *map, struct mmap_params *mp)
 {
-       map->affinity_mask.nbits = cpu__max_cpu();
+       map->affinity_mask.nbits = cpu__max_cpu().cpu;
        map->affinity_mask.bits = bitmap_zalloc(map->affinity_mask.nbits);
        if (!map->affinity_mask.bits)
                return -1;
        if (mp->affinity == PERF_AFFINITY_NODE && cpu__max_node() > 1)
                build_node_mask(cpu__get_node(map->core.cpu), &map->affinity_mask);
        else if (mp->affinity == PERF_AFFINITY_CPU)
-               set_bit(map->core.cpu, map->affinity_mask.bits);
+               set_bit(map->core.cpu.cpu, map->affinity_mask.bits);
 
        return 0;
 }
 
-int mmap__mmap(struct mmap *map, struct mmap_params *mp, int fd, int cpu)
+int mmap__mmap(struct mmap *map, struct mmap_params *mp, int fd, struct perf_cpu cpu)
 {
        if (perf_mmap__mmap(&map->core, &mp->core, fd, cpu)) {
                pr_debug2("failed to mmap perf event ring buffer, error %d\n",
 
 #include <linux/types.h>
 #include <linux/ring_buffer.h>
 #include <linux/bitops.h>
+#include <perf/cpumap.h>
 #include <stdbool.h>
 #include <pthread.h> // for cpu_set_t
 #ifdef HAVE_AIO_SUPPORT
        struct auxtrace_mmap_params auxtrace_mp;
 };
 
-int mmap__mmap(struct mmap *map, struct mmap_params *mp, int fd, int cpu);
+int mmap__mmap(struct mmap *map, struct mmap_params *mp, int fd, struct perf_cpu cpu);
 void mmap__munmap(struct mmap *map);
 
 union perf_event *perf_mmap__read_forward(struct mmap *map);
 
 
 typedef void (*setup_probe_fn_t)(struct evsel *evsel);
 
-static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
+static int perf_do_probe_api(setup_probe_fn_t fn, struct perf_cpu cpu, const char *str)
 {
        struct evlist *evlist;
        struct evsel *evsel;
        evsel = evlist__first(evlist);
 
        while (1) {
-               fd = sys_perf_event_open(&evsel->core.attr, pid, cpu, -1, flags);
+               fd = sys_perf_event_open(&evsel->core.attr, pid, cpu.cpu, -1, flags);
                if (fd < 0) {
                        if (pid == -1 && errno == EACCES) {
                                pid = 0;
 
        fn(evsel);
 
-       fd = sys_perf_event_open(&evsel->core.attr, pid, cpu, -1, flags);
+       fd = sys_perf_event_open(&evsel->core.attr, pid, cpu.cpu, -1, flags);
        if (fd < 0) {
                if (errno == EINVAL)
                        err = -EINVAL;
 {
        const char *try[] = {"cycles:u", "instructions:u", "cpu-clock:u", NULL};
        struct perf_cpu_map *cpus;
-       int cpu, ret, i = 0;
+       struct perf_cpu cpu;
+       int ret, i = 0;
 
        cpus = perf_cpu_map__new(NULL);
        if (!cpus)
                .exclude_kernel = 1,
        };
        struct perf_cpu_map *cpus;
-       int cpu, fd;
+       struct perf_cpu cpu;
+       int fd;
 
        cpus = perf_cpu_map__new(NULL);
        if (!cpus)
                return false;
+
        cpu = cpus->map[0];
        perf_cpu_map__put(cpus);
 
-       fd = sys_perf_event_open(&attr, -1, cpu, -1, 0);
+       fd = sys_perf_event_open(&attr, -1, cpu.cpu, -1, 0);
        if (fd < 0)
                return false;
        close(fd);
 
        for (i = 0; i < evlist->core.nr_mmaps; i++) {
                struct mmap *md = &evlist->mmap[i];
 
-               if (md->core.cpu == cpu)
+               if (md->core.cpu.cpu == cpu)
                        return md;
        }
 
  * Dummy, to avoid dragging all the test_attr infrastructure in the python
  * binding.
  */
-void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu,
+void test_attr__open(struct perf_event_attr *attr, pid_t pid, struct perf_cpu cpu,
                      int fd, int group_fd, unsigned long flags)
 {
 }
 
        if (opts->group)
                evlist__set_leader(evlist);
 
-       if (evlist->core.cpus->map[0] < 0)
+       if (evlist->core.cpus->map[0].cpu < 0)
                opts->no_inherit = true;
 
        use_comm_exec = perf_can_comm_exec();
 {
        struct evlist *temp_evlist;
        struct evsel *evsel;
-       int err, fd, cpu;
+       int err, fd;
+       struct perf_cpu cpu = { .cpu = 0 };
        bool ret = false;
        pid_t pid = -1;
 
        if (!evlist || perf_cpu_map__empty(evlist->core.cpus)) {
                struct perf_cpu_map *cpus = perf_cpu_map__new(NULL);
 
-               cpu =  cpus ? cpus->map[0] : 0;
+               if (cpus)
+                       cpu =  cpus->map[0];
+
                perf_cpu_map__put(cpus);
        } else {
                cpu = evlist->core.cpus->map[0];
        }
 
        while (1) {
-               fd = sys_perf_event_open(&evsel->core.attr, pid, cpu, -1,
+               fd = sys_perf_event_open(&evsel->core.attr, pid, cpu.cpu, -1,
                                         perf_event_open_cloexec_flag());
                if (fd < 0) {
                        if (pid == -1 && errno == EACCES) {
 
 }
 
 static void
-process_stat(struct evsel *counter, int cpu, int thread, u64 tstamp,
+process_stat(struct evsel *counter, struct perf_cpu cpu, int thread, u64 tstamp,
             struct perf_counts_values *count)
 {
        PyObject *handler, *t;
                return;
        }
 
-       PyTuple_SetItem(t, n++, _PyLong_FromLong(cpu));
+       PyTuple_SetItem(t, n++, _PyLong_FromLong(cpu.cpu));
        PyTuple_SetItem(t, n++, _PyLong_FromLong(thread));
 
        tuple_set_u64(t, n++, tstamp);
        int cpu, thread;
 
        if (config->aggr_mode == AGGR_GLOBAL) {
-               process_stat(counter, -1, -1, tstamp,
+               process_stat(counter, (struct perf_cpu){ .cpu = -1 }, -1, tstamp,
                             &counter->counts->aggr);
                return;
        }
 
        }
 
        for (i = 0; i < map->nr; i++) {
-               int cpu = map->map[i];
+               struct perf_cpu cpu = map->map[i];
 
-               if (cpu >= nr_cpus) {
+               if (cpu.cpu >= nr_cpus) {
                        pr_err("Requested CPU %d too large. "
-                              "Consider raising MAX_NR_CPUS\n", cpu);
+                              "Consider raising MAX_NR_CPUS\n", cpu.cpu);
                        goto out_delete_map;
                }
 
-               set_bit(cpu, cpu_bitmap);
+               set_bit(cpu.cpu, cpu_bitmap);
        }
 
        err = 0;
                if (!sid)
                        return -ENOENT;
                sid->idx = e->idx;
-               sid->cpu = e->cpu;
+               sid->cpu.cpu = e->cpu;
                sid->tid = e->tid;
        }
        return 0;
 
                                id.die,
                                config->csv_output ? 0 : -3,
                                id.core, config->csv_sep);
-               } else if (id.cpu > -1) {
+               } else if (id.cpu.cpu > -1) {
                        fprintf(config->output, "CPU%*d%s",
                                config->csv_output ? 0 : -7,
-                               id.cpu, config->csv_sep);
+                               id.cpu.cpu, config->csv_sep);
                }
                break;
        case AGGR_THREAD:
                                struct evsel *evsel, const struct aggr_cpu_id *id)
 {
        struct perf_cpu_map *cpus = evsel__cpus(evsel);
-       int cpu, idx;
+       struct perf_cpu cpu;
+       int idx;
 
        if (config->aggr_mode == AGGR_NONE)
                return perf_cpu_map__idx(cpus, id->cpu);
 static void aggr_update_shadow(struct perf_stat_config *config,
                               struct evlist *evlist)
 {
-       int cpu, idx, s;
+       int idx, s;
+       struct perf_cpu cpu;
        struct aggr_cpu_id s2, id;
        u64 val;
        struct evsel *counter;
                    struct evsel *counter, void *data, bool first)
 {
        struct aggr_data *ad = data;
-       int idx, cpu;
+       int idx;
+       struct perf_cpu cpu;
        struct perf_cpu_map *cpus;
        struct aggr_cpu_id s2;
 
 static void print_counter_aggrdata(struct perf_stat_config *config,
                                   struct evsel *counter, int s,
                                   char *prefix, bool metric_only,
-                                  bool *first, int cpu)
+                                  bool *first, struct perf_cpu cpu)
 {
        struct aggr_data ad;
        FILE *output = config->output;
                fprintf(output, "%s", prefix);
 
        uval = val * counter->scale;
-       if (cpu != -1)
+       if (cpu.cpu != -1)
                id = aggr_cpu_id__cpu(cpu, /*data=*/NULL);
 
        printout(config, id, nr, counter, uval,
                first = true;
                evlist__for_each_entry(evlist, counter) {
                        print_counter_aggrdata(config, counter, s,
-                                              prefix, metric_only,
-                                              &first, /*cpu=*/-1);
+                                       prefix, metric_only,
+                                       &first, (struct perf_cpu){ .cpu = -1 });
                }
                if (metric_only)
                        fputc('\n', output);
        FILE *output = config->output;
        u64 ena, run, val;
        double uval;
-       int idx, cpu;
+       int idx;
+       struct perf_cpu cpu;
        struct aggr_cpu_id id;
 
        perf_cpu_map__for_each_cpu(cpu, idx, evsel__cpus(counter)) {
                                 struct evlist *evlist,
                                 char *prefix)
 {
-       int all_idx, cpu;
+       int all_idx;
+       struct perf_cpu cpu;
 
        perf_cpu_map__for_each_cpu(cpu, all_idx, evlist->core.cpus) {
                struct evsel *counter;
        struct aggr_cpu_id s2, id;
        struct perf_cpu_map *cpus;
        bool first = true;
-       int idx, cpu;
+       int idx;
+       struct perf_cpu cpu;
 
        cpus = evsel__cpus(counter);
        perf_cpu_map__for_each_cpu(cpu, idx, cpus) {
                        fprintf(output, "%s", prefix);
 
                print_counter_aggrdata(config, counter, s,
-                                      prefix, metric_only,
-                                      &first, /*cpu=*/-1);
+                               prefix, metric_only,
+                               &first, (struct perf_cpu){ .cpu = -1 });
        }
 
        if (metric_only)
 
 {
        struct hashmap *mask = counter->per_pkg_mask;
        struct perf_cpu_map *cpus = evsel__cpus(counter);
-       int cpu = perf_cpu_map__cpu(cpus, cpu_map_idx);
+       struct perf_cpu cpu = perf_cpu_map__cpu(cpus, cpu_map_idx);
        int s, d, ret = 0;
        uint64_t *key;
 
 
        struct rblist value_list;
 };
 
-typedef struct aggr_cpu_id (*aggr_get_id_t)(struct perf_stat_config *config, int cpu);
+typedef struct aggr_cpu_id (*aggr_get_id_t)(struct perf_stat_config *config, struct perf_cpu cpu);
 
 struct perf_stat_config {
        enum aggr_mode           aggr_mode;
 
        int i;
        int ret = 0;
        struct perf_cpu_map *m;
-       int c;
+       struct perf_cpu c;
 
        m = perf_cpu_map__new(s);
        if (!m)
 
        for (i = 0; i < m->nr; i++) {
                c = m->map[i];
-               if (c >= nr_cpus) {
+               if (c.cpu >= nr_cpus) {
                        ret = -1;
                        break;
                }
 
-               set_bit(c, cpumask_bits(b));
+               set_bit(c.cpu, cpumask_bits(b));
        }
 
        perf_cpu_map__put(m);
 
        cpus->nr = map->nr;
 
        for (i = 0; i < map->nr; i++)
-               cpus->cpu[i] = map->map[i];
+               cpus->cpu[i] = map->map[i].cpu;
 }
 
 static void synthesize_mask(struct perf_record_record_cpu_map *mask,
        mask->long_size = sizeof(long);
 
        for (i = 0; i < map->nr; i++)
-               set_bit(map->map[i], mask->mask);
+               set_bit(map->map[i].cpu, mask->mask);
 }
 
 static size_t cpus_size(struct perf_cpu_map *map)
 
        for (i = 0; i < map->nr; i++) {
                /* bit position of the cpu is + 1 */
-               int bit = map->map[i] + 1;
+               int bit = map->map[i].cpu + 1;
 
                if (bit > *max)
                        *max = bit;
 }
 
 int perf_event__synthesize_stat(struct perf_tool *tool,
-                               u32 cpu, u32 thread, u64 id,
+                               struct perf_cpu cpu, u32 thread, u64 id,
                                struct perf_counts_values *count,
                                perf_event__handler_t process,
                                struct machine *machine)
        event.header.misc = 0;
 
        event.id        = id;
-       event.cpu       = cpu;
+       event.cpu       = cpu.cpu;
        event.thread    = thread;
        event.val       = count->val;
        event.ena       = count->ena;
                        }
 
                        e->idx = sid->idx;
-                       e->cpu = sid->cpu;
+                       e->cpu = sid->cpu.cpu;
                        e->tid = sid->tid;
                }
        }
 
 #include <sys/types.h> // pid_t
 #include <linux/compiler.h>
 #include <linux/types.h>
+#include <perf/cpumap.h>
 
 struct auxtrace_record;
 struct dso;
 int perf_event__synthesize_stat_config(struct perf_tool *tool, struct perf_stat_config *config, perf_event__handler_t process, struct machine *machine);
 int perf_event__synthesize_stat_events(struct perf_stat_config *config, struct perf_tool *tool, struct evlist *evlist, perf_event__handler_t process, bool attrs);
 int perf_event__synthesize_stat_round(struct perf_tool *tool, u64 time, u64 type, perf_event__handler_t process, struct machine *machine);
-int perf_event__synthesize_stat(struct perf_tool *tool, u32 cpu, u32 thread, u64 id, struct perf_counts_values *count, perf_event__handler_t process, struct machine *machine);
+int perf_event__synthesize_stat(struct perf_tool *tool, struct perf_cpu cpu, u32 thread, u64 id, struct perf_counts_values *count, perf_event__handler_t process, struct machine *machine);
 int perf_event__synthesize_thread_map2(struct perf_tool *tool, struct perf_thread_map *threads, perf_event__handler_t process, struct machine *machine);
 int perf_event__synthesize_thread_map(struct perf_tool *tool, struct perf_thread_map *threads, perf_event__handler_t process, struct machine *machine, bool needs_mmap, bool mmap_data);
 int perf_event__synthesize_threads(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine, bool needs_mmap, bool mmap_data, unsigned int nr_threads_synthesize);
 
 #include <stddef.h>
 #include <linux/compiler.h>
 #include <sys/types.h>
+#ifndef __cplusplus
+#include <internal/cpumap.h>
+#endif
 
 /* General helper functions */
 void usage(const char *err) __noreturn;
 void test_attr__ready(void);
 void test_attr__init(void);
 struct perf_event_attr;
-void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu,
+void test_attr__open(struct perf_event_attr *attr, pid_t pid, struct perf_cpu cpu,
                     int fd, int group_fd, unsigned long flags);
 #endif /* GIT_COMPAT_UTIL_H */