소스 검색

Use historical average of test times to schedule tests.

Zach Mullen 16 년 전
부모
커밋
b4d27dc041

+ 89 - 21
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<float>(
-      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<cmsys::String> parts = 
         cmSystemTools::SplitString(line.c_str(), ' ');
+      //Format: <name> <previous_runs> <avg_cost>
+      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)
+        {
+        // 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(), ' ');
 
-      int index = atoi(parts[0].c_str());
-      float cost = static_cast<float>(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<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)
         {
         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();
 }

+ 5 - 1
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();

+ 17 - 1
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<std::string>::const_iterator j = 

+ 2 - 0
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);

+ 1 - 0
Source/CTest/cmCTestTestHandler.cxx

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

+ 1 - 0
Source/CTest/cmCTestTestHandler.h

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