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 <new>
19 #include <thread>
20 #include <dlfcn.h>
21 #include <pthread.h>
22 #include <unistd.h>
23 #include <sys/prctl.h>
24 #include <sys/syscall.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
ThreadFuncCpp(void * param)99 void* ThreadFuncCpp(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
ThreadFuncCppHook(void * param)124 void* ThreadFuncCppHook(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 {
172 Timer timer = {};
173 if (threadNum <= 0) {
174 printf("threadNum less than or equal to 0.\n");
175 return 1;
176 }
177 pthread_t* thrArray = new (std::nothrow) pthread_t[threadNum];
178 if (!thrArray) {
179 printf("new thread array failed.\n");
180 return 1;
181 }
182 int idx;
183 for (idx = 0; idx < threadNum; ++idx) {
184 if (pthread_create(thrArray + idx, nullptr, ThreadFuncCpp, static_cast<void*>(&mallocTimes)) != 0) {
185 printf("Creating thread failed.\n");
186 }
187 }
188 for (idx = 0; idx < threadNum; ++idx) {
189 pthread_join(thrArray[idx], nullptr);
190 }
191 delete []thrArray;
192 auto timeCost = timer.ElapsedUs();
193 printf("Before hook, time cost %ldus.\nAfter hook test sleeping 200 ......., please send signal\n", timeCost);
194 sleep(SLEEP_TIME);
195 printf("Hook test start\n");
196 Timer hooktimer = {};
197 pthread_t* thrArrayHook = new (std::nothrow) pthread_t[threadNum];
198 if (!thrArrayHook) {
199 printf("new thread lock array failed.\n");
200 return 1;
201 }
202 for (idx = 0; idx < threadNum; ++idx) {
203 if (pthread_create(thrArrayHook + idx, nullptr, ThreadFuncCppHook, static_cast<void*>(&mallocTimes)) !=
204 0) {
205 printf("Creating thread failed.\n");
206 }
207 }
208 for (idx = 0; idx < threadNum; ++idx) {
209 pthread_join(thrArrayHook[idx], nullptr);
210 }
211 delete []thrArrayHook;
212 auto hookCost = hooktimer.ElapsedUs();
213 printf("After hook, time cost %ldus.\nPerformance test finish!", hookCost);
214 return 0;
215 }
216 } // namespace
217
main(int argc,char * argv[])218 int main(int argc, char *argv[])
219 {
220 int threadNum = 1;
221 int mallocTimes = 0;
222 if (argc >= ARGC_NUM_MUST) {
223 if (atoi(argv[1]) > 0) {
224 threadNum = atoi(argv[1]);
225 }
226 mallocTimes = atoi(argv[ARGC_MALLOC_TIMES]);
227 if (argc == ARGC_NUM_MAX) {
228 g_stickDepth = static_cast<unsigned int>(atoi(argv[ARGC_STICK_DEPTH]));
229 }
230 } else {
231 printf("command error\n");
232 return 0;
233 }
234 printf("Test start %d thread, malloc %d times\n", threadNum, mallocTimes);
235 if (!ThreadTimeCost(threadNum, mallocTimes)) {
236 printf("Test success end!\n");
237 } else {
238 printf("Test failure end!\n");
239 }
240 }
241
242 #pragma clang optimize on
243