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 <queue>
18 using namespace std;
19
20
21 #define error(msg) do { perror(msg); exit(1); } while(0)
22 #define MAXN 128
23
perf_event_open(struct perf_event_attr * perf_event,pid_t pid,int cpu,int group_fd,unsigned long flags)24 static long perf_event_open(struct perf_event_attr *perf_event, pid_t pid, int cpu, int group_fd, unsigned long flags) {
25 return syscall(__NR_perf_event_open, perf_event, pid, cpu, group_fd, flags);
26 }
27 static void *addr = NULL;
28 static int fd = -1;
29 static long long psize;
30 vector<int> res;
31 static unsigned long long cx_count=0, g_stime=0, g_total=0, g_rtotal=0;
32 int alive=1;
int_exit(int s)33 void int_exit(int s) {
34 for (auto x: res) close(x);
35 res.clear();
36 alive=0;
37 }
38
39
40
41 #define MAXCPU 1024
42 char buf[10240];
main(int argc,char * argv[])43 int main(int argc, char *argv[]) {
44 if (argc != 2) { printf("need pid\n"); return 1; }
45 int pid = atoi(argv[1]); if (pid<=0) { printf("invalid pid %s\n", argv[1]); return 1; }
46 // find cgroup
47 char xb[256], xb2[256];
48 int i, j, k;
49 sprintf(xb, "/proc/%d/cgroup", pid);
50 FILE* fp = fopen(xb, "r");
51 if (fp==NULL) error("fail to open cgroup file");
52 char *p;
53 xb2[0]=0;
54 int cgroup_name_len=0;
55 while(1) {
56 p = fgets(xb, sizeof(xb), fp); if (p==NULL) break;
57 i=0; while(p[i]&&p[i]!=':') i++; if (p[i]==0) continue;
58 if (strstr(p, "perf_event")) {
59 i++; while(p[i]!=':'&&p[i]) i++; if (p[i]!=':') continue; i++;
60 j=i; while(p[j]!='\r'&&p[j]!='\n'&&p[j]!=0) j++; p[j]=0;
61 sprintf(xb2, "/sys/fs/cgroup/perf_event%s", p+i);
62 cgroup_name_len=j-i;
63 break;
64 } else if (p[i+1]==':') {
65 i+=2; j=i; while(p[j]!='\r'&&p[j]!='\n'&&p[j]!=0) j++; p[j]=0;
66 sprintf(xb2, "/sys/fs/cgroup/%s", p+i);
67 cgroup_name_len=j-i;
68 }
69 }
70 fclose(fp);
71 if (xb2[0]==0) error("no proper cgroup found\n");
72 if (cgroup_name_len<2) {
73 printf("cgroup %s seems to be root, not allowed\n", xb2);
74 return -1;
75 }
76
77 printf("try to use cgroup %s\n", xb2);
78 int cgroup_id = open(xb2, O_CLOEXEC);
79 if (cgroup_id<=0) { perror("error open cgroup dir"); return 1; }
80
81 // start perf event
82 psize = sysconf(_SC_PAGE_SIZE); // getpagesize();
83 int cpu_num = sysconf(_SC_NPROCESSORS_ONLN);
84 struct perf_event_attr attr;
85 memset(&attr, 0, sizeof(attr));
86 attr.type = PERF_TYPE_SOFTWARE;
87 attr.size = sizeof(attr);
88 attr.sample_period = 1;
89 attr.wakeup_events = 1;
90 attr.config = PERF_COUNT_SW_PAGE_FAULTS_MAJ;
91 for (i=0, k=0; i<cpu_num&&i<MAXCPU; i++) {
92 printf("attaching cpu %d\n", i);
93 fd = perf_event_open(&attr, cgroup_id, i, -1, PERF_FLAG_FD_CLOEXEC|PERF_FLAG_PID_CGROUP);
94 if (fd<0) { perror("fail to open perf event"); continue; }
95 res.push_back(fd);
96 }
97 if (res.size()==0) { printf("no cpu event attached at all\n"); return 1; }
98
99 signal(SIGINT, int_exit);
100 signal(SIGTERM, int_exit);
101
102 unsigned long long counter;
103 while(alive) {
104 sleep(1);
105 counter = 0;
106 for (auto x:res) {
107 k = read(x, buf, sizeof(buf));
108 if (k>=8) {
109 counter += *(unsigned long long *)buf;
110 }
111 if (k<0) perror("fail to read");
112 }
113 printf("counter --> %lld\n", counter);
114 }
115
116
117 int_exit(0);
118 return 0;
119 }
120