diff options
author | Brad King <brad.king@kitware.com> | 2024-03-11 14:18:38 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2024-03-11 14:18:50 (GMT) |
commit | 89e99cca63e834901649da45b5e68fd50840e5a7 (patch) | |
tree | b19c572bc48eb332447f54913ef0f755500cc6d9 /Source/CTest | |
parent | 91feb31577f772a22aa25988a18cf5e24374b558 (diff) | |
parent | 5de1e21659090ca83e39e223d351e353347eb88e (diff) | |
download | CMake-89e99cca63e834901649da45b5e68fd50840e5a7.zip CMake-89e99cca63e834901649da45b5e68fd50840e5a7.tar.gz CMake-89e99cca63e834901649da45b5e68fd50840e5a7.tar.bz2 |
Merge topic 'ctest-j-default'
5de1e21659 ctest: Allow passing -j without value to choose a contextual default
bbcbcff7d9 cmCTestMultiProcessHandler: Modernize member initialization
7457b474a1 Tests: Remove unnecessary parallel suppression from CTestCoverageCollectGCOV
ae69801d96 Tests: Convert CTestTestSkipReturnCode to RunCMake.ctest_test case
30dda49416 Tests: Convert CTestTestSerialOrder to RunCMake.ctest_test case
Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: buildbot <buildbot@kitware.com>
Acked-by: scivision <michael@scivision.dev>
Merge-request: !9315
Diffstat (limited to 'Source/CTest')
-rw-r--r-- | Source/CTest/cmCTestMultiProcessHandler.cxx | 83 | ||||
-rw-r--r-- | Source/CTest/cmCTestMultiProcessHandler.h | 45 | ||||
-rw-r--r-- | Source/CTest/cmCTestTestCommand.cxx | 4 | ||||
-rw-r--r-- | Source/CTest/cmCTestTestCommand.h | 4 | ||||
-rw-r--r-- | Source/CTest/cmCTestTestHandler.cxx | 23 |
5 files changed, 109 insertions, 50 deletions
diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index 4c39d6e..a0bb1ea 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -43,6 +43,17 @@ #include "cmUVJobServerClient.h" #include "cmWorkingDirectory.h" +namespace { +// For unspecified parallelism, limit to the number of processors, +// but with a minimum greater than 1 so there is some parallelism. +constexpr unsigned long kParallelLevelMinimum = 2u; + +// For "unbounded" parallelism, limit to a very high value. +// Under a job server, parallelism is effectively limited +// only by available job server tokens. +constexpr unsigned long kParallelLevelUnbounded = 0x10000u; +} + namespace cmsys { class RegularExpression; } @@ -66,18 +77,14 @@ private: cmCTestMultiProcessHandler* Handler; }; -cmCTestMultiProcessHandler::cmCTestMultiProcessHandler() +cmCTestMultiProcessHandler::cmCTestMultiProcessHandler( + cmCTest* ctest, cmCTestTestHandler* handler) + : CTest(ctest) + , TestHandler(handler) + , ProcessorsAvailable(cmAffinity::GetProcessorsAvailable()) + , HaveAffinity(this->ProcessorsAvailable.size()) + , ParallelLevelDefault(kParallelLevelMinimum) { - this->ParallelLevel = 1; - this->TestLoad = 0; - this->FakeLoadForTesting = 0; - this->Completed = 0; - this->RunningCount = 0; - this->ProcessorsAvailable = cmAffinity::GetProcessorsAvailable(); - this->HaveAffinity = this->ProcessorsAvailable.size(); - this->HasCycles = false; - this->HasInvalidGeneratedResourceSpec = false; - this->SerialTestRunning = false; } cmCTestMultiProcessHandler::~cmCTestMultiProcessHandler() = default; @@ -103,9 +110,43 @@ bool cmCTestMultiProcessHandler::SetTests(TestMap tests, } // Set the max number of tests that can be run at the same time. -void cmCTestMultiProcessHandler::SetParallelLevel(size_t level) +void cmCTestMultiProcessHandler::SetParallelLevel(cm::optional<size_t> level) +{ + this->ParallelLevel = level; + + if (!this->ParallelLevel) { + // '-j' was given with no value. Limit by number of processors. + cmsys::SystemInformation info; + info.RunCPUCheck(); + unsigned long processorCount = info.GetNumberOfLogicalCPU(); + + if (cm::optional<std::string> fakeProcessorCount = + cmSystemTools::GetEnvVar( + "__CTEST_FAKE_PROCESSOR_COUNT_FOR_TESTING")) { + unsigned long pc = 0; + if (cmStrToULong(*fakeProcessorCount, &pc)) { + processorCount = pc; + } else { + cmSystemTools::Error("Failed to parse fake processor count: " + + *fakeProcessorCount); + } + } + + this->ParallelLevelDefault = + std::max(kParallelLevelMinimum, processorCount); + } +} + +size_t cmCTestMultiProcessHandler::GetParallelLevel() const { - this->ParallelLevel = level < 1 ? 1 : level; + if ((this->ParallelLevel && *this->ParallelLevel == 0) || + (!this->ParallelLevel && this->JobServerClient)) { + return kParallelLevelUnbounded; + } + if (this->ParallelLevel) { + return *this->ParallelLevel; + } + return this->ParallelLevelDefault; } void cmCTestMultiProcessHandler::SetTestLoad(unsigned long load) @@ -452,10 +493,11 @@ void cmCTestMultiProcessHandler::UnlockResources(int index) inline size_t cmCTestMultiProcessHandler::GetProcessorsUsed(int test) { size_t processors = static_cast<int>(this->Properties[test]->Processors); + size_t const parallelLevel = this->GetParallelLevel(); // If processors setting is set higher than the -j // setting, we default to using all of the process slots. - if (processors > this->ParallelLevel) { - processors = this->ParallelLevel; + if (processors > parallelLevel) { + processors = parallelLevel; } // Cap tests that want affinity to the maximum affinity available. if (this->HaveAffinity && processors > this->HaveAffinity && @@ -509,8 +551,9 @@ void cmCTestMultiProcessHandler::StartNextTests() size_t numToStart = 0; - if (this->RunningCount < this->ParallelLevel) { - numToStart = this->ParallelLevel - this->RunningCount; + size_t const parallelLevel = this->GetParallelLevel(); + if (this->RunningCount < parallelLevel) { + numToStart = parallelLevel - this->RunningCount; } if (numToStart == 0) { @@ -524,7 +567,7 @@ void cmCTestMultiProcessHandler::StartNextTests() } bool allTestsFailedTestLoadCheck = false; - size_t minProcessorsRequired = this->ParallelLevel; + size_t minProcessorsRequired = this->GetParallelLevel(); std::string testWithMinProcessors; cmsys::SystemInformation info; @@ -819,7 +862,7 @@ void cmCTestMultiProcessHandler::ReadCostData() this->Properties[index]->PreviousRuns = prev; // When not running in parallel mode, don't use cost data - if (this->ParallelLevel > 1 && this->Properties[index] && + if (this->GetParallelLevel() > 1 && this->Properties[index] && this->Properties[index]->Cost == 0) { this->Properties[index]->Cost = cost; } @@ -848,7 +891,7 @@ int cmCTestMultiProcessHandler::SearchByName(std::string const& name) void cmCTestMultiProcessHandler::CreateTestCostList() { - if (this->ParallelLevel > 1) { + if (this->GetParallelLevel() > 1) { this->CreateParallelTestCostList(); } else { this->CreateSerialTestCostList(); diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h index d66c348..1f6b042 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.h +++ b/Source/CTest/cmCTestMultiProcessHandler.h @@ -58,12 +58,12 @@ public: unsigned int Slots; }; - cmCTestMultiProcessHandler(); + cmCTestMultiProcessHandler(cmCTest* ctest, cmCTestTestHandler* handler); virtual ~cmCTestMultiProcessHandler(); // Set the tests bool SetTests(TestMap tests, PropertiesMap properties); // Set the max number of tests that can be run at the same time. - void SetParallelLevel(size_t); + void SetParallelLevel(cm::optional<size_t> level); void SetTestLoad(unsigned long load); virtual void RunTests(); void PrintOutputAsJson(); @@ -81,13 +81,6 @@ public: this->TestResults = r; } - void SetCTest(cmCTest* ctest) { this->CTest = ctest; } - - void SetTestHandler(cmCTestTestHandler* handler) - { - this->TestHandler = handler; - } - cmCTestTestHandler* GetTestHandler() { return this->TestHandler; } void SetRepeatMode(cmCTest::Repeat mode, int count) @@ -171,22 +164,26 @@ protected: bool InitResourceAllocator(std::string& error); bool CheckGeneratedResourceSpec(); +private: + cmCTest* CTest; + cmCTestTestHandler* TestHandler; + bool UseResourceSpec = false; cmCTestResourceSpec ResourceSpec; std::string ResourceSpecFile; std::string ResourceSpecSetupFixture; cm::optional<std::size_t> ResourceSpecSetupTest; - bool HasInvalidGeneratedResourceSpec; + bool HasInvalidGeneratedResourceSpec = false; // Tests pending selection to start. They may have dependencies. TestMap PendingTests; // List of pending test indexes, ordered by cost. std::list<int> OrderedTests; // Total number of tests we'll be running - size_t Total; + size_t Total = 0; // Number of tests that are complete - size_t Completed; - size_t RunningCount; + size_t Completed = 0; + size_t RunningCount = 0; std::set<size_t> ProcessorsAvailable; size_t HaveAffinity; bool StopTimePassed = false; @@ -204,7 +201,15 @@ protected: ResourceAvailabilityErrors; cmCTestResourceAllocator ResourceAllocator; std::vector<cmCTestTestHandler::cmCTestTestResult>* TestResults; - size_t ParallelLevel; // max number of process that can be run at once + + // Get the maximum number of processors that may be used at once. + size_t GetParallelLevel() const; + + // With no '-j' option, default to serial testing. + cm::optional<size_t> ParallelLevel = 1; + + // Fallback parallelism limit when '-j' is given with no value. + size_t ParallelLevelDefault; // 'make' jobserver client. If connected, we acquire a token // for each test before running its process. @@ -214,16 +219,14 @@ protected: // Callback invoked when a token is received. void JobServerReceivedToken(); - unsigned long TestLoad; - unsigned long FakeLoadForTesting; + unsigned long TestLoad = 0; + unsigned long FakeLoadForTesting = 0; cm::uv_loop_ptr Loop; cm::uv_idle_ptr StartNextTestsOnIdle_; cm::uv_timer_ptr StartNextTestsOnTimer_; - cmCTestTestHandler* TestHandler; - cmCTest* CTest; - bool HasCycles; + bool HasCycles = false; cmCTest::Repeat RepeatMode = cmCTest::Repeat::Never; int RepeatCount = 1; - bool Quiet; - bool SerialTestRunning; + bool Quiet = false; + bool SerialTestRunning = false; }; diff --git a/Source/CTest/cmCTestTestCommand.cxx b/Source/CTest/cmCTestTestCommand.cxx index ed16354..98ce862 100644 --- a/Source/CTest/cmCTestTestCommand.cxx +++ b/Source/CTest/cmCTestTestCommand.cxx @@ -105,8 +105,8 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler() if (this->StopOnFailure) { handler->SetOption("StopOnFailure", "ON"); } - if (!this->ParallelLevel.empty()) { - handler->SetOption("ParallelLevel", this->ParallelLevel); + if (this->ParallelLevel) { + handler->SetOption("ParallelLevel", *this->ParallelLevel); } if (!this->Repeat.empty()) { handler->SetOption("Repeat", this->Repeat); diff --git a/Source/CTest/cmCTestTestCommand.h b/Source/CTest/cmCTestTestCommand.h index ce054ed..23661c5 100644 --- a/Source/CTest/cmCTestTestCommand.h +++ b/Source/CTest/cmCTestTestCommand.h @@ -8,7 +8,9 @@ #include <utility> #include <cm/memory> +#include <cm/optional> +#include "cmArgumentParserTypes.h" #include "cmCTestHandlerCommand.h" #include "cmCommand.h" @@ -56,7 +58,7 @@ protected: std::string ExcludeFixture; std::string ExcludeFixtureSetup; std::string ExcludeFixtureCleanup; - std::string ParallelLevel; + cm::optional<ArgumentParser::Maybe<std::string>> ParallelLevel; std::string Repeat; std::string ScheduleRandom; std::string StopTime; diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index 957806a..b75df27 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -550,9 +550,21 @@ bool cmCTestTestHandler::ProcessOptions() return false; } } - if (this->GetOption("ParallelLevel")) { - this->CTest->SetParallelLevel( - std::stoi(*this->GetOption("ParallelLevel"))); + if (cmValue parallelLevel = this->GetOption("ParallelLevel")) { + if (parallelLevel.IsEmpty()) { + // An empty value tells ctest to choose a default. + this->CTest->SetParallelLevel(cm::nullopt); + } else { + // A non-empty value must be a non-negative integer. + unsigned long plevel = 0; + if (!cmStrToULong(*parallelLevel, &plevel)) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "ParallelLevel invalid value: " << *parallelLevel + << std::endl); + return false; + } + this->CTest->SetParallelLevel(plevel); + } } if (this->GetOption("StopOnFailure")) { @@ -1360,10 +1372,9 @@ bool cmCTestTestHandler::ProcessDirectory(std::vector<std::string>& passed, this->StartTestTime = std::chrono::system_clock::now(); auto elapsed_time_start = std::chrono::steady_clock::now(); - auto parallel = cm::make_unique<cmCTestMultiProcessHandler>(); - parallel->SetCTest(this->CTest); + auto parallel = + cm::make_unique<cmCTestMultiProcessHandler>(this->CTest, this); parallel->SetParallelLevel(this->CTest->GetParallelLevel()); - parallel->SetTestHandler(this); if (this->RepeatMode != cmCTest::Repeat::Never) { parallel->SetRepeatMode(this->RepeatMode, this->RepeatCount); } else { |