| 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 const bool _isProduct = const bool.fromEnvironment("dart.vm.product"); | 7 const bool _isProduct = const bool.fromEnvironment("dart.vm.product"); |
| 8 | 8 |
| 9 typedef dynamic TimelineSyncFunction(); | 9 typedef dynamic TimelineSyncFunction(); |
| 10 typedef Future TimelineAsyncFunction(); | 10 typedef Future TimelineAsyncFunction(); |
| 11 | 11 |
| 12 /// Add to the timeline. | 12 /// Add to the timeline. |
| 13 class Timeline { | 13 class Timeline { |
| 14 /// Start a synchronous operation labeled [name]. Optionally takes | 14 /// Start a synchronous operation labeled [name]. Optionally takes |
| 15 /// a [Map] of [arguments]. This operation must be finished before | 15 /// a [Map] of [arguments]. This operation must be finished before |
| 16 /// returning to the event queue. | 16 /// returning to the event queue. |
| 17 static void startSync(String name, {Map arguments}) { | 17 static void startSync(String name, {Map arguments}) { |
| 18 if (_isProduct) { | 18 if (_isProduct) { |
| 19 return; | 19 return; |
| 20 } | 20 } |
| 21 if (name is! String) { | 21 if (name is! String) { |
| 22 throw new ArgumentError.value(name, | 22 throw new ArgumentError.value(name, 'name', 'Must be a String'); |
| 23 'name', | |
| 24 'Must be a String'); | |
| 25 } | 23 } |
| 26 if (!_isDartStreamEnabled()) { | 24 if (!_isDartStreamEnabled()) { |
| 27 // Push a null onto the stack and return. | 25 // Push a null onto the stack and return. |
| 28 _stack.add(null); | 26 _stack.add(null); |
| 29 return; | 27 return; |
| 30 } | 28 } |
| 31 var block = new _SyncBlock._(name, _getTraceClock(), _getThreadCpuClock()); | 29 var block = new _SyncBlock._(name, _getTraceClock(), _getThreadCpuClock()); |
| 32 if (arguments is Map) { | 30 if (arguments is Map) { |
| 33 block._appendArguments(arguments); | 31 block._appendArguments(arguments); |
| 34 } | 32 } |
| 35 _stack.add(block); | 33 _stack.add(block); |
| 36 } | 34 } |
| 37 | 35 |
| 38 /// Finish the last synchronous operation that was started. | 36 /// Finish the last synchronous operation that was started. |
| 39 static void finishSync() { | 37 static void finishSync() { |
| 40 if (_isProduct) { | 38 if (_isProduct) { |
| 41 return; | 39 return; |
| 42 } | 40 } |
| 43 if (_stack.length == 0) { | 41 if (_stack.length == 0) { |
| 44 throw new StateError( | 42 throw new StateError('Uneven calls to startSync and finishSync'); |
| 45 'Uneven calls to startSync and finishSync'); | |
| 46 } | 43 } |
| 47 // Pop top item off of stack. | 44 // Pop top item off of stack. |
| 48 var block = _stack.removeLast(); | 45 var block = _stack.removeLast(); |
| 49 if (block == null) { | 46 if (block == null) { |
| 50 // Dart stream was disabled when startSync was called. | 47 // Dart stream was disabled when startSync was called. |
| 51 return; | 48 return; |
| 52 } | 49 } |
| 53 // Finish it. | 50 // Finish it. |
| 54 block.finish(); | 51 block.finish(); |
| 55 } | 52 } |
| 56 | 53 |
| 57 /// Emit an instant event. | 54 /// Emit an instant event. |
| 58 static void instantSync(String name, {Map arguments}) { | 55 static void instantSync(String name, {Map arguments}) { |
| 59 if (_isProduct) { | 56 if (_isProduct) { |
| 60 return; | 57 return; |
| 61 } | 58 } |
| 62 if (name is! String) { | 59 if (name is! String) { |
| 63 throw new ArgumentError.value(name, | 60 throw new ArgumentError.value(name, 'name', 'Must be a String'); |
| 64 'name', | |
| 65 'Must be a String'); | |
| 66 } | 61 } |
| 67 if (!_isDartStreamEnabled()) { | 62 if (!_isDartStreamEnabled()) { |
| 68 // Stream is disabled. | 63 // Stream is disabled. |
| 69 return; | 64 return; |
| 70 } | 65 } |
| 71 Map instantArguments; | 66 Map instantArguments; |
| 72 if (arguments is Map) { | 67 if (arguments is Map) { |
| 73 instantArguments = new Map.from(arguments); | 68 instantArguments = new Map.from(arguments); |
| 74 } | 69 } |
| 75 _reportInstantEvent(_getTraceClock(), | 70 _reportInstantEvent( |
| 76 'Dart', | 71 _getTraceClock(), 'Dart', name, _argumentsAsJson(instantArguments)); |
| 77 name, | |
| 78 _argumentsAsJson(instantArguments)); | |
| 79 } | 72 } |
| 80 | 73 |
| 81 | |
| 82 /// A utility method to time a synchronous [function]. Internally calls | 74 /// A utility method to time a synchronous [function]. Internally calls |
| 83 /// [function] bracketed by calls to [startSync] and [finishSync]. | 75 /// [function] bracketed by calls to [startSync] and [finishSync]. |
| 84 static dynamic timeSync(String name, | 76 static dynamic timeSync(String name, TimelineSyncFunction function, |
| 85 TimelineSyncFunction function, | 77 {Map arguments}) { |
| 86 {Map arguments}) { | |
| 87 startSync(name, arguments: arguments); | 78 startSync(name, arguments: arguments); |
| 88 try { | 79 try { |
| 89 return function(); | 80 return function(); |
| 90 } finally { | 81 } finally { |
| 91 finishSync(); | 82 finishSync(); |
| 92 } | 83 } |
| 93 } | 84 } |
| 94 | 85 |
| 95 /// The current time stamp from the clock used by the timeline. Units are | 86 /// The current time stamp from the clock used by the timeline. Units are |
| 96 /// microseconds. | 87 /// microseconds. |
| 97 static int get now => _getTraceClock(); | 88 static int get now => _getTraceClock(); |
| 98 static final List<_SyncBlock> _stack = new List<_SyncBlock>(); | 89 static final List<_SyncBlock> _stack = new List<_SyncBlock>(); |
| 99 static final int _isolateId = _getIsolateNum(); | 90 static final int _isolateId = _getIsolateNum(); |
| 100 static final String _isolateIdString = _isolateId.toString(); | 91 static final String _isolateIdString = _isolateId.toString(); |
| 101 } | 92 } |
| 102 | 93 |
| 103 /// An asynchronous task on the timeline. An asynchronous task can have many | 94 /// An asynchronous task on the timeline. An asynchronous task can have many |
| 104 /// (nested) synchronous operations. Synchronous operations can live longer than | 95 /// (nested) synchronous operations. Synchronous operations can live longer than |
| 105 /// the current isolate event. To pass a [TimelineTask] to another isolate, | 96 /// the current isolate event. To pass a [TimelineTask] to another isolate, |
| 106 /// you must first call [pass] to get the task id and then construct a new | 97 /// you must first call [pass] to get the task id and then construct a new |
| 107 /// [TimelineTask] in the other isolate. | 98 /// [TimelineTask] in the other isolate. |
| 108 class TimelineTask { | 99 class TimelineTask { |
| 109 /// Create a task. [taskId] will be set by the system. | 100 /// Create a task. [taskId] will be set by the system. |
| 110 TimelineTask() | 101 TimelineTask() : _taskId = _getNextAsyncId() {} |
| 111 : _taskId = _getNextAsyncId() { | |
| 112 } | |
| 113 | 102 |
| 114 /// Create a task with an explicit [taskId]. This is useful if you are | 103 /// Create a task with an explicit [taskId]. This is useful if you are |
| 115 /// passing a task from one isolate to another. | 104 /// passing a task from one isolate to another. |
| 116 TimelineTask.withTaskId(int taskId) | 105 TimelineTask.withTaskId(int taskId) : _taskId = taskId { |
| 117 : _taskId = taskId { | |
| 118 if (taskId is! int) { | 106 if (taskId is! int) { |
| 119 throw new ArgumentError.value(taskId, | 107 throw new ArgumentError.value(taskId, 'taskId', 'Must be an int'); |
| 120 'taskId', | |
| 121 'Must be an int'); | |
| 122 } | 108 } |
| 123 } | 109 } |
| 124 | 110 |
| 125 /// Start a synchronous operation within this task named [name]. | 111 /// Start a synchronous operation within this task named [name]. |
| 126 /// Optionally takes a [Map] of [arguments]. | 112 /// Optionally takes a [Map] of [arguments]. |
| 127 void start(String name, {Map arguments}) { | 113 void start(String name, {Map arguments}) { |
| 128 if (_isProduct) { | 114 if (_isProduct) { |
| 129 return; | 115 return; |
| 130 } | 116 } |
| 131 if (name is! String) { | 117 if (name is! String) { |
| 132 throw new ArgumentError.value(name, | 118 throw new ArgumentError.value(name, 'name', 'Must be a String'); |
| 133 'name', | |
| 134 'Must be a String'); | |
| 135 } | 119 } |
| 136 var block = new _AsyncBlock._(name, _taskId); | 120 var block = new _AsyncBlock._(name, _taskId); |
| 137 if (arguments is Map) { | 121 if (arguments is Map) { |
| 138 block._appendArguments(arguments); | 122 block._appendArguments(arguments); |
| 139 } | 123 } |
| 140 _stack.add(block); | 124 _stack.add(block); |
| 141 block._start(); | 125 block._start(); |
| 142 } | 126 } |
| 143 | 127 |
| 144 /// Emit an instant event for this task. | 128 /// Emit an instant event for this task. |
| 145 void instant(String name, {Map arguments}) { | 129 void instant(String name, {Map arguments}) { |
| 146 if (_isProduct) { | 130 if (_isProduct) { |
| 147 return; | 131 return; |
| 148 } | 132 } |
| 149 if (name is! String) { | 133 if (name is! String) { |
| 150 throw new ArgumentError.value(name, | 134 throw new ArgumentError.value(name, 'name', 'Must be a String'); |
| 151 'name', | |
| 152 'Must be a String'); | |
| 153 } | 135 } |
| 154 Map instantArguments; | 136 Map instantArguments; |
| 155 if (arguments is Map) { | 137 if (arguments is Map) { |
| 156 instantArguments = new Map.from(arguments); | 138 instantArguments = new Map.from(arguments); |
| 157 } | 139 } |
| 158 _reportTaskEvent(_getTraceClock(), | 140 _reportTaskEvent(_getTraceClock(), _taskId, 'n', 'Dart', name, |
| 159 _taskId, | 141 _argumentsAsJson(instantArguments)); |
| 160 'n', | |
| 161 'Dart', | |
| 162 name, | |
| 163 _argumentsAsJson(instantArguments)); | |
| 164 } | 142 } |
| 165 | 143 |
| 166 /// Finish the last synchronous operation that was started. | 144 /// Finish the last synchronous operation that was started. |
| 167 void finish() { | 145 void finish() { |
| 168 if (_isProduct) { | 146 if (_isProduct) { |
| 169 return; | 147 return; |
| 170 } | 148 } |
| 171 if (_stack.length == 0) { | 149 if (_stack.length == 0) { |
| 172 throw new StateError( | 150 throw new StateError('Uneven calls to start and finish'); |
| 173 'Uneven calls to start and finish'); | |
| 174 } | 151 } |
| 175 // Pop top item off of stack. | 152 // Pop top item off of stack. |
| 176 var block = _stack.removeLast(); | 153 var block = _stack.removeLast(); |
| 177 block._finish(); | 154 block._finish(); |
| 178 } | 155 } |
| 179 | 156 |
| 180 /// Retrieve the [TimelineTask]'s task id. Will throw an exception if the | 157 /// Retrieve the [TimelineTask]'s task id. Will throw an exception if the |
| 181 /// stack is not empty. | 158 /// stack is not empty. |
| 182 int pass() { | 159 int pass() { |
| 183 if (_stack.length > 0) { | 160 if (_stack.length > 0) { |
| 184 throw new StateError( | 161 throw new StateError( |
| 185 'You cannot pass a TimelineTask without finishing all started ' | 162 'You cannot pass a TimelineTask without finishing all started ' |
| 186 'operations'); | 163 'operations'); |
| 187 } | 164 } |
| 188 int r = _taskId; | 165 int r = _taskId; |
| 189 return r; | 166 return r; |
| 190 } | 167 } |
| 191 | 168 |
| 192 final int _taskId; | 169 final int _taskId; |
| 193 final List<_AsyncBlock> _stack = []; | 170 final List<_AsyncBlock> _stack = []; |
| 194 } | 171 } |
| 195 | 172 |
| 196 /// An asynchronous block of time on the timeline. This block can be kept | 173 /// An asynchronous block of time on the timeline. This block can be kept |
| 197 /// open across isolate messages. | 174 /// open across isolate messages. |
| 198 class _AsyncBlock { | 175 class _AsyncBlock { |
| 199 /// The category this block belongs to. | 176 /// The category this block belongs to. |
| 200 final String category = 'Dart'; | 177 final String category = 'Dart'; |
| 178 |
| 201 /// The name of this block. | 179 /// The name of this block. |
| 202 final String name; | 180 final String name; |
| 181 |
| 203 /// The asynchronous task id. | 182 /// The asynchronous task id. |
| 204 final int _taskId; | 183 final int _taskId; |
| 184 |
| 205 /// An (optional) set of arguments which will be serialized to JSON and | 185 /// An (optional) set of arguments which will be serialized to JSON and |
| 206 /// associated with this block. | 186 /// associated with this block. |
| 207 Map _arguments; | 187 Map _arguments; |
| 208 | 188 |
| 209 _AsyncBlock._(this.name, this._taskId); | 189 _AsyncBlock._(this.name, this._taskId); |
| 210 | 190 |
| 211 // Emit the start event. | 191 // Emit the start event. |
| 212 void _start() { | 192 void _start() { |
| 213 _reportTaskEvent(_getTraceClock(), | 193 _reportTaskEvent(_getTraceClock(), _taskId, 'b', category, name, |
| 214 _taskId, | 194 _argumentsAsJson(_arguments)); |
| 215 'b', | |
| 216 category, | |
| 217 name, | |
| 218 _argumentsAsJson(_arguments)); | |
| 219 } | 195 } |
| 220 | 196 |
| 221 // Emit the finish event. | 197 // Emit the finish event. |
| 222 void _finish() { | 198 void _finish() { |
| 223 _reportTaskEvent(_getTraceClock(), | 199 _reportTaskEvent( |
| 224 _taskId, | 200 _getTraceClock(), _taskId, 'e', category, name, _argumentsAsJson(null)); |
| 225 'e', | |
| 226 category, | |
| 227 name, | |
| 228 _argumentsAsJson(null)); | |
| 229 } | 201 } |
| 230 | 202 |
| 231 void _appendArguments(Map arguments) { | 203 void _appendArguments(Map arguments) { |
| 232 if (_arguments == null) { | 204 if (_arguments == null) { |
| 233 _arguments = {}; | 205 _arguments = {}; |
| 234 } | 206 } |
| 235 _arguments.addAll(arguments); | 207 _arguments.addAll(arguments); |
| 236 } | 208 } |
| 237 } | 209 } |
| 238 | 210 |
| 239 /// A synchronous block of time on the timeline. This block should not be | 211 /// A synchronous block of time on the timeline. This block should not be |
| 240 /// kept open across isolate messages. | 212 /// kept open across isolate messages. |
| 241 class _SyncBlock { | 213 class _SyncBlock { |
| 242 /// The category this block belongs to. | 214 /// The category this block belongs to. |
| 243 final String category = 'Dart'; | 215 final String category = 'Dart'; |
| 216 |
| 244 /// The name of this block. | 217 /// The name of this block. |
| 245 final String name; | 218 final String name; |
| 219 |
| 246 /// An (optional) set of arguments which will be serialized to JSON and | 220 /// An (optional) set of arguments which will be serialized to JSON and |
| 247 /// associated with this block. | 221 /// associated with this block. |
| 248 Map _arguments; | 222 Map _arguments; |
| 249 // The start time stamp. | 223 // The start time stamp. |
| 250 final int _start; | 224 final int _start; |
| 251 // The start time stamp of the thread cpu clock. | 225 // The start time stamp of the thread cpu clock. |
| 252 final int _startCpu; | 226 final int _startCpu; |
| 253 | 227 |
| 254 _SyncBlock._(this.name, | 228 _SyncBlock._(this.name, this._start, this._startCpu); |
| 255 this._start, | |
| 256 this._startCpu); | |
| 257 | 229 |
| 258 /// Finish this block of time. At this point, this block can no longer be | 230 /// Finish this block of time. At this point, this block can no longer be |
| 259 /// used. | 231 /// used. |
| 260 void finish() { | 232 void finish() { |
| 261 // Report event to runtime. | 233 // Report event to runtime. |
| 262 _reportCompleteEvent(_start, | 234 _reportCompleteEvent( |
| 263 _startCpu, | 235 _start, _startCpu, category, name, _argumentsAsJson(_arguments)); |
| 264 category, | |
| 265 name, | |
| 266 _argumentsAsJson(_arguments)); | |
| 267 } | 236 } |
| 268 | 237 |
| 269 void _appendArguments(Map arguments) { | 238 void _appendArguments(Map arguments) { |
| 270 if (arguments == null) { | 239 if (arguments == null) { |
| 271 return; | 240 return; |
| 272 } | 241 } |
| 273 if (_arguments == null) { | 242 if (_arguments == null) { |
| 274 _arguments = {}; | 243 _arguments = {}; |
| 275 } | 244 } |
| 276 _arguments.addAll(arguments); | 245 _arguments.addAll(arguments); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 300 /// Returns the current value from the trace clock. | 269 /// Returns the current value from the trace clock. |
| 301 external int _getTraceClock(); | 270 external int _getTraceClock(); |
| 302 | 271 |
| 303 /// Returns the current value from the thread CPU usage clock. | 272 /// Returns the current value from the thread CPU usage clock. |
| 304 external int _getThreadCpuClock(); | 273 external int _getThreadCpuClock(); |
| 305 | 274 |
| 306 /// Returns the isolate's main port number. | 275 /// Returns the isolate's main port number. |
| 307 external int _getIsolateNum(); | 276 external int _getIsolateNum(); |
| 308 | 277 |
| 309 /// Reports an event for a task. | 278 /// Reports an event for a task. |
| 310 external void _reportTaskEvent(int start, | 279 external void _reportTaskEvent(int start, int taskId, String phase, |
| 311 int taskId, | 280 String category, String name, String argumentsAsJson); |
| 312 String phase, | |
| 313 String category, | |
| 314 String name, | |
| 315 String argumentsAsJson); | |
| 316 | 281 |
| 317 /// Reports a complete synchronous event. | 282 /// Reports a complete synchronous event. |
| 318 external void _reportCompleteEvent(int start, | 283 external void _reportCompleteEvent(int start, int startCpu, String category, |
| 319 int startCpu, | 284 String name, String argumentsAsJson); |
| 320 String category, | |
| 321 String name, | |
| 322 String argumentsAsJson); | |
| 323 | 285 |
| 324 /// Reports an instant event. | 286 /// Reports an instant event. |
| 325 external void _reportInstantEvent(int start, | 287 external void _reportInstantEvent( |
| 326 String category, | 288 int start, String category, String name, String argumentsAsJson); |
| 327 String name, | |
| 328 String argumentsAsJson); | |
| OLD | NEW |