From b4d27dc041c9164d6f3ad39e192f4b7d116ca3b3 Mon Sep 17 00:00:00 2001 From: Zach Mullen Date: Thu, 25 Feb 2010 16:23:49 -0500 Subject: Use historical average of test times to schedule tests. --- Source/CTest/cmCTestMultiProcessHandler.cxx | 110 ++++++++++++++++++++++------ Source/CTest/cmCTestMultiProcessHandler.h | 6 +- Source/CTest/cmCTestRunTest.cxx | 18 ++++- Source/CTest/cmCTestRunTest.h | 2 + Source/CTest/cmCTestTestHandler.cxx | 1 + Source/CTest/cmCTestTestHandler.h | 1 + 6 files changed, 115 insertions(+), 23 deletions(-) diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index b6226a3..02974a2 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -76,6 +76,7 @@ void cmCTestMultiProcessHandler::RunTests() { } this->MarkFinished(); + this->UpdateCostData(); } //--------------------------------------------------------- @@ -272,8 +273,7 @@ bool cmCTestMultiProcessHandler::CheckOutput() this->TestRunningMap[test] = false; this->RunningTests.erase(p); this->WriteCheckpoint(test); - this->WriteCostData(test, static_cast( - p->GetTestResults().ExecutionTime)); + this->RunningCount -= GetProcessorsUsed(test); delete p; } @@ -281,24 +281,88 @@ bool cmCTestMultiProcessHandler::CheckOutput() } //--------------------------------------------------------- -void cmCTestMultiProcessHandler::ReadCostData() +void cmCTestMultiProcessHandler::UpdateCostData() { std::string fname = this->CTest->GetBinaryDir() + "/Testing/Temporary/CTestCostData.txt"; + std::string tmpout = fname + ".tmp"; + std::fstream fout; + fout.open(tmpout.c_str(), std::ios::out); + + PropertiesMap temp = this->Properties; - if(cmSystemTools::FileExists(fname.c_str(), true) - && this->ParallelLevel > 1) - { + if(cmSystemTools::FileExists(fname.c_str())) + { std::ifstream fin; fin.open(fname.c_str()); + std::string line; while(std::getline(fin, line)) { std::vector parts = cmSystemTools::SplitString(line.c_str(), ' '); + //Format: + if(parts.size() < 3) break; + + std::string name = parts[0]; + int prev = atoi(parts[1].c_str()); + float cost = static_cast(atof(parts[2].c_str())); + + int index = this->SearchByName(name); + if(index == -1) + { + // This test is not in memory. We just rewrite the entry + fout << name << " " << prev << " " << cost << "\n"; + } + else + { + // Update with our new average cost + fout << name << " " << this->Properties[index]->PreviousRuns << " " + << this->Properties[index]->Cost << "\n"; + temp.erase(index); + } + } + fin.close(); + cmSystemTools::RemoveFile(fname.c_str()); + } + + // Add all tests not previously listed in the file + for(PropertiesMap::iterator i = temp.begin(); i != temp.end(); ++i) + { + fout << i->second->Name << " " << i->second->PreviousRuns << " " + << i->second->Cost << "\n"; + } + fout.close(); + cmSystemTools::RenameFile(tmpout.c_str(), fname.c_str()); +} + +//--------------------------------------------------------- +void cmCTestMultiProcessHandler::ReadCostData() +{ + //TODO variable location of the cost data file + std::string fname = this->CTest->GetBinaryDir() + + "/Testing/Temporary/CTestCostData.txt"; + if(cmSystemTools::FileExists(fname.c_str(), true)) + { + std::ifstream fin; + fin.open(fname.c_str()); + std::string line; + while(std::getline(fin, line)) + { + std::vector parts = + cmSystemTools::SplitString(line.c_str(), ' '); - int index = atoi(parts[0].c_str()); - float cost = static_cast(atof(parts[1].c_str())); + // Probably an older version of the file, will be fixed next run + if(parts.size() < 3) break; + + std::string name = parts[0]; + int prev = atoi(parts[1].c_str()); + float cost = static_cast(atof(parts[2].c_str())); + + int index = this->SearchByName(name); + if(index == -1) continue; + + this->Properties[index]->PreviousRuns = prev; if(this->Properties[index] && this->Properties[index]->Cost == 0) { this->Properties[index]->Cost = cost; @@ -306,28 +370,32 @@ void cmCTestMultiProcessHandler::ReadCostData() } fin.close(); } - cmSystemTools::RemoveFile(fname.c_str()); } //--------------------------------------------------------- -void cmCTestMultiProcessHandler::CreateTestCostList() +int cmCTestMultiProcessHandler::SearchByName(std::string name) { - for(TestMap::iterator i = this->Tests.begin(); - i != this->Tests.end(); ++i) + int index = -1; + + for(PropertiesMap::iterator i = this->Properties.begin(); + i != this->Properties.end(); ++i) { - this->TestCosts[this->Properties[i->first]->Cost].insert(i->first); + if(i->second->Name == name) + { + index = i->first; + } } + return index; } //--------------------------------------------------------- -void cmCTestMultiProcessHandler::WriteCostData(int index, float cost) +void cmCTestMultiProcessHandler::CreateTestCostList() { - std::string fname = this->CTest->GetBinaryDir() - + "/Testing/Temporary/CTestCostData.txt"; - std::fstream fout; - fout.open(fname.c_str(), std::ios::out | std::ios::app); - fout << index << " " << cost << "\n"; - fout.close(); + for(TestMap::iterator i = this->Tests.begin(); + i != this->Tests.end(); ++i) + { + this->TestCosts[this->Properties[i->first]->Cost].insert(i->first); + } } //--------------------------------------------------------- @@ -336,7 +404,7 @@ void cmCTestMultiProcessHandler::WriteCheckpoint(int index) std::string fname = this->CTest->GetBinaryDir() + "/Testing/Temporary/CTestCheckpoint.txt"; std::fstream fout; - fout.open(fname.c_str(), std::ios::app); + fout.open(fname.c_str(), std::ios::app | std::ios::out); fout << index << "\n"; fout.close(); } diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h index 16591b0..6136103 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.h +++ b/Source/CTest/cmCTestMultiProcessHandler.h @@ -64,8 +64,12 @@ protected: bool StartTest(int test); // Mark the checkpoint for the given test void WriteCheckpoint(int index); - void WriteCostData(int index, float cost); + + void UpdateCostData(); void ReadCostData(); + // Return index of a test based on its name + int SearchByName(std::string name); + void CreateTestCostList(); // Removes the checkpoint file void MarkFinished(); diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index 3e9156c..fa9794a 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -334,6 +334,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) this->TestResult.CompletionStatus = "Completed"; this->TestResult.ExecutionTime = this->TestProcess->GetTotalTime(); this->MemCheckPostProcess(); + this->ComputeWeightedCost(); } // Always push the current TestResult onto the // TestHandler vector @@ -342,7 +343,21 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) return passed; } -//-------------------------------------------------------------- +//---------------------------------------------------------------------- +void cmCTestRunTest::ComputeWeightedCost() +{ + int prev = this->TestProperties->PreviousRuns; + float avgcost = this->TestProperties->Cost; + double current = this->TestResult.ExecutionTime; + + if(this->TestResult.Status == cmCTestTestHandler::COMPLETED) + { + this->TestProperties->Cost = ((prev * avgcost) + current) / (prev + 1); + this->TestProperties->PreviousRuns++; + } +} + +//---------------------------------------------------------------------- void cmCTestRunTest::MemCheckPostProcess() { if(!this->TestHandler->MemCheck) @@ -430,6 +445,7 @@ bool cmCTestRunTest::StartTest(size_t total) &this->TestProperties->Environment); } +//---------------------------------------------------------------------- void cmCTestRunTest::ComputeArguments() { std::vector::const_iterator j = diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h index 1084643..1e4c1cc 100644 --- a/Source/CTest/cmCTestRunTest.h +++ b/Source/CTest/cmCTestRunTest.h @@ -54,6 +54,8 @@ public: bool EndTest(size_t completed, size_t total, bool started); //Called by ctest -N to log the command string void ComputeArguments(); + + void ComputeWeightedCost(); private: void DartProcessing(); void ExeNotFound(std::string exe); diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index 8af2815..e36074f 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -2274,6 +2274,7 @@ bool cmCTestTestHandler::AddTest(const std::vector& args) test.Timeout = 0; test.Cost = 0; test.Processors = 1; + test.PreviousRuns = 0; if (this->UseIncludeRegExpFlag && !this->IncludeTestsRegularExpression.find(testname.c_str())) { diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index 1513410..05bdf86 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -96,6 +96,7 @@ public: bool IsInBasedOnREOptions; bool WillFail; float Cost; + int PreviousRuns; bool RunSerial; double Timeout; int Index; -- cgit v0.12