| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
| file Copyright.txt or https://cmake.org/licensing for details. */ |
| #pragma once |
| |
| #include "cmConfigure.h" // IWYU pragma: keep |
| |
| #include <cstddef> |
| #include <list> |
| #include <map> |
| #include <memory> |
| #include <set> |
| #include <string> |
| #include <vector> |
| |
| #include <cm/optional> |
| |
| #include "cmCTest.h" |
| #include "cmCTestResourceAllocator.h" |
| #include "cmCTestResourceSpec.h" |
| #include "cmCTestTestHandler.h" |
| #include "cmUVHandlePtr.h" |
| #include "cmUVJobServerClient.h" |
| |
| struct cmCTestBinPackerAllocation; |
| class cmCTestRunTest; |
| |
| /** \class cmCTestMultiProcessHandler |
| * \brief run parallel ctest |
| * |
| * cmCTestMultiProcessHandler |
| */ |
| class cmCTestMultiProcessHandler |
| { |
| friend class TestComparator; |
| friend class cmCTestRunTest; |
| |
| public: |
| struct TestSet : public std::set<int> |
| { |
| }; |
| struct TestInfo |
| { |
| TestSet Depends; |
| }; |
| struct TestMap : public std::map<int, TestInfo> |
| { |
| }; |
| struct TestList : public std::vector<int> |
| { |
| }; |
| struct PropertiesMap |
| : public std::map<int, cmCTestTestHandler::cmCTestTestProperties*> |
| { |
| }; |
| struct ResourceAllocation |
| { |
| std::string Id; |
| unsigned int Slots; |
| }; |
| |
| 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(cm::optional<size_t> level); |
| void SetTestLoad(unsigned long load); |
| virtual void RunTests(); |
| void PrintOutputAsJson(); |
| void PrintTestList(); |
| void PrintLabels(); |
| |
| void SetPassFailVectors(std::vector<std::string>* passed, |
| std::vector<std::string>* failed) |
| { |
| this->Passed = passed; |
| this->Failed = failed; |
| } |
| void SetTestResults(std::vector<cmCTestTestHandler::cmCTestTestResult>* r) |
| { |
| this->TestResults = r; |
| } |
| |
| cmCTestTestHandler* GetTestHandler() { return this->TestHandler; } |
| |
| void SetRepeatMode(cmCTest::Repeat mode, int count) |
| { |
| this->RepeatMode = mode; |
| this->RepeatCount = count; |
| } |
| |
| void SetResourceSpecFile(const std::string& resourceSpecFile) |
| { |
| this->ResourceSpecFile = resourceSpecFile; |
| } |
| |
| void SetQuiet(bool b) { this->Quiet = b; } |
| |
| void CheckResourceAvailability(); |
| |
| protected: |
| // Start the next test or tests as many as are allowed by |
| // ParallelLevel |
| void StartNextTests(); |
| void StartTestProcess(int test); |
| void StartTest(int test); |
| // Mark the checkpoint for the given test |
| void WriteCheckpoint(int index); |
| |
| void UpdateCostData(); |
| void ReadCostData(); |
| // Return index of a test based on its name |
| int SearchByName(std::string const& name); |
| |
| void CreateTestCostList(); |
| |
| void GetAllTestDependencies(int test, TestList& dependencies); |
| void CreateSerialTestCostList(); |
| |
| void CreateParallelTestCostList(); |
| |
| // Removes the checkpoint file |
| void MarkFinished(); |
| void FinishTestProcess(std::unique_ptr<cmCTestRunTest> runner, bool started); |
| |
| void StartNextTestsOnIdle(); |
| void StartNextTestsOnTimer(); |
| |
| void RemoveTest(int index); |
| // Check if we need to resume an interrupted test set |
| void CheckResume(); |
| // Check if there are any circular dependencies |
| bool CheckCycles(); |
| int FindMaxIndex(); |
| inline size_t GetProcessorsUsed(int index); |
| std::string GetName(int index); |
| |
| bool CheckStopOnFailure(); |
| |
| bool CheckStopTimePassed(); |
| void SetStopTimePassed(); |
| |
| void InitializeLoop(); |
| void FinalizeLoop(); |
| |
| bool ResourceLocksAvailable(int test); |
| void LockResources(int index); |
| void UnlockResources(int index); |
| |
| enum class ResourceAvailabilityError |
| { |
| NoResourceType, |
| InsufficientResources, |
| }; |
| |
| bool Complete(); |
| bool AllocateResources(int index); |
| bool TryAllocateResources( |
| int index, |
| std::map<std::string, std::vector<cmCTestBinPackerAllocation>>& |
| allocations, |
| std::map<std::string, ResourceAvailabilityError>* errors = nullptr); |
| void DeallocateResources(int index); |
| bool AllResourcesAvailable(); |
| 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 = 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 = 0; |
| // Number of tests that are complete |
| size_t Completed = 0; |
| size_t RunningCount = 0; |
| std::set<size_t> ProcessorsAvailable; |
| size_t HaveAffinity; |
| bool StopTimePassed = false; |
| // list of test properties (indices concurrent to the test map) |
| PropertiesMap Properties; |
| std::map<int, std::string> TestOutput; |
| std::vector<std::string>* Passed; |
| std::vector<std::string>* Failed; |
| std::vector<std::string> LastTestsFailed; |
| std::set<std::string> ProjectResourcesLocked; |
| std::map<int, |
| std::vector<std::map<std::string, std::vector<ResourceAllocation>>>> |
| AllocatedResources; |
| std::map<int, std::map<std::string, ResourceAvailabilityError>> |
| ResourceAvailabilityErrors; |
| cmCTestResourceAllocator ResourceAllocator; |
| std::vector<cmCTestTestHandler::cmCTestTestResult>* TestResults; |
| |
| // 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. |
| 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 = 0; |
| unsigned long FakeLoadForTesting = 0; |
| cm::uv_loop_ptr Loop; |
| cm::uv_idle_ptr StartNextTestsOnIdle_; |
| cm::uv_timer_ptr StartNextTestsOnTimer_; |
| bool HasCycles = false; |
| cmCTest::Repeat RepeatMode = cmCTest::Repeat::Never; |
| int RepeatCount = 1; |
| bool Quiet = false; |
| bool SerialTestRunning = false; |
| }; |