| Index: tools/full-coverage.dart
|
| diff --git a/tools/full-coverage.dart b/tools/full-coverage.dart
|
| index b16f94459c82d4602d5b74a9ccb4642089046721..0fe6e6fed2ee18d820cf401e27073d8dd7411310 100644
|
| --- a/tools/full-coverage.dart
|
| +++ b/tools/full-coverage.dart
|
| @@ -6,7 +6,6 @@ import "dart:async";
|
| import "dart:convert";
|
| import "dart:io";
|
| import "dart:isolate";
|
| -import "dart:mirrors";
|
|
|
| import "package:args/args.dart";
|
| import "package:path/path.dart";
|
| @@ -189,7 +188,7 @@ Map createHitmap(String rawJson, Resolver resolver) {
|
| hitMap[source][line] += count;
|
| }
|
|
|
| - JSON.decode(rawJson).forEach((Map e) {
|
| + JSON.decode(rawJson)['coverage'].forEach((Map e) {
|
| String source = resolver.resolve(e["source"]);
|
| if (source == null) {
|
| // Couldnt resolve import, so skip this entry.
|
| @@ -255,58 +254,79 @@ List filesToProcess(String absPath) {
|
| return [new File(absPath)];
|
| }
|
|
|
| -worker() {
|
| +worker(WorkMessage msg) {
|
| final start = new DateTime.now().millisecondsSinceEpoch;
|
| - String me = currentMirrorSystem().isolate.debugName;
|
|
|
| - port.receive((Message message, reply) {
|
| - if (message.type == Message.SHUTDOWN) {
|
| - port.close();
|
| + var env = msg.environment;
|
| + List files = msg.files;
|
| + Resolver resolver = new Resolver(env);
|
| + var workerHitmap = {};
|
| + files.forEach((File fileEntry) {
|
| + // Read file sync, as it only contains 1 object.
|
| + String contents = fileEntry.readAsStringSync();
|
| + if (contents.length > 0) {
|
| + mergeHitmaps(createHitmap(contents, resolver), workerHitmap);
|
| }
|
| + });
|
|
|
| - if (message.type == Message.WORK) {
|
| - var env = message.payload[0];
|
| - List files = message.payload[1];
|
| - Resolver resolver = new Resolver(env);
|
| - var workerHitmap = {};
|
| - files.forEach((File fileEntry) {
|
| - // Read file sync, as it only contains 1 object.
|
| - String contents = fileEntry.readAsStringSync();
|
| - if (contents.length > 0) {
|
| - mergeHitmaps(createHitmap(contents, resolver), workerHitmap);
|
| - }
|
| - });
|
| - if (env["verbose"]) {
|
| - final end = new DateTime.now().millisecondsSinceEpoch;
|
| - print("worker[${me}]: Finished processing files. "
|
| - "Took ${end - start} ms.");
|
| - }
|
| - reply.send(new Message(Message.RESULT, [workerHitmap, resolver.failed]));
|
| - }
|
| + if (env["verbose"]) {
|
| + final end = new DateTime.now().millisecondsSinceEpoch;
|
| + print("${msg.workerName}: Finished processing files. "
|
| + "Took ${end - start} ms.");
|
| + }
|
|
|
| - });
|
| + msg.replyPort.send(new ResultMessage(workerHitmap, resolver.failed));
|
| }
|
|
|
| -class Message {
|
| - static const int SHUTDOWN = 1;
|
| - static const int RESULT = 2;
|
| - static const int WORK = 3;
|
| -
|
| - final int type;
|
| - final payload;
|
| +class WorkMessage {
|
| + final String workerName;
|
| + final Map environment;
|
| + final List files;
|
| + final SendPort replyPort;
|
| + WorkMessage(this.workerName, this.environment, this.files, this.replyPort);
|
| +}
|
|
|
| - Message(this.type, this.payload);
|
| +class ResultMessage {
|
| + final hitmap;
|
| + final failedResolves;
|
| + ResultMessage(this.hitmap, this.failedResolves);
|
| }
|
|
|
| final env = new Environment();
|
|
|
| +List<List> split(List list, int nBuckets) {
|
| + // Leftover goes in the last bucket.
|
| + // TODO(16505): Do a fair split.
|
| + var buckets = new List(nBuckets);
|
| + var bucketSize = list.length ~/ nBuckets;
|
| + var taken = 0;
|
| + for (int i = 0; i < nBuckets; i++) {
|
| + bool lastBucket = i + 1 == nBuckets;
|
| + var start = i * bucketSize;
|
| + var end = lastBucket ? list.length : start + bucketSize ;
|
| + buckets[i] = list.sublist(start, end);
|
| + taken += buckets[i].length;
|
| + }
|
| + if (taken != list.length) throw "Error splitting";
|
| + return buckets;
|
| +}
|
| +
|
| +Future<ResultMessage> spawnWorker(name, environment, files) {
|
| + RawReceivePort port = new RawReceivePort();
|
| + var completer = new Completer();
|
| + port.handler = ((ResultMessage msg) {
|
| + completer.complete(msg);
|
| + port.close();
|
| + });
|
| + var msg = new WorkMessage(name, environment, files, port.sendPort);
|
| + Isolate.spawn(worker, msg);
|
| + return completer.future;
|
| +}
|
| +
|
| main(List<String> arguments) {
|
| parseArgs(arguments);
|
|
|
| List files = filesToProcess(env.input);
|
| - int filesPerWorker = files.length ~/ env.workers;
|
| - List workerPorts = [];
|
| - int doneCnt = 0;
|
|
|
| List failedResolves = [];
|
| List failedLoads = [];
|
| @@ -321,57 +341,6 @@ main(List<String> arguments) {
|
| print(" package-root: ${env.pkgRoot}");
|
| }
|
|
|
| - port.receive((Message message, reply) {
|
| - if (message.type == Message.RESULT) {
|
| - mergeHitmaps(message.payload[0], globalHitmap);
|
| - failedResolves.addAll(message.payload[1]);
|
| - doneCnt++;
|
| - }
|
| -
|
| - // All workers are done. Process the data.
|
| - if (doneCnt == env.workers) {
|
| - workerPorts.forEach((p) => p.send(new Message(Message.SHUTDOWN, null)));
|
| - if (env.verbose) {
|
| - final end = new DateTime.now().millisecondsSinceEpoch;
|
| - print("Done creating a global hitmap. Took ${end - start} ms.");
|
| - }
|
| -
|
| - Future out;
|
| - if (env.prettyPrint) {
|
| - out = prettyPrint(globalHitmap, failedLoads);
|
| - }
|
| - if (env.lcov) {
|
| - out = lcov(globalHitmap);
|
| - }
|
| -
|
| - out.then((_) {
|
| - env.output.close().then((_) {
|
| - if (env.verbose) {
|
| - final end = new DateTime.now().millisecondsSinceEpoch;
|
| - print("Done flushing output. Took ${end - start} ms.");
|
| - }
|
| - });
|
| - port.close();
|
| -
|
| - if (env.verbose) {
|
| - if (failedResolves.length > 0) {
|
| - print("Failed to resolve:");
|
| - failedResolves.toSet().forEach((e) {
|
| - print(" ${e}");
|
| - });
|
| - }
|
| - if (failedLoads.length > 0) {
|
| - print("Failed to load:");
|
| - failedLoads.toSet().forEach((e) {
|
| - print(" ${e}");
|
| - });
|
| - }
|
| - }
|
| -
|
| - });
|
| - }
|
| - });
|
| -
|
| Map sharedEnv = {
|
| "sdkRoot": env.sdkRoot,
|
| "pkgRoot": env.pkgRoot,
|
| @@ -379,22 +348,54 @@ main(List<String> arguments) {
|
| };
|
|
|
| // Create workers.
|
| - for (var i = 1; i < env.workers; i++) {
|
| - var p = spawnFunction(worker);
|
| - workerPorts.add(p);
|
| - var start = files.length - filesPerWorker;
|
| - var end = files.length;
|
| - var workerFiles = files.getRange(start, end).toList();
|
| - files.removeRange(start, end);
|
| - p.send(new Message(Message.WORK, [sharedEnv, workerFiles]), port);
|
| - }
|
| - // Let the last worker deal with the rest of the files (which should be only
|
| - // off by at max (#workers - 1).
|
| - var p = spawnFunction(worker);
|
| - workerPorts.add(p);
|
| - p.send(new Message(Message.WORK, [sharedEnv, files]), port.toSendPort());
|
| + int workerId = 0;
|
| + var results = split(files, env.workers).map((workerFiles) {
|
| + var result = spawnWorker("Worker ${workerId++}", sharedEnv, workerFiles);
|
| + return result.then((ResultMessage message) {
|
| + mergeHitmaps(message.hitmap, globalHitmap);
|
| + failedResolves.addAll(message.failedResolves);
|
| + });
|
| + });
|
| +
|
| + Future.wait(results).then((ignore) {
|
| + // All workers are done. Process the data.
|
| + if (env.verbose) {
|
| + final end = new DateTime.now().millisecondsSinceEpoch;
|
| + print("Done creating a global hitmap. Took ${end - start} ms.");
|
| + }
|
| +
|
| + Future out;
|
| + if (env.prettyPrint) {
|
| + out = prettyPrint(globalHitmap, failedLoads);
|
| + }
|
| + if (env.lcov) {
|
| + out = lcov(globalHitmap);
|
| + }
|
|
|
| - return 0;
|
| + out.then((_) {
|
| + env.output.close().then((_) {
|
| + if (env.verbose) {
|
| + final end = new DateTime.now().millisecondsSinceEpoch;
|
| + print("Done flushing output. Took ${end - start} ms.");
|
| + }
|
| + });
|
| +
|
| + if (env.verbose) {
|
| + if (failedResolves.length > 0) {
|
| + print("Failed to resolve:");
|
| + failedResolves.toSet().forEach((e) {
|
| + print(" ${e}");
|
| + });
|
| + }
|
| + if (failedLoads.length > 0) {
|
| + print("Failed to load:");
|
| + failedLoads.toSet().forEach((e) {
|
| + print(" ${e}");
|
| + });
|
| + }
|
| + }
|
| + });
|
| + });
|
| }
|
|
|
| /// Checks the validity of the provided arguments. Does not initialize actual
|
|
|