1*387f9dfdSAndroid Build Coastguard Worker /*
2*387f9dfdSAndroid Build Coastguard Worker * Copyright (c) 2015 PLUMgrid, Inc.
3*387f9dfdSAndroid Build Coastguard Worker *
4*387f9dfdSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*387f9dfdSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*387f9dfdSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*387f9dfdSAndroid Build Coastguard Worker *
8*387f9dfdSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*387f9dfdSAndroid Build Coastguard Worker *
10*387f9dfdSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*387f9dfdSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*387f9dfdSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*387f9dfdSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*387f9dfdSAndroid Build Coastguard Worker * limitations under the License.
15*387f9dfdSAndroid Build Coastguard Worker */
16*387f9dfdSAndroid Build Coastguard Worker
17*387f9dfdSAndroid Build Coastguard Worker #include <inttypes.h>
18*387f9dfdSAndroid Build Coastguard Worker #include <poll.h>
19*387f9dfdSAndroid Build Coastguard Worker #include <stdio.h>
20*387f9dfdSAndroid Build Coastguard Worker #include <stdint.h>
21*387f9dfdSAndroid Build Coastguard Worker #include <stdlib.h>
22*387f9dfdSAndroid Build Coastguard Worker #include <string.h>
23*387f9dfdSAndroid Build Coastguard Worker #include <syscall.h>
24*387f9dfdSAndroid Build Coastguard Worker #include <sys/ioctl.h>
25*387f9dfdSAndroid Build Coastguard Worker #include <sys/mman.h>
26*387f9dfdSAndroid Build Coastguard Worker #include <sys/types.h>
27*387f9dfdSAndroid Build Coastguard Worker #include <unistd.h>
28*387f9dfdSAndroid Build Coastguard Worker #include <linux/types.h>
29*387f9dfdSAndroid Build Coastguard Worker #include <linux/perf_event.h>
30*387f9dfdSAndroid Build Coastguard Worker
31*387f9dfdSAndroid Build Coastguard Worker #include "libbpf.h"
32*387f9dfdSAndroid Build Coastguard Worker #include "perf_reader.h"
33*387f9dfdSAndroid Build Coastguard Worker
34*387f9dfdSAndroid Build Coastguard Worker enum {
35*387f9dfdSAndroid Build Coastguard Worker RB_NOT_USED = 0, // ring buffer not usd
36*387f9dfdSAndroid Build Coastguard Worker RB_USED_IN_MUNMAP = 1, // used in munmap
37*387f9dfdSAndroid Build Coastguard Worker RB_USED_IN_READ = 2, // used in read
38*387f9dfdSAndroid Build Coastguard Worker };
39*387f9dfdSAndroid Build Coastguard Worker
40*387f9dfdSAndroid Build Coastguard Worker struct perf_reader {
41*387f9dfdSAndroid Build Coastguard Worker perf_reader_raw_cb raw_cb;
42*387f9dfdSAndroid Build Coastguard Worker perf_reader_lost_cb lost_cb;
43*387f9dfdSAndroid Build Coastguard Worker void *cb_cookie; // to be returned in the cb
44*387f9dfdSAndroid Build Coastguard Worker void *buf; // for keeping segmented data
45*387f9dfdSAndroid Build Coastguard Worker size_t buf_size;
46*387f9dfdSAndroid Build Coastguard Worker void *base;
47*387f9dfdSAndroid Build Coastguard Worker int rb_use_state;
48*387f9dfdSAndroid Build Coastguard Worker pid_t rb_read_tid;
49*387f9dfdSAndroid Build Coastguard Worker int page_size;
50*387f9dfdSAndroid Build Coastguard Worker int page_cnt;
51*387f9dfdSAndroid Build Coastguard Worker int fd;
52*387f9dfdSAndroid Build Coastguard Worker };
53*387f9dfdSAndroid Build Coastguard Worker
perf_reader_new(perf_reader_raw_cb raw_cb,perf_reader_lost_cb lost_cb,void * cb_cookie,int page_cnt)54*387f9dfdSAndroid Build Coastguard Worker struct perf_reader * perf_reader_new(perf_reader_raw_cb raw_cb,
55*387f9dfdSAndroid Build Coastguard Worker perf_reader_lost_cb lost_cb,
56*387f9dfdSAndroid Build Coastguard Worker void *cb_cookie, int page_cnt) {
57*387f9dfdSAndroid Build Coastguard Worker struct perf_reader *reader = calloc(1, sizeof(struct perf_reader));
58*387f9dfdSAndroid Build Coastguard Worker if (!reader)
59*387f9dfdSAndroid Build Coastguard Worker return NULL;
60*387f9dfdSAndroid Build Coastguard Worker reader->raw_cb = raw_cb;
61*387f9dfdSAndroid Build Coastguard Worker reader->lost_cb = lost_cb;
62*387f9dfdSAndroid Build Coastguard Worker reader->cb_cookie = cb_cookie;
63*387f9dfdSAndroid Build Coastguard Worker reader->fd = -1;
64*387f9dfdSAndroid Build Coastguard Worker reader->page_size = getpagesize();
65*387f9dfdSAndroid Build Coastguard Worker reader->page_cnt = page_cnt;
66*387f9dfdSAndroid Build Coastguard Worker return reader;
67*387f9dfdSAndroid Build Coastguard Worker }
68*387f9dfdSAndroid Build Coastguard Worker
perf_reader_free(void * ptr)69*387f9dfdSAndroid Build Coastguard Worker void perf_reader_free(void *ptr) {
70*387f9dfdSAndroid Build Coastguard Worker if (ptr) {
71*387f9dfdSAndroid Build Coastguard Worker struct perf_reader *reader = ptr;
72*387f9dfdSAndroid Build Coastguard Worker pid_t tid = syscall(__NR_gettid);
73*387f9dfdSAndroid Build Coastguard Worker while (!__sync_bool_compare_and_swap(&reader->rb_use_state, RB_NOT_USED, RB_USED_IN_MUNMAP)) {
74*387f9dfdSAndroid Build Coastguard Worker // If the same thread, it is called from call back handler, no locking needed
75*387f9dfdSAndroid Build Coastguard Worker if (tid == reader->rb_read_tid)
76*387f9dfdSAndroid Build Coastguard Worker break;
77*387f9dfdSAndroid Build Coastguard Worker }
78*387f9dfdSAndroid Build Coastguard Worker munmap(reader->base, reader->page_size * (reader->page_cnt + 1));
79*387f9dfdSAndroid Build Coastguard Worker if (reader->fd >= 0) {
80*387f9dfdSAndroid Build Coastguard Worker ioctl(reader->fd, PERF_EVENT_IOC_DISABLE, 0);
81*387f9dfdSAndroid Build Coastguard Worker close(reader->fd);
82*387f9dfdSAndroid Build Coastguard Worker }
83*387f9dfdSAndroid Build Coastguard Worker free(reader->buf);
84*387f9dfdSAndroid Build Coastguard Worker free(ptr);
85*387f9dfdSAndroid Build Coastguard Worker }
86*387f9dfdSAndroid Build Coastguard Worker }
87*387f9dfdSAndroid Build Coastguard Worker
perf_reader_mmap(struct perf_reader * reader)88*387f9dfdSAndroid Build Coastguard Worker int perf_reader_mmap(struct perf_reader *reader) {
89*387f9dfdSAndroid Build Coastguard Worker int mmap_size = reader->page_size * (reader->page_cnt + 1);
90*387f9dfdSAndroid Build Coastguard Worker
91*387f9dfdSAndroid Build Coastguard Worker if (reader->fd < 0) {
92*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "%s: reader fd is not set\n", __FUNCTION__);
93*387f9dfdSAndroid Build Coastguard Worker return -1;
94*387f9dfdSAndroid Build Coastguard Worker }
95*387f9dfdSAndroid Build Coastguard Worker
96*387f9dfdSAndroid Build Coastguard Worker reader->base = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, reader->fd, 0);
97*387f9dfdSAndroid Build Coastguard Worker if (reader->base == MAP_FAILED) {
98*387f9dfdSAndroid Build Coastguard Worker perror("mmap");
99*387f9dfdSAndroid Build Coastguard Worker return -1;
100*387f9dfdSAndroid Build Coastguard Worker }
101*387f9dfdSAndroid Build Coastguard Worker
102*387f9dfdSAndroid Build Coastguard Worker return 0;
103*387f9dfdSAndroid Build Coastguard Worker }
104*387f9dfdSAndroid Build Coastguard Worker
105*387f9dfdSAndroid Build Coastguard Worker struct perf_sample_trace_common {
106*387f9dfdSAndroid Build Coastguard Worker uint16_t id;
107*387f9dfdSAndroid Build Coastguard Worker uint8_t flags;
108*387f9dfdSAndroid Build Coastguard Worker uint8_t preempt_count;
109*387f9dfdSAndroid Build Coastguard Worker int pid;
110*387f9dfdSAndroid Build Coastguard Worker };
111*387f9dfdSAndroid Build Coastguard Worker
112*387f9dfdSAndroid Build Coastguard Worker struct perf_sample_trace_kprobe {
113*387f9dfdSAndroid Build Coastguard Worker struct perf_sample_trace_common common;
114*387f9dfdSAndroid Build Coastguard Worker uint64_t ip;
115*387f9dfdSAndroid Build Coastguard Worker };
116*387f9dfdSAndroid Build Coastguard Worker
parse_sw(struct perf_reader * reader,void * data,int size)117*387f9dfdSAndroid Build Coastguard Worker static void parse_sw(struct perf_reader *reader, void *data, int size) {
118*387f9dfdSAndroid Build Coastguard Worker uint8_t *ptr = data;
119*387f9dfdSAndroid Build Coastguard Worker struct perf_event_header *header = (void *)data;
120*387f9dfdSAndroid Build Coastguard Worker
121*387f9dfdSAndroid Build Coastguard Worker struct {
122*387f9dfdSAndroid Build Coastguard Worker uint32_t size;
123*387f9dfdSAndroid Build Coastguard Worker char data[0];
124*387f9dfdSAndroid Build Coastguard Worker } *raw = NULL;
125*387f9dfdSAndroid Build Coastguard Worker
126*387f9dfdSAndroid Build Coastguard Worker ptr += sizeof(*header);
127*387f9dfdSAndroid Build Coastguard Worker if (ptr > (uint8_t *)data + size) {
128*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "%s: corrupt sample header\n", __FUNCTION__);
129*387f9dfdSAndroid Build Coastguard Worker return;
130*387f9dfdSAndroid Build Coastguard Worker }
131*387f9dfdSAndroid Build Coastguard Worker
132*387f9dfdSAndroid Build Coastguard Worker raw = (void *)ptr;
133*387f9dfdSAndroid Build Coastguard Worker ptr += sizeof(raw->size) + raw->size;
134*387f9dfdSAndroid Build Coastguard Worker if (ptr > (uint8_t *)data + size) {
135*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "%s: corrupt raw sample\n", __FUNCTION__);
136*387f9dfdSAndroid Build Coastguard Worker return;
137*387f9dfdSAndroid Build Coastguard Worker }
138*387f9dfdSAndroid Build Coastguard Worker
139*387f9dfdSAndroid Build Coastguard Worker // sanity check
140*387f9dfdSAndroid Build Coastguard Worker if (ptr != (uint8_t *)data + size) {
141*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "%s: extra data at end of sample\n", __FUNCTION__);
142*387f9dfdSAndroid Build Coastguard Worker return;
143*387f9dfdSAndroid Build Coastguard Worker }
144*387f9dfdSAndroid Build Coastguard Worker
145*387f9dfdSAndroid Build Coastguard Worker if (reader->raw_cb)
146*387f9dfdSAndroid Build Coastguard Worker reader->raw_cb(reader->cb_cookie, raw->data, raw->size);
147*387f9dfdSAndroid Build Coastguard Worker }
148*387f9dfdSAndroid Build Coastguard Worker
read_data_head(volatile struct perf_event_mmap_page * perf_header)149*387f9dfdSAndroid Build Coastguard Worker static uint64_t read_data_head(volatile struct perf_event_mmap_page *perf_header) {
150*387f9dfdSAndroid Build Coastguard Worker uint64_t data_head = perf_header->data_head;
151*387f9dfdSAndroid Build Coastguard Worker asm volatile("" ::: "memory");
152*387f9dfdSAndroid Build Coastguard Worker return data_head;
153*387f9dfdSAndroid Build Coastguard Worker }
154*387f9dfdSAndroid Build Coastguard Worker
write_data_tail(volatile struct perf_event_mmap_page * perf_header,uint64_t data_tail)155*387f9dfdSAndroid Build Coastguard Worker static void write_data_tail(volatile struct perf_event_mmap_page *perf_header, uint64_t data_tail) {
156*387f9dfdSAndroid Build Coastguard Worker asm volatile("" ::: "memory");
157*387f9dfdSAndroid Build Coastguard Worker perf_header->data_tail = data_tail;
158*387f9dfdSAndroid Build Coastguard Worker }
159*387f9dfdSAndroid Build Coastguard Worker
perf_reader_event_read(struct perf_reader * reader)160*387f9dfdSAndroid Build Coastguard Worker void perf_reader_event_read(struct perf_reader *reader) {
161*387f9dfdSAndroid Build Coastguard Worker volatile struct perf_event_mmap_page *perf_header = reader->base;
162*387f9dfdSAndroid Build Coastguard Worker uint64_t buffer_size = (uint64_t)reader->page_size * reader->page_cnt;
163*387f9dfdSAndroid Build Coastguard Worker uint64_t data_head;
164*387f9dfdSAndroid Build Coastguard Worker uint8_t *base = (uint8_t *)reader->base + reader->page_size;
165*387f9dfdSAndroid Build Coastguard Worker uint8_t *sentinel = (uint8_t *)reader->base + buffer_size + reader->page_size;
166*387f9dfdSAndroid Build Coastguard Worker uint8_t *begin, *end;
167*387f9dfdSAndroid Build Coastguard Worker
168*387f9dfdSAndroid Build Coastguard Worker reader->rb_read_tid = syscall(__NR_gettid);
169*387f9dfdSAndroid Build Coastguard Worker if (!__sync_bool_compare_and_swap(&reader->rb_use_state, RB_NOT_USED, RB_USED_IN_READ))
170*387f9dfdSAndroid Build Coastguard Worker return;
171*387f9dfdSAndroid Build Coastguard Worker
172*387f9dfdSAndroid Build Coastguard Worker // Consume all the events on this ring, calling the cb function for each one.
173*387f9dfdSAndroid Build Coastguard Worker // The message may fall on the ring boundary, in which case copy the message
174*387f9dfdSAndroid Build Coastguard Worker // into a malloced buffer.
175*387f9dfdSAndroid Build Coastguard Worker for (data_head = read_data_head(perf_header); perf_header->data_tail != data_head;
176*387f9dfdSAndroid Build Coastguard Worker data_head = read_data_head(perf_header)) {
177*387f9dfdSAndroid Build Coastguard Worker uint64_t data_tail = perf_header->data_tail;
178*387f9dfdSAndroid Build Coastguard Worker uint8_t *ptr;
179*387f9dfdSAndroid Build Coastguard Worker
180*387f9dfdSAndroid Build Coastguard Worker begin = base + data_tail % buffer_size;
181*387f9dfdSAndroid Build Coastguard Worker // event header is u64, won't wrap
182*387f9dfdSAndroid Build Coastguard Worker struct perf_event_header *e = (void *)begin;
183*387f9dfdSAndroid Build Coastguard Worker ptr = begin;
184*387f9dfdSAndroid Build Coastguard Worker end = base + (data_tail + e->size) % buffer_size;
185*387f9dfdSAndroid Build Coastguard Worker if (end < begin) {
186*387f9dfdSAndroid Build Coastguard Worker // perf event wraps around the ring, make a contiguous copy
187*387f9dfdSAndroid Build Coastguard Worker reader->buf = realloc(reader->buf, e->size);
188*387f9dfdSAndroid Build Coastguard Worker size_t len = sentinel - begin;
189*387f9dfdSAndroid Build Coastguard Worker memcpy(reader->buf, begin, len);
190*387f9dfdSAndroid Build Coastguard Worker memcpy((void *)((unsigned long)reader->buf + len), base, e->size - len);
191*387f9dfdSAndroid Build Coastguard Worker ptr = reader->buf;
192*387f9dfdSAndroid Build Coastguard Worker }
193*387f9dfdSAndroid Build Coastguard Worker
194*387f9dfdSAndroid Build Coastguard Worker if (e->type == PERF_RECORD_LOST) {
195*387f9dfdSAndroid Build Coastguard Worker /*
196*387f9dfdSAndroid Build Coastguard Worker * struct {
197*387f9dfdSAndroid Build Coastguard Worker * struct perf_event_header header;
198*387f9dfdSAndroid Build Coastguard Worker * u64 id;
199*387f9dfdSAndroid Build Coastguard Worker * u64 lost;
200*387f9dfdSAndroid Build Coastguard Worker * struct sample_id sample_id;
201*387f9dfdSAndroid Build Coastguard Worker * };
202*387f9dfdSAndroid Build Coastguard Worker */
203*387f9dfdSAndroid Build Coastguard Worker uint64_t lost = *(uint64_t *)(ptr + sizeof(*e) + sizeof(uint64_t));
204*387f9dfdSAndroid Build Coastguard Worker if (reader->lost_cb) {
205*387f9dfdSAndroid Build Coastguard Worker reader->lost_cb(reader->cb_cookie, lost);
206*387f9dfdSAndroid Build Coastguard Worker } else {
207*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "Possibly lost %" PRIu64 " samples\n", lost);
208*387f9dfdSAndroid Build Coastguard Worker }
209*387f9dfdSAndroid Build Coastguard Worker } else if (e->type == PERF_RECORD_SAMPLE) {
210*387f9dfdSAndroid Build Coastguard Worker parse_sw(reader, ptr, e->size);
211*387f9dfdSAndroid Build Coastguard Worker } else {
212*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "%s: unknown sample type %d\n", __FUNCTION__, e->type);
213*387f9dfdSAndroid Build Coastguard Worker }
214*387f9dfdSAndroid Build Coastguard Worker
215*387f9dfdSAndroid Build Coastguard Worker write_data_tail(perf_header, perf_header->data_tail + e->size);
216*387f9dfdSAndroid Build Coastguard Worker }
217*387f9dfdSAndroid Build Coastguard Worker reader->rb_use_state = RB_NOT_USED;
218*387f9dfdSAndroid Build Coastguard Worker __sync_synchronize();
219*387f9dfdSAndroid Build Coastguard Worker reader->rb_read_tid = 0;
220*387f9dfdSAndroid Build Coastguard Worker }
221*387f9dfdSAndroid Build Coastguard Worker
perf_reader_poll(int num_readers,struct perf_reader ** readers,int timeout)222*387f9dfdSAndroid Build Coastguard Worker int perf_reader_poll(int num_readers, struct perf_reader **readers, int timeout) {
223*387f9dfdSAndroid Build Coastguard Worker struct pollfd pfds[num_readers];
224*387f9dfdSAndroid Build Coastguard Worker int i;
225*387f9dfdSAndroid Build Coastguard Worker
226*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i <num_readers; ++i) {
227*387f9dfdSAndroid Build Coastguard Worker pfds[i].fd = readers[i]->fd;
228*387f9dfdSAndroid Build Coastguard Worker pfds[i].events = POLLIN;
229*387f9dfdSAndroid Build Coastguard Worker }
230*387f9dfdSAndroid Build Coastguard Worker
231*387f9dfdSAndroid Build Coastguard Worker if (poll(pfds, num_readers, timeout) > 0) {
232*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < num_readers; ++i) {
233*387f9dfdSAndroid Build Coastguard Worker if (pfds[i].revents & POLLIN)
234*387f9dfdSAndroid Build Coastguard Worker perf_reader_event_read(readers[i]);
235*387f9dfdSAndroid Build Coastguard Worker }
236*387f9dfdSAndroid Build Coastguard Worker }
237*387f9dfdSAndroid Build Coastguard Worker return 0;
238*387f9dfdSAndroid Build Coastguard Worker }
239*387f9dfdSAndroid Build Coastguard Worker
perf_reader_consume(int num_readers,struct perf_reader ** readers)240*387f9dfdSAndroid Build Coastguard Worker int perf_reader_consume(int num_readers, struct perf_reader **readers) {
241*387f9dfdSAndroid Build Coastguard Worker int i;
242*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < num_readers; ++i) {
243*387f9dfdSAndroid Build Coastguard Worker perf_reader_event_read(readers[i]);
244*387f9dfdSAndroid Build Coastguard Worker }
245*387f9dfdSAndroid Build Coastguard Worker return 0;
246*387f9dfdSAndroid Build Coastguard Worker }
247*387f9dfdSAndroid Build Coastguard Worker
perf_reader_set_fd(struct perf_reader * reader,int fd)248*387f9dfdSAndroid Build Coastguard Worker void perf_reader_set_fd(struct perf_reader *reader, int fd) {
249*387f9dfdSAndroid Build Coastguard Worker reader->fd = fd;
250*387f9dfdSAndroid Build Coastguard Worker }
251*387f9dfdSAndroid Build Coastguard Worker
perf_reader_fd(struct perf_reader * reader)252*387f9dfdSAndroid Build Coastguard Worker int perf_reader_fd(struct perf_reader *reader) {
253*387f9dfdSAndroid Build Coastguard Worker return reader->fd;
254*387f9dfdSAndroid Build Coastguard Worker }
255