ctest: Add support for running under a make job server on POSIX systems

Share job slots with the job server by acquiring a token before running
each test, and releasing the token when the test finishes.
This commit is contained in:
Brad King
2023-11-15 13:55:35 -05:00
parent 5396f4a9a3
commit 80fe56c481
13 changed files with 136 additions and 0 deletions
@@ -40,6 +40,7 @@
#include "cmRange.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmUVJobServerClient.h"
#include "cmWorkingDirectory.h"
namespace cmsys {
@@ -130,10 +131,19 @@ void cmCTestMultiProcessHandler::InitializeLoop()
this->Loop.init();
this->StartNextTestsOnIdle_.init(*this->Loop, this);
this->StartNextTestsOnTimer_.init(*this->Loop, this);
this->JobServerClient = cmUVJobServerClient::Connect(
*this->Loop, /*onToken=*/[this]() { this->JobServerReceivedToken(); },
/*onDisconnect=*/nullptr);
if (this->JobServerClient) {
cmCTestLog(this->CTest, OUTPUT,
"Connected to MAKE jobserver" << std::endl);
}
}
void cmCTestMultiProcessHandler::FinalizeLoop()
{
this->JobServerClient.reset();
this->StartNextTestsOnTimer_.reset();
this->StartNextTestsOnIdle_.reset();
this->Loop.reset();
@@ -461,6 +471,26 @@ std::string cmCTestMultiProcessHandler::GetName(int test)
void cmCTestMultiProcessHandler::StartTest(int test)
{
if (this->JobServerClient) {
// There is a job server. Request a token and queue the test to run
// when a token is received. Note that if we do not get a token right
// away it's possible that the system load will be higher when the
// token is received and we may violate the test-load limit. However,
// this is unlikely because if we do not get a token right away, some
// other job that's currently running must finish before we get one.
this->JobServerClient->RequestToken();
this->JobServerQueuedTests.emplace_back(test);
} else {
// There is no job server. Start the test now.
this->StartTestProcess(test);
}
}
void cmCTestMultiProcessHandler::JobServerReceivedToken()
{
assert(!this->JobServerQueuedTests.empty());
int test = this->JobServerQueuedTests.front();
this->JobServerQueuedTests.pop_front();
this->StartTestProcess(test);
}
@@ -692,6 +722,9 @@ void cmCTestMultiProcessHandler::FinishTestProcess(
runner.reset();
if (this->JobServerClient) {
this->JobServerClient->ReleaseToken();
}
this->StartNextTestsOnIdle();
}
+10
View File
@@ -19,6 +19,7 @@
#include "cmCTestResourceSpec.h"
#include "cmCTestTestHandler.h"
#include "cmUVHandlePtr.h"
#include "cmUVJobServerClient.h"
struct cmCTestBinPackerAllocation;
class cmCTestRunTest;
@@ -204,6 +205,15 @@ protected:
cmCTestResourceAllocator ResourceAllocator;
std::vector<cmCTestTestHandler::cmCTestTestResult>* TestResults;
size_t ParallelLevel; // max number of process that can be run at once
// 'make' jobserver client. If connected, we acquire a token
// for each test before running its process.
cm::optional<cmUVJobServerClient> JobServerClient;
// List of tests that are queued to run when a token is available.
std::list<int> JobServerQueuedTests;
// Callback invoked when a token is received.
void JobServerReceivedToken();
unsigned long TestLoad;
unsigned long FakeLoadForTesting;
cm::uv_loop_ptr Loop;