This is a simple example and shows how to use the new ability
to get the selected PMU counter value.

The trace output:
  $ ./bpf_pmu_test
  $ cat /sys/kernel/debug/tracing/trace
       ...
       syslog-ng-555   [001] dn.1 10189.004626: : bpf count: CPU-0  9935764297
       syslog-ng-555   [001] d..1 10189.053776: : bpf count: CPU-0  10000706398
       syslog-ng-555   [001] dn.1 10189.102972: : bpf count: CPU-0  10067117321
       syslog-ng-555   [001] d..1 10189.152925: : bpf count: CPU-0  10134551505
       syslog-ng-555   [001] dn.1 10189.202043: : bpf count: CPU-0  10200869299
       syslog-ng-555   [001] d..1 10189.251167: : bpf count: CPU-0  10267179481
       syslog-ng-555   [001] dn.1 10189.300285: : bpf count: CPU-0  10333493522
       syslog-ng-555   [001] d..1 10189.349410: : bpf count: CPU-0  10399808073
       syslog-ng-555   [001] dn.1 10189.398528: : bpf count: CPU-0  10466121583
       syslog-ng-555   [001] d..1 10189.447645: : bpf count: CPU-0  10532433368
       syslog-ng-555   [001] d..1 10189.496841: : bpf count: CPU-0  10598841104
       syslog-ng-555   [001] d..1 10189.546891: : bpf count: CPU-0  10666410564
       syslog-ng-555   [001] dn.1 10189.596016: : bpf count: CPU-0  10732729739
       syslog-ng-555   [001] d..1 10189.645146: : bpf count: CPU-0  12884941186
       syslog-ng-555   [001] d..1 10189.694263: : bpf count: CPU-0  12951249903
       syslog-ng-555   [001] dn.1 10189.743382: : bpf count: CPU-0  13017561470
       syslog-ng-555   [001] d..1 10189.792506: : bpf count: CPU-0  13083873521
       syslog-ng-555   [001] d..1 10189.841631: : bpf count: CPU-0  13150190416
       syslog-ng-555   [001] d..1 10189.890749: : bpf count: CPU-0  13216505962
       syslog-ng-555   [001] d..1 10189.939945: : bpf count: CPU-0  13282913062
       ...

Signed-off-by: kaixu xia <xiaka...@huawei.com>
---
 samples/bpf/bpf_helpers.h  |    2 +
 samples/bpf/bpf_pmu_test.c |  143 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 145 insertions(+)
 create mode 100644 samples/bpf/bpf_pmu_test.c

diff --git a/samples/bpf/bpf_helpers.h b/samples/bpf/bpf_helpers.h
index bdf1c16..a421be1 100644
--- a/samples/bpf/bpf_helpers.h
+++ b/samples/bpf/bpf_helpers.h
@@ -31,6 +31,8 @@ static unsigned long long (*bpf_get_current_uid_gid)(void) =
        (void *) BPF_FUNC_get_current_uid_gid;
 static int (*bpf_get_current_comm)(void *buf, int buf_size) =
        (void *) BPF_FUNC_get_current_comm;
+static int (*bpf_read_pmu)(void *pmu) =
+       (void *) BPF_FUNC_read_pmu;
 
 /* llvm builtin functions that eBPF C program may use to
  * emit BPF_LD_ABS and BPF_LD_IND instructions
diff --git a/samples/bpf/bpf_pmu_test.c b/samples/bpf/bpf_pmu_test.c
new file mode 100644
index 0000000..aced233
--- /dev/null
+++ b/samples/bpf/bpf_pmu_test.c
@@ -0,0 +1,143 @@
+/* eBPF example program shows how to get hardware PMU counter
+ * - creates hashmap in kernel
+ *
+ * - save the pointer to struct perf_event to map
+ *
+ * - loads eBPF program:
+ *   r0 = 0 (the chosen key: CPU-0)
+ *   *(u32 *)(fp - 4) = r0
+ *   value = bpf_map_lookup_elem(map_fd, fp - 4);
+ *   count = bpf_read_pmu(value);
+ *   bpf_trace_printk(fmt, fmt_size, key, count);
+ *
+ * - attaches this program to kprobes/sys_write
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <assert.h>
+#include <linux/bpf.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <sys/ioctl.h>
+#include <linux/perf_event.h>
+#include "libbpf.h"
+
+static int test_pmu(void)
+{
+       int kprobe_fd, prog_fd, i;
+       int nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
+       int *pmu_fd = malloc(nr_cpus * sizeof(int));
+       int key, map_fd;
+       unsigned long value;
+
+       char fmt[] = "bpf count: CPU-%d  %lld\n";
+       int fmt_size = sizeof(fmt);
+
+       int type = BPF_MAP_TYPE_HASH | BPF_MAP_FLAG_PERF_EVENT;
+
+       map_fd = bpf_create_map(type, sizeof(key), sizeof(value),
+                               nr_cpus);
+       if(map_fd < 0) {
+               printf("failed to create map '%s'\n", strerror(errno));
+               return -1;
+       }
+
+       struct perf_event_attr attr_insn_kprobe = {
+               .sample_period = 1,
+               .type = PERF_TYPE_TRACEPOINT,
+               .sample_type = PERF_SAMPLE_RAW,
+               .wakeup_events = 1,
+               .config = 0x46B, /* sys_write (this ID maybe change) */
+       };
+
+       struct perf_event_attr attr_insn_pmu = {
+               .freq = 0,
+               .sample_period = 0x7fffffffffffffffULL,
+               .inherit = 0,
+               .type = PERF_TYPE_RAW,
+               .read_format = 0,
+               .sample_type = 0,
+               .config = 0x11,/* PMU: cycles (ARM) */
+
+       };
+
+       for(i = 0; i < nr_cpus; i++) {
+               pmu_fd[i] = perf_event_open(&attr_insn_pmu, -1/*pid*/, 
i/*cpu*/, -1/*group_fd*/, 0);
+               if (pmu_fd[i] < 0) {
+                       printf("event syscall failed ****\n");
+                       return -1;
+               }
+
+               ioctl(pmu_fd[i], PERF_EVENT_IOC_ENABLE, 0);
+
+               bpf_update_elem(map_fd, &i, (pmu_fd + i), BPF_ANY);
+       }
+
+       kprobe_fd = perf_event_open(&attr_insn_kprobe, -1/*pid*/, 0/*cpu*/, 
-1/*group_fd*/, 0);
+       if (kprobe_fd < 0) {
+               printf("kprobe event syscall failed ****\n");
+               return -1;
+       }
+       ioctl(kprobe_fd, PERF_EVENT_IOC_ENABLE, 0);
+
+       struct bpf_insn prog[] = {
+               BPF_MOV64_IMM(BPF_REG_0, 0), /* r0 = 0 */
+               BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4), /* *(u32 *)(fp - 
4) = r0 */
+               BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), /* r2 = fp */
+               BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4), /* r2 = fp - 4 */
+               BPF_LD_MAP_FD(BPF_REG_1, map_fd),
+               BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, 
BPF_FUNC_map_lookup_elem),
+               BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
+               BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_read_pmu),
+               BPF_MOV64_REG(BPF_REG_6, BPF_REG_0),
+               BPF_MOV64_IMM(BPF_REG_1, 0),
+               BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_1, -8),
+               BPF_LD_IMM64(BPF_REG_1, 748842649785475172),
+               BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, -16),
+               BPF_LD_IMM64(BPF_REG_1, 2678891156567243380),
+               BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, -24),
+               BPF_LD_IMM64(BPF_REG_1, 7959390387983249506),
+               BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, -32),
+               BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
+               BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -32),
+               BPF_MOV64_IMM(BPF_REG_2, 25),
+               BPF_MOV64_IMM(BPF_REG_3, 0),
+               BPF_MOV64_REG(BPF_REG_4, BPF_REG_6),
+               BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, 
BPF_FUNC_trace_printk),
+               BPF_EXIT_INSN(),
+       };
+
+       prog_fd = bpf_prog_load(BPF_PROG_TYPE_KPROBE, prog, sizeof(prog),
+                       "GPL", 0);
+       if (prog_fd < 0) {
+               printf("failed to load prog '%s'\n", strerror(errno));
+               return -1;
+       }
+
+       ioctl(kprobe_fd, PERF_EVENT_IOC_SET_BPF, prog_fd);
+
+       system("ls");
+       system("pwd");
+       system("sleep 4");
+
+       for(i = 0; i < nr_cpus; i++) {
+               close(pmu_fd[i]);
+       }
+
+       close(map_fd);
+
+       free(pmu_fd);
+       return 0;
+}
+
+int main(int argc, char **argv)
+{
+       test_pmu();
+
+       return 0;
+}
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to