[Cmake-commits] [cmake-commits] hoffman committed cmCTestGenericHandler.cxx 1.16 1.17 cmCTestMultiProcessHandler.cxx NONE 1.1 cmCTestMultiProcessHandler.h NONE 1.1 cmCTestTestHandler.cxx 1.71 1.72 cmCTestTestHandler.h 1.27 1.28

cmake-commits at cmake.org cmake-commits at cmake.org
Thu Jul 3 09:31:35 EDT 2008


Update of /cvsroot/CMake/CMake/Source/CTest
In directory public:/mounts/ram/cvs-serv18162/Source/CTest

Modified Files:
	cmCTestGenericHandler.cxx cmCTestTestHandler.cxx 
	cmCTestTestHandler.h 
Added Files:
	cmCTestMultiProcessHandler.cxx cmCTestMultiProcessHandler.h 
Log Message:
ENH: add initial ctest -j feature


--- NEW FILE: cmCTestMultiProcessHandler.cxx ---
/*=========================================================================

  Program:   CMake - Cross-Platform Makefile Generator
  Module:    $RCSfile: cmCTestMultiProcessHandler.cxx,v $
  Language:  C++
  Date:      $Date: 2008-07-03 13:31:30 $
  Version:   $Revision: 1.1 $

  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "cmCTestMultiProcessHandler.h"
#include "cmProcess.h"
#include "cmStandardIncludes.h"
#include "cmCTest.h"


cmCTestMultiProcessHandler::cmCTestMultiProcessHandler()
{
  this->ParallelLevel = 1;
  this->ProcessId = 0;
}
  // Set the tests
void 
cmCTestMultiProcessHandler::SetTests(std::map<int, std::set<int> >& tests,
                                          std::map<int,cmStdString>& testNames)
{
  // set test run map to false for all
  for(std::map<int, std::set<int> >::iterator i = this->Tests.begin();
      i != this->Tests.end(); ++i)
    {
    this->TestRunningMap[i->first] = false;
    this->TestFinishMap[i->first] = false;
    }
  this->Tests = tests;
  this->TestNames = testNames;
}
  // Set the max number of tests that can be run at the same time.
void cmCTestMultiProcessHandler::SetParallelLevel(size_t l)
{
  this->ParallelLevel = l;
}


void cmCTestMultiProcessHandler::RunTests()
{
  this->StartNextTests();
  while(this->Tests.size() != 0)
    {
    this->CheckOutput();
    this->StartNextTests();
    }
  // let all running tests finish
  while(this->CheckOutput())
    {
    }
  
  for(std::map<int, cmStdString>::iterator i =
        this->TestOutput.begin();
      i != this->TestOutput.end(); ++i)
    {
    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, 
               i->second << std::endl);
    }
      
}

void cmCTestMultiProcessHandler::StartTestProcess(int test)
{
  cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, 
            " test " << test << "\n");
  this->TestRunningMap[test] = true; // mark the test as running
  // now remove the test itself
  this->Tests.erase(test);
  // now run the test
  cmProcess* newp = new cmProcess;
  newp->SetId(this->ProcessId);
  newp->SetId(test);
  newp->SetCommand(this->CTestCommand.c_str());
  std::vector<std::string> args;
  args.push_back("-I");
  cmOStringStream strm;
  strm << test << "," << test;
  args.push_back(strm.str());
  args.push_back("--parallel-cache");
  args.push_back(this->CTestCacheFile.c_str());
  args.push_back("--internal-ctest-parallel"); 
  cmOStringStream strm2;
  strm2 << test;
  args.push_back(strm2.str());
  if(this->CTest->GetExtraVerbose())
    {
    args.push_back("-VV");
    }
  newp->SetCommandArguments(args);
  if(!newp->StartProcess())
    {
     cmCTestLog(this->CTest, ERROR_MESSAGE, 
                "Error starting " << newp->GetCommand() << "\n");
    this->EndTest(newp);
    }
  else
    {
    this->RunningTests.insert(newp);
    }
 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, 
            "ctest -I " << test << "\n");
 this->ProcessId++;
}

bool cmCTestMultiProcessHandler::StartTest(int test)
{
  // copy the depend tests locally because when 
  // a test is finished it will be removed from the depend list
  // and we don't want to be iterating a list while removing from it
  std::set<int> depends = this->Tests[test];
  size_t totalDepends = depends.size();
  if(totalDepends)
    {
    for(std::set<int>::const_iterator i = depends.begin();
        i != depends.end(); ++i)
      {
      // if the test is not already running then start it
      if(!this->TestRunningMap[*i])
        {
        // this test might be finished, but since
        // this is a copy of the depend map we might
        // still have it
        if(!this->TestFinishMap[*i])
          {
          // only start one test in this function
          return this->StartTest(*i);
          }
        else
          {
          // the depend has been and finished
          totalDepends--;
          }
        }
      }
    }
  // if there are no depends left then run this test
  if(totalDepends == 0)
    {
    // Start this test it has no depends 
    this->StartTestProcess(test);
    return true;
    }
  // This test was not able to start because it is waiting 
  // on depends to run
  return false;  
}

void cmCTestMultiProcessHandler::StartNextTests()
{
  cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl
             << "Number of running tests : " << this->RunningTests.size()
             << "\n");
  size_t numToStart = this->ParallelLevel - this->RunningTests.size();
  if(numToStart == 0)
    {
    return;
    }
  std::map<int, std::set<int> > tests = this->Tests;
  for(std::map<int, std::set<int> >::iterator i = tests.begin();
      i !=  tests.end(); ++i)
    {
    // start test should start only one test
    if(this->StartTest(i->first))
      {
      numToStart--;
      }
    else
      {
      cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl
             << "Test did not start waiting on depends to finish: " 
                 << i->first << "\n");
      }
    if(numToStart == 0 )
      {
      return;
      }
    }
}


bool cmCTestMultiProcessHandler::CheckOutput()
{
  // no more output we are done
  if(this->RunningTests.size() == 0)
    {
    return false;
    }
  std::vector<cmProcess*> finished;
  std::string out, err;
  for(std::set<cmProcess*>::const_iterator i = this->RunningTests.begin();
      i != this->RunningTests.end(); ++i)
    {
    cmProcess* p = *i;
    int pipe = p->CheckOutput(.1, out, err);
    if(pipe == cmsysProcess_Pipe_STDOUT)
      {
      cmCTestLog(this->CTest, HANDLER_OUTPUT, 
                 p->GetId() << ": " << out << std::endl);
      this->TestOutput[ p->GetId() ] += out;
      this->TestOutput[ p->GetId() ] += "\n";
      }
    else if(pipe == cmsysProcess_Pipe_STDERR)
      {
      cmCTestLog(this->CTest, HANDLER_OUTPUT, 
                 p->GetId() << ": " << err << std::endl);
      this->TestOutput[ p->GetId() ] += err;
      this->TestOutput[ p->GetId() ] += "\n";
      }
    if(!p->IsRunning())
      {
      finished.push_back(p);
      }
    }
  for( std::vector<cmProcess*>::iterator i = finished.begin();
       i != finished.end(); ++i)
    {
    cmProcess* p = *i;
    this->EndTest(p);
    }
  return true;
}

void cmCTestMultiProcessHandler::EndTest(cmProcess* p)
{
  int test = p->GetId();
  int exitVal = p->GetExitValue();
  cmCTestTestHandler::cmCTestTestResult cres;
  cres.Properties = 0;
  cres.ExecutionTime = 0;// ???
  cres.ReturnValue = exitVal;
  cres.Status = cmCTestTestHandler::COMPLETED;
  cres.TestCount = test;  
  cres.Name = this->TestNames[test];
  cres.Path.clear();
  if(exitVal)
    {
    cres.Status = cmCTestTestHandler::FAILED;
    this->Failed->push_back(this->TestNames[test]);
    }
  else
    {
    this->Passed->push_back(this->TestNames[test]);
    }
  this->TestResults->push_back(cres);
  // remove test from depend of all other tests
  for( std::map<int, std::set<int> >::iterator i = this->Tests.begin();
       i!=  this->Tests.end(); ++i)
    {
    i->second.erase(test);
    }
  this->TestFinishMap[test] = true;
  this->TestRunningMap[test] = false;
  this->RunningTests.erase(p);
  delete p;
  cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, 
             "finish test " << test << "\n");
}


void cmCTestMultiProcessHandler::PrintTests()
{
#undef cout
  for( std::map<int, std::set<int> >::iterator i = this->Tests.begin();
       i!=  this->Tests.end(); ++i)
    {
    std::cout << "Test " << i->first << "  (";
    for(std::set<int>::iterator j = i->second.begin(); 
        j != i->second.end(); ++j)
      {
      std::cout << *j << " ";
      }
    std::cout << ")\n";
    }
}

#if 0
int main()
{
  cmCTestMultiProcessHandler h;
  h.SetParallelLevel(4);
  std::map<int, std::set<int> > tests;
  std::set<int> depends;
  for(int i =1; i < 92; i++)
    {
    tests[i] = depends;
    }
  depends.clear();
  depends.insert(45);  subprject
  tests[46] = depends;  subproject-stage2
  depends.clear();
  depends.insert(55);  simpleinstall simpleinstall-s2
  tests[56] = depends;
  depends.clear();
  depends.insert(70);  wrapping
  tests[71] = depends; qtwrapping
  depends.clear();
  depends.insert(71);  qtwrapping
  tests[72] = depends;  testdriver1
  depends.clear();
  depends.insert(72)    testdriver1
  tests[73] = depends;  testdriver2
  depends.clear();
  depends.insert(73);   testdriver2
  tests[74] = depends;  testdriver3
  depends.clear();
  depends.insert(79);   linkorder1
  tests[80] = depends;  linkorder2
  h.SetTests(tests);
  h.PrintTests();
  h.RunTests();
}
#endif

--- NEW FILE: cmCTestMultiProcessHandler.h ---
/*=========================================================================

  Program:   CMake - Cross-Platform Makefile Generator
  Module:    $RCSfile: cmCTestMultiProcessHandler.h,v $
  Language:  C++
  Date:      $Date: 2008-07-03 13:31:31 $
  Version:   $Revision: 1.1 $

  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#ifndef cmCTestMultiProcessHandler_h
#define cmCTestMultiProcessHandler_h

#include <set>
#include <map>
#include <string>
#include <vector>
class cmProcess;
#include <cmStandardIncludes.h>
#include <cmCTestTestHandler.h>

/** \class cmCTestMultiProcessHandler
 * \brief run parallel ctest
 *
 * cmCTestMultiProcessHandler 
 */
class cmCTestMultiProcessHandler 
{
public:
  cmCTestMultiProcessHandler();
  // Set the tests
  void SetTests(std::map<int, std::set<int> >& tests,
                std::map<int, cmStdString>& testNames);
  // Set the max number of tests that can be run at the same time.
  void SetParallelLevel(size_t);
  void RunTests();
  void PrintTests();
  void SetCTestCommand(const char* c) { this->CTestCommand = c;}
  void SetTestCacheFile(const char* c) { this->CTestCacheFile = c;}
  void SetPassFailVectors(std::vector<cmStdString>* passed,
                          std::vector<cmStdString>* failed)
    {
      this->Passed = passed;
      this->Failed = failed;
    }
  void SetTestResults(std::vector<cmCTestTestHandler::cmCTestTestResult>* r)
    {
      this->TestResults = r;
    }
  void SetCTest(cmCTest* ctest) { this->CTest = ctest;}
protected:  
  cmCTest* CTest;
  // Start the next test or tests as many as are allowed by
  // ParallelLevel
  void StartNextTests();
  void StartTestProcess(int test);
  bool StartTest(int test);
  void EndTest(cmProcess*);
  // Return true if there are still tests running
  // check all running processes for output and exit case
  bool CheckOutput();
  // map from test number to set of depend tests
  std::map<int, std::set<int> > Tests;
  std::map<int, cmStdString> TestNames;
  std::map<int, bool> TestRunningMap;
  std::map<int, bool> TestFinishMap;
  std::map<int, cmStdString> TestOutput;
  std::string CTestCommand;
  std::string CTestCacheFile;
  std::vector<cmStdString>* Passed;
  std::vector<cmStdString>* Failed;
  std::vector<cmCTestTestHandler::cmCTestTestResult>* TestResults;
  int ProcessId;
  size_t ParallelLevel; // max number of process that can be run at once
  std::set<cmProcess*> RunningTests;  // current running tests
};

#endif

Index: cmCTestTestHandler.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/CTest/cmCTestTestHandler.cxx,v
retrieving revision 1.71
retrieving revision 1.72
diff -C 2 -d -r1.71 -r1.72
*** cmCTestTestHandler.cxx	17 Jun 2008 18:03:49 -0000	1.71
--- cmCTestTestHandler.cxx	3 Jul 2008 13:31:32 -0000	1.72
***************
*** 17,21 ****
  
  #include "cmCTestTestHandler.h"
! 
  #include "cmCTest.h"
  #include "cmake.h"
--- 17,21 ----
  
  #include "cmCTestTestHandler.h"
! #include "cmCTestMultiProcessHandler.h"
  #include "cmCTest.h"
  #include "cmake.h"
***************
*** 501,509 ****
    
    this->TestResults.clear();
! 
!   cmCTestLog(this->CTest, HANDLER_OUTPUT,
!     (this->MemCheck ? "Memory check" : "Test")
!              << " project " << cmSystemTools::GetCurrentWorkingDirectory()
!              << std::endl);
    if ( ! this->PreProcessHandler() )
      {
--- 501,512 ----
    
    this->TestResults.clear();
!  // do not output startup if this is a sub-process for parallel tests
!   if(!this->CTest->GetParallelSubprocess())
!     {
!     cmCTestLog(this->CTest, HANDLER_OUTPUT,
!                (this->MemCheck ? "Memory check" : "Test")
!                << " project " << cmSystemTools::GetCurrentWorkingDirectory()
!                << std::endl);
!     }
    if ( ! this->PreProcessHandler() )
      {
***************
*** 518,522 ****
    std::vector<cmStdString> failed;
    int total;
- 
    this->ProcessDirectory(passed, failed);
  
--- 521,524 ----
***************
*** 551,581 ****
        percent = 99;
        }
!     cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl
!       << static_cast<int>(percent + .5) << "% tests passed, "
!       << failed.size() << " tests failed out of " << total << std::endl);
!     //fprintf(stderr,"\n%.0f%% tests passed, %i tests failed out of %i\n",
!     //  percent, int(failed.size()), total);
  
      if (failed.size())
        {
        cmGeneratedFileStream ofs;
! 
!       cmCTestLog(this->CTest, ERROR_MESSAGE, std::endl
!         << "The following tests FAILED:" << std::endl);
!       this->StartLogFile("TestsFailed", ofs);
! 
!       std::vector<cmCTestTestHandler::cmCTestTestResult>::iterator ftit;
!       for(ftit = this->TestResults.begin();
!         ftit != this->TestResults.end(); ++ftit)
          {
!         if ( ftit->Status != cmCTestTestHandler::COMPLETED )
            {
!           ofs << ftit->TestCount << ":" << ftit->Name << std::endl;
!           cmCTestLog(this->CTest, HANDLER_OUTPUT, "\t" << std::setw(3)
!             << ftit->TestCount << " - " << ftit->Name.c_str() << " ("
!             << this->GetTestStatus(ftit->Status) << ")" << std::endl);
            }
          }
- 
        }
      }
--- 553,587 ----
        percent = 99;
        }
!     if(!this->CTest->GetParallelSubprocess())
!       {
!       cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl
!                  << static_cast<int>(percent + .5) << "% tests passed, "
!                  << failed.size() << " tests failed out of " 
!                  << total << std::endl);
!       }
  
      if (failed.size())
        {
        cmGeneratedFileStream ofs;
!       if(!this->CTest->GetParallelSubprocess())
          {
!         cmCTestLog(this->CTest, ERROR_MESSAGE, std::endl
!                    << "The following tests FAILED:" << std::endl);
!         this->StartLogFile("TestsFailed", ofs);
!         
!         std::vector<cmCTestTestHandler::cmCTestTestResult>::iterator ftit;
!         for(ftit = this->TestResults.begin();
!             ftit != this->TestResults.end(); ++ftit)
            {
!           if ( ftit->Status != cmCTestTestHandler::COMPLETED )
!             {
!             ofs << ftit->TestCount << ":" << ftit->Name << std::endl;
!             cmCTestLog(this->CTest, HANDLER_OUTPUT, "\t" << std::setw(3)
!                        << ftit->TestCount << " - " << ftit->Name.c_str() << " ("
!                        << this->GetTestStatus(ftit->Status) << ")" << std::endl);
!             }
            }
+         
          }
        }
      }
***************
*** 678,683 ****
    // add the arguments
    std::vector<std::string>::const_iterator j = args.begin();
!   ++j;
!   ++j;
    std::vector<const char*> arguments;
    this->GenerateTestCommand(arguments);
--- 684,689 ----
    // add the arguments
    std::vector<std::string>::const_iterator j = args.begin();
!   ++j; // skip test name
!   ++j; // skip command as it is in actualCommand
    std::vector<const char*> arguments;
    this->GenerateTestCommand(arguments);
***************
*** 918,938 ****
  
  //----------------------------------------------------------------------
! void cmCTestTestHandler::ProcessDirectory(std::vector<cmStdString> &passed,
!                                           std::vector<cmStdString> &failed)
  {
!   std::string current_dir = cmSystemTools::GetCurrentWorkingDirectory();
!   this->TestList.clear();
! 
!   this->GetListOfTests();
    cmCTestTestHandler::ListOfTests::size_type tmsize = this->TestList.size();
  
-   this->StartTest = this->CTest->CurrentTime();
-   this->StartTestTime = static_cast<unsigned int>(cmSystemTools::GetTime());
-   double elapsed_time_start = cmSystemTools::GetTime();
- 
-   *this->LogFile << "Start testing: " << this->StartTest << std::endl
-     << "----------------------------------------------------------"
-     << std::endl;
- 
    // how many tests are in based on RegExp?
    int inREcnt = 0;
--- 924,941 ----
  
  //----------------------------------------------------------------------
! void cmCTestTestHandler::ComputeTestList()
  {
!   this->TestList.clear(); // clear list of test
!   if(this->CTest->GetParallelSubprocess())
!     {
!     this->LoadTestList();
!     return;
!     }
!   else
!     {
!     this->GetListOfTests();
!     }
    cmCTestTestHandler::ListOfTests::size_type tmsize = this->TestList.size();
  
    // how many tests are in based on RegExp?
    int inREcnt = 0;
***************
*** 954,961 ****
      this->ExpandTestsToRunInformation(inREcnt);
      }
! 
    int cnt = 0;
    inREcnt = 0;
!   std::string last_directory = "";
    for ( it = this->TestList.begin(); it != this->TestList.end(); it ++ )
      {
--- 957,965 ----
      this->ExpandTestsToRunInformation(inREcnt);
      }
!   // Now create a final list of tests to run
    int cnt = 0;
    inREcnt = 0;
!   std::string last_directory = ""; 
!   ListOfTests finalList;
    for ( it = this->TestList.begin(); it != this->TestList.end(); it ++ )
      {
***************
*** 966,986 ****
        }
  
-     // if we are out of time then skip this test, we leave two minutes 
-     // to submit results
-     if (this->CTest->GetRemainingTimeAllowed() - 120 <= 0)
-       {
-       continue;
-       }
-     
-     if (!(last_directory == it->Directory))
-       {
-       cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
-                  "Changing directory into " << it->Directory.c_str() << "\n");
-       *this->LogFile << "Changing directory into: " << it->Directory.c_str()
-                      << std::endl;
-       last_directory = it->Directory;
-       cmSystemTools::ChangeDirectory(it->Directory.c_str());
-       }
- 
      if (this->UseUnion)
        {
--- 970,973 ----
***************
*** 1004,1011 ****
          }
        }
!     
      // process this one test
!     this->ProcessOneTest(&(*it), passed, failed, cnt, 
!                          static_cast<int>(tmsize));
      }
  
--- 991,1310 ----
          }
        }
!     it->Index = cnt;  // save the index into the test list for this test
!     finalList.push_back(*it);
!     }
!   // Save the total number of tests before exclusions
!   this->TotalNumberOfTests = this->TestList.size();
!   // Set the TestList to the final list of all test
!   this->TestList = finalList;
! }
!  
! bool cmCTestTestHandler::GetValue(const char* tag,
!                                   int& value,
!                                   std::ifstream& fin)
! {
!   std::string line;
!   cmSystemTools::GetLineFromStream(fin, line);
!   if(line == tag)
!     {
!     fin >> value;
!     cmSystemTools::GetLineFromStream(fin, line); // read blank line
!     }
!   else
!     {
!     cmCTestLog(this->CTest, ERROR_MESSAGE,
!                "parse error: missing tag: "
!                << tag << " found [" << line << "]" << std::endl);
!     return false;
!     }
!   return true;
! }
! 
! bool cmCTestTestHandler::GetValue(const char* tag,
!                                   double& value,
!                                   std::ifstream& fin)
! {
!   std::string line;
!   cmSystemTools::GetLineFromStream(fin, line);
!   if(line == tag)
!     {
!     fin >> value;
!     cmSystemTools::GetLineFromStream(fin, line); // read blank line
!     }
!   else
!     {
!     cmCTestLog(this->CTest, ERROR_MESSAGE,
!                "parse error: missing tag: "
!                << tag << " found [" << line << "]" << std::endl);
!     return false;
!     }
!   return true;
! }
! 
! bool cmCTestTestHandler::GetValue(const char* tag,
!                                   bool& value,
!                                   std::ifstream& fin)
! {
!   std::string line;
!   cmSystemTools::GetLineFromStream(fin, line);
!   if(line == tag)
!     {
!     fin >> value;
!     cmSystemTools::GetLineFromStream(fin, line); // read blank line
!     }
!   else
!     {
!     cmCTestLog(this->CTest, ERROR_MESSAGE,
!                "parse error: missing tag: "
!                << tag << " found [" << line << "]" << std::endl);
!     return false;
!     }
!   return true;
! }
! 
! bool cmCTestTestHandler::GetValue(const char* tag,
!                                   size_t& value,
!                                   std::ifstream& fin)
! {
!   std::string line;
!   cmSystemTools::GetLineFromStream(fin, line);
!   if(line == tag)
!     {
!     fin >> value;
!     cmSystemTools::GetLineFromStream(fin, line); // read blank line
!     }
!   else
!     { 
!     cmCTestLog(this->CTest, ERROR_MESSAGE,
!                "parse error: missing tag: "
!                << tag << " found [" << line.c_str() << "]" << std::endl);
!     return false;
!     }
!   return true;
! }
! 
! bool cmCTestTestHandler::GetValue(const char* tag,
!                                   std::string& value,
!                                   std::ifstream& fin)
! {
!   std::string line;
!   cmSystemTools::GetLineFromStream(fin, line);
!   if(line == tag)
!     {
!     return cmSystemTools::GetLineFromStream(fin, value);
!     }
!   else
!     {
!     cmCTestLog(this->CTest, ERROR_MESSAGE,
!                "parse error: missing tag: "
!                << tag << " found [" << line << "]" << std::endl);
!     return false;
!     }
!   return true;
! }
! 
! 
! // This should load only one test and is used in -j N mode.
! // it is used by the sub-process ctest runs which should have
! // only one -I N test to run.
! void cmCTestTestHandler::LoadTestList()
! {
!   this->TestList.clear();
!   std::string fname = this->CTest->GetBinaryDir()
!     + "/Testing/Temporary/PCache.txt";
!   std::ifstream fin(fname.c_str());
!   std::string line;
!   if(!fin)
!     {
!     cmCTestLog(this->CTest, ERROR_MESSAGE,
!                "Could not load PCache.txt file: "
!                << fname.c_str() << std::endl);
!     return;
!     }
!   bool ok = true;
!   int numTestsToRun;
!   ok = ok && this->GetValue("TotalNumberOfTests:", 
!                             this->TotalNumberOfTests, fin);
!   ok = ok && this->GetValue("NumberOfTestsToRun:", numTestsToRun, fin);
!   this->ExpandTestsToRunInformation(this->TotalNumberOfTests);
!   if(this->TestsToRun.size() != 1)
!     { 
!     cmCTestLog(this->CTest, ERROR_MESSAGE,
!                "Error when in parallel mode only one test should be run: "
!                << this->TestsToRun.size() << std::endl);
!     }
!   int testIndexToRun = this->TestsToRun[0];
!   this->CTest->SetParallelSubprocessId(testIndexToRun);
!   if(!ok)
!     {
!     return;
!     }
!   for(int i =0; i < numTestsToRun; i++)
!     {
!     cmCTestTestProperties p;
!     int numArgs;
!     bool ok = this->GetValue("Name:", p.Name, fin);
!     ok = ok && this->GetValue("Directory:", p.Directory, fin);
!     ok = ok && this->GetValue("Args:", numArgs, fin);
!     for(int j =0; j < numArgs; ++j)
!       {
!       cmSystemTools::GetLineFromStream(fin, line);
!       p.Args.push_back(line);
!       }
!     int numDep = 0;
!     ok = ok && this->GetValue("Depends:", numDep, fin);
!     for(int j =0; j < numDep; ++j)
!       {
!       cmSystemTools::GetLineFromStream(fin, line);
!       p.Depends.push_back(line);
!       }
!     int isinre;
!     ok = ok && this->GetValue("IsInBasedOnREOptions:", isinre, fin);
!     ok = ok && this->GetValue("WillFail:", p.WillFail, fin);
!     ok = ok && this->GetValue("TimeOut:", p.Timeout, fin);
!     ok = ok && this->GetValue("Index:", p.Index, fin);
!     if(!ok)
!       {
!       return;
!       }
!     if(p.Index == testIndexToRun)
!       {
!       // add the one test and stop reading
!       this->TestList.push_back(p);
!       return;
!       }
!     }
! }
! std::string cmCTestTestHandler::SaveTestList()
! {
!   std::string fname = this->CTest->GetBinaryDir()
!     + "/Testing/Temporary/PCache.txt";
!   cmGeneratedFileStream fout(fname.c_str());
!   if(!fout)
!     {
!     cmCTestLog(this->CTest, ERROR_MESSAGE, std::endl
!                << "Could not open PCache.txt for write:" 
!                << fname.c_str()
!                << std::endl);
!     }
!   fout << "TotalNumberOfTests:\n";
!   fout << this->TotalNumberOfTests << "\n";
!   fout << "NumberOfTestsToRun:\n";
!   fout << this->TestList.size() << "\n";
!   for (ListOfTests::iterator it = this->TestList.begin();
!        it != this->TestList.end(); it ++ )
!     {
!     cmCTestTestProperties& p = *it;
!     fout << "Name:\n"
!          << p.Name.c_str()
!          << "\nDirectory:\n"
!          << p.Directory.c_str()
!          << "\nArgs:\n"
!          << p.Args.size() << "\n";
!     for(std::vector<std::string>::iterator i = p.Args.begin();
!         i != p.Args.end(); ++i)
!       {
!       fout << i->c_str() << "\n";
!       }
!     fout << "Depends:\n" << p.Depends.size() << "\n";
!     for(std::vector<std::string>::iterator i = p.Depends.begin();
!         i != p.Depends.end(); ++i)
!       {
!       fout << i->c_str() << "\n";
!       }
!     fout << "IsInBasedOnREOptions:\n"
!          << p.IsInBasedOnREOptions
!          << "\nWillFail:\n"
!          << p.WillFail
!          << "\nTimeOut:\n"
!          << p.Timeout
!          << "\nIndex:\n"
!          << p.Index << "\n";
!     }
!   fout.close();
!   return fname;
! }
! 
! void cmCTestTestHandler::ProcessParallel(std::vector<cmStdString> &passed,
!                                          std::vector<cmStdString> &failed)
! {
!   this->ComputeTestList();
!   cmCTestMultiProcessHandler parallel;
!   parallel.SetCTest(this->CTest);
!   parallel.SetParallelLevel(this->CTest->GetParallelLevel()); 
!   std::set<int> depends;
!   std::map<int, std::set<int> > tests; 
!   std::map<int, cmStdString> testnames;
!   for (ListOfTests::iterator it = this->TestList.begin();
!        it != this->TestList.end(); it ++ )
!     { 
!     cmCTestTestProperties& p = *it;
!     testnames[p.Index] = p.Name;
!     if(p.Depends.size())
!       {
!       for(std::vector<std::string>::iterator i = p.Depends.begin();
!         i != p.Depends.end(); ++i)
!         {
!         for(ListOfTests::iterator it2 = this->TestList.begin();
!             it2 != this->TestList.end(); it2 ++ )
!           {
!           if(it2->Name == *i)
!             {
!             depends.insert(it2->Index);
!             break; // break out of test loop as name can only match 1
!             }
!           }
!         }
!       }
!     tests[it->Index] = depends;
!     }
!   parallel.SetCTestCommand(this->CTest->GetCTestExecutable());
!   parallel.SetTests(tests, testnames);
!   std::string fname = this->SaveTestList();
!   parallel.SetTestCacheFile(fname.c_str());
!   parallel.SetPassFailVectors(&passed, &failed);
!   this->TestResults.clear();
!   parallel.SetTestResults(&this->TestResults);
!   parallel.RunTests();
!   cmSystemTools::RemoveFile(fname.c_str());
! }
! 
! 
! //----------------------------------------------------------------------
! void cmCTestTestHandler::ProcessDirectory(std::vector<cmStdString> &passed,
!                                           std::vector<cmStdString> &failed)
! {
!   if(this->CTest->GetParallelLevel() > 0)
!     {
!     this->ProcessParallel(passed, failed);
!     return;
!     }
!   // save the current working directory
!   std::string current_dir = cmSystemTools::GetCurrentWorkingDirectory();
!   // compute the list of tests to run
!   this->ComputeTestList();
!   this->StartTest = this->CTest->CurrentTime();
!   this->StartTestTime = static_cast<unsigned int>(cmSystemTools::GetTime());
!   double elapsed_time_start = cmSystemTools::GetTime();
!   *this->LogFile << "Start testing: " << this->StartTest << std::endl
!     << "----------------------------------------------------------"
!     << std::endl;
!   std::string last_directory = "";
!   // run each test
!   for (ListOfTests::iterator it = this->TestList.begin();
!        it != this->TestList.end(); it ++ )
!     {
!     if (!(last_directory == it->Directory))
!       {
!       cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
!                  "Changing directory into " << it->Directory.c_str() << "\n");
!       *this->LogFile << "Changing directory into: " << it->Directory.c_str()
!                      << std::endl;
!       last_directory = it->Directory;
!       cmSystemTools::ChangeDirectory(it->Directory.c_str());
!       }
      // process this one test
!     this->ProcessOneTest(&(*it), passed, failed, it->Index, 
!                          static_cast<int>(this->TotalNumberOfTests));
      }
  
***************
*** 1891,1894 ****
--- 2190,2204 ----
                }
              }
+           if ( key == "DEPENDS" )
+             { 
+             std::vector<std::string> lval;
+             cmSystemTools::ExpandListArgument(val.c_str(), lval);
+             std::vector<std::string>::iterator crit;
+             for ( crit = lval.begin(); crit != lval.end(); ++ crit )
+               {
+               cmCTestTestProperties* tp = &(*rtit);
+               rtit->Depends.push_back(*crit);
+               }
+             }
            if ( key == "MEASUREMENT" )
              {

Index: cmCTestTestHandler.h
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/CTest/cmCTestTestHandler.h,v
retrieving revision 1.27
retrieving revision 1.28
diff -C 2 -d -r1.27 -r1.28
*** cmCTestTestHandler.h	30 Jan 2008 16:17:36 -0000	1.27
--- cmCTestTestHandler.h	3 Jul 2008 13:31:32 -0000	1.28
***************
*** 81,84 ****
--- 81,85 ----
      cmStdString Directory;
      std::vector<std::string> Args;
+     std::vector<std::string> Depends;
      std::vector<std::pair<cmsys::RegularExpression,
                            std::string> > ErrorRegularExpressions;
***************
*** 89,92 ****
--- 90,94 ----
      bool WillFail;
      double Timeout;
+     int Index;
    };
  
***************
*** 121,124 ****
--- 123,127 ----
  
  protected:
+   // comput a final test list
    virtual int PreProcessHandler();
    virtual int PostProcessHandler();
***************
*** 153,157 ****
  
  
! private:
    enum { // Program statuses
      NOT_RUN = 0,
--- 156,160 ----
  
  
! public:
    enum { // Program statuses
      NOT_RUN = 0,
***************
*** 167,171 ****
    };
  
! 
    /**
     * Generate the Dart compatible output
--- 170,174 ----
    };
  
! private:
    /**
     * Generate the Dart compatible output
***************
*** 184,188 ****
     */
    void GetListOfTests();
! 
    /**
     * Find the executable for a test
--- 187,216 ----
     */
    void GetListOfTests();
!   // compute the lists of tests that will actually run
!   // based on union regex and -I stuff
!   void ComputeTestList();
!   
!   // Save the state of the test list and return the file
!   // name it was saved to
!   std::string SaveTestList();
!   void LoadTestList();
!   bool GetValue(const char* tag,
!                 std::string& value,
!                 std::ifstream& fin);
!   bool GetValue(const char* tag,
!                 int& value,
!                 std::ifstream& fin);
!   bool GetValue(const char* tag,
!                 size_t& value,
!                 std::ifstream& fin);
!   bool GetValue(const char* tag,
!                 bool& value,
!                 std::ifstream& fin);
!   bool GetValue(const char* tag,
!                 double& value,
!                 std::ifstream& fin);
!   // run in -j N mode
!   void ProcessParallel(std::vector<cmStdString> &passed,
!                        std::vector<cmStdString> &failed);
    /**
     * Find the executable for a test
***************
*** 211,214 ****
--- 239,243 ----
    bool UseUnion;
    ListOfTests TestList;
+   size_t TotalNumberOfTests;
    cmsys::RegularExpression DartStuff;
  

Index: cmCTestGenericHandler.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/CTest/cmCTestGenericHandler.cxx,v
retrieving revision 1.16
retrieving revision 1.17
diff -C 2 -d -r1.16 -r1.17
*** cmCTestGenericHandler.cxx	28 Aug 2007 17:46:57 -0000	1.16
--- cmCTestGenericHandler.cxx	3 Jul 2008 13:31:30 -0000	1.17
***************
*** 162,165 ****
--- 162,171 ----
      }
    ostr << ".log";
+   // if this is a parallel subprocess then add the id to the
+   // file so they don't clobber each other
+   if(this->CTest->GetParallelSubprocess())
+     {
+     ostr << "." << this->CTest->GetParallelSubprocessId();
+     }
    if( !this->CTest->OpenOutputFile("Temporary", ostr.str().c_str(), xofs) )
      {



More information about the Cmake-commits mailing list