1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "util.h"
17 #include <unistd.h>
18 #include <cstring>
19 #include <iostream>
20 #include <functional>
21 #include <sys/syscall.h>
22 #include <sys/ioctl.h>
23 #include <sched.h>
24 #include <pthread.h>
25 #include <linux/perf_event.h>
26 #include "internal_inc/osal.h"
27 
28 using namespace std;
29 
30 constexpr uint32_t PROC_STATUS_LINE_NUM_MAX = 50;
31 
get_proc_memory(pid_t pid)32 uint32_t get_proc_memory(pid_t pid)
33 {
34     FILE* fd;
35     char line[1024] = {0};
36     char node_name[64] = {0};
37     char vmrss_name[32] = {0};
38     uint32_t vmrss_num = 0;
39     sprintf(node_name, "/proc/%d/status", pid);
40     fd = fopen(node_name, "r");
41     if (fd == nullptr) {
42         cout << "open " << node_name << " failed" << endl;
43         return 0;
44     }
45 
46     // VmRSS line is uncertain
47     for (int i = 0; i < PROC_STATUS_LINE_NUM_MAX; i++) {
48         if (fgets(line, sizeof(line), fd) == nullptr) {
49             break;
50         }
51         if (strstr(line, "VmRSS:") != nullptr) {
52             sscanf(line, "%s %d", vmrss_name, &vmrss_num);
53             break;
54         }
55     }
56     fclose(fd);
57     return vmrss_num;
58 }
set_cur_process_cpu_affinity(int cpuid)59 void set_cur_process_cpu_affinity(int cpuid)
60 {
61     cpu_set_t mask;
62     CPU_ZERO(&mask);
63     CPU_SET(cpuid, &mask);
64     if (sched_setaffinity(0, sizeof(mask), &mask) == -1) {
65         printf("warning:could not set cpu affinity\n");
66     }
67     cpu_set_t affinity;
68     CPU_ZERO(&affinity);
69     if (sched_getaffinity(0, sizeof(affinity), &affinity) == -1) {
70         printf("warning:could not get cpu affinity\n");
71         return;
72     }
73     int cpu_num = sysconf(_SC_NPROCESSORS_CONF);
74     printf("cpu_num:%d\n", cpu_num);
75     for (int i = 0; i < cpu_num; i++) {
76         if (CPU_ISSET(i, &affinity)) {
77             printf("this process is running on cpu:%d\n", i);
78         }
79     }
80 }
81 #if (defined FFRT_SUPPORT_AOS)
set_cur_thread_cpu_affinity(int cpuid)82 void set_cur_thread_cpu_affinity(int cpuid)
83 {
84     cpu_set_t mask;
85     CPU_ZERO(&mask);
86     CPU_SET(cpuid, &mask);
87     int ret = syscall(__NR_sched_setaffinity, gettid(), sizeof(mask), &mask);
88     if (ret != 0) {
89         printf("warning:could not set cpu affinity\n");
90         return;
91     }
92     printf("this thread:%u is running on cpu:%d\n", GetTid(), cpuid);
93 }
94 #else
set_cur_thread_cpu_affinity(int cpuid)95 void set_cur_thread_cpu_affinity(int cpuid)
96 {
97     cpu_set_t mask;
98     CPU_ZERO(&mask);
99     CPU_SET(cpuid, &mask);
100     if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) == -1) {
101         printf("warning:could not set cpu affinity\n");
102     }
103     cpu_set_t affinity;
104     CPU_ZERO(&affinity);
105     if (pthread_getaffinity_np(pthread_self(), sizeof(affinity), &affinity) == -1) {
106         printf("warning:could not get cpu affinity\n");
107         return;
108     }
109     int cpu_num = sysconf(_SC_NPROCESSORS_CONF);
110     printf("cpu_num:%d\n", cpu_num);
111     for (int i = 0; i < cpu_num; i++) {
112         if (CPU_ISSET(i, &affinity)) {
113             printf("this thread:%d is running on cpu:%d\n", GetTid(), i);
114         }
115     }
116 }
117 #endif
118 
119 #ifdef FFRT_PERF_EVENT_ENABLE
perf_event_open(struct perf_event_attr * attr,pid_t pid,int cpu,int group_fd,unsigned long flags)120 static int perf_event_open(struct perf_event_attr* attr, pid_t pid, int cpu, int group_fd, unsigned long flags)
121 {
122     return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
123 }
124 
125 //  sudo perf stat -e instructions:u ./test_main
perf_single_event(std::function<void ()> func,size_t & count,uint32_t event)126 int perf_single_event(std::function<void()> func, size_t& count, uint32_t event)
127 {
128     int fd;
129     struct perf_event_attr attr = {};
130     attr.type = PERF_TYPE_HARDWARE;
131     attr.size = sizeof(struct perf_event_attr);
132     attr.config = event;
133     attr.disabled = 1;
134     attr.exclude_kernel = 1; // ignore kernel
135     attr.exclude_hv = 1; // ignore hyper-visior
136 
137     // pid=0,cpu=-1 current process, all cpu
138     fd = perf_event_open(&attr, 0, -1, -1, 0);
139     if (fd == -1) {
140         printf("perf_event_open fail! errno:%d %s\n", errno, strerror(errno));
141         return -1;
142     }
143     ioctl(fd, PERF_EVENT_IOC_RESET, 0); // reset counter
144     ioctl(fd, PERF_EVENT_IOC_ENABLE, 0); // start count
145     func();
146     size_t rcount = read(fd, &count, sizeof(count));
147     if (rcount < sizeof(count)) {
148         printf("perf data read fail! errno:%d %s\n", errno, strerror(errno));
149         return -1;
150     }
151     ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
152     close(fd);
153     return 0;
154 }
155 
perf_event2(std::function<void ()> func,struct perf_event2_read_format & data,uint32_t event1,uint32_t event2)156 int perf_event2(std::function<void()> func, struct perf_event2_read_format& data, uint32_t event1, uint32_t event2)
157 {
158     int fd;
159     struct perf_event_attr attr = {};
160     attr.type = PERF_TYPE_HARDWARE;
161     attr.size = sizeof(struct perf_event_attr);
162     attr.config = event1;
163     attr.disabled = 1;
164     attr.exclude_kernel = 1;
165     attr.exclude_hv = 1;
166     attr.read_format = PERF_FORMAT_GROUP;
167 
168     // pid=0,cpu=-1 current process, all cpu
169     fd = perf_event_open(&attr, 0, -1, -1, 0);
170     if (fd == -1) {
171         printf("perf_event_open fail! errno:%d %s\n", errno, strerror(errno));
172         return -1;
173     }
174     attr = {0};
175     attr.type = PERF_TYPE_HARDWARE;
176     attr.size = sizeof(struct perf_event_attr);
177     attr.config = event2;
178     attr.disabled = 1;
179     attr.exclude_kernel = 1;
180     attr.exclude_hv = 1;
181     attr.read_format = PERF_FORMAT_GROUP;
182     int fd2 = perf_event_open(&attr, 0, -1, fd, 0);
183     if (fd2 == -1) {
184         printf("perf_event_open fail! errno:%d %s\n", errno, strerror(errno));
185         return -1;
186     }
187     ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP);
188 
189     ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP);
190 
191     func();
192     size_t rcount = read(fd, &data, sizeof(struct perf_event2_read_format));
193     if (rcount < sizeof(struct perf_event2_read_format)) {
194         printf("perf data read fail! errno:%d %s\n", errno, strerror(errno));
195         return -1;
196     }
197 
198     ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP);
199     close(fd);
200     close(fd2);
201     return 0;
202 }
203 
perf_event_instructions(std::function<void ()> func,size_t & count)204 int perf_event_instructions(std::function<void()> func, size_t& count)
205 {
206     return perf_single_event(func, count, PERF_COUNT_HW_INSTRUCTIONS);
207 }
perf_event_cycles(std::function<void ()> func,size_t & count)208 int perf_event_cycles(std::function<void()> func, size_t& count)
209 {
210     return perf_single_event(func, count, PERF_COUNT_HW_CPU_CYCLES);
211 }
perf_event_branch_instructions(std::function<void ()> func,size_t & count)212 int perf_event_branch_instructions(std::function<void()> func, size_t& count)
213 {
214     return perf_single_event(func, count, PERF_COUNT_HW_BRANCH_INSTRUCTIONS);
215 }
perf_event_branch_misses(std::function<void ()> func,size_t & count)216 int perf_event_branch_misses(std::function<void()> func, size_t& count)
217 {
218     return perf_single_event(func, count, PERF_COUNT_HW_BRANCH_MISSES);
219 }
220 
221 #else
perf_event_instructions(std::function<void ()> func,size_t & count)222 int perf_event_instructions(std::function<void()> func, size_t& count)
223 {
224     func();
225     count = 0;
226     return 0;
227 }
228 
perf_event_cycles(std::function<void ()> func,size_t & count)229 int perf_event_cycles(std::function<void()> func, size_t& count)
230 {
231     func();
232     count = 0;
233     return 0;
234 }
235 
perf_event_branch_instructions(std::function<void ()> func,size_t & count)236 int perf_event_branch_instructions(std::function<void()> func, size_t& count)
237 {
238     func();
239     count = 0;
240     return 0;
241 }
242 
perf_event_branch_misses(std::function<void ()> func,size_t & count)243 int perf_event_branch_misses(std::function<void()> func, size_t& count)
244 {
245     func();
246     count = 0;
247     return 0;
248 }
249 #endif