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