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