178c68143SDavid Wang #include <stdlib.h> 278c68143SDavid Wang #include <stdio.h> 378c68143SDavid Wang #include <unistd.h> 478c68143SDavid Wang #include <string.h> 578c68143SDavid Wang #include <sys/ioctl.h> 678c68143SDavid Wang #include <linux/perf_event.h> 778c68143SDavid Wang #include <asm/unistd.h> 878c68143SDavid Wang #include <sys/mman.h> 978c68143SDavid Wang #include <sys/stat.h> 1078c68143SDavid Wang #include <poll.h> 1178c68143SDavid Wang #include <signal.h> 1278c68143SDavid Wang #include <fcntl.h> 1378c68143SDavid Wang #include <elf.h> 1478c68143SDavid Wang #include <string.h> 1578c68143SDavid Wang 1678c68143SDavid Wang #include <vector> 1778c68143SDavid Wang #include <string> 1878c68143SDavid Wang #include <map> 1978c68143SDavid Wang #include <unordered_map> 2093979a5eSDavid Wang #include <unordered_set> 2178c68143SDavid Wang #include <algorithm> 2278c68143SDavid Wang using namespace std; 2378c68143SDavid Wang 2478c68143SDavid Wang 2593979a5eSDavid Wang #define MAXN 512 2693979a5eSDavid Wang #define MAXCPU 128 2778c68143SDavid Wang #define error(msg) do { perror(msg); exit(1); } while(0) 2878c68143SDavid Wang //--------------------------------Tree for call chain and report------------------------------- 2978c68143SDavid Wang // 3078c68143SDavid Wang struct TNode { 3178c68143SDavid Wang int c=0; 3278c68143SDavid Wang unordered_map<string, TNode*> s; 3378c68143SDavid Wang struct TNode *add(string n) { 3478c68143SDavid Wang c++; 3578c68143SDavid Wang if (s[n]==nullptr) s[n] = new TNode(); 3678c68143SDavid Wang return s[n]; 3778c68143SDavid Wang } 3878c68143SDavid Wang int printit(FILE *fp, int k) { 3978c68143SDavid Wang if (s.size()) { 4078c68143SDavid Wang using tt = tuple<int, string, TNode*>; 4178c68143SDavid Wang vector<tt> xx; 4278c68143SDavid Wang for (auto x: s) xx.push_back(make_tuple(x.second->c, x.first, x.second)); 4378c68143SDavid Wang sort(begin(xx), end(xx), greater<tt>()); 4478c68143SDavid Wang for (auto x: xx) { 4578c68143SDavid Wang auto count = get<0>(x); 4678c68143SDavid Wang if (100.0*count/c<1) continue; 4778c68143SDavid Wang auto name = get<1>(x); 4878c68143SDavid Wang auto nx = get<2>(x); 4978c68143SDavid Wang fprintf(fp, "<li>\n"); 5078c68143SDavid Wang fprintf(fp, "<input type=\"checkbox\" id=\"c%d\" />\n", k); 5178c68143SDavid 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); 5278c68143SDavid Wang fprintf(fp, "<ul>\n"); 5378c68143SDavid Wang // printf("%s(%.3f%% %d/%d)\n", name.c_str(), 100.0*count/c, count, c); 5478c68143SDavid Wang k = nx->printit(fp, k+1); 5578c68143SDavid Wang fprintf(fp, "</ul>\n"); 5678c68143SDavid Wang fprintf(fp, "</li>\n"); 5778c68143SDavid Wang } 5878c68143SDavid Wang } 5978c68143SDavid Wang return k; 6078c68143SDavid Wang } 6178c68143SDavid Wang }; 6278c68143SDavid Wang 6378c68143SDavid Wang //--------------------------------symbols------------------------------------------- 6478c68143SDavid Wang using STORE_T = map<unsigned long long, pair<string, unsigned long long>>; 6578c68143SDavid Wang using K_STORE_T = map<unsigned long long, string>; 6678c68143SDavid Wang 6778c68143SDavid Wang /* 6878c68143SDavid Wang * load FUNC symbols refering to the section indicated by the offset, relocate the virtual address 6978c68143SDavid Wang */ 7078c68143SDavid Wang void parse_elf64(FILE *fp, unsigned long long v_addr, unsigned long long v_size, unsigned long long v_offset, STORE_T& store) { 7178c68143SDavid Wang // printf("read elf with offset 0x%llx, addr 0x%llx\n", v_offset, v_addr); 7278c68143SDavid Wang Elf64_Ehdr ehdr; 7378c68143SDavid Wang int rc = fread(&ehdr, sizeof(ehdr), 1, fp); 7478c68143SDavid Wang if (rc != 1) return; 7578c68143SDavid Wang int n, s, i; 7678c68143SDavid Wang unsigned long long offset; 7778c68143SDavid Wang 7878c68143SDavid Wang // load program headers 7978c68143SDavid Wang unsigned long long p_vaddr, p_size; 8078c68143SDavid Wang n = ehdr.e_phnum; 8178c68143SDavid Wang s = ehdr.e_phentsize; 8278c68143SDavid Wang offset = ehdr.e_phoff; 8378c68143SDavid Wang Elf64_Phdr phdr; 8478c68143SDavid Wang for (i=0; i<n; i++) { 8578c68143SDavid Wang rc = fseek(fp, offset, SEEK_SET); 8678c68143SDavid Wang if (rc<0) { perror("fail to seek"); return; } 8778c68143SDavid Wang rc = fread(&phdr, sizeof(phdr), 1, fp); 8878c68143SDavid Wang if (rc != 1) { perror("fail to read program header"); return; } 8978c68143SDavid Wang if (phdr.p_flags&PF_X) { 9078c68143SDavid Wang if (phdr.p_offset == v_offset) { 9178c68143SDavid Wang p_vaddr = phdr.p_vaddr; 9278c68143SDavid Wang p_size = phdr.p_memsz; if (p_size==0) p_size = 0xffffffff; 9378c68143SDavid Wang break; 9478c68143SDavid Wang } 9578c68143SDavid Wang } 9678c68143SDavid Wang offset+=s; 9778c68143SDavid Wang } 9878c68143SDavid Wang if (i>=n) { printf("No program header match offset found, fail to load\n"); return; } 9978c68143SDavid Wang 10078c68143SDavid Wang // load section headers 10178c68143SDavid Wang n = ehdr.e_shnum; 10278c68143SDavid Wang s = ehdr.e_shentsize; 10378c68143SDavid Wang offset = ehdr.e_shoff; 10478c68143SDavid Wang Elf64_Shdr shdr; 10578c68143SDavid Wang vector<Elf64_Shdr> headers; 10678c68143SDavid Wang for (int i=0; i<n; i++) { 10778c68143SDavid Wang rc = fseek(fp, offset, SEEK_SET); 10878c68143SDavid Wang if (rc<0) { perror("fail to seek"); return; } 10978c68143SDavid Wang rc = fread(&shdr, sizeof(shdr), 1, fp); 11078c68143SDavid Wang if (rc != 1) { perror("fail to read sec header"); return; } 11178c68143SDavid Wang headers.push_back(shdr); 11278c68143SDavid Wang offset+=s; 11378c68143SDavid Wang } 11478c68143SDavid Wang Elf64_Sym symb; 11578c68143SDavid Wang unsigned long long faddr, fsize; 11678c68143SDavid Wang unsigned long long size, item_size; 11778c68143SDavid Wang int link, ix, flink, k; 11878c68143SDavid Wang char fname[128]; 11978c68143SDavid Wang for (int i=0; i<n; i++) { 12078c68143SDavid Wang switch(headers[i].sh_type) { 12178c68143SDavid Wang case SHT_SYMTAB: 12278c68143SDavid Wang case SHT_DYNSYM: 12378c68143SDavid Wang offset = headers[i].sh_offset; 12478c68143SDavid Wang size = headers[i].sh_size; 12578c68143SDavid Wang item_size = headers[i].sh_entsize; 12678c68143SDavid Wang link = headers[i].sh_link; 12778c68143SDavid Wang if (link<=0) break; 12878c68143SDavid Wang for (k=0; k+item_size<=size; k+=item_size) { 12978c68143SDavid Wang rc = fseek(fp, offset+k, SEEK_SET); if (rc<0) continue; 13078c68143SDavid Wang rc = fread(&symb, sizeof(symb), 1, fp); if (rc != 1) continue; 13178c68143SDavid Wang if (ELF64_ST_TYPE(symb.st_info) != STT_FUNC ) continue; 13278c68143SDavid Wang flink = symb.st_shndx; if (flink==0) continue; 13393979a5eSDavid Wang fsize = symb.st_size; // if (fsize==0) continue; 13478c68143SDavid Wang faddr = symb.st_value; if (faddr>p_vaddr+p_size) continue; 13578c68143SDavid Wang ix = symb.st_name; if (ix==0) continue; 13678c68143SDavid Wang rc = fseek(fp, headers[link].sh_offset+ix, SEEK_SET); if (rc<0) continue; 13778c68143SDavid Wang if (fgets(fname, sizeof(fname), fp)==NULL) continue; 13878c68143SDavid Wang faddr = faddr-p_vaddr+v_addr; 13993979a5eSDavid Wang if (store.count(faddr)) { 14093979a5eSDavid Wang if (store[faddr].second<fsize) store[faddr] = make_pair(string(fname), fsize); 14193979a5eSDavid Wang } else store[faddr] = make_pair(string(fname), fsize); 14278c68143SDavid Wang } 14378c68143SDavid Wang break; 14478c68143SDavid Wang default: 14578c68143SDavid Wang break; 14678c68143SDavid Wang } 14778c68143SDavid Wang } 14878c68143SDavid Wang } 14978c68143SDavid Wang 15078c68143SDavid Wang int load_symbol_from_file(const char *path, unsigned long long addr, unsigned long long size, unsigned long long offset, STORE_T& store) { 15178c68143SDavid Wang printf("loading symble from %s\n", path); 15278c68143SDavid Wang FILE *fp = fopen(path, "rb"); 15378c68143SDavid Wang if (fp==NULL) { perror("fail to open file"); return -1; } 15478c68143SDavid Wang char ident[EI_NIDENT], c; 15578c68143SDavid Wang int err=0; 15678c68143SDavid Wang int rc = fread(ident, sizeof(ident), 1, fp); 15778c68143SDavid Wang if (rc != 1) { perror("fail to read ident"); err=-1; goto end; } 15878c68143SDavid Wang if (ident[0]!=0x7f) { printf("not a elf file\n"); err=-1; goto end; } 15978c68143SDavid Wang c=ident[4]; 16078c68143SDavid Wang rc = fseek(fp, 0, SEEK_SET); if (rc<0) { perror("fail to rewind"); goto end; } 16178c68143SDavid Wang if (c == ELFCLASS32) { 16278c68143SDavid Wang printf("32bit elf not supported yet\n"); err=-2; goto end; 16378c68143SDavid Wang } else if (c == ELFCLASS64) { 16478c68143SDavid Wang parse_elf64(fp, addr, size, offset, store); 16578c68143SDavid Wang } 16678c68143SDavid Wang 16778c68143SDavid Wang end: 16878c68143SDavid Wang fclose(fp); 16978c68143SDavid Wang return err; 17078c68143SDavid Wang } 17178c68143SDavid Wang 17278c68143SDavid Wang static unsigned long long parse_hex(char *p, int *n) { 17378c68143SDavid Wang unsigned long long r=0; 17478c68143SDavid Wang int i=0; 17578c68143SDavid Wang *n = 0; 17678c68143SDavid Wang while(p[i]==' '||p[i]=='\t') i++; 17778c68143SDavid Wang if (p[i]==0) return 0; 17878c68143SDavid Wang if (p[i+1]=='x') i+=2; 17978c68143SDavid Wang int v; 18078c68143SDavid Wang while(p[i]) { 18178c68143SDavid Wang if (p[i]>='0'&&p[i]<='9') v=p[i]-'0'; 18278c68143SDavid Wang else if (p[i]>='a'&&p[i]<='f') v=10+p[i]-'a'; 18378c68143SDavid Wang else if (p[i]>='A'&&p[i]<='F') v=10+p[i]-'A'; 18478c68143SDavid Wang else break; 18578c68143SDavid Wang r=(r<<4)+v; 18678c68143SDavid Wang i++; 18778c68143SDavid Wang } 18878c68143SDavid Wang *n = i; 18978c68143SDavid Wang return r; 19078c68143SDavid Wang } 19178c68143SDavid Wang 19278c68143SDavid Wang STORE_T* load_symbol_pid(int pid) { 19378c68143SDavid Wang printf("loading symbols for %d\n", pid); 19493979a5eSDavid Wang char bb[256]; 19578c68143SDavid Wang sprintf(bb, "/proc/%d/maps", pid); 19678c68143SDavid Wang FILE* fp = fopen(bb, "r"); 19778c68143SDavid Wang if (fp==NULL) return NULL; 19878c68143SDavid Wang STORE_T *store = new STORE_T(); 19993979a5eSDavid Wang unsigned long long start, end, offset, inode; 20078c68143SDavid Wang char *p; 20178c68143SDavid Wang int i, c, j; 20293979a5eSDavid Wang char fname[128], xx[64], xxx[32], mod[16], idx[16]; 20378c68143SDavid Wang while(1) { 20478c68143SDavid Wang p=fgets(bb, sizeof(bb), fp); if (p==NULL) break; 20593979a5eSDavid Wang if (sscanf(p, "%s %s %s %s %lld %s", xx, mod, xxx, idx, &inode, fname)!=6) continue; 20678c68143SDavid Wang i=0; c=0; 20793979a5eSDavid Wang start = parse_hex(xx, &c); if (c==0) continue; i+=c; if (p[i]!='-') continue; i++; 20893979a5eSDavid Wang end = parse_hex(xx+i, &c); if (c==0) continue; 20978c68143SDavid Wang // parse type 21093979a5eSDavid Wang for (j=0; j<8; j++) if (mod[j]=='x') break; if (j>=8) continue; 21193979a5eSDavid Wang if (fname[0]!='/') continue; 21293979a5eSDavid Wang offset = parse_hex(xxx, &c); if (c==0) continue; 21378c68143SDavid Wang // remaining should contains '/' indicating this mmap is refering to a file 21493979a5eSDavid Wang sprintf(bb, "/proc/%d/root%s", pid, fname); 21578c68143SDavid Wang load_symbol_from_file(bb, start, end-start, offset, *store); 21678c68143SDavid Wang } 21778c68143SDavid Wang fclose(fp); 21878c68143SDavid Wang return store; 21978c68143SDavid Wang } 22078c68143SDavid Wang 22178c68143SDavid Wang /* parse kernel func symbols from /proc/kallsyms */ 22278c68143SDavid Wang K_STORE_T* load_kernel() { 22378c68143SDavid Wang FILE* fp = fopen("/proc/kallsyms", "r"); 22478c68143SDavid Wang if (fp == NULL) return NULL; 22578c68143SDavid Wang char *p; 22678c68143SDavid Wang unsigned long long addr; 22778c68143SDavid Wang int c; 22878c68143SDavid Wang K_STORE_T* store = new K_STORE_T(); 22978c68143SDavid Wang char bb[128], adr[128], type[8], name[128]; 23078c68143SDavid Wang while(1) { 23178c68143SDavid Wang p = fgets(bb, sizeof(bb), fp); if (p==NULL) break; 23278c68143SDavid Wang if (sscanf(p, "%s %s %s", adr, type, name)!=3) continue;; 23378c68143SDavid Wang if (type[0]!='t'&&type[0]!='T') continue; 23478c68143SDavid Wang addr=parse_hex(adr, &c); if (c==0) continue; 23578c68143SDavid Wang (*store)[addr] = string(name); 23678c68143SDavid Wang } 23778c68143SDavid Wang return store; 23878c68143SDavid Wang fclose(fp); 23978c68143SDavid Wang } 24078c68143SDavid Wang 24178c68143SDavid Wang //------------------------------perf profiler------------------------- 24278c68143SDavid Wang static long perf_event_open(struct perf_event_attr *perf_event, pid_t pid, int cpu, int group_fd, unsigned long flags) { 24378c68143SDavid Wang return syscall(__NR_perf_event_open, perf_event, pid, cpu, group_fd, flags); 24478c68143SDavid Wang } 24578c68143SDavid Wang unordered_map<int, STORE_T*> pid_symbols; 24678c68143SDavid Wang K_STORE_T* kernel_symbols = NULL; 24778c68143SDavid Wang 24878c68143SDavid Wang struct pollfd polls[MAXCPU]; 24978c68143SDavid Wang // res for cleanup 25078c68143SDavid Wang static long long psize; 25178c68143SDavid Wang map<int, pair<void*, long long>> res; 25278c68143SDavid Wang TNode* gnode = NULL; 25378c68143SDavid Wang 25493979a5eSDavid Wang unordered_map<unsigned long long, string> unknowns; 25578c68143SDavid Wang void int_exit(int _) { 25678c68143SDavid Wang for (auto x: res) { 25778c68143SDavid Wang auto y = x.second; 25878c68143SDavid Wang void* addr = y.first; 25978c68143SDavid Wang munmap(addr, (1+MAXN)*psize); 26078c68143SDavid Wang close(x.first); 26178c68143SDavid Wang } 26278c68143SDavid Wang res.clear(); 26378c68143SDavid Wang if (gnode!=NULL) { 26478c68143SDavid Wang FILE* fp = fopen("./report.html", "w"); 26578c68143SDavid Wang if (fp) { 26678c68143SDavid Wang fprintf(fp, "<head> <link rel=\"stylesheet\" href=\"report.css\"> <script src=\"report.js\"> </script> </head>\n"); 26778c68143SDavid Wang fprintf(fp, "<ul class=\"tree\">\n"); 26878c68143SDavid Wang gnode->printit(fp, 0); 26978c68143SDavid Wang fprintf(fp, "</ul>\n"); 27078c68143SDavid Wang fclose(fp); 27178c68143SDavid Wang printf("report done\n"); 27278c68143SDavid Wang } 27378c68143SDavid Wang gnode = NULL; 27478c68143SDavid Wang } 27593979a5eSDavid Wang printf("---------------------unknowns-----------------\n"); 27693979a5eSDavid Wang for (auto x=unknowns.begin(); x!=unknowns.end(); x++) { 27793979a5eSDavid Wang printf("0x%llx --?> %s\n", (*x).first, (*x).second.c_str()); 27893979a5eSDavid Wang } 279a7aacf28SDavid Wang exit(0); 28078c68143SDavid Wang } 28178c68143SDavid Wang /* 28278c68143SDavid Wang perf call chain process 28378c68143SDavid Wang For now, if a address would not be located to some function, the address would be skipped. 28478c68143SDavid Wang */ 28578c68143SDavid Wang int process_event(char *base, unsigned long long size, unsigned long long offset) { 28678c68143SDavid Wang struct perf_event_header* p = NULL; 28778c68143SDavid Wang int pid, xpid; 28878c68143SDavid Wang unsigned long long time; 28978c68143SDavid Wang offset%=size; 29078c68143SDavid Wang // assuming the header would fit within size 29178c68143SDavid Wang p = (struct perf_event_header*) (base+offset); 29278c68143SDavid Wang offset+=sizeof(*p); if (offset>=size) offset-=size; 29378c68143SDavid Wang if (p->type != PERF_RECORD_SAMPLE) return p->size; 29478c68143SDavid Wang // pid, tip; 29578c68143SDavid Wang pid = *((int *)(base+offset)); offset+=8; if (offset>=size) offset-=size; 29678c68143SDavid Wang unsigned long long nr = *((unsigned long long*)(base+offset)); offset+=8; if (offset>=size) offset-=size; 29793979a5eSDavid Wang if (nr>128) return -1; 29878c68143SDavid Wang unsigned long long addr, o, addr0; 29978c68143SDavid Wang if (nr) { 30078c68143SDavid Wang if (gnode==NULL) gnode=new TNode(); 30178c68143SDavid Wang char bb[64]; 30278c68143SDavid Wang TNode* r = gnode; 30378c68143SDavid Wang if (pid_symbols.count(pid)==0) pid_symbols[pid] = load_symbol_pid(pid); 30478c68143SDavid Wang STORE_T* px = pid_symbols[pid]; 30578c68143SDavid Wang addr0 = *((unsigned long long *)(base+offset)); 30678c68143SDavid Wang char user_mark = 0; 30778c68143SDavid Wang for (int i=nr-1; i>=0; i--) { 30878c68143SDavid Wang o = i*8+offset; if (o>=size) o-=size; 30978c68143SDavid Wang addr = *((unsigned long long*)(base+o)); 31093979a5eSDavid Wang if (addr==0) continue; // something wrong? 31178c68143SDavid Wang if ((addr>>56)==(addr0>>56) && (p->misc&PERF_RECORD_MISC_KERNEL)) { 31278c68143SDavid Wang // skip the cross line command, no idear how to correctly resolve it now. 31378c68143SDavid Wang if (user_mark) { user_mark=0; continue; } 31478c68143SDavid Wang // check in kernel 31578c68143SDavid Wang if (kernel_symbols&&!kernel_symbols->empty()) { 31678c68143SDavid Wang auto x = kernel_symbols->upper_bound(addr); 31778c68143SDavid Wang if (x==kernel_symbols->begin()) { 31878c68143SDavid Wang // sprintf(bb, "0x%llx", addr); r = r->add(string(bb)); 319a7aacf28SDavid Wang r = r->add(string("unknown")); 32078c68143SDavid Wang } else { 32178c68143SDavid Wang x--; 32278c68143SDavid Wang r = r->add((*x).second); 32378c68143SDavid Wang } 32478c68143SDavid Wang } else { 32578c68143SDavid Wang // sprintf(bb, "0x%llx", addr); r = r->add(string(bb)); 326a7aacf28SDavid Wang r = r->add(string("unknown")); 32778c68143SDavid Wang } 32878c68143SDavid Wang } else { 32978c68143SDavid Wang if (px) { 33078c68143SDavid Wang auto x = px->upper_bound(addr); 33178c68143SDavid Wang if (x==px->begin()) { 33278c68143SDavid Wang // sprintf(bb, "0x%llx", addr); r = r->add(string(bb)); 333*f82de63eSDavid Wang auto y = (*x).second; 334*f82de63eSDavid Wang r = r->add(y.first+"?"); 33578c68143SDavid Wang } else { 33678c68143SDavid Wang x--; 33778c68143SDavid Wang auto y = (*x).second; 33893979a5eSDavid Wang if (y.second && addr>(*x).first+y.second) { 33978c68143SDavid Wang // r = r->add(y.first); 34078c68143SDavid Wang // sprintf(bb, "0x%llx", addr); r = r->add(string(bb)); 341*f82de63eSDavid Wang x++; 342*f82de63eSDavid Wang if (x==px->end()) r = r->add(y.first+"??"); 343*f82de63eSDavid Wang else { 344*f82de63eSDavid Wang auto y = (*x).second; 34593979a5eSDavid Wang r = r->add(y.first+"?"); 346*f82de63eSDavid Wang } 34778c68143SDavid Wang } else { 34878c68143SDavid Wang r = r->add(y.first); 34978c68143SDavid Wang } 35078c68143SDavid Wang } 35178c68143SDavid Wang } else { 35278c68143SDavid Wang // sprintf(bb, "0x%llx", addr); r = r->add(string(bb)); 35393979a5eSDavid Wang // r = r->add(string("unknown")); 35493979a5eSDavid Wang unknowns[addr] = "no pid symbol"; 35578c68143SDavid Wang } 35678c68143SDavid Wang user_mark=1; 35778c68143SDavid Wang } 35878c68143SDavid Wang } 35978c68143SDavid Wang } 36078c68143SDavid Wang return p->size; 36178c68143SDavid Wang } 36278c68143SDavid Wang 36378c68143SDavid Wang int main(int argc, char *argv[]) { 36478c68143SDavid Wang kernel_symbols = load_kernel(); 3654092c028SDavid Wang if (argc<2) { printf("Need pid\n"); return 1; } 36678c68143SDavid Wang int pid = atoi(argv[1]); if (pid<=0) { printf("invalid pid %s\n", argv[1]); return 1; } 36778c68143SDavid Wang // find cgroup 36878c68143SDavid Wang char xb[256], xb2[256]; 36978c68143SDavid Wang int i, j, k, fd; 37078c68143SDavid Wang void* addr; 37178c68143SDavid Wang sprintf(xb, "/proc/%d/cgroup", pid); 37278c68143SDavid Wang FILE* fp = fopen(xb, "r"); 37378c68143SDavid Wang if (fp==NULL) error("fail to open cgroup file"); 37478c68143SDavid Wang char *p; 37578c68143SDavid Wang xb2[0]=0; 3764092c028SDavid Wang int cgroup_name_len=0; 37778c68143SDavid Wang while(1) { 37878c68143SDavid Wang p = fgets(xb, sizeof(xb), fp); if (p==NULL) break; 37978c68143SDavid Wang i=0; while(p[i]&&p[i]!=':') i++; if (p[i]==0) continue; 38078c68143SDavid Wang if (strstr(p, "perf_event")) { 38178c68143SDavid Wang i++; while(p[i]!=':'&&p[i]) i++; if (p[i]!=':') continue; i++; 38278c68143SDavid Wang j=i; while(p[j]!='\r'&&p[j]!='\n'&&p[j]!=0) j++; p[j]=0; 38378c68143SDavid Wang sprintf(xb2, "/sys/fs/cgroup/perf_event%s", p+i); 3844092c028SDavid Wang cgroup_name_len=j-i; 38578c68143SDavid Wang break; 38678c68143SDavid Wang } else if (p[i+1]==':') { 38778c68143SDavid Wang i+=2; j=i; while(p[j]!='\r'&&p[j]!='\n'&&p[j]!=0) j++; p[j]=0; 38878c68143SDavid Wang sprintf(xb2, "/sys/fs/cgroup/%s", p+i); 3894092c028SDavid Wang cgroup_name_len=j-i; 39078c68143SDavid Wang } 39178c68143SDavid Wang } 39278c68143SDavid Wang fclose(fp); 39378c68143SDavid Wang if (xb2[0]==0) error("no proper cgroup found\n"); 3944092c028SDavid Wang if (cgroup_name_len<2) { 3954092c028SDavid Wang printf("cgroup %s seems to be root, not allowed\n", xb2); 3964092c028SDavid Wang return -1; 3974092c028SDavid Wang } 39878c68143SDavid Wang printf("try to use cgroup %s\n", xb2); 39978c68143SDavid Wang int cgroup_id = open(xb2, O_CLOEXEC); 40078c68143SDavid Wang if (cgroup_id<=0) { perror("error open cgroup dir"); return 1; } 40178c68143SDavid Wang // start perf event 40278c68143SDavid Wang psize = sysconf(_SC_PAGE_SIZE); // getpagesize(); 40378c68143SDavid Wang int cpu_num = sysconf(_SC_NPROCESSORS_ONLN); 40478c68143SDavid Wang struct perf_event_attr attr; 40578c68143SDavid Wang memset(&attr, 0, sizeof(attr)); 40678c68143SDavid Wang attr.type = PERF_TYPE_SOFTWARE; 40778c68143SDavid Wang attr.size = sizeof(attr); 40878c68143SDavid Wang attr.config = PERF_COUNT_SW_CPU_CLOCK; 40993979a5eSDavid Wang attr.sample_freq = 777; // adjust it 41078c68143SDavid Wang attr.freq = 1; 41193979a5eSDavid Wang attr.wakeup_events = 16; 41278c68143SDavid Wang attr.sample_type = PERF_SAMPLE_TID|PERF_SAMPLE_CALLCHAIN; 41378c68143SDavid Wang for (i=0, k=0; i<cpu_num&&i<MAXCPU; i++) { 41478c68143SDavid Wang printf("attaching cpu %d\n", i); 41578c68143SDavid Wang fd = perf_event_open(&attr, cgroup_id, i, -1, PERF_FLAG_FD_CLOEXEC|PERF_FLAG_PID_CGROUP); 41678c68143SDavid Wang if (fd<0) { perror("fail to open perf event"); continue; } 41778c68143SDavid Wang addr = mmap(NULL, (1+MAXN)*psize, PROT_READ, MAP_SHARED, fd, 0); 41878c68143SDavid Wang if (addr == MAP_FAILED) { perror("mmap failed"); close(fd); continue; } 41978c68143SDavid Wang res[fd] = make_pair(addr, 0); 42078c68143SDavid Wang polls[k].fd = fd; 42178c68143SDavid Wang polls[k].events = POLLIN; 42278c68143SDavid Wang polls[k].revents = 0; 42378c68143SDavid Wang k++; 42478c68143SDavid Wang } 42578c68143SDavid Wang if (k==0) { printf("no cpu event attached at all\n"); return 1; } 42678c68143SDavid Wang 42778c68143SDavid Wang signal(SIGINT, int_exit); 42878c68143SDavid Wang signal(SIGTERM, int_exit); 42978c68143SDavid Wang 43078c68143SDavid Wang unsigned long long head; 43193979a5eSDavid Wang int event_size; 43278c68143SDavid Wang struct perf_event_mmap_page *mp; 43378c68143SDavid Wang while (poll(polls, k, -1)>0) { 43478c68143SDavid Wang // printf("wake\n"); 43578c68143SDavid Wang for (i=0; i<k; i++) { 43678c68143SDavid Wang if ((polls[i].revents&POLLIN)==0) continue; 43778c68143SDavid Wang fd = polls[i].fd; 43878c68143SDavid Wang addr = res[fd].first; 43978c68143SDavid Wang mp = (struct perf_event_mmap_page *)addr; 44078c68143SDavid Wang head = res[fd].second; 44178c68143SDavid Wang ioctl(fd, PERF_EVENT_IOC_PAUSE_OUTPUT, 1); 44293979a5eSDavid Wang if (head>mp->data_head) head=mp->data_head; 44378c68143SDavid Wang head = mp->data_head-((mp->data_head-head)%mp->data_size); 44493979a5eSDavid Wang while(head<mp->data_head) { 44593979a5eSDavid Wang event_size = process_event((char*)addr+mp->data_offset, mp->data_size, head); 44693979a5eSDavid Wang if (event_size<0) { 44793979a5eSDavid Wang // resync 44893979a5eSDavid Wang head=mp->data_head; 44993979a5eSDavid Wang break; 45093979a5eSDavid Wang } 45193979a5eSDavid Wang head += event_size; 45293979a5eSDavid Wang } 45378c68143SDavid Wang res[fd].second = mp->data_head; 45493979a5eSDavid Wang ioctl(fd, PERF_EVENT_IOC_PAUSE_OUTPUT, 0); 45578c68143SDavid Wang } 45678c68143SDavid Wang } 45778c68143SDavid Wang 45878c68143SDavid Wang int_exit(0); 45978c68143SDavid Wang return 0; 46078c68143SDavid Wang } 461