Index: pkg/barback/lib/src/graph/transform_node.dart |
diff --git a/pkg/barback/lib/src/graph/transform_node.dart b/pkg/barback/lib/src/graph/transform_node.dart |
index 901d79e6074038202b20699f01f3801b037dccec..44b369e0ecd8001d72768508db2693e02882cf70 100644 |
--- a/pkg/barback/lib/src/graph/transform_node.dart |
+++ b/pkg/barback/lib/src/graph/transform_node.dart |
@@ -166,6 +166,18 @@ class TransformNode { |
/// [_State.NEEDS_DECLARE], and always `null` otherwise. |
AggregateTransformController _applyController; |
+ /// The number of secondary inputs that have been requested but not yet |
+ /// produced. |
+ int _pendingSecondaryInputs = 0; |
+ |
+ /// A stopwatch that tracks the total time spent in a transformer's `apply` |
+ /// function. |
+ final _timeInTransformer = new Stopwatch(); |
+ |
+ /// A stopwatch that tracks the time in a transformer's `apply` function spent |
+ /// waiting for [getInput] calls to complete. |
+ final _timeAwaitingInputs = new Stopwatch(); |
+ |
TransformNode(this.classifier, this.transformer, this.key, this._location) { |
_forced = transformer is! DeclaringAggregateTransformer; |
@@ -548,6 +560,8 @@ class TransformNode { |
/// |
/// If an input with [id] cannot be found, throws an [AssetNotFoundException]. |
Future<Asset> getInput(AssetId id) { |
+ _timeAwaitingInputs.start(); |
+ _pendingSecondaryInputs++; |
return phase.previous.getOutput(id).then((node) { |
// Throw if the input isn't found. This ensures the transformer's apply |
// is exited. We'll then catch this and report it through the proper |
@@ -562,6 +576,9 @@ class TransformNode { |
}); |
return node.asset; |
+ }).whenComplete(() { |
+ _pendingSecondaryInputs--; |
+ if (_pendingSecondaryInputs != 0) _timeAwaitingInputs.stop(); |
}); |
} |
@@ -579,8 +596,14 @@ class TransformNode { |
_maybeFinishApplyController(); |
return syncFuture(() { |
+ _timeInTransformer.reset(); |
+ _timeAwaitingInputs.reset(); |
+ _timeInTransformer.start(); |
return transformer.apply(controller.transform); |
}).whenComplete(() { |
+ _timeInTransformer.stop(); |
+ _timeAwaitingInputs.stop(); |
+ |
// Cancel the controller here even if `apply` wasn't interrupted. Since |
// the apply is finished, we want to close out the controller's streams. |
controller.cancel(); |
@@ -600,6 +623,27 @@ class TransformNode { |
if (_state == _State.NEEDS_APPLY) return false; |
if (_state == _State.NEEDS_DECLARE) return false; |
if (controller.loggedError) return true; |
+ |
+ // If the transformer took long enough, log its duration in fine output. |
+ // That way it's not always visible, but users running with "pub serve |
+ // --verbose" can see it. |
+ var ranLong = _timeInTransformer.elapsed > new Duration(seconds: 1); |
+ var ranLongLocally = |
+ _timeInTransformer.elapsed - _timeAwaitingInputs.elapsed > |
+ new Duration(milliseconds: 200); |
+ |
+ // Report the transformer's timing information if it spent more than 0.2s |
+ // doing things other than waiting for its secondary inputs or if it spent |
+ // more than 1s in total. |
+ if (ranLongLocally || ranLong) { |
+ _streams.onLogController.add(new LogEntry( |
+ info, info.primaryId, LogLevel.FINE, |
+ "Took ${niceDuration(_timeInTransformer.elapsed)} " |
+ "(${niceDuration(_timeAwaitingInputs.elapsed)} awaiting " |
+ "secondary inputs).", |
+ null)); |
+ } |
+ |
_handleApplyResults(controller); |
return false; |
}).catchError((error, stackTrace) { |