Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Manage affinity to optimize IPIs inside the kernel perf API. */
0003 #define _GNU_SOURCE 1
0004 #include <sched.h>
0005 #include <stdlib.h>
0006 #include <linux/bitmap.h>
0007 #include <linux/zalloc.h>
0008 #include "perf.h"
0009 #include "cpumap.h"
0010 #include "affinity.h"
0011 
0012 static int get_cpu_set_size(void)
0013 {
0014     int sz = cpu__max_cpu().cpu + 8 - 1;
0015     /*
0016      * sched_getaffinity doesn't like masks smaller than the kernel.
0017      * Hopefully that's big enough.
0018      */
0019     if (sz < 4096)
0020         sz = 4096;
0021     return sz / 8;
0022 }
0023 
0024 int affinity__setup(struct affinity *a)
0025 {
0026     int cpu_set_size = get_cpu_set_size();
0027 
0028     a->orig_cpus = bitmap_zalloc(cpu_set_size * 8);
0029     if (!a->orig_cpus)
0030         return -1;
0031     sched_getaffinity(0, cpu_set_size, (cpu_set_t *)a->orig_cpus);
0032     a->sched_cpus = bitmap_zalloc(cpu_set_size * 8);
0033     if (!a->sched_cpus) {
0034         zfree(&a->orig_cpus);
0035         return -1;
0036     }
0037     bitmap_zero((unsigned long *)a->sched_cpus, cpu_set_size);
0038     a->changed = false;
0039     return 0;
0040 }
0041 
0042 /*
0043  * perf_event_open does an IPI internally to the target CPU.
0044  * It is more efficient to change perf's affinity to the target
0045  * CPU and then set up all events on that CPU, so we amortize
0046  * CPU communication.
0047  */
0048 void affinity__set(struct affinity *a, int cpu)
0049 {
0050     int cpu_set_size = get_cpu_set_size();
0051 
0052     /*
0053      * Return:
0054      * - if cpu is -1
0055      * - restrict out of bound access to sched_cpus
0056      */
0057     if (cpu == -1 || ((cpu >= (cpu_set_size * 8))))
0058         return;
0059 
0060     a->changed = true;
0061     set_bit(cpu, a->sched_cpus);
0062     /*
0063      * We ignore errors because affinity is just an optimization.
0064      * This could happen for example with isolated CPUs or cpusets.
0065      * In this case the IPIs inside the kernel's perf API still work.
0066      */
0067     sched_setaffinity(0, cpu_set_size, (cpu_set_t *)a->sched_cpus);
0068     clear_bit(cpu, a->sched_cpus);
0069 }
0070 
0071 static void __affinity__cleanup(struct affinity *a)
0072 {
0073     int cpu_set_size = get_cpu_set_size();
0074 
0075     if (a->changed)
0076         sched_setaffinity(0, cpu_set_size, (cpu_set_t *)a->orig_cpus);
0077     zfree(&a->sched_cpus);
0078     zfree(&a->orig_cpus);
0079 }
0080 
0081 void affinity__cleanup(struct affinity *a)
0082 {
0083     if (a != NULL)
0084         __affinity__cleanup(a);
0085 }