cmCTestRunTest: Consolidate test timeout selection logic

Test timeout selection was previously spread out over several locations.
Consolidate it in a single place to make it easier to follow.
This commit is contained in:
Brad King
2023-05-04 16:55:13 -04:00
parent 426e38cc10
commit 0a5aeaf302
5 changed files with 74 additions and 62 deletions
+3 -2
View File
@@ -19,6 +19,7 @@
#include <vector> #include <vector>
#include <cm/memory> #include <cm/memory>
#include <cm/optional>
#include <cmext/algorithm> #include <cmext/algorithm>
#include <cm3p/json/value.h> #include <cm3p/json/value.h>
@@ -1095,9 +1096,9 @@ static Json::Value DumpCTestProperties(
properties.append( properties.append(
DumpCTestProperty("SKIP_RETURN_CODE", testProperties.SkipReturnCode)); DumpCTestProperty("SKIP_RETURN_CODE", testProperties.SkipReturnCode));
} }
if (testProperties.ExplicitTimeout) { if (testProperties.Timeout) {
properties.append( properties.append(
DumpCTestProperty("TIMEOUT", testProperties.Timeout.count())); DumpCTestProperty("TIMEOUT", testProperties.Timeout->count()));
} }
if (!testProperties.TimeoutRegularExpressions.empty()) { if (!testProperties.TimeoutRegularExpressions.empty()) {
properties.append(DumpCTestProperty( properties.append(DumpCTestProperty(
+67 -50
View File
@@ -14,12 +14,14 @@
#include <utility> #include <utility>
#include <cm/memory> #include <cm/memory>
#include <cm/optional>
#include "cmsys/RegularExpression.hxx" #include "cmsys/RegularExpression.hxx"
#include "cmCTest.h" #include "cmCTest.h"
#include "cmCTestMemCheckHandler.h" #include "cmCTestMemCheckHandler.h"
#include "cmCTestMultiProcessHandler.h" #include "cmCTestMultiProcessHandler.h"
#include "cmDuration.h"
#include "cmProcess.h" #include "cmProcess.h"
#include "cmStringAlgorithms.h" #include "cmStringAlgorithms.h"
#include "cmSystemTools.h" #include "cmSystemTools.h"
@@ -618,25 +620,7 @@ bool cmCTestRunTest::StartTest(size_t completed, size_t total)
} }
this->StartTime = this->CTest->CurrentTime(); this->StartTime = this->CTest->CurrentTime();
auto timeout = this->TestProperties->Timeout; return this->ForkProcess();
this->TimeoutIsForStopTime = false;
std::chrono::system_clock::time_point stop_time = this->CTest->GetStopTime();
if (stop_time != std::chrono::system_clock::time_point()) {
std::chrono::duration<double> stop_timeout =
(stop_time - std::chrono::system_clock::now()) % std::chrono::hours(24);
if (stop_timeout <= std::chrono::duration<double>::zero()) {
stop_timeout = std::chrono::duration<double>::zero();
}
if (timeout == std::chrono::duration<double>::zero() ||
stop_timeout < timeout) {
this->TimeoutIsForStopTime = true;
timeout = stop_timeout;
}
}
return this->ForkProcess(timeout);
} }
void cmCTestRunTest::ComputeArguments() void cmCTestRunTest::ComputeArguments()
@@ -734,46 +718,79 @@ void cmCTestRunTest::ParseOutputForMeasurements()
} }
} }
bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut) bool cmCTestRunTest::ForkProcess()
{ {
this->TestProcess->SetId(this->Index); this->TestProcess->SetId(this->Index);
this->TestProcess->SetWorkingDirectory(this->TestProperties->Directory); this->TestProcess->SetWorkingDirectory(this->TestProperties->Directory);
this->TestProcess->SetCommand(this->ActualCommand); this->TestProcess->SetCommand(this->ActualCommand);
this->TestProcess->SetCommandArguments(this->Arguments); this->TestProcess->SetCommandArguments(this->Arguments);
// determine how much time we have cm::optional<cmDuration> timeout;
cmDuration timeout = this->CTest->GetRemainingTimeAllowed();
if (timeout != cmCTest::MaxDuration()) { // Check TIMEOUT test property.
timeout -= std::chrono::minutes(2); if (this->TestProperties->Timeout &&
*this->TestProperties->Timeout >= cmDuration::zero()) {
timeout = this->TestProperties->Timeout;
} }
if (this->CTest->GetTimeOut() > cmDuration::zero() &&
this->CTest->GetTimeOut() < timeout) {
timeout = this->CTest->GetTimeOut();
}
if (testTimeOut > cmDuration::zero() &&
testTimeOut < this->CTest->GetRemainingTimeAllowed()) {
timeout = testTimeOut;
}
// always have at least 1 second if we got to here
if (timeout <= cmDuration::zero()) {
timeout = std::chrono::seconds(1);
}
// handle timeout explicitly set to 0
if (testTimeOut == cmDuration::zero() &&
this->TestProperties->ExplicitTimeout) {
timeout = cmDuration::zero();
}
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
this->Index << ": "
<< "Test timeout computed to be: "
<< cmDurationTo<unsigned int>(timeout)
<< "\n",
this->TestHandler->GetQuiet());
// An explicit TIMEOUT=0 test property means "no timeout". // An explicit TIMEOUT=0 test property means "no timeout".
if (timeout != cmDuration::zero() || if (timeout && *timeout == std::chrono::duration<double>::zero()) {
!this->TestProperties->ExplicitTimeout) { timeout = cm::nullopt;
this->TestProcess->SetTimeout(timeout); } else {
// Check --timeout.
if (!timeout && this->CTest->GetGlobalTimeout() > cmDuration::zero()) {
timeout = this->CTest->GetGlobalTimeout();
}
// Check CTEST_TEST_TIMEOUT.
cmDuration ctestTestTimeout = this->CTest->GetTimeOut();
if (ctestTestTimeout > cmDuration::zero() &&
(!timeout || ctestTestTimeout < *timeout)) {
timeout = ctestTestTimeout;
}
}
// Check CTEST_TIME_LIMIT.
cmDuration timeRemaining = this->CTest->GetRemainingTimeAllowed();
if (timeRemaining != cmCTest::MaxDuration()) {
// This two minute buffer is historical.
timeRemaining -= std::chrono::minutes(2);
}
// Check --stop-time.
std::chrono::system_clock::time_point stop_time = this->CTest->GetStopTime();
if (stop_time != std::chrono::system_clock::time_point()) {
cmDuration timeUntilStop =
(stop_time - std::chrono::system_clock::now()) % std::chrono::hours(24);
if (timeUntilStop < timeRemaining) {
timeRemaining = timeUntilStop;
}
}
// Enforce remaining time even over explicit TIMEOUT=0.
if (timeRemaining <= cmDuration::zero()) {
timeRemaining = cmDuration::zero();
}
if (!timeout || timeRemaining < *timeout) {
this->TimeoutIsForStopTime = true;
timeout = timeRemaining;
}
if (timeout) {
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
this->Index << ": "
<< "Test timeout computed to be: "
<< cmDurationTo<unsigned int>(*timeout)
<< "\n",
this->TestHandler->GetQuiet());
this->TestProcess->SetTimeout(*timeout);
} else {
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
this->Index
<< ": "
<< "Test timeout suppressed by TIMEOUT property.\n",
this->TestHandler->GetQuiet());
} }
cmSystemTools::SaveRestoreEnvironment sre; cmSystemTools::SaveRestoreEnvironment sre;
+1 -2
View File
@@ -14,7 +14,6 @@
#include "cmCTest.h" #include "cmCTest.h"
#include "cmCTestMultiProcessHandler.h" #include "cmCTestMultiProcessHandler.h"
#include "cmCTestTestHandler.h" #include "cmCTestTestHandler.h"
#include "cmDuration.h"
#include "cmProcess.h" #include "cmProcess.h"
/** \class cmRunTest /** \class cmRunTest
@@ -110,7 +109,7 @@ private:
bool NeedsToRepeat(); bool NeedsToRepeat();
void ParseOutputForMeasurements(); void ParseOutputForMeasurements();
void ExeNotFound(std::string exe); void ExeNotFound(std::string exe);
bool ForkProcess(cmDuration testTimeOut); bool ForkProcess();
void WriteLogOutputTop(size_t completed, size_t total); void WriteLogOutputTop(size_t completed, size_t total);
// Run post processing of the process output for MemCheck // Run post processing of the process output for MemCheck
void MemCheckPostProcess(); void MemCheckPostProcess();
-6
View File
@@ -1379,11 +1379,6 @@ bool cmCTestTestHandler::ProcessDirectory(std::vector<std::string>& passed,
p.Cost = static_cast<float>(rand()); p.Cost = static_cast<float>(rand());
} }
if (p.Timeout == cmDuration::zero() && !p.ExplicitTimeout &&
this->CTest->GetGlobalTimeout() != cmDuration::zero()) {
p.Timeout = this->CTest->GetGlobalTimeout();
}
if (!p.Depends.empty()) { if (!p.Depends.empty()) {
for (std::string const& i : p.Depends) { for (std::string const& i : p.Depends) {
for (cmCTestTestProperties const& it2 : this->TestList) { for (cmCTestTestProperties const& it2 : this->TestList) {
@@ -2252,7 +2247,6 @@ bool cmCTestTestHandler::SetTestsProperties(
rt.FixturesRequired.insert(lval.begin(), lval.end()); rt.FixturesRequired.insert(lval.begin(), lval.end());
} else if (key == "TIMEOUT"_s) { } else if (key == "TIMEOUT"_s) {
rt.Timeout = cmDuration(atof(val.c_str())); rt.Timeout = cmDuration(atof(val.c_str()));
rt.ExplicitTimeout = true;
} else if (key == "COST"_s) { } else if (key == "COST"_s) {
rt.Cost = static_cast<float>(atof(val.c_str())); rt.Cost = static_cast<float>(atof(val.c_str()));
} else if (key == "REQUIRED_FILES"_s) { } else if (key == "REQUIRED_FILES"_s) {
+3 -2
View File
@@ -14,6 +14,8 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <cm/optional>
#include "cmsys/RegularExpression.hxx" #include "cmsys/RegularExpression.hxx"
#include "cmCTest.h" #include "cmCTest.h"
@@ -145,8 +147,7 @@ public:
float Cost = 0; float Cost = 0;
int PreviousRuns = 0; int PreviousRuns = 0;
bool RunSerial = false; bool RunSerial = false;
cmDuration Timeout = cmDuration::zero(); cm::optional<cmDuration> Timeout;
bool ExplicitTimeout = false;
cmDuration AlternateTimeout; cmDuration AlternateTimeout;
int Index = 0; int Index = 0;
// Requested number of process slots // Requested number of process slots