]>
Commit | Line | Data |
---|---|---|
267ed5d8 AK |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Manage affinity to optimize IPIs inside the kernel perf API. */ | |
3 | #define _GNU_SOURCE 1 | |
4 | #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 | ||
12 | static int get_cpu_set_size(void) | |
13 | { | |
14 | int sz = cpu__max_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 | ||
24 | int affinity__setup(struct affinity *a) | |
25 | { | |
26 | int cpu_set_size = get_cpu_set_size(); | |
27 | ||
28 | a->orig_cpus = bitmap_alloc(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_alloc(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 target | |
45 | * CPU and then set up all events on that CPU, so we amortize | |
46 | * CPU communication. | |
47 | */ | |
48 | void affinity__set(struct affinity *a, int cpu) | |
49 | { | |
50 | int cpu_set_size = get_cpu_set_size(); | |
51 | ||
52 | if (cpu == -1) | |
53 | return; | |
54 | a->changed = true; | |
55 | set_bit(cpu, a->sched_cpus); | |
56 | /* | |
57 | * We ignore errors because affinity is just an optimization. | |
58 | * This could happen for example with isolated CPUs or cpusets. | |
59 | * In this case the IPIs inside the kernel's perf API still work. | |
60 | */ | |
61 | sched_setaffinity(0, cpu_set_size, (cpu_set_t *)a->sched_cpus); | |
62 | clear_bit(cpu, a->sched_cpus); | |
63 | } | |
64 | ||
65 | void affinity__cleanup(struct affinity *a) | |
66 | { | |
67 | int cpu_set_size = get_cpu_set_size(); | |
68 | ||
69 | if (a->changed) | |
70 | sched_setaffinity(0, cpu_set_size, (cpu_set_t *)a->orig_cpus); | |
71 | zfree(&a->sched_cpus); | |
72 | zfree(&a->orig_cpus); | |
73 | } |