Use historical average of test times to schedule tests.

This commit is contained in:
Zach Mullen 2010-02-25 16:23:49 -05:00 committed by Brad King
parent 55f012989c
commit b4d27dc041
6 changed files with 115 additions and 23 deletions

View File

@ -76,6 +76,7 @@ void cmCTestMultiProcessHandler::RunTests()
{ {
} }
this->MarkFinished(); this->MarkFinished();
this->UpdateCostData();
} }
//--------------------------------------------------------- //---------------------------------------------------------
@ -272,8 +273,7 @@ bool cmCTestMultiProcessHandler::CheckOutput()
this->TestRunningMap[test] = false; this->TestRunningMap[test] = false;
this->RunningTests.erase(p); this->RunningTests.erase(p);
this->WriteCheckpoint(test); this->WriteCheckpoint(test);
this->WriteCostData(test, static_cast<float>(
p->GetTestResults().ExecutionTime));
this->RunningCount -= GetProcessorsUsed(test); this->RunningCount -= GetProcessorsUsed(test);
delete p; delete p;
} }
@ -281,24 +281,88 @@ bool cmCTestMultiProcessHandler::CheckOutput()
} }
//--------------------------------------------------------- //---------------------------------------------------------
void cmCTestMultiProcessHandler::ReadCostData() void cmCTestMultiProcessHandler::UpdateCostData()
{ {
std::string fname = this->CTest->GetBinaryDir() std::string fname = this->CTest->GetBinaryDir()
+ "/Testing/Temporary/CTestCostData.txt"; + "/Testing/Temporary/CTestCostData.txt";
std::string tmpout = fname + ".tmp";
std::fstream fout;
fout.open(tmpout.c_str(), std::ios::out);
if(cmSystemTools::FileExists(fname.c_str(), true) PropertiesMap temp = this->Properties;
&& this->ParallelLevel > 1)
{ if(cmSystemTools::FileExists(fname.c_str()))
{
std::ifstream fin; std::ifstream fin;
fin.open(fname.c_str()); fin.open(fname.c_str());
std::string line; std::string line;
while(std::getline(fin, line)) while(std::getline(fin, line))
{ {
std::vector<cmsys::String> parts = std::vector<cmsys::String> parts =
cmSystemTools::SplitString(line.c_str(), ' '); cmSystemTools::SplitString(line.c_str(), ' ');
//Format: <name> <previous_runs> <avg_cost>
if(parts.size() < 3) break;
int index = atoi(parts[0].c_str()); std::string name = parts[0];
float cost = static_cast<float>(atof(parts[1].c_str())); int prev = atoi(parts[1].c_str());
float cost = static_cast<float>(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<cmsys::String> parts =
cmSystemTools::SplitString(line.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<float>(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) if(this->Properties[index] && this->Properties[index]->Cost == 0)
{ {
this->Properties[index]->Cost = cost; this->Properties[index]->Cost = cost;
@ -306,7 +370,22 @@ void cmCTestMultiProcessHandler::ReadCostData()
} }
fin.close(); fin.close();
} }
cmSystemTools::RemoveFile(fname.c_str()); }
//---------------------------------------------------------
int cmCTestMultiProcessHandler::SearchByName(std::string name)
{
int index = -1;
for(PropertiesMap::iterator i = this->Properties.begin();
i != this->Properties.end(); ++i)
{
if(i->second->Name == name)
{
index = i->first;
}
}
return index;
} }
//--------------------------------------------------------- //---------------------------------------------------------
@ -319,24 +398,13 @@ void cmCTestMultiProcessHandler::CreateTestCostList()
} }
} }
//---------------------------------------------------------
void cmCTestMultiProcessHandler::WriteCostData(int index, float cost)
{
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();
}
//--------------------------------------------------------- //---------------------------------------------------------
void cmCTestMultiProcessHandler::WriteCheckpoint(int index) void cmCTestMultiProcessHandler::WriteCheckpoint(int index)
{ {
std::string fname = this->CTest->GetBinaryDir() std::string fname = this->CTest->GetBinaryDir()
+ "/Testing/Temporary/CTestCheckpoint.txt"; + "/Testing/Temporary/CTestCheckpoint.txt";
std::fstream fout; 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 << index << "\n";
fout.close(); fout.close();
} }

View File

@ -64,8 +64,12 @@ protected:
bool StartTest(int test); bool StartTest(int test);
// Mark the checkpoint for the given test // Mark the checkpoint for the given test
void WriteCheckpoint(int index); void WriteCheckpoint(int index);
void WriteCostData(int index, float cost);
void UpdateCostData();
void ReadCostData(); void ReadCostData();
// Return index of a test based on its name
int SearchByName(std::string name);
void CreateTestCostList(); void CreateTestCostList();
// Removes the checkpoint file // Removes the checkpoint file
void MarkFinished(); void MarkFinished();

View File

@ -334,6 +334,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
this->TestResult.CompletionStatus = "Completed"; this->TestResult.CompletionStatus = "Completed";
this->TestResult.ExecutionTime = this->TestProcess->GetTotalTime(); this->TestResult.ExecutionTime = this->TestProcess->GetTotalTime();
this->MemCheckPostProcess(); this->MemCheckPostProcess();
this->ComputeWeightedCost();
} }
// Always push the current TestResult onto the // Always push the current TestResult onto the
// TestHandler vector // TestHandler vector
@ -342,7 +343,21 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
return passed; 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() void cmCTestRunTest::MemCheckPostProcess()
{ {
if(!this->TestHandler->MemCheck) if(!this->TestHandler->MemCheck)
@ -430,6 +445,7 @@ bool cmCTestRunTest::StartTest(size_t total)
&this->TestProperties->Environment); &this->TestProperties->Environment);
} }
//----------------------------------------------------------------------
void cmCTestRunTest::ComputeArguments() void cmCTestRunTest::ComputeArguments()
{ {
std::vector<std::string>::const_iterator j = std::vector<std::string>::const_iterator j =

View File

@ -54,6 +54,8 @@ public:
bool EndTest(size_t completed, size_t total, bool started); bool EndTest(size_t completed, size_t total, bool started);
//Called by ctest -N to log the command string //Called by ctest -N to log the command string
void ComputeArguments(); void ComputeArguments();
void ComputeWeightedCost();
private: private:
void DartProcessing(); void DartProcessing();
void ExeNotFound(std::string exe); void ExeNotFound(std::string exe);

View File

@ -2274,6 +2274,7 @@ bool cmCTestTestHandler::AddTest(const std::vector<std::string>& args)
test.Timeout = 0; test.Timeout = 0;
test.Cost = 0; test.Cost = 0;
test.Processors = 1; test.Processors = 1;
test.PreviousRuns = 0;
if (this->UseIncludeRegExpFlag && if (this->UseIncludeRegExpFlag &&
!this->IncludeTestsRegularExpression.find(testname.c_str())) !this->IncludeTestsRegularExpression.find(testname.c_str()))
{ {

View File

@ -96,6 +96,7 @@ public:
bool IsInBasedOnREOptions; bool IsInBasedOnREOptions;
bool WillFail; bool WillFail;
float Cost; float Cost;
int PreviousRuns;
bool RunSerial; bool RunSerial;
double Timeout; double Timeout;
int Index; int Index;