tdf#162786, tdf#161947: Add support for setuptools and pip
[LibreOffice.git] / comphelper / qa / unit / threadpooltest.cxx
blob13eaf210a18b9a2332c4280c5d23266d1115c905
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <comphelper/threadpool.hxx>
11 #include <cppunit/TestAssert.h>
12 #include <cppunit/TestFixture.h>
13 #include <cppunit/extensions/HelperMacros.h>
14 #include <cppunit/plugin/TestPlugIn.h>
15 #include <tools/time.hxx>
16 #include <osl/thread.hxx>
18 #include <stdlib.h>
19 #include <atomic>
20 #include <cstddef>
21 #include <thread>
22 #include <mutex>
24 class ThreadPoolTest : public CppUnit::TestFixture
26 public:
27 void testPreferredConcurrency();
28 void testWorkerUsage();
29 void testTasksInThreads();
30 void testNoThreads();
31 void testDedicatedPool();
33 CPPUNIT_TEST_SUITE(ThreadPoolTest);
34 CPPUNIT_TEST(testPreferredConcurrency);
35 CPPUNIT_TEST(testWorkerUsage);
36 CPPUNIT_TEST(testTasksInThreads);
37 CPPUNIT_TEST(testNoThreads);
38 CPPUNIT_TEST(testDedicatedPool);
39 CPPUNIT_TEST_SUITE_END();
42 void ThreadPoolTest::testPreferredConcurrency()
44 // Check default.
45 auto nThreads = comphelper::ThreadPool::getPreferredConcurrency();
46 std::size_t nExpected = 4; // UTs are capped to 4.
47 CPPUNIT_ASSERT_MESSAGE("Expected no more than 4 threads", nExpected >= nThreads);
49 #ifndef _WIN32
50 // The result should be cached, so this should change anything.
51 nThreads = std::thread::hardware_concurrency() * 2;
52 setenv("MAX_CONCURRENCY", std::to_string(nThreads).c_str(), true);
53 nThreads = comphelper::ThreadPool::getPreferredConcurrency();
54 CPPUNIT_ASSERT_MESSAGE("Expected no more than hardware threads",
55 nThreads <= std::thread::hardware_concurrency());
57 // Revert and check. Again, nothing should change.
58 unsetenv("MAX_CONCURRENCY");
59 nThreads = comphelper::ThreadPool::getPreferredConcurrency();
60 CPPUNIT_ASSERT_MESSAGE("Expected no more than 4 threads", nExpected >= nThreads);
61 #endif
64 namespace
66 class UsageTask : public comphelper::ThreadTask
68 public:
69 UsageTask(const std::shared_ptr<comphelper::ThreadTaskTag>& pTag)
70 : ThreadTask(pTag)
73 virtual void doWork()
75 ++count;
76 mutex.lock();
77 mutex.unlock();
79 static inline std::atomic<int> count = 0;
80 static inline std::mutex mutex;
82 } // namespace
84 void ThreadPoolTest::testWorkerUsage()
86 // Create tasks for each available worker. Lock a shared mutex before that to make all
87 // tasks block on it. And check that all workers have started, i.e. that the full
88 // thread pool capacity is used.
89 comphelper::ThreadPool& rSharedPool = comphelper::ThreadPool::getSharedOptimalPool();
90 std::shared_ptr<comphelper::ThreadTaskTag> pTag = comphelper::ThreadPool::createThreadTaskTag();
91 UsageTask::mutex.lock();
92 for (int i = 0; i < rSharedPool.getWorkerCount(); ++i)
94 rSharedPool.pushTask(std::make_unique<UsageTask>(pTag));
95 osl::Thread::wait(std::chrono::milliseconds(10)); // give it a time to start
97 sal_uInt64 startTicks = tools::Time::GetSystemTicks();
98 while (UsageTask::count != rSharedPool.getWorkerCount())
100 // Wait at most 5 seconds, that should do even on slow systems.
101 CPPUNIT_ASSERT_MESSAGE("Thread pool does not use all worker threads.",
102 startTicks + 5000 > tools::Time::GetSystemTicks());
103 osl::Thread::wait(std::chrono::milliseconds(10));
105 UsageTask::mutex.unlock();
106 rSharedPool.waitUntilDone(pTag);
109 namespace
111 class CheckThreadTask : public comphelper::ThreadTask
113 oslThreadIdentifier mThreadId;
114 bool mCheckEqual;
116 public:
117 CheckThreadTask(oslThreadIdentifier threadId, bool checkEqual,
118 const std::shared_ptr<comphelper::ThreadTaskTag>& pTag)
119 : ThreadTask(pTag)
120 , mThreadId(threadId)
121 , mCheckEqual(checkEqual)
124 virtual void doWork()
126 CPPUNIT_ASSERT(mCheckEqual ? osl::Thread::getCurrentIdentifier() == mThreadId
127 : osl::Thread::getCurrentIdentifier() != mThreadId);
130 } // namespace
132 void ThreadPoolTest::testTasksInThreads()
134 // Check that all tasks are run in worker threads, not this thread.
135 comphelper::ThreadPool& pool = comphelper::ThreadPool::getSharedOptimalPool();
136 std::shared_ptr<comphelper::ThreadTaskTag> pTag = comphelper::ThreadPool::createThreadTaskTag();
137 for (int i = 0; i < 8; ++i)
138 pool.pushTask(
139 std::make_unique<CheckThreadTask>(osl::Thread::getCurrentIdentifier(), false, pTag));
140 pool.waitUntilDone(pTag);
143 void ThreadPoolTest::testNoThreads()
145 // No worker threads, tasks will be run in this thread.
146 comphelper::ThreadPool pool(0);
147 std::shared_ptr<comphelper::ThreadTaskTag> pTag = comphelper::ThreadPool::createThreadTaskTag();
148 for (int i = 0; i < 8; ++i)
149 pool.pushTask(
150 std::make_unique<CheckThreadTask>(osl::Thread::getCurrentIdentifier(), true, pTag));
151 pool.waitUntilDone(pTag);
154 void ThreadPoolTest::testDedicatedPool()
156 // Test that a separate thread pool works. The tasks themselves do not matter.
157 comphelper::ThreadPool pool(4);
158 std::shared_ptr<comphelper::ThreadTaskTag> pTag = comphelper::ThreadPool::createThreadTaskTag();
159 for (int i = 0; i < 8; ++i)
160 pool.pushTask(
161 std::make_unique<CheckThreadTask>(osl::Thread::getCurrentIdentifier(), false, pTag));
162 pool.waitUntilDone(pTag);
165 CPPUNIT_TEST_SUITE_REGISTRATION(ThreadPoolTest);
167 CPPUNIT_PLUGIN_IMPLEMENT();
169 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */