• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 #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 
26 #pragma clang optimize off
27 
28 namespace {
29 typedef char* (*DepthMallocSo)(int depth, int mallocSize);
30 typedef void (*DepthFreeSo)(int depth, char *p);
31 constexpr int MALLOC_SIZE = 1000;
32 constexpr int DATA_SIZE = 200;
33 constexpr int SLEEP_TIME = 200;
34 constexpr int ARGC_NUM_MAX = 4;
35 constexpr int ARGC_NUM_MUST = 3;
36 constexpr int ARGC_MALLOC_TIMES = 2;
37 constexpr int ARGC_STICK_DEPTH = 3;
38 unsigned int g_stickDepth = 100;
39 
40 const static char SO_PATH[] = "libnativetest_so.z.so";
41 using StaticSpace = struct {
42     int data[DATA_SIZE];
43 };
44 
45 class Timer {
46 public:
47     using Clock = std::chrono::steady_clock;
48     using TimePoint = Clock::time_point;
49 
Timer()50     Timer() : startTime_(Now()) {}
51 
~Timer()52     ~Timer() {}
53 
ElapsedUs()54     long ElapsedUs()
55     {
56         auto currentTime = Now();
57         return std::chrono::duration_cast<std::chrono::microseconds>(currentTime - startTime_).count();
58     }
59 
Reset()60     void Reset()
61     {
62         startTime_ = Now();
63     }
64 
65 protected:
Now()66     TimePoint Now()
67     {
68         return Clock::now();
69     }
70 
71 private:
72     TimePoint startTime_;
73 };
74 
DepthMalloc(int depth,int mallocSize)75 char *DepthMalloc(int depth, int mallocSize)
76 {
77     if (mallocSize <= 0) {
78         return nullptr;
79     }
80     StaticSpace staticeData;
81     if (depth == 0) {
82         staticeData.data[0] = 1;
83         return new char[mallocSize];
84     }
85     return (DepthMalloc(depth - 1, mallocSize));
86 }
87 
DepthFree(int depth,char * p)88 void DepthFree(int depth, char *p)
89 {
90     StaticSpace staticeData;
91     if (depth == 0) {
92         staticeData.data[0] = 1;
93         delete []p;
94         return;
95     }
96     return (DepthFree(depth - 1, p));
97 }
98 
thread_func_cpp(void * param)99 void* thread_func_cpp(void* param)
100 {
101     char *p = nullptr;
102     long tid = syscall(SYS_gettid);
103     printf("start thread %ld\n", tid);
104     int times = *static_cast<int*>(param);
105     int idx = 0;
106     std::string name = "thread";
107     name = name + std::to_string(times);
108     prctl(PR_SET_NAME, name.c_str());
109 
110     constexpr int timeBase = 100;
111     while (idx < times) {
112         p = DepthMalloc(g_stickDepth, MALLOC_SIZE);
113         if (idx % timeBase == 0) {
114             printf("thread %ld malloc %d times\n", tid, idx);
115         }
116         if (p) {
117             DepthFree(g_stickDepth, p);
118         }
119         idx++;
120     }
121     return nullptr;
122 }
123 
thread_func_cpp_hook(void * param)124 void* thread_func_cpp_hook(void* param)
125 {
126     char *p = nullptr;
127     long tid = syscall(SYS_gettid);
128     printf("start thread %ld\n", tid);
129     int times = *static_cast<int*>(param);
130     int idx = 0;
131     std::string name = "thread";
132     name = name + std::to_string(times);
133     prctl(PR_SET_NAME, name.c_str());
134     constexpr int timeBase = 1000;
135     void* handle = nullptr;
136     DepthMallocSo mallocFunc = DepthMalloc;
137     DepthFreeSo freeFunc = DepthFree;
138 
139     constexpr unsigned int dlopenTrigger = 30000;
140     while (idx < times) {
141         if (idx == static_cast<int>(dlopenTrigger)) {
142             printf("dlopen!!!\n");
143             handle = dlopen(SO_PATH, RTLD_LAZY);
144             if (handle == nullptr) {
145                 printf("library not exist!\n");
146                 exit(0);
147             }
148             mallocFunc = (DepthMallocSo)dlsym(handle, "DepthMallocSo");
149             freeFunc = (DepthFreeSo)dlsym(handle, "DepthFreeSo");
150             if (mallocFunc == nullptr || freeFunc == nullptr) {
151                 printf("function not exist!\n");
152                 exit(0);
153             }
154         }
155         p = mallocFunc(g_stickDepth, MALLOC_SIZE);
156         if (idx % timeBase == 0) {
157             printf("thread %ld malloc %d times\n", tid, idx);
158         }
159         if (p) {
160             freeFunc(g_stickDepth, p);
161         }
162         idx++;
163     }
164     if (handle != nullptr) {
165         dlclose(handle);
166     }
167     return nullptr;
168 }
169 
ThreadTimeCost(int threadNum,int mallocTimes)170 int ThreadTimeCost(int threadNum, int mallocTimes) {
171     Timer timer = {};
172     if (threadNum <= 0) {
173         printf("threadNum less than or equal to 0.\n");
174         return 1;
175     }
176     pthread_t* thr_array = new (std::nothrow) pthread_t[threadNum];
177     if (!thr_array) {
178         printf("new thread array failed.\n");
179         return 1;
180     }
181     int idx;
182     for (idx = 0; idx < threadNum; ++idx) {
183         if (pthread_create(thr_array + idx, nullptr, thread_func_cpp, static_cast<void*>(&mallocTimes)) != 0) {
184             printf("Creating thread failed.\n");
185         }
186     }
187     for (idx = 0; idx < threadNum; ++idx) {
188         pthread_join(thr_array[idx], nullptr);
189     }
190     delete []thr_array;
191     auto timeCost = timer.ElapsedUs();
192     printf("Before hook, time cost %ldus.\nAfter hook test sleeping 200 ......., please send signal\n", timeCost);
193     sleep(SLEEP_TIME);
194     printf("Hook test start\n");
195     Timer hooktimer = {};
196     pthread_t* thr_array_hook = new (std::nothrow) pthread_t[threadNum];
197     if (!thr_array_hook) {
198         printf("new thread lock array failed.\n");
199         return 1;
200     }
201     for (idx = 0; idx < threadNum; ++idx) {
202         if (pthread_create(thr_array_hook + idx, nullptr, thread_func_cpp_hook, static_cast<void*>(&mallocTimes)) !=
203             0) {
204             printf("Creating thread failed.\n");
205         }
206     }
207     for (idx = 0; idx < threadNum; ++idx) {
208         pthread_join(thr_array_hook[idx], nullptr);
209     }
210     delete []thr_array_hook;
211     auto hookCost = hooktimer.ElapsedUs();
212     printf("After hook, time cost %ldus.\nPerformance test finish!", hookCost);
213     return 0;
214 }
215 } // namespace
216 
main(int argc,char * argv[])217 int main(int argc, char *argv[])
218 {
219     int threadNum = 1;
220     int mallocTimes = 0;
221     if  (argc >= ARGC_NUM_MUST) {
222         if (atoi(argv[1]) > 0) {
223             threadNum = atoi(argv[1]);
224         }
225         mallocTimes = atoi(argv[ARGC_MALLOC_TIMES]);
226         if (argc == ARGC_NUM_MAX) {
227             g_stickDepth = static_cast<unsigned int>(atoi(argv[ARGC_STICK_DEPTH]));
228         }
229     } else {
230         printf("command error\n");
231         return 0;
232     }
233     printf("Test start %d thread, malloc %d times\n", threadNum, mallocTimes);
234     if (!ThreadTimeCost(threadNum, mallocTimes)) {
235         printf("Test success end!\n");
236     } else {
237         printf("Test failure end!\n");
238     }
239 }
240 
241 #pragma clang optimize on
242