73 lines · 1.8 KB · C
RawDownload
// 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.h"#include "cpumap.h"#include "affinity.h" static int get_cpu_set_size(void){	int sz = cpu__max_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_alloc(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_alloc(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(); 	if (cpu == -1)		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);} 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);}