1 /*
2 * Copyright (c) 2023 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 <benchmark/benchmark.h>
17 #include "thread_ex.h"
18 #include <iostream>
19 #include <cstdio>
20 #include <sys/prctl.h>
21 #include <unistd.h>
22 #include <sys/resource.h>
23 #include "../log.h"
24 #include "../assert.h"
25 using namespace std;
26
27 namespace OHOS {
28 namespace {
29
30 class BenchmarkThreadTest : public benchmark::Fixture {
31 public:
BenchmarkThreadTest()32 BenchmarkThreadTest()
33 {
34 Iterations(iterations);
35 Repetitions(repetitions);
36 ReportAggregatesOnly();
37 }
38
39 ~BenchmarkThreadTest() override = default;
SetUp(const::benchmark::State & state)40 void SetUp(const ::benchmark::State& state) override
41 {
42 }
43
TearDown(const::benchmark::State & state)44 void TearDown(const ::benchmark::State& state) override
45 {
46 }
47
48 protected:
49 const int32_t repetitions = 3;
50 const int32_t iterations = 100;
51 };
52
53 static int g_times = 0;
54 constexpr int DEFAULT_PRIO = 0;
55 const std::string& DEFAULT_THREAD_NAME = "default";
56 const int INITIAL_TIMES = 0;
57 const int INITIAL_TEST_VALUE = 0;
58 const int THREAD_STACK_SIZE = 1024;
59 const int INVALID_THREAD_ID = -1;
60 const int SLEEP_FOR_ONE_SECOND = 1;
61
62 using ThreadRunFunc = bool (*)(int& data);
63
TestRun01(int & data)64 bool TestRun01(int& data)
65 {
66 BENCHMARK_LOGD("ThreadTest bool TestRun01 is called.");
67 ++data;
68 return false;
69 }
70
TestRun02(int & data)71 bool TestRun02(int& data)
72 {
73 BENCHMARK_LOGD("ThreadTest bool TestRun02 is called.");
74 ++data;
75 return true;
76 }
77
TestRun03(int & data)78 bool TestRun03(int& data)
79 {
80 BENCHMARK_LOGD("ThreadTest bool TestRun03 is called.");
81 static const int TRY_TIMES = 10;
82 if (g_times <= TRY_TIMES) {
83 ++data;
84 return true;
85 }
86
87 return false;
88 }
89
90 class TestThread : public OHOS::Thread {
91 public:
TestThread(const int data,const bool readyToWork,ThreadRunFunc runFunc)92 TestThread(const int data, const bool readyToWork, ThreadRunFunc runFunc)
93 : data_(data),
94 priority_(DEFAULT_PRIO),
95 name_(DEFAULT_THREAD_NAME),
96 readyToWork_(readyToWork),
97 runFunc_(runFunc)
98 {};
99
100 TestThread() = delete;
~TestThread()101 ~TestThread() {}
102
103 bool ReadyToWork() override;
104
105 int data_;
106 int priority_;
107 std::string name_;
108
109 protected:
110 bool Run() override;
111
112 private:
113 bool readyToWork_;
114 ThreadRunFunc runFunc_;
115 };
116
ReadyToWork()117 bool TestThread::ReadyToWork()
118 {
119 BENCHMARK_LOGD("ThreadTest bool TestThread::ReadyToWork is called.");
120 return readyToWork_;
121 }
122
Run()123 bool TestThread::Run()
124 {
125 BENCHMARK_LOGD("ThreadTest bool TestThread::Run is called.");
126 priority_ = getpriority(PRIO_PROCESS, 0);
127 char threadName[MAX_THREAD_NAME_LEN] = {0};
128 prctl(PR_GET_NAME, threadName, 0, 0);
129 name_ = threadName;
130
131 if (runFunc_ != nullptr) {
132 return (*runFunc_)(data_);
133 }
134
135 return false;
136 }
137
138 /*
139 * @tc.name: testThread001
140 * @tc.desc: ThreadTest
141 */
BENCHMARK_F(BenchmarkThreadTest,testThread001)142 BENCHMARK_F(BenchmarkThreadTest, testThread001)(benchmark::State& state)
143 {
144 BENCHMARK_LOGD("ThreadTest testThread001 start.");
145 const int expectedDataValue = 0;
146 while (state.KeepRunning()) {
147 g_times = 0;
148 std::unique_ptr<TestThread> test = std::make_unique<TestThread>(INITIAL_TEST_VALUE, false, TestRun01);
149 ThreadStatus status = test->Start("test_thread_01", THREAD_PROI_LOW, THREAD_STACK_SIZE);
150 AssertEqual((status == ThreadStatus::OK), true,
151 "(status == ThreadStatus::OK) did not equal true as expected.", state);
152
153 pthread_t thread = test->GetThread();
154
155 // pthread_equal return non-zero if equal
156 AssertEqual((pthread_equal(thread, INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true),
157 "(pthread_equal(thread, INVALID_THREAD_ID) != 0) did not equal \
158 (test->IsRunning() ? false : true) as expected.", state);
159
160 // ReadyToWork return false, RUN will not be called!
161 AssertEqual(test->priority_, DEFAULT_PRIO, "test->priority_ did not equal DEFAULT_PRIO as expected.", state);
162 AssertEqual(test->name_, DEFAULT_THREAD_NAME,
163 "test->name_ did not equal DEFAULT_THREAD_NAME as expected.", state);
164
165 // get stacksize of threa, may be different because of system memory align
166 AssertEqual(test->data_, expectedDataValue,
167 "test->data_ did not equal EXPECTED_DATA_VALUE as expected.", state);
168 AssertEqual(g_times, INITIAL_TIMES, "g_times did not equal INITIAL_TIMES as expected.", state);
169 test->NotifyExitSync();
170 sleep(SLEEP_FOR_ONE_SECOND);
171 AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true),
172 "(pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0) did not equal \
173 (test->IsRunning() ? false : true) as expected.", state);
174 }
175 BENCHMARK_LOGD("ThreadTest testThread001 end.");
176 }
177
178 /*
179 * @tc.name: testThread002
180 * @tc.desc: ThreadTest
181 */
BENCHMARK_F(BenchmarkThreadTest,testThread002)182 BENCHMARK_F(BenchmarkThreadTest, testThread002)(benchmark::State& state)
183 {
184 BENCHMARK_LOGD("ThreadTest testThread002 start.");
185 const int expectedDataValue = 1;
186 while (state.KeepRunning()) {
187 g_times = 0;
188 std::unique_ptr<TestThread> test = std::make_unique<TestThread>(INITIAL_TEST_VALUE, true, TestRun01);
189 ThreadStatus status = test->Start("test_thread_02", THREAD_PROI_LOW, THREAD_STACK_SIZE);
190
191 AssertEqual((status == ThreadStatus::OK), true,
192 "status == ThreadStatus::OK did not equal true as expected.", state);
193
194 sleep(SLEEP_FOR_ONE_SECOND); // let the new thread has chance to run
195
196 // pthread_equal return non-zero if equal, RUN return false,may exit already
197 AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true),
198 "(pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0) did not equal \
199 (test->IsRunning() ? false : true) as expected.", state);
200
201 // ReadyToWork return true, RUN will be called!
202 AssertEqual(test->priority_, THREAD_PROI_LOW,
203 "test->priority_ did not equal THREAD_PROI_LOW as expected.", state);
204 AssertEqual(test->name_, "test_thread_02",
205 "test->name_ did not equal \"test_thread_02\" as expected.", state);
206 AssertEqual(test->data_, expectedDataValue, "test->data_ did not equal expectedDataValue as expected.", state);
207 AssertEqual(g_times, INITIAL_TIMES, "g_times did not equal INITIAL_TIMES as expected.", state);
208
209 test->NotifyExitSync();
210 sleep(SLEEP_FOR_ONE_SECOND);
211 AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true),
212 "pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0 did not equal \
213 (test->IsRunning() ? false : true) as expected.", state);
214 }
215 BENCHMARK_LOGD("ThreadTest testThread002 end.");
216 }
217
218 /*
219 * @tc.name: testThread003
220 * @tc.desc: ThreadTest
221 */
BENCHMARK_F(BenchmarkThreadTest,testThread003)222 BENCHMARK_F(BenchmarkThreadTest, testThread003)(benchmark::State& state)
223 {
224 BENCHMARK_LOGD("ThreadTest testThread003 start.");
225 const int expectedDataValue = 0;
226 while (state.KeepRunning()) {
227 g_times = 0;
228 std::unique_ptr<TestThread> test = std::make_unique<TestThread>(INITIAL_TEST_VALUE, false, TestRun02);
229 ThreadStatus status = test->Start("test_thread_03", THREAD_PROI_LOW, THREAD_STACK_SIZE);
230 AssertEqual((status == ThreadStatus::OK), true,
231 "status == ThreadStatus::OK did not equal true as expected.", state);
232
233 pthread_t thread = test->GetThread();
234
235 // pthread_equal return non-zero if equal
236 AssertEqual((pthread_equal(thread, INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true),
237 "pthread_equal(thread, INVALID_THREAD_ID) != 0 did not equal \
238 (test->IsRunning() ? false : true) as expected.", state);
239
240 // ReadyToWork return false, RUN will not be called!
241 AssertEqual(test->priority_, DEFAULT_PRIO,
242 "test->priority_ did not equal DEFAULT_PRIO as expected.", state);
243 AssertEqual(test->name_, DEFAULT_THREAD_NAME,
244 "test->name_ did not equal DEFAULT_THREAD_NAME as expected.", state);
245 AssertEqual(test->data_, expectedDataValue, "test->data_ did not equal expectedDataValue as expected.", state);
246 AssertEqual(g_times, INITIAL_TIMES, "g_times did not equal INITIAL_TIMES as expected.", state);
247
248 test->NotifyExitSync();
249 sleep(SLEEP_FOR_ONE_SECOND);
250 AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true),
251 "pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0 did not equal \
252 (test->IsRunning() ? false : true) as expected.", state);
253 }
254 BENCHMARK_LOGD("ThreadTest testThread003 end.");
255 }
256
257 /*
258 * @tc.name: testThread004
259 * @tc.desc: ThreadTest
260 */
BENCHMARK_F(BenchmarkThreadTest,testThread004)261 BENCHMARK_F(BenchmarkThreadTest, testThread004)(benchmark::State& state)
262 {
263 BENCHMARK_LOGD("ThreadTest testThread004 start.");
264 const int comparisonValue = 1;
265 while (state.KeepRunning()) {
266 g_times = 0;
267 std::unique_ptr<TestThread> test = std::make_unique<TestThread>(INITIAL_TEST_VALUE, true, TestRun02);
268 ThreadStatus status = test->Start("test_thread_04", THREAD_PROI_LOW, THREAD_STACK_SIZE);
269
270 AssertEqual((status == ThreadStatus::OK), true,
271 "status == ThreadStatus::OK did not equal true as expected.", state);
272
273 sleep(SLEEP_FOR_ONE_SECOND); // let the new thread has chance to run
274
275 // pthread_equal return non-zero if equal, RUN return false,may exit already
276 AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true),
277 "pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0 did not equal \
278 (test->IsRunning() ? false : true) as expected.", state);
279 // ReadyToWork return true, RUN will be called!
280 AssertEqual(test->priority_, THREAD_PROI_LOW,
281 "test->priority_ did not equal THREAD_PROI_LOW as expected.", state);
282 AssertEqual(test->name_, "test_thread_04",
283 "test->name_ did not equal \"test_thread_04\" as expected.", state);
284 AssertGreaterThan(test->data_, comparisonValue,
285 "test->data_ was not greater than comparisonValue as expected.", state);
286 AssertEqual(g_times, INITIAL_TIMES, "g_times did not equal INITIAL_TIMES as expected.", state);
287
288 test->NotifyExitSync();
289 sleep(SLEEP_FOR_ONE_SECOND);
290 AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true),
291 "pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0 did not equal \
292 (test->IsRunning() ? false : true) as expected.", state);
293 }
294 BENCHMARK_LOGD("ThreadTest testThread004 end.");
295 }
296
297 /*
298 * @tc.name: testThread005
299 * @tc.desc: ThreadTest
300 */
BENCHMARK_F(BenchmarkThreadTest,testThread005)301 BENCHMARK_F(BenchmarkThreadTest, testThread005)(benchmark::State& state)
302 {
303 BENCHMARK_LOGD("ThreadTest testThread005 start.");
304 const int expectedDataValue = 0;
305 while (state.KeepRunning()) {
306 g_times = 0;
307 std::unique_ptr<TestThread> test = std::make_unique<TestThread>(INITIAL_TEST_VALUE, false, TestRun03);
308 ThreadStatus status = test->Start("test_thread_05", THREAD_PROI_LOW, THREAD_STACK_SIZE);
309 AssertEqual((status == ThreadStatus::OK), true,
310 "status == ThreadStatus::OK did not equal true as expected.", state);
311
312 pthread_t thread = test->GetThread();
313 // pthread_equal return non-zero if equal
314 AssertEqual((pthread_equal(thread, INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true),
315 "pthread_equal(thread, INVALID_THREAD_ID) != 0 did not equal \
316 (test->IsRunning() ? false : true) as expected.", state);
317 // ReadyToWork return false, RUN will not be called!
318 AssertEqual(test->priority_, DEFAULT_PRIO,
319 "test->priority_ did not equal DEFAULT_PRIO as expected.", state);
320 AssertEqual(test->name_, DEFAULT_THREAD_NAME,
321 "test->name_ did not equal DEFAULT_THREAD_NAME as expected.", state);
322 AssertEqual(test->data_, expectedDataValue, "test->data_ did not equal expectedDataValue as expected.", state);
323 AssertEqual(g_times, INITIAL_TIMES, "g_times did not equal INITIAL_TIMES as expected.", state);
324
325 test->NotifyExitSync();
326 sleep(SLEEP_FOR_ONE_SECOND);
327 AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true),
328 "pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0 did not equal \
329 (test->IsRunning() ? false : true) as expected.", state);
330 }
331 BENCHMARK_LOGD("ThreadTest testThread005 end.");
332 }
333
334 /*
335 * @tc.name: testThread006
336 * @tc.desc: ThreadTest
337 */
BENCHMARK_F(BenchmarkThreadTest,testThread006)338 BENCHMARK_F(BenchmarkThreadTest, testThread006)(benchmark::State& state)
339 {
340 BENCHMARK_LOGD("ThreadTest testThread006 start.");
341 const int comparisonValue = 10;
342 while (state.KeepRunning()) {
343 g_times = 0;
344 std::unique_ptr<TestThread> test = std::make_unique<TestThread>(INITIAL_TEST_VALUE, true, TestRun03);
345 ThreadStatus status = test->Start("test_thread_06", THREAD_PROI_LOW, THREAD_STACK_SIZE);
346 AssertEqual((status == ThreadStatus::OK), true,
347 "status == ThreadStatus::OK did not equal true as expected.", state);
348
349 sleep(SLEEP_FOR_ONE_SECOND); // let the new thread has chance to run
350
351 // pthread_equal return non-zero if equal, RUN return false,may exit already
352 AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true),
353 "pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0 did not equal \
354 (test->IsRunning() ? false : true) as expected.", state);
355 // ReadyToWork return true, RUN will be called!
356 AssertEqual(test->priority_, THREAD_PROI_LOW,
357 "test->priority_ did not equal THREAD_PROI_LOW as expected.", state);
358 AssertEqual(test->name_, "test_thread_06",
359 "test->name_ did not equal \"test_thread_06\" as expected.", state);
360 AssertGreaterThan(test->data_, comparisonValue,
361 "test->data_ was not greater than comparisonValue as expected.", state);
362 AssertEqual(g_times, INITIAL_TIMES, "g_times did not equal INITIAL_TIMES as expected.", state);
363
364 g_times = 100;
365 AssertGreaterThan(test->data_, comparisonValue,
366 "test->data_ was not greater than comparisonValue as expected.", state);
367
368 sleep(SLEEP_FOR_ONE_SECOND); // let the new thread has chance to run
369
370 // g_times > 10, TestRun03 return false, thread exit
371 AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true),
372 "pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0 did not equal \
373 (test->IsRunning() ? false : true) as expected.", state);
374 }
375 BENCHMARK_LOGD("ThreadTest testThread006 end.");
376 }
377
378 /*
379 * @tc.name: testThread007
380 * @tc.desc: ThreadTest
381 */
BENCHMARK_F(BenchmarkThreadTest,testThread007)382 BENCHMARK_F(BenchmarkThreadTest, testThread007)(benchmark::State& state)
383 {
384 BENCHMARK_LOGD("ThreadTest testThread007 start.");
385 while (state.KeepRunning()) {
386 g_times = 0;
387 std::unique_ptr<TestThread> test = std::make_unique<TestThread>(INITIAL_TEST_VALUE, true, TestRun03);
388 ThreadStatus status = test->Start("", THREAD_PROI_LOW, 0);
389 AssertEqual((status == ThreadStatus::OK), true,
390 "status == ThreadStatus::OK did not equal true as expected.", state);
391
392 if (test->IsRunning()) {
393 status = test->Start("", THREAD_PROI_NORMAL, THREAD_STACK_SIZE);
394 AssertEqual(status == ThreadStatus::INVALID_OPERATION, true,
395 "status == ThreadStatus::INVALID_OPERATION did not equal true as expected.", state);
396
397 test->NotifyExitSync();
398 AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true),
399 "pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0 did not equal \
400 (test->IsRunning() ? false : true) as expected.", state);
401 }
402
403 sleep(SLEEP_FOR_ONE_SECOND); // let the new thread has chance to run
404
405 AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true),
406 "pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0 did not equal \
407 (test->IsRunning() ? false : true) as expected.", state);
408 }
409 BENCHMARK_LOGD("ThreadTest testThread007 end.");
410 }
411
412 /*
413 * @tc.name: testThread008
414 * @tc.desc: ThreadTest
415 */
BENCHMARK_F(BenchmarkThreadTest,testThread008)416 BENCHMARK_F(BenchmarkThreadTest, testThread008)(benchmark::State& state)
417 {
418 BENCHMARK_LOGD("ThreadTest testThread008 start.");
419 while (state.KeepRunning()) {
420 g_times = 0;
421 std::unique_ptr<TestThread> test = std::make_unique<TestThread>(INITIAL_TEST_VALUE, true, TestRun03);
422
423 bool res = test->Thread::ReadyToWork();
424 AssertEqual(res, true, "res did not equal true as expected.", state);
425
426 ThreadStatus status = test->Start("", THREAD_PROI_NORMAL, THREAD_STACK_SIZE);
427 AssertEqual((status == ThreadStatus::OK), true,
428 "status == ThreadStatus::OK did not equal true as expected.", state);
429
430 sleep(SLEEP_FOR_ONE_SECOND);
431 test->NotifyExitAsync();
432
433 sleep(SLEEP_FOR_ONE_SECOND); // let the new thread has chance to run
434 AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true),
435 "pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0 did not equal \
436 (test->IsRunning() ? false : true) as expected.", state);
437 }
438 BENCHMARK_LOGD("ThreadTest testThread008 end.");
439 }
440
441 class TestThread2 : public OHOS::Thread {
442 public:
TestThread2(const int data,ThreadRunFunc runFunc)443 TestThread2(const int data, ThreadRunFunc runFunc)
444 : data_(data), priority_(DEFAULT_PRIO), name_(DEFAULT_THREAD_NAME), runFunc_(runFunc)
445 {};
446
447 TestThread2() = delete;
~TestThread2()448 ~TestThread2() {}
449
450 int data_;
451 int priority_;
452 std::string name_;
453 protected:
454 bool Run() override;
455
456 private:
457 ThreadRunFunc runFunc_;
458 };
459
Run()460 bool TestThread2::Run()
461 {
462 BENCHMARK_LOGD("ThreadTest bool TestThread2::Run is called.");
463 priority_ = getpriority(PRIO_PROCESS, 0);
464 char threadName[MAX_THREAD_NAME_LEN] = {0};
465 prctl(PR_GET_NAME, threadName, 0, 0);
466 name_ = threadName;
467
468 if (runFunc_ != nullptr) {
469 return (*runFunc_)(data_);
470 }
471
472 return false;
473 }
474
475 /*
476 * @tc.name: testThread009
477 * @tc.desc: ThreadTest
478 */
BENCHMARK_F(BenchmarkThreadTest,testThread009)479 BENCHMARK_F(BenchmarkThreadTest, testThread009)(benchmark::State& state)
480 {
481 BENCHMARK_LOGD("ThreadTest testThread009 start.");
482 while (state.KeepRunning()) {
483 g_times = 0;
484 std::unique_ptr<TestThread2> test = std::make_unique<TestThread2>(0, TestRun03);
485
486 bool res = test->ReadyToWork();
487 AssertEqual(res, true, "res did not equal true as expected.", state);
488
489 ThreadStatus status = test->Start("", THREAD_PROI_NORMAL, THREAD_STACK_SIZE);
490 AssertEqual((status == ThreadStatus::OK), true,
491 "status == ThreadStatus::OK did not equal true as expected.", state);
492
493 sleep(SLEEP_FOR_ONE_SECOND);
494 test->NotifyExitAsync();
495
496 sleep(SLEEP_FOR_ONE_SECOND); // let the new thread has chance to run
497 AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true),
498 "pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0 did not equal \
499 (test->IsRunning() ? false : true) as expected.", state);
500 }
501 BENCHMARK_LOGD("ThreadTest testThread009 end.");
502 }
503 } // namespace
504 } // namespace OHOS
505 // Run the benchmark
506 BENCHMARK_MAIN();