• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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