linux/tools/perf/util/target.h
Song Liu fa853c4b83 perf stat: Enable counting events for BPF programs
Introduce 'perf stat -b' option, which counts events for BPF programs, like:

  [root@localhost ~]# ~/perf stat -e ref-cycles,cycles -b 254 -I 1000
     1.487903822            115,200      ref-cycles
     1.487903822             86,012      cycles
     2.489147029             80,560      ref-cycles
     2.489147029             73,784      cycles
     3.490341825             60,720      ref-cycles
     3.490341825             37,797      cycles
     4.491540887             37,120      ref-cycles
     4.491540887             31,963      cycles

The example above counts 'cycles' and 'ref-cycles' of BPF program of id
254.  This is similar to bpftool-prog-profile command, but more
flexible.

'perf stat -b' creates per-cpu perf_event and loads fentry/fexit BPF
programs (monitor-progs) to the target BPF program (target-prog). The
monitor-progs read perf_event before and after the target-prog, and
aggregate the difference in a BPF map. Then the user space reads data
from these maps.

A new 'struct bpf_counter' is introduced to provide a common interface
that uses BPF programs/maps to count perf events.

Committer notes:

Removed all but bpf_counter.h includes from evsel.h, not needed at all.

Also BPF map lookups for PERCPU_ARRAYs need to have as its value receive
buffer passed to the kernel libbpf_num_possible_cpus() entries, not
evsel__nr_cpus(evsel), as the former uses
/sys/devices/system/cpu/possible while the later uses
/sys/devices/system/cpu/online, which may be less than the 'possible'
number making the bpf map lookup overwrite memory and cause hard to
debug memory corruption.

We need to continue using evsel__nr_cpus(evsel) when accessing the
perf_counts array tho, not to overwrite another are of memory :-)

Signed-off-by: Song Liu <songliubraving@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: https://lore.kernel.org/lkml/20210120163031.GU12699@kernel.org/
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: kernel-team@fb.com
Link: http://lore.kernel.org/lkml/20201229214214.3413833-4-songliubraving@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-01-20 14:25:28 -03:00

98 lines
2.4 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _PERF_TARGET_H
#define _PERF_TARGET_H
#include <stdbool.h>
#include <sys/types.h>
struct target {
const char *pid;
const char *tid;
const char *cpu_list;
const char *uid_str;
const char *bpf_str;
uid_t uid;
bool system_wide;
bool uses_mmap;
bool default_per_cpu;
bool per_thread;
};
enum target_errno {
TARGET_ERRNO__SUCCESS = 0,
/*
* Choose an arbitrary negative big number not to clash with standard
* errno since SUS requires the errno has distinct positive values.
* See 'Issue 6' in the link below.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
*/
__TARGET_ERRNO__START = -10000,
/* for target__validate() */
TARGET_ERRNO__PID_OVERRIDE_CPU = __TARGET_ERRNO__START,
TARGET_ERRNO__PID_OVERRIDE_UID,
TARGET_ERRNO__UID_OVERRIDE_CPU,
TARGET_ERRNO__PID_OVERRIDE_SYSTEM,
TARGET_ERRNO__UID_OVERRIDE_SYSTEM,
TARGET_ERRNO__SYSTEM_OVERRIDE_THREAD,
TARGET_ERRNO__BPF_OVERRIDE_CPU,
TARGET_ERRNO__BPF_OVERRIDE_PID,
TARGET_ERRNO__BPF_OVERRIDE_UID,
TARGET_ERRNO__BPF_OVERRIDE_THREAD,
/* for target__parse_uid() */
TARGET_ERRNO__INVALID_UID,
TARGET_ERRNO__USER_NOT_FOUND,
__TARGET_ERRNO__END,
};
enum target_errno target__validate(struct target *target);
enum target_errno target__parse_uid(struct target *target);
int target__strerror(struct target *target, int errnum, char *buf, size_t buflen);
static inline bool target__has_task(struct target *target)
{
return target->tid || target->pid || target->uid_str;
}
static inline bool target__has_cpu(struct target *target)
{
return target->system_wide || target->cpu_list;
}
static inline bool target__has_bpf(struct target *target)
{
return target->bpf_str;
}
static inline bool target__none(struct target *target)
{
return !target__has_task(target) && !target__has_cpu(target);
}
static inline bool target__has_per_thread(struct target *target)
{
return target->system_wide && target->per_thread;
}
static inline bool target__uses_dummy_map(struct target *target)
{
bool use_dummy = false;
if (target->default_per_cpu)
use_dummy = target->per_thread ? true : false;
else if (target__has_task(target) ||
(!target__has_cpu(target) && !target->uses_mmap))
use_dummy = true;
else if (target__has_per_thread(target))
use_dummy = true;
return use_dummy;
}
#endif /* _PERF_TARGET_H */