Changeset View
Changeset View
Standalone View
Standalone View
source/ps/tests/test_TaskManager.h
/* Copyright (C) 2021 Wildfire Games. | /* Copyright (C) 2021 Wildfire Games. | ||||
Lint: Inaccurate Copyright Year: Inaccurate Copyright Year | |||||
* This file is part of 0 A.D. | * This file is part of 0 A.D. | ||||
* | * | ||||
* 0 A.D. is free software: you can redistribute it and/or modify | * 0 A.D. is free software: you can redistribute it and/or modify | ||||
* it under the terms of the GNU General Public License as published by | * it under the terms of the GNU General Public License as published by | ||||
* the Free Software Foundation, either version 2 of the License, or | * the Free Software Foundation, either version 2 of the License, or | ||||
* (at your option) any later version. | * (at your option) any later version. | ||||
* | * | ||||
* 0 A.D. is distributed in the hope that it will be useful, | * 0 A.D. is distributed in the hope that it will be useful, | ||||
Show All 20 Lines | public: | ||||
void test_basic() | void test_basic() | ||||
{ | { | ||||
Threading::TaskManager& taskManager = Threading::TaskManager::Instance(); | Threading::TaskManager& taskManager = Threading::TaskManager::Instance(); | ||||
// There is a minimum of 3. | // There is a minimum of 3. | ||||
TS_ASSERT(taskManager.GetNumberOfWorkers() >= 3); | TS_ASSERT(taskManager.GetNumberOfWorkers() >= 3); | ||||
std::atomic<int> tasks_run = 0; | std::atomic<int> tasks_run = 0; | ||||
auto increment_run = [&tasks_run]() { tasks_run++; }; | auto increment_run = [&tasks_run]() { tasks_run++; }; | ||||
Future future = taskManager.PushTask(increment_run); | Future future0 = taskManager.PushTask(increment_run); | ||||
future.Wait(); | future0.Wait(); | ||||
TS_ASSERT_EQUALS(tasks_run.load(), 1); | TS_ASSERT_EQUALS(tasks_run.load(), 1); | ||||
// Test Execute. | // Test Execute. | ||||
std::condition_variable cv; | std::condition_variable cv; | ||||
std::mutex mutex; | std::mutex mutex; | ||||
std::atomic<bool> go = false; | std::atomic<bool> go = false; | ||||
future = taskManager.PushTask([&]() { | Future future1 = taskManager.PushTask([&]() { | ||||
std::unique_lock<std::mutex> lock(mutex); | std::unique_lock<std::mutex> lock(mutex); | ||||
cv.wait(lock, [&go]() -> bool { return go; }); | cv.wait(lock, [&go]() -> bool { return go; }); | ||||
lock.unlock(); | lock.unlock(); | ||||
increment_run(); | increment_run(); | ||||
lock.lock(); | lock.lock(); | ||||
go = false; | go = false; | ||||
lock.unlock(); | lock.unlock(); | ||||
cv.notify_all(); | cv.notify_all(); | ||||
}); | }); | ||||
TS_ASSERT_EQUALS(tasks_run.load(), 1); | TS_ASSERT_EQUALS(tasks_run.load(), 1); | ||||
std::unique_lock<std::mutex> lock(mutex); | std::unique_lock<std::mutex> lock(mutex); | ||||
go = true; | go = true; | ||||
lock.unlock(); | lock.unlock(); | ||||
cv.notify_all(); | cv.notify_all(); | ||||
lock.lock(); | lock.lock(); | ||||
cv.wait(lock, [&go]() -> bool { return !go; }); | cv.wait(lock, [&go]() -> bool { return !go; }); | ||||
TS_ASSERT_EQUALS(tasks_run.load(), 2); | TS_ASSERT_EQUALS(tasks_run.load(), 2); | ||||
// Wait on the future before the mutex/cv go out of scope. | // Wait on the future before the mutex/cv go out of scope. | ||||
future.Wait(); | future1.Wait(); | ||||
} | } | ||||
void test_Priority() | void test_Priority() | ||||
{ | { | ||||
Threading::TaskManager& taskManager = Threading::TaskManager::Instance(); | Threading::TaskManager& taskManager = Threading::TaskManager::Instance(); | ||||
std::atomic<int> tasks_run = 0; | std::atomic<int> tasks_run = 0; | ||||
// Push general tasks | // Push general tasks | ||||
auto increment_run = [&tasks_run]() { tasks_run++; }; | auto increment_run = [&tasks_run]() { tasks_run++; }; | ||||
Future future = taskManager.PushTask(increment_run); | Future future = taskManager.PushTask(increment_run); | ||||
Future futureLow = taskManager.PushTask(increment_run, Threading::TaskPriority::LOW); | Future futureLow = taskManager.PushTask(increment_run, Threading::TaskPriority::LOW); | ||||
future.Wait(); | future.Wait(); | ||||
futureLow.Wait(); | futureLow.Wait(); | ||||
TS_ASSERT_EQUALS(tasks_run.load(), 2); | TS_ASSERT_EQUALS(tasks_run.load(), 2); | ||||
// Also check with no waiting expected. | // Also check with no waiting expected. | ||||
taskManager.PushTask(increment_run).Wait(); | taskManager.PushTask(increment_run).Wait(); | ||||
TS_ASSERT_EQUALS(tasks_run.load(), 3); | TS_ASSERT_EQUALS(tasks_run.load(), 3); | ||||
taskManager.PushTask(increment_run, Threading::TaskPriority::LOW).Wait(); | taskManager.PushTask(increment_run, Threading::TaskPriority::LOW).Wait(); | ||||
TS_ASSERT_EQUALS(tasks_run.load(), 4); | TS_ASSERT_EQUALS(tasks_run.load(), 4); | ||||
} | } | ||||
static int func() | |||||
{ | |||||
return 5; | |||||
} | |||||
void test_Load() | void test_Load() | ||||
{ | { | ||||
Threading::TaskManager& taskManager = Threading::TaskManager::Instance(); | Threading::TaskManager& taskManager = Threading::TaskManager::Instance(); | ||||
#define ITERATIONS 100000 | #define ITERATIONS 100000 | ||||
std::vector<Future<int>> futures; | std::vector<Future<decltype(&func)>> futures; | ||||
futures.resize(ITERATIONS); | futures.resize(ITERATIONS); | ||||
std::vector<u32> values(ITERATIONS); | std::vector<u32> values(ITERATIONS); | ||||
auto f1 = taskManager.PushTask([&taskManager, &futures]() { | auto f1 = taskManager.PushTask([&taskManager, &futures]() { | ||||
for (u32 i = 0; i < ITERATIONS; i+=3) | for (u32 i = 0; i < ITERATIONS; i+=3) | ||||
futures[i] = taskManager.PushTask([]() { return 5; }); | futures[i] = taskManager.PushTask(func); | ||||
}); | }); | ||||
auto f2 = taskManager.PushTask([&taskManager, &futures]() { | auto f2 = taskManager.PushTask([&taskManager, &futures]() { | ||||
for (u32 i = 1; i < ITERATIONS; i+=3) | for (u32 i = 1; i < ITERATIONS; i+=3) | ||||
futures[i] = taskManager.PushTask([]() { return 5; }, Threading::TaskPriority::LOW); | futures[i] = taskManager.PushTask(func, Threading::TaskPriority::LOW); | ||||
}); | }); | ||||
auto f3 = taskManager.PushTask([&taskManager, &futures]() { | auto f3 = taskManager.PushTask([&taskManager, &futures]() { | ||||
for (u32 i = 2; i < ITERATIONS; i+=3) | for (u32 i = 2; i < ITERATIONS; i+=3) | ||||
futures[i] = taskManager.PushTask([]() { return 5; }); | futures[i] = taskManager.PushTask(func); | ||||
}); | }); | ||||
f1.Wait(); | f1.Wait(); | ||||
f2.Wait(); | f2.Wait(); | ||||
f3.Wait(); | f3.Wait(); | ||||
for (size_t i = 0; i < ITERATIONS; ++i) | for (size_t i = 0; i < ITERATIONS; ++i) | ||||
TS_ASSERT_EQUALS(futures[i].Get(), 5); | TS_ASSERT_EQUALS(futures[i].Get(), 5); | ||||
#undef ITERATIONS | #undef ITERATIONS | ||||
} | } | ||||
}; | }; |
Wildfire Games · Phabricator
Inaccurate Copyright Year