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