1*9b8b2884SDavid Wang #include <stdlib.h>
2*9b8b2884SDavid Wang #include <stdio.h>
3*9b8b2884SDavid Wang #include <unistd.h>
4*9b8b2884SDavid Wang #include <string.h>
5*9b8b2884SDavid Wang #include <sys/ioctl.h>
6*9b8b2884SDavid Wang #include <linux/perf_event.h>
7*9b8b2884SDavid Wang #include <asm/unistd.h>
8*9b8b2884SDavid Wang #include <sys/mman.h>
9*9b8b2884SDavid Wang #include <sys/stat.h>
10*9b8b2884SDavid Wang #include <poll.h>
11*9b8b2884SDavid Wang #include <signal.h>
12*9b8b2884SDavid Wang #include <fcntl.h>
13*9b8b2884SDavid Wang #include <elf.h>
14*9b8b2884SDavid Wang #include <string.h>
15*9b8b2884SDavid Wang
16*9b8b2884SDavid Wang #include <vector>
17*9b8b2884SDavid Wang #include <string>
18*9b8b2884SDavid Wang #include <map>
19*9b8b2884SDavid Wang #include <unordered_map>
20*9b8b2884SDavid Wang #include <algorithm>
21*9b8b2884SDavid Wang using namespace std;
22*9b8b2884SDavid Wang
23*9b8b2884SDavid Wang
24*9b8b2884SDavid Wang #define MAXN 128
25*9b8b2884SDavid Wang #define MAXCPU 1024
26*9b8b2884SDavid Wang #define error(msg) do { perror(msg); exit(1); } while(0)
27*9b8b2884SDavid Wang //--------------------------------Tree for call chain and report-------------------------------
28*9b8b2884SDavid Wang //
29*9b8b2884SDavid Wang struct TNode {
30*9b8b2884SDavid Wang int c=0;
31*9b8b2884SDavid Wang unordered_map<string, TNode*> s;
addTNode32*9b8b2884SDavid Wang struct TNode *add(string n) {
33*9b8b2884SDavid Wang c++;
34*9b8b2884SDavid Wang if (s[n]==nullptr) s[n] = new TNode();
35*9b8b2884SDavid Wang return s[n];
36*9b8b2884SDavid Wang }
printitTNode37*9b8b2884SDavid Wang int printit(FILE *fp, int k) {
38*9b8b2884SDavid Wang if (s.size()) {
39*9b8b2884SDavid Wang using tt = tuple<int, string, TNode*>;
40*9b8b2884SDavid Wang vector<tt> xx;
41*9b8b2884SDavid Wang for (auto x: s) xx.push_back(make_tuple(x.second->c, x.first, x.second));
42*9b8b2884SDavid Wang sort(begin(xx), end(xx), greater<tt>());
43*9b8b2884SDavid Wang for (auto x: xx) {
44*9b8b2884SDavid Wang auto count = get<0>(x);
45*9b8b2884SDavid Wang if (100.0*count/c<1) continue;
46*9b8b2884SDavid Wang auto name = get<1>(x);
47*9b8b2884SDavid Wang auto nx = get<2>(x);
48*9b8b2884SDavid Wang fprintf(fp, "<li>\n");
49*9b8b2884SDavid Wang fprintf(fp, "<input type=\"checkbox\" id=\"c%d\" />\n", k);
50*9b8b2884SDavid Wang fprintf(fp, "<label class=\"tree_label\" for=\"c%d\">%s(%.3f%% %d/%d)</label>\n", k, name.c_str(), 100.0*count/c, count, c);
51*9b8b2884SDavid Wang fprintf(fp, "<ul>\n");
52*9b8b2884SDavid Wang // printf("%s(%.3f%% %d/%d)\n", name.c_str(), 100.0*count/c, count, c);
53*9b8b2884SDavid Wang k = nx->printit(fp, k+1);
54*9b8b2884SDavid Wang fprintf(fp, "</ul>\n");
55*9b8b2884SDavid Wang fprintf(fp, "</li>\n");
56*9b8b2884SDavid Wang }
57*9b8b2884SDavid Wang }
58*9b8b2884SDavid Wang return k;
59*9b8b2884SDavid Wang }
60*9b8b2884SDavid Wang };
61*9b8b2884SDavid Wang
62*9b8b2884SDavid Wang //--------------------------------symbols-------------------------------------------
63*9b8b2884SDavid Wang using STORE_T = map<unsigned long long, pair<string, unsigned long long>>;
64*9b8b2884SDavid Wang using K_STORE_T = map<unsigned long long, string>;
65*9b8b2884SDavid Wang
66*9b8b2884SDavid Wang /*
67*9b8b2884SDavid Wang * load FUNC symbols refering to the section indicated by the offset, relocate the virtual address
68*9b8b2884SDavid Wang */
parse_elf64(FILE * fp,unsigned long long v_addr,unsigned long long v_size,unsigned long long v_offset,STORE_T & store)69*9b8b2884SDavid Wang void parse_elf64(FILE *fp, unsigned long long v_addr, unsigned long long v_size, unsigned long long v_offset, STORE_T& store) {
70*9b8b2884SDavid Wang // printf("read elf with offset 0x%llx, addr 0x%llx\n", v_offset, v_addr);
71*9b8b2884SDavid Wang Elf64_Ehdr ehdr;
72*9b8b2884SDavid Wang int rc = fread(&ehdr, sizeof(ehdr), 1, fp);
73*9b8b2884SDavid Wang if (rc != 1) return;
74*9b8b2884SDavid Wang int n, s, i;
75*9b8b2884SDavid Wang unsigned long long offset;
76*9b8b2884SDavid Wang
77*9b8b2884SDavid Wang // load program headers
78*9b8b2884SDavid Wang unsigned long long p_vaddr, p_size;
79*9b8b2884SDavid Wang n = ehdr.e_phnum;
80*9b8b2884SDavid Wang s = ehdr.e_phentsize;
81*9b8b2884SDavid Wang offset = ehdr.e_phoff;
82*9b8b2884SDavid Wang Elf64_Phdr phdr;
83*9b8b2884SDavid Wang for (i=0; i<n; i++) {
84*9b8b2884SDavid Wang rc = fseek(fp, offset, SEEK_SET);
85*9b8b2884SDavid Wang if (rc<0) { perror("fail to seek"); return; }
86*9b8b2884SDavid Wang rc = fread(&phdr, sizeof(phdr), 1, fp);
87*9b8b2884SDavid Wang if (rc != 1) { perror("fail to read program header"); return; }
88*9b8b2884SDavid Wang if (phdr.p_flags&PF_X) {
89*9b8b2884SDavid Wang if (phdr.p_offset == v_offset) {
90*9b8b2884SDavid Wang p_vaddr = phdr.p_vaddr;
91*9b8b2884SDavid Wang p_size = phdr.p_memsz; if (p_size==0) p_size = 0xffffffff;
92*9b8b2884SDavid Wang break;
93*9b8b2884SDavid Wang }
94*9b8b2884SDavid Wang }
95*9b8b2884SDavid Wang offset+=s;
96*9b8b2884SDavid Wang }
97*9b8b2884SDavid Wang if (i>=n) { printf("No program header match offset found, fail to load\n"); return; }
98*9b8b2884SDavid Wang
99*9b8b2884SDavid Wang // load section headers
100*9b8b2884SDavid Wang n = ehdr.e_shnum;
101*9b8b2884SDavid Wang s = ehdr.e_shentsize;
102*9b8b2884SDavid Wang offset = ehdr.e_shoff;
103*9b8b2884SDavid Wang Elf64_Shdr shdr;
104*9b8b2884SDavid Wang vector<Elf64_Shdr> headers;
105*9b8b2884SDavid Wang for (int i=0; i<n; i++) {
106*9b8b2884SDavid Wang rc = fseek(fp, offset, SEEK_SET);
107*9b8b2884SDavid Wang if (rc<0) { perror("fail to seek"); return; }
108*9b8b2884SDavid Wang rc = fread(&shdr, sizeof(shdr), 1, fp);
109*9b8b2884SDavid Wang if (rc != 1) { perror("fail to read sec header"); return; }
110*9b8b2884SDavid Wang headers.push_back(shdr);
111*9b8b2884SDavid Wang offset+=s;
112*9b8b2884SDavid Wang }
113*9b8b2884SDavid Wang Elf64_Sym symb;
114*9b8b2884SDavid Wang unsigned long long faddr, fsize;
115*9b8b2884SDavid Wang unsigned long long size, item_size;
116*9b8b2884SDavid Wang int link, ix, flink, k;
117*9b8b2884SDavid Wang char fname[128];
118*9b8b2884SDavid Wang for (int i=0; i<n; i++) {
119*9b8b2884SDavid Wang switch(headers[i].sh_type) {
120*9b8b2884SDavid Wang case SHT_SYMTAB:
121*9b8b2884SDavid Wang case SHT_DYNSYM:
122*9b8b2884SDavid Wang offset = headers[i].sh_offset;
123*9b8b2884SDavid Wang size = headers[i].sh_size;
124*9b8b2884SDavid Wang item_size = headers[i].sh_entsize;
125*9b8b2884SDavid Wang link = headers[i].sh_link;
126*9b8b2884SDavid Wang if (link<=0) break;
127*9b8b2884SDavid Wang for (k=0; k+item_size<=size; k+=item_size) {
128*9b8b2884SDavid Wang rc = fseek(fp, offset+k, SEEK_SET); if (rc<0) continue;
129*9b8b2884SDavid Wang rc = fread(&symb, sizeof(symb), 1, fp); if (rc != 1) continue;
130*9b8b2884SDavid Wang if (ELF64_ST_TYPE(symb.st_info) != STT_FUNC ) continue;
131*9b8b2884SDavid Wang flink = symb.st_shndx; if (flink==0) continue;
132*9b8b2884SDavid Wang fsize = symb.st_size; if (fsize==0) continue;
133*9b8b2884SDavid Wang faddr = symb.st_value; if (faddr>p_vaddr+p_size) continue;
134*9b8b2884SDavid Wang ix = symb.st_name; if (ix==0) continue;
135*9b8b2884SDavid Wang rc = fseek(fp, headers[link].sh_offset+ix, SEEK_SET); if (rc<0) continue;
136*9b8b2884SDavid Wang if (fgets(fname, sizeof(fname), fp)==NULL) continue;
137*9b8b2884SDavid Wang faddr = faddr-p_vaddr+v_addr;
138*9b8b2884SDavid Wang store[faddr] = make_pair(string(fname), fsize);
139*9b8b2884SDavid Wang }
140*9b8b2884SDavid Wang break;
141*9b8b2884SDavid Wang default:
142*9b8b2884SDavid Wang break;
143*9b8b2884SDavid Wang }
144*9b8b2884SDavid Wang }
145*9b8b2884SDavid Wang }
146*9b8b2884SDavid Wang
load_symbol_from_file(const char * path,unsigned long long addr,unsigned long long size,unsigned long long offset,STORE_T & store)147*9b8b2884SDavid Wang int load_symbol_from_file(const char *path, unsigned long long addr, unsigned long long size, unsigned long long offset, STORE_T& store) {
148*9b8b2884SDavid Wang printf("loading symble from %s\n", path);
149*9b8b2884SDavid Wang FILE *fp = fopen(path, "rb");
150*9b8b2884SDavid Wang if (fp==NULL) { perror("fail to open file"); return -1; }
151*9b8b2884SDavid Wang char ident[EI_NIDENT], c;
152*9b8b2884SDavid Wang int err=0;
153*9b8b2884SDavid Wang int rc = fread(ident, sizeof(ident), 1, fp);
154*9b8b2884SDavid Wang if (rc != 1) { perror("fail to read ident"); err=-1; goto end; }
155*9b8b2884SDavid Wang if (ident[0]!=0x7f) { printf("not a elf file\n"); err=-1; goto end; }
156*9b8b2884SDavid Wang c=ident[4];
157*9b8b2884SDavid Wang rc = fseek(fp, 0, SEEK_SET); if (rc<0) { perror("fail to rewind"); goto end; }
158*9b8b2884SDavid Wang if (c == ELFCLASS32) {
159*9b8b2884SDavid Wang printf("32bit elf not supported yet\n"); err=-2; goto end;
160*9b8b2884SDavid Wang } else if (c == ELFCLASS64) {
161*9b8b2884SDavid Wang parse_elf64(fp, addr, size, offset, store);
162*9b8b2884SDavid Wang }
163*9b8b2884SDavid Wang
164*9b8b2884SDavid Wang end:
165*9b8b2884SDavid Wang fclose(fp);
166*9b8b2884SDavid Wang return err;
167*9b8b2884SDavid Wang }
168*9b8b2884SDavid Wang
parse_hex(char * p,int * n)169*9b8b2884SDavid Wang static unsigned long long parse_hex(char *p, int *n) {
170*9b8b2884SDavid Wang unsigned long long r=0;
171*9b8b2884SDavid Wang int i=0;
172*9b8b2884SDavid Wang *n = 0;
173*9b8b2884SDavid Wang while(p[i]==' '||p[i]=='\t') i++;
174*9b8b2884SDavid Wang if (p[i]==0) return 0;
175*9b8b2884SDavid Wang if (p[i+1]=='x') i+=2;
176*9b8b2884SDavid Wang int v;
177*9b8b2884SDavid Wang while(p[i]) {
178*9b8b2884SDavid Wang if (p[i]>='0'&&p[i]<='9') v=p[i]-'0';
179*9b8b2884SDavid Wang else if (p[i]>='a'&&p[i]<='f') v=10+p[i]-'a';
180*9b8b2884SDavid Wang else if (p[i]>='A'&&p[i]<='F') v=10+p[i]-'A';
181*9b8b2884SDavid Wang else break;
182*9b8b2884SDavid Wang r=(r<<4)+v;
183*9b8b2884SDavid Wang i++;
184*9b8b2884SDavid Wang }
185*9b8b2884SDavid Wang *n = i;
186*9b8b2884SDavid Wang return r;
187*9b8b2884SDavid Wang }
188*9b8b2884SDavid Wang
load_symbol_pid(int pid)189*9b8b2884SDavid Wang STORE_T* load_symbol_pid(int pid) {
190*9b8b2884SDavid Wang printf("loading symbols for %d\n", pid);
191*9b8b2884SDavid Wang char bb[128];
192*9b8b2884SDavid Wang sprintf(bb, "/proc/%d/maps", pid);
193*9b8b2884SDavid Wang FILE* fp = fopen(bb, "r");
194*9b8b2884SDavid Wang if (fp==NULL) return NULL;
195*9b8b2884SDavid Wang STORE_T *store = new STORE_T();
196*9b8b2884SDavid Wang unsigned long long start, end, offset;
197*9b8b2884SDavid Wang char *p;
198*9b8b2884SDavid Wang int i, c, j;
199*9b8b2884SDavid Wang while(1) {
200*9b8b2884SDavid Wang p=fgets(bb, sizeof(bb), fp); if (p==NULL) break;
201*9b8b2884SDavid Wang i=0; c=0;
202*9b8b2884SDavid Wang start = parse_hex(p, &c); if (start==0) continue; i+=c; if (p[i]!='-') continue; i++;
203*9b8b2884SDavid Wang end = parse_hex(p+i, &c); if (end==0) continue; i+=c;
204*9b8b2884SDavid Wang // parse type
205*9b8b2884SDavid Wang for (j=0; j<8; j++) { if (p[i]=='x') break; i++; } if (j>=8) continue;
206*9b8b2884SDavid Wang while(p[i]!=' '&&p[i]!='\t'&&p[i]!=0) i++; if (p[i]==0) continue;
207*9b8b2884SDavid Wang offset = parse_hex(p+i, &c); if (c==0) continue;
208*9b8b2884SDavid Wang // remaining should contains '/' indicating this mmap is refering to a file
209*9b8b2884SDavid Wang while(p[i]&&p[i]!='/') i++; if (p[i]==0) continue;
210*9b8b2884SDavid Wang sprintf(bb, "/proc/%d/map_files/%llx-%llx", pid, start, end);
211*9b8b2884SDavid Wang load_symbol_from_file(bb, start, end-start, offset, *store);
212*9b8b2884SDavid Wang }
213*9b8b2884SDavid Wang fclose(fp);
214*9b8b2884SDavid Wang return store;
215*9b8b2884SDavid Wang }
216*9b8b2884SDavid Wang
217*9b8b2884SDavid Wang /* parse kernel func symbols from /proc/kallsyms */
load_kernel()218*9b8b2884SDavid Wang K_STORE_T* load_kernel() {
219*9b8b2884SDavid Wang FILE* fp = fopen("/proc/kallsyms", "r");
220*9b8b2884SDavid Wang if (fp == NULL) return NULL;
221*9b8b2884SDavid Wang char *p;
222*9b8b2884SDavid Wang unsigned long long addr;
223*9b8b2884SDavid Wang int c;
224*9b8b2884SDavid Wang K_STORE_T* store = new K_STORE_T();
225*9b8b2884SDavid Wang char bb[128], adr[128], type[8], name[128];
226*9b8b2884SDavid Wang while(1) {
227*9b8b2884SDavid Wang p = fgets(bb, sizeof(bb), fp); if (p==NULL) break;
228*9b8b2884SDavid Wang if (sscanf(p, "%s %s %s", adr, type, name)!=3) continue;;
229*9b8b2884SDavid Wang if (type[0]!='t'&&type[0]!='T') continue;
230*9b8b2884SDavid Wang addr=parse_hex(adr, &c); if (c==0) continue;
231*9b8b2884SDavid Wang (*store)[addr] = string(name);
232*9b8b2884SDavid Wang }
233*9b8b2884SDavid Wang return store;
234*9b8b2884SDavid Wang fclose(fp);
235*9b8b2884SDavid Wang }
236*9b8b2884SDavid Wang
237*9b8b2884SDavid Wang //------------------------------perf profiler-------------------------
perf_event_open(struct perf_event_attr * perf_event,pid_t pid,int cpu,int group_fd,unsigned long flags)238*9b8b2884SDavid Wang static long perf_event_open(struct perf_event_attr *perf_event, pid_t pid, int cpu, int group_fd, unsigned long flags) {
239*9b8b2884SDavid Wang return syscall(__NR_perf_event_open, perf_event, pid, cpu, group_fd, flags);
240*9b8b2884SDavid Wang }
241*9b8b2884SDavid Wang unordered_map<int, STORE_T*> pid_symbols;
242*9b8b2884SDavid Wang K_STORE_T* kernel_symbols = NULL;
243*9b8b2884SDavid Wang
244*9b8b2884SDavid Wang struct pollfd polls[MAXCPU];
245*9b8b2884SDavid Wang // res for cleanup
246*9b8b2884SDavid Wang static long long psize;
247*9b8b2884SDavid Wang map<int, pair<void*, long long>> res;
248*9b8b2884SDavid Wang TNode* gnode = NULL;
249*9b8b2884SDavid Wang
int_exit(int _)250*9b8b2884SDavid Wang void int_exit(int _) {
251*9b8b2884SDavid Wang for (auto x: res) {
252*9b8b2884SDavid Wang auto y = x.second;
253*9b8b2884SDavid Wang void* addr = y.first;
254*9b8b2884SDavid Wang munmap(addr, (1+MAXN)*psize);
255*9b8b2884SDavid Wang close(x.first);
256*9b8b2884SDavid Wang }
257*9b8b2884SDavid Wang res.clear();
258*9b8b2884SDavid Wang if (gnode!=NULL) {
259*9b8b2884SDavid Wang FILE* fp = fopen("./report.html", "w");
260*9b8b2884SDavid Wang if (fp) {
261*9b8b2884SDavid Wang fprintf(fp, "<head> <link rel=\"stylesheet\" href=\"report.css\"> <script src=\"report.js\"> </script> </head>\n");
262*9b8b2884SDavid Wang fprintf(fp, "<ul class=\"tree\">\n");
263*9b8b2884SDavid Wang gnode->printit(fp, 0);
264*9b8b2884SDavid Wang fprintf(fp, "</ul>\n");
265*9b8b2884SDavid Wang fclose(fp);
266*9b8b2884SDavid Wang printf("report done\n");
267*9b8b2884SDavid Wang }
268*9b8b2884SDavid Wang gnode = NULL;
269*9b8b2884SDavid Wang }
270*9b8b2884SDavid Wang }
271*9b8b2884SDavid Wang /*
272*9b8b2884SDavid Wang perf call chain process
273*9b8b2884SDavid Wang For now, if a address would not be located to some function, the address would be skipped.
274*9b8b2884SDavid Wang */
process_event(char * base,unsigned long long size,unsigned long long offset)275*9b8b2884SDavid Wang int process_event(char *base, unsigned long long size, unsigned long long offset) {
276*9b8b2884SDavid Wang struct perf_event_header* p = NULL;
277*9b8b2884SDavid Wang int pid, xpid;
278*9b8b2884SDavid Wang unsigned long long time;
279*9b8b2884SDavid Wang offset%=size;
280*9b8b2884SDavid Wang // assuming the header would fit within size
281*9b8b2884SDavid Wang p = (struct perf_event_header*) (base+offset);
282*9b8b2884SDavid Wang offset+=sizeof(*p); if (offset>=size) offset-=size;
283*9b8b2884SDavid Wang if (p->type != PERF_RECORD_SAMPLE) return p->size;
284*9b8b2884SDavid Wang // pid, tip;
285*9b8b2884SDavid Wang pid = *((int *)(base+offset)); offset+=8; if (offset>=size) offset-=size;
286*9b8b2884SDavid Wang unsigned long long nr = *((unsigned long long*)(base+offset)); offset+=8; if (offset>=size) offset-=size;
287*9b8b2884SDavid Wang unsigned long long addr, o, addr0;
288*9b8b2884SDavid Wang if (nr) {
289*9b8b2884SDavid Wang if (gnode==NULL) gnode=new TNode();
290*9b8b2884SDavid Wang char bb[64];
291*9b8b2884SDavid Wang TNode* r = gnode;
292*9b8b2884SDavid Wang if (pid_symbols.count(pid)==0) pid_symbols[pid] = load_symbol_pid(pid);
293*9b8b2884SDavid Wang STORE_T* px = pid_symbols[pid];
294*9b8b2884SDavid Wang addr0 = *((unsigned long long *)(base+offset));
295*9b8b2884SDavid Wang char user_mark = 0;
296*9b8b2884SDavid Wang for (int i=nr-1; i>=0; i--) {
297*9b8b2884SDavid Wang o = i*8+offset; if (o>=size) o-=size;
298*9b8b2884SDavid Wang addr = *((unsigned long long*)(base+o));
299*9b8b2884SDavid Wang if ((addr>>56)==(addr0>>56) && (p->misc&PERF_RECORD_MISC_KERNEL)) {
300*9b8b2884SDavid Wang // skip the cross line command, no idear how to correctly resolve it now.
301*9b8b2884SDavid Wang if (user_mark) { user_mark=0; continue; }
302*9b8b2884SDavid Wang // check in kernel
303*9b8b2884SDavid Wang if (kernel_symbols&&!kernel_symbols->empty()) {
304*9b8b2884SDavid Wang auto x = kernel_symbols->upper_bound(addr);
305*9b8b2884SDavid Wang if (x==kernel_symbols->begin()) {
306*9b8b2884SDavid Wang // sprintf(bb, "0x%llx", addr); r = r->add(string(bb));
307*9b8b2884SDavid Wang } else {
308*9b8b2884SDavid Wang x--;
309*9b8b2884SDavid Wang r = r->add((*x).second);
310*9b8b2884SDavid Wang }
311*9b8b2884SDavid Wang } else {
312*9b8b2884SDavid Wang // sprintf(bb, "0x%llx", addr); r = r->add(string(bb));
313*9b8b2884SDavid Wang }
314*9b8b2884SDavid Wang } else {
315*9b8b2884SDavid Wang if (px) {
316*9b8b2884SDavid Wang auto x = px->upper_bound(addr);
317*9b8b2884SDavid Wang if (x==px->begin()) {
318*9b8b2884SDavid Wang // sprintf(bb, "0x%llx", addr); r = r->add(string(bb));
319*9b8b2884SDavid Wang } else {
320*9b8b2884SDavid Wang x--;
321*9b8b2884SDavid Wang auto y = (*x).second;
322*9b8b2884SDavid Wang if (addr>(*x).first+y.second) {
323*9b8b2884SDavid Wang // r = r->add(y.first);
324*9b8b2884SDavid Wang // sprintf(bb, "0x%llx", addr); r = r->add(string(bb));
325*9b8b2884SDavid Wang } else {
326*9b8b2884SDavid Wang r = r->add(y.first);
327*9b8b2884SDavid Wang }
328*9b8b2884SDavid Wang }
329*9b8b2884SDavid Wang } else {
330*9b8b2884SDavid Wang // sprintf(bb, "0x%llx", addr); r = r->add(string(bb));
331*9b8b2884SDavid Wang }
332*9b8b2884SDavid Wang user_mark=1;
333*9b8b2884SDavid Wang }
334*9b8b2884SDavid Wang }
335*9b8b2884SDavid Wang }
336*9b8b2884SDavid Wang return p->size;
337*9b8b2884SDavid Wang }
338*9b8b2884SDavid Wang
main(int argc,char * argv[])339*9b8b2884SDavid Wang int main(int argc, char *argv[]) {
340*9b8b2884SDavid Wang if (argc != 2) { printf("need pid\n"); return 1; }
341*9b8b2884SDavid Wang load_kernel();
342*9b8b2884SDavid Wang int pid = atoi(argv[1]); if (pid<=0) { printf("invalid pid %s\n", argv[1]); return 1; }
343*9b8b2884SDavid Wang // find cgroup
344*9b8b2884SDavid Wang char xb[256], xb2[256];
345*9b8b2884SDavid Wang int i, j, k;
346*9b8b2884SDavid Wang int fd;
347*9b8b2884SDavid Wang void *addr;
348*9b8b2884SDavid Wang sprintf(xb, "/proc/%d/cgroup", pid);
349*9b8b2884SDavid Wang FILE* fp = fopen(xb, "r");
350*9b8b2884SDavid Wang if (fp==NULL) error("fail to open cgroup file");
351*9b8b2884SDavid Wang char *p;
352*9b8b2884SDavid Wang xb2[0]=0;
353*9b8b2884SDavid Wang int cgroup_name_len=0;
354*9b8b2884SDavid Wang while(1) {
355*9b8b2884SDavid Wang p = fgets(xb, sizeof(xb), fp); if (p==NULL) break;
356*9b8b2884SDavid Wang i=0; while(p[i]&&p[i]!=':') i++; if (p[i]==0) continue;
357*9b8b2884SDavid Wang if (strstr(p, "perf_event")) {
358*9b8b2884SDavid Wang i++; while(p[i]!=':'&&p[i]) i++; if (p[i]!=':') continue; i++;
359*9b8b2884SDavid Wang j=i; while(p[j]!='\r'&&p[j]!='\n'&&p[j]!=0) j++; p[j]=0;
360*9b8b2884SDavid Wang sprintf(xb2, "/sys/fs/cgroup/perf_event%s", p+i);
361*9b8b2884SDavid Wang cgroup_name_len=j-i;
362*9b8b2884SDavid Wang break;
363*9b8b2884SDavid Wang } else if (p[i+1]==':') {
364*9b8b2884SDavid Wang i+=2; j=i; while(p[j]!='\r'&&p[j]!='\n'&&p[j]!=0) j++; p[j]=0;
365*9b8b2884SDavid Wang sprintf(xb2, "/sys/fs/cgroup/%s", p+i);
366*9b8b2884SDavid Wang cgroup_name_len=j-i;
367*9b8b2884SDavid Wang }
368*9b8b2884SDavid Wang }
369*9b8b2884SDavid Wang fclose(fp);
370*9b8b2884SDavid Wang if (xb2[0]==0) error("no proper cgroup found\n");
371*9b8b2884SDavid Wang if (cgroup_name_len<2) {
372*9b8b2884SDavid Wang printf("cgroup %s seems to be root, not allowed\n", xb2);
373*9b8b2884SDavid Wang return -1;
374*9b8b2884SDavid Wang }
375*9b8b2884SDavid Wang printf("try to use cgroup %s\n", xb2);
376*9b8b2884SDavid Wang int cgroup_id = open(xb2, O_CLOEXEC);
377*9b8b2884SDavid Wang if (cgroup_id<=0) { perror("error open cgroup dir"); return 1; }
378*9b8b2884SDavid Wang // start perf event
379*9b8b2884SDavid Wang psize = sysconf(_SC_PAGE_SIZE); // getpagesize();
380*9b8b2884SDavid Wang int cpu_num = sysconf(_SC_NPROCESSORS_ONLN);
381*9b8b2884SDavid Wang struct perf_event_attr attr;
382*9b8b2884SDavid Wang memset(&attr, 0, sizeof(attr));
383*9b8b2884SDavid Wang attr.type = PERF_TYPE_SOFTWARE;
384*9b8b2884SDavid Wang attr.size = sizeof(attr);
385*9b8b2884SDavid Wang attr.config = PERF_COUNT_SW_CONTEXT_SWITCHES;
386*9b8b2884SDavid Wang // attr.config = PERF_COUNT_SW_CPU_MIGRATIONS;
387*9b8b2884SDavid Wang attr.sample_period = 1;
388*9b8b2884SDavid Wang attr.wakeup_events = 32;
389*9b8b2884SDavid Wang attr.sample_type = PERF_SAMPLE_TID|PERF_SAMPLE_CALLCHAIN;
390*9b8b2884SDavid Wang attr.context_switch = 1;
391*9b8b2884SDavid Wang // attr.sample_id_all = 1;
392*9b8b2884SDavid Wang for (i=0, k=0; i<cpu_num&&i<MAXCPU; i++) {
393*9b8b2884SDavid Wang printf("attaching cpu %d\n", i);
394*9b8b2884SDavid Wang fd = perf_event_open(&attr, cgroup_id, i, -1, PERF_FLAG_FD_CLOEXEC|PERF_FLAG_PID_CGROUP);
395*9b8b2884SDavid Wang if (fd<0) { perror("fail to open perf event"); continue; }
396*9b8b2884SDavid Wang addr = mmap(NULL, (1+MAXN)*psize, PROT_READ, MAP_SHARED, fd, 0);
397*9b8b2884SDavid Wang if (addr == MAP_FAILED) { perror("mmap failed"); close(fd); continue; }
398*9b8b2884SDavid Wang res[fd] = make_pair(addr, 0);
399*9b8b2884SDavid Wang polls[k].fd = fd;
400*9b8b2884SDavid Wang polls[k].events = POLLIN;
401*9b8b2884SDavid Wang polls[k].revents = 0;
402*9b8b2884SDavid Wang k++;
403*9b8b2884SDavid Wang }
404*9b8b2884SDavid Wang if (k==0) { printf("no cpu event attached at all\n"); return 1; }
405*9b8b2884SDavid Wang
406*9b8b2884SDavid Wang signal(SIGINT, int_exit);
407*9b8b2884SDavid Wang signal(SIGTERM, int_exit);
408*9b8b2884SDavid Wang
409*9b8b2884SDavid Wang unsigned long long head;
410*9b8b2884SDavid Wang struct perf_event_mmap_page *mp;
411*9b8b2884SDavid Wang while (poll(polls, k, -1)>0) {
412*9b8b2884SDavid Wang for (i=0; i<k; i++) {
413*9b8b2884SDavid Wang if ((polls[i].revents&POLLIN)==0) continue;
414*9b8b2884SDavid Wang fd = polls[i].fd;
415*9b8b2884SDavid Wang addr = res[fd].first;
416*9b8b2884SDavid Wang mp = (struct perf_event_mmap_page *)addr;
417*9b8b2884SDavid Wang head = res[fd].second;
418*9b8b2884SDavid Wang if (head==mp->data_head) continue;
419*9b8b2884SDavid Wang ioctl(fd, PERF_EVENT_IOC_PAUSE_OUTPUT, 1);
420*9b8b2884SDavid Wang head = mp->data_head-((mp->data_head-head)%mp->data_size);
421*9b8b2884SDavid Wang while(head<mp->data_head) head+=process_event((char*)addr+mp->data_offset, mp->data_size, head);
422*9b8b2884SDavid Wang ioctl(fd, PERF_EVENT_IOC_PAUSE_OUTPUT, 0);
423*9b8b2884SDavid Wang res[fd].second = mp->data_head;
424*9b8b2884SDavid Wang }
425*9b8b2884SDavid Wang }
426*9b8b2884SDavid Wang
427*9b8b2884SDavid Wang int_exit(0);
428*9b8b2884SDavid Wang return 0;
429*9b8b2884SDavid Wang }
430