1267ed5d8SAndi Kleen // SPDX-License-Identifier: GPL-2.0
2267ed5d8SAndi Kleen /* Manage affinity to optimize IPIs inside the kernel perf API. */
3267ed5d8SAndi Kleen #define _GNU_SOURCE 1
4267ed5d8SAndi Kleen #include <sched.h>
5267ed5d8SAndi Kleen #include <stdlib.h>
6267ed5d8SAndi Kleen #include <linux/bitmap.h>
7267ed5d8SAndi Kleen #include <linux/zalloc.h>
8267ed5d8SAndi Kleen #include "perf.h"
9267ed5d8SAndi Kleen #include "cpumap.h"
10267ed5d8SAndi Kleen #include "affinity.h"
11267ed5d8SAndi Kleen
get_cpu_set_size(void)12267ed5d8SAndi Kleen static int get_cpu_set_size(void)
13267ed5d8SAndi Kleen {
146d18804bSIan Rogers int sz = cpu__max_cpu().cpu + 8 - 1;
15267ed5d8SAndi Kleen /*
16267ed5d8SAndi Kleen * sched_getaffinity doesn't like masks smaller than the kernel.
17267ed5d8SAndi Kleen * Hopefully that's big enough.
18267ed5d8SAndi Kleen */
19267ed5d8SAndi Kleen if (sz < 4096)
20267ed5d8SAndi Kleen sz = 4096;
21267ed5d8SAndi Kleen return sz / 8;
22267ed5d8SAndi Kleen }
23267ed5d8SAndi Kleen
affinity__setup(struct affinity * a)24267ed5d8SAndi Kleen int affinity__setup(struct affinity *a)
25267ed5d8SAndi Kleen {
26267ed5d8SAndi Kleen int cpu_set_size = get_cpu_set_size();
27267ed5d8SAndi Kleen
287fc5b571SAndy Shevchenko a->orig_cpus = bitmap_zalloc(cpu_set_size * 8);
29267ed5d8SAndi Kleen if (!a->orig_cpus)
30267ed5d8SAndi Kleen return -1;
31267ed5d8SAndi Kleen sched_getaffinity(0, cpu_set_size, (cpu_set_t *)a->orig_cpus);
327fc5b571SAndy Shevchenko a->sched_cpus = bitmap_zalloc(cpu_set_size * 8);
33267ed5d8SAndi Kleen if (!a->sched_cpus) {
34267ed5d8SAndi Kleen zfree(&a->orig_cpus);
35267ed5d8SAndi Kleen return -1;
36267ed5d8SAndi Kleen }
37267ed5d8SAndi Kleen bitmap_zero((unsigned long *)a->sched_cpus, cpu_set_size);
38267ed5d8SAndi Kleen a->changed = false;
39267ed5d8SAndi Kleen return 0;
40267ed5d8SAndi Kleen }
41267ed5d8SAndi Kleen
42267ed5d8SAndi Kleen /*
43267ed5d8SAndi Kleen * perf_event_open does an IPI internally to the target CPU.
44267ed5d8SAndi Kleen * It is more efficient to change perf's affinity to the target
45267ed5d8SAndi Kleen * CPU and then set up all events on that CPU, so we amortize
46267ed5d8SAndi Kleen * CPU communication.
47267ed5d8SAndi Kleen */
affinity__set(struct affinity * a,int cpu)48267ed5d8SAndi Kleen void affinity__set(struct affinity *a, int cpu)
49267ed5d8SAndi Kleen {
50267ed5d8SAndi Kleen int cpu_set_size = get_cpu_set_size();
51267ed5d8SAndi Kleen
5272cd652bSAthira Rajeev /*
5372cd652bSAthira Rajeev * Return:
5472cd652bSAthira Rajeev * - if cpu is -1
5572cd652bSAthira Rajeev * - restrict out of bound access to sched_cpus
5672cd652bSAthira Rajeev */
5772cd652bSAthira Rajeev if (cpu == -1 || ((cpu >= (cpu_set_size * 8))))
58267ed5d8SAndi Kleen return;
5972cd652bSAthira Rajeev
60267ed5d8SAndi Kleen a->changed = true;
61*75d7ba32SSean Christopherson __set_bit(cpu, a->sched_cpus);
62267ed5d8SAndi Kleen /*
63267ed5d8SAndi Kleen * We ignore errors because affinity is just an optimization.
64267ed5d8SAndi Kleen * This could happen for example with isolated CPUs or cpusets.
65267ed5d8SAndi Kleen * In this case the IPIs inside the kernel's perf API still work.
66267ed5d8SAndi Kleen */
67267ed5d8SAndi Kleen sched_setaffinity(0, cpu_set_size, (cpu_set_t *)a->sched_cpus);
68*75d7ba32SSean Christopherson __clear_bit(cpu, a->sched_cpus);
69267ed5d8SAndi Kleen }
70267ed5d8SAndi Kleen
__affinity__cleanup(struct affinity * a)711855b796SArnaldo Carvalho de Melo static void __affinity__cleanup(struct affinity *a)
72267ed5d8SAndi Kleen {
73267ed5d8SAndi Kleen int cpu_set_size = get_cpu_set_size();
74267ed5d8SAndi Kleen
75267ed5d8SAndi Kleen if (a->changed)
76267ed5d8SAndi Kleen sched_setaffinity(0, cpu_set_size, (cpu_set_t *)a->orig_cpus);
77267ed5d8SAndi Kleen zfree(&a->sched_cpus);
78267ed5d8SAndi Kleen zfree(&a->orig_cpus);
79267ed5d8SAndi Kleen }
801855b796SArnaldo Carvalho de Melo
affinity__cleanup(struct affinity * a)811855b796SArnaldo Carvalho de Melo void affinity__cleanup(struct affinity *a)
821855b796SArnaldo Carvalho de Melo {
831855b796SArnaldo Carvalho de Melo if (a != NULL)
841855b796SArnaldo Carvalho de Melo __affinity__cleanup(a);
851855b796SArnaldo Carvalho de Melo }
86