xref: /linux-tools/perf/pagefault/perf_pagefault.cpp (revision 1e38ed8497ebb85cc1cfea52fd4338fc824c896e)
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