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