1 #include <stdlib.h> 2 #include <stdio.h> 3 #include <unistd.h> 4 #include <string.h> 5 #include <sys/ioctl.h> 6 #include <linux/perf_event.h> 7 #include <asm/unistd.h> 8 #include <sys/mman.h> 9 #include <sys/stat.h> 10 #include <poll.h> 11 #include <signal.h> 12 #include <fcntl.h> 13 14 15 #include <map> 16 #include <unordered_set> 17 #include <unordered_map> 18 #include <queue> 19 using namespace std; 20 21 22 #define error(msg) do { perror(msg); exit(1); } while(0) 23 #define MAXN 128 24 25 static long perf_event_open(struct perf_event_attr *perf_event, pid_t pid, int cpu, int group_fd, unsigned long flags) { 26 return syscall(__NR_perf_event_open, perf_event, pid, cpu, group_fd, flags); 27 } 28 static void *addr = NULL; 29 static long long psize; 30 map<int, pair<void*, long long>> res; 31 static unsigned long long cx_count=0, g_stime=0, g_total=0, g_rtotal=0; 32 static int alive=1; 33 void int_exit(int s) { 34 for (auto x: res) { 35 auto y = x.second; 36 void* addr = y.first; 37 munmap(addr, (1+MAXN)*psize); 38 close(x.first); 39 } 40 res.clear(); 41 alive=0; 42 } 43 44 unordered_map<int, string> hostnames; 45 unordered_map<int, string> commands; 46 queue<int> pids; 47 char bb[256]; 48 int get_hostname(int pid) { 49 sprintf(bb, "/proc/%d/root/etc/hostname", pid); 50 FILE* fp = fopen(bb, "r"); 51 int i=0; 52 if (fp) { 53 fgets(bb, sizeof(bb), fp); 54 while(i<sizeof(bb)-1&&bb[i]&&bb[i]!='\r'&&bb[i]!='\n') i++; bb[i]=0; 55 fclose(fp); 56 } 57 return i; 58 } 59 60 int process_event(char *base, unsigned long long size, unsigned long long offset) { 61 struct perf_event_header* p = NULL; 62 int pid, i, j, ppid; 63 offset%=size; 64 // assuming the header would fit within size 65 p = (struct perf_event_header*) (base+offset); 66 offset+=sizeof(*p); if (offset>=size) offset-=size; 67 if (p->type == PERF_RECORD_FORK) { 68 pid = *(int*)(base+offset); 69 ppid = *(int*)(base+offset+4); 70 if (hostnames.count(pid)==0&&get_hostname(ppid)) hostnames[pid] =string(bb); 71 } else if (p->type == PERF_RECORD_COMM) { 72 pid = *(int*)(base+offset); 73 offset+=8; if (offset>=size) offset-=size; 74 i=offset; 75 for (j=0; j<sizeof(bb)-1; j++) { 76 if (base[i]==0) break; 77 bb[j]=base[i]; 78 i++; if (i>=size) i-=size; 79 } bb[j]=0; 80 commands[pid] = string(bb); 81 if (hostnames.count(pid)==0&&get_hostname(pid)) hostnames[pid] = string(bb); 82 pids.push(pid); 83 } else if (p->type == PERF_RECORD_EXIT) { 84 pid = *(int*)(base+offset); 85 ppid = *(int*)(base+offset+4); 86 if (hostnames.count(pid)==0&&get_hostname(ppid)) hostnames[pid] =string(bb); 87 pids.push(-pid); 88 } 89 return p->size; 90 } 91 92 void process_queue() { 93 int pid; 94 while(!pids.empty()) { 95 pid=pids.front(); pids.pop(); 96 if (pid>0) { 97 if (commands.count(pid)==0) continue; 98 if (hostnames.count(pid)==0&&get_hostname(pid)) hostnames[pid]=string(bb); 99 if (hostnames.count(pid)==0) { 100 printf("<--?--> start command [%s](%d)\n", commands[pid].c_str(), pid); 101 } else { 102 printf("<%s> start command [%s](%d)\n", hostnames[pid].c_str(), commands[pid].c_str(), pid); 103 } 104 } else { 105 pid=-pid; 106 if (commands.count(pid)) { 107 if (hostnames.count(pid)==0) { 108 printf("<--?--> stop command [%s](%d)\n", commands[pid].c_str(), pid); 109 } else { 110 printf("<%s> stop command [%s](%d)\n", hostnames[pid].c_str(), commands[pid].c_str(), pid); 111 } 112 commands.erase(pid); 113 } 114 if (hostnames.count(pid)) hostnames.erase(pid); 115 } 116 } 117 fflush(stdout); 118 } 119 120 #define MAXCPU 1024 121 struct pollfd polls[MAXCPU]; 122 int main(int argc, char *argv[]) { 123 int i, k; 124 // start perf event 125 psize = sysconf(_SC_PAGE_SIZE); // getpagesize(); 126 int cpu_num = sysconf(_SC_NPROCESSORS_ONLN); 127 struct perf_event_attr attr; 128 memset(&attr, 0, sizeof(attr)); 129 attr.type = PERF_TYPE_SOFTWARE; 130 attr.size = sizeof(attr); 131 attr.config = PERF_COUNT_SW_DUMMY; 132 // attr.sample_period = 1; 133 // attr.wakeup_events = 1; 134 attr.comm = 1; 135 // attr.comm_exec = 1; 136 attr.sample_id_all = 1; 137 attr.task = 1; 138 int fd, cgroup_fd; 139 for (i=0, k=0; i<cpu_num&&i<MAXCPU; i++) { 140 printf("attaching cpu %d\n", i); 141 fd = perf_event_open(&attr, -1, i, -1, PERF_FLAG_FD_CLOEXEC); 142 if (fd<0) { perror("fail to open perf event"); continue; } 143 addr = mmap(NULL, (1+MAXN)*psize, PROT_READ, MAP_SHARED, fd, 0); 144 if (addr == MAP_FAILED) { perror("mmap failed"); close(fd); continue; } 145 res[fd] = make_pair(addr, 0); 146 k++; 147 } 148 if (k==0) { printf("no cpu event attached at all\n"); return 1; } 149 150 signal(SIGINT, int_exit); 151 signal(SIGTERM, int_exit); 152 153 unsigned long long head; 154 struct perf_event_mmap_page *mp; 155 while(alive) { 156 process_queue(); 157 sleep(1); 158 for (auto x: res) { 159 addr = x.second.first; 160 head = x.second.second; 161 mp = (struct perf_event_mmap_page *)addr; 162 fd = x.first; 163 if (head >= mp->data_head) continue; 164 ioctl(fd, PERF_EVENT_IOC_PAUSE_OUTPUT, 1); 165 head = mp->data_head-((mp->data_head-head)%mp->data_size); 166 while(head<mp->data_head) head+=process_event((char*)addr+mp->data_offset, mp->data_size, head); 167 res[fd].second = mp->data_head; 168 ioctl(fd, PERF_EVENT_IOC_PAUSE_OUTPUT, 0); 169 } 170 } 171 int_exit(0); 172 return 0; 173 } 174