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 |