Resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Source / CTest / cmCTestMultiProcessHandler.cxx
blobebe81a8b625a1c61aff1c65adf768cd0f7c56c8c
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmCTestMultiProcessHandler.cxx,v $
5 Language: C++
6 Date: $Date: 2009-02-24 22:23:51 $
7 Version: $Revision: 1.5 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmCTestMultiProcessHandler.h"
18 #include "cmProcess.h"
19 #include "cmStandardIncludes.h"
20 #include "cmCTest.h"
23 cmCTestMultiProcessHandler::cmCTestMultiProcessHandler()
25 this->ParallelLevel = 1;
26 this->ProcessId = 0;
28 // Set the tests
29 void
30 cmCTestMultiProcessHandler::SetTests(TestMap& tests,
31 std::map<int,cmStdString>& testNames)
33 // set test run map to false for all
34 for(TestMap::iterator i = this->Tests.begin();
35 i != this->Tests.end(); ++i)
37 this->TestRunningMap[i->first] = false;
38 this->TestFinishMap[i->first] = false;
40 this->Tests = tests;
41 this->TestNames = testNames;
43 // Set the max number of tests that can be run at the same time.
44 void cmCTestMultiProcessHandler::SetParallelLevel(size_t l)
46 this->ParallelLevel = l;
50 void cmCTestMultiProcessHandler::RunTests()
52 this->StartNextTests();
53 while(this->Tests.size() != 0)
55 this->CheckOutput();
56 this->StartNextTests();
58 // let all running tests finish
59 while(this->CheckOutput())
63 for(std::map<int, cmStdString>::iterator i =
64 this->TestOutput.begin();
65 i != this->TestOutput.end(); ++i)
67 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
68 i->second << std::endl);
73 void cmCTestMultiProcessHandler::StartTestProcess(int test)
75 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
76 " test " << test << "\n");
77 this->TestRunningMap[test] = true; // mark the test as running
78 // now remove the test itself
79 this->Tests.erase(test);
80 // now run the test
81 cmProcess* newp = new cmProcess;
82 newp->SetId(this->ProcessId);
83 newp->SetId(test);
84 newp->SetCommand(this->CTestCommand.c_str());
85 std::vector<std::string> args;
86 cmOStringStream width;
87 if(this->CTest->GetMaxTestNameWidth())
89 args.push_back("-W");
90 width << this->CTest->GetMaxTestNameWidth();
91 args.push_back(width.str().c_str());
93 args.push_back("-I");
94 cmOStringStream strm;
95 strm << test << "," << test;
96 args.push_back(strm.str());
97 args.push_back("--parallel-cache");
98 args.push_back(this->CTestCacheFile.c_str());
99 args.push_back("--internal-ctest-parallel");
100 cmOStringStream strm2;
101 strm2 << test;
102 args.push_back(strm2.str());
103 if(this->CTest->GetExtraVerbose())
105 args.push_back("-VV");
107 newp->SetCommandArguments(args);
108 if(!newp->StartProcess())
110 cmCTestLog(this->CTest, ERROR_MESSAGE,
111 "Error starting " << newp->GetCommand() << "\n");
112 this->EndTest(newp);
114 else
116 this->RunningTests.insert(newp);
118 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
119 "ctest -I " << test << "\n");
120 this->ProcessId++;
123 bool cmCTestMultiProcessHandler::StartTest(int test)
125 // copy the depend tests locally because when
126 // a test is finished it will be removed from the depend list
127 // and we don't want to be iterating a list while removing from it
128 TestSet depends = this->Tests[test];
129 size_t totalDepends = depends.size();
130 if(totalDepends)
132 for(TestSet::const_iterator i = depends.begin();
133 i != depends.end(); ++i)
135 // if the test is not already running then start it
136 if(!this->TestRunningMap[*i])
138 // this test might be finished, but since
139 // this is a copy of the depend map we might
140 // still have it
141 if(!this->TestFinishMap[*i])
143 // only start one test in this function
144 return this->StartTest(*i);
146 else
148 // the depend has been and finished
149 totalDepends--;
154 // if there are no depends left then run this test
155 if(totalDepends == 0)
157 // Start this test it has no depends
158 this->StartTestProcess(test);
159 return true;
161 // This test was not able to start because it is waiting
162 // on depends to run
163 return false;
166 void cmCTestMultiProcessHandler::StartNextTests()
168 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl
169 << "Number of running tests : " << this->RunningTests.size()
170 << "\n");
171 size_t numToStart = this->ParallelLevel - this->RunningTests.size();
172 if(numToStart == 0)
174 return;
176 TestMap tests = this->Tests;
177 for(TestMap::iterator i = tests.begin();
178 i != tests.end(); ++i)
180 // start test should start only one test
181 if(this->StartTest(i->first))
183 numToStart--;
185 else
187 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl
188 << "Test did not start waiting on depends to finish: "
189 << i->first << "\n");
191 if(numToStart == 0 )
193 return;
199 bool cmCTestMultiProcessHandler::CheckOutput()
201 // no more output we are done
202 if(this->RunningTests.size() == 0)
204 return false;
206 std::vector<cmProcess*> finished;
207 std::string out, err;
208 for(std::set<cmProcess*>::const_iterator i = this->RunningTests.begin();
209 i != this->RunningTests.end(); ++i)
211 cmProcess* p = *i;
212 int pipe = p->CheckOutput(.1, out, err);
213 if(pipe == cmsysProcess_Pipe_STDOUT)
215 cmCTestLog(this->CTest, HANDLER_OUTPUT,
216 p->GetId() << ": " << out << std::endl);
217 this->TestOutput[ p->GetId() ] += out;
218 this->TestOutput[ p->GetId() ] += "\n";
220 else if(pipe == cmsysProcess_Pipe_STDERR)
222 cmCTestLog(this->CTest, HANDLER_OUTPUT,
223 p->GetId() << ": " << err << std::endl);
224 this->TestOutput[ p->GetId() ] += err;
225 this->TestOutput[ p->GetId() ] += "\n";
227 if(!p->IsRunning())
229 finished.push_back(p);
232 for( std::vector<cmProcess*>::iterator i = finished.begin();
233 i != finished.end(); ++i)
235 cmProcess* p = *i;
236 this->EndTest(p);
238 return true;
241 void cmCTestMultiProcessHandler::EndTest(cmProcess* p)
243 // Should have a way of getting this stuff from the
244 // launched ctest, maybe a temp file or some extra xml
245 // stuff in the stdout
246 // Need things like Reason and ExecutionTime, Path, etc.
247 int test = p->GetId();
248 int exitVal = p->GetExitValue();
249 cmCTestTestHandler::cmCTestTestResult cres;
250 cres.Properties = 0;
251 cres.ExecutionTime = 0;// ???
252 cres.ReturnValue = exitVal;
253 cres.Status = cmCTestTestHandler::COMPLETED;
254 cres.TestCount = test;
255 cres.Name = this->TestNames[test];
256 cres.Path = "";
257 if(exitVal)
259 cres.Status = cmCTestTestHandler::FAILED;
260 this->Failed->push_back(this->TestNames[test]);
262 else
264 this->Passed->push_back(this->TestNames[test]);
266 this->TestResults->push_back(cres);
267 // remove test from depend of all other tests
268 for(TestMap::iterator i = this->Tests.begin();
269 i!= this->Tests.end(); ++i)
271 i->second.erase(test);
273 this->TestFinishMap[test] = true;
274 this->TestRunningMap[test] = false;
275 this->RunningTests.erase(p);
276 delete p;
277 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
278 "finish test " << test << "\n");
282 void cmCTestMultiProcessHandler::PrintTests()
284 #undef cout
285 for( TestMap::iterator i = this->Tests.begin();
286 i!= this->Tests.end(); ++i)
288 std::cout << "Test " << i->first << " (";
289 for(TestSet::iterator j = i->second.begin();
290 j != i->second.end(); ++j)
292 std::cout << *j << " ";
294 std::cout << ")\n";
298 #if 0
299 int main()
301 cmCTestMultiProcessHandler h;
302 h.SetParallelLevel(4);
303 std::map<int, std::set<int> > tests;
304 std::set<int> depends;
305 for(int i =1; i < 92; i++)
307 tests[i] = depends;
309 depends.clear();
310 depends.insert(45); subprject
311 tests[46] = depends; subproject-stage2
312 depends.clear();
313 depends.insert(55); simpleinstall simpleinstall-s2
314 tests[56] = depends;
315 depends.clear();
316 depends.insert(70); wrapping
317 tests[71] = depends; qtwrapping
318 depends.clear();
319 depends.insert(71); qtwrapping
320 tests[72] = depends; testdriver1
321 depends.clear();
322 depends.insert(72) testdriver1
323 tests[73] = depends; testdriver2
324 depends.clear();
325 depends.insert(73); testdriver2
326 tests[74] = depends; testdriver3
327 depends.clear();
328 depends.insert(79); linkorder1
329 tests[80] = depends; linkorder2
330 h.SetTests(tests);
331 h.PrintTests();
332 h.RunTests();
334 #endif