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