Precommit (#1)

* first commit

* cleanup
This commit is contained in:
tompzf
2025-11-04 13:28:06 +01:00
committed by GitHub
parent dba45dc636
commit 6ed4b1534e
898 changed files with 256340 additions and 0 deletions

View File

@@ -0,0 +1,25 @@
# Define project
project(SchedulerTests VERSION 1.0 LANGUAGES CXX)
# Define target
add_executable(UnitTest_Scheduler scheduler_test.cpp)
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_link_libraries(UnitTest_Scheduler GTest::GTest)
if (WIN32)
target_link_libraries(UnitTest_Scheduler Ws2_32 Winmm Rpcrt4.lib)
else()
target_link_libraries(UnitTest_Scheduler ${CMAKE_DL_LIBS} rt)
endif()
else()
target_link_libraries(UnitTest_Scheduler GTest::GTest Rpcrt4.lib)
endif()
# Add the test
add_test(NAME UnitTest_Scheduler COMMAND UnitTest_Scheduler WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
# Execute the test
add_custom_command(TARGET UnitTest_Scheduler POST_BUILD
COMMAND ${CMAKE_COMMAND} -E env TEST_EXECUTION_MODE=CMake "$<TARGET_FILE:UnitTest_Scheduler>" --gtest_output=xml:${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/UnitTest_Scheduler.xml
VERBATIM
)

View File

@@ -0,0 +1,180 @@
#include <fstream>
#include <gtest/gtest.h>
#include <chrono>
#include "../../../global/process_watchdog.h"
#include "../../../global/scheduler/scheduler.cpp"
#if defined(_WIN32) && defined(_UNICODE)
extern "C" int wmain(int argc, wchar_t* argv[])
#else
extern "C" int main(int argc, char* argv[])
#endif
{
CProcessWatchdog watchdog;
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
TEST(TaskSchedulerTest, Construction)
{
CTaskScheduler scheduler(2);
EXPECT_EQ(scheduler.GetThreadCount(), 2);
EXPECT_EQ(scheduler.GetBusyThreadCount(), 0);
EXPECT_EQ(scheduler.GetIdleThreadCount(), 2);
EXPECT_EQ(scheduler.GetMaxThreadCount(), 2);
bool bFinished = false;
scheduler.Schedule([&]()
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
bFinished = true;
});
EXPECT_FALSE(bFinished);
scheduler.WaitForExecution();
EXPECT_TRUE(bFinished);
}
TEST(TaskSchedulerTest, PreallocatedConcurrencyExecution)
{
CTaskScheduler scheduler(4);
// Schedule tasks onto 4 threads
std::atomic_size_t nExecuted = 0;
bool bWait = true;
for (size_t n = 0; n < 4; n++)
scheduler.Schedule([&]()
{
while (bWait)
std::this_thread::sleep_for(std::chrono::milliseconds(100));
nExecuted++;
});
bWait = false;
// Wait until all threads are finalized
scheduler.WaitForExecution();
// Should be in parallel and threfore shorter to sequential.
EXPECT_EQ(scheduler.GetMaxThreadCount(), 4u);
EXPECT_EQ(nExecuted, 4u);
}
TEST(TaskSchedulerTest, AllocateConcurrency)
{
CTaskScheduler scheduler(2);
// Schedule 4 tasks onto two threads pre-allocated and two just-in-time-allocated threads
std::atomic_size_t nExecuted = 0;
bool bWait = true;
for (size_t n = 0; n < 4; n++)
scheduler.Schedule([&]()
{
while (bWait)
std::this_thread::sleep_for(std::chrono::milliseconds(100));
nExecuted++;
});
bWait = false;
// Wait until all threads are finalized
scheduler.WaitForExecution();
// Four tasks should be in parallel at the time.
EXPECT_EQ(scheduler.GetMaxThreadCount(), 4u);
EXPECT_EQ(nExecuted, 4u);
}
TEST(TaskSchedulerTest, ConcurrencyAndTaskQueueing)
{
CTaskScheduler scheduler(2, 2);
// Schedule 4 tasks onto two threads
std::atomic_size_t nExecuted = 0;
bool bWait = true;
for (size_t n = 0; n < 4; n++)
scheduler.Schedule([&]()
{
while (bWait)
std::this_thread::sleep_for(std::chrono::milliseconds(100));
nExecuted++;
});
bWait = false;
// Wait until all threads are finalized
scheduler.WaitForExecution();
// Two tasks should be in parallel at the time.
EXPECT_EQ(scheduler.GetMaxThreadCount(), 2u);
EXPECT_EQ(nExecuted, 4u);
}
TEST(TaskSchedulerTest, ConcurrencyAndDisallowTaskQueueing)
{
CTaskScheduler scheduler(2, 2);
// Schedule 4 tasks onto two threads.. Disallow the second task to be queued and the fourth task to be queued.
std::atomic_size_t nExecuted = 0;
bool bWait = true;
for (size_t n = 0; n < 4; n++)
scheduler.Schedule([&]()
{
while (bWait)
std::this_thread::sleep_for(std::chrono::milliseconds(100));
nExecuted++;
}, (n % 2 ? CTaskScheduler::EScheduleFlags::no_queue: CTaskScheduler::EScheduleFlags::normal));
bWait = false;
// Wait until all threads are finalized
scheduler.WaitForExecution();
// Two tasks should be in parallel at the time. Three tasks were executed
EXPECT_EQ(scheduler.GetMaxThreadCount(), 2u);
EXPECT_EQ(nExecuted, 3u);
}
TEST(TaskSchedulerTest, ConcurrencyAndPrioritizedTaskQueueing)
{
CTaskScheduler scheduler(2, 2);
// Schedule 5 tasks onto two threads.. Queue the fifth task with high priority.
std::atomic_size_t nExecuted = 0;
bool bWait = true;
std::vector<size_t> vecOrder;
std::mutex mtxOrder;
for (size_t n = 0; n < 5; n++)
scheduler.Schedule([&, n]()
{
// Synchronize start
while (bWait)
std::this_thread::sleep_for(std::chrono::milliseconds(2));
// Add the task...
std::unique_lock<std::mutex> lock(mtxOrder);
vecOrder.push_back(n);
lock.unlock();
// Wait once more
std::this_thread::sleep_for(std::chrono::milliseconds(300));
nExecuted++;
}, (n == 4 ? CTaskScheduler::EScheduleFlags::priority : CTaskScheduler::EScheduleFlags::normal));
bWait = false;
// Wait until all threads are finalized
scheduler.WaitForExecution();
std::cout << "vecOrder={";
for (size_t nx : vecOrder)
std::cout << nx << ", ";
std::cout << "}" << std::endl;
// Two tasks should be in parallel at the time. Five tasks were executed. The first two can come in any order. Then the fifth
// task comes and the last two can also be in any order.
EXPECT_EQ(scheduler.GetMaxThreadCount(), 2u);
EXPECT_EQ(nExecuted, 5u);
ASSERT_EQ(vecOrder.size(), 5u);
EXPECT_TRUE(vecOrder[0] == 0 || vecOrder[1] == 0);
EXPECT_TRUE(vecOrder[0] == 1 || vecOrder[1] == 1);
EXPECT_EQ(vecOrder[2], 4u);
EXPECT_TRUE(vecOrder[3] == 2 || vecOrder[4] == 2);
EXPECT_TRUE(vecOrder[3] == 3 || vecOrder[4] == 3);
}