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 <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 28namespace { 29typedef char* (*DepthMallocSo)(int depth, int mallocSize); 30typedef void (*DepthFreeSo)(int depth, char *p); 31constexpr int MALLOC_SIZE = 1000; 32constexpr int DATA_SIZE = 200; 33constexpr int SLEEP_TIME = 200; 34constexpr int ARGC_NUM_MAX = 4; 35constexpr int ARGC_NUM_MUST = 3; 36constexpr int ARGC_MALLOC_TIMES = 2; 37constexpr int ARGC_STICK_DEPTH = 3; 38unsigned int g_stickDepth = 100; 39 40const static char SO_PATH[] = "libnativetest_so.z.so"; 41using StaticSpace = struct { 42 int data[DATA_SIZE]; 43}; 44 45class Timer { 46public: 47 using Clock = std::chrono::steady_clock; 48 using TimePoint = Clock::time_point; 49 50 Timer() : startTime_(Now()) {} 51 52 ~Timer() {} 53 54 long ElapsedUs() 55 { 56 auto currentTime = Now(); 57 return std::chrono::duration_cast<std::chrono::microseconds>(currentTime - startTime_).count(); 58 } 59 60 void Reset() 61 { 62 startTime_ = Now(); 63 } 64 65protected: 66 TimePoint Now() 67 { 68 return Clock::now(); 69 } 70 71private: 72 TimePoint startTime_; 73}; 74 75char *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 88void 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 99void* 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 124void* 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 170int 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 218int 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