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
16 #include <cstdio>
17 #include <cstring>
18 #include <unistd.h>
19 #include <cstdlib>
20 #include <pthread.h>
21 #include <vector>
22 #include <ctime>
23 #include <csignal>
24 #include <atomic>
25 #include <memory>
26
27 namespace {
28 static int g_duration;
29 static int g_memSize;
30 static std::atomic<long long> g_times;
31 static std::atomic<long long> g_mallocTotalTime;
32 static std::atomic<long long> g_freeTotalTime;
33 static constexpr int N_INSTALL_MALLOC_HOOK_SIGNAL = 36;
34 static constexpr int DURATION_TIME = 30 * 60;
35 static constexpr int MEMORY_BUFFER_SIZE = 19;
36
UserThread(void * param)37 void* UserThread(void* param)
38 {
39 int idx = *static_cast<int*>(param);
40 struct timespec beginTime;
41 struct timespec endTime;
42 struct timespec beginTimeMalloc;
43 struct timespec endTimeMalloc;
44 struct timespec beginTimeFree;
45 struct timespec endTimeFree;
46
47 clock_gettime(CLOCK_REALTIME, &beginTime);
48 int displaySize = g_memSize > 5 ? 5 : g_memSize;
49 do {
50 clock_gettime(CLOCK_REALTIME, &endTime);
51 if (endTime.tv_sec - beginTime.tv_sec >= g_duration) {
52 break;
53 }
54 clock_gettime(CLOCK_REALTIME, &beginTimeMalloc);
55 char* mem = (char *)malloc(g_memSize);
56 if (mem == nullptr) {
57 printf("Error: malloc mem memory failed.\n");
58 return nullptr;
59 }
60 clock_gettime(CLOCK_REALTIME, &endTimeMalloc);
61 std::atomic_fetch_add_explicit(
62 &g_mallocTotalTime,
63 static_cast<long long>((endTimeMalloc.tv_sec - beginTimeMalloc.tv_sec) * 1000000000L +
64 (endTimeMalloc.tv_nsec - beginTimeMalloc.tv_nsec)),
65 std::memory_order_relaxed);
66 long long currentTimes = ++g_times;
67 long long timeBase = 10000;
68 if (currentTimes % timeBase == 0) {
69 printf("Thread %d, %lld: ", idx + 1, currentTimes);
70 for (int i = 0 ; i < displaySize ; i++) {
71 printf("%d ", mem[i]);
72 }
73 printf("\n");
74 }
75 clock_gettime(CLOCK_REALTIME, &beginTimeFree);
76 if (mem != nullptr) {
77 free(mem);
78 }
79 clock_gettime(CLOCK_REALTIME, &endTimeFree);
80 std::atomic_fetch_add_explicit(
81 &g_freeTotalTime,
82 static_cast<long long>((endTimeFree.tv_sec - beginTimeFree.tv_sec) * 1000000000L +
83 (endTimeFree.tv_nsec - beginTimeFree.tv_nsec)),
84 std::memory_order_relaxed);
85 }
86 while (true);
87 return nullptr;
88 }
89 #define PRINTF_DATA(fileptr, fmt, ...) \
90 { \
91 do { \
92 fprintf(stderr, fmt, ## __VA_ARGS__); \
93 fprintf(fileptr, fmt, ## __VA_ARGS__); \
94 fflush(fileptr); \
95 } while (0); \
96 }
97
Usage()98 void Usage()
99 {
100 printf("Usage: perf_test_data <-o output_file_name> [-t threadNum[] [-d g_duration] [-s g_memSize]\n");
101 }
102
FileClose(FILE * fp)103 void FileClose(FILE* fp)
104 {
105 if (fp != nullptr) {
106 fclose(fp);
107 }
108 }
109
110 } // namespace
111
main(int argc,char * argv[])112 int main(int argc, char *argv[])
113 {
114 int threadNum = 1;
115 g_duration = DURATION_TIME;
116 g_memSize = MEMORY_BUFFER_SIZE;
117 std::unique_ptr<FILE, void (*)(FILE*)> outFp(nullptr, nullptr);
118 for (int idx = 1; idx < argc; ++idx) {
119 if (strcmp(argv[idx], "-o") == 0) {
120 if (idx + 1 >= argc) {
121 Usage();
122 return 1;
123 } else {
124 ++idx;
125 outFp = std::unique_ptr<FILE, void (*)(FILE*)>(fopen(argv[idx], "w"), FileClose);
126 if (outFp == nullptr) {
127 printf("File '%s' can't be opened.\n", argv[idx]);
128 return 1;
129 }
130 }
131 } else if (strcmp(argv[idx], "-t") == 0) {
132 if (idx + 1 >= argc) {
133 Usage();
134 return 1;
135 } else {
136 ++idx;
137 threadNum = atoi(argv[idx]);
138 if (threadNum <= 0) {
139 printf("Thread number can't be less or equal zero.\n");
140 return 1;
141 }
142 }
143 } else if (strcmp(argv[idx], "-d") == 0) {
144 if (idx + 1 >= argc) {
145 Usage();
146 return 1;
147 } else {
148 ++idx;
149 g_duration = atoi(argv[idx]);
150 if (g_duration <= 0) {
151 printf("g_duration can't be less or equal zero.\n");
152 return 1;
153 }
154 }
155 } else if (strcmp(argv[idx], "-s") == 0) {
156 if (idx + 1 >= argc) {
157 Usage();
158 return 1;
159 } else {
160 ++idx;
161 g_memSize = atoi(argv[idx]);
162 if (g_memSize <= 0) {
163 printf("memory size can't be less or equal zero.\n");
164 return 1;
165 }
166 }
167 }
168 }
169 if (outFp == nullptr) {
170 Usage();
171 return 1;
172 }
173 pthread_t* thrArray = (pthread_t*)malloc(sizeof(pthread_t) * threadNum);
174 if (thrArray == nullptr) {
175 printf("malloc thrArray memory failed.\n");
176 return 1;
177 }
178 int idxSituation;
179 int idxSituationMax = 2;
180 int pid = static_cast<int>(getpid());
181 PRINTF_DATA(outFp.get(), "PID: %d, file: %d.nativehook\n", pid, pid);
182 PRINTF_DATA(outFp.get(),
183 "Thread number: %d, duration: %d seconds, memory size: %d bytes\n",
184 threadNum,
185 g_duration,
186 g_memSize);
187 for (idxSituation = 0; idxSituation < idxSituationMax; ++idxSituation) {
188 if (idxSituation == 0) {
189 PRINTF_DATA(outFp.get(), "No hook situation\n");
190 } else {
191 PRINTF_DATA(outFp.get(), "\nWith hook situation\n");
192 raise(N_INSTALL_MALLOC_HOOK_SIGNAL);
193 }
194 int idx;
195
196 std::atomic_store_explicit(&g_times, static_cast<long long>(0), std::memory_order_seq_cst);
197 std::atomic_store_explicit(&g_mallocTotalTime, static_cast<long long>(0), std::memory_order_seq_cst);
198 std::atomic_store_explicit(&g_freeTotalTime, static_cast<long long>(0), std::memory_order_seq_cst);
199
200 for (idx = 0; idx < threadNum; ++idx) {
201 if (pthread_create(thrArray + idx, nullptr, UserThread, reinterpret_cast<void*>(&idx)) != 0) {
202 printf("Creating thread failed.\n");
203 }
204 }
205
206 for (idx = 0; idx < threadNum; ++idx) {
207 pthread_join(thrArray[idx], nullptr);
208 }
209 long long totalTimes = g_times.load(std::memory_order_relaxed);
210 PRINTF_DATA(outFp.get(), "The total g_times(malloc/free): %lld\n", totalTimes);
211 }
212 if (thrArray != nullptr) {
213 free(thrArray);
214 }
215 printf("Exit\n");
216 }
217