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 | } |
