cmCTestMultiProcessHandler.cxx 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
  4. Distributed under the OSI-approved BSD License (the "License");
  5. see accompanying file Copyright.txt for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even the
  7. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the License for more information.
  9. ============================================================================*/
  10. #include "cmCTestMultiProcessHandler.h"
  11. #include "cmProcess.h"
  12. #include "cmStandardIncludes.h"
  13. #include "cmCTest.h"
  14. #include "cmSystemTools.h"
  15. #include <stdlib.h>
  16. #include <stack>
  17. #include <list>
  18. #include <float.h>
  19. #include <cmsys/FStream.hxx>
  20. class TestComparator
  21. {
  22. public:
  23. TestComparator(cmCTestMultiProcessHandler* handler) : Handler(handler) {}
  24. ~TestComparator() {}
  25. // Sorts tests in descending order of cost
  26. bool operator() (int index1, int index2) const
  27. {
  28. return Handler->Properties[index1]->Cost >
  29. Handler->Properties[index2]->Cost;
  30. }
  31. private:
  32. cmCTestMultiProcessHandler* Handler;
  33. };
  34. cmCTestMultiProcessHandler::cmCTestMultiProcessHandler()
  35. {
  36. this->ParallelLevel = 1;
  37. this->Completed = 0;
  38. this->RunningCount = 0;
  39. this->StopTimePassed = false;
  40. this->HasCycles = false;
  41. }
  42. cmCTestMultiProcessHandler::~cmCTestMultiProcessHandler()
  43. {
  44. }
  45. // Set the tests
  46. void
  47. cmCTestMultiProcessHandler::SetTests(TestMap& tests,
  48. PropertiesMap& properties)
  49. {
  50. this->Tests = tests;
  51. this->Properties = properties;
  52. this->Total = this->Tests.size();
  53. // set test run map to false for all
  54. for(TestMap::iterator i = this->Tests.begin();
  55. i != this->Tests.end(); ++i)
  56. {
  57. this->TestRunningMap[i->first] = false;
  58. this->TestFinishMap[i->first] = false;
  59. }
  60. if(!this->CTest->GetShowOnly())
  61. {
  62. this->ReadCostData();
  63. this->HasCycles = !this->CheckCycles();
  64. if(this->HasCycles)
  65. {
  66. return;
  67. }
  68. this->CreateTestCostList();
  69. }
  70. }
  71. // Set the max number of tests that can be run at the same time.
  72. void cmCTestMultiProcessHandler::SetParallelLevel(size_t level)
  73. {
  74. this->ParallelLevel = level < 1 ? 1 : level;
  75. }
  76. //---------------------------------------------------------
  77. void cmCTestMultiProcessHandler::RunTests()
  78. {
  79. this->CheckResume();
  80. if(this->HasCycles)
  81. {
  82. return;
  83. }
  84. this->TestHandler->SetMaxIndex(this->FindMaxIndex());
  85. this->StartNextTests();
  86. while(!this->Tests.empty())
  87. {
  88. if(this->StopTimePassed)
  89. {
  90. return;
  91. }
  92. this->CheckOutput();
  93. this->StartNextTests();
  94. }
  95. // let all running tests finish
  96. while(this->CheckOutput())
  97. {
  98. }
  99. this->MarkFinished();
  100. this->UpdateCostData();
  101. }
  102. //---------------------------------------------------------
  103. void cmCTestMultiProcessHandler::StartTestProcess(int test)
  104. {
  105. cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  106. "test " << test << "\n", this->Quiet);
  107. this->TestRunningMap[test] = true; // mark the test as running
  108. // now remove the test itself
  109. this->EraseTest(test);
  110. this->RunningCount += GetProcessorsUsed(test);
  111. cmCTestRunTest* testRun = new cmCTestRunTest(this->TestHandler);
  112. testRun->SetIndex(test);
  113. testRun->SetTestProperties(this->Properties[test]);
  114. std::string current_dir = cmSystemTools::GetCurrentWorkingDirectory();
  115. cmSystemTools::ChangeDirectory(this->Properties[test]->Directory);
  116. // Lock the resources we'll be using
  117. this->LockResources(test);
  118. if(testRun->StartTest(this->Total))
  119. {
  120. this->RunningTests.insert(testRun);
  121. }
  122. else if(testRun->IsStopTimePassed())
  123. {
  124. this->StopTimePassed = true;
  125. delete testRun;
  126. return;
  127. }
  128. else
  129. {
  130. for(TestMap::iterator j = this->Tests.begin();
  131. j != this->Tests.end(); ++j)
  132. {
  133. j->second.erase(test);
  134. }
  135. this->UnlockResources(test);
  136. this->Completed++;
  137. this->TestFinishMap[test] = true;
  138. this->TestRunningMap[test] = false;
  139. this->RunningCount -= GetProcessorsUsed(test);
  140. testRun->EndTest(this->Completed, this->Total, false);
  141. this->Failed->push_back(this->Properties[test]->Name);
  142. delete testRun;
  143. }
  144. cmSystemTools::ChangeDirectory(current_dir);
  145. }
  146. //---------------------------------------------------------
  147. void cmCTestMultiProcessHandler::LockResources(int index)
  148. {
  149. this->LockedResources.insert(
  150. this->Properties[index]->LockedResources.begin(),
  151. this->Properties[index]->LockedResources.end());
  152. }
  153. //---------------------------------------------------------
  154. void cmCTestMultiProcessHandler::UnlockResources(int index)
  155. {
  156. for(std::set<std::string>::iterator i =
  157. this->Properties[index]->LockedResources.begin();
  158. i != this->Properties[index]->LockedResources.end(); ++i)
  159. {
  160. this->LockedResources.erase(*i);
  161. }
  162. }
  163. //---------------------------------------------------------
  164. void cmCTestMultiProcessHandler::EraseTest(int test)
  165. {
  166. this->Tests.erase(test);
  167. this->SortedTests.erase(
  168. std::find(this->SortedTests.begin(), this->SortedTests.end(), test));
  169. }
  170. //---------------------------------------------------------
  171. inline size_t cmCTestMultiProcessHandler::GetProcessorsUsed(int test)
  172. {
  173. size_t processors =
  174. static_cast<int>(this->Properties[test]->Processors);
  175. //If this is set to run serially, it must run alone.
  176. //Also, if processors setting is set higher than the -j
  177. //setting, we default to using all of the process slots.
  178. if(this->Properties[test]->RunSerial
  179. || processors > this->ParallelLevel)
  180. {
  181. processors = this->ParallelLevel;
  182. }
  183. return processors;
  184. }
  185. //---------------------------------------------------------
  186. bool cmCTestMultiProcessHandler::StartTest(int test)
  187. {
  188. //Check for locked resources
  189. for(std::set<std::string>::iterator i =
  190. this->Properties[test]->LockedResources.begin();
  191. i != this->Properties[test]->LockedResources.end(); ++i)
  192. {
  193. if(this->LockedResources.find(*i) != this->LockedResources.end())
  194. {
  195. return false;
  196. }
  197. }
  198. // if there are no depends left then run this test
  199. if(this->Tests[test].empty())
  200. {
  201. this->StartTestProcess(test);
  202. return true;
  203. }
  204. // This test was not able to start because it is waiting
  205. // on depends to run
  206. return false;
  207. }
  208. //---------------------------------------------------------
  209. void cmCTestMultiProcessHandler::StartNextTests()
  210. {
  211. size_t numToStart = 0;
  212. if(this->RunningCount < this->ParallelLevel)
  213. {
  214. numToStart = this->ParallelLevel - this->RunningCount;
  215. }
  216. if(numToStart == 0)
  217. {
  218. return;
  219. }
  220. TestList copy = this->SortedTests;
  221. for(TestList::iterator test = copy.begin(); test != copy.end(); ++test)
  222. {
  223. size_t processors = GetProcessorsUsed(*test);
  224. if(processors <= numToStart && this->StartTest(*test))
  225. {
  226. if(this->StopTimePassed)
  227. {
  228. return;
  229. }
  230. numToStart -= processors;
  231. }
  232. else if(numToStart == 0)
  233. {
  234. return;
  235. }
  236. }
  237. }
  238. //---------------------------------------------------------
  239. bool cmCTestMultiProcessHandler::CheckOutput()
  240. {
  241. // no more output we are done
  242. if(this->RunningTests.empty())
  243. {
  244. return false;
  245. }
  246. std::vector<cmCTestRunTest*> finished;
  247. std::string out, err;
  248. for(std::set<cmCTestRunTest*>::const_iterator i = this->RunningTests.begin();
  249. i != this->RunningTests.end(); ++i)
  250. {
  251. cmCTestRunTest* p = *i;
  252. if(!p->CheckOutput())
  253. {
  254. finished.push_back(p);
  255. }
  256. }
  257. for( std::vector<cmCTestRunTest*>::iterator i = finished.begin();
  258. i != finished.end(); ++i)
  259. {
  260. this->Completed++;
  261. cmCTestRunTest* p = *i;
  262. int test = p->GetIndex();
  263. if(p->EndTest(this->Completed, this->Total, true))
  264. {
  265. this->Passed->push_back(p->GetTestProperties()->Name);
  266. }
  267. else
  268. {
  269. this->Failed->push_back(p->GetTestProperties()->Name);
  270. }
  271. for(TestMap::iterator j = this->Tests.begin();
  272. j != this->Tests.end(); ++j)
  273. {
  274. j->second.erase(test);
  275. }
  276. this->TestFinishMap[test] = true;
  277. this->TestRunningMap[test] = false;
  278. this->RunningTests.erase(p);
  279. this->WriteCheckpoint(test);
  280. this->UnlockResources(test);
  281. this->RunningCount -= GetProcessorsUsed(test);
  282. delete p;
  283. }
  284. return true;
  285. }
  286. //---------------------------------------------------------
  287. void cmCTestMultiProcessHandler::UpdateCostData()
  288. {
  289. std::string fname = this->CTest->GetCostDataFile();
  290. std::string tmpout = fname + ".tmp";
  291. cmsys::ofstream fout;
  292. fout.open(tmpout.c_str());
  293. PropertiesMap temp = this->Properties;
  294. if(cmSystemTools::FileExists(fname.c_str()))
  295. {
  296. cmsys::ifstream fin;
  297. fin.open(fname.c_str());
  298. std::string line;
  299. while(std::getline(fin, line))
  300. {
  301. if(line == "---") break;
  302. std::vector<cmsys::String> parts =
  303. cmSystemTools::SplitString(line, ' ');
  304. //Format: <name> <previous_runs> <avg_cost>
  305. if(parts.size() < 3) break;
  306. std::string name = parts[0];
  307. int prev = atoi(parts[1].c_str());
  308. float cost = static_cast<float>(atof(parts[2].c_str()));
  309. int index = this->SearchByName(name);
  310. if(index == -1)
  311. {
  312. // This test is not in memory. We just rewrite the entry
  313. fout << name << " " << prev << " " << cost << "\n";
  314. }
  315. else
  316. {
  317. // Update with our new average cost
  318. fout << name << " " << this->Properties[index]->PreviousRuns << " "
  319. << this->Properties[index]->Cost << "\n";
  320. temp.erase(index);
  321. }
  322. }
  323. fin.close();
  324. cmSystemTools::RemoveFile(fname);
  325. }
  326. // Add all tests not previously listed in the file
  327. for(PropertiesMap::iterator i = temp.begin(); i != temp.end(); ++i)
  328. {
  329. fout << i->second->Name << " " << i->second->PreviousRuns << " "
  330. << i->second->Cost << "\n";
  331. }
  332. // Write list of failed tests
  333. fout << "---\n";
  334. for(std::vector<std::string>::iterator i = this->Failed->begin();
  335. i != this->Failed->end(); ++i)
  336. {
  337. fout << i->c_str() << "\n";
  338. }
  339. fout.close();
  340. cmSystemTools::RenameFile(tmpout.c_str(), fname.c_str());
  341. }
  342. //---------------------------------------------------------
  343. void cmCTestMultiProcessHandler::ReadCostData()
  344. {
  345. std::string fname = this->CTest->GetCostDataFile();
  346. if(cmSystemTools::FileExists(fname.c_str(), true))
  347. {
  348. cmsys::ifstream fin;
  349. fin.open(fname.c_str());
  350. std::string line;
  351. while(std::getline(fin, line))
  352. {
  353. if(line == "---") break;
  354. std::vector<cmsys::String> parts =
  355. cmSystemTools::SplitString(line, ' ');
  356. // Probably an older version of the file, will be fixed next run
  357. if(parts.size() < 3)
  358. {
  359. fin.close();
  360. return;
  361. }
  362. std::string name = parts[0];
  363. int prev = atoi(parts[1].c_str());
  364. float cost = static_cast<float>(atof(parts[2].c_str()));
  365. int index = this->SearchByName(name);
  366. if(index == -1) continue;
  367. this->Properties[index]->PreviousRuns = prev;
  368. // When not running in parallel mode, don't use cost data
  369. if(this->ParallelLevel > 1 &&
  370. this->Properties[index] &&
  371. this->Properties[index]->Cost == 0)
  372. {
  373. this->Properties[index]->Cost = cost;
  374. }
  375. }
  376. // Next part of the file is the failed tests
  377. while(std::getline(fin, line))
  378. {
  379. if(line != "")
  380. {
  381. this->LastTestsFailed.push_back(line);
  382. }
  383. }
  384. fin.close();
  385. }
  386. }
  387. //---------------------------------------------------------
  388. int cmCTestMultiProcessHandler::SearchByName(std::string name)
  389. {
  390. int index = -1;
  391. for(PropertiesMap::iterator i = this->Properties.begin();
  392. i != this->Properties.end(); ++i)
  393. {
  394. if(i->second->Name == name)
  395. {
  396. index = i->first;
  397. }
  398. }
  399. return index;
  400. }
  401. //---------------------------------------------------------
  402. void cmCTestMultiProcessHandler::CreateTestCostList()
  403. {
  404. if(this->ParallelLevel > 1)
  405. {
  406. CreateParallelTestCostList();
  407. }
  408. else
  409. {
  410. CreateSerialTestCostList();
  411. }
  412. }
  413. //---------------------------------------------------------
  414. void cmCTestMultiProcessHandler::CreateParallelTestCostList()
  415. {
  416. TestSet alreadySortedTests;
  417. std::list<TestSet> priorityStack;
  418. priorityStack.push_back(TestSet());
  419. TestSet &topLevel = priorityStack.back();
  420. // In parallel test runs add previously failed tests to the front
  421. // of the cost list and queue other tests for further sorting
  422. for(TestMap::const_iterator i = this->Tests.begin();
  423. i != this->Tests.end(); ++i)
  424. {
  425. if(std::find(this->LastTestsFailed.begin(), this->LastTestsFailed.end(),
  426. this->Properties[i->first]->Name) != this->LastTestsFailed.end())
  427. {
  428. //If the test failed last time, it should be run first.
  429. this->SortedTests.push_back(i->first);
  430. alreadySortedTests.insert(i->first);
  431. }
  432. else
  433. {
  434. topLevel.insert(i->first);
  435. }
  436. }
  437. // In parallel test runs repeatedly move dependencies of the tests on
  438. // the current dependency level to the next level until no
  439. // further dependencies exist.
  440. while(priorityStack.back().size())
  441. {
  442. TestSet &previousSet = priorityStack.back();
  443. priorityStack.push_back(TestSet());
  444. TestSet &currentSet = priorityStack.back();
  445. for(TestSet::const_iterator i = previousSet.begin();
  446. i != previousSet.end(); ++i)
  447. {
  448. TestSet const& dependencies = this->Tests[*i];
  449. currentSet.insert(dependencies.begin(), dependencies.end());
  450. }
  451. for(TestSet::const_iterator i = currentSet.begin();
  452. i != currentSet.end(); ++i)
  453. {
  454. previousSet.erase(*i);
  455. }
  456. }
  457. // Remove the empty dependency level
  458. priorityStack.pop_back();
  459. // Reverse iterate over the different dependency levels (deepest first).
  460. // Sort tests within each level by COST and append them to the cost list.
  461. for(std::list<TestSet>::reverse_iterator i = priorityStack.rbegin();
  462. i != priorityStack.rend(); ++i)
  463. {
  464. TestSet const& currentSet = *i;
  465. TestComparator comp(this);
  466. TestList sortedCopy;
  467. sortedCopy.insert(sortedCopy.end(),
  468. currentSet.begin(), currentSet.end());
  469. std::stable_sort(sortedCopy.begin(), sortedCopy.end(), comp);
  470. for(TestList::const_iterator j = sortedCopy.begin();
  471. j != sortedCopy.end(); ++j)
  472. {
  473. if(alreadySortedTests.find(*j) == alreadySortedTests.end())
  474. {
  475. this->SortedTests.push_back(*j);
  476. alreadySortedTests.insert(*j);
  477. }
  478. }
  479. }
  480. }
  481. //---------------------------------------------------------
  482. void cmCTestMultiProcessHandler::GetAllTestDependencies(
  483. int test, TestList& dependencies)
  484. {
  485. TestSet const& dependencySet = this->Tests[test];
  486. for(TestSet::const_iterator i = dependencySet.begin();
  487. i != dependencySet.end(); ++i)
  488. {
  489. GetAllTestDependencies(*i, dependencies);
  490. dependencies.push_back(*i);
  491. }
  492. }
  493. //---------------------------------------------------------
  494. void cmCTestMultiProcessHandler::CreateSerialTestCostList()
  495. {
  496. TestList presortedList;
  497. for(TestMap::iterator i = this->Tests.begin();
  498. i != this->Tests.end(); ++i)
  499. {
  500. presortedList.push_back(i->first);
  501. }
  502. TestComparator comp(this);
  503. std::stable_sort(presortedList.begin(), presortedList.end(), comp);
  504. TestSet alreadySortedTests;
  505. for(TestList::const_iterator i = presortedList.begin();
  506. i != presortedList.end(); ++i)
  507. {
  508. int test = *i;
  509. if(alreadySortedTests.find(test) != alreadySortedTests.end())
  510. {
  511. continue;
  512. }
  513. TestList dependencies;
  514. GetAllTestDependencies(test, dependencies);
  515. for(TestList::const_iterator j = dependencies.begin();
  516. j != dependencies.end(); ++j)
  517. {
  518. int testDependency = *j;
  519. if(alreadySortedTests.find(testDependency) == alreadySortedTests.end())
  520. {
  521. alreadySortedTests.insert(testDependency);
  522. this->SortedTests.push_back(testDependency);
  523. }
  524. }
  525. alreadySortedTests.insert(test);
  526. this->SortedTests.push_back(test);
  527. }
  528. }
  529. //---------------------------------------------------------
  530. void cmCTestMultiProcessHandler::WriteCheckpoint(int index)
  531. {
  532. std::string fname = this->CTest->GetBinaryDir()
  533. + "/Testing/Temporary/CTestCheckpoint.txt";
  534. cmsys::ofstream fout;
  535. fout.open(fname.c_str(), std::ios::app);
  536. fout << index << "\n";
  537. fout.close();
  538. }
  539. //---------------------------------------------------------
  540. void cmCTestMultiProcessHandler::MarkFinished()
  541. {
  542. std::string fname = this->CTest->GetBinaryDir()
  543. + "/Testing/Temporary/CTestCheckpoint.txt";
  544. cmSystemTools::RemoveFile(fname);
  545. }
  546. //---------------------------------------------------------
  547. //For ShowOnly mode
  548. void cmCTestMultiProcessHandler::PrintTestList()
  549. {
  550. this->TestHandler->SetMaxIndex(this->FindMaxIndex());
  551. int count = 0;
  552. for (PropertiesMap::iterator it = this->Properties.begin();
  553. it != this->Properties.end(); ++it)
  554. {
  555. count++;
  556. cmCTestTestHandler::cmCTestTestProperties& p = *it->second;
  557. //push working dir
  558. std::string current_dir = cmSystemTools::GetCurrentWorkingDirectory();
  559. cmSystemTools::ChangeDirectory(p.Directory);
  560. cmCTestRunTest testRun(this->TestHandler);
  561. testRun.SetIndex(p.Index);
  562. testRun.SetTestProperties(&p);
  563. testRun.ComputeArguments(); //logs the command in verbose mode
  564. if(!p.Labels.empty()) //print the labels
  565. {
  566. cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Labels:",
  567. this->Quiet);
  568. }
  569. for(std::vector<std::string>::iterator label = p.Labels.begin();
  570. label != p.Labels.end(); ++label)
  571. {
  572. cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " " << *label,
  573. this->Quiet);
  574. }
  575. if(!p.Labels.empty()) //print the labels
  576. {
  577. cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl,
  578. this->Quiet);
  579. }
  580. if (this->TestHandler->MemCheck)
  581. {
  582. cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " Memory Check",
  583. this->Quiet);
  584. }
  585. else
  586. {
  587. cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " Test", this->Quiet);
  588. }
  589. std::ostringstream indexStr;
  590. indexStr << " #" << p.Index << ":";
  591. cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
  592. std::setw(3 + getNumWidth(this->TestHandler->GetMaxIndex()))
  593. << indexStr.str(), this->Quiet);
  594. cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " ", this->Quiet);
  595. cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
  596. p.Name.c_str() << std::endl, this->Quiet);
  597. //pop working dir
  598. cmSystemTools::ChangeDirectory(current_dir);
  599. }
  600. cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, std::endl << "Total Tests: "
  601. << this->Total << std::endl, this->Quiet);
  602. }
  603. void cmCTestMultiProcessHandler::PrintLabels()
  604. {
  605. std::set<std::string> allLabels;
  606. for (PropertiesMap::iterator it = this->Properties.begin();
  607. it != this->Properties.end(); ++it)
  608. {
  609. cmCTestTestHandler::cmCTestTestProperties& p = *it->second;
  610. allLabels.insert(p.Labels.begin(), p.Labels.end());
  611. }
  612. if(!allLabels.empty())
  613. {
  614. cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
  615. "All Labels:" << std::endl, this->Quiet);
  616. }
  617. else
  618. {
  619. cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
  620. "No Labels Exist" << std::endl, this->Quiet);
  621. }
  622. for(std::set<std::string>::iterator label = allLabels.begin();
  623. label != allLabels.end(); ++label)
  624. {
  625. cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
  626. " " << *label << std::endl, this->Quiet);
  627. }
  628. }
  629. //---------------------------------------------------------
  630. void cmCTestMultiProcessHandler::CheckResume()
  631. {
  632. std::string fname = this->CTest->GetBinaryDir()
  633. + "/Testing/Temporary/CTestCheckpoint.txt";
  634. if(this->CTest->GetFailover())
  635. {
  636. if(cmSystemTools::FileExists(fname.c_str(), true))
  637. {
  638. *this->TestHandler->LogFile << "Resuming previously interrupted test set"
  639. << std::endl
  640. << "----------------------------------------------------------"
  641. << std::endl;
  642. cmsys::ifstream fin;
  643. fin.open(fname.c_str());
  644. std::string line;
  645. while(std::getline(fin, line))
  646. {
  647. int index = atoi(line.c_str());
  648. this->RemoveTest(index);
  649. }
  650. fin.close();
  651. }
  652. }
  653. else if(cmSystemTools::FileExists(fname.c_str(), true))
  654. {
  655. cmSystemTools::RemoveFile(fname);
  656. }
  657. }
  658. //---------------------------------------------------------
  659. void cmCTestMultiProcessHandler::RemoveTest(int index)
  660. {
  661. this->EraseTest(index);
  662. this->Properties.erase(index);
  663. this->TestRunningMap[index] = false;
  664. this->TestFinishMap[index] = true;
  665. this->Completed++;
  666. }
  667. //---------------------------------------------------------
  668. int cmCTestMultiProcessHandler::FindMaxIndex()
  669. {
  670. int max = 0;
  671. cmCTestMultiProcessHandler::TestMap::iterator i = this->Tests.begin();
  672. for(; i != this->Tests.end(); ++i)
  673. {
  674. if(i->first > max)
  675. {
  676. max = i->first;
  677. }
  678. }
  679. return max;
  680. }
  681. //Returns true if no cycles exist in the dependency graph
  682. bool cmCTestMultiProcessHandler::CheckCycles()
  683. {
  684. cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  685. "Checking test dependency graph..." << std::endl, this->Quiet);
  686. for(TestMap::iterator it = this->Tests.begin();
  687. it != this->Tests.end(); ++it)
  688. {
  689. //DFS from each element to itself
  690. int root = it->first;
  691. std::set<int> visited;
  692. std::stack<int> s;
  693. s.push(root);
  694. while(!s.empty())
  695. {
  696. int test = s.top();
  697. s.pop();
  698. if(visited.insert(test).second)
  699. {
  700. for(TestSet::iterator d = this->Tests[test].begin();
  701. d != this->Tests[test].end(); ++d)
  702. {
  703. if(*d == root)
  704. {
  705. //cycle exists
  706. cmCTestLog(this->CTest, ERROR_MESSAGE,
  707. "Error: a cycle exists in the test dependency graph "
  708. "for the test \"" << this->Properties[root]->Name <<
  709. "\".\nPlease fix the cycle and run ctest again.\n");
  710. return false;
  711. }
  712. else
  713. {
  714. s.push(*d);
  715. }
  716. }
  717. }
  718. }
  719. }
  720. cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  721. "Checking test dependency graph end" << std::endl, this->Quiet);
  722. return true;
  723. }