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