1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
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 #include <chrono>
16 #include <cstdio>
17 #include <cstdlib>
18 #include <dlfcn.h>
19 #include <new>
20 #include <pthread.h>
21 #include <sys/syscall.h>
22 #include <unistd.h>
23 #include <thread>
24 #include <sys/prctl.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <vector>
29
30 #pragma clang optimize off
31
32 namespace {
33 constexpr int ARGC_NUM_MUST = 3;
34 constexpr int ARGC_WRITE_READ_TIMES = 2;
35 constexpr int BUF_SIZE = 512;
36 constexpr int FILE_MODE = 0644;
37 std::string DEFAULT_PATH("./");
38
39 class Timer {
40 public:
41 using Clock = std::chrono::steady_clock;
42 using TimePoint = Clock::time_point;
43
Timer()44 Timer() : startTime_(Now()) {}
45
~Timer()46 ~Timer() {}
47
ElapsedUs()48 long ElapsedUs()
49 {
50 auto currentTime = Now();
51 return std::chrono::duration_cast<std::chrono::microseconds>(currentTime - startTime_).count();
52 }
53
Reset()54 void Reset()
55 {
56 startTime_ = Now();
57 }
58
59 protected:
Now()60 static TimePoint Now()
61 {
62 return Clock::now();
63 }
64
65 private:
66 TimePoint startTime_;
67 };
68
69 static int g_sleepUs = 0;
CallStack1(const char * filename)70 void CallStack1(const char * filename)
71 {
72 int fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, FILE_MODE);
73 if (fd < 0) {
74 printf("NOTE Open file err: %s!\n", filename);
75 return ;
76 }
77 if (g_sleepUs) {
78 usleep(g_sleepUs);
79 }
80
81 std::vector<char> buf(BUF_SIZE * 2, 'a'); // 2: double
82 write(fd, buf.data(), buf.size());
83 fsync(fd);
84 if (g_sleepUs) {
85 usleep(g_sleepUs);
86 }
87
88 lseek(fd, 0, SEEK_SET);
89 read(fd, buf.data(), BUF_SIZE);
90 read(fd, buf.data(), BUF_SIZE);
91 if (g_sleepUs) {
92 usleep(g_sleepUs);
93 }
94
95 close(fd);
96 if (g_sleepUs) {
97 usleep(g_sleepUs);
98 }
99 }
CallStack0(const char * filename)100 void CallStack0(const char * filename)
101 {
102 CallStack1(filename);
103 }
104
ThreadFuncCpp(void * param)105 void* ThreadFuncCpp(void* param)
106 {
107 unsigned int idx = 0;
108 int threadNo = static_cast<int*>(param)[0];
109 int time = static_cast<int*>(param)[1];
110 long tid = syscall(SYS_gettid);
111
112 printf("start threadNo: %d , threadId: %ld\n", threadNo, tid);
113
114 std::string name = "thread";
115 name = name + std::to_string(threadNo);
116 prctl(PR_SET_NAME, name.c_str());
117 name = DEFAULT_PATH + name;
118 const auto startTime = std::chrono::steady_clock::now();
119 std::chrono::seconds timeOut{time};
120 const auto endTime = startTime + timeOut;
121
122 while (true) {
123 const auto thisTime = std::chrono::steady_clock::now();
124 if (thisTime >= endTime) {
125 break;
126 }
127
128 CallStack0(name.c_str());
129 idx++;
130 printf("%2d: Thread %ld file(%s) open,write,read,close %u times\n", threadNo, tid, name.c_str(), idx);
131 }
132
133 return nullptr;
134 }
135
ThreadTimeCost(int threadNum,int writeReadTime)136 long ThreadTimeCost(int threadNum, int writeReadTime)
137 {
138 Timer timer = {};
139 int idx;
140 int args[threadNum][2];
141
142 if (threadNum <= 0) {
143 printf("threadNum less than or equal to 0.\n");
144 return 1;
145 }
146
147 pthread_t* thrArray = new (std::nothrow) pthread_t[threadNum];
148 if (!thrArray) {
149 printf("new thread array failed.\n");
150 return 1;
151 }
152
153 for (idx = 0; idx < threadNum; ++idx) {
154 args[idx][0] = idx;
155 args[idx][1] = writeReadTime;
156 if (pthread_create(thrArray + idx, nullptr, ThreadFuncCpp, static_cast<void*>(args[idx])) != 0) {
157 printf("Creating thread failed.\n");
158 }
159 }
160
161 for (idx = 0; idx < threadNum; ++idx) {
162 pthread_join(thrArray[idx], nullptr);
163 }
164 delete []thrArray;
165
166 return timer.ElapsedUs();
167 }
168 } // namespace
169
main(int argc,char * argv[])170 int main(int argc, char *argv[])
171 {
172 int threadNum = 1;
173 int writeReadTime = 0;
174 if (argc >= ARGC_NUM_MUST) {
175 if (atoi(argv[1]) > 0) {
176 threadNum = atoi(argv[1]);
177 }
178 writeReadTime = atoi(argv[ARGC_WRITE_READ_TIMES]);
179 } else {
180 printf("Command error,Please input:thread Num, run seconds, sleep us\n");
181 return 0;
182 }
183 if (argc > ARGC_NUM_MUST) {
184 g_sleepUs = atoi(argv[3]); // 3: 4th argument
185 }
186
187 printf("Test start %d thread, read or write %d times\n", threadNum, writeReadTime);
188 printf("First isn't bpf hook.");
189
190 auto timeCost = ThreadTimeCost(threadNum, writeReadTime);
191 if (timeCost > 0) {
192 printf("Time cost %ld us.\n", timeCost);
193 } else {
194 printf("Test failure end!\n");
195 return 0;
196 }
197
198 return 0;
199 }
200
201 #pragma clang optimize on
202