linux/tools/perf/util/affinity.c
<<
>>
Prefs
   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
  12static 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
  24int affinity__setup(struct affinity *a)
  25{
  26        int cpu_set_size = get_cpu_set_size();
  27
  28        a->orig_cpus = bitmap_zalloc(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_zalloc(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 */
  48void 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
  65void 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}
  74