162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Manage affinity to optimize IPIs inside the kernel perf API. */ 362306a36Sopenharmony_ci#define _GNU_SOURCE 1 462306a36Sopenharmony_ci#include <sched.h> 562306a36Sopenharmony_ci#include <stdlib.h> 662306a36Sopenharmony_ci#include <linux/bitmap.h> 762306a36Sopenharmony_ci#include <linux/zalloc.h> 862306a36Sopenharmony_ci#include "perf.h" 962306a36Sopenharmony_ci#include "cpumap.h" 1062306a36Sopenharmony_ci#include "affinity.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistatic int get_cpu_set_size(void) 1362306a36Sopenharmony_ci{ 1462306a36Sopenharmony_ci int sz = cpu__max_cpu().cpu + 8 - 1; 1562306a36Sopenharmony_ci /* 1662306a36Sopenharmony_ci * sched_getaffinity doesn't like masks smaller than the kernel. 1762306a36Sopenharmony_ci * Hopefully that's big enough. 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_ci if (sz < 4096) 2062306a36Sopenharmony_ci sz = 4096; 2162306a36Sopenharmony_ci return sz / 8; 2262306a36Sopenharmony_ci} 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ciint affinity__setup(struct affinity *a) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci int cpu_set_size = get_cpu_set_size(); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci a->orig_cpus = bitmap_zalloc(cpu_set_size * 8); 2962306a36Sopenharmony_ci if (!a->orig_cpus) 3062306a36Sopenharmony_ci return -1; 3162306a36Sopenharmony_ci sched_getaffinity(0, cpu_set_size, (cpu_set_t *)a->orig_cpus); 3262306a36Sopenharmony_ci a->sched_cpus = bitmap_zalloc(cpu_set_size * 8); 3362306a36Sopenharmony_ci if (!a->sched_cpus) { 3462306a36Sopenharmony_ci zfree(&a->orig_cpus); 3562306a36Sopenharmony_ci return -1; 3662306a36Sopenharmony_ci } 3762306a36Sopenharmony_ci bitmap_zero((unsigned long *)a->sched_cpus, cpu_set_size); 3862306a36Sopenharmony_ci a->changed = false; 3962306a36Sopenharmony_ci return 0; 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* 4362306a36Sopenharmony_ci * perf_event_open does an IPI internally to the target CPU. 4462306a36Sopenharmony_ci * It is more efficient to change perf's affinity to the target 4562306a36Sopenharmony_ci * CPU and then set up all events on that CPU, so we amortize 4662306a36Sopenharmony_ci * CPU communication. 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_civoid affinity__set(struct affinity *a, int cpu) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci int cpu_set_size = get_cpu_set_size(); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci /* 5362306a36Sopenharmony_ci * Return: 5462306a36Sopenharmony_ci * - if cpu is -1 5562306a36Sopenharmony_ci * - restrict out of bound access to sched_cpus 5662306a36Sopenharmony_ci */ 5762306a36Sopenharmony_ci if (cpu == -1 || ((cpu >= (cpu_set_size * 8)))) 5862306a36Sopenharmony_ci return; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci a->changed = true; 6162306a36Sopenharmony_ci __set_bit(cpu, a->sched_cpus); 6262306a36Sopenharmony_ci /* 6362306a36Sopenharmony_ci * We ignore errors because affinity is just an optimization. 6462306a36Sopenharmony_ci * This could happen for example with isolated CPUs or cpusets. 6562306a36Sopenharmony_ci * In this case the IPIs inside the kernel's perf API still work. 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_ci sched_setaffinity(0, cpu_set_size, (cpu_set_t *)a->sched_cpus); 6862306a36Sopenharmony_ci __clear_bit(cpu, a->sched_cpus); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic void __affinity__cleanup(struct affinity *a) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci int cpu_set_size = get_cpu_set_size(); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci if (a->changed) 7662306a36Sopenharmony_ci sched_setaffinity(0, cpu_set_size, (cpu_set_t *)a->orig_cpus); 7762306a36Sopenharmony_ci zfree(&a->sched_cpus); 7862306a36Sopenharmony_ci zfree(&a->orig_cpus); 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_civoid affinity__cleanup(struct affinity *a) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci if (a != NULL) 8462306a36Sopenharmony_ci __affinity__cleanup(a); 8562306a36Sopenharmony_ci} 86