| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- // SPDX-License-Identifier: GPL-2.0
- /* Manage affinity to optimize IPIs inside the kernel perf API. */
- #define _GNU_SOURCE 1
- #include <sched.h>
- #include <stdlib.h>
- #include <linux/bitmap.h>
- #include <linux/zalloc.h>
- #include <perf/cpumap.h>
- #include "perf.h"
- #include "cpumap.h"
- #include "affinity.h"
- static int get_cpu_set_size(void)
- {
- int sz = cpu__max_cpu().cpu + 8 - 1;
- /*
- * sched_getaffinity doesn't like masks smaller than the kernel.
- * Hopefully that's big enough.
- */
- if (sz < 4096)
- sz = 4096;
- return sz / 8;
- }
- int affinity__setup(struct affinity *a)
- {
- int cpu_set_size = get_cpu_set_size();
- a->orig_cpus = bitmap_zalloc(cpu_set_size * 8);
- if (!a->orig_cpus)
- return -1;
- sched_getaffinity(0, cpu_set_size, (cpu_set_t *)a->orig_cpus);
- a->sched_cpus = bitmap_zalloc(cpu_set_size * 8);
- if (!a->sched_cpus) {
- zfree(&a->orig_cpus);
- return -1;
- }
- bitmap_zero((unsigned long *)a->sched_cpus, cpu_set_size);
- a->changed = false;
- return 0;
- }
- /*
- * perf_event_open does an IPI internally to the target CPU.
- * It is more efficient to change perf's affinity to the target
- * CPU and then set up all events on that CPU, so we amortize
- * CPU communication.
- */
- void affinity__set(struct affinity *a, int cpu)
- {
- int cpu_set_size = get_cpu_set_size();
- /*
- * Return:
- * - if cpu is -1
- * - restrict out of bound access to sched_cpus
- */
- if (cpu == -1 || ((cpu >= (cpu_set_size * 8))))
- return;
- a->changed = true;
- __set_bit(cpu, a->sched_cpus);
- /*
- * We ignore errors because affinity is just an optimization.
- * This could happen for example with isolated CPUs or cpusets.
- * In this case the IPIs inside the kernel's perf API still work.
- */
- sched_setaffinity(0, cpu_set_size, (cpu_set_t *)a->sched_cpus);
- __clear_bit(cpu, a->sched_cpus);
- }
- static void __affinity__cleanup(struct affinity *a)
- {
- int cpu_set_size = get_cpu_set_size();
- if (a->changed)
- sched_setaffinity(0, cpu_set_size, (cpu_set_t *)a->orig_cpus);
- zfree(&a->sched_cpus);
- zfree(&a->orig_cpus);
- }
- void affinity__cleanup(struct affinity *a)
- {
- if (a != NULL)
- __affinity__cleanup(a);
- }
- void cpu_map__set_affinity(const struct perf_cpu_map *cpumap)
- {
- int cpu_set_size = get_cpu_set_size();
- unsigned long *cpuset = bitmap_zalloc(cpu_set_size * 8);
- struct perf_cpu cpu;
- int idx;
- if (!cpuset)
- return;
- perf_cpu_map__for_each_cpu_skip_any(cpu, idx, cpumap)
- __set_bit(cpu.cpu, cpuset);
- sched_setaffinity(0, cpu_set_size, (cpu_set_t *)cpuset);
- zfree(&cpuset);
- }
|