diff options
Diffstat (limited to 'Source/CTest/cmCTestMultiProcessHandler.cxx')
-rw-r--r-- | Source/CTest/cmCTestMultiProcessHandler.cxx | 151 |
1 files changed, 81 insertions, 70 deletions
diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index 8a69780..d50eaaa 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -18,11 +18,29 @@ #include <stack> #include <float.h> +class TestComparator +{ +public: + TestComparator(cmCTestMultiProcessHandler* handler) : Handler(handler) {} + ~TestComparator() {} + + // Sorts tests in descending order of cost + bool operator() (int index1, int index2) const + { + return Handler->Properties[index1]->Cost > + Handler->Properties[index2]->Cost; + } + +private: + cmCTestMultiProcessHandler* Handler; +}; + cmCTestMultiProcessHandler::cmCTestMultiProcessHandler() { this->ParallelLevel = 1; this->Completed = 0; this->RunningCount = 0; + this->StopTimePassed = false; } cmCTestMultiProcessHandler::~cmCTestMultiProcessHandler() @@ -69,6 +87,10 @@ void cmCTestMultiProcessHandler::RunTests() this->StartNextTests(); while(this->Tests.size() != 0) { + if(this->StopTimePassed) + { + return; + } this->CheckOutput(); this->StartNextTests(); } @@ -87,6 +109,7 @@ void cmCTestMultiProcessHandler::StartTestProcess(int test) this->TestRunningMap[test] = true; // mark the test as running // now remove the test itself this->EraseTest(test); + this->RunningCount += GetProcessorsUsed(test); cmCTestRunTest* testRun = new cmCTestRunTest(this->TestHandler); testRun->SetIndex(test); @@ -102,6 +125,12 @@ void cmCTestMultiProcessHandler::StartTestProcess(int test) { this->RunningTests.insert(testRun); } + else if(testRun->IsStopTimePassed()) + { + this->StopTimePassed = true; + delete testRun; + return; + } else { this->UnlockResources(test); @@ -142,15 +171,8 @@ void cmCTestMultiProcessHandler::UnlockResources(int index) void cmCTestMultiProcessHandler::EraseTest(int test) { this->Tests.erase(test); - for(TestCostMap::iterator i = this->TestCosts.begin(); - i != this->TestCosts.end(); ++i) - { - if(i->second.find(test) != i->second.end()) - { - i->second.erase(test); - return; - } - } + this->SortedTests.erase( + std::find(this->SortedTests.begin(), this->SortedTests.end(), test)); } //--------------------------------------------------------- @@ -232,38 +254,36 @@ void cmCTestMultiProcessHandler::StartNextTests() return; } - for(TestCostMap::reverse_iterator i = this->TestCosts.rbegin(); - i != this->TestCosts.rend(); ++i) + TestList copy = this->SortedTests; + for(TestList::iterator test = copy.begin(); test != copy.end(); ++test) { - TestSet tests = i->second; //copy the test set - for(TestSet::iterator test = tests.begin(); - test != tests.end(); ++test) + //in case this test has already been started due to dependency + if(this->TestRunningMap[*test] || this->TestFinishMap[*test]) { - //in case this test has already been started due to dependency - if(this->TestRunningMap[*test] || this->TestFinishMap[*test]) - { - continue; - } - size_t processors = GetProcessorsUsed(*test); - if(processors > numToStart) - { - return; - } - if(this->StartTest(*test)) - { - numToStart -= processors; - this->RunningCount += processors; - } - else - { - cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl - << "Test did not start waiting on depends to finish: " - << *test << "\n"); - } - if(numToStart == 0) + continue; + } + size_t processors = GetProcessorsUsed(*test); + if(processors > numToStart) + { + return; + } + if(this->StartTest(*test)) + { + if(this->StopTimePassed) { return; } + numToStart -= processors; + } + else + { + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl + << "Test did not start waiting on depends to finish: " + << *test << "\n"); + } + if(numToStart == 0) + { + return; } } } @@ -453,26 +473,22 @@ void cmCTestMultiProcessHandler::CreateTestCostList() for(TestMap::iterator i = this->Tests.begin(); i != this->Tests.end(); ++i) { - //We only want to schedule them by cost in a parallel situation - if(this->ParallelLevel > 1) - { - std::string name = this->Properties[i->first]->Name; - if(std::find(this->LastTestsFailed.begin(), this->LastTestsFailed.end(), - name) != this->LastTestsFailed.end()) - { - this->TestCosts[FLT_MAX].insert(i->first); - } - else - { - this->TestCosts[this->Properties[i->first]->Cost].insert(i->first); - } - } - else //we ignore their cost + SortedTests.push_back(i->first); + + //If the test failed last time, it should be run first, so max the cost + if(std::find(this->LastTestsFailed.begin(), + this->LastTestsFailed.end(), + this->Properties[i->first]->Name) + != this->LastTestsFailed.end()) { - this->TestCosts[this->Tests.size() - - this->Properties[i->first]->Index].insert(i->first); + this->Properties[i->first]->Cost = FLT_MAX; } } + if(this->ParallelLevel > 1) + { + TestComparator comp(this); + std::sort(SortedTests.begin(), SortedTests.end(), comp); + } } //--------------------------------------------------------- @@ -595,7 +611,7 @@ int cmCTestMultiProcessHandler::FindMaxIndex() //Returns true if no cycles exist in the dependency graph bool cmCTestMultiProcessHandler::CheckCycles() { - cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Checking test dependency graph..." << std::endl); for(TestMap::iterator it = this->Tests.begin(); it != this->Tests.end(); ++it) @@ -603,34 +619,29 @@ bool cmCTestMultiProcessHandler::CheckCycles() //DFS from each element to itself std::stack<int> s; std::vector<int> visited; + s.push(it->first); - visited.push_back(it->first); while(!s.empty()) { int test = s.top(); s.pop(); - + for(TestSet::iterator d = this->Tests[test].begin(); d != this->Tests[test].end(); ++d) { - s.push(*d); - for(std::vector<int>::iterator v = visited.begin(); - v != visited.end(); ++v) + if(std::find(visited.begin(), visited.end(), *d) != visited.end()) { - if(*v == *d) - { - //cycle exists - cmCTestLog(this->CTest, ERROR_MESSAGE, "Error: a cycle exists in " - "the test dependency graph for the test \"" - << this->Properties[*d]->Name << "\"." << std::endl - << "Please fix the cycle and run ctest again." << std::endl); - return false; - } + //cycle exists + cmCTestLog(this->CTest, ERROR_MESSAGE, "Error: a cycle exists in " + "the test dependency graph for the test \"" + << this->Properties[it->first]->Name << "\"." << std::endl + << "Please fix the cycle and run ctest again." << std::endl); + return false; } - visited.push_back(*d); + s.push(*d); } - visited.pop_back(); + visited.push_back(test); } } return true; |