86 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Manage affinity to optimize IPIs inside the kernel perf API. */3#define _GNU_SOURCE 14#include <sched.h>5#include <stdlib.h>6#include <linux/bitmap.h>7#include <linux/zalloc.h>8#include "perf.h"9#include "cpumap.h"10#include "affinity.h"11 12static int get_cpu_set_size(void)13{14 int sz = cpu__max_cpu().cpu + 8 - 1;15 /*16 * sched_getaffinity doesn't like masks smaller than the kernel.17 * Hopefully that's big enough.18 */19 if (sz < 4096)20 sz = 4096;21 return sz / 8;22}23 24int affinity__setup(struct affinity *a)25{26 int cpu_set_size = get_cpu_set_size();27 28 a->orig_cpus = bitmap_zalloc(cpu_set_size * 8);29 if (!a->orig_cpus)30 return -1;31 sched_getaffinity(0, cpu_set_size, (cpu_set_t *)a->orig_cpus);32 a->sched_cpus = bitmap_zalloc(cpu_set_size * 8);33 if (!a->sched_cpus) {34 zfree(&a->orig_cpus);35 return -1;36 }37 bitmap_zero((unsigned long *)a->sched_cpus, cpu_set_size);38 a->changed = false;39 return 0;40}41 42/*43 * perf_event_open does an IPI internally to the target CPU.44 * It is more efficient to change perf's affinity to the target45 * CPU and then set up all events on that CPU, so we amortize46 * CPU communication.47 */48void affinity__set(struct affinity *a, int cpu)49{50 int cpu_set_size = get_cpu_set_size();51 52 /*53 * Return:54 * - if cpu is -155 * - restrict out of bound access to sched_cpus56 */57 if (cpu == -1 || ((cpu >= (cpu_set_size * 8))))58 return;59 60 a->changed = true;61 __set_bit(cpu, a->sched_cpus);62 /*63 * We ignore errors because affinity is just an optimization.64 * This could happen for example with isolated CPUs or cpusets.65 * In this case the IPIs inside the kernel's perf API still work.66 */67 sched_setaffinity(0, cpu_set_size, (cpu_set_t *)a->sched_cpus);68 __clear_bit(cpu, a->sched_cpus);69}70 71static void __affinity__cleanup(struct affinity *a)72{73 int cpu_set_size = get_cpu_set_size();74 75 if (a->changed)76 sched_setaffinity(0, cpu_set_size, (cpu_set_t *)a->orig_cpus);77 zfree(&a->sched_cpus);78 zfree(&a->orig_cpus);79}80 81void affinity__cleanup(struct affinity *a)82{83 if (a != NULL)84 __affinity__cleanup(a);85}86