diff options
Diffstat (limited to 'samples/bpf/trace_output_user.c')
-rw-r--r-- | samples/bpf/trace_output_user.c | 110 |
1 files changed, 10 insertions, 100 deletions
diff --git a/samples/bpf/trace_output_user.c b/samples/bpf/trace_output_user.c index ccca1e348017..5e78c2ecd08d 100644 --- a/samples/bpf/trace_output_user.c +++ b/samples/bpf/trace_output_user.c | |||
@@ -21,100 +21,10 @@ | |||
21 | #include "libbpf.h" | 21 | #include "libbpf.h" |
22 | #include "bpf_load.h" | 22 | #include "bpf_load.h" |
23 | #include "perf-sys.h" | 23 | #include "perf-sys.h" |
24 | #include "trace_helpers.h" | ||
24 | 25 | ||
25 | static int pmu_fd; | 26 | static int pmu_fd; |
26 | 27 | ||
27 | int page_size; | ||
28 | int page_cnt = 8; | ||
29 | volatile struct perf_event_mmap_page *header; | ||
30 | |||
31 | typedef void (*print_fn)(void *data, int size); | ||
32 | |||
33 | static int perf_event_mmap(int fd) | ||
34 | { | ||
35 | void *base; | ||
36 | int mmap_size; | ||
37 | |||
38 | page_size = getpagesize(); | ||
39 | mmap_size = page_size * (page_cnt + 1); | ||
40 | |||
41 | base = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); | ||
42 | if (base == MAP_FAILED) { | ||
43 | printf("mmap err\n"); | ||
44 | return -1; | ||
45 | } | ||
46 | |||
47 | header = base; | ||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | static int perf_event_poll(int fd) | ||
52 | { | ||
53 | struct pollfd pfd = { .fd = fd, .events = POLLIN }; | ||
54 | |||
55 | return poll(&pfd, 1, 1000); | ||
56 | } | ||
57 | |||
58 | struct perf_event_sample { | ||
59 | struct perf_event_header header; | ||
60 | __u32 size; | ||
61 | char data[]; | ||
62 | }; | ||
63 | |||
64 | static void perf_event_read(print_fn fn) | ||
65 | { | ||
66 | __u64 data_tail = header->data_tail; | ||
67 | __u64 data_head = header->data_head; | ||
68 | __u64 buffer_size = page_cnt * page_size; | ||
69 | void *base, *begin, *end; | ||
70 | char buf[256]; | ||
71 | |||
72 | asm volatile("" ::: "memory"); /* in real code it should be smp_rmb() */ | ||
73 | if (data_head == data_tail) | ||
74 | return; | ||
75 | |||
76 | base = ((char *)header) + page_size; | ||
77 | |||
78 | begin = base + data_tail % buffer_size; | ||
79 | end = base + data_head % buffer_size; | ||
80 | |||
81 | while (begin != end) { | ||
82 | struct perf_event_sample *e; | ||
83 | |||
84 | e = begin; | ||
85 | if (begin + e->header.size > base + buffer_size) { | ||
86 | long len = base + buffer_size - begin; | ||
87 | |||
88 | assert(len < e->header.size); | ||
89 | memcpy(buf, begin, len); | ||
90 | memcpy(buf + len, base, e->header.size - len); | ||
91 | e = (void *) buf; | ||
92 | begin = base + e->header.size - len; | ||
93 | } else if (begin + e->header.size == base + buffer_size) { | ||
94 | begin = base; | ||
95 | } else { | ||
96 | begin += e->header.size; | ||
97 | } | ||
98 | |||
99 | if (e->header.type == PERF_RECORD_SAMPLE) { | ||
100 | fn(e->data, e->size); | ||
101 | } else if (e->header.type == PERF_RECORD_LOST) { | ||
102 | struct { | ||
103 | struct perf_event_header header; | ||
104 | __u64 id; | ||
105 | __u64 lost; | ||
106 | } *lost = (void *) e; | ||
107 | printf("lost %lld events\n", lost->lost); | ||
108 | } else { | ||
109 | printf("unknown event type=%d size=%d\n", | ||
110 | e->header.type, e->header.size); | ||
111 | } | ||
112 | } | ||
113 | |||
114 | __sync_synchronize(); /* smp_mb() */ | ||
115 | header->data_tail = data_head; | ||
116 | } | ||
117 | |||
118 | static __u64 time_get_ns(void) | 28 | static __u64 time_get_ns(void) |
119 | { | 29 | { |
120 | struct timespec ts; | 30 | struct timespec ts; |
@@ -127,7 +37,7 @@ static __u64 start_time; | |||
127 | 37 | ||
128 | #define MAX_CNT 100000ll | 38 | #define MAX_CNT 100000ll |
129 | 39 | ||
130 | static void print_bpf_output(void *data, int size) | 40 | static int print_bpf_output(void *data, int size) |
131 | { | 41 | { |
132 | static __u64 cnt; | 42 | static __u64 cnt; |
133 | struct { | 43 | struct { |
@@ -138,7 +48,7 @@ static void print_bpf_output(void *data, int size) | |||
138 | if (e->cookie != 0x12345678) { | 48 | if (e->cookie != 0x12345678) { |
139 | printf("BUG pid %llx cookie %llx sized %d\n", | 49 | printf("BUG pid %llx cookie %llx sized %d\n", |
140 | e->pid, e->cookie, size); | 50 | e->pid, e->cookie, size); |
141 | kill(0, SIGINT); | 51 | return PERF_EVENT_ERROR; |
142 | } | 52 | } |
143 | 53 | ||
144 | cnt++; | 54 | cnt++; |
@@ -146,8 +56,10 @@ static void print_bpf_output(void *data, int size) | |||
146 | if (cnt == MAX_CNT) { | 56 | if (cnt == MAX_CNT) { |
147 | printf("recv %lld events per sec\n", | 57 | printf("recv %lld events per sec\n", |
148 | MAX_CNT * 1000000000ll / (time_get_ns() - start_time)); | 58 | MAX_CNT * 1000000000ll / (time_get_ns() - start_time)); |
149 | kill(0, SIGINT); | 59 | return PERF_EVENT_DONE; |
150 | } | 60 | } |
61 | |||
62 | return PERF_EVENT_CONT; | ||
151 | } | 63 | } |
152 | 64 | ||
153 | static void test_bpf_perf_event(void) | 65 | static void test_bpf_perf_event(void) |
@@ -170,6 +82,7 @@ int main(int argc, char **argv) | |||
170 | { | 82 | { |
171 | char filename[256]; | 83 | char filename[256]; |
172 | FILE *f; | 84 | FILE *f; |
85 | int ret; | ||
173 | 86 | ||
174 | snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); | 87 | snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); |
175 | 88 | ||
@@ -187,10 +100,7 @@ int main(int argc, char **argv) | |||
187 | (void) f; | 100 | (void) f; |
188 | 101 | ||
189 | start_time = time_get_ns(); | 102 | start_time = time_get_ns(); |
190 | for (;;) { | 103 | ret = perf_event_poller(pmu_fd, print_bpf_output); |
191 | perf_event_poll(pmu_fd); | 104 | kill(0, SIGINT); |
192 | perf_event_read(print_bpf_output); | 105 | return ret; |
193 | } | ||
194 | |||
195 | return 0; | ||
196 | } | 106 | } |