diff --git a/base/test/benchmarktest/BUILD.gn b/base/test/benchmarktest/BUILD.gn index f42ae72331605e7edbbb35f469387356d4545069..bc4afa2ea53083ebbb117de4870fb15bc1a74cc0 100644 --- a/base/test/benchmarktest/BUILD.gn +++ b/base/test/benchmarktest/BUILD.gn @@ -18,6 +18,7 @@ group("benchmarktest") { # deps file "ashemem_benchmark_test:AshememTest", "datatime_benchmark_test:DatatimeTest", + "directory_benchmark_test:DirectoryTest", "mapped_benchmark_test:MappedTest", "observer_benchmark_test:ObserverTest", "parcel_benchmark_test:ParcelTest", @@ -27,6 +28,8 @@ group("benchmarktest") { "singleton_benchmark_test:SingletonTest", "sorted_vector_benchmark_test:SortedVectorTest", "string_benchmark_test:StringTest", + "thread_benchmark_test:ThreadTest", + "thread_pool_benchmark_test:ThreadPoolTest", "timer_benchmark_test:TimerTest", ] } diff --git a/base/test/benchmarktest/directory_benchmark_test/BUILD.gn b/base/test/benchmarktest/directory_benchmark_test/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..d036d25d971753a0354984b4cb14260b2ebb0655 --- /dev/null +++ b/base/test/benchmarktest/directory_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/directory" + +ohos_benchmarktest("DirectoryTest") { + module_out_path = module_output_path + + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + sources = [ "directory_benchmark_test.cpp" ] + + deps = [ "//third_party/benchmark:benchmark" ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog_base", + ] +} diff --git a/base/test/benchmarktest/directory_benchmark_test/directory_benchmark_test.cpp b/base/test/benchmarktest/directory_benchmark_test/directory_benchmark_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..519a9d5f8051d0203cd312b9e0f82e8f221e0ee0 --- /dev/null +++ b/base/test/benchmarktest/directory_benchmark_test/directory_benchmark_test.cpp @@ -0,0 +1,557 @@ +/* + * 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 "directory_ex.h" +#include +#include +#include +#include +#include +#include "../log.h" +#include "../assert.h" +using namespace std; + +namespace OHOS { +namespace { + +class BenchmarkDirectoryTest : public benchmark::Fixture { +public: + BenchmarkDirectoryTest() + { + Iterations(iterations); + Repetitions(repetitions); + ReportAggregatesOnly(); + } + + ~BenchmarkDirectoryTest() 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 = 1000; +}; + +/* + * @tc.name: testGetCurrentProcFullFileName001 + * @tc.desc: get the directory of directorytest + */ +BENCHMARK_F(BenchmarkDirectoryTest, testGetCurrentProcFullFileName001)(benchmark::State& state) +{ + BENCHMARK_LOGD("DirectoryTest testGetCurrentProcFullFileName001 start."); + while (state.KeepRunning()) { + string strBaseName = "/data/test/DirectoryTest"; + string strFilename = GetCurrentProcFullFileName(); + AssertEqual(strFilename, strBaseName, "strFilename did not equal strBaseName as expected.", state); + } + BENCHMARK_LOGD("DirectoryTest testGetCurrentProcFullFileName001 end."); +} + +/* + * @tc.name: testGetCurrentProcPath001 + * @tc.desc: get the path of directorytest + */ +BENCHMARK_F(BenchmarkDirectoryTest, testGetCurrentProcPath001)(benchmark::State& state) +{ + BENCHMARK_LOGD("DirectoryTest testGetCurrentProcPath001 start."); + while (state.KeepRunning()) { + string strPathName = "/data/test/"; + string strCurPathName = GetCurrentProcPath(); + AssertEqual(strCurPathName, strPathName, "strCurPathName did not equal strPathName as expected.", state); + } + BENCHMARK_LOGD("DirectoryTest testGetCurrentProcPath001 end."); +} + +/* + * @tc.name: testExtractFilePath001 + * @tc.desc: get the filename of the path + */ +BENCHMARK_F(BenchmarkDirectoryTest, testExtractFilePath001)(benchmark::State& state) +{ + BENCHMARK_LOGD("DirectoryTest testExtractFilePath001 start."); + while (state.KeepRunning()) { + string strFilePath = "/data/test/"; + string strPath = ExtractFilePath(GetCurrentProcFullFileName()); + AssertEqual(strFilePath, strPath, "strFilePath did not equal strPath as expected.", state); + } + BENCHMARK_LOGD("DirectoryTest testExtractFilePath001 end."); +} + +/* + * @tc.name: testExtractFileName001 + * @tc.desc: get the filename of the path + */ +BENCHMARK_F(BenchmarkDirectoryTest, testExtractFileName001)(benchmark::State& state) +{ + BENCHMARK_LOGD("DirectoryTest testExtractFileName001 start."); + while (state.KeepRunning()) { + string strBaseName = "DirectoryTest"; + string strName = ExtractFileName(GetCurrentProcFullFileName()); + AssertEqual(strBaseName, strName, "strBaseName did not equal strName as expected.", state); + } + BENCHMARK_LOGD("DirectoryTest testExtractFileName001 end."); +} + +/* + * @tc.name: testExtractFileExt001 + * @tc.desc: get the filename of the path + */ +BENCHMARK_F(BenchmarkDirectoryTest, testExtractFileExt001)(benchmark::State& state) +{ + BENCHMARK_LOGD("DirectoryTest testExtractFileExt001 start."); + while (state.KeepRunning()) { + string strBaseName = "test/test.txt"; + string strTypeName = ExtractFileExt(strBaseName); + AssertEqual(strTypeName, "txt", "strTypeName did not equal \"txt\" as expected.", state); + } + BENCHMARK_LOGD("DirectoryTest testExtractFileExt001 end."); +} + +/* + * @tc.name: testExtractFileExt002 + * @tc.desc: get the filename of the path and test whether the filename contains "." + */ +BENCHMARK_F(BenchmarkDirectoryTest, testExtractFileExt002)(benchmark::State& state) +{ + BENCHMARK_LOGD("DirectoryTest testExtractFileExt002 start."); + while (state.KeepRunning()) { + string strBaseName = "test/test_txt"; + string strTypeName = ExtractFileExt(strBaseName); + AssertEqual(strTypeName, "", "strTypeName did not equal \"\" as expected.", state); + } + BENCHMARK_LOGD("DirectoryTest testExtractFileExt002 end."); +} + +/* + * @tc.name: testExcludeTrailingPathDelimiter001 + * @tc.desc: directory unit test + */ +BENCHMARK_F(BenchmarkDirectoryTest, testExcludeTrailingPathDelimiter001)(benchmark::State& state) +{ + BENCHMARK_LOGD("DirectoryTest testExcludeTrailingPathDelimiter001 start."); + while (state.KeepRunning()) { + string strResult = "data/test/DirectoryTest"; + string strName = ExcludeTrailingPathDelimiter("data/test/DirectoryTest/"); + AssertEqual(strResult, strName, "strResult did not equal strName as expected.", state); + } + BENCHMARK_LOGD("DirectoryTest testExcludeTrailingPathDelimiter001 end."); +} + +/* + * @tc.name: testIncludeTrailingPathDelimiter001 + * @tc.desc: directory unit test + */ +BENCHMARK_F(BenchmarkDirectoryTest, testIncludeTrailingPathDelimiter001)(benchmark::State& state) +{ + BENCHMARK_LOGD("DirectoryTest testIncludeTrailingPathDelimiter001 start."); + while (state.KeepRunning()) { + string strResult = "data/test/DirectoryTest/"; + string strName = IncludeTrailingPathDelimiter("data/test/DirectoryTest"); + AssertEqual(strResult, strName, "strResult did not equal strName as expected.", state); + } + BENCHMARK_LOGD("DirectoryTest testIncludeTrailingPathDelimiter001 end."); +} + +/* + * @tc.name: testGetDirFiles001 + * @tc.desc: directory unit test + */ +BENCHMARK_F(BenchmarkDirectoryTest, testGetDirFiles001)(benchmark::State& state) +{ + BENCHMARK_LOGD("DirectoryTest testGetDirFiles001 start."); + while (state.KeepRunning()) { + string resultfile[2] = { "/data/test/TestFile.txt", "/data/test/DirectoryTest" }; + // prepare test data + ofstream file(resultfile[0], fstream::out); + + string dirpath = "/data/"; + vector filenames; + GetDirFiles(dirpath, filenames); + auto pos = find(filenames.begin(), filenames.end(), resultfile[0]); + AssertUnequal(pos, filenames.end(), "pos was not different from filenames.end() as expected.", state); + + pos = find(filenames.begin(), filenames.end(), resultfile[1]); + AssertUnequal(pos, filenames.end(), "pos was not different from filenames.end() as expected.", state); + + // delete test data + RemoveFile(resultfile[0]); + } + BENCHMARK_LOGD("DirectoryTest testGetDirFiles001 end."); +} + +/* + * @tc.name: testForceCreateDirectory001 + * @tc.desc: directory unit test + */ +BENCHMARK_F(BenchmarkDirectoryTest, testForceCreateDirectory001)(benchmark::State& state) +{ + BENCHMARK_LOGD("DirectoryTest testForceCreateDirectory001 start."); + while (state.KeepRunning()) { + string dirpath = "/data/test_dir/test2/test3"; + bool ret = ForceCreateDirectory(dirpath); + AssertEqual(ret, true, "ret did not equal true as expected.", state); + ret = IsEmptyFolder(dirpath); + AssertEqual(ret, true, "ret did not equal true as expected.", state); + } + BENCHMARK_LOGD("DirectoryTest testForceCreateDirectory001 end."); +} + +/* + * @tc.name: testForceRemoveDirectory001 + * @tc.desc: directory unit test + */ +BENCHMARK_F(BenchmarkDirectoryTest, testForceRemoveDirectory001)(benchmark::State& state) +{ + BENCHMARK_LOGD("DirectoryTest testForceRemoveDirectory001 start."); + while (state.KeepRunning()) { + string dirpath = "/data/test_dir"; + bool ret = ForceCreateDirectory(dirpath); + AssertEqual(ret, true, "ret did not equal true as expected.", state); + ret = ForceRemoveDirectory(dirpath); + BENCHMARK_LOGD("DirectoryTest testForceRemoveDirectory001 ret:%{public}d.", ret); + AssertEqual(ret, true, "ret did not equal true as expected.", state); + } + BENCHMARK_LOGD("DirectoryTest testForceRemoveDirectory001 end."); +} + +/* + * @tc.name: testForceRemoveDirectory002 + * @tc.desc: test whether the folder exists + */ +BENCHMARK_F(BenchmarkDirectoryTest, testForceRemoveDirectory002)(benchmark::State& state) +{ + BENCHMARK_LOGD("DirectoryTest testForceRemoveDirectory002 start."); + while (state.KeepRunning()) { + string dirpath = "/data/test/utils_directory_tmp/"; + bool ret = ForceRemoveDirectory(dirpath); + AssertEqual(ret, false, "ret did not equal false as expected.", state); + } + BENCHMARK_LOGD("DirectoryTest testForceRemoveDirectory002 end."); +} + +/* + * @tc.name: testRemoveFile001 + * @tc.desc: directory unit test + */ +BENCHMARK_F(BenchmarkDirectoryTest, testRemoveFile001)(benchmark::State& state) +{ + BENCHMARK_LOGD("DirectoryTest testRemoveFile001 start."); + while (state.KeepRunning()) { + string dirpath = "/data/test_dir"; + bool ret = ForceCreateDirectory(dirpath); + AssertEqual(ret, true, "ret did not equal true as expected.", state); + string filename = dirpath + "/test.txt"; + FILE *fp = fopen(filename.c_str(), "w"); + if (fp != nullptr) { + fclose(fp); + ret = RemoveFile(filename); + AssertEqual(ret, true, "ret did not equal true as expected.", state); + } + ret = ForceRemoveDirectory(dirpath); + AssertEqual(ret, true, "ret did not equal true as expected.", state); + } + BENCHMARK_LOGD("DirectoryTest testRemoveFile001 end."); +} + +/* + * @tc.name: testRemoveFile002 + * @tc.desc: Remove soft link file. + */ +BENCHMARK_F(BenchmarkDirectoryTest, testRemoveFile002)(benchmark::State& state) +{ + BENCHMARK_LOGD("DirectoryTest testRemoveFile002 start."); + while (state.KeepRunning()) { + string dirpath = "/data/test_dir"; + bool ret = ForceCreateDirectory(dirpath); + AssertEqual(ret, true, "ret did not equal true as expected.", state); + + string targetname = "/data/test_target.txt"; + FILE *fp = fopen(targetname.c_str(), "w"); + if (fp != nullptr) { + fclose(fp); + } + + // symlink to a directory + string linkpath = "/data/test_symlink_dir"; + int res = symlink(dirpath.c_str(), linkpath.c_str()); + AssertEqual(res, 0, "res did not equal 0 as expected.", state); + + ret = ForceRemoveDirectory(linkpath); + AssertEqual(ret, true, "ret did not equal true as expected.", state); + + // Target dir is not removed. + ret = faccessat(AT_FDCWD, dirpath.c_str(), F_OK, AT_SYMLINK_NOFOLLOW); + AssertEqual(ret, 0, "ret did not equal 0 as expected.", state); + + // symlink to a file + string filename = dirpath + "/test.txt"; + res = symlink(targetname.c_str(), filename.c_str()); + AssertEqual(res, 0, "res did not equal 0 as expected.", state); + + ret = ForceRemoveDirectory(dirpath); + AssertEqual(ret, true, "ret did not equal true as expected.", state); + + // Target file is not removed. + ret = faccessat(AT_FDCWD, targetname.c_str(), F_OK, AT_SYMLINK_NOFOLLOW); + AssertEqual(ret, 0, "ret did not equal 0 as expected.", state); + + ret = RemoveFile(targetname); + AssertEqual(ret, true, "ret did not equal true as expected.", state); + } + BENCHMARK_LOGD("DirectoryTest testRemoveFile002 end."); +} + +/* + * @tc.name: testRemoveFile003 + * @tc.desc: Remove dangling soft link file. + */ +BENCHMARK_F(BenchmarkDirectoryTest, testRemoveFile003)(benchmark::State& state) +{ + BENCHMARK_LOGD("DirectoryTest testRemoveFile003 start."); + while (state.KeepRunning()) { + string dirpath = "/data/test_dir"; + bool ret = ForceCreateDirectory(dirpath); + AssertEqual(ret, true, "ret did not equal true as expected.", state); + + // symlink to a file + string targetname = "/data/nonexisted.txt"; + string filename = dirpath + "/test.txt"; + int res = symlink(targetname.c_str(), filename.c_str()); + AssertEqual(res, 0, "res did not equal 0 as expected.", state); + + ret = ForceRemoveDirectory(dirpath); + AssertEqual(ret, true, "ret did not equal true as expected.", state); + + ret = RemoveFile(targetname); + AssertEqual(ret, true, "ret did not equal true as expected.", state); + } + BENCHMARK_LOGD("DirectoryTest testRemoveFile003 end."); +} + +/* + * @tc.name: testGetFolderSize001 + * @tc.desc: directory unit test + */ +BENCHMARK_F(BenchmarkDirectoryTest, testGetFolderSize001)(benchmark::State& state) +{ + BENCHMARK_LOGD("DirectoryTest testGetFolderSize001 start."); + while (state.KeepRunning()) { + string dirpath = "/data/test_folder/"; + bool ret = ForceCreateDirectory(dirpath); + AssertEqual(ret, true, "ret did not equal true as expected.", state); + ofstream out(dirpath + "test.txt"); + if (out.is_open()) { + out << "This is a line.\n"; + out << "This is another line.\n"; + out.close(); + } + uint64_t resultsize = GetFolderSize(dirpath); + uint64_t resultcomp = 38; + AssertEqual(resultsize, resultcomp, "resultsize did not equal resultcomp as expected.", state); + + mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO; + ret = ChangeModeFile(dirpath + "test.txt", mode); + AssertEqual(ret, true, "ret did not equal true as expected.", state); + + mode = S_IRUSR | S_IRGRP | S_IROTH; + ret = ChangeModeDirectory(dirpath, mode); + AssertEqual(ret, true, "ret did not equal true as expected.", state); + + ret = ForceRemoveDirectory(dirpath); + AssertEqual(ret, true, "ret did not equal true as expected.", state); + } + BENCHMARK_LOGD("DirectoryTest testGetFolderSize001 end."); +} + +/* + * @tc.name: testChangeModeFile001 + * @tc.desc: test whether the folder exists + */ +BENCHMARK_F(BenchmarkDirectoryTest, testChangeModeFile001)(benchmark::State& state) +{ + BENCHMARK_LOGD("DirectoryTest testChangeModeFile001 start."); + while (state.KeepRunning()) { + string dirpath = "/data/test/utils_directory_tmp/"; + mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO; + bool ret = ChangeModeFile(dirpath + "test.txt", mode); + AssertEqual(ret, false, "ret did not equal false as expected.", state); + } + BENCHMARK_LOGD("DirectoryTest testChangeModeFile001 end."); +} + +/* + * @tc.name: testChangeModeDirectory001 + * @tc.desc: test whether the folder is empty and get the size of the folder + */ +BENCHMARK_F(BenchmarkDirectoryTest, testChangeModeDirectory001)(benchmark::State& state) +{ + BENCHMARK_LOGD("DirectoryTest testChangeModeDirectory001 start."); + while (state.KeepRunning()) { + string dirpath = ""; + mode_t mode = S_IRUSR | S_IRGRP | S_IROTH; + bool ret = ChangeModeDirectory(dirpath, mode); + AssertEqual(ret, false, "ret did not equal false as expected.", state); + + uint64_t resultsize = GetFolderSize(dirpath); + uint64_t resultcomp = 0; + AssertEqual(resultsize, resultcomp, "resultsize did not equal resultcomp as expected.", state); + } + BENCHMARK_LOGD("DirectoryTest testChangeModeDirectory001 end."); +} + +/* + * @tc.name: testPathToRealPath001 + * @tc.desc: directory unit test + */ +BENCHMARK_F(BenchmarkDirectoryTest, testPathToRealPath001)(benchmark::State& state) +{ + BENCHMARK_LOGD("DirectoryTest testPathToRealPath001 start."); + while (state.KeepRunning()) { + string path = "/data/test"; + string realpath; + bool ret = PathToRealPath(path, realpath); + AssertEqual(ret, true, "ret did not equal true as expected.", state); + AssertEqual(path, realpath, "path did not equal realpath as expected.", state); + } + BENCHMARK_LOGD("DirectoryTest testPathToRealPath001 end."); +} + +/* + * @tc.name: testPathToRealPath002 + * @tc.desc: directory unit test + */ +BENCHMARK_F(BenchmarkDirectoryTest, testPathToRealPath002)(benchmark::State& state) +{ + BENCHMARK_LOGD("DirectoryTest testPathToRealPath002 start."); + while (state.KeepRunning()) { + string path = "/data/../data/test"; + string realpath; + bool ret = PathToRealPath(path, realpath); + AssertEqual(ret, true, "ret did not equal true as expected.", state); + AssertEqual("/data/test", realpath, "\"/data/test\" did not equal realpath as expected.", state); + } + BENCHMARK_LOGD("DirectoryTest testPathToRealPath002 end."); +} + +/* + * @tc.name: testPathToRealPath003 + * @tc.desc: directory unit test + */ +BENCHMARK_F(BenchmarkDirectoryTest, testPathToRealPath003)(benchmark::State& state) +{ + BENCHMARK_LOGD("DirectoryTest testPathToRealPath003 start."); + while (state.KeepRunning()) { + string path = "./"; + string realpath; + bool ret = PathToRealPath(path, realpath); + AssertEqual(ret, true, "ret did not equal true as expected.", state); + AssertEqual("/data/test", realpath, "\"/data/test\" did not equal realpath as expected.", state); + } + BENCHMARK_LOGD("DirectoryTest testPathToRealPath003 end."); +} + +/* + * @tc.name: testPathToRealPath004 + * @tc.desc: directory unit test + */ +BENCHMARK_F(BenchmarkDirectoryTest, testPathToRealPath004)(benchmark::State& state) +{ + BENCHMARK_LOGD("DirectoryTest testPathToRealPath004 start."); + while (state.KeepRunning()) { + string path = ""; + string realpath; + bool ret = PathToRealPath(path, realpath); + AssertEqual(ret, false, "ret did not equal false as expected.", state); + } + BENCHMARK_LOGD("DirectoryTest testPathToRealPath004 end."); +} + +/* + * @tc.name: testPathToRealPath005 + * @tc.desc: directory unit test + */ +BENCHMARK_F(BenchmarkDirectoryTest, testPathToRealPath005)(benchmark::State& state) +{ + BENCHMARK_LOGD("DirectoryTest testPathToRealPath005 start."); + while (state.KeepRunning()) { + string path = "/data/test/data/test/data/test/data/test/data/test/data/ \ + test/data/test/data/test/data/test/data/test/data/test/data/test/data/ \ + test/data/test/data/test/data/test/data/test/data/test/data/test/data/ \ + test/data/test/data/test/data/test/data/test/data/test/data/test/data/ \ + test/data/test/data/test/data/test"; + string realpath; + bool ret = PathToRealPath(path, realpath); + AssertEqual(ret, false, "ret did not equal false as expected.", state); + } + BENCHMARK_LOGD("DirectoryTest testPathToRealPath005 end."); +} + +/* + * @tc.name: testPathToRealPath006 + * @tc.desc: test whether the folder exists + */ +BENCHMARK_F(BenchmarkDirectoryTest, testPathToRealPath006)(benchmark::State& state) +{ + BENCHMARK_LOGD("DirectoryTest testPathToRealPath006 start."); + while (state.KeepRunning()) { + string path(PATH_MAX, 'x'); + string realpath; + bool ret = PathToRealPath(path, realpath); + AssertEqual(ret, false, "ret did not equal false as expected.", state); + } + BENCHMARK_LOGD("DirectoryTest testPathToRealPath006 end."); +} + +/* + * @tc.name: testTransformFileName001 + * @tc.desc: test transform the file name + */ +#if defined(IOS_PLATFORM) || defined(_WIN32) +BENCHMARK_F(BenchmarkDirectoryTest, testTransformFileName001)(benchmark::State& state) +{ + BENCHMARK_LOGD("DirectoryTest testTransformFileName001 start."); + while (state.KeepRunning()) { + string srcName = "test"; + string result = TransformFileName(srcName); + string cmpName = srcName; + #ifdef _WIN32 + cmpName = cmpName.append(".dll"); + #elif defined IOS_PLATFORM + cmpName = cmpName.append(".dylib"); + #endif + AssertEqual(result, cmpName, "result did not equal cmpName as expected.", state); + + srcName = srcName.append(".app"); + result = TransformFileName(srcName); + #ifdef _WIN32 + cmpName = cmpName.append(".dll"); + #elif defined IOS_PLATFORM + cmpName = cmpName.append(".dylib"); + #endif + AssertEqual(result, cmpName, "result did not equal cmpName as expected.", state); + } + BENCHMARK_LOGD("DirectoryTest testTransformFileName001 end."); +} +#endif +} // namespace +} // namespace OHOS +// Run the benchmark +BENCHMARK_MAIN(); \ No newline at end of file diff --git a/base/test/benchmarktest/thread_benchmark_test/BUILD.gn b/base/test/benchmarktest/thread_benchmark_test/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..93a1806a063bec32a9828d1074279202c97e43b9 --- /dev/null +++ b/base/test/benchmarktest/thread_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/thread" + +ohos_benchmarktest("ThreadTest") { + module_out_path = module_output_path + + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + sources = [ "thread_benchmark_test.cpp" ] + + deps = [ "//third_party/benchmark:benchmark" ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog_base", + ] +} diff --git a/base/test/benchmarktest/thread_benchmark_test/thread_benchmark_test.cpp b/base/test/benchmarktest/thread_benchmark_test/thread_benchmark_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c273fc74ea69579e6f22ca2ce15003a7340aaa35 --- /dev/null +++ b/base/test/benchmarktest/thread_benchmark_test/thread_benchmark_test.cpp @@ -0,0 +1,506 @@ +/* + * 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 "thread_ex.h" +#include +#include +#include +#include +#include +#include "../log.h" +#include "../assert.h" +using namespace std; + +namespace OHOS { +namespace { + +class BenchmarkThreadTest : public benchmark::Fixture { +public: + BenchmarkThreadTest() + { + Iterations(iterations); + Repetitions(repetitions); + ReportAggregatesOnly(); + } + + ~BenchmarkThreadTest() 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; +}; + +static int g_times = 0; +constexpr int DEFAULT_PRIO = 0; +const std::string& DEFAULT_THREAD_NAME = "default"; +const int INITIAL_TIMES = 0; +const int INITIAL_TEST_VALUE = 0; +const int THREAD_STACK_SIZE = 1024; +const int INVALID_THREAD_ID = -1; +const int SLEEP_FOR_ONE_SECOND = 1; + +using ThreadRunFunc = bool (*)(int& data); + +bool TestRun01(int& data) +{ + BENCHMARK_LOGD("ThreadTest bool TestRun01 is called."); + ++data; + return false; +} + +bool TestRun02(int& data) +{ + BENCHMARK_LOGD("ThreadTest bool TestRun02 is called."); + ++data; + return true; +} + +bool TestRun03(int& data) +{ + BENCHMARK_LOGD("ThreadTest bool TestRun03 is called."); + static const int TRY_TIMES = 10; + if (g_times <= TRY_TIMES) { + ++data; + return true; + } + + return false; +} + +class TestThread : public OHOS::Thread { +public: + TestThread(const int data, const bool readyToWork, ThreadRunFunc runFunc) + : data_(data), + priority_(DEFAULT_PRIO), + name_(DEFAULT_THREAD_NAME), + readyToWork_(readyToWork), + runFunc_(runFunc) + {}; + + TestThread() = delete; + ~TestThread() {} + + bool ReadyToWork() override; + + int data_; + int priority_; + std::string name_; + +protected: + bool Run() override; + +private: + bool readyToWork_; + ThreadRunFunc runFunc_; +}; + +bool TestThread::ReadyToWork() +{ + BENCHMARK_LOGD("ThreadTest bool TestThread::ReadyToWork is called."); + return readyToWork_; +} + +bool TestThread::Run() +{ + BENCHMARK_LOGD("ThreadTest bool TestThread::Run is called."); + priority_ = getpriority(PRIO_PROCESS, 0); + char threadName[MAX_THREAD_NAME_LEN] = {0}; + prctl(PR_GET_NAME, threadName, 0, 0); + name_ = threadName; + + if (runFunc_ != nullptr) { + return (*runFunc_)(data_); + } + + return false; +} + +/* + * @tc.name: testThread001 + * @tc.desc: ThreadTest + */ +BENCHMARK_F(BenchmarkThreadTest, testThread001)(benchmark::State& state) +{ + BENCHMARK_LOGD("ThreadTest testThread001 start."); + const int expectedDataValue = 0; + while (state.KeepRunning()) { + g_times = 0; + std::unique_ptr test = std::make_unique(INITIAL_TEST_VALUE, false, TestRun01); + ThreadStatus status = test->Start("test_thread_01", THREAD_PROI_LOW, THREAD_STACK_SIZE); + AssertEqual((status == ThreadStatus::OK), true, + "(status == ThreadStatus::OK) did not equal true as expected.", state); + + pthread_t thread = test->GetThread(); + + // pthread_equal return non-zero if equal + AssertEqual((pthread_equal(thread, INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true), + "(pthread_equal(thread, INVALID_THREAD_ID) != 0) did not equal \ + (test->IsRunning() ? false : true) as expected.", state); + + // ReadyToWork return false, RUN will not be called! + AssertEqual(test->priority_, DEFAULT_PRIO, "test->priority_ did not equal DEFAULT_PRIO as expected.", state); + AssertEqual(test->name_, DEFAULT_THREAD_NAME, + "test->name_ did not equal DEFAULT_THREAD_NAME as expected.", state); + + // get stacksize of threa, may be different because of system memory align + AssertEqual(test->data_, expectedDataValue, + "test->data_ did not equal EXPECTED_DATA_VALUE as expected.", state); + AssertEqual(g_times, INITIAL_TIMES, "g_times did not equal INITIAL_TIMES as expected.", state); + test->NotifyExitSync(); + sleep(SLEEP_FOR_ONE_SECOND); + AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true), + "(pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0) did not equal \ + (test->IsRunning() ? false : true) as expected.", state); + } + BENCHMARK_LOGD("ThreadTest testThread001 end."); +} + +/* + * @tc.name: testThread002 + * @tc.desc: ThreadTest + */ +BENCHMARK_F(BenchmarkThreadTest, testThread002)(benchmark::State& state) +{ + BENCHMARK_LOGD("ThreadTest testThread002 start."); + const int expectedDataValue = 1; + while (state.KeepRunning()) { + g_times = 0; + std::unique_ptr test = std::make_unique(INITIAL_TEST_VALUE, true, TestRun01); + ThreadStatus status = test->Start("test_thread_02", THREAD_PROI_LOW, THREAD_STACK_SIZE); + + AssertEqual((status == ThreadStatus::OK), true, + "status == ThreadStatus::OK did not equal true as expected.", state); + + sleep(SLEEP_FOR_ONE_SECOND); // let the new thread has chance to run + + // pthread_equal return non-zero if equal, RUN return false,may exit already + AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true), + "(pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0) did not equal \ + (test->IsRunning() ? false : true) as expected.", state); + + // ReadyToWork return true, RUN will be called! + AssertEqual(test->priority_, THREAD_PROI_LOW, + "test->priority_ did not equal THREAD_PROI_LOW as expected.", state); + AssertEqual(test->name_, "test_thread_02", + "test->name_ did not equal \"test_thread_02\" as expected.", state); + AssertEqual(test->data_, expectedDataValue, "test->data_ did not equal expectedDataValue as expected.", state); + AssertEqual(g_times, INITIAL_TIMES, "g_times did not equal INITIAL_TIMES as expected.", state); + + test->NotifyExitSync(); + sleep(SLEEP_FOR_ONE_SECOND); + AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true), + "pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0 did not equal \ + (test->IsRunning() ? false : true) as expected.", state); + } + BENCHMARK_LOGD("ThreadTest testThread002 end."); +} + +/* + * @tc.name: testThread003 + * @tc.desc: ThreadTest + */ +BENCHMARK_F(BenchmarkThreadTest, testThread003)(benchmark::State& state) +{ + BENCHMARK_LOGD("ThreadTest testThread003 start."); + const int expectedDataValue = 0; + while (state.KeepRunning()) { + g_times = 0; + std::unique_ptr test = std::make_unique(INITIAL_TEST_VALUE, false, TestRun02); + ThreadStatus status = test->Start("test_thread_03", THREAD_PROI_LOW, THREAD_STACK_SIZE); + AssertEqual((status == ThreadStatus::OK), true, + "status == ThreadStatus::OK did not equal true as expected.", state); + + pthread_t thread = test->GetThread(); + + // pthread_equal return non-zero if equal + AssertEqual((pthread_equal(thread, INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true), + "pthread_equal(thread, INVALID_THREAD_ID) != 0 did not equal \ + (test->IsRunning() ? false : true) as expected.", state); + + // ReadyToWork return false, RUN will not be called! + AssertEqual(test->priority_, DEFAULT_PRIO, + "test->priority_ did not equal DEFAULT_PRIO as expected.", state); + AssertEqual(test->name_, DEFAULT_THREAD_NAME, + "test->name_ did not equal DEFAULT_THREAD_NAME as expected.", state); + AssertEqual(test->data_, expectedDataValue, "test->data_ did not equal expectedDataValue as expected.", state); + AssertEqual(g_times, INITIAL_TIMES, "g_times did not equal INITIAL_TIMES as expected.", state); + + test->NotifyExitSync(); + sleep(SLEEP_FOR_ONE_SECOND); + AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true), + "pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0 did not equal \ + (test->IsRunning() ? false : true) as expected.", state); + } + BENCHMARK_LOGD("ThreadTest testThread003 end."); +} + +/* + * @tc.name: testThread004 + * @tc.desc: ThreadTest + */ +BENCHMARK_F(BenchmarkThreadTest, testThread004)(benchmark::State& state) +{ + BENCHMARK_LOGD("ThreadTest testThread004 start."); + const int comparisonValue = 1; + while (state.KeepRunning()) { + g_times = 0; + std::unique_ptr test = std::make_unique(INITIAL_TEST_VALUE, true, TestRun02); + ThreadStatus status = test->Start("test_thread_04", THREAD_PROI_LOW, THREAD_STACK_SIZE); + + AssertEqual((status == ThreadStatus::OK), true, + "status == ThreadStatus::OK did not equal true as expected.", state); + + sleep(SLEEP_FOR_ONE_SECOND); // let the new thread has chance to run + + // pthread_equal return non-zero if equal, RUN return false,may exit already + AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true), + "pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0 did not equal \ + (test->IsRunning() ? false : true) as expected.", state); + // ReadyToWork return true, RUN will be called! + AssertEqual(test->priority_, THREAD_PROI_LOW, + "test->priority_ did not equal THREAD_PROI_LOW as expected.", state); + AssertEqual(test->name_, "test_thread_04", + "test->name_ did not equal \"test_thread_04\" as expected.", state); + AssertGreaterThan(test->data_, comparisonValue, + "test->data_ was not greater than comparisonValue as expected.", state); + AssertEqual(g_times, INITIAL_TIMES, "g_times did not equal INITIAL_TIMES as expected.", state); + + test->NotifyExitSync(); + sleep(SLEEP_FOR_ONE_SECOND); + AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true), + "pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0 did not equal \ + (test->IsRunning() ? false : true) as expected.", state); + } + BENCHMARK_LOGD("ThreadTest testThread004 end."); +} + +/* + * @tc.name: testThread005 + * @tc.desc: ThreadTest + */ +BENCHMARK_F(BenchmarkThreadTest, testThread005)(benchmark::State& state) +{ + BENCHMARK_LOGD("ThreadTest testThread005 start."); + const int expectedDataValue = 0; + while (state.KeepRunning()) { + g_times = 0; + std::unique_ptr test = std::make_unique(INITIAL_TEST_VALUE, false, TestRun03); + ThreadStatus status = test->Start("test_thread_05", THREAD_PROI_LOW, THREAD_STACK_SIZE); + AssertEqual((status == ThreadStatus::OK), true, + "status == ThreadStatus::OK did not equal true as expected.", state); + + pthread_t thread = test->GetThread(); + // pthread_equal return non-zero if equal + AssertEqual((pthread_equal(thread, INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true), + "pthread_equal(thread, INVALID_THREAD_ID) != 0 did not equal \ + (test->IsRunning() ? false : true) as expected.", state); + // ReadyToWork return false, RUN will not be called! + AssertEqual(test->priority_, DEFAULT_PRIO, + "test->priority_ did not equal DEFAULT_PRIO as expected.", state); + AssertEqual(test->name_, DEFAULT_THREAD_NAME, + "test->name_ did not equal DEFAULT_THREAD_NAME as expected.", state); + AssertEqual(test->data_, expectedDataValue, "test->data_ did not equal expectedDataValue as expected.", state); + AssertEqual(g_times, INITIAL_TIMES, "g_times did not equal INITIAL_TIMES as expected.", state); + + test->NotifyExitSync(); + sleep(SLEEP_FOR_ONE_SECOND); + AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true), + "pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0 did not equal \ + (test->IsRunning() ? false : true) as expected.", state); + } + BENCHMARK_LOGD("ThreadTest testThread005 end."); +} + +/* + * @tc.name: testThread006 + * @tc.desc: ThreadTest + */ +BENCHMARK_F(BenchmarkThreadTest, testThread006)(benchmark::State& state) +{ + BENCHMARK_LOGD("ThreadTest testThread006 start."); + const int comparisonValue = 10; + while (state.KeepRunning()) { + g_times = 0; + std::unique_ptr test = std::make_unique(INITIAL_TEST_VALUE, true, TestRun03); + ThreadStatus status = test->Start("test_thread_06", THREAD_PROI_LOW, THREAD_STACK_SIZE); + AssertEqual((status == ThreadStatus::OK), true, + "status == ThreadStatus::OK did not equal true as expected.", state); + + sleep(SLEEP_FOR_ONE_SECOND); // let the new thread has chance to run + + // pthread_equal return non-zero if equal, RUN return false,may exit already + AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true), + "pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0 did not equal \ + (test->IsRunning() ? false : true) as expected.", state); + // ReadyToWork return true, RUN will be called! + AssertEqual(test->priority_, THREAD_PROI_LOW, + "test->priority_ did not equal THREAD_PROI_LOW as expected.", state); + AssertEqual(test->name_, "test_thread_06", + "test->name_ did not equal \"test_thread_06\" as expected.", state); + AssertGreaterThan(test->data_, comparisonValue, + "test->data_ was not greater than comparisonValue as expected.", state); + AssertEqual(g_times, INITIAL_TIMES, "g_times did not equal INITIAL_TIMES as expected.", state); + + g_times = 100; + AssertGreaterThan(test->data_, comparisonValue, + "test->data_ was not greater than comparisonValue as expected.", state); + + sleep(SLEEP_FOR_ONE_SECOND); // let the new thread has chance to run + + // g_times > 10, TestRun03 return false, thread exit + AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true), + "pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0 did not equal \ + (test->IsRunning() ? false : true) as expected.", state); + } + BENCHMARK_LOGD("ThreadTest testThread006 end."); +} + +/* + * @tc.name: testThread007 + * @tc.desc: ThreadTest + */ +BENCHMARK_F(BenchmarkThreadTest, testThread007)(benchmark::State& state) +{ + BENCHMARK_LOGD("ThreadTest testThread007 start."); + while (state.KeepRunning()) { + g_times = 0; + std::unique_ptr test = std::make_unique(INITIAL_TEST_VALUE, true, TestRun03); + ThreadStatus status = test->Start("", THREAD_PROI_LOW, 0); + AssertEqual((status == ThreadStatus::OK), true, + "status == ThreadStatus::OK did not equal true as expected.", state); + + if (test->IsRunning()) { + status = test->Start("", THREAD_PROI_NORMAL, THREAD_STACK_SIZE); + AssertEqual(status == ThreadStatus::INVALID_OPERATION, true, + "status == ThreadStatus::INVALID_OPERATION did not equal true as expected.", state); + + test->NotifyExitSync(); + AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true), + "pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0 did not equal \ + (test->IsRunning() ? false : true) as expected.", state); + } + + sleep(SLEEP_FOR_ONE_SECOND); // let the new thread has chance to run + + AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true), + "pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0 did not equal \ + (test->IsRunning() ? false : true) as expected.", state); + } + BENCHMARK_LOGD("ThreadTest testThread007 end."); +} + +/* + * @tc.name: testThread008 + * @tc.desc: ThreadTest + */ +BENCHMARK_F(BenchmarkThreadTest, testThread008)(benchmark::State& state) +{ + BENCHMARK_LOGD("ThreadTest testThread008 start."); + while (state.KeepRunning()) { + g_times = 0; + std::unique_ptr test = std::make_unique(INITIAL_TEST_VALUE, true, TestRun03); + + bool res = test->Thread::ReadyToWork(); + AssertEqual(res, true, "res did not equal true as expected.", state); + + ThreadStatus status = test->Start("", THREAD_PROI_NORMAL, THREAD_STACK_SIZE); + AssertEqual((status == ThreadStatus::OK), true, + "status == ThreadStatus::OK did not equal true as expected.", state); + + sleep(SLEEP_FOR_ONE_SECOND); + test->NotifyExitAsync(); + + sleep(SLEEP_FOR_ONE_SECOND); // let the new thread has chance to run + AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true), + "pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0 did not equal \ + (test->IsRunning() ? false : true) as expected.", state); + } + BENCHMARK_LOGD("ThreadTest testThread008 end."); +} + +class TestThread2 : public OHOS::Thread { +public: + TestThread2(const int data, ThreadRunFunc runFunc) + : data_(data), priority_(DEFAULT_PRIO), name_(DEFAULT_THREAD_NAME), runFunc_(runFunc) + {}; + + TestThread2() = delete; + ~TestThread2() {} + + int data_; + int priority_; + std::string name_; +protected: + bool Run() override; + +private: + ThreadRunFunc runFunc_; +}; + +bool TestThread2::Run() +{ + BENCHMARK_LOGD("ThreadTest bool TestThread2::Run is called."); + priority_ = getpriority(PRIO_PROCESS, 0); + char threadName[MAX_THREAD_NAME_LEN] = {0}; + prctl(PR_GET_NAME, threadName, 0, 0); + name_ = threadName; + + if (runFunc_ != nullptr) { + return (*runFunc_)(data_); + } + + return false; +} + +/* + * @tc.name: testThread009 + * @tc.desc: ThreadTest + */ +BENCHMARK_F(BenchmarkThreadTest, testThread009)(benchmark::State& state) +{ + BENCHMARK_LOGD("ThreadTest testThread009 start."); + while (state.KeepRunning()) { + g_times = 0; + std::unique_ptr test = std::make_unique(0, TestRun03); + + bool res = test->ReadyToWork(); + AssertEqual(res, true, "res did not equal true as expected.", state); + + ThreadStatus status = test->Start("", THREAD_PROI_NORMAL, THREAD_STACK_SIZE); + AssertEqual((status == ThreadStatus::OK), true, + "status == ThreadStatus::OK did not equal true as expected.", state); + + sleep(SLEEP_FOR_ONE_SECOND); + test->NotifyExitAsync(); + + sleep(SLEEP_FOR_ONE_SECOND); // let the new thread has chance to run + AssertEqual((pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0), (test->IsRunning() ? false : true), + "pthread_equal(test->GetThread(), INVALID_THREAD_ID) != 0 did not equal \ + (test->IsRunning() ? false : true) as expected.", state); + } + BENCHMARK_LOGD("ThreadTest testThread009 end."); +} +} // namespace +} // namespace OHOS +// Run the benchmark +BENCHMARK_MAIN(); \ No newline at end of file diff --git a/base/test/benchmarktest/thread_pool_benchmark_test/BUILD.gn b/base/test/benchmarktest/thread_pool_benchmark_test/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..475ef62859a511d77c3aa924132e09b395583af6 --- /dev/null +++ b/base/test/benchmarktest/thread_pool_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/thread_pool" + +ohos_benchmarktest("ThreadPoolTest") { + module_out_path = module_output_path + + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + sources = [ "thread_pool_benchmark_test.cpp" ] + + deps = [ "//third_party/benchmark:benchmark" ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog_base", + ] +} diff --git a/base/test/benchmarktest/thread_pool_benchmark_test/thread_pool_benchmark_test.cpp b/base/test/benchmarktest/thread_pool_benchmark_test/thread_pool_benchmark_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cecb290e9a12956cea64b786c5e8e54443b761a3 --- /dev/null +++ b/base/test/benchmarktest/thread_pool_benchmark_test/thread_pool_benchmark_test.cpp @@ -0,0 +1,426 @@ +/* + * 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 +#include +#include +#include "thread_pool.h" +#include "../log.h" +#include "../assert.h" +#include + +namespace OHOS { +namespace { + +int g_times = 0; +bool g_ready = false; +std::mutex g_mutex; +std::condition_variable g_cv; +const int SLEEP_FOR_ONE_SECOND = 1; +static bool g_flagTestFuncGetName = true; + +class BenchmarkThreadPoolTest : public benchmark::Fixture { +public: + BenchmarkThreadPoolTest() + { + Iterations(iterations); + Repetitions(repetitions); + ReportAggregatesOnly(); + } + + ~BenchmarkThreadPoolTest() 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; +}; + +BENCHMARK_F(BenchmarkThreadPoolTest, test_01)(benchmark::State& state) +{ + BENCHMARK_LOGD("ThreadPoolTest test_01 start."); + const int maxTaskNum = 0; + const int threadsNum = 0; + const int curTaskNum = 0; + while (state.KeepRunning()) { + ThreadPool pool; + AssertEqual(pool.GetName(), "", "pool.GetName() did not equal \"\" as expected.", state); + AssertEqual((int)pool.GetMaxTaskNum(), maxTaskNum, + "(int)pool.GetMaxTaskNum() did not equal maxTaskNum as expected.", state); + AssertEqual((int)pool.GetThreadsNum(), threadsNum, + "(int)pool.GetThreadsNum() did not equal threadsNum as expected.", state); + AssertEqual((int)pool.GetCurTaskNum(), curTaskNum, + "(int)pool.GetCurTaskNum() did not equal curTaskNum as expected.", state); + } + BENCHMARK_LOGD("ThreadPoolTest test_01 end."); +} + +BENCHMARK_F(BenchmarkThreadPoolTest, test_02)(benchmark::State& state) +{ + BENCHMARK_LOGD("ThreadPoolTest test_02 start."); + const int maxTaskNum = 0; + const int threadsNum = 0; + const int curTaskNum = 0; + while (state.KeepRunning()) { + ThreadPool pool("test_02_pool"); + AssertEqual(pool.GetName(), "test_02_pool", + "pool.GetName() did not equal \"test_02_pool\" as expected.", state); + AssertEqual((int)pool.GetMaxTaskNum(), maxTaskNum, + "(int)pool.GetMaxTaskNum() did not equal maxTaskNum as expected.", state); + AssertEqual((int)pool.GetThreadsNum(), threadsNum, + "(int)pool.GetThreadsNum() did not equal threadsNum as expected.", state); + AssertEqual((int)pool.GetCurTaskNum(), curTaskNum, + "(int)pool.GetCurTaskNum() did not equal curTaskNum as expected.", state); + } + BENCHMARK_LOGD("ThreadPoolTest test_02 end."); +} + +BENCHMARK_F(BenchmarkThreadPoolTest, test_03)(benchmark::State& state) +{ + BENCHMARK_LOGD("ThreadPoolTest test_03 start."); + const int maxTaskNum = 10; + const int threadsNum = 0; + const int curTaskNum = 0; + while (state.KeepRunning()) { + ThreadPool pool("test_02_pool"); + pool.SetMaxTaskNum(maxTaskNum); + AssertEqual(pool.GetName(), + "test_02_pool", "pool.GetName() did not equal \"test_02_pool\" as expected.", state); + AssertEqual((int)pool.GetMaxTaskNum(), maxTaskNum, + "(int)pool.GetMaxTaskNum() did not equal maxTaskNum as expected.", state); + AssertEqual((int)pool.GetThreadsNum(), threadsNum, + "(int)pool.GetThreadsNum() did not equal threadsNum as expected.", state); + AssertEqual((int)pool.GetCurTaskNum(), curTaskNum, + "(int)pool.GetCurTaskNum() did not equal curTaskNum as expected.", state); + } + BENCHMARK_LOGD("ThreadPoolTest test_03 end."); +} + +BENCHMARK_F(BenchmarkThreadPoolTest, test_04)(benchmark::State& state) +{ + BENCHMARK_LOGD("ThreadPoolTest test_04 start."); + const int startThreads = 4; + const int maxTaskNum = 0; + const int threadsNum = 4; + const int curTaskNum = 0; + while (state.KeepRunning()) { + ThreadPool pool; + pool.Start(startThreads); + AssertEqual(pool.GetName(), "", "pool.GetName() did not equal \"\" as expected.", state); + AssertEqual((int)pool.GetMaxTaskNum(), maxTaskNum, + "(int)pool.GetMaxTaskNum() did not equal maxTaskNum as expected.", state); + AssertEqual((int)pool.GetThreadsNum(), threadsNum, + "(int)pool.GetThreadsNum() did not equal threadsNum as expected.", state); + AssertEqual((int)pool.GetCurTaskNum(), curTaskNum, + "(int)pool.GetCurTaskNum() did not equal curTaskNum as expected.", state); + + // add no task, g_times has no change + AssertEqual(g_times, 0, "g_times did not equal 0 as expected.", state); + pool.Stop(); + } + BENCHMARK_LOGD("ThreadPoolTest test_04 end."); +} + +void TestFuncAddOneTime(int& i) +{ + std::lock_guard lock(g_mutex); + ++g_times; + BENCHMARK_LOGD("ThreadPoolTest TestFuncAddOneTime g_times:%{public}d", g_times); +} + +void TestFuncSubOneTime(int& i) +{ + std::lock_guard lock(g_mutex); + --g_times; + BENCHMARK_LOGD("ThreadPoolTest TestFuncSubOneTime g_times:%{public}d", g_times); +} + +// simple task, total task num less than the MaxTaskNum +BENCHMARK_F(BenchmarkThreadPoolTest, test_05)(benchmark::State& state) +{ + BENCHMARK_LOGD("ThreadPoolTest test_05 start."); + const int startThreads = 5; + const int threadsNum = 5; + const int curTaskNum = 0; + const int loopIterations1 = 3; + const int loopIterations2 = 2; + const int expectedTimesValue = 1; + while (state.KeepRunning()) { + BENCHMARK_LOGD("ThreadPoolTest test_05 in"); + ThreadPool pool; + pool.Start(startThreads); + AssertEqual(pool.GetName(), "", "pool.GetName() did not equal \"\" as expected.", state); + AssertEqual((int)pool.GetThreadsNum(), threadsNum, + "(int)pool.GetThreadsNum() did not equal threadsNum as expected.", state); + AssertEqual((int)pool.GetCurTaskNum(), curTaskNum, + "(int)pool.GetCurTaskNum() did not equal curTaskNum as expected.", state); + + for (int i = 0; i < loopIterations1; ++i) { + auto task = std::bind(TestFuncAddOneTime, i); + pool.AddTask(task); + } + + for (int i = 0; i < loopIterations2; ++i) { + auto task = std::bind(TestFuncSubOneTime, i); + pool.AddTask(task); + } + + sleep(SLEEP_FOR_ONE_SECOND); + AssertEqual((int)pool.GetCurTaskNum(), curTaskNum, + "(int)pool.GetCurTaskNum() did not equal curTaskNum as expected.", state); + // add 5 tasks, add 3 times and sub 2 times + BENCHMARK_LOGD("ThreadPoolTest test_05 g_times:%{public}d", g_times); + AssertEqual(g_times, expectedTimesValue, "g_times did not equal expectedTimesValue as expected.", state); + pool.Stop(); + g_times = 0; + BENCHMARK_LOGD("ThreadPoolTest test_05 off"); + } + BENCHMARK_LOGD("ThreadPoolTest test_05 end."); +} + +// simaple task, total task num exceed the MaxTaskNum and the threads num +BENCHMARK_F(BenchmarkThreadPoolTest, test_06)(benchmark::State& state) +{ + BENCHMARK_LOGD("ThreadPoolTest test_06 start."); + const int startThreads = 5; + const int threadsNum = 5; + const int curTaskNum = 0; + const int maxTaskNum = 10; + const int loopIterations1 = 8; + const int loopIterations2 = 7; + const int expectedTimesValue = 1; + while (state.KeepRunning()) { + ThreadPool pool; + pool.Start(startThreads); + AssertEqual(pool.GetName(), "", "pool.GetName() did not equal \"\" as expected.", state); + AssertEqual((int)pool.GetThreadsNum(), threadsNum, + "(int)pool.GetThreadsNum() did not equal threadsNum as expected.", state); + AssertEqual((int)pool.GetCurTaskNum(), curTaskNum, + "(int)pool.GetCurTaskNum() did not equal curTaskNum as expected.", state); + + pool.SetMaxTaskNum(maxTaskNum); + + for (int i = 0; i < loopIterations1; ++i) { + auto task = std::bind(TestFuncAddOneTime, i); + pool.AddTask(task); + } + + for (int i = 0; i < loopIterations2; ++i) { + auto task = std::bind(TestFuncSubOneTime, i); + pool.AddTask(task); + } + + sleep(SLEEP_FOR_ONE_SECOND); + // 1 second should be enough to complete these tasks. if not, this case would be fail + AssertEqual((int)pool.GetCurTaskNum(), curTaskNum, + "(int)pool.GetCurTaskNum() did not equal curTaskNum as expected.", state); + // add 5 task, add 3 times and sub 2 times + AssertEqual(g_times, expectedTimesValue, "g_times did not equal expectedTimesValue as expected.", state); + pool.Stop(); + g_times = 0; + } + BENCHMARK_LOGD("ThreadPoolTest test_06 end."); +} + +void TestFuncAddWait(int& i) +{ + BENCHMARK_LOGD("ThreadPoolTest void TestFuncAddWait is called."); + std::unique_lock lk(g_mutex); + ++g_times; + BENCHMARK_LOGD("ThreadPoolTest TestFuncAddWait i:%{public}d g_times:%{public}d", i, g_times); + g_cv.wait(lk, [] {return g_ready;}); + BENCHMARK_LOGD("ThreadPoolTest TestFuncAddWait received i:%{public}d g_ready:%{public}d", i, g_ready); +} + +void TestFuncSubWait(int& i) +{ + std::unique_lock lk(g_mutex); + --g_times; + BENCHMARK_LOGD("ThreadPoolTest TestFuncSubWait i:%{public}d g_times:%{public}d", i, g_times); + g_cv.wait(lk, [] {return g_ready;}); + BENCHMARK_LOGD("ThreadPoolTest TestFuncSubWait received i:%{public}d g_ready:%{public}d", i, g_ready); +} + +// complex task, wait for notify by the main thread +// total task num less than the threads num and the MaxTaskNum +BENCHMARK_F(BenchmarkThreadPoolTest, test_07)(benchmark::State& state) +{ + BENCHMARK_LOGD("ThreadPoolTest test_07 start."); + const int startThreads = 5; + const int threadsNum = 5; + const int curTaskNum = 0; + const int loopIterations1 = 3; + const int loopIterations2 = 2; + const int expectedTimesValue = 1; + while (state.KeepRunning()) { + ThreadPool pool; + pool.Start(startThreads); + AssertEqual(pool.GetName(), "", "pool.GetName() did not equal \"\" as expected.", state); + AssertEqual((int)pool.GetThreadsNum(), threadsNum, + "(int)pool.GetThreadsNum() did not equal threadsNum as expected.", state); + AssertEqual((int)pool.GetCurTaskNum(), curTaskNum, + "(int)pool.GetCurTaskNum() did not equal curTaskNum as expected.", state); + + for (int i = 0; i < loopIterations1; ++i) { + auto task = std::bind(TestFuncAddWait, i); + pool.AddTask(task); + } + + for (int i = 0; i < loopIterations2; ++i) { + auto task = std::bind(TestFuncSubWait, i); + pool.AddTask(task); + } + + // release cpu proactively, let the task threads go into wait + std::this_thread::sleep_for(std::chrono::seconds(SLEEP_FOR_ONE_SECOND)); + { + std::lock_guard lk(g_mutex); + g_ready = true; + } + + g_cv.notify_all(); + + // these tasks are endless Loop, 5 threads process 5 tasks, zero task remains in the task queue + AssertEqual((int)pool.GetCurTaskNum(), curTaskNum, + "(int)pool.GetCurTaskNum() did not equal curTaskNum as expected.", state); + // add 5 task, add 3 times and sub 2 times + BENCHMARK_LOGD("ThreadPoolTest test_07 g_times:%{public}d", g_times); + AssertEqual(g_times, expectedTimesValue, "g_times did not equal expectedTimesValue as expected.", state); + pool.Stop(); + g_times = 0; + g_ready = false; + } + BENCHMARK_LOGD("ThreadPoolTest test_07 end."); +} + +BENCHMARK_F(BenchmarkThreadPoolTest, test_08)(benchmark::State& state) +{ + BENCHMARK_LOGD("ThreadPoolTest test_08 start."); + const int startThreads = 5; + const int threadsNum = 5; + const int curTaskNum = 0; + const int maxTaskNum = 10; + const int loopIterations1 = 8; + const int loopIterations2 = 7; + const int curTaskNum2 = 10; + const int expectedTimesValue = 5; + const int expectedTimesValue2 = 1; + while (state.KeepRunning()) { + ThreadPool pool; + pool.Start(startThreads); + AssertEqual(pool.GetName(), "", "pool.GetName() did not equal \"\" as expected.", state); + AssertEqual((int)pool.GetThreadsNum(), threadsNum, + "(int)pool.GetThreadsNum() did not equal threadsNum as expected.", state); + AssertEqual((int)pool.GetCurTaskNum(), curTaskNum, + "(int)pool.GetCurTaskNum() did not equal curTaskNum as expected.", state); + + pool.SetMaxTaskNum(maxTaskNum); + + // ADD 15 tasks + for (int i = 0; i < loopIterations1; ++i) { + auto task = std::bind(TestFuncAddWait, i); + pool.AddTask(task); + } + + for (int i = 0; i < loopIterations2; ++i) { + auto task = std::bind(TestFuncSubWait, i); + pool.AddTask(task); + } + + sleep(SLEEP_FOR_ONE_SECOND); + // at this time, the first 5 tasks execute and wait for notify, the rest 10 tasks stay in the task queue. + BENCHMARK_LOGD("ThreadPoolTest test_08 g_times:%{tastNum}d", (int)pool.GetCurTaskNum()); + AssertEqual((int)pool.GetCurTaskNum(), curTaskNum2, + "(int)pool.GetCurTaskNum() did not equal curTaskNum2 as expected.", state); + // FIFO, + AssertEqual(g_times, expectedTimesValue, "g_times did not equal expectedTimesValue as expected.", state); + + // notify_all + { + std::lock_guard lk(g_mutex); + g_ready = true; + } + g_cv.notify_all(); + + // after noity, task thread wake up, and g_ready is true, new tasks didn't need to wait + sleep(SLEEP_FOR_ONE_SECOND); + // these tasks are endless Loop, and total num of task exceed the MaxTaskNum + AssertEqual((int)pool.GetCurTaskNum(), curTaskNum, + "(int)pool.GetCurTaskNum() did not equal curTaskNum as expected.", state); + AssertEqual(g_times, expectedTimesValue2, "g_times did not equal expectedTimesValue2 as expected.", state); + pool.Stop(); + g_times = 0; + g_ready = false; + } + BENCHMARK_LOGD("ThreadPoolTest test_08 end."); +} + +void TestFuncGetName(const std::string& poolName) +{ + BENCHMARK_LOGD("ThreadPoolTest void TestFuncGetName is called."); + char name[16]; + prctl(PR_GET_NAME, name); + std::string nameStr(name); + size_t found = nameStr.find(poolName); + if (found != 0) { + g_flagTestFuncGetName = false; + } +} + +/* + * Test_09 is used to verify the name set to ThreadPool will be set as the real name of threads in pool. + */ +BENCHMARK_F(BenchmarkThreadPoolTest, test_09)(benchmark::State& state) +{ + BENCHMARK_LOGD("ThreadPoolTest test_09 start."); + const int startThreads = 5; + const int threadsNum = 5; + const int curTaskNum = 0; + const int loopIterations = 5; + while (state.KeepRunning()) { + std::string poolName("test_09_pool"); + ThreadPool pool(poolName); + pool.Start(startThreads); + AssertEqual(pool.GetName(), poolName, "pool.GetName() did not equal poolName as expected.", state); + AssertEqual((int)pool.GetThreadsNum(), threadsNum, + "(int)pool.GetThreadsNum() did not equal threadsNum as expected.", state); + AssertEqual((int)pool.GetCurTaskNum(), curTaskNum, + "(int)pool.GetCurTaskNum() did not equal curTaskNum as expected.", state); + + for (int i = 0; i < loopIterations; ++i) { + auto task = std::bind(TestFuncGetName, poolName); + AssertTrue(g_flagTestFuncGetName, "found did not equal true as expected.", state); + pool.AddTask(task); + } + + sleep(SLEEP_FOR_ONE_SECOND); + // these tasks are endless Loop, 5 threads process 5 tasks, zero task remains in the task queue + AssertEqual((int)pool.GetCurTaskNum(), curTaskNum, + "(int)pool.GetCurTaskNum() did not equal curTaskNum as expected.", state); + pool.Stop(); + } + BENCHMARK_LOGD("ThreadPoolTest test_09 end."); +} +} // namespace +} // namespace OHOS +// Run the benchmark +BENCHMARK_MAIN(); \ No newline at end of file