|
|
|
/* 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;
|
|
|
|
};
|