// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. library MandelIsolateTest; import 'dart:async'; import 'dart:isolate'; import 'dart:math'; import 'package:unittest/unittest.dart'; import "remote_unittest_helper.dart"; const TERMINATION_MESSAGE = -1; const N = 100; const ISOLATES = 20; void main([args, port]) { if (testRemote(main, port)) return; // Test is really slow in debug builds of the VM. var configuration = unittestConfiguration; configuration.timeout = const Duration(seconds: 480); test("Render Mandelbrot in parallel", () { final state = new MandelbrotState(); state._validated.future.then(expectAsync((result) { expect(result, isTrue); })); for (int i = 0; i < min(ISOLATES, N); i++) state.startClient(i); }); } class MandelbrotState { MandelbrotState() { _result = new List>(N); _lineProcessedBy = new List(N); _sent = 0; _missing = N; _validated = new Completer(); } void startClient(int id) { assert(_sent < N); int line = _sent++; LineProcessorClient.create(this, id).then((final client) { client.processLine(line); }); } void notifyProcessedLine(LineProcessorClient client, int y, List line) { assert(_result[y] == null); _result[y] = line; _lineProcessedBy[y] = client; if (_sent != N) { client.processLine(_sent++); } else { client.shutdown(); } // If all lines have been computed, validate the result. if (--_missing == 0) { _printResult(); _validateResult(); } } void _validateResult() { // TODO(ngeoffray): Implement this. _validated.complete(true); } void _printResult() { var output = new StringBuffer(); for (int i = 0; i < _result.length; i++) { List line = _result[i]; for (int j = 0; j < line.length; j++) { if (line[j] < 10) output.write("0"); output.write(line[j]); } output.write("\n"); } // print(output); } List> _result; List _lineProcessedBy; int _sent; int _missing; Completer _validated; } class LineProcessorClient { MandelbrotState _state; int _id; SendPort _port; LineProcessorClient(this._state, this._id, this._port); static Future create(MandelbrotState state, int id) { ReceivePort reply = new ReceivePort(); return Isolate.spawn(processLines, reply.sendPort).then((_) { return reply.first.then((port) { return new LineProcessorClient(state, id, port); }); }); } void processLine(int y) { ReceivePort reply = new ReceivePort(); _port.send([y, reply.sendPort]); reply.first.then((List message) { _state.notifyProcessedLine(this, y, message); }); } void shutdown() { _port.send(TERMINATION_MESSAGE); } } List processLine(int y) { double inverseN = 2.0 / N; double Civ = y * inverseN - 1.0; List result = new List(N); for (int x = 0; x < N; x++) { double Crv = x * inverseN - 1.5; double Zrv = Crv; double Ziv = Civ; double Trv = Crv * Crv; double Tiv = Civ * Civ; int i = 49; do { Ziv = (Zrv * Ziv) + (Zrv * Ziv) + Civ; Zrv = Trv - Tiv + Crv; Trv = Zrv * Zrv; Tiv = Ziv * Ziv; } while (((Trv + Tiv) <= 4.0) && (--i > 0)); result[x] = i; } return result; } void processLines(SendPort replyPort) { ReceivePort port = new ReceivePort(); port.listen((message) { if (message != TERMINATION_MESSAGE) { int line = message[0]; SendPort replyTo = message[1]; replyTo.send(processLine(line)); } else { port.close(); } }); replyPort.send(port.sendPort); }