| Index: sdk/lib/developer/timeline.dart
|
| diff --git a/sdk/lib/developer/timeline.dart b/sdk/lib/developer/timeline.dart
|
| index 867475f2a14e9d5b3ba27d8528bb835254dc20fa..55de99dbb92317ec1d63e830a1e35a11aa95f040 100644
|
| --- a/sdk/lib/developer/timeline.dart
|
| +++ b/sdk/lib/developer/timeline.dart
|
| @@ -5,6 +5,7 @@
|
| part of dart.developer;
|
|
|
| typedef dynamic TimelineSyncFunction();
|
| +typedef Future TimelineAsyncFunction();
|
|
|
| /// Add to the timeline.
|
| class Timeline {
|
| @@ -36,6 +37,27 @@ class Timeline {
|
| block.finish();
|
| }
|
|
|
| + /// Emit an instant event.
|
| + static void instantSync(String name, {Map arguments}) {
|
| + if (name is! String) {
|
| + throw new ArgumentError.value(name,
|
| + 'name',
|
| + 'Must be a String');
|
| + }
|
| + Map instantArguments = {
|
| + 'isolateNumber': '${Timeline._isolateId}'
|
| + };
|
| + if (arguments is Map) {
|
| + instantArguments.addAll(arguments);
|
| + }
|
| + String argumentsAsJson = JSON.encode(instantArguments);
|
| + _reportInstantEvent(_getTraceClock(),
|
| + 'Dart',
|
| + name,
|
| + argumentsAsJson);
|
| + }
|
| +
|
| +
|
| /// A utility method to time a synchronous [function]. Internally calls
|
| /// [function] bracketed by calls to [startSync] and [finishSync].
|
| static dynamic timeSync(String name,
|
| @@ -54,74 +76,98 @@ class Timeline {
|
| static final int _isolateId = _getIsolateNum();
|
| }
|
|
|
| -/// An asynchronous task on the timeline. Asynchronous tasks can live
|
| -/// longer than the current event and can even be shared between isolates.
|
| -/// An asynchronous task can have many (nested) blocks. To share a
|
| -/// [TimelineTask] across isolates, you must construct a [TimelineTask] in
|
| -/// both isolates using the same [taskId] and [category].
|
| +/// An asynchronous task on the timeline. An asynchronous task can have many
|
| +/// (nested) synchronous operations. Synchronous operations can live longer than
|
| +/// the current isolate event. To pass a [TimelineTask] to another isolate,
|
| +/// you must first call [pass] to get the task id and then construct a new
|
| +/// [TimelineTask] in the other isolate.
|
| class TimelineTask {
|
| /// Create a task. [taskId] will be set by the system.
|
| - /// Optionally you can specify a [category] name.
|
| - TimelineTask({String category: 'Dart'})
|
| - : _taskId = _getNextAsyncId(),
|
| - category = category {
|
| - if (category is! String) {
|
| - throw new ArgumentError.value(category,
|
| - 'category',
|
| - 'Must be a String');
|
| - }
|
| + TimelineTask()
|
| + : _taskId = _getNextAsyncId() {
|
| }
|
|
|
| /// Create a task with an explicit [taskId]. This is useful if you are
|
| - /// passing a task between isolates. Optionally you can specify a [category]
|
| - /// name.
|
| - TimelineTask.withTaskId(int taskId, {String category: 'Dart'})
|
| - : _taskId = taskId,
|
| - category = category {
|
| + /// passing a task from one isolate to another.
|
| + TimelineTask.withTaskId(int taskId)
|
| + : _taskId = taskId {
|
| if (taskId is! int) {
|
| throw new ArgumentError.value(taskId,
|
| 'taskId',
|
| 'Must be an int');
|
| }
|
| - if (category is! String) {
|
| - throw new ArgumentError.value(category,
|
| - 'category',
|
| - 'Must be a String');
|
| - }
|
| }
|
|
|
| - /// Start a block in this task named [name]. Optionally takes
|
| - /// a [Map] of [arguments].
|
| - /// Returns an [AsyncBlock] which is used to finish this block.
|
| - AsyncBlock start(String name, {Map arguments}) {
|
| + /// Start a synchronous operation within this task named [name].
|
| + /// Optionally takes a [Map] of [arguments].
|
| + void start(String name, {Map arguments}) {
|
| if (name is! String) {
|
| throw new ArgumentError.value(name,
|
| 'name',
|
| 'Must be a String');
|
| }
|
| - var block = new AsyncBlock._(name, _taskId, category);
|
| + var block = new _AsyncBlock._(name, _taskId);
|
| if (arguments is Map) {
|
| block.arguments.addAll(arguments);
|
| }
|
| - /// Emit start event.
|
| + _stack.add(block);
|
| block._start();
|
| - return block;
|
| }
|
|
|
| - /// Retrieve the asynchronous task's id. Can be used to construct a
|
| - /// [TimelineTask] in another isolate.
|
| - int get taskId => _taskId;
|
| + /// Emit an instant event for this task.
|
| + void instant(String name, {Map arguments}) {
|
| + if (name is! String) {
|
| + throw new ArgumentError.value(name,
|
| + 'name',
|
| + 'Must be a String');
|
| + }
|
| + Map instantArguments = {
|
| + 'isolateNumber': '${Timeline._isolateId}'
|
| + };
|
| + if (arguments is Map) {
|
| + instantArguments.addAll(arguments);
|
| + }
|
| + String argumentsAsJson = JSON.encode(instantArguments);
|
| + _reportTaskEvent(_getTraceClock(),
|
| + _taskId,
|
| + 'n',
|
| + 'Dart',
|
| + name,
|
| + argumentsAsJson);
|
| + }
|
| +
|
| + /// Finish the last synchronous operation that was started.
|
| + void finish() {
|
| + if (_stack.length == 0) {
|
| + throw new StateError(
|
| + 'Uneven calls to start and finish');
|
| + }
|
| + // Pop top item off of stack.
|
| + var block = _stack.removeLast();
|
| + block._finish();
|
| + }
|
| +
|
| + /// Retrieve the [TimelineTask]'s task id. Will throw an exception if the
|
| + /// stack is not empty.
|
| + int pass() {
|
| + if (_stack.length > 0) {
|
| + throw new StateError(
|
| + 'You cannot pass a TimelineTask without finishing all started '
|
| + 'operations');
|
| + }
|
| + int r = _taskId;
|
| + return r;
|
| + }
|
| +
|
| final int _taskId;
|
| - /// Retrieve the asynchronous task's category. Can be used to construct a
|
| - /// [TimelineTask] in another isolate.
|
| - final String category;
|
| + final List<_AsyncBlock> _stack = [];
|
| }
|
|
|
| /// An asynchronous block of time on the timeline. This block can be kept
|
| /// open across isolate messages.
|
| -class AsyncBlock {
|
| +class _AsyncBlock {
|
| /// The category this block belongs to.
|
| - final String category;
|
| + final String category = 'Dart';
|
| /// The name of this block.
|
| final String name;
|
| /// The asynchronous task id.
|
| @@ -129,9 +175,8 @@ class AsyncBlock {
|
| /// An (optional) set of arguments which will be serialized to JSON and
|
| /// associated with this block.
|
| final Map arguments = {};
|
| - bool _finished = false;
|
|
|
| - AsyncBlock._(this.name, this._taskId, this.category);
|
| + _AsyncBlock._(this.name, this._taskId);
|
|
|
| // Emit the start event.
|
| void _start() {
|
| @@ -154,29 +199,6 @@ class AsyncBlock {
|
| name,
|
| JSON.encode({}));
|
| }
|
| -
|
| - /// Finish this block. Cannot be called twice.
|
| - void finish() {
|
| - if (_finished) {
|
| - throw new StateError(
|
| - 'It is illegal to call finish twice on the same AsyncBlock');
|
| - }
|
| - _finished = true;
|
| - _finish();
|
| - }
|
| -
|
| - /// Finishes this block when [future] completes. Returns a [Future]
|
| - /// chained to [future].
|
| - Future finishWhenComplete(Future future) {
|
| - if (future is! Future) {
|
| - throw new ArgumentError.value(future,
|
| - 'future',
|
| - 'Must be a Future');
|
| - }
|
| - return future.whenComplete(() {
|
| - finish();
|
| - });
|
| - }
|
| }
|
|
|
| /// A synchronous block of time on the timeline. This block should not be
|
| @@ -237,3 +259,9 @@ external void _reportCompleteEvent(int start,
|
| String category,
|
| String name,
|
| String argumentsAsJson);
|
| +
|
| +/// Reports an instant event.
|
| +external void _reportInstantEvent(int start,
|
| + String category,
|
| + String name,
|
| + String argumentsAsJson);
|
|
|