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 <pthread.h>
20 #include <sys/syscall.h>
21 #include <unistd.h>
22
23 #pragma clang optimize off
24
25
26 namespace {
27 constexpr int MALLOC_SIZE = 1000;
28 constexpr int TIME_BASE = 1000;
29 constexpr int DATA_SIZE = 200;
30 constexpr int SLEEP_TIME = 200;
31 constexpr int ARGC_NUM_MAX = 4;
32 constexpr int ARGC_NUM_MUST = 3;
33 constexpr int ARGC_MALLOC_TIMES = 2;
34 constexpr int ARGC_STICK_DEPTH = 3;
35 unsigned int g_stickDepth = 100;
36
37 using StaticSpace = struct {
38 int data[DATA_SIZE];
39 };
40
41 class Timer {
42 public:
43 using Clock = std::chrono::steady_clock;
44 using TimePoint = Clock::time_point;
45
Timer()46 Timer() : startTime_(Now()) {}
47
~Timer()48 ~Timer() {}
49
ElapsedUs()50 long ElapsedUs()
51 {
52 auto currentTime = Now();
53 return std::chrono::duration_cast<std::chrono::microseconds>(currentTime - startTime_).count();
54 }
55
Reset()56 void Reset()
57 {
58 startTime_ = Now();
59 }
60
61 protected:
Now()62 TimePoint Now()
63 {
64 return Clock::now();
65 }
66
67 private:
68 TimePoint startTime_;
69 };
70
DepthMalloc(int depth,int mallocSize)71 char *DepthMalloc(int depth, int mallocSize)
72 {
73 if (mallocSize <= 0) {
74 return nullptr;
75 }
76 StaticSpace staticeData;
77 if (depth == 0) {
78 staticeData.data[0] = 1;
79 return new char[mallocSize];
80 }
81 return (DepthMalloc(depth - 1, mallocSize));
82 }
83
DepthFree(int depth,char * p)84 void DepthFree(int depth, char *p)
85 {
86 StaticSpace staticeData;
87 if (depth == 0) {
88 staticeData.data[0] = 1;
89 delete []p;
90 return;
91 }
92 return (DepthFree(depth - 1, p));
93 }
94
thread_func_cpp(void * param)95 void* thread_func_cpp(void* param)
96 {
97 char *p = nullptr;
98 long tid = syscall(SYS_gettid);
99 printf("start thread %ld\n", tid);
100 int times = *static_cast<int*>(param);
101 int idx = 0;
102 while (idx < times) {
103 p = DepthMalloc(g_stickDepth, MALLOC_SIZE);
104 if (idx % TIME_BASE == 0) {
105 printf("thread %ld malloc %d times\n", tid, idx);
106 }
107 if (p) {
108 DepthFree(g_stickDepth, p);
109 }
110 idx++;
111 }
112 return nullptr;
113 }
114
ThreadTimeCost(int threadNum,int mallocTimes)115 int ThreadTimeCost(int threadNum, int mallocTimes) {
116 Timer timer = {};
117 if (threadNum <= 0) {
118 printf("threadNum less than or equal to 0.\n");
119 return 1;
120 }
121 pthread_t* thr_array = new (std::nothrow) pthread_t[threadNum];
122 if (!thr_array) {
123 printf("new thread array failed.\n");
124 return 1;
125 }
126 int idx;
127 for (idx = 0; idx < threadNum; ++idx) {
128 if (pthread_create(thr_array + idx, nullptr, thread_func_cpp, static_cast<void*>(&mallocTimes)) != 0) {
129 printf("Creating thread failed.\n");
130 }
131 }
132 for (idx = 0; idx < threadNum; ++idx) {
133 pthread_join(thr_array[idx], nullptr);
134 }
135 delete []thr_array;
136 auto timeCost = timer.ElapsedUs();
137 printf("Before hook, time cost %ldus.\nAfter hook test sleeping 200 ......., please send signal\n", timeCost);
138 sleep(SLEEP_TIME);
139 printf("Hook test start\n");
140 Timer hooktimer = {};
141 pthread_t* thr_array_hook = new (std::nothrow) pthread_t[threadNum];
142 if (!thr_array_hook) {
143 printf("new thread lock array failed.\n");
144 return 1;
145 }
146 for (idx = 0; idx < threadNum; ++idx) {
147 if (pthread_create(thr_array_hook + idx, nullptr, thread_func_cpp, static_cast<void*>(&mallocTimes)) !=
148 0) {
149 printf("Creating thread failed.\n");
150 }
151 }
152 for (idx = 0; idx < threadNum; ++idx) {
153 pthread_join(thr_array_hook[idx], nullptr);
154 }
155 delete []thr_array_hook;
156 auto hookCost = hooktimer.ElapsedUs();
157 printf("After hook, time cost %ldus.\nPerformance test finish!", hookCost);
158 return 0;
159 }
160 } // namespace
161
main(int argc,char * argv[])162 int main(int argc, char *argv[])
163 {
164 int threadNum = 1;
165 int mallocTimes = 0;
166 if (argc >= ARGC_NUM_MUST) {
167 if (atoi(argv[1]) > 0) {
168 threadNum = atoi(argv[1]);
169 }
170 mallocTimes = atoi(argv[ARGC_MALLOC_TIMES]);
171 if (argc == ARGC_NUM_MAX) {
172 g_stickDepth = atoi(argv[ARGC_STICK_DEPTH]);
173 }
174 } else {
175 printf("command error\n");
176 return 0;
177 }
178 printf("Test start %d thread, malloc %d times\n", threadNum, mallocTimes);
179 if (!ThreadTimeCost(threadNum, mallocTimes)) {
180 printf("Test success end!\n");
181 } else {
182 printf("Test failure end!\n");
183 }
184 }
185
186 #pragma clang optimize on
187