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
perf_event_open(struct perf_event_attr * perf_event,pid_t pid,int cpu,int group_fd,unsigned long flags)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;
int_exit(int s)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];
get_hostname(int pid)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
process_event(char * base,unsigned long long size,unsigned long long offset)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
process_queue()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];
main(int argc,char * argv[])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