diff options
Diffstat (limited to 'tools/perf/util/affinity.c')
| -rw-r--r-- | tools/perf/util/affinity.c | 73 | 
1 files changed, 73 insertions, 0 deletions
diff --git a/tools/perf/util/affinity.c b/tools/perf/util/affinity.c new file mode 100644 index 000000000000..a5e31f826828 --- /dev/null +++ b/tools/perf/util/affinity.c @@ -0,0 +1,73 @@ +// 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); +}  |