mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-21 22:20:48 -06:00
The `ctest --test-load` option is implemented in `StartNextTests` by not starting any tests when the load is too high and instead sleeping and then returning. Prior to commit v3.11.0-rc1~117^2 (CTest: Re-implement test process handling using libuv, 2017-12-10) our outer loop in `RunTests` would immediately call `StartNextTests` again. However, now the `uv_run` loop may simply terminate if there are no tests running because no events are left pending. Fix this by converting the sleep in `StartNextTests` into a libuv timer that it starts instead. This avoids leaving `uv_run` with no pending events. In the case that there are other running tests this also allows CTest to detect when they finish even if it during the wait period where we previously slept. This regression was not caught by the test suite because it only verified that we do not start new tests when the load was too high and not that we proceed to start tests when the load drops. Revise the test suite to cover both. Fixes: #18338
152 lines
4.0 KiB
C++
152 lines
4.0 KiB
C++
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
file Copyright.txt or https://cmake.org/licensing for details. */
|
|
#ifndef cmCTestMultiProcessHandler_h
|
|
#define cmCTestMultiProcessHandler_h
|
|
|
|
#include "cmConfigure.h" // IWYU pragma: keep
|
|
|
|
#include "cmCTestTestHandler.h"
|
|
#include <map>
|
|
#include <set>
|
|
#include <stddef.h>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "cmUVHandlePtr.h"
|
|
#include "cm_uv.h"
|
|
|
|
class cmCTest;
|
|
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 TestMap : public std::map<int, TestSet>
|
|
{
|
|
};
|
|
struct TestList : public std::vector<int>
|
|
{
|
|
};
|
|
struct PropertiesMap
|
|
: public std::map<int, cmCTestTestHandler::cmCTestTestProperties*>
|
|
{
|
|
};
|
|
|
|
cmCTestMultiProcessHandler();
|
|
virtual ~cmCTestMultiProcessHandler();
|
|
// Set the tests
|
|
void SetTests(TestMap& tests, PropertiesMap& properties);
|
|
// Set the max number of tests that can be run at the same time.
|
|
void SetParallelLevel(size_t);
|
|
void SetTestLoad(unsigned long load);
|
|
virtual void RunTests();
|
|
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;
|
|
}
|
|
|
|
void SetCTest(cmCTest* ctest) { this->CTest = ctest; }
|
|
|
|
void SetTestHandler(cmCTestTestHandler* handler)
|
|
{
|
|
this->TestHandler = handler;
|
|
}
|
|
|
|
cmCTestTestHandler* GetTestHandler() { return this->TestHandler; }
|
|
|
|
void SetQuiet(bool b) { this->Quiet = b; }
|
|
|
|
protected:
|
|
// Start the next test or tests as many as are allowed by
|
|
// ParallelLevel
|
|
void StartNextTests();
|
|
bool StartTestProcess(int test);
|
|
bool 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 EraseTest(int index);
|
|
void FinishTestProcess(cmCTestRunTest* runner, bool started);
|
|
|
|
static void OnTestLoadRetryCB(uv_timer_t* timer);
|
|
|
|
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);
|
|
|
|
void LockResources(int index);
|
|
void UnlockResources(int index);
|
|
// map from test number to set of depend tests
|
|
TestMap Tests;
|
|
TestList SortedTests;
|
|
// Total number of tests we'll be running
|
|
size_t Total;
|
|
// Number of tests that are complete
|
|
size_t Completed;
|
|
size_t RunningCount;
|
|
std::set<size_t> ProcessorsAvailable;
|
|
size_t HaveAffinity;
|
|
bool StopTimePassed;
|
|
// list of test properties (indices concurrent to the test map)
|
|
PropertiesMap Properties;
|
|
std::map<int, bool> TestRunningMap;
|
|
std::map<int, bool> TestFinishMap;
|
|
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> LockedResources;
|
|
std::vector<cmCTestTestHandler::cmCTestTestResult>* TestResults;
|
|
size_t ParallelLevel; // max number of process that can be run at once
|
|
unsigned long TestLoad;
|
|
unsigned long FakeLoadForTesting;
|
|
uv_loop_t Loop;
|
|
cm::uv_timer_ptr TestLoadRetryTimer;
|
|
cmCTestTestHandler* TestHandler;
|
|
cmCTest* CTest;
|
|
bool HasCycles;
|
|
bool Quiet;
|
|
bool SerialTestRunning;
|
|
};
|
|
|
|
#endif
|