| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 part of dart.developer; | 5 part of dart.developer; |
| 6 | 6 |
| 7 typedef dynamic TimelineSyncFunction(); | 7 typedef dynamic TimelineSyncFunction(); |
| 8 typedef Future TimelineAsyncFunction(); |
| 8 | 9 |
| 9 /// Add to the timeline. | 10 /// Add to the timeline. |
| 10 class Timeline { | 11 class Timeline { |
| 11 /// Start a synchronous operation labeled [name]. Optionally takes | 12 /// Start a synchronous operation labeled [name]. Optionally takes |
| 12 /// a [Map] of [arguments]. This operation must be finished before | 13 /// a [Map] of [arguments]. This operation must be finished before |
| 13 /// returning to the event queue. | 14 /// returning to the event queue. |
| 14 static void startSync(String name, {Map arguments}) { | 15 static void startSync(String name, {Map arguments}) { |
| 15 if (name is! String) { | 16 if (name is! String) { |
| 16 throw new ArgumentError.value(name, | 17 throw new ArgumentError.value(name, |
| 17 'name', | 18 'name', |
| (...skipping 11 matching lines...) Expand all Loading... |
| 29 if (_stack.length == 0) { | 30 if (_stack.length == 0) { |
| 30 throw new StateError( | 31 throw new StateError( |
| 31 'Uneven calls to startSync and finishSync'); | 32 'Uneven calls to startSync and finishSync'); |
| 32 } | 33 } |
| 33 // Pop top item off of stack. | 34 // Pop top item off of stack. |
| 34 var block = _stack.removeLast(); | 35 var block = _stack.removeLast(); |
| 35 // Finish it. | 36 // Finish it. |
| 36 block.finish(); | 37 block.finish(); |
| 37 } | 38 } |
| 38 | 39 |
| 40 /// Emit an instant event. |
| 41 static void instantSync(String name, {Map arguments}) { |
| 42 if (name is! String) { |
| 43 throw new ArgumentError.value(name, |
| 44 'name', |
| 45 'Must be a String'); |
| 46 } |
| 47 Map instantArguments = { |
| 48 'isolateNumber': '${Timeline._isolateId}' |
| 49 }; |
| 50 if (arguments is Map) { |
| 51 instantArguments.addAll(arguments); |
| 52 } |
| 53 String argumentsAsJson = JSON.encode(instantArguments); |
| 54 _reportInstantEvent(_getTraceClock(), |
| 55 'Dart', |
| 56 name, |
| 57 argumentsAsJson); |
| 58 } |
| 59 |
| 60 |
| 39 /// A utility method to time a synchronous [function]. Internally calls | 61 /// A utility method to time a synchronous [function]. Internally calls |
| 40 /// [function] bracketed by calls to [startSync] and [finishSync]. | 62 /// [function] bracketed by calls to [startSync] and [finishSync]. |
| 41 static dynamic timeSync(String name, | 63 static dynamic timeSync(String name, |
| 42 TimelineSyncFunction function, | 64 TimelineSyncFunction function, |
| 43 {Map arguments}) { | 65 {Map arguments}) { |
| 44 startSync(name, arguments: arguments); | 66 startSync(name, arguments: arguments); |
| 45 try { | 67 try { |
| 46 return function(); | 68 return function(); |
| 47 } finally { | 69 } finally { |
| 48 finishSync(); | 70 finishSync(); |
| 49 } | 71 } |
| 50 } | 72 } |
| 51 | 73 |
| 52 static final List<_SyncBlock> _stack = new List<_SyncBlock>(); | 74 static final List<_SyncBlock> _stack = new List<_SyncBlock>(); |
| 53 | 75 |
| 54 static final int _isolateId = _getIsolateNum(); | 76 static final int _isolateId = _getIsolateNum(); |
| 55 } | 77 } |
| 56 | 78 |
| 57 /// An asynchronous task on the timeline. Asynchronous tasks can live | 79 /// An asynchronous task on the timeline. An asynchronous task can have many |
| 58 /// longer than the current event and can even be shared between isolates. | 80 /// (nested) synchronous operations. Synchronous operations can live longer than |
| 59 /// An asynchronous task can have many (nested) blocks. To share a | 81 /// the current isolate event. To pass a [TimelineTask] to another isolate, |
| 60 /// [TimelineTask] across isolates, you must construct a [TimelineTask] in | 82 /// you must first call [pass] to get the task id and then construct a new |
| 61 /// both isolates using the same [taskId] and [category]. | 83 /// [TimelineTask] in the other isolate. |
| 62 class TimelineTask { | 84 class TimelineTask { |
| 63 /// Create a task. [taskId] will be set by the system. | 85 /// Create a task. [taskId] will be set by the system. |
| 64 /// Optionally you can specify a [category] name. | 86 TimelineTask() |
| 65 TimelineTask({String category: 'Dart'}) | 87 : _taskId = _getNextAsyncId() { |
| 66 : _taskId = _getNextAsyncId(), | |
| 67 category = category { | |
| 68 if (category is! String) { | |
| 69 throw new ArgumentError.value(category, | |
| 70 'category', | |
| 71 'Must be a String'); | |
| 72 } | |
| 73 } | 88 } |
| 74 | 89 |
| 75 /// Create a task with an explicit [taskId]. This is useful if you are | 90 /// Create a task with an explicit [taskId]. This is useful if you are |
| 76 /// passing a task between isolates. Optionally you can specify a [category] | 91 /// passing a task from one isolate to another. |
| 77 /// name. | 92 TimelineTask.withTaskId(int taskId) |
| 78 TimelineTask.withTaskId(int taskId, {String category: 'Dart'}) | 93 : _taskId = taskId { |
| 79 : _taskId = taskId, | |
| 80 category = category { | |
| 81 if (taskId is! int) { | 94 if (taskId is! int) { |
| 82 throw new ArgumentError.value(taskId, | 95 throw new ArgumentError.value(taskId, |
| 83 'taskId', | 96 'taskId', |
| 84 'Must be an int'); | 97 'Must be an int'); |
| 85 } | 98 } |
| 86 if (category is! String) { | |
| 87 throw new ArgumentError.value(category, | |
| 88 'category', | |
| 89 'Must be a String'); | |
| 90 } | |
| 91 } | 99 } |
| 92 | 100 |
| 93 /// Start a block in this task named [name]. Optionally takes | 101 /// Start a synchronous operation within this task named [name]. |
| 94 /// a [Map] of [arguments]. | 102 /// Optionally takes a [Map] of [arguments]. |
| 95 /// Returns an [AsyncBlock] which is used to finish this block. | 103 void start(String name, {Map arguments}) { |
| 96 AsyncBlock start(String name, {Map arguments}) { | |
| 97 if (name is! String) { | 104 if (name is! String) { |
| 98 throw new ArgumentError.value(name, | 105 throw new ArgumentError.value(name, |
| 99 'name', | 106 'name', |
| 100 'Must be a String'); | 107 'Must be a String'); |
| 101 } | 108 } |
| 102 var block = new AsyncBlock._(name, _taskId, category); | 109 var block = new _AsyncBlock._(name, _taskId); |
| 103 if (arguments is Map) { | 110 if (arguments is Map) { |
| 104 block.arguments.addAll(arguments); | 111 block.arguments.addAll(arguments); |
| 105 } | 112 } |
| 106 /// Emit start event. | 113 _stack.add(block); |
| 107 block._start(); | 114 block._start(); |
| 108 return block; | |
| 109 } | 115 } |
| 110 | 116 |
| 111 /// Retrieve the asynchronous task's id. Can be used to construct a | 117 /// Emit an instant event for this task. |
| 112 /// [TimelineTask] in another isolate. | 118 void instant(String name, {Map arguments}) { |
| 113 int get taskId => _taskId; | 119 if (name is! String) { |
| 120 throw new ArgumentError.value(name, |
| 121 'name', |
| 122 'Must be a String'); |
| 123 } |
| 124 Map instantArguments = { |
| 125 'isolateNumber': '${Timeline._isolateId}' |
| 126 }; |
| 127 if (arguments is Map) { |
| 128 instantArguments.addAll(arguments); |
| 129 } |
| 130 String argumentsAsJson = JSON.encode(instantArguments); |
| 131 _reportTaskEvent(_getTraceClock(), |
| 132 _taskId, |
| 133 'n', |
| 134 'Dart', |
| 135 name, |
| 136 argumentsAsJson); |
| 137 } |
| 138 |
| 139 /// Finish the last synchronous operation that was started. |
| 140 void finish() { |
| 141 if (_stack.length == 0) { |
| 142 throw new StateError( |
| 143 'Uneven calls to start and finish'); |
| 144 } |
| 145 // Pop top item off of stack. |
| 146 var block = _stack.removeLast(); |
| 147 block._finish(); |
| 148 } |
| 149 |
| 150 /// Retrieve the [TimelineTask]'s task id. Will throw an exception if the |
| 151 /// stack is not empty. |
| 152 int pass() { |
| 153 if (_stack.length > 0) { |
| 154 throw new StateError( |
| 155 'You cannot pass a TimelineTask without finishing all started ' |
| 156 'operations'); |
| 157 } |
| 158 int r = _taskId; |
| 159 return r; |
| 160 } |
| 161 |
| 114 final int _taskId; | 162 final int _taskId; |
| 115 /// Retrieve the asynchronous task's category. Can be used to construct a | 163 final List<_AsyncBlock> _stack = []; |
| 116 /// [TimelineTask] in another isolate. | |
| 117 final String category; | |
| 118 } | 164 } |
| 119 | 165 |
| 120 /// An asynchronous block of time on the timeline. This block can be kept | 166 /// An asynchronous block of time on the timeline. This block can be kept |
| 121 /// open across isolate messages. | 167 /// open across isolate messages. |
| 122 class AsyncBlock { | 168 class _AsyncBlock { |
| 123 /// The category this block belongs to. | 169 /// The category this block belongs to. |
| 124 final String category; | 170 final String category = 'Dart'; |
| 125 /// The name of this block. | 171 /// The name of this block. |
| 126 final String name; | 172 final String name; |
| 127 /// The asynchronous task id. | 173 /// The asynchronous task id. |
| 128 final int _taskId; | 174 final int _taskId; |
| 129 /// An (optional) set of arguments which will be serialized to JSON and | 175 /// An (optional) set of arguments which will be serialized to JSON and |
| 130 /// associated with this block. | 176 /// associated with this block. |
| 131 final Map arguments = {}; | 177 final Map arguments = {}; |
| 132 bool _finished = false; | |
| 133 | 178 |
| 134 AsyncBlock._(this.name, this._taskId, this.category); | 179 _AsyncBlock._(this.name, this._taskId); |
| 135 | 180 |
| 136 // Emit the start event. | 181 // Emit the start event. |
| 137 void _start() { | 182 void _start() { |
| 138 arguments['isolateNumber'] = '${Timeline._isolateId}'; | 183 arguments['isolateNumber'] = '${Timeline._isolateId}'; |
| 139 String argumentsAsJson = JSON.encode(arguments); | 184 String argumentsAsJson = JSON.encode(arguments); |
| 140 _reportTaskEvent(_getTraceClock(), | 185 _reportTaskEvent(_getTraceClock(), |
| 141 _taskId, | 186 _taskId, |
| 142 'b', | 187 'b', |
| 143 category, | 188 category, |
| 144 name, | 189 name, |
| 145 argumentsAsJson); | 190 argumentsAsJson); |
| 146 } | 191 } |
| 147 | 192 |
| 148 // Emit the finish event. | 193 // Emit the finish event. |
| 149 void _finish() { | 194 void _finish() { |
| 150 _reportTaskEvent(_getTraceClock(), | 195 _reportTaskEvent(_getTraceClock(), |
| 151 _taskId, | 196 _taskId, |
| 152 'e', | 197 'e', |
| 153 category, | 198 category, |
| 154 name, | 199 name, |
| 155 JSON.encode({})); | 200 JSON.encode({})); |
| 156 } | 201 } |
| 157 | |
| 158 /// Finish this block. Cannot be called twice. | |
| 159 void finish() { | |
| 160 if (_finished) { | |
| 161 throw new StateError( | |
| 162 'It is illegal to call finish twice on the same AsyncBlock'); | |
| 163 } | |
| 164 _finished = true; | |
| 165 _finish(); | |
| 166 } | |
| 167 | |
| 168 /// Finishes this block when [future] completes. Returns a [Future] | |
| 169 /// chained to [future]. | |
| 170 Future finishWhenComplete(Future future) { | |
| 171 if (future is! Future) { | |
| 172 throw new ArgumentError.value(future, | |
| 173 'future', | |
| 174 'Must be a Future'); | |
| 175 } | |
| 176 return future.whenComplete(() { | |
| 177 finish(); | |
| 178 }); | |
| 179 } | |
| 180 } | 202 } |
| 181 | 203 |
| 182 /// A synchronous block of time on the timeline. This block should not be | 204 /// A synchronous block of time on the timeline. This block should not be |
| 183 /// kept open across isolate messages. | 205 /// kept open across isolate messages. |
| 184 class _SyncBlock { | 206 class _SyncBlock { |
| 185 /// The category this block belongs to. | 207 /// The category this block belongs to. |
| 186 final String category = 'Dart'; | 208 final String category = 'Dart'; |
| 187 /// The name of this block. | 209 /// The name of this block. |
| 188 final String name; | 210 final String name; |
| 189 /// An (optional) set of arguments which will be serialized to JSON and | 211 /// An (optional) set of arguments which will be serialized to JSON and |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 230 String category, | 252 String category, |
| 231 String name, | 253 String name, |
| 232 String argumentsAsJson); | 254 String argumentsAsJson); |
| 233 | 255 |
| 234 /// Reports a complete synchronous event. | 256 /// Reports a complete synchronous event. |
| 235 external void _reportCompleteEvent(int start, | 257 external void _reportCompleteEvent(int start, |
| 236 int end, | 258 int end, |
| 237 String category, | 259 String category, |
| 238 String name, | 260 String name, |
| 239 String argumentsAsJson); | 261 String argumentsAsJson); |
| 262 |
| 263 /// Reports an instant event. |
| 264 external void _reportInstantEvent(int start, |
| 265 String category, |
| 266 String name, |
| 267 String argumentsAsJson); |
| OLD | NEW |