1484543d1Sopenharmony_ci/*
2484543d1Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
3484543d1Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4484543d1Sopenharmony_ci * you may not use this file except in compliance with the License.
5484543d1Sopenharmony_ci * You may obtain a copy of the License at
6484543d1Sopenharmony_ci *
7484543d1Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8484543d1Sopenharmony_ci *
9484543d1Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10484543d1Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11484543d1Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12484543d1Sopenharmony_ci * See the License for the specific language governing permissions and
13484543d1Sopenharmony_ci * limitations under the License.
14484543d1Sopenharmony_ci */
15484543d1Sopenharmony_ci
16484543d1Sopenharmony_ci#include "util.h"
17484543d1Sopenharmony_ci#include <unistd.h>
18484543d1Sopenharmony_ci#include <cstring>
19484543d1Sopenharmony_ci#include <iostream>
20484543d1Sopenharmony_ci#include <functional>
21484543d1Sopenharmony_ci#include <sys/syscall.h>
22484543d1Sopenharmony_ci#include <sys/ioctl.h>
23484543d1Sopenharmony_ci#include <sched.h>
24484543d1Sopenharmony_ci#include <pthread.h>
25484543d1Sopenharmony_ci#include <linux/perf_event.h>
26484543d1Sopenharmony_ci#include "internal_inc/osal.h"
27484543d1Sopenharmony_ci
28484543d1Sopenharmony_ciusing namespace std;
29484543d1Sopenharmony_ci
30484543d1Sopenharmony_ciconstexpr uint32_t PROC_STATUS_LINE_NUM_MAX = 50;
31484543d1Sopenharmony_ci
32484543d1Sopenharmony_ciuint32_t get_proc_memory(pid_t pid)
33484543d1Sopenharmony_ci{
34484543d1Sopenharmony_ci    FILE* fd;
35484543d1Sopenharmony_ci    char line[1024] = {0};
36484543d1Sopenharmony_ci    char node_name[64] = {0};
37484543d1Sopenharmony_ci    char vmrss_name[32] = {0};
38484543d1Sopenharmony_ci    uint32_t vmrss_num = 0;
39484543d1Sopenharmony_ci    sprintf(node_name, "/proc/%d/status", pid);
40484543d1Sopenharmony_ci    fd = fopen(node_name, "r");
41484543d1Sopenharmony_ci    if (fd == nullptr) {
42484543d1Sopenharmony_ci        cout << "open " << node_name << " failed" << endl;
43484543d1Sopenharmony_ci        return 0;
44484543d1Sopenharmony_ci    }
45484543d1Sopenharmony_ci
46484543d1Sopenharmony_ci    // VmRSS line is uncertain
47484543d1Sopenharmony_ci    for (int i = 0; i < PROC_STATUS_LINE_NUM_MAX; i++) {
48484543d1Sopenharmony_ci        if (fgets(line, sizeof(line), fd) == nullptr) {
49484543d1Sopenharmony_ci            break;
50484543d1Sopenharmony_ci        }
51484543d1Sopenharmony_ci        if (strstr(line, "VmRSS:") != nullptr) {
52484543d1Sopenharmony_ci            sscanf(line, "%s %d", vmrss_name, &vmrss_num);
53484543d1Sopenharmony_ci            break;
54484543d1Sopenharmony_ci        }
55484543d1Sopenharmony_ci    }
56484543d1Sopenharmony_ci    fclose(fd);
57484543d1Sopenharmony_ci    return vmrss_num;
58484543d1Sopenharmony_ci}
59484543d1Sopenharmony_civoid set_cur_process_cpu_affinity(int cpuid)
60484543d1Sopenharmony_ci{
61484543d1Sopenharmony_ci    cpu_set_t mask;
62484543d1Sopenharmony_ci    CPU_ZERO(&mask);
63484543d1Sopenharmony_ci    CPU_SET(cpuid, &mask);
64484543d1Sopenharmony_ci    if (sched_setaffinity(0, sizeof(mask), &mask) == -1) {
65484543d1Sopenharmony_ci        printf("warning:could not set cpu affinity\n");
66484543d1Sopenharmony_ci    }
67484543d1Sopenharmony_ci    cpu_set_t affinity;
68484543d1Sopenharmony_ci    CPU_ZERO(&affinity);
69484543d1Sopenharmony_ci    if (sched_getaffinity(0, sizeof(affinity), &affinity) == -1) {
70484543d1Sopenharmony_ci        printf("warning:could not get cpu affinity\n");
71484543d1Sopenharmony_ci        return;
72484543d1Sopenharmony_ci    }
73484543d1Sopenharmony_ci    int cpu_num = sysconf(_SC_NPROCESSORS_CONF);
74484543d1Sopenharmony_ci    printf("cpu_num:%d\n", cpu_num);
75484543d1Sopenharmony_ci    for (int i = 0; i < cpu_num; i++) {
76484543d1Sopenharmony_ci        if (CPU_ISSET(i, &affinity)) {
77484543d1Sopenharmony_ci            printf("this process is running on cpu:%d\n", i);
78484543d1Sopenharmony_ci        }
79484543d1Sopenharmony_ci    }
80484543d1Sopenharmony_ci}
81484543d1Sopenharmony_ci#if (defined FFRT_SUPPORT_AOS)
82484543d1Sopenharmony_civoid set_cur_thread_cpu_affinity(int cpuid)
83484543d1Sopenharmony_ci{
84484543d1Sopenharmony_ci    cpu_set_t mask;
85484543d1Sopenharmony_ci    CPU_ZERO(&mask);
86484543d1Sopenharmony_ci    CPU_SET(cpuid, &mask);
87484543d1Sopenharmony_ci    int ret = syscall(__NR_sched_setaffinity, gettid(), sizeof(mask), &mask);
88484543d1Sopenharmony_ci    if (ret != 0) {
89484543d1Sopenharmony_ci        printf("warning:could not set cpu affinity\n");
90484543d1Sopenharmony_ci        return;
91484543d1Sopenharmony_ci    }
92484543d1Sopenharmony_ci    printf("this thread:%u is running on cpu:%d\n", GetTid(), cpuid);
93484543d1Sopenharmony_ci}
94484543d1Sopenharmony_ci#else
95484543d1Sopenharmony_civoid set_cur_thread_cpu_affinity(int cpuid)
96484543d1Sopenharmony_ci{
97484543d1Sopenharmony_ci    cpu_set_t mask;
98484543d1Sopenharmony_ci    CPU_ZERO(&mask);
99484543d1Sopenharmony_ci    CPU_SET(cpuid, &mask);
100484543d1Sopenharmony_ci    if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) == -1) {
101484543d1Sopenharmony_ci        printf("warning:could not set cpu affinity\n");
102484543d1Sopenharmony_ci    }
103484543d1Sopenharmony_ci    cpu_set_t affinity;
104484543d1Sopenharmony_ci    CPU_ZERO(&affinity);
105484543d1Sopenharmony_ci    if (pthread_getaffinity_np(pthread_self(), sizeof(affinity), &affinity) == -1) {
106484543d1Sopenharmony_ci        printf("warning:could not get cpu affinity\n");
107484543d1Sopenharmony_ci        return;
108484543d1Sopenharmony_ci    }
109484543d1Sopenharmony_ci    int cpu_num = sysconf(_SC_NPROCESSORS_CONF);
110484543d1Sopenharmony_ci    printf("cpu_num:%d\n", cpu_num);
111484543d1Sopenharmony_ci    for (int i = 0; i < cpu_num; i++) {
112484543d1Sopenharmony_ci        if (CPU_ISSET(i, &affinity)) {
113484543d1Sopenharmony_ci            printf("this thread:%d is running on cpu:%d\n", GetTid(), i);
114484543d1Sopenharmony_ci        }
115484543d1Sopenharmony_ci    }
116484543d1Sopenharmony_ci}
117484543d1Sopenharmony_ci#endif
118484543d1Sopenharmony_ci
119484543d1Sopenharmony_ci#ifdef FFRT_PERF_EVENT_ENABLE
120484543d1Sopenharmony_cistatic int perf_event_open(struct perf_event_attr* attr, pid_t pid, int cpu, int group_fd, unsigned long flags)
121484543d1Sopenharmony_ci{
122484543d1Sopenharmony_ci    return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
123484543d1Sopenharmony_ci}
124484543d1Sopenharmony_ci
125484543d1Sopenharmony_ci//  sudo perf stat -e instructions:u ./test_main
126484543d1Sopenharmony_ciint perf_single_event(std::function<void()> func, size_t& count, uint32_t event)
127484543d1Sopenharmony_ci{
128484543d1Sopenharmony_ci    int fd;
129484543d1Sopenharmony_ci    struct perf_event_attr attr = {};
130484543d1Sopenharmony_ci    attr.type = PERF_TYPE_HARDWARE;
131484543d1Sopenharmony_ci    attr.size = sizeof(struct perf_event_attr);
132484543d1Sopenharmony_ci    attr.config = event;
133484543d1Sopenharmony_ci    attr.disabled = 1;
134484543d1Sopenharmony_ci    attr.exclude_kernel = 1; // ignore kernel
135484543d1Sopenharmony_ci    attr.exclude_hv = 1; // ignore hyper-visior
136484543d1Sopenharmony_ci
137484543d1Sopenharmony_ci    // pid=0,cpu=-1 current process, all cpu
138484543d1Sopenharmony_ci    fd = perf_event_open(&attr, 0, -1, -1, 0);
139484543d1Sopenharmony_ci    if (fd == -1) {
140484543d1Sopenharmony_ci        printf("perf_event_open fail! errno:%d %s\n", errno, strerror(errno));
141484543d1Sopenharmony_ci        return -1;
142484543d1Sopenharmony_ci    }
143484543d1Sopenharmony_ci    ioctl(fd, PERF_EVENT_IOC_RESET, 0); // reset counter
144484543d1Sopenharmony_ci    ioctl(fd, PERF_EVENT_IOC_ENABLE, 0); // start count
145484543d1Sopenharmony_ci    func();
146484543d1Sopenharmony_ci    size_t rcount = read(fd, &count, sizeof(count));
147484543d1Sopenharmony_ci    if (rcount < sizeof(count)) {
148484543d1Sopenharmony_ci        printf("perf data read fail! errno:%d %s\n", errno, strerror(errno));
149484543d1Sopenharmony_ci        return -1;
150484543d1Sopenharmony_ci    }
151484543d1Sopenharmony_ci    ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
152484543d1Sopenharmony_ci    close(fd);
153484543d1Sopenharmony_ci    return 0;
154484543d1Sopenharmony_ci}
155484543d1Sopenharmony_ci
156484543d1Sopenharmony_ciint perf_event2(std::function<void()> func, struct perf_event2_read_format& data, uint32_t event1, uint32_t event2)
157484543d1Sopenharmony_ci{
158484543d1Sopenharmony_ci    int fd;
159484543d1Sopenharmony_ci    struct perf_event_attr attr = {};
160484543d1Sopenharmony_ci    attr.type = PERF_TYPE_HARDWARE;
161484543d1Sopenharmony_ci    attr.size = sizeof(struct perf_event_attr);
162484543d1Sopenharmony_ci    attr.config = event1;
163484543d1Sopenharmony_ci    attr.disabled = 1;
164484543d1Sopenharmony_ci    attr.exclude_kernel = 1;
165484543d1Sopenharmony_ci    attr.exclude_hv = 1;
166484543d1Sopenharmony_ci    attr.read_format = PERF_FORMAT_GROUP;
167484543d1Sopenharmony_ci
168484543d1Sopenharmony_ci    // pid=0,cpu=-1 current process, all cpu
169484543d1Sopenharmony_ci    fd = perf_event_open(&attr, 0, -1, -1, 0);
170484543d1Sopenharmony_ci    if (fd == -1) {
171484543d1Sopenharmony_ci        printf("perf_event_open fail! errno:%d %s\n", errno, strerror(errno));
172484543d1Sopenharmony_ci        return -1;
173484543d1Sopenharmony_ci    }
174484543d1Sopenharmony_ci    attr = {0};
175484543d1Sopenharmony_ci    attr.type = PERF_TYPE_HARDWARE;
176484543d1Sopenharmony_ci    attr.size = sizeof(struct perf_event_attr);
177484543d1Sopenharmony_ci    attr.config = event2;
178484543d1Sopenharmony_ci    attr.disabled = 1;
179484543d1Sopenharmony_ci    attr.exclude_kernel = 1;
180484543d1Sopenharmony_ci    attr.exclude_hv = 1;
181484543d1Sopenharmony_ci    attr.read_format = PERF_FORMAT_GROUP;
182484543d1Sopenharmony_ci    int fd2 = perf_event_open(&attr, 0, -1, fd, 0);
183484543d1Sopenharmony_ci    if (fd2 == -1) {
184484543d1Sopenharmony_ci        printf("perf_event_open fail! errno:%d %s\n", errno, strerror(errno));
185484543d1Sopenharmony_ci        return -1;
186484543d1Sopenharmony_ci    }
187484543d1Sopenharmony_ci    ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP);
188484543d1Sopenharmony_ci
189484543d1Sopenharmony_ci    ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP);
190484543d1Sopenharmony_ci
191484543d1Sopenharmony_ci    func();
192484543d1Sopenharmony_ci    size_t rcount = read(fd, &data, sizeof(struct perf_event2_read_format));
193484543d1Sopenharmony_ci    if (rcount < sizeof(struct perf_event2_read_format)) {
194484543d1Sopenharmony_ci        printf("perf data read fail! errno:%d %s\n", errno, strerror(errno));
195484543d1Sopenharmony_ci        return -1;
196484543d1Sopenharmony_ci    }
197484543d1Sopenharmony_ci
198484543d1Sopenharmony_ci    ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP);
199484543d1Sopenharmony_ci    close(fd);
200484543d1Sopenharmony_ci    close(fd2);
201484543d1Sopenharmony_ci    return 0;
202484543d1Sopenharmony_ci}
203484543d1Sopenharmony_ci
204484543d1Sopenharmony_ciint perf_event_instructions(std::function<void()> func, size_t& count)
205484543d1Sopenharmony_ci{
206484543d1Sopenharmony_ci    return perf_single_event(func, count, PERF_COUNT_HW_INSTRUCTIONS);
207484543d1Sopenharmony_ci}
208484543d1Sopenharmony_ciint perf_event_cycles(std::function<void()> func, size_t& count)
209484543d1Sopenharmony_ci{
210484543d1Sopenharmony_ci    return perf_single_event(func, count, PERF_COUNT_HW_CPU_CYCLES);
211484543d1Sopenharmony_ci}
212484543d1Sopenharmony_ciint perf_event_branch_instructions(std::function<void()> func, size_t& count)
213484543d1Sopenharmony_ci{
214484543d1Sopenharmony_ci    return perf_single_event(func, count, PERF_COUNT_HW_BRANCH_INSTRUCTIONS);
215484543d1Sopenharmony_ci}
216484543d1Sopenharmony_ciint perf_event_branch_misses(std::function<void()> func, size_t& count)
217484543d1Sopenharmony_ci{
218484543d1Sopenharmony_ci    return perf_single_event(func, count, PERF_COUNT_HW_BRANCH_MISSES);
219484543d1Sopenharmony_ci}
220484543d1Sopenharmony_ci
221484543d1Sopenharmony_ci#else
222484543d1Sopenharmony_ciint perf_event_instructions(std::function<void()> func, size_t& count)
223484543d1Sopenharmony_ci{
224484543d1Sopenharmony_ci    func();
225484543d1Sopenharmony_ci    count = 0;
226484543d1Sopenharmony_ci    return 0;
227484543d1Sopenharmony_ci}
228484543d1Sopenharmony_ci
229484543d1Sopenharmony_ciint perf_event_cycles(std::function<void()> func, size_t& count)
230484543d1Sopenharmony_ci{
231484543d1Sopenharmony_ci    func();
232484543d1Sopenharmony_ci    count = 0;
233484543d1Sopenharmony_ci    return 0;
234484543d1Sopenharmony_ci}
235484543d1Sopenharmony_ci
236484543d1Sopenharmony_ciint perf_event_branch_instructions(std::function<void()> func, size_t& count)
237484543d1Sopenharmony_ci{
238484543d1Sopenharmony_ci    func();
239484543d1Sopenharmony_ci    count = 0;
240484543d1Sopenharmony_ci    return 0;
241484543d1Sopenharmony_ci}
242484543d1Sopenharmony_ci
243484543d1Sopenharmony_ciint perf_event_branch_misses(std::function<void()> func, size_t& count)
244484543d1Sopenharmony_ci{
245484543d1Sopenharmony_ci    func();
246484543d1Sopenharmony_ci    count = 0;
247484543d1Sopenharmony_ci    return 0;
248484543d1Sopenharmony_ci}
249484543d1Sopenharmony_ci#endif