linux/samples/bpf/tracex6_user.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#define _GNU_SOURCE
   3
   4#include <assert.h>
   5#include <fcntl.h>
   6#include <linux/perf_event.h>
   7#include <linux/bpf.h>
   8#include <sched.h>
   9#include <stdio.h>
  10#include <stdlib.h>
  11#include <sys/ioctl.h>
  12#include <sys/resource.h>
  13#include <sys/time.h>
  14#include <sys/types.h>
  15#include <sys/wait.h>
  16#include <unistd.h>
  17
  18#include "bpf_load.h"
  19#include <bpf/bpf.h>
  20#include "perf-sys.h"
  21
  22#define SAMPLE_PERIOD  0x7fffffffffffffffULL
  23
  24static void check_on_cpu(int cpu, struct perf_event_attr *attr)
  25{
  26        struct bpf_perf_event_value value2;
  27        int pmu_fd, error = 0;
  28        cpu_set_t set;
  29        __u64 value;
  30
  31        /* Move to target CPU */
  32        CPU_ZERO(&set);
  33        CPU_SET(cpu, &set);
  34        assert(sched_setaffinity(0, sizeof(set), &set) == 0);
  35        /* Open perf event and attach to the perf_event_array */
  36        pmu_fd = sys_perf_event_open(attr, -1/*pid*/, cpu/*cpu*/, -1/*group_fd*/, 0);
  37        if (pmu_fd < 0) {
  38                fprintf(stderr, "sys_perf_event_open failed on CPU %d\n", cpu);
  39                error = 1;
  40                goto on_exit;
  41        }
  42        assert(bpf_map_update_elem(map_fd[0], &cpu, &pmu_fd, BPF_ANY) == 0);
  43        assert(ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0) == 0);
  44        /* Trigger the kprobe */
  45        bpf_map_get_next_key(map_fd[1], &cpu, NULL);
  46        /* Check the value */
  47        if (bpf_map_lookup_elem(map_fd[1], &cpu, &value)) {
  48                fprintf(stderr, "Value missing for CPU %d\n", cpu);
  49                error = 1;
  50                goto on_exit;
  51        } else {
  52                fprintf(stderr, "CPU %d: %llu\n", cpu, value);
  53        }
  54        /* The above bpf_map_lookup_elem should trigger the second kprobe */
  55        if (bpf_map_lookup_elem(map_fd[2], &cpu, &value2)) {
  56                fprintf(stderr, "Value2 missing for CPU %d\n", cpu);
  57                error = 1;
  58                goto on_exit;
  59        } else {
  60                fprintf(stderr, "CPU %d: counter: %llu, enabled: %llu, running: %llu\n", cpu,
  61                        value2.counter, value2.enabled, value2.running);
  62        }
  63
  64on_exit:
  65        assert(bpf_map_delete_elem(map_fd[0], &cpu) == 0 || error);
  66        assert(ioctl(pmu_fd, PERF_EVENT_IOC_DISABLE, 0) == 0 || error);
  67        assert(close(pmu_fd) == 0 || error);
  68        assert(bpf_map_delete_elem(map_fd[1], &cpu) == 0 || error);
  69        exit(error);
  70}
  71
  72static void test_perf_event_array(struct perf_event_attr *attr,
  73                                  const char *name)
  74{
  75        int i, status, nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
  76        pid_t pid[nr_cpus];
  77        int err = 0;
  78
  79        printf("Test reading %s counters\n", name);
  80
  81        for (i = 0; i < nr_cpus; i++) {
  82                pid[i] = fork();
  83                assert(pid[i] >= 0);
  84                if (pid[i] == 0) {
  85                        check_on_cpu(i, attr);
  86                        exit(1);
  87                }
  88        }
  89
  90        for (i = 0; i < nr_cpus; i++) {
  91                assert(waitpid(pid[i], &status, 0) == pid[i]);
  92                err |= status;
  93        }
  94
  95        if (err)
  96                printf("Test: %s FAILED\n", name);
  97}
  98
  99static void test_bpf_perf_event(void)
 100{
 101        struct perf_event_attr attr_cycles = {
 102                .freq = 0,
 103                .sample_period = SAMPLE_PERIOD,
 104                .inherit = 0,
 105                .type = PERF_TYPE_HARDWARE,
 106                .read_format = 0,
 107                .sample_type = 0,
 108                .config = PERF_COUNT_HW_CPU_CYCLES,
 109        };
 110        struct perf_event_attr attr_clock = {
 111                .freq = 0,
 112                .sample_period = SAMPLE_PERIOD,
 113                .inherit = 0,
 114                .type = PERF_TYPE_SOFTWARE,
 115                .read_format = 0,
 116                .sample_type = 0,
 117                .config = PERF_COUNT_SW_CPU_CLOCK,
 118        };
 119        struct perf_event_attr attr_raw = {
 120                .freq = 0,
 121                .sample_period = SAMPLE_PERIOD,
 122                .inherit = 0,
 123                .type = PERF_TYPE_RAW,
 124                .read_format = 0,
 125                .sample_type = 0,
 126                /* Intel Instruction Retired */
 127                .config = 0xc0,
 128        };
 129        struct perf_event_attr attr_l1d_load = {
 130                .freq = 0,
 131                .sample_period = SAMPLE_PERIOD,
 132                .inherit = 0,
 133                .type = PERF_TYPE_HW_CACHE,
 134                .read_format = 0,
 135                .sample_type = 0,
 136                .config =
 137                        PERF_COUNT_HW_CACHE_L1D |
 138                        (PERF_COUNT_HW_CACHE_OP_READ << 8) |
 139                        (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16),
 140        };
 141        struct perf_event_attr attr_llc_miss = {
 142                .freq = 0,
 143                .sample_period = SAMPLE_PERIOD,
 144                .inherit = 0,
 145                .type = PERF_TYPE_HW_CACHE,
 146                .read_format = 0,
 147                .sample_type = 0,
 148                .config =
 149                        PERF_COUNT_HW_CACHE_LL |
 150                        (PERF_COUNT_HW_CACHE_OP_READ << 8) |
 151                        (PERF_COUNT_HW_CACHE_RESULT_MISS << 16),
 152        };
 153        struct perf_event_attr attr_msr_tsc = {
 154                .freq = 0,
 155                .sample_period = 0,
 156                .inherit = 0,
 157                /* From /sys/bus/event_source/devices/msr/ */
 158                .type = 7,
 159                .read_format = 0,
 160                .sample_type = 0,
 161                .config = 0,
 162        };
 163
 164        test_perf_event_array(&attr_cycles, "HARDWARE-cycles");
 165        test_perf_event_array(&attr_clock, "SOFTWARE-clock");
 166        test_perf_event_array(&attr_raw, "RAW-instruction-retired");
 167        test_perf_event_array(&attr_l1d_load, "HW_CACHE-L1D-load");
 168
 169        /* below tests may fail in qemu */
 170        test_perf_event_array(&attr_llc_miss, "HW_CACHE-LLC-miss");
 171        test_perf_event_array(&attr_msr_tsc, "Dynamic-msr-tsc");
 172}
 173
 174int main(int argc, char **argv)
 175{
 176        struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
 177        char filename[256];
 178
 179        snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
 180
 181        setrlimit(RLIMIT_MEMLOCK, &r);
 182        if (load_bpf_file(filename)) {
 183                printf("%s", bpf_log_buf);
 184                return 1;
 185        }
 186
 187        test_bpf_perf_event();
 188        return 0;
 189}
 190