Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(654)

Side by Side Diff: tools/testing/dart/test_runner.dart

Issue 8729030: Support batch running of dartc tests. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Minor cleanup Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tests/standalone/src/TestRunnerTest.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #library("test_runner"); 5 #library("test_runner");
6 6
7 #import("status_file_parser.dart"); 7 #import("status_file_parser.dart");
8 #import("test_progress.dart"); 8 #import("test_progress.dart");
9 #import("test_suite.dart"); 9 #import("test_suite.dart");
10 10
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 bool get didFail() => exitCode != 0 && !hasCrashed; 94 bool get didFail() => exitCode != 0 && !hasCrashed;
95 95
96 // Reverse result of a negative test. 96 // Reverse result of a negative test.
97 bool get hasFailed() => (testCase.isNegative ? !didFail : didFail); 97 bool get hasFailed() => (testCase.isNegative ? !didFail : didFail);
98 } 98 }
99 99
100 100
101 class RunningProcess { 101 class RunningProcess {
102 Process process; 102 Process process;
103 TestCase testCase; 103 TestCase testCase;
104 int timeout;
105 bool timedOut = false; 104 bool timedOut = false;
106 Date startTime; 105 Date startTime;
107 Timer timeoutTimer; 106 Timer timeoutTimer;
108 List<String> stdout; 107 List<String> stdout;
109 List<String> stderr; 108 List<String> stderr;
110 List<Function> handlers; 109 List<Function> handlers;
111 110
112 RunningProcess(this.testCase, [this.timeout = NO_TIMEOUT]); 111 RunningProcess(this.testCase);
113 112
114 void exitHandler(int exitCode) { 113 void exitHandler(int exitCode) {
115 new TestOutput(testCase, exitCode, timedOut, stdout, 114 new TestOutput(testCase, exitCode, timedOut, stdout,
116 stderr, new Date.now().difference(startTime)); 115 stderr, new Date.now().difference(startTime));
117 process.close(); 116 process.close();
118 timeoutTimer.cancel(); 117 timeoutTimer.cancel();
119 testCase.completed(); 118 testCase.completed();
120 } 119 }
121 120
122 void makeReadHandler(StringInputStream source, List<String> destination) { 121 void makeReadHandler(StringInputStream source, List<String> destination) {
(...skipping 17 matching lines...) Expand all
140 InputStream stdoutStream = process.stdout; 139 InputStream stdoutStream = process.stdout;
141 InputStream stderrStream = process.stderr; 140 InputStream stderrStream = process.stderr;
142 stdout = new List<String>(); 141 stdout = new List<String>();
143 stderr = new List<String>(); 142 stderr = new List<String>();
144 StringInputStream stdoutStringStream = new StringInputStream(stdoutStream); 143 StringInputStream stdoutStringStream = new StringInputStream(stdoutStream);
145 StringInputStream stderrStringStream = new StringInputStream(stderrStream); 144 StringInputStream stderrStringStream = new StringInputStream(stderrStream);
146 stdoutStringStream.dataHandler = 145 stdoutStringStream.dataHandler =
147 makeReadHandler(stdoutStringStream, stdout); 146 makeReadHandler(stdoutStringStream, stdout);
148 stderrStringStream.dataHandler = 147 stderrStringStream.dataHandler =
149 makeReadHandler(stderrStringStream, stderr); 148 makeReadHandler(stderrStringStream, stderr);
150 if (timeout != NO_TIMEOUT) { 149 timeoutTimer = new Timer(timeoutHandler, 1000 * testCase.timeout, false);
151 timeoutTimer = new Timer(timeoutHandler, 1000 * timeout, false);
152 }
153 } 150 }
154 151
155 void timeoutHandler(Timer unusedTimer) { 152 void timeoutHandler(Timer unusedTimer) {
156 timedOut = true; 153 timedOut = true;
157 process.kill(); 154 process.kill();
158 } 155 }
159 } 156 }
160 157
161 158
159 class DartcBatchRunnerProcess {
160 String _executable;
161
162 Process _process;
163 StringInputStream _stdoutStream;
164 StringInputStream _stderrStream;
165
166 TestCase _currentTest;
167 StringBuffer _testStdout;
168 StringBuffer _testStderr;
169 Date _startTime;
170 Timer _timer;
171
172 DartcBatchRunnerProcess(String this._executable) {
173 _startProcess();
174 }
175
176 bool get active() => _currentTest != null;
177
178 void startTest(TestCase testCase) {
179 _startTime = new Date.now();
180 _currentTest = testCase;
181 _testStdout = new List<String>();
182 _testStderr = new List<String>();
183 _stdoutStream.dataHandler = _readOutput(_stdoutStream, _testStdout);
184 _stderrStream.dataHandler = _readOutput(_stderrStream, _testStderr);
185 _timer = new Timer(_timeoutHandler(testCase),
186 testCase.timeout * 1000,
187 false);
188 _process.stdin.write(_createArgumentsLine(testCase.arguments).charCodes());
189 }
190
191 void terminate() {
192 _process.exitHandler = (exitCode) {
193 _process.close();
194 };
195 _process.kill();
196 }
197
198 String _createArgumentsLine(List<String> arguments) {
199 var buffer = new StringBuffer();
200 for (var i = 0; i < arguments.length; i++) {
201 buffer.add("${arguments[i]} ");
202 }
203 buffer.add("\n");
204 return buffer.toString();
205 }
206
207 int _reportResult(String output) {
208 var test = _currentTest;
209 _currentTest = null;
210
211 // output = '>>> TEST {PASS, FAIL, OK, CRASH, FAIL, TIMEOUT}'
212 var outcome = output.split(" ")[2];
213 var exitCode = 0;
214 if (outcome == "CRASH") exitCode = -10;
215 if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1;
216 new TestOutput(test, exitCode, outcome == "TIMEOUT", _testStdout,
217 _testStderr, new Date.now().difference(_startTime));
218 test.completed();
219 }
220
221 void _readOutput(StringInputStream stream, List<String> buffer) {
222 return () {
223 var status;
224 var line = stream.readLine();
225 // Drain the input stream to get the error output.
226 while (line != null) {
227 if (line.startsWith('>>> TEST')) {
228 status = line;
229 } else if (line.startsWith('>>> BATCH START')) {
230 // ignore
231 } else if (line.startsWith('>>> ')) {
232 throw new Exception('Unexpected command from dartc batch runner.');
233 } else {
234 buffer.add(line);
235 }
236 line = stream.readLine();
237 }
238 if (status != null) {
239 _timer.cancel();
240 // For crashing processes, let the exit handler deal with it.
241 if (!status.contains("CRASH")) {
242 _reportResult(status);
243 }
244 }
245 };
246 }
247
248 void _exitHandler(exitCode) {
249 if (_timer != null) _timer.cancel();
250 _process.close();
251 _startProcess();
252 _reportResult(">>> TEST CRASH");
253 }
254
255 void _timeoutHandler(TestCase test) {
256 return (ignore) {
257 _process.exitHandler = (exitCode) {
258 _process.close();
259 _startProcess();
260 _reportResult(">>> TEST TIMEOUT");
261 };
262 _process.kill();
263 };
264 }
265
266 void _startProcess() {
267 _process = new Process(_executable, ['-batch']);
268 _stdoutStream = new StringInputStream(_process.stdout);
269 _stderrStream = new StringInputStream(_process.stderr);
270 _testStdout = new List<String>();
271 _testStderr = new List<String>();
272 _stdoutStream.dataHandler = _readOutput(_stdoutStream, _testStdout);
273 _stderrStream.dataHandler = _readOutput(_stderrStream, _testStderr);
274 _process.exitHandler = _exitHandler;
275 _process.start();
276 }
277 }
278
279
162 class ProcessQueue { 280 class ProcessQueue {
163 int _numProcesses = 0; 281 int _numProcesses = 0;
164 int _activeTestListers = 0; 282 int _activeTestListers = 0;
165 final int _maxProcesses; 283 int _maxProcesses;
166 Queue<TestCase> _tests; 284 Queue<TestCase> _tests;
167 ProgressIndicator _progress; 285 ProgressIndicator _progress;
168 286
287 // For dartc batch processing we keep a list of batch processes for
288 // each of debug and release mode. If dartc tests are run in both
289 // release and debug mode this will spawn many processes but only
290 // half of them will be active at a time.
291 Map<String, List<DartcBatchRunnerProcess>> _batchProcessesMap;
292
169 ProcessQueue(int this._maxProcesses, 293 ProcessQueue(int this._maxProcesses,
170 String progress, 294 String progress,
171 Date start_time) 295 Date start_time)
172 : _tests = new Queue<TestCase>(), 296 : _tests = new Queue<TestCase>(),
173 _progress = new ProgressIndicator.fromName(progress, start_time); 297 _progress = new ProgressIndicator.fromName(progress, start_time),
174 298 _batchProcessesMap = new Map<String, List<DartcBatchRunnerProcess>>() {
175 addTestSuite(TestSuite testSuite) { 299 _maxProcesses = _maxProcesses;
300 }
301
302 void addTestSuite(TestSuite testSuite) {
176 _activeTestListers++; 303 _activeTestListers++;
177 testSuite.forEachTest(_runTest, _testListerDone); 304 testSuite.forEachTest(_runTest, _testListerDone);
178 } 305 }
179 306
180 _testListerDone() { 307 void _testListerDone() {
181 _activeTestListers--; 308 _activeTestListers--;
182 _checkDone(); 309 _checkDone();
183 } 310 }
184 311
185 _checkDone() { 312 void _checkDone() {
186 if (_activeTestListers == 0 && _tests.isEmpty() && _numProcesses == 0) { 313 if (_activeTestListers == 0 && _tests.isEmpty() && _numProcesses == 0) {
314 _terminateDartcBatchRunners();
187 _progress.allDone(); 315 _progress.allDone();
188 } 316 }
189 } 317 }
190 318
191 _runTest(TestCase test) { 319 void _runTest(TestCase test) {
192 _progress.testAdded(); 320 _progress.testAdded();
193 _tests.add(test); 321 _tests.add(test);
194 _tryRunTest(); 322 _tryRunTest();
195 } 323 }
196 324
197 _tryRunTest() { 325 void _terminateDartcBatchRunners() {
326 _batchProcessesMap.forEach((key, value) {
327 for (int i = 0; i < value.length; i++) {
328 value[i].terminate();
329 }
330 });
331 }
332
333 DartcBatchRunnerProcess _getDartcBatchRunnerProcess(TestCase test) {
334 var batchProcesses = _batchProcessesMap[test.executablePath];
335 if (batchProcesses == null) {
336 // Dartc batch processing is heavy. Scale down the number of
337 // concurrent tasks to be no more than the actual number of
338 // processors even when running dartc benchmarks in both debug
339 // and release mode.
340 var processors = new Platform().numberOfProcessors();
341 if (_maxProcesses >= (processors / 2)) {
342 _maxProcesses = (processors / 2).toInt();
343 }
344 batchProcesses = new List<DartcBatchRunnerProcess>(_maxProcesses);
345 _batchProcessesMap[test.executablePath] = batchProcesses;
346 for (int i = 0; i < _maxProcesses; i++) {
347 batchProcesses[i] = new DartcBatchRunnerProcess(test.executablePath);
348 }
349 }
350 for (int i = 0; i < batchProcesses.length; i++) {
351 var runner = batchProcesses[i];
352 if (!runner.active) return runner;
353 }
354 throw new Exception('Unable to find inactive batch runner.');
355 }
356
357 void _tryRunTest() {
198 _checkDone(); 358 _checkDone();
199 if (_numProcesses < _maxProcesses && !_tests.isEmpty()) { 359 if (_numProcesses < _maxProcesses && !_tests.isEmpty()) {
200 TestCase test = _tests.removeFirst(); 360 TestCase test = _tests.removeFirst();
201 _progress.start(test); 361 _progress.start(test);
202 Function oldCallback = test.completedHandler; 362 Function oldCallback = test.completedHandler;
203 Function wrapper = (TestCase test_arg) { 363 Function wrapper = (TestCase test_arg) {
204 _numProcesses--; 364 _numProcesses--;
205 _progress.done(test_arg); 365 _progress.done(test_arg);
206 _tryRunTest(); 366 _tryRunTest();
207 oldCallback(test_arg); 367 oldCallback(test_arg);
208 }; 368 };
209 test.completedHandler = wrapper; 369 test.completedHandler = wrapper;
210 new RunningProcess(test, test.timeout).start(); 370 if (test.executablePath.contains('dartc_test')) {
371 _getDartcBatchRunnerProcess(test).startTest(test);
372 } else {
373 new RunningProcess(test).start();
374 }
211 _numProcesses++; 375 _numProcesses++;
212 } 376 }
213 } 377 }
214 } 378 }
OLDNEW
« no previous file with comments | « tests/standalone/src/TestRunnerTest.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698