xref: /aosp_15_r20/external/bcc/src/cc/perf_reader.c (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
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