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