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 /// A class to represent Flow events. |
| 13 /// |
| 14 /// [Flow] objects are used to thread flow events between timeline slices, |
| 15 /// for example, those created with the [Timeline] class below. Adding |
| 16 /// [Flow] objects cause arrows to be drawn between slices in Chrome's trace |
| 17 /// viewer. The arrows start at e.g [Timeline] events that are passed a |
| 18 /// [Flow.begin] object, go through [Timeline] events that are passed a |
| 19 /// [Flow.step] object, and end at [Timeline] events that are passed a |
| 20 /// [Flow.end] object, all having the same [Flow.id]. For example: |
| 21 /// |
| 22 /// ```dart |
| 23 /// var flow = Flow.begin(); |
| 24 /// Timeline.timeSync('flow_test', () { |
| 25 /// doSomething(); |
| 26 /// }, flow: flow); |
| 27 /// |
| 28 /// Timeline.timeSync('flow_test', () { |
| 29 /// doSomething(); |
| 30 /// }, flow: Flow.step(flow.id)); |
| 31 /// |
| 32 /// Timeline.timeSync('flow_test', () { |
| 33 /// doSomething(); |
| 34 /// }, flow: Flow.end(flow.id)); |
| 35 /// ``` |
| 36 class Flow { |
| 37 // These values must be kept in sync with the enum "EventType" in |
| 38 // runtime/vm/timeline.h. |
| 39 static const int _begin = 9; |
| 40 static const int _step = 10; |
| 41 static const int _end = 11; |
| 42 |
| 43 final int _type; |
| 44 |
| 45 /// The flow id of the flow event. |
| 46 final int id; |
| 47 |
| 48 Flow._(this._type, this.id); |
| 49 |
| 50 /// A "begin" Flow event. |
| 51 /// |
| 52 /// When passed to a [Timeline] method, generates a "begin" Flow event. |
| 53 /// If [id] is not provided, an id that conflicts with no other Dart-generated |
| 54 /// flow id's will be generated. |
| 55 static Flow begin({int id}) { |
| 56 return new Flow._(_begin, id ?? _getNextAsyncId()); |
| 57 } |
| 58 |
| 59 /// A "step" Flow event. |
| 60 /// |
| 61 /// When passed to a [Timeline] method, generates a "step" Flow event. |
| 62 /// The [id] argument is required. It can come either from another [Flow] |
| 63 /// event, or some id that comes from the environment. |
| 64 static Flow step(int id) => new Flow._(_step, id); |
| 65 |
| 66 /// An "end" Flow event. |
| 67 /// |
| 68 /// When passed to a [Timeline] method, generates a "end" Flow event. |
| 69 /// The [id] argument is required. It can come either from another [Flow] |
| 70 /// event, or some id that comes from the environment. |
| 71 static Flow end(int id) => new Flow._(_end, id); |
| 72 } |
| 73 |
12 /// Add to the timeline. | 74 /// Add to the timeline. |
| 75 /// |
| 76 /// [Timeline]'s methods add synchronous events to the timeline. When |
| 77 /// generating a timeline in Chrome's tracing format, using [Timeline] generates |
| 78 /// "Complete" events. [Timeline]'s [startSync] and [endSync] can be used |
| 79 /// explicitly, or implicitly by wrapping a closure in [timeSync]. For exmaple: |
| 80 /// |
| 81 /// ```dart |
| 82 /// Timeline.startSync("Doing Something"); |
| 83 /// doSomething(); |
| 84 /// Timeline.finishSync(); |
| 85 /// ``` |
| 86 /// |
| 87 /// Or: |
| 88 /// |
| 89 /// ```dart |
| 90 /// Timeline.timeSync("Doing Something", () { |
| 91 /// doSomething(); |
| 92 /// }); |
| 93 /// ``` |
13 class Timeline { | 94 class Timeline { |
14 /// Start a synchronous operation labeled [name]. Optionally takes | 95 /// Start a synchronous operation labeled [name]. Optionally takes |
15 /// a [Map] of [arguments]. This operation must be finished before | 96 /// a [Map] of [arguments]. This slice may also optionally be associated with |
| 97 /// a [Flow] event. This operation must be finished before |
16 /// returning to the event queue. | 98 /// returning to the event queue. |
17 static void startSync(String name, {Map arguments}) { | 99 static void startSync(String name, {Map arguments, Flow flow}) { |
18 if (_isProduct) { | 100 if (_isProduct) { |
19 return; | 101 return; |
20 } | 102 } |
21 if (name is! String) { | 103 if (name is! String) { |
22 throw new ArgumentError.value(name, 'name', 'Must be a String'); | 104 throw new ArgumentError.value(name, 'name', 'Must be a String'); |
23 } | 105 } |
24 if (!_isDartStreamEnabled()) { | 106 if (!_isDartStreamEnabled()) { |
25 // Push a null onto the stack and return. | 107 // Push a null onto the stack and return. |
26 _stack.add(null); | 108 _stack.add(null); |
27 return; | 109 return; |
28 } | 110 } |
29 var block = new _SyncBlock._(name, _getTraceClock(), _getThreadCpuClock()); | 111 var block = new _SyncBlock._(name, _getTraceClock(), _getThreadCpuClock()); |
30 if (arguments is Map) { | 112 if (arguments is Map) { |
31 block._appendArguments(arguments); | 113 block._appendArguments(arguments); |
32 } | 114 } |
| 115 if (flow is Flow) { |
| 116 block.flow = flow; |
| 117 } |
33 _stack.add(block); | 118 _stack.add(block); |
34 } | 119 } |
35 | 120 |
36 /// Finish the last synchronous operation that was started. | 121 /// Finish the last synchronous operation that was started. |
37 static void finishSync() { | 122 static void finishSync() { |
38 if (_isProduct) { | 123 if (_isProduct) { |
39 return; | 124 return; |
40 } | 125 } |
41 if (_stack.length == 0) { | 126 if (_stack.length == 0) { |
42 throw new StateError('Uneven calls to startSync and finishSync'); | 127 throw new StateError('Uneven calls to startSync and finishSync'); |
(...skipping 24 matching lines...) Expand all Loading... |
67 if (arguments is Map) { | 152 if (arguments is Map) { |
68 instantArguments = new Map.from(arguments); | 153 instantArguments = new Map.from(arguments); |
69 } | 154 } |
70 _reportInstantEvent( | 155 _reportInstantEvent( |
71 _getTraceClock(), 'Dart', name, _argumentsAsJson(instantArguments)); | 156 _getTraceClock(), 'Dart', name, _argumentsAsJson(instantArguments)); |
72 } | 157 } |
73 | 158 |
74 /// A utility method to time a synchronous [function]. Internally calls | 159 /// A utility method to time a synchronous [function]. Internally calls |
75 /// [function] bracketed by calls to [startSync] and [finishSync]. | 160 /// [function] bracketed by calls to [startSync] and [finishSync]. |
76 static dynamic timeSync(String name, TimelineSyncFunction function, | 161 static dynamic timeSync(String name, TimelineSyncFunction function, |
77 {Map arguments}) { | 162 {Map arguments, Flow flow}) { |
78 startSync(name, arguments: arguments); | 163 startSync(name, arguments: arguments, flow: flow); |
79 try { | 164 try { |
80 return function(); | 165 return function(); |
81 } finally { | 166 } finally { |
82 finishSync(); | 167 finishSync(); |
83 } | 168 } |
84 } | 169 } |
85 | 170 |
86 /// The current time stamp from the clock used by the timeline. Units are | 171 /// The current time stamp from the clock used by the timeline. Units are |
87 /// microseconds. | 172 /// microseconds. |
88 static int get now => _getTraceClock(); | 173 static int get now => _getTraceClock(); |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
218 final String name; | 303 final String name; |
219 | 304 |
220 /// An (optional) set of arguments which will be serialized to JSON and | 305 /// An (optional) set of arguments which will be serialized to JSON and |
221 /// associated with this block. | 306 /// associated with this block. |
222 Map _arguments; | 307 Map _arguments; |
223 // The start time stamp. | 308 // The start time stamp. |
224 final int _start; | 309 final int _start; |
225 // The start time stamp of the thread cpu clock. | 310 // The start time stamp of the thread cpu clock. |
226 final int _startCpu; | 311 final int _startCpu; |
227 | 312 |
| 313 /// An (optional) flow event associated with this block. |
| 314 Flow _flow; |
| 315 |
228 _SyncBlock._(this.name, this._start, this._startCpu); | 316 _SyncBlock._(this.name, this._start, this._startCpu); |
229 | 317 |
230 /// Finish this block of time. At this point, this block can no longer be | 318 /// Finish this block of time. At this point, this block can no longer be |
231 /// used. | 319 /// used. |
232 void finish() { | 320 void finish() { |
233 // Report event to runtime. | 321 // Report event to runtime. |
234 _reportCompleteEvent( | 322 _reportCompleteEvent( |
235 _start, _startCpu, category, name, _argumentsAsJson(_arguments)); | 323 _start, _startCpu, category, name, _argumentsAsJson(_arguments)); |
| 324 if (_flow != null) { |
| 325 _reportFlowEvent(_start, _startCpu, category, name, _flow._type, _flow.id, |
| 326 _argumentsAsJson(null)); |
| 327 } |
236 } | 328 } |
237 | 329 |
238 void _appendArguments(Map arguments) { | 330 void _appendArguments(Map arguments) { |
239 if (arguments == null) { | 331 if (arguments == null) { |
240 return; | 332 return; |
241 } | 333 } |
242 if (_arguments == null) { | 334 if (_arguments == null) { |
243 _arguments = {}; | 335 _arguments = {}; |
244 } | 336 } |
245 _arguments.addAll(arguments); | 337 _arguments.addAll(arguments); |
246 } | 338 } |
| 339 |
| 340 void set flow(Flow f) { |
| 341 _flow = f; |
| 342 } |
247 } | 343 } |
248 | 344 |
249 String _fastPathArguments; | 345 String _fastPathArguments; |
250 String _argumentsAsJson(Map arguments) { | 346 String _argumentsAsJson(Map arguments) { |
251 if ((arguments == null) || (arguments.length == 0)) { | 347 if ((arguments == null) || (arguments.length == 0)) { |
252 // Fast path no arguments. Avoid calling JSON.encode. | 348 // Fast path no arguments. Avoid calling JSON.encode. |
253 if (_fastPathArguments == null) { | 349 if (_fastPathArguments == null) { |
254 _fastPathArguments = '{"isolateNumber":"${Timeline._isolateId}"}'; | 350 _fastPathArguments = '{"isolateNumber":"${Timeline._isolateId}"}'; |
255 } | 351 } |
256 return _fastPathArguments; | 352 return _fastPathArguments; |
(...skipping 19 matching lines...) Expand all Loading... |
276 external int _getIsolateNum(); | 372 external int _getIsolateNum(); |
277 | 373 |
278 /// Reports an event for a task. | 374 /// Reports an event for a task. |
279 external void _reportTaskEvent(int start, int taskId, String phase, | 375 external void _reportTaskEvent(int start, int taskId, String phase, |
280 String category, String name, String argumentsAsJson); | 376 String category, String name, String argumentsAsJson); |
281 | 377 |
282 /// Reports a complete synchronous event. | 378 /// Reports a complete synchronous event. |
283 external void _reportCompleteEvent(int start, int startCpu, String category, | 379 external void _reportCompleteEvent(int start, int startCpu, String category, |
284 String name, String argumentsAsJson); | 380 String name, String argumentsAsJson); |
285 | 381 |
| 382 /// Reports a flow event. |
| 383 external void _reportFlowEvent(int start, int startCpu, String category, |
| 384 String name, int type, int id, String argumentsAsJson); |
| 385 |
286 /// Reports an instant event. | 386 /// Reports an instant event. |
287 external void _reportInstantEvent( | 387 external void _reportInstantEvent( |
288 int start, String category, String name, String argumentsAsJson); | 388 int start, String category, String name, String argumentsAsJson); |
OLD | NEW |