Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104// 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; unsigned 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);}