aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@plumgrid.com>2015-03-25 15:49:26 -0400
committerIngo Molnar <mingo@kernel.org>2015-04-02 07:25:51 -0400
commit9811e35359d4b18baf5bb603b225e957255b9c46 (patch)
treeba65e75bc85cb6e570a17a48408b202161bbcd05
parent5c7fc2d27d004f28f3a94b35edd40e68f779e35a (diff)
samples/bpf: Add kmem_alloc()/free() tracker tool
One BPF program attaches to kmem_cache_alloc_node() and remembers all allocated objects in the map. Another program attaches to kmem_cache_free() and deletes corresponding object from the map. User space walks the map every second and prints any objects which are older than 1 second. Usage: $ sudo tracex4 Then start few long living processes. The 'tracex4' will print something like this: obj 0xffff880465928000 is 13sec old was allocated at ip ffffffff8105dc32 obj 0xffff88043181c280 is 13sec old was allocated at ip ffffffff8105dc32 obj 0xffff880465848000 is 8sec old was allocated at ip ffffffff8105dc32 obj 0xffff8804338bc280 is 15sec old was allocated at ip ffffffff8105dc32 $ addr2line -fispe vmlinux ffffffff8105dc32 do_fork at fork.c:1665 As soon as processes exit the memory is reclaimed and 'tracex4' prints nothing. Similar experiment can be done with the __kmalloc()/kfree() pair. Signed-off-by: Alexei Starovoitov <ast@plumgrid.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Arnaldo Carvalho de Melo <acme@infradead.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Daniel Borkmann <daniel@iogearbox.net> Cc: David S. Miller <davem@davemloft.net> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Steven Rostedt <rostedt@goodmis.org> Link: http://lkml.kernel.org/r/1427312966-8434-10-git-send-email-ast@plumgrid.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--samples/bpf/Makefile4
-rw-r--r--samples/bpf/tracex4_kern.c54
-rw-r--r--samples/bpf/tracex4_user.c69
3 files changed, 127 insertions, 0 deletions
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index dcd850546d52..fe98fb226e6e 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -9,6 +9,7 @@ hostprogs-y += sockex2
9hostprogs-y += tracex1 9hostprogs-y += tracex1
10hostprogs-y += tracex2 10hostprogs-y += tracex2
11hostprogs-y += tracex3 11hostprogs-y += tracex3
12hostprogs-y += tracex4
12 13
13test_verifier-objs := test_verifier.o libbpf.o 14test_verifier-objs := test_verifier.o libbpf.o
14test_maps-objs := test_maps.o libbpf.o 15test_maps-objs := test_maps.o libbpf.o
@@ -18,6 +19,7 @@ sockex2-objs := bpf_load.o libbpf.o sockex2_user.o
18tracex1-objs := bpf_load.o libbpf.o tracex1_user.o 19tracex1-objs := bpf_load.o libbpf.o tracex1_user.o
19tracex2-objs := bpf_load.o libbpf.o tracex2_user.o 20tracex2-objs := bpf_load.o libbpf.o tracex2_user.o
20tracex3-objs := bpf_load.o libbpf.o tracex3_user.o 21tracex3-objs := bpf_load.o libbpf.o tracex3_user.o
22tracex4-objs := bpf_load.o libbpf.o tracex4_user.o
21 23
22# Tell kbuild to always build the programs 24# Tell kbuild to always build the programs
23always := $(hostprogs-y) 25always := $(hostprogs-y)
@@ -26,6 +28,7 @@ always += sockex2_kern.o
26always += tracex1_kern.o 28always += tracex1_kern.o
27always += tracex2_kern.o 29always += tracex2_kern.o
28always += tracex3_kern.o 30always += tracex3_kern.o
31always += tracex4_kern.o
29 32
30HOSTCFLAGS += -I$(objtree)/usr/include 33HOSTCFLAGS += -I$(objtree)/usr/include
31 34
@@ -35,6 +38,7 @@ HOSTLOADLIBES_sockex2 += -lelf
35HOSTLOADLIBES_tracex1 += -lelf 38HOSTLOADLIBES_tracex1 += -lelf
36HOSTLOADLIBES_tracex2 += -lelf 39HOSTLOADLIBES_tracex2 += -lelf
37HOSTLOADLIBES_tracex3 += -lelf 40HOSTLOADLIBES_tracex3 += -lelf
41HOSTLOADLIBES_tracex4 += -lelf -lrt
38 42
39# point this to your LLVM backend with bpf support 43# point this to your LLVM backend with bpf support
40LLC=$(srctree)/tools/bpf/llvm/bld/Debug+Asserts/bin/llc 44LLC=$(srctree)/tools/bpf/llvm/bld/Debug+Asserts/bin/llc
diff --git a/samples/bpf/tracex4_kern.c b/samples/bpf/tracex4_kern.c
new file mode 100644
index 000000000000..126b80512228
--- /dev/null
+++ b/samples/bpf/tracex4_kern.c
@@ -0,0 +1,54 @@
1/* Copyright (c) 2015 PLUMgrid, http://plumgrid.com
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of version 2 of the GNU General Public
5 * License as published by the Free Software Foundation.
6 */
7#include <linux/ptrace.h>
8#include <linux/version.h>
9#include <uapi/linux/bpf.h>
10#include "bpf_helpers.h"
11
12struct pair {
13 u64 val;
14 u64 ip;
15};
16
17struct bpf_map_def SEC("maps") my_map = {
18 .type = BPF_MAP_TYPE_HASH,
19 .key_size = sizeof(long),
20 .value_size = sizeof(struct pair),
21 .max_entries = 1000000,
22};
23
24/* kprobe is NOT a stable ABI. If kernel internals change this bpf+kprobe
25 * example will no longer be meaningful
26 */
27SEC("kprobe/kmem_cache_free")
28int bpf_prog1(struct pt_regs *ctx)
29{
30 long ptr = ctx->si;
31
32 bpf_map_delete_elem(&my_map, &ptr);
33 return 0;
34}
35
36SEC("kretprobe/kmem_cache_alloc_node")
37int bpf_prog2(struct pt_regs *ctx)
38{
39 long ptr = ctx->ax;
40 long ip = 0;
41
42 /* get ip address of kmem_cache_alloc_node() caller */
43 bpf_probe_read(&ip, sizeof(ip), (void *)(ctx->bp + sizeof(ip)));
44
45 struct pair v = {
46 .val = bpf_ktime_get_ns(),
47 .ip = ip,
48 };
49
50 bpf_map_update_elem(&my_map, &ptr, &v, BPF_ANY);
51 return 0;
52}
53char _license[] SEC("license") = "GPL";
54u32 _version SEC("version") = LINUX_VERSION_CODE;
diff --git a/samples/bpf/tracex4_user.c b/samples/bpf/tracex4_user.c
new file mode 100644
index 000000000000..bc4a3bdea6ed
--- /dev/null
+++ b/samples/bpf/tracex4_user.c
@@ -0,0 +1,69 @@
1/* Copyright (c) 2015 PLUMgrid, http://plumgrid.com
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of version 2 of the GNU General Public
5 * License as published by the Free Software Foundation.
6 */
7#include <stdio.h>
8#include <stdlib.h>
9#include <signal.h>
10#include <unistd.h>
11#include <stdbool.h>
12#include <string.h>
13#include <time.h>
14#include <linux/bpf.h>
15#include "libbpf.h"
16#include "bpf_load.h"
17
18struct pair {
19 long long val;
20 __u64 ip;
21};
22
23static __u64 time_get_ns(void)
24{
25 struct timespec ts;
26
27 clock_gettime(CLOCK_MONOTONIC, &ts);
28 return ts.tv_sec * 1000000000ull + ts.tv_nsec;
29}
30
31static void print_old_objects(int fd)
32{
33 long long val = time_get_ns();
34 __u64 key, next_key;
35 struct pair v;
36
37 key = write(1, "\e[1;1H\e[2J", 12); /* clear screen */
38
39 key = -1;
40 while (bpf_get_next_key(map_fd[0], &key, &next_key) == 0) {
41 bpf_lookup_elem(map_fd[0], &next_key, &v);
42 key = next_key;
43 if (val - v.val < 1000000000ll)
44 /* object was allocated more then 1 sec ago */
45 continue;
46 printf("obj 0x%llx is %2lldsec old was allocated at ip %llx\n",
47 next_key, (val - v.val) / 1000000000ll, v.ip);
48 }
49}
50
51int main(int ac, char **argv)
52{
53 char filename[256];
54 int i;
55
56 snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
57
58 if (load_bpf_file(filename)) {
59 printf("%s", bpf_log_buf);
60 return 1;
61 }
62
63 for (i = 0; ; i++) {
64 print_old_objects(map_fd[1]);
65 sleep(1);
66 }
67
68 return 0;
69}