From df728dbc038a010dd0817985861e226ce730080a Mon Sep 17 00:00:00 2001 From: liujia178 Date: Mon, 4 Dec 2023 08:42:38 +0800 Subject: [PATCH] Add benchmark testcase for safeblockqueue safeblockqueuetracking and uniquefd. Signed-off-by: liujia178 --- base/test/benchmarktest/BUILD.gn | 23 + base/test/benchmarktest/assert.h | 91 +++ base/test/benchmarktest/log.h | 36 + .../safe_block_queue_benchmark_test/BUILD.gn | 35 + .../safe_block_queue_benchmark_test.cpp | 687 ++++++++++++++++++ .../BUILD.gn | 35 + ...fe_block_queue_tracking_benchmark_test.cpp | 669 +++++++++++++++++ .../unique_fd_benchmark_test/BUILD.gn | 35 + .../unique_fd_benchmark_test.cpp | 297 ++++++++ bundle.json | 3 +- 10 files changed, 1910 insertions(+), 1 deletion(-) create mode 100644 base/test/benchmarktest/BUILD.gn create mode 100644 base/test/benchmarktest/assert.h create mode 100644 base/test/benchmarktest/log.h create mode 100644 base/test/benchmarktest/safe_block_queue_benchmark_test/BUILD.gn create mode 100644 base/test/benchmarktest/safe_block_queue_benchmark_test/safe_block_queue_benchmark_test.cpp create mode 100644 base/test/benchmarktest/safe_block_queue_tracking_benchmark_test/BUILD.gn create mode 100644 base/test/benchmarktest/safe_block_queue_tracking_benchmark_test/safe_block_queue_tracking_benchmark_test.cpp create mode 100644 base/test/benchmarktest/unique_fd_benchmark_test/BUILD.gn create mode 100644 base/test/benchmarktest/unique_fd_benchmark_test/unique_fd_benchmark_test.cpp diff --git a/base/test/benchmarktest/BUILD.gn b/base/test/benchmarktest/BUILD.gn new file mode 100644 index 0000000..4937f04 --- /dev/null +++ b/base/test/benchmarktest/BUILD.gn @@ -0,0 +1,23 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +group("benchmarktest") { + testonly = true + deps = [] + deps += [ + # deps file + "safe_block_queue_benchmark_test:SafeBlockQueueTest", + "safe_block_queue_tracking_benchmark_test:SafeBlockQueueTrackingTest", + "unique_fd_benchmark_test:UniqueFdTest", + ] +} diff --git a/base/test/benchmarktest/assert.h b/base/test/benchmarktest/assert.h new file mode 100644 index 0000000..e9ebc2a --- /dev/null +++ b/base/test/benchmarktest/assert.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ASSERT_H +#define ASSERT_H + +#include + +template +void AssertEqual(const T1 &t1, const T2 &t2, const char* printInfo, benchmark::State& state) +{ + if (t1 != t2) { + state.SkipWithError(printInfo); + } +} + +template +void AssertUnequal(const T1 &t1, const T2 &t2, const char* printInfo, benchmark::State& state) +{ + if (t1 == t2) { + state.SkipWithError(printInfo); + } +} + +template +void AssertFalse(const T &t, const char* printInfo, benchmark::State& state) +{ + if (t) { + state.SkipWithError(printInfo); + } +} + +template +void AssertTrue(const T &t, const char* printInfo, benchmark::State& state) +{ + if (!t) { + state.SkipWithError(printInfo); + } +} + +template +void AssertLessThan(const T1 &t1, const T2 &t2, const char* printInfo, benchmark::State& state) +{ + if (t1 >= t2) { + state.SkipWithError(printInfo); + } +} + +template +void AssertLessThanOrEqual(const T1 &t1, const T2 &t2, const char* printInfo, benchmark::State& state) +{ + if (t1 > t2) { + state.SkipWithError(printInfo); + } +} + +template +void AssertGreaterThan(const T1 &t1, const T2 &t2, const char* printInfo, benchmark::State& state) +{ + if (t1 <= t2) { + state.SkipWithError(printInfo); + } +} + +template +void AssertGreaterThanOrEqual(const T1 &t1, const T2 &t2, const char* printInfo, benchmark::State& state) +{ + if (t1 < t2) { + state.SkipWithError(printInfo); + } +} + +void AssertStringEqual(const char* str1, const char* str2, const char* printInfo, benchmark::State& state) +{ + if (strcmp(str1, str2) != 0) { + state.SkipWithError(printInfo); + } +} +#endif \ No newline at end of file diff --git a/base/test/benchmarktest/log.h b/base/test/benchmarktest/log.h new file mode 100644 index 0000000..19c2e78 --- /dev/null +++ b/base/test/benchmarktest/log.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LOG_H +#define LOG_H + +#include "hilog_base/log_base.h" + +constexpr LogType BENCHMARK_LOG_TYPE = LOG_CORE; +constexpr unsigned int BENCHMARK_LOG_DOMAIN = 0xD003D00; +constexpr const char *BENCHMARK_LOG_TAG = "benchmark_test"; + +#define BENCHMARK_LOGF(...) \ + (void)HiLogBasePrint(BENCHMARK_LOG_TYPE, LOG_FATAL, BENCHMARK_LOG_DOMAIN, BENCHMARK_LOG_TAG, __VA_ARGS__) +#define BENCHMARK_LOGE(...) \ + (void)HiLogBasePrint(BENCHMARK_LOG_TYPE, LOG_ERROR, BENCHMARK_LOG_DOMAIN, BENCHMARK_LOG_TAG, __VA_ARGS__) +#define BENCHMARK_LOGW(...) \ + (void)HiLogBasePrint(BENCHMARK_LOG_TYPE, LOG_WARN, BENCHMARK_LOG_DOMAIN, BENCHMARK_LOG_TAG, __VA_ARGS__) +#define BENCHMARK_LOGI(...) \ + (void)HiLogBasePrint(BENCHMARK_LOG_TYPE, LOG_INFO, BENCHMARK_LOG_DOMAIN, BENCHMARK_LOG_TAG, __VA_ARGS__) +#define BENCHMARK_LOGD(...) \ + (void)HiLogBasePrint(BENCHMARK_LOG_TYPE, LOG_DEBUG, BENCHMARK_LOG_DOMAIN, BENCHMARK_LOG_TAG, __VA_ARGS__) + +#endif // LOG_H diff --git a/base/test/benchmarktest/safe_block_queue_benchmark_test/BUILD.gn b/base/test/benchmarktest/safe_block_queue_benchmark_test/BUILD.gn new file mode 100644 index 0000000..1879597 --- /dev/null +++ b/base/test/benchmarktest/safe_block_queue_benchmark_test/BUILD.gn @@ -0,0 +1,35 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/test.gni") + +module_output_path = "commonlibrary_c_utils/safe_block_queue" + +ohos_benchmarktest("SafeBlockQueueTest") { + module_out_path = module_output_path + + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + sources = [ "safe_block_queue_benchmark_test.cpp" ] + + deps = [ "//third_party/benchmark:benchmark" ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog_base", + ] +} diff --git a/base/test/benchmarktest/safe_block_queue_benchmark_test/safe_block_queue_benchmark_test.cpp b/base/test/benchmarktest/safe_block_queue_benchmark_test/safe_block_queue_benchmark_test.cpp new file mode 100644 index 0000000..3a99d63 --- /dev/null +++ b/base/test/benchmarktest/safe_block_queue_benchmark_test/safe_block_queue_benchmark_test.cpp @@ -0,0 +1,687 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "safe_block_queue.h" +#include +#include +#include +#include +#include +#include +#include "../log.h" +#include "../assert.h" +using namespace std; + +namespace OHOS { +namespace { + +class BenchmarkSafeBlockQueue : public benchmark::Fixture { +public: + BenchmarkSafeBlockQueue() + { + Iterations(iterations); + Repetitions(repetitions); + ReportAggregatesOnly(); + } + + ~BenchmarkSafeBlockQueue() override = default; + void SetUp(const ::benchmark::State& state) override + { + } + + void TearDown(const ::benchmark::State& state) override + { + } + +protected: + const int32_t repetitions = 3; + const int32_t iterations = 100; +}; + +const unsigned int QUEUE_SLOTS = 10; +const unsigned int THREAD_NUM = QUEUE_SLOTS + 1; +const int QUEUE_CAPACITY = 10; +const int SLEEP_FOR_TWENTY_MILLISECOND = 20; + +class DemoThreadData { +public: + DemoThreadData() + { + putStatus = false; + getStatus = false; + } + static SafeBlockQueue shareQueue; + bool putStatus; + bool getStatus; + + void Put(int i) + { + shareQueue.Push(i); + putStatus = true; + } + + void Get() + { + shareQueue.Pop(); + getStatus = true; + } +}; + +SafeBlockQueue DemoThreadData::shareQueue(QUEUE_SLOTS); + +void PutHandleThreadData(DemoThreadData& q, int i) +{ + q.Put(i); +} + +void GetThreadDatePushedStatus(std::array& demoDatas, unsigned int& pushedIn, + unsigned int& unpushedIn) +{ + pushedIn = 0; + unpushedIn = 0; + for (auto& t : demoDatas) { + if (t.putStatus) { + pushedIn++; + } else { + unpushedIn++; + } + } +} + +void GetThreadDateGetedStatus(std::array& demoDatas, unsigned int& getedOut, + unsigned int& ungetedOut) +{ + getedOut = 0; + ungetedOut = 0; + for (auto& t : demoDatas) { + if (t.getStatus) { + getedOut++; + } else { + ungetedOut++; + } + } +} + +void PutHandleThreadDataTime(DemoThreadData& q, int i, + std::chrono::time_point absTime) +{ + std::this_thread::sleep_until(absTime); + q.Put(i); +} + +void GetHandleThreadDataTime(DemoThreadData& q, int i, + std::chrono::time_point absTime) +{ + std::this_thread::sleep_until(absTime); + q.Get(); +} + +/* + * @tc.name: testPut001 + * @tc.desc: Single-threaded call put and get to determine that the normal scenario + */ +BENCHMARK_F(BenchmarkSafeBlockQueue, testPut001)(benchmark::State& state) +{ + BENCHMARK_LOGD("SafeBlockQueue testPut001 start."); + while (state.KeepRunning()) { + SafeBlockQueue qi(QUEUE_CAPACITY); + int i = 1; + qi.Push(i); + const unsigned int expectedQueueSize = 1; + AssertEqual(static_cast(expectedQueueSize), qi.Size(), + "static_cast(expectedQueueSize) did not equal qi.Size() as expected.", state); + } + BENCHMARK_LOGD("SafeBlockQueue testPut001 end."); +} + +/* + * @tc.name: testGet001 + * @tc.desc: Single-threaded call put and get to determine that the normal scenario + */ +BENCHMARK_F(BenchmarkSafeBlockQueue, testGet001)(benchmark::State& state) +{ + BENCHMARK_LOGD("SafeBlockQueue testGet001 start."); + const int pushCount = 3; + const unsigned int expectedQueueSize = 3; + const int expectedFirstElement = 0; + while (state.KeepRunning()) { + SafeBlockQueue qi(QUEUE_CAPACITY); + for (int i = 0; i < pushCount; i++) { + qi.Push(i); + } + AssertEqual(static_cast(expectedQueueSize), qi.Size(), + "static_cast(expectedQueueSize) did not equal qi.Size() as expected.", state); + int t = qi.Pop(); + AssertEqual(t, expectedFirstElement, "t did not equal expectedFirstElement as expected.", state); + } + BENCHMARK_LOGD("SafeBlockQueue testGet001 end."); +} + +/* + * @tc.name: testMutilthreadPutAndBlock001 + * @tc.desc: Multiple threads put until blocking runs, one thread gets, all threads finish running normally + */ +BENCHMARK_F(BenchmarkSafeBlockQueue, testMutilthreadPutAndBlock001)(benchmark::State& state) +{ + BENCHMARK_LOGD("SafeBlockQueue testMutilthreadPutAndBlock001 start."); + std::thread threads[THREAD_NUM]; + std::array demoDatas; + while (state.KeepRunning()) { + demoDatas.fill(DemoThreadData()); + for (unsigned int i = 0; i < THREAD_NUM; i++) { + threads[i] = std::thread(PutHandleThreadData, std::ref(demoDatas[i]), i); + } + // 1. queue is full and some threads is blocked + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_TWENTY_MILLISECOND)); + AssertTrue((DemoThreadData::shareQueue.IsFull()), + "DemoThreadData::shareQueue.IsFull() did not equal true as expected.", state); + unsigned int pushedIn = 0; + unsigned int unpushedIn = 0; + unsigned int getedOut = 0; + unsigned int ungetedOut = 0; + GetThreadDatePushedStatus(demoDatas, pushedIn, unpushedIn); + AssertEqual(pushedIn, QUEUE_SLOTS, "pushedIn did not equal QUEUE_SLOTS as expected.", state); + AssertEqual(unpushedIn, THREAD_NUM - QUEUE_SLOTS, + "unpushedIn did not equal THREAD_NUM - QUEUE_SLOTS as expected.", state); + // 2. get one out and wait some put in + for (unsigned int i = 0; i < THREAD_NUM - QUEUE_SLOTS; i++) { + demoDatas[0].Get(); + } + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_TWENTY_MILLISECOND)); + // queue is full and some threads is blocked and is not joined + AssertTrue((DemoThreadData::shareQueue.IsFull()), + "DemoThreadData::shareQueue.IsFull() did not equal true as expected.", state); + GetThreadDatePushedStatus(demoDatas, pushedIn, unpushedIn); + GetThreadDateGetedStatus(demoDatas, getedOut, ungetedOut); + AssertEqual(pushedIn, THREAD_NUM, "pushedIn did not equal THREAD_NUM as expected.", state); + AssertEqual(getedOut, THREAD_NUM - QUEUE_SLOTS, + "getedOut did not equal THREAD_NUM - QUEUE_SLOTS as expected.", state); + for (auto& t : threads) { + t.join(); + } + while (!DemoThreadData::shareQueue.IsEmpty()) { + demoDatas[0].Get(); + } + } + BENCHMARK_LOGD("SafeBlockQueue testMutilthreadPutAndBlock001 end."); +} + +/* + * @tc.name: testMutilthreadConcurrentPutAndBlockInblankqueue001 + * @tc.desc: Multi-threaded put() on the empty queue. When n threads are waiting to reach a certain + * time-point, everyone puts concurrent to see the status of the queue and the state of the thread. + */ +BENCHMARK_F(BenchmarkSafeBlockQueue, testMutilthreadConcurrentPutAndBlockInblankqueue001)(benchmark::State& state) +{ + BENCHMARK_LOGD("SafeBlockQueue testMutilthreadConcurrentPutAndBlockInblankqueue001 start."); + std::thread threads[THREAD_NUM]; + std::array demoDatas; + while (state.KeepRunning()) { + demoDatas.fill(DemoThreadData()); + using std::chrono::system_clock; + auto timeT = std::chrono::high_resolution_clock::now(); + timeT += std::chrono::milliseconds(SLEEP_FOR_TWENTY_MILLISECOND); + AssertTrue((DemoThreadData::shareQueue.IsEmpty()), + "DemoThreadData::shareQueue.IsEmpty() did not equal true as expected.", state); + for (unsigned int i = 0; i < THREAD_NUM; i++) { + threads[i] = std::thread(PutHandleThreadDataTime, + std::ref(demoDatas[i]), i, timeT); + } + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_TWENTY_MILLISECOND)); + AssertTrue((DemoThreadData::shareQueue.IsFull()), + "DemoThreadData::shareQueue.IsFull() did not equal true as expected.", state); + unsigned int pushedIn = 0; + unsigned int unpushedIn = 0; + unsigned int getedOut = 0; + unsigned int ungetedOut = 0; + GetThreadDatePushedStatus(demoDatas, pushedIn, unpushedIn); + AssertEqual(pushedIn, QUEUE_SLOTS, "pushedIn did not equal QUEUE_SLOTS as expected.", state); + AssertEqual(unpushedIn, THREAD_NUM - QUEUE_SLOTS, + "unpushedIn did not equal THREAD_NUM - QUEUE_SLOTS as expected.", state); + for (unsigned int i = 0; i < THREAD_NUM - QUEUE_SLOTS; i++) { + demoDatas[0].Get(); + } + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_TWENTY_MILLISECOND)); + AssertTrue((DemoThreadData::shareQueue.IsFull()), + "DemoThreadData::shareQueue.IsFull() did not equal true as expected.", state); + GetThreadDatePushedStatus(demoDatas, pushedIn, unpushedIn); + GetThreadDateGetedStatus(demoDatas, getedOut, ungetedOut); + AssertEqual(pushedIn, THREAD_NUM, "pushedIn did not equal THREAD_NUM as expected.", state); + AssertEqual(getedOut, THREAD_NUM - QUEUE_SLOTS, + "getedOut did not equal THREAD_NUM - QUEUE_SLOTS as expected.", state); + for (auto& t : threads) { + t.join(); + } + while (!DemoThreadData::shareQueue.IsEmpty()) { + demoDatas[0].Get(); + } + } + BENCHMARK_LOGD("SafeBlockQueue testMutilthreadConcurrentPutAndBlockInblankqueue001 end."); +} + +/* + * @tc.name: testMutilthreadConcurrentPutAndBlockInfullqueue001 + * @tc.desc: Multi-threaded put() on the full queue. When n threads are waiting to reach a certain + * time-point, everyone puts concurrent to see the status of the queue and the state of the thread. + */ +BENCHMARK_F(BenchmarkSafeBlockQueue, testMutilthreadConcurrentPutAndBlockInfullqueue001)(benchmark::State& state) +{ + BENCHMARK_LOGD("SafeBlockQueue testMutilthreadConcurrentPutAndBlockInfullqueue001 start."); + std::thread threads[THREAD_NUM]; + std::array demoDatas; + while (state.KeepRunning()) { + demoDatas.fill(DemoThreadData()); + using std::chrono::system_clock; + auto timeT = std::chrono::high_resolution_clock::now(); + timeT += std::chrono::milliseconds(SLEEP_FOR_TWENTY_MILLISECOND); + AssertTrue((DemoThreadData::shareQueue.IsEmpty()), + "DemoThreadData::shareQueue.IsEmpty() did not equal true as expected.", state); + for (unsigned int i = 0; i < QUEUE_SLOTS; i++) { + int t = i; + DemoThreadData::shareQueue.Push(t); + } + AssertTrue((DemoThreadData::shareQueue.IsFull()), + "DemoThreadData::shareQueue.IsFull() did not equal true as expected.", state); + for (unsigned int i = 0; i < THREAD_NUM; i++) { + threads[i] = std::thread(PutHandleThreadDataTime, + std::ref(demoDatas[i]), i, timeT); + } + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_TWENTY_MILLISECOND)); + unsigned int pushedIn = 0; + unsigned int unpushedIn = 0; + GetThreadDatePushedStatus(demoDatas, pushedIn, unpushedIn); + AssertEqual(pushedIn, static_cast(0), + "pushedIn did not equal static_cast(0) as expected.", state); + AssertEqual(unpushedIn, THREAD_NUM, "unpushedIn did not equal THREAD_NUM as expected.", state); + AssertTrue((DemoThreadData::shareQueue.IsFull()), + "DemoThreadData::shareQueue.IsFull() did not equal true as expected.", state); + for (unsigned int i = 0; i < THREAD_NUM; i++) { + DemoThreadData::shareQueue.Pop(); + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_TWENTY_MILLISECOND)); + AssertTrue((DemoThreadData::shareQueue.IsFull()), + "DemoThreadData::shareQueue.IsFull() did not equal true as expected.", state); + GetThreadDatePushedStatus(demoDatas, pushedIn, unpushedIn); + AssertEqual(pushedIn, i + 1, "pushedIn did not equal i + 1 as expected.", state); + AssertEqual(unpushedIn, THREAD_NUM - (i + 1), "unpushedIn did not equal THREAD_NUM - (i + 1).", state); + } + for (auto& t : threads) { + t.join(); + } + while (!DemoThreadData::shareQueue.IsEmpty()) { + demoDatas[0].Get(); + } + } + BENCHMARK_LOGD("SafeBlockQueue testMutilthreadConcurrentPutAndBlockInfullqueue001 end."); +} + +/* + * @tc.name: testMutilthreadConcurrentGetAndBlockInblankqueue001 + * @tc.desc: Multi-threaded get() on the empty queue. When n threads are waiting to reach a certain + * time-point, everyone gets concurrent to see the status of the queue and the state of the thread. + */ +BENCHMARK_F(BenchmarkSafeBlockQueue, testMutilthreadConcurrentGetAndBlockInblankqueue001)(benchmark::State& state) +{ + BENCHMARK_LOGD("SafeBlockQueue testMutilthreadConcurrentGetAndBlockInblankqueue001 start."); + std::thread threads[THREAD_NUM]; + std::array demoDatas; + while (state.KeepRunning()) { + demoDatas.fill(DemoThreadData()); + using std::chrono::system_clock; + auto timeT = std::chrono::high_resolution_clock::now(); + timeT += std::chrono::milliseconds(SLEEP_FOR_TWENTY_MILLISECOND); + AssertTrue((DemoThreadData::shareQueue.IsEmpty()), + "DemoThreadData::shareQueue.IsEmpty() did not equal true as expected.", state); + for (unsigned int i = 0; i < THREAD_NUM; i++) { + threads[i] = std::thread(GetHandleThreadDataTime, + std::ref(demoDatas[i]), i, timeT); + } + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_TWENTY_MILLISECOND)); + unsigned int getedOut = 0; + unsigned int ungetedOut = 0; + GetThreadDateGetedStatus(demoDatas, getedOut, ungetedOut); + AssertEqual(getedOut, static_cast(0), + "getedOut did not equal static_cast(0) as expected.", state); + AssertEqual(ungetedOut, THREAD_NUM, "ungetedOut did not equal THREAD_NUM as expected.", state); + AssertTrue((DemoThreadData::shareQueue.IsEmpty()), + "DemoThreadData::shareQueue.IsEmpty() did not equal true as expected.", state); + + int value = 1; + for (unsigned int i = 0; i < THREAD_NUM; i++) { + DemoThreadData::shareQueue.Push(value); + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_TWENTY_MILLISECOND)); + AssertTrue((DemoThreadData::shareQueue.IsEmpty()), + "DemoThreadData::shareQueue.IsEmpty() did not equal true as expected.", state); + GetThreadDateGetedStatus(demoDatas, getedOut, ungetedOut); + AssertEqual(getedOut, i + 1, "getedOut did not equal i + 1 as expected.", state); + AssertEqual(ungetedOut, THREAD_NUM - (i + 1), + "ungetedOut did not equal THREAD_NUM - (i + 1) as expected.", state); + } + for (auto& t : threads) { + t.join(); + } + + while (!DemoThreadData::shareQueue.IsEmpty()) { + demoDatas[0].Get(); + } + } + BENCHMARK_LOGD("SafeBlockQueue testMutilthreadConcurrentGetAndBlockInblankqueue001 end."); +} + +/* + * @tc.name: testMutilthreadConcurrentGetAndBlockInfullqueue001 + * @tc.desc: Multi-threaded get() on the full queue. When n threads are waiting to reach a certain + * time-point, everyone gets concurrent to see the status of the queue and the state of the thread. + */ +BENCHMARK_F(BenchmarkSafeBlockQueue, testMutilthreadConcurrentGetAndBlockInfullqueue001)(benchmark::State& state) +{ + BENCHMARK_LOGD("SafeBlockQueue testMutilthreadConcurrentGetAndBlockInfullqueue001 start."); + std::thread threads[THREAD_NUM]; + std::array demoDatas; + while (state.KeepRunning()) { + demoDatas.fill(DemoThreadData()); + using std::chrono::system_clock; + auto timeT = std::chrono::high_resolution_clock::now(); + timeT += std::chrono::milliseconds(SLEEP_FOR_TWENTY_MILLISECOND); + AssertTrue((DemoThreadData::shareQueue.IsEmpty()), + "DemoThreadData::shareQueue.IsEmpty() did not equal true as expected.", state); + int t = 1; + for (unsigned int i = 0; i < QUEUE_SLOTS; i++) { + DemoThreadData::shareQueue.Push(t); + } + AssertTrue((DemoThreadData::shareQueue.IsFull()), + "DemoThreadData::shareQueue.IsFull() did not equal true as expected.", state); + for (unsigned int i = 0; i < THREAD_NUM; i++) { + threads[i] = std::thread(GetHandleThreadDataTime, + std::ref(demoDatas[i]), i, timeT); + } + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_TWENTY_MILLISECOND)); + AssertTrue((DemoThreadData::shareQueue.IsEmpty()), + "DemoThreadData::shareQueue.IsEmpty() did not equal true as expected.", state); + unsigned int getedOut = 0; + unsigned int ungetedOut = 0; + GetThreadDateGetedStatus(demoDatas, getedOut, ungetedOut); + AssertEqual(getedOut, QUEUE_SLOTS, "getedOut did not equal QUEUE_SLOTS as expected.", state); + AssertEqual(ungetedOut, THREAD_NUM - QUEUE_SLOTS, "ungetedOut did not equal THREAD_NUM - QUEUE_SLOTS.", state); + for (unsigned int i = 0; i < THREAD_NUM - QUEUE_SLOTS; i++) { + demoDatas[0].Put(t); + } + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_TWENTY_MILLISECOND)); + AssertTrue((DemoThreadData::shareQueue.IsEmpty()), + "DemoThreadData::shareQueue.IsEmpty() did not equal true as expected.", state); + GetThreadDateGetedStatus(demoDatas, getedOut, ungetedOut); + AssertEqual(getedOut, THREAD_NUM, "getedOut did not equal THREAD_NUM as expected.", state); + AssertEqual(ungetedOut, static_cast(0), + "ungetedOut did not equal static_cast(0) as expected.", state); + for (auto& t : threads) { + t.join(); + } + while (!DemoThreadData::shareQueue.IsEmpty()) { + demoDatas[0].Get(); + } + } + BENCHMARK_LOGD("SafeBlockQueue testMutilthreadConcurrentGetAndBlockInfullqueue001 end."); +} + +/* + * @tc.name: testMutilthreadConcurrentGetAndBlockInnotfullqueue001 + * @tc.desc: Multi-threaded get() on the notfull queue. When n threads are waiting to reach a certain + * time-point, everyone get concurrent to see the status of the queue and the state of the thread. + */ +BENCHMARK_F(BenchmarkSafeBlockQueue, testMutilthreadConcurrentGetAndBlockInnotfullqueue001)(benchmark::State& state) +{ + BENCHMARK_LOGD("SafeBlockQueue testMutilthreadConcurrentGetAndBlockInnotfullqueue001 start."); + std::thread threads[THREAD_NUM]; + std::array demoDatas; + while (state.KeepRunning()) { + demoDatas.fill(DemoThreadData()); + using std::chrono::system_clock; + const unsigned int REMAIN_SLOTS = 5; + auto timeT = std::chrono::high_resolution_clock::now(); + timeT += std::chrono::milliseconds(SLEEP_FOR_TWENTY_MILLISECOND); + AssertTrue((DemoThreadData::shareQueue.IsEmpty()), + "DemoThreadData::shareQueue.IsEmpty() did not equal true as expected.", state); + for (unsigned int i = 0; i < QUEUE_SLOTS - REMAIN_SLOTS; i++) { + int t = i; + DemoThreadData::shareQueue.Push(t); + } + for (unsigned int i = 0; i < THREAD_NUM; i++) { + threads[i] = std::thread(GetHandleThreadDataTime, + std::ref(demoDatas[i]), i, timeT); + } + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_TWENTY_MILLISECOND)); + unsigned int getedOut = 0; + unsigned int ungetedOut = 0; + GetThreadDateGetedStatus(demoDatas, getedOut, ungetedOut); + AssertEqual(getedOut, QUEUE_SLOTS - REMAIN_SLOTS, + "getedOut did not equal QUEUE_SLOTS - REMAIN_SLOTS as expected.", state); + AssertEqual(ungetedOut, THREAD_NUM - (QUEUE_SLOTS - REMAIN_SLOTS), + "ungetedOut did not equal THREAD_NUM - (QUEUE_SLOTS - REMAIN_SLOTS) as expected.", state); + for (unsigned int i = 0; i < ungetedOut; i++) { + int t = i; + DemoThreadData::shareQueue.Push(t); + } + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_TWENTY_MILLISECOND)); + GetThreadDateGetedStatus(demoDatas, getedOut, ungetedOut); + AssertEqual(getedOut, THREAD_NUM, "getedOut did not equal THREAD_NUM as expected.", state); + AssertEqual(ungetedOut, static_cast(0), + "ungetedOut did not equal static_cast(0) as expected.", state); + for (auto& t : threads) { + t.join(); + } + while (!DemoThreadData::shareQueue.IsEmpty()) { + demoDatas[0].Get(); + } + } + BENCHMARK_LOGD("SafeBlockQueue testMutilthreadConcurrentGetAndBlockInnotfullqueue001 end."); +} + +/* + * @tc.name: testMutilthreadConcurrentPutAndBlockInnotfullqueue001 + * @tc.desc: Multi-threaded put() on the not full queue. When n threads are waiting to reach a certain + * time-point, everyone puts concurrent to see the status of the queue and the state of the thread. + */ +BENCHMARK_F(BenchmarkSafeBlockQueue, testMutilthreadConcurrentPutAndBlockInnotfullqueue001)(benchmark::State& state) +{ + BENCHMARK_LOGD("SafeBlockQueue testMutilthreadConcurrentPutAndBlockInnotfullqueue001 start."); + std::thread threads[THREAD_NUM]; + std::array demoDatas; + while (state.KeepRunning()) { + demoDatas.fill(DemoThreadData()); + using std::chrono::system_clock; + const unsigned int REMAIN_SLOTS = 5; + auto timeT = std::chrono::high_resolution_clock::now(); + timeT += std::chrono::milliseconds(SLEEP_FOR_TWENTY_MILLISECOND); + AssertTrue((DemoThreadData::shareQueue.IsEmpty()), + "DemoThreadData::shareQueue.IsEmpty() did not equal true as expected.", state); + for (unsigned int i = 0; i < QUEUE_SLOTS - REMAIN_SLOTS; i++) { + int t = i; + DemoThreadData::shareQueue.Push(t); + } + for (unsigned int i = 0; i < THREAD_NUM; i++) { + threads[i] = std::thread(PutHandleThreadDataTime, + std::ref(demoDatas[i]), i, timeT); + } + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_TWENTY_MILLISECOND)); + unsigned int putedin = 0; + unsigned int unputedin = 0; + GetThreadDatePushedStatus(demoDatas, putedin, unputedin); + AssertEqual(putedin, REMAIN_SLOTS, "putedin did not equal REMAIN_SLOTS as expected.", state); + AssertEqual(unputedin, THREAD_NUM - REMAIN_SLOTS, + "unputedin did not equal THREAD_NUM - REMAIN_SLOTS as expected.", state); + for (unsigned int i = 0; i < unputedin; i++) { + DemoThreadData::shareQueue.Pop(); + } + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_TWENTY_MILLISECOND)); + GetThreadDatePushedStatus(demoDatas, putedin, unputedin); + AssertEqual(putedin, THREAD_NUM, "putedin did not equal THREAD_NUM as expected.", state); + AssertEqual(unputedin, static_cast(0), + "unputedin did not equal static_cast(0) as expected.", state); + for (auto& t : threads) { + t.join(); + } + while (!DemoThreadData::shareQueue.IsEmpty()) { + demoDatas[0].Get(); + } + } + BENCHMARK_LOGD("SafeBlockQueue testMutilthreadConcurrentPutAndBlockInnotfullqueue001 end."); +} + +/* + * @tc.name: testMutilthreadConcurrentGetAndPopInblankqueue001 + * @tc.desc: Multi-threaded put() and Multi-threaded get() on the empty queue. When all threads are waiting to reach + * a certain time-point, everyone run concurrently to see the status of the queue and the state of the thread. + */ +BENCHMARK_F(BenchmarkSafeBlockQueue, testMutilthreadConcurrentGetAndPopInblankqueue001)(benchmark::State& state) +{ + BENCHMARK_LOGD("SafeBlockQueue testMutilthreadConcurrentGetAndPopInblankqueue001 start."); + std::thread threadsout[THREAD_NUM]; + std::array demoDatas; + while (state.KeepRunning()) { + demoDatas.fill(DemoThreadData()); + std::thread threadsin[THREAD_NUM]; + using std::chrono::system_clock; + auto timeT = std::chrono::high_resolution_clock::now(); + timeT += std::chrono::milliseconds(SLEEP_FOR_TWENTY_MILLISECOND); + AssertTrue((DemoThreadData::shareQueue.IsEmpty()), + "DemoThreadData::shareQueue.IsEmpty() did not equal true as expected.", state); + for (unsigned int i = 0; i < THREAD_NUM; i++) { + threadsout[i] = std::thread(GetHandleThreadDataTime, + std::ref(demoDatas[i]), i, timeT); + } + for (unsigned int i = 0; i < THREAD_NUM; i++) { + threadsin[i] = std::thread(PutHandleThreadDataTime, + std::ref(demoDatas[i]), i, timeT); + } + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_TWENTY_MILLISECOND)); + AssertTrue((DemoThreadData::shareQueue.IsEmpty()), + "DemoThreadData::shareQueue.IsEmpty() did not equal true as expected.", state); + unsigned int getedOut = 0; + unsigned int ungetedOut = 0; + unsigned int pushedIn = 0; + unsigned int unpushedIn = 0; + GetThreadDateGetedStatus(demoDatas, getedOut, ungetedOut); + GetThreadDatePushedStatus(demoDatas, pushedIn, unpushedIn); + AssertEqual(pushedIn, THREAD_NUM, "pushedIn did not equal THREAD_NUM as expected.", state); + AssertEqual(getedOut, THREAD_NUM, "getedOut did not equal THREAD_NUM as expected.", state); + for (auto& t : threadsout) { + t.join(); + } + for (auto& t : threadsin) { + t.join(); + } + while (!DemoThreadData::shareQueue.IsEmpty()) { + demoDatas[0].Get(); + } + } + BENCHMARK_LOGD("SafeBlockQueue testMutilthreadConcurrentGetAndPopInblankqueue001 end."); +} + +/* + * @tc.name: testMutilthreadConcurrentGetAndPopInfullqueue001 + * @tc.desc: Multi-threaded put() and Multi-threaded get() on the full queue. + * When all threads are waiting to reach a certain + * time-point, everyone run concurrently to see the status of the queue and the state of the thread. + */ +BENCHMARK_F(BenchmarkSafeBlockQueue, testMutilthreadConcurrentGetAndPopInfullqueue001)(benchmark::State& state) +{ + BENCHMARK_LOGD("SafeBlockQueue testMutilthreadConcurrentGetAndPopInfullqueue001 start."); + std::thread threadsout[THREAD_NUM]; + std::array demoDatas; + while (state.KeepRunning()) { + demoDatas.fill(DemoThreadData()); + std::thread threadsin[THREAD_NUM]; + using std::chrono::system_clock; + auto timeT = std::chrono::high_resolution_clock::now(); + timeT += std::chrono::milliseconds(SLEEP_FOR_TWENTY_MILLISECOND); + AssertTrue((DemoThreadData::shareQueue.IsEmpty()), + "DemoThreadData::shareQueue.IsEmpty() did not equal true as expected.", state); + int t = 1; + for (unsigned int i = 0; i < QUEUE_SLOTS; i++) { + DemoThreadData::shareQueue.Push(t); + } + AssertTrue((DemoThreadData::shareQueue.IsFull()), + "DemoThreadData::shareQueue.IsFull() did not equal true as expected.", state); + for (unsigned int i = 0; i < THREAD_NUM; i++) { + threadsin[i] = std::thread(PutHandleThreadDataTime, + std::ref(demoDatas[i]), i, timeT); + } + for (unsigned int i = 0; i < THREAD_NUM; i++) { + threadsout[i] = std::thread(GetHandleThreadDataTime, + std::ref(demoDatas[i]), i, timeT); + } + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_TWENTY_MILLISECOND)); + AssertTrue((DemoThreadData::shareQueue.IsFull()), + "DemoThreadData::shareQueue.IsFull() did not equal true as expected.", state); + unsigned int getedOut = 0; + unsigned int ungetedOut = 0; + unsigned int pushedIn = 0; + unsigned int unpushedIn = 0; + GetThreadDateGetedStatus(demoDatas, getedOut, ungetedOut); + GetThreadDatePushedStatus(demoDatas, pushedIn, unpushedIn); + AssertEqual(pushedIn, THREAD_NUM, "pushedIn did not equal THREAD_NUM as expected.", state); + AssertEqual(getedOut, THREAD_NUM, "getedOut did not equal THREAD_NUM as expected.", state); + for (auto& t : threadsout) { + t.join(); + } + for (auto& t : threadsin) { + t.join(); + } + while (!DemoThreadData::shareQueue.IsEmpty()) { + demoDatas[0].Get(); + } + } + BENCHMARK_LOGD("SafeBlockQueue testMutilthreadConcurrentGetAndPopInfullqueue001 end."); +} + +/* + * @tc.name: testPushNoWait001 + * @tc.desc: Single-threaded call PushNoWait and check the performance + */ +BENCHMARK_F(BenchmarkSafeBlockQueue, testPushNoWait001)(benchmark::State& state) +{ + BENCHMARK_LOGD("SafeBlockQueue testPushNoWait001 start."); + while (state.KeepRunning()) { + SafeBlockQueue qi(QUEUE_CAPACITY); + int i = 1; + bool result = qi.PushNoWait(i); + AssertTrue(result, "PushNoWait returned false, expected true.", state); + } + BENCHMARK_LOGD("SafeBlockQueue testPushNoWait001 end."); +} + +/* + * @tc.name: testPopNoWait001 + * @tc.desc: Single-threaded call PopNoWait and check the performance + */ +BENCHMARK_F(BenchmarkSafeBlockQueue, testPopNoWait001)(benchmark::State& state) +{ + BENCHMARK_LOGD("SafeBlockQueue testPopNoWait001 start."); + const int pushCount = 10; + while (state.KeepRunning()) { + SafeBlockQueue qi(QUEUE_CAPACITY); + for (int i = 0; i < pushCount; i++) { + qi.Push(i); // Fill the queue + } + int out; + bool result = qi.PopNotWait(out); + AssertTrue(result, "PopNoWait returned false, expected true.", state); + } + BENCHMARK_LOGD("SafeBlockQueue testPopNoWait001 end."); +} +} // namespace +} // namespace OHOS +// Run the benchmark +BENCHMARK_MAIN(); \ No newline at end of file diff --git a/base/test/benchmarktest/safe_block_queue_tracking_benchmark_test/BUILD.gn b/base/test/benchmarktest/safe_block_queue_tracking_benchmark_test/BUILD.gn new file mode 100644 index 0000000..8557000 --- /dev/null +++ b/base/test/benchmarktest/safe_block_queue_tracking_benchmark_test/BUILD.gn @@ -0,0 +1,35 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/test.gni") + +module_output_path = "commonlibrary_c_utils/safe_block_queue_tracking" + +ohos_benchmarktest("SafeBlockQueueTrackingTest") { + module_out_path = module_output_path + + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + sources = [ "safe_block_queue_tracking_benchmark_test.cpp" ] + + deps = [ "//third_party/benchmark:benchmark" ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog_base", + ] +} diff --git a/base/test/benchmarktest/safe_block_queue_tracking_benchmark_test/safe_block_queue_tracking_benchmark_test.cpp b/base/test/benchmarktest/safe_block_queue_tracking_benchmark_test/safe_block_queue_tracking_benchmark_test.cpp new file mode 100644 index 0000000..6184d9f --- /dev/null +++ b/base/test/benchmarktest/safe_block_queue_tracking_benchmark_test/safe_block_queue_tracking_benchmark_test.cpp @@ -0,0 +1,669 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "safe_block_queue.h" +#include +#include +#include +#include +#include +#include "../log.h" +#include "../assert.h" +using namespace std; + +namespace OHOS { +namespace { + +class BenchmarkSafeBlockQueueTracking : public benchmark::Fixture { +public: + BenchmarkSafeBlockQueueTracking() + { + Iterations(iterations); + Repetitions(repetitions); + ReportAggregatesOnly(); + } + + ~BenchmarkSafeBlockQueueTracking() override = default; + void SetUp(const ::benchmark::State& state) override + { + } + + void TearDown(const ::benchmark::State& state) override + { + } + +protected: + const int32_t repetitions = 3; + const int32_t iterations = 50; +}; + +const unsigned int QUEUE_SLOTS = 5; +const unsigned int THREAD_NUM = QUEUE_SLOTS + 1; +const int QUEUE_CAPACITY = 10; +const int SLEEP_FOR_HUNDRED_MILLISECOND = 50; + +class DemoThreadData { +public: + DemoThreadData() + { + putStatus = false; + getStatus = false; + joinStatus = false; + } + + static SafeBlockQueueTracking shareQueue; + static bool joinStatus; + bool putStatus; + bool getStatus; + + void Put(int i) + { + shareQueue.Push(i); + putStatus = true; + } + + void Get() + { + shareQueue.Pop(); + getStatus = true; + } + + void GetAndOneTaskDone() + { + shareQueue.Pop(); + getStatus = true; + shareQueue.OneTaskDone(); + } + + void Join() + { + shareQueue.Join(); + joinStatus = true; + } +}; + +SafeBlockQueueTracking DemoThreadData::shareQueue(QUEUE_SLOTS); +bool DemoThreadData::joinStatus = false; + +void PutHandleThreadData(DemoThreadData& q, int i) +{ + q.Put(i); +} + +void GetThreadDatePushedStatus(std::array& demoDatas, unsigned int& pushedIn, + unsigned int& unpushedIn) +{ + pushedIn = 0; + unpushedIn = 0; + for (auto& t : demoDatas) { + if (t.putStatus) { + pushedIn++; + } else { + unpushedIn++; + } + } +} + +void GetThreadDateGetedStatus(std::array& demoDatas, unsigned int& getedOut, + unsigned int& ungetedOut) +{ + getedOut = 0; + ungetedOut = 0; + for (auto& t : demoDatas) { + if (t.getStatus) { + getedOut++; + } else { + ungetedOut++; + } + } +} + +void PutHandleThreadDataTime(DemoThreadData& q, int i, + std::chrono::time_point absTime) +{ + std::this_thread::sleep_until(absTime); + q.Put(i); +} + +void GetAndOneTaskDoneHandleThreadDataTime(DemoThreadData& q, int i, + std::chrono::time_point absTime) +{ + std::this_thread::sleep_until(absTime); + q.GetAndOneTaskDone(); +} + +void StartThreads(std::thread (&threads)[THREAD_NUM], + void (*function)(DemoThreadData&, int, std::chrono::time_point), + std::array& demoDatas, + std::chrono::time_point timeT) +{ + for (unsigned int i = 0; i < THREAD_NUM; i++) { + threads[i] = std::thread(function, std::ref(demoDatas[i]), i, timeT); + } +} + +template +void joinAllThreads(std::thread (&threads)[N]) +{ + for (auto& t : threads) { + if (t.joinable()) { + t.join(); + } + } +} + +void processSharedQueueTasks(DemoThreadData& data) +{ + while (!DemoThreadData::shareQueue.IsEmpty()) { + data.GetAndOneTaskDone(); + } +} + +/* + * @tc.name: testPut001 + * @tc.desc: Single-threaded call put and get to determine that the normal scenario is working properly + */ +BENCHMARK_F(BenchmarkSafeBlockQueueTracking, testPut001)(benchmark::State& state) +{ + BENCHMARK_LOGD("SafeBlockQueueTracking testPut001 start."); + while (state.KeepRunning()) { + SafeBlockQueueTracking qi(QUEUE_CAPACITY); + int i = 1; + qi.Push(i); + AssertEqual(static_cast(1), qi.Size(), + "static_cast(1) did not equal qi.Size() as expected.", state); + AssertGreaterThan(qi.GetUnfinishTaskNum(), 0, + "qi.GetUnfinishTaskNum() was not greater than 0 as expected.", state); + } + BENCHMARK_LOGD("SafeBlockQueueTracking testPut001 end."); +} + +/* + * @tc.name: testGet001 + * @tc.desc: Single-threaded call put and get to determine that the normal scenario is working properly + */ +BENCHMARK_F(BenchmarkSafeBlockQueueTracking, testGet001)(benchmark::State& state) +{ + BENCHMARK_LOGD("SafeBlockQueueTracking testGet001 start."); + const int numberOfPushes = 3; + const int expectedFirstElement = 0; + const int minValueForComparison = 0; + while (state.KeepRunning()) { + SafeBlockQueueTracking qi(QUEUE_CAPACITY); + for (int i = 0; i < numberOfPushes; i++) { + qi.Push(i); + } + AssertEqual(static_cast(numberOfPushes), qi.Size(), + "static_cast(numberOfPushes) did not equal qi.Size() as expected.", state); + int t = qi.Pop(); + AssertEqual(t, expectedFirstElement, "t did not equal expectedFirstElement as expected.", state); + AssertGreaterThan(qi.GetUnfinishTaskNum(), minValueForComparison, + "qi.GetUnfinishTaskNum() was not greater than minValueForComparison as expected.", state); + } + BENCHMARK_LOGD("SafeBlockQueueTracking testGet001 end."); +} + +/* + * @tc.name: testMutilthreadPutAndBlock001 + * @tc.desc: Multiple threads put until blocking runs, one thread gets, all threads finish running normally + */ +BENCHMARK_F(BenchmarkSafeBlockQueueTracking, testMutilthreadPutAndBlock001)(benchmark::State& state) +{ + BENCHMARK_LOGD("SafeBlockQueueTracking testMutilthreadPutAndBlock001 start."); + const int putValue = 1; + std::thread threads[THREAD_NUM]; + std::array demoDatas; + while (state.KeepRunning()) { + demoDatas.fill(DemoThreadData()); + demoDatas[0].Put(putValue); + AssertFalse((demoDatas[0].joinStatus), "step 1: demoDatas[0].joinStatus did not equal false.", state); + + // start thread to join + DemoThreadData tmp = DemoThreadData(); + std::thread joinThread = std::thread(&DemoThreadData::Join, tmp); + AssertFalse((demoDatas[0].joinStatus), "step 2: demoDatas[0].joinStatus did not equal false.", state); + + for (unsigned int i = 0; i < THREAD_NUM; i++) { + threads[i] = std::thread(PutHandleThreadData, std::ref(demoDatas[i]), i); + } + AssertFalse((demoDatas[0].joinStatus), "step 3: demoDatas[0].joinStatus did not equal false.", state); + // 1. queue is full and some threads is blocked + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_HUNDRED_MILLISECOND)); + AssertTrue((DemoThreadData::shareQueue.IsFull()), + "DemoThreadData::shareQueue.IsFull() did not equal true as expected.", state); + + AssertFalse((demoDatas[0].joinStatus), "step 4: demoDatas[0].joinStatus did not equal false.", state); + // 2. get one out and wait some put in + for (unsigned int i = 0; i < THREAD_NUM; i++) { + demoDatas[0].GetAndOneTaskDone(); + AssertFalse((demoDatas[0].joinStatus), "step 5: demoDatas[0].joinStatus did not equal false.", state); + } + AssertFalse((demoDatas[0].joinStatus), "step 6: demoDatas[0].joinStatus did not equal false.", state); + demoDatas[0].GetAndOneTaskDone(); + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_HUNDRED_MILLISECOND)); + + AssertTrue((demoDatas[0].joinStatus), "step 7: demoDatas[0].joinStatus did not equal true.", state); + + // recover state + joinAllThreads(threads); + joinThread.join(); + + processSharedQueueTasks(demoDatas[0]); + demoDatas[0].joinStatus = false; + } + BENCHMARK_LOGD("SafeBlockQueueTracking testMutilthreadPutAndBlock001 end."); +} + +/* + * @tc.name: PutAndBlockInblankqueue001 + * @tc.desc: Multi-threaded put() on the empty queue. When n threads are waiting to reach a certain + * time-point, everyone puts concurrent to see the status of the queue and the state of the thread. + */ +BENCHMARK_F(BenchmarkSafeBlockQueueTracking, PutAndBlockInblankqueue001)(benchmark::State& state) +{ + BENCHMARK_LOGD("SafeBlockQueueTracking PutAndBlockInblankqueue001 start."); + std::thread threads[THREAD_NUM]; + std::array demoDatas; + while (state.KeepRunning()) { + demoDatas.fill(DemoThreadData()); + using std::chrono::system_clock; + auto timeT = std::chrono::high_resolution_clock::now(); + timeT += std::chrono::milliseconds(SLEEP_FOR_HUNDRED_MILLISECOND); + AssertTrue((DemoThreadData::shareQueue.IsEmpty()), + "DemoThreadData::shareQueue.IsEmpty() did not equal true as expected.", state); + StartThreads(threads, PutHandleThreadDataTime, demoDatas, timeT); + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_HUNDRED_MILLISECOND)); + DemoThreadData tmp = DemoThreadData(); + std::thread joinThread = std::thread(&DemoThreadData::Join, tmp); + AssertFalse((demoDatas[0].joinStatus), "step 1: demoDatas[0].joinStatus did not equal false.", state); + AssertTrue((DemoThreadData::shareQueue.IsFull()), + "DemoThreadData::shareQueue.IsFull() did not equal true as expected.", state); + unsigned int pushedIn = 0; + unsigned int unpushedIn = 0; + unsigned int getedOut = 0; + unsigned int ungetedOut = 0; + GetThreadDatePushedStatus(demoDatas, pushedIn, unpushedIn); + AssertEqual(pushedIn, QUEUE_SLOTS, "pushedIn did not equal QUEUE_SLOTS as expected.", state); + AssertEqual(unpushedIn, THREAD_NUM - QUEUE_SLOTS, + "unpushedIn did not equal THREAD_NUM - QUEUE_SLOTS as expected.", state); + for (unsigned int i = 0; i < THREAD_NUM - QUEUE_SLOTS; i++) { + demoDatas[0].GetAndOneTaskDone(); + AssertFalse((demoDatas[0].joinStatus), "step 2: demoDatas[0].joinStatus did not equal false.", state); + } + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_HUNDRED_MILLISECOND)); + AssertTrue((DemoThreadData::shareQueue.IsFull()), + "DemoThreadData::shareQueue.IsFull() did not equal true as expected.", state); + GetThreadDatePushedStatus(demoDatas, pushedIn, unpushedIn); + GetThreadDateGetedStatus(demoDatas, getedOut, ungetedOut); + AssertEqual(pushedIn, THREAD_NUM, "pushedIn did not equal THREAD_NUM as expected.", state); + AssertEqual(getedOut, THREAD_NUM - QUEUE_SLOTS, + "getedOut did not equal THREAD_NUM - QUEUE_SLOTS as expected.", state); + joinAllThreads(threads); + processSharedQueueTasks(demoDatas[0]); + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_HUNDRED_MILLISECOND)); + AssertTrue((demoDatas[0].joinStatus), "step 3: demoDatas[0].joinStatus did not equal true.", state); + demoDatas[0].joinStatus = false; + joinThread.join(); + } + BENCHMARK_LOGD("SafeBlockQueueTracking PutAndBlockInblankqueue001 end."); +} + +/* + * @tc.name: testPutAndBlockInFullQueue001 + * @tc.desc: Multi-threaded put() on the full queue. When n threads are waiting to reach a certain + * time-point, everyone puts concurrent to see the status of the queue and the state of the thread. + */ +BENCHMARK_F(BenchmarkSafeBlockQueueTracking, testPutAndBlockInFullQueue001)(benchmark::State& state) +{ + BENCHMARK_LOGD("SafeBlockQueueTracking testPutAndBlockInFullQueue001 start."); + std::thread threads[THREAD_NUM]; + std::array demoDatas; + while (state.KeepRunning()) { + demoDatas.fill(DemoThreadData()); + using std::chrono::system_clock; + auto timeT = std::chrono::high_resolution_clock::now(); + timeT += std::chrono::milliseconds(SLEEP_FOR_HUNDRED_MILLISECOND); + AssertTrue((DemoThreadData::shareQueue.IsEmpty()), + "DemoThreadData::shareQueue.IsEmpty() did not equal true as expected.", state); + for (unsigned int i = 0; i < QUEUE_SLOTS; i++) { + int t = i; + DemoThreadData::shareQueue.Push(t); + } + AssertTrue((DemoThreadData::shareQueue.IsFull()), "shareQueue.IsFull() did not equal true.", state); + StartThreads(threads, PutHandleThreadDataTime, demoDatas, timeT); + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_HUNDRED_MILLISECOND)); + DemoThreadData tmp = DemoThreadData(); + std::thread joinThread = std::thread(&DemoThreadData::Join, tmp); + AssertFalse((demoDatas[0].joinStatus), "demoDatas[0].joinStatus did not equal false as expected.", state); + unsigned int pushedIn = 0; + unsigned int unpushedIn = 0; + GetThreadDatePushedStatus(demoDatas, pushedIn, unpushedIn); + AssertEqual(pushedIn, static_cast(0), + "pushedIn did not equal static_cast(0) as expected.", state); + AssertEqual(unpushedIn, THREAD_NUM, "unpushedIn did not equal THREAD_NUM as expected.", state); + AssertTrue((DemoThreadData::shareQueue.IsFull()), + "DemoThreadData::shareQueue.IsFull() did not equal true as expected.", state); + for (unsigned int i = 0; i < THREAD_NUM; i++) { + DemoThreadData::shareQueue.Pop(); + DemoThreadData::shareQueue.OneTaskDone(); + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_HUNDRED_MILLISECOND)); + AssertTrue((DemoThreadData::shareQueue.IsFull()), "shareQueue.IsFull() did not equal true.", state); + GetThreadDatePushedStatus(demoDatas, pushedIn, unpushedIn); + AssertEqual(pushedIn, i + 1, "pushedIn did not equal i + 1 as expected.", state); + AssertEqual(unpushedIn, THREAD_NUM - (i + 1), + "unpushedIn did not equal THREAD_NUM - (i + 1) as expected.", state); + } + joinAllThreads(threads); + processSharedQueueTasks(demoDatas[0]); + demoDatas[0].joinStatus = false; + joinThread.join(); + } + BENCHMARK_LOGD("SafeBlockQueueTracking testPutAndBlockInFullQueue001 end."); +} + +/* + * @tc.name: GetAndBlockInblankqueue001 + * @tc.desc: Multi-threaded get() on the empty queue. When n threads are waiting to reach a certain + * time-point, everyone gets concurrent to see the status of the queue and the state of the thread. + */ +BENCHMARK_F(BenchmarkSafeBlockQueueTracking, GetAndBlockInblankqueue001)(benchmark::State& state) +{ + BENCHMARK_LOGD("SafeBlockQueueTracking GetAndBlockInblankqueue001 start."); + std::thread threads[THREAD_NUM]; + std::array demoDatas; + while (state.KeepRunning()) { + demoDatas.fill(DemoThreadData()); + using std::chrono::system_clock; + auto timeT = std::chrono::high_resolution_clock::now(); + timeT += std::chrono::milliseconds(SLEEP_FOR_HUNDRED_MILLISECOND); + AssertTrue((DemoThreadData::shareQueue.IsEmpty()), + "DemoThreadData::shareQueue.IsEmpty() did not equal true as expected.", state); + StartThreads(threads, GetAndOneTaskDoneHandleThreadDataTime, demoDatas, timeT); + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_HUNDRED_MILLISECOND)); + unsigned int getedOut = 0; + unsigned int ungetedOut = 0; + GetThreadDateGetedStatus(demoDatas, getedOut, ungetedOut); + AssertEqual(getedOut, static_cast(0), + "getedOut did not equal static_cast(0) as expected.", state); + AssertEqual(ungetedOut, THREAD_NUM, "ungetedOut did not equal THREAD_NUM as expected.", state); + AssertTrue((DemoThreadData::shareQueue.IsEmpty()), + "DemoThreadData::shareQueue.IsEmpty() did not equal true as expected.", state); + DemoThreadData tmp = DemoThreadData(); + std::thread joinThread = std::thread(&DemoThreadData::Join, tmp); + AssertFalse((demoDatas[0].joinStatus), "demoDatas[0].joinStatus did not equal false as expected.", state); + int value = 1; + for (unsigned int i = 0; i < THREAD_NUM; i++) { + DemoThreadData::shareQueue.Push(value); + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_HUNDRED_MILLISECOND)); + AssertTrue((DemoThreadData::shareQueue.IsEmpty()), + "DemoThreadData::shareQueue.IsEmpty() did not equal true as expected.", state); + GetThreadDateGetedStatus(demoDatas, getedOut, ungetedOut); + AssertEqual(getedOut, i + 1, "getedOut did not equal i + 1 as expected.", state); + AssertEqual(ungetedOut, THREAD_NUM - (i + 1), + "ungetedOut did not equal THREAD_NUM - (i + 1) as expected.", state); + } + joinAllThreads(threads); + processSharedQueueTasks(demoDatas[0]); + AssertTrue((demoDatas[0].joinStatus), "demoDatas[0].joinStatus did not equal true as expected.", state); + demoDatas[0].joinStatus = false; + joinThread.join(); + } + BENCHMARK_LOGD("SafeBlockQueueTracking GetAndBlockInblankqueue001 end."); +} + +/* + * @tc.name: GetAndBlockInfullqueue001 + * @tc.desc: Multi-threaded get() on the full queue. When n threads are waiting to reach a certain + * time-point, everyone gets concurrent to see the status of the queue and the state of the thread. + */ +BENCHMARK_F(BenchmarkSafeBlockQueueTracking, GetAndBlockInfullqueue001)(benchmark::State& state) +{ + BENCHMARK_LOGD("SafeBlockQueueTracking GetAndBlockInfullqueue001 start."); + std::thread threads[THREAD_NUM]; + std::array demoDatas; + while (state.KeepRunning()) { + demoDatas.fill(DemoThreadData()); + using std::chrono::system_clock; + auto timeT = std::chrono::high_resolution_clock::now(); + timeT += std::chrono::milliseconds(SLEEP_FOR_HUNDRED_MILLISECOND); + AssertTrue((DemoThreadData::shareQueue.IsEmpty()), "shareQueue.IsEmpty() did not equal true.", state); + int t = 1; + for (unsigned int i = 0; i < QUEUE_SLOTS; i++) { + DemoThreadData::shareQueue.Push(t); + } + AssertTrue((DemoThreadData::shareQueue.IsFull()), "shareQueue.IsFull() did not equal true.", state); + demoDatas[0].joinStatus = false; + DemoThreadData tmp = DemoThreadData(); + std::thread joinThread = std::thread(&DemoThreadData::Join, tmp); + AssertFalse((demoDatas[0].joinStatus), "step 1: demoDatas[0].joinStatus did not equal false.", state); + StartThreads(threads, GetAndOneTaskDoneHandleThreadDataTime, demoDatas, timeT); + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_HUNDRED_MILLISECOND)); + AssertTrue((DemoThreadData::shareQueue.IsEmpty()), "shareQueue.IsEmpty() did not equal true.", state); + AssertTrue((demoDatas[0].joinStatus), "step 2: demoDatas[0].joinStatus did not equal true.", state); + unsigned int getedOut = 0; + unsigned int ungetedOut = 0; + GetThreadDateGetedStatus(demoDatas, getedOut, ungetedOut); + AssertEqual(getedOut, QUEUE_SLOTS, "getedOut did not equal QUEUE_SLOTS as expected.", state); + AssertEqual(ungetedOut, THREAD_NUM - QUEUE_SLOTS, "ungetedOut did not equal THREAD_NUM - QUEUE_SLOTS", state); + for (unsigned int i = 0; i < THREAD_NUM - QUEUE_SLOTS; i++) { + demoDatas[0].Put(t); + } + demoDatas[0].joinStatus = false; + DemoThreadData tmp2 = DemoThreadData(); + std::thread joinThread2 = std::thread(&DemoThreadData::Join, tmp2); + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_HUNDRED_MILLISECOND)); + AssertTrue((DemoThreadData::shareQueue.IsEmpty()), "shareQueue.IsEmpty() did not equal true.", state); + AssertTrue((demoDatas[0].joinStatus), "step 3: demoDatas[0].joinStatus did not equal true.", state); + GetThreadDateGetedStatus(demoDatas, getedOut, ungetedOut); + AssertEqual(getedOut, THREAD_NUM, "getedOut did not equal THREAD_NUM as expected.", state); + AssertEqual(ungetedOut, static_cast(0), + "ungetedOut did not equal static_cast(0) as expected.", state); + joinAllThreads(threads); + processSharedQueueTasks(demoDatas[0]); + demoDatas[0].joinStatus = false; + joinThread.join(); + joinThread2.join(); + } + BENCHMARK_LOGD("SafeBlockQueueTracking GetAndBlockInfullqueue001 end."); +} + +/* + * @tc.name: GetAndBlockInnotfullqueue001 + * @tc.desc: Multi-threaded get() on the notfull queue. When n threads are waiting to reach a certain + * time-point, everyone get concurrent to see the status of the queue and the state of the thread. + */ +BENCHMARK_F(BenchmarkSafeBlockQueueTracking, GetAndBlockInnotfullqueue001)(benchmark::State& state) +{ + BENCHMARK_LOGD("SafeBlockQueueTracking GetAndBlockInnotfullqueue001 start."); + std::thread threads[THREAD_NUM]; + std::array demoDatas; + while (state.KeepRunning()) { + demoDatas.fill(DemoThreadData()); + using std::chrono::system_clock; + const unsigned int REMAIN_SLOTS = 3; + auto timeT = std::chrono::high_resolution_clock::now(); + timeT += std::chrono::milliseconds(SLEEP_FOR_HUNDRED_MILLISECOND); + AssertTrue((DemoThreadData::shareQueue.IsEmpty()), + "DemoThreadData::shareQueue.IsEmpty() did not equal true as expected.", state); + for (unsigned int i = 0; i < QUEUE_SLOTS - REMAIN_SLOTS; i++) { + int t = i; + DemoThreadData::shareQueue.Push(t); + } + demoDatas[0].joinStatus = false; + DemoThreadData tmp = DemoThreadData(); + std::thread joinThread = std::thread(&DemoThreadData::Join, tmp); + AssertFalse((demoDatas[0].joinStatus), "step 1: demoDatas[0].joinStatus did not equal false.", state); + StartThreads(threads, GetAndOneTaskDoneHandleThreadDataTime, demoDatas, timeT); + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_HUNDRED_MILLISECOND)); + unsigned int getedOut = 0; + unsigned int ungetedOut = 0; + GetThreadDateGetedStatus(demoDatas, getedOut, ungetedOut); + AssertEqual(getedOut, QUEUE_SLOTS - REMAIN_SLOTS, "getedOut did not equal QUEUE_SLOTS - REMAIN_SLOTS.", state); + AssertEqual(ungetedOut, THREAD_NUM - (QUEUE_SLOTS - REMAIN_SLOTS), + "ungetedOut did not equal THREAD_NUM - (QUEUE_SLOTS - REMAIN_SLOTS) as expected.", state); + AssertTrue((demoDatas[0].joinStatus), "step 2: demoDatas[0].joinStatus did not equal true.", state); + for (unsigned int i = 0; i < ungetedOut; i++) { + int t = i; + DemoThreadData::shareQueue.Push(t); + } + demoDatas[0].joinStatus = false; + DemoThreadData tmp2 = DemoThreadData(); + std::thread joinThread2 = std::thread(&DemoThreadData::Join, tmp2); + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_HUNDRED_MILLISECOND)); + GetThreadDateGetedStatus(demoDatas, getedOut, ungetedOut); + AssertEqual(getedOut, THREAD_NUM, "getedOut did not equal THREAD_NUM as expected.", state); + AssertEqual(ungetedOut, static_cast(0), + "ungetedOut did not equal static_cast(0) as expected.", state); + joinAllThreads(threads); + AssertTrue((demoDatas[0].joinStatus), "step 3: demoDatas[0].joinStatus did not equal true.", state); + demoDatas[0].joinStatus = false; + joinThread.join(); + joinThread2.join(); + } + BENCHMARK_LOGD("SafeBlockQueueTracking GetAndBlockInnotfullqueue001 end."); +} + +/* + * @tc.name: PutAndBlockInnotfullqueue001 + * @tc.desc: Multi-threaded put() on the not full queue. When n threads are waiting to reach a certain + * time-point, everyone puts concurrent to see the status of the queue and the state of the thread. + */ +BENCHMARK_F(BenchmarkSafeBlockQueueTracking, PutAndBlockInnotfullqueue001)(benchmark::State& state) +{ + BENCHMARK_LOGD("SafeBlockQueueTracking PutAndBlockInnotfullqueue001 start."); + std::thread threads[THREAD_NUM]; + std::array demoDatas; + while (state.KeepRunning()) { + demoDatas.fill(DemoThreadData()); + using std::chrono::system_clock; + const unsigned int REMAIN_SLOTS = 3; + auto timeT = std::chrono::high_resolution_clock::now(); + timeT += std::chrono::milliseconds(SLEEP_FOR_HUNDRED_MILLISECOND); + AssertTrue((DemoThreadData::shareQueue.IsEmpty()), + "DemoThreadData::shareQueue.IsEmpty() did not equal true as expected.", state); + for (unsigned int i = 0; i < QUEUE_SLOTS - REMAIN_SLOTS; i++) { + int t = i; + DemoThreadData::shareQueue.Push(t); + } + demoDatas[0].joinStatus = false; + DemoThreadData tmp = DemoThreadData(); + std::thread joinThread = std::thread(&DemoThreadData::Join, tmp); + AssertFalse((demoDatas[0].joinStatus), "step 1: demoDatas[0].joinStatus did not equal false.", state); + StartThreads(threads, PutHandleThreadDataTime, demoDatas, timeT); + AssertFalse((demoDatas[0].joinStatus), "step 2: demoDatas[0].joinStatus did not equal false.", state); + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_HUNDRED_MILLISECOND)); + AssertFalse((demoDatas[0].joinStatus), "step 3: demoDatas[0].joinStatus did not equal false.", state); + unsigned int putedin = 0; + unsigned int unputedin = 0; + GetThreadDatePushedStatus(demoDatas, putedin, unputedin); + AssertEqual(putedin, REMAIN_SLOTS, "putedin did not equal REMAIN_SLOTS as expected.", state); + AssertEqual(unputedin, THREAD_NUM - REMAIN_SLOTS, + "unputedin did not equal THREAD_NUM - REMAIN_SLOTS as expected.", state); + for (unsigned int i = 0; i < unputedin; i++) { + DemoThreadData::shareQueue.Pop(); + DemoThreadData::shareQueue.OneTaskDone(); + } + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_HUNDRED_MILLISECOND)); + GetThreadDatePushedStatus(demoDatas, putedin, unputedin); + AssertEqual(putedin, THREAD_NUM, "putedin did not equal THREAD_NUM as expected.", state); + AssertEqual(unputedin, static_cast(0), + "unputedin did not equal static_cast(0) as expected.", state); + AssertFalse((demoDatas[0].joinStatus), "step 4: demoDatas[0].joinStatus did not equal false.", state); + joinAllThreads(threads); + processSharedQueueTasks(demoDatas[0]); + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_HUNDRED_MILLISECOND)); + AssertTrue((demoDatas[0].joinStatus), "step 5: demoDatas[0].joinStatus did not equal true.", state); + joinThread.join(); + demoDatas[0].joinStatus = false; + } + BENCHMARK_LOGD("SafeBlockQueueTracking PutAndBlockInnotfullqueue001 end."); +} + +/* + * @tc.name: testMutilthreadConcurrentGetAndPopInfullqueue001 + * @tc.desc: Multi-threaded put() and Multi-threaded get() on the full queue. When all threads are waiting to reach a + * certain time-point, everyone run concurrently to see the status of the queue and the state of the thread. + */ +BENCHMARK_F(BenchmarkSafeBlockQueueTracking, testMutilthreadConcurrentGetAndPopInfullqueue001)(benchmark::State& state) +{ + BENCHMARK_LOGD("SafeBlockQueueTracking testMutilthreadConcurrentGetAndPopInfullqueue001 start."); + std::thread threadsout[THREAD_NUM]; + std::array demoDatas; + while (state.KeepRunning()) { + demoDatas.fill(DemoThreadData()); + std::thread threadsin[THREAD_NUM]; + using std::chrono::system_clock; + auto timeT = std::chrono::high_resolution_clock::now(); + timeT += std::chrono::milliseconds(SLEEP_FOR_HUNDRED_MILLISECOND); + AssertTrue((DemoThreadData::shareQueue.IsEmpty()), "shareQueue.IsEmpty() did not equal true.", state); + int t = 1; + for (unsigned int i = 0; i < QUEUE_SLOTS; i++) { + DemoThreadData::shareQueue.Push(t); + } + AssertTrue((DemoThreadData::shareQueue.IsFull()), "shareQueue.IsFull() did not equal true.", state); + demoDatas[0].joinStatus = false; + DemoThreadData tmp = DemoThreadData(); + std::thread joinThread = std::thread(&DemoThreadData::Join, tmp); + AssertFalse((demoDatas[0].joinStatus), "step 1: demoDatas[0].joinStatus did not equal false.", state); + StartThreads(threadsin, PutHandleThreadDataTime, demoDatas, timeT); + StartThreads(threadsout, GetAndOneTaskDoneHandleThreadDataTime, demoDatas, timeT); + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_FOR_HUNDRED_MILLISECOND)); + AssertTrue((DemoThreadData::shareQueue.IsFull()), "shareQueue.IsFull() did not equal true.", state); + unsigned int getedOut = 0; + unsigned int ungetedOut = 0; + unsigned int pushedIn = 0; + unsigned int unpushedIn = 0; + GetThreadDateGetedStatus(demoDatas, getedOut, ungetedOut); + GetThreadDatePushedStatus(demoDatas, pushedIn, unpushedIn); + AssertEqual(pushedIn, THREAD_NUM, "pushedIn did not equal THREAD_NUM as expected.", state); + AssertEqual(getedOut, THREAD_NUM, "getedOut did not equal THREAD_NUM as expected.", state); + AssertFalse((demoDatas[0].joinStatus), "step 2: demoDatas[0].joinStatus did not equal false.", state); + demoDatas[0].joinStatus = false; + for (auto& t : threadsout) { + t.join(); + } + for (auto& t : threadsin) { + t.join(); + } + processSharedQueueTasks(demoDatas[0]); + joinThread.join(); + AssertTrue((demoDatas[0].joinStatus), "step 3: demoDatas[0].joinStatus did not equal true.", state); + demoDatas[0].joinStatus = false; + } + BENCHMARK_LOGD("SafeBlockQueueTracking testMutilthreadConcurrentGetAndPopInfullqueue001 end."); +} + +/* + * @tc.name: testPushNoWait001 + * @tc.desc: Single-threaded call PushNoWait of SafeBlockQueueTracking and check the performance + */ +BENCHMARK_F(BenchmarkSafeBlockQueueTracking, testPushNoWait001)(benchmark::State& state) +{ + BENCHMARK_LOGD("SafeBlockQueueTracking testPushNoWait001 start."); + const int pushAttempts = 10; + while (state.KeepRunning()) { + SafeBlockQueueTracking qi(QUEUE_CAPACITY); + for (int i = 0; i < pushAttempts; i++) { + bool result = qi.PushNoWait(i); + AssertTrue(result, "PushNoWait returned false, expected true.", state); + } + } + BENCHMARK_LOGD("SafeBlockQueueTracking testPushNoWait001 end."); +} +} // namespace +} // namespace OHOS +// Run the benchmark +BENCHMARK_MAIN(); \ No newline at end of file diff --git a/base/test/benchmarktest/unique_fd_benchmark_test/BUILD.gn b/base/test/benchmarktest/unique_fd_benchmark_test/BUILD.gn new file mode 100644 index 0000000..72499d1 --- /dev/null +++ b/base/test/benchmarktest/unique_fd_benchmark_test/BUILD.gn @@ -0,0 +1,35 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/test.gni") + +module_output_path = "commonlibrary_c_utils/unique_fd" + +ohos_benchmarktest("UniqueFdTest") { + module_out_path = module_output_path + + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + sources = [ "unique_fd_benchmark_test.cpp" ] + + deps = [ "//third_party/benchmark:benchmark" ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog_base", + ] +} diff --git a/base/test/benchmarktest/unique_fd_benchmark_test/unique_fd_benchmark_test.cpp b/base/test/benchmarktest/unique_fd_benchmark_test/unique_fd_benchmark_test.cpp new file mode 100644 index 0000000..b3f66b8 --- /dev/null +++ b/base/test/benchmarktest/unique_fd_benchmark_test/unique_fd_benchmark_test.cpp @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "unique_fd.h" +#include +#include +#include +#include +#include +#include "../log.h" +#include "../assert.h" +using namespace std; + +namespace OHOS { +namespace { + +static char const* testfilename = "testfilename.test"; + +class BenchmarkUniqueFd : public benchmark::Fixture { +public: + BenchmarkUniqueFd() + { + Iterations(iterations); + Repetitions(repetitions); + ReportAggregatesOnly(); + } + + ~BenchmarkUniqueFd() override = default; + void SetUp(const ::benchmark::State& state) override + { + ofstream outfile; + outfile.open(testfilename, ios::out | ios::trunc); + outfile << "testdata\n" + << std::endl; + outfile.close(); + } + + void TearDown(::benchmark::State& state) override + { + ifstream inputfile; + inputfile.open(testfilename, ios::in); + std::string testStr; + inputfile >> testStr; + inputfile.close(); + AssertEqual(remove(testfilename), 0, "remove(testfilename) did not equal 0 as expected.", state); + } + +protected: + const int32_t repetitions = 3; + const int32_t iterations = 1000; +}; + +const int FILE_PERMISSION_READ_WRITE = 0666; +const int MIN_VALID_FD = 0; +const int MAX_VALID_FD = 1000000; + +BENCHMARK_F(BenchmarkUniqueFd, testUtilsUniqueFd)(benchmark::State& state) +{ + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFd start."); + const int expectedValue = -1; + while (state.KeepRunning()) { + int fd = open("NOTHISFILE", O_RDWR, FILE_PERMISSION_READ_WRITE); + + UniqueFd ufd2(fd); + AssertEqual(ufd2, expectedValue, "ufd2 did not equal expectedValue as expected.", state); + } + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFd end."); +} + +BENCHMARK_F(BenchmarkUniqueFd, testUtilsUniqueCtroFromInt)(benchmark::State& state) +{ + BENCHMARK_LOGD("UniqueFd testUtilsUniqueCtroFromInt start."); + const int expectedValue = -1; + while (state.KeepRunning()) { + UniqueFd ufd2(open(testfilename, O_RDWR, FILE_PERMISSION_READ_WRITE)); + AssertUnequal(ufd2, expectedValue, "ufd2 was not different from expectedValue as expected.", state); + } + BENCHMARK_LOGD("UniqueFd testUtilsUniqueCtroFromInt end."); +} + +BENCHMARK_F(BenchmarkUniqueFd, testUtilsUniqueFdeqcompare)(benchmark::State& state) +{ + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdeqcompare start."); + while (state.KeepRunning()) { + int fd = open(testfilename, O_RDWR, FILE_PERMISSION_READ_WRITE); + UniqueFd ufd2(fd); + AssertEqual(fd, ufd2, "fd did not equal ufd2 as expected.", state); + AssertEqual(ufd2, fd, "ufd2 did not equal fd as expected.", state); + } + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdeqcompare end."); +} + +BENCHMARK_F(BenchmarkUniqueFd, testUtilsUniqueFdeqcompareNl)(benchmark::State& state) +{ + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdeqcompareNl start."); + while (state.KeepRunning()) { + int fd = open(testfilename, O_RDWR, FILE_PERMISSION_READ_WRITE); + UniqueFd ufd2(fd); + AssertGreaterThanOrEqual(ufd2, 0, "ufd2 >= 0 did not equal true as expected.", state); + AssertLessThanOrEqual(0, ufd2, "0 <= ufd2 did not equal true as expected.", state); + } + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdeqcompareNl end."); +} + +BENCHMARK_F(BenchmarkUniqueFd, testUtilsUniqueFdeqcompareBg)(benchmark::State& state) +{ + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdeqcompareBg start."); + while (state.KeepRunning()) { + int fd = open(testfilename, O_RDWR, FILE_PERMISSION_READ_WRITE); + UniqueFd ufd2(fd); + AssertGreaterThan(ufd2, MIN_VALID_FD, "ufd2 > MIN_VALID_FD did not equal true as expected.", state); + AssertLessThan(MIN_VALID_FD, ufd2, "MIN_VALID_FD < ufd2 did not equal true as expected.", state); + } + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdeqcompareBg end."); +} + +BENCHMARK_F(BenchmarkUniqueFd, testUtilsUniqueFdeqcompareNb)(benchmark::State& state) +{ + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdeqcompareNb start."); + while (state.KeepRunning()) { + int fd = open(testfilename, O_RDWR, FILE_PERMISSION_READ_WRITE); + UniqueFd ufd2(fd); + AssertLessThanOrEqual(ufd2, MAX_VALID_FD, "ufd2 <= MAX_VALID_FD did not equal true as expected.", state); + AssertGreaterThanOrEqual(MAX_VALID_FD, ufd2, "MAX_VALID_FD >= ufd2 did not equal true as expected.", state); + } + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdeqcompareNb end."); +} + +BENCHMARK_F(BenchmarkUniqueFd, testUtilsUniqueFdeqcompareLess)(benchmark::State& state) +{ + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdeqcompareLess start."); + while (state.KeepRunning()) { + int fd = open(testfilename, O_RDWR, FILE_PERMISSION_READ_WRITE); + UniqueFd ufd2(fd); + AssertLessThan(ufd2, MAX_VALID_FD, "ufd2 < MAX_VALID_FD did not equal true as expected.", state); + AssertGreaterThan(MAX_VALID_FD, ufd2, "MAX_VALID_FD > ufd2 did not equal true as expected.", state); + } + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdeqcompareLess end."); +} + +BENCHMARK_F(BenchmarkUniqueFd, testUtilsUniqueFdeqcompareNeq)(benchmark::State& state) +{ + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdeqcompareNeq start."); + while (state.KeepRunning()) { + int fd = open(testfilename, O_RDWR, FILE_PERMISSION_READ_WRITE); + UniqueFd ufd2(fd); + AssertUnequal(ufd2, MAX_VALID_FD, "ufd2 != MAX_VALID_FD did not equal true as expected.", state); + AssertUnequal(MAX_VALID_FD, ufd2, "MAX_VALID_FD != ufd2 did not equal true as expected.", state); + } + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdeqcompareNeq end."); +} + +class NewDeleter { +public: + static int iflag; + static void Close(int fd) + { + BENCHMARK_LOGD("UniqueFd static void Close is called."); + + iflag = 10; + close(fd); + } +}; + +int NewDeleter::iflag = 0; + +BENCHMARK_F(BenchmarkUniqueFd, testUtilsUniqueFdDefineDeletor)(benchmark::State& state) +{ + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdDefineDeletor start."); + const int initialFlagValue = 0; + const int expectedFlagValueAfterDelete = 10; + const int invalidFileDescriptor = -1; + while (state.KeepRunning()) { + NewDeleter::iflag = 0; + int fd = open(testfilename, O_RDWR); + + { + UniqueFdAddDeletor ufd2(fd); + AssertEqual(NewDeleter::iflag, initialFlagValue, + "NewDeleter::iflag did not equal 0 as expected.", state); + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdDefineDeletor NewDeleter::iflag: %{public}d", NewDeleter::iflag); + AssertUnequal(ufd2, invalidFileDescriptor, "open test.h error", state); + } + AssertEqual(NewDeleter::iflag, expectedFlagValueAfterDelete, + "NewDeleter::iflag did not equal expectedFlagValueAfterDelete as expected.", state); + } + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdDefineDeletor end."); +} + +BENCHMARK_F(BenchmarkUniqueFd, testUtilsUniqueFdDefineDeletorCloseStatus)(benchmark::State& state) +{ + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdDefineDeletorCloseStatus start."); + const int errorReturn = -1; + while (state.KeepRunning()) { + int fd = open(testfilename, O_RDWR); + + { + UniqueFdAddDeletor ufd2(fd); + } + + char buf[] = "test"; + int ret = write(fd, buf, sizeof(buf)); + AssertEqual(ret, errorReturn, "ret did not equal errorReturn as expected.", state); + } + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdDefineDeletorCloseStatus end."); +} + +BENCHMARK_F(BenchmarkUniqueFd, testUtilsUniqueFdRelease)(benchmark::State& state) +{ + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdRelease start."); + const int expectedValue = -1; + while (state.KeepRunning()) { + UniqueFd ufd(open(testfilename, O_RDWR, FILE_PERMISSION_READ_WRITE)); + AssertUnequal(ufd, expectedValue, "ufd was not different from expectedValue as expected.", state); + + int fd = ufd.Release(); + AssertUnequal(fd, expectedValue, "fd was not different from expectedValue as expected.", state); + DefaultDeleter::Close(fd); + } + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdRelease end."); +} + +BENCHMARK_F(BenchmarkUniqueFd, testUtilsUniqueFdOperatorInt)(benchmark::State& state) +{ + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdOperatorInt start."); + const int expectedValue = -1; + while (state.KeepRunning()) { + UniqueFd ufd(open(testfilename, O_RDWR, FILE_PERMISSION_READ_WRITE)); + AssertUnequal(ufd, expectedValue, "ufd was not different from expectedValue as expected.", state); + + int fd = ufd; + AssertEqual(fd, ufd, "fd did not equal ufd as expected.", state); + } + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdOperatorInt end."); +} + +BENCHMARK_F(BenchmarkUniqueFd, testUtilsUniqueFdGet)(benchmark::State& state) +{ + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdGet start."); + const int expectedValue = -1; + while (state.KeepRunning()) { + UniqueFd ufd(open(testfilename, O_RDWR, FILE_PERMISSION_READ_WRITE)); + AssertUnequal(ufd, expectedValue, "ufd was not different from expectedValue as expected.", state); + + int fd = ufd.Get(); + AssertEqual(fd, ufd, "fd did not equal ufd as expected.", state); + } + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdGet end."); +} + +BENCHMARK_F(BenchmarkUniqueFd, testUtilsUniqueFdMoveConstructor)(benchmark::State& state) +{ + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdMoveConstructor start."); + const int expectedValue = -1; + while (state.KeepRunning()) { + UniqueFd ufd(open(testfilename, O_RDWR, FILE_PERMISSION_READ_WRITE)); + AssertUnequal(ufd, expectedValue, "ufd was not different from expectedValue as expected.", state); + + UniqueFd ufd1(std::move(ufd)); + AssertEqual(ufd, expectedValue, "ufd did not equal expectedValue as expected.", state); + AssertUnequal(ufd1, expectedValue, "ufd1 was not different from expectedValue as expected.", state); + } + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdMoveConstructor end."); +} + +BENCHMARK_F(BenchmarkUniqueFd, testUtilsUniqueFdMoveAssignment)(benchmark::State& state) +{ + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdMoveAssignment start."); + const int expectedValue = -1; + while (state.KeepRunning()) { + UniqueFd ufd(open(testfilename, O_RDWR, FILE_PERMISSION_READ_WRITE)); + AssertUnequal(ufd, expectedValue, "ufd was not different from expectedValue as expected.", state); + + UniqueFd ufd1; + ufd1 = std::move(ufd); + AssertEqual(ufd, expectedValue, "ufd did not equal expectedValue as expected.", state); + AssertUnequal(ufd1, expectedValue, "ufd1 was not different from expectedValue as expected.", state); + } + BENCHMARK_LOGD("UniqueFd testUtilsUniqueFdMoveAssignment end."); +} +} // namespace +} // namespace OHOS +// Run the benchmark +BENCHMARK_MAIN(); \ No newline at end of file diff --git a/bundle.json b/bundle.json index 4366b17..9f72ca3 100644 --- a/bundle.json +++ b/bundle.json @@ -110,7 +110,8 @@ } ], "test": [ - "//commonlibrary/c_utils/base/test:unittest" + "//commonlibrary/c_utils/base/test:unittest", + "//commonlibrary/c_utils/base/test/benchmarktest:benchmarktest" ] } } -- Gitee