]>
git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blob - samples/bpf/trace_output_user.c
1 /* This program is free software; you can redistribute it and/or
2 * modify it under the terms of version 2 of the GNU General Public
3 * License as published by the Free Software Foundation.
12 #include <sys/ioctl.h>
13 #include <linux/perf_event.h>
14 #include <linux/bpf.h>
17 #include <sys/syscall.h>
18 #include <sys/ioctl.h>
30 volatile struct perf_event_mmap_page
*header
;
32 typedef void (*print_fn
)(void *data
, int size
);
34 static int perf_event_mmap(int fd
)
39 page_size
= getpagesize();
40 mmap_size
= page_size
* (page_cnt
+ 1);
42 base
= mmap(NULL
, mmap_size
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, fd
, 0);
43 if (base
== MAP_FAILED
) {
52 static int perf_event_poll(int fd
)
54 struct pollfd pfd
= { .fd
= fd
, .events
= POLLIN
};
56 return poll(&pfd
, 1, 1000);
59 struct perf_event_sample
{
60 struct perf_event_header header
;
65 static void perf_event_read(print_fn fn
)
67 __u64 data_tail
= header
->data_tail
;
68 __u64 data_head
= header
->data_head
;
69 __u64 buffer_size
= page_cnt
* page_size
;
70 void *base
, *begin
, *end
;
73 asm volatile("" ::: "memory"); /* in real code it should be smp_rmb() */
74 if (data_head
== data_tail
)
77 base
= ((char *)header
) + page_size
;
79 begin
= base
+ data_tail
% buffer_size
;
80 end
= base
+ data_head
% buffer_size
;
82 while (begin
!= end
) {
83 struct perf_event_sample
*e
;
86 if (begin
+ e
->header
.size
> base
+ buffer_size
) {
87 long len
= base
+ buffer_size
- begin
;
89 assert(len
< e
->header
.size
);
90 memcpy(buf
, begin
, len
);
91 memcpy(buf
+ len
, base
, e
->header
.size
- len
);
93 begin
= base
+ e
->header
.size
- len
;
94 } else if (begin
+ e
->header
.size
== base
+ buffer_size
) {
97 begin
+= e
->header
.size
;
100 if (e
->header
.type
== PERF_RECORD_SAMPLE
) {
101 fn(e
->data
, e
->size
);
102 } else if (e
->header
.type
== PERF_RECORD_LOST
) {
104 struct perf_event_header header
;
107 } *lost
= (void *) e
;
108 printf("lost %lld events\n", lost
->lost
);
110 printf("unknown event type=%d size=%d\n",
111 e
->header
.type
, e
->header
.size
);
115 __sync_synchronize(); /* smp_mb() */
116 header
->data_tail
= data_head
;
119 static __u64
time_get_ns(void)
123 clock_gettime(CLOCK_MONOTONIC
, &ts
);
124 return ts
.tv_sec
* 1000000000ull + ts
.tv_nsec
;
127 static __u64 start_time
;
129 #define MAX_CNT 100000ll
131 static void print_bpf_output(void *data
, int size
)
139 if (e
->cookie
!= 0x12345678) {
140 printf("BUG pid %llx cookie %llx sized %d\n",
141 e
->pid
, e
->cookie
, size
);
147 if (cnt
== MAX_CNT
) {
148 printf("recv %lld events per sec\n",
149 MAX_CNT
* 1000000000ll / (time_get_ns() - start_time
));
154 static void test_bpf_perf_event(void)
156 struct perf_event_attr attr
= {
157 .sample_type
= PERF_SAMPLE_RAW
,
158 .type
= PERF_TYPE_SOFTWARE
,
159 .config
= PERF_COUNT_SW_BPF_OUTPUT
,
163 pmu_fd
= sys_perf_event_open(&attr
, -1/*pid*/, 0/*cpu*/, -1/*group_fd*/, 0);
166 assert(bpf_map_update_elem(map_fd
[0], &key
, &pmu_fd
, BPF_ANY
) == 0);
167 ioctl(pmu_fd
, PERF_EVENT_IOC_ENABLE
, 0);
170 int main(int argc
, char **argv
)
175 snprintf(filename
, sizeof(filename
), "%s_kern.o", argv
[0]);
177 if (load_bpf_file(filename
)) {
178 printf("%s", bpf_log_buf
);
182 test_bpf_perf_event();
184 if (perf_event_mmap(pmu_fd
) < 0)
187 f
= popen("taskset 1 dd if=/dev/zero of=/dev/null", "r");
190 start_time
= time_get_ns();
192 perf_event_poll(pmu_fd
);
193 perf_event_read(print_bpf_output
);