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 | 8 |
9 /// Add to the timeline. | 9 /// Add to the timeline. |
10 class Timeline { | 10 class Timeline { |
(...skipping 14 matching lines...) Expand all Loading... |
25 } | 25 } |
26 | 26 |
27 /// Finish the last synchronous operation that was started. | 27 /// Finish the last synchronous operation that was started. |
28 static void finishSync() { | 28 static void finishSync() { |
29 if (_stack.length == 0) { | 29 if (_stack.length == 0) { |
30 throw new StateError( | 30 throw new StateError( |
31 'Uneven calls to startSync and finishSync'); | 31 'Uneven calls to startSync and finishSync'); |
32 } | 32 } |
33 // Pop top item off of stack. | 33 // Pop top item off of stack. |
34 var block = _stack.removeLast(); | 34 var block = _stack.removeLast(); |
35 // Close it. | 35 // Finish it. |
36 block.close(); | 36 block.finish(); |
37 } | 37 } |
38 | 38 |
39 /// A utility method to time a synchronous [function]. Internally calls | 39 /// A utility method to time a synchronous [function]. Internally calls |
40 /// [function] bracketed by calls to [startSync] and [finishSync]. | 40 /// [function] bracketed by calls to [startSync] and [finishSync]. |
41 static dynamic timeSync(String name, | 41 static dynamic timeSync(String name, |
42 TimelineSyncFunction function, | 42 TimelineSyncFunction function, |
43 {Map arguments}) { | 43 {Map arguments}) { |
44 startSync(name, arguments: arguments); | 44 startSync(name, arguments: arguments); |
45 try { | 45 try { |
46 return function(); | 46 return function(); |
47 } finally { | 47 } finally { |
48 finishSync(); | 48 finishSync(); |
49 } | 49 } |
50 } | 50 } |
51 | 51 |
52 static final List<_SyncBlock> _stack = new List<_SyncBlock>(); | 52 static final List<_SyncBlock> _stack = new List<_SyncBlock>(); |
53 } | 53 } |
54 | 54 |
| 55 /// An asynchronous task on the timeline. Asynchronous tasks can live |
| 56 /// longer than the current event and can even be shared between isolates. |
| 57 /// An asynchronous task can have many (nested) blocks. To share a |
| 58 /// [TimelineTask] across isolates, you must construct a [TimelineTask] in |
| 59 /// both isolates using the same [taskId] and [category]. |
| 60 class TimelineTask { |
| 61 /// Create a task. [taskId] will be set by the system. |
| 62 /// Optionally you can specify a [category] name. |
| 63 TimelineTask({String category: 'Dart'}) |
| 64 : _taskId = _getNextAsyncId(), |
| 65 category = category { |
| 66 if (category is! String) { |
| 67 throw new ArgumentError.value(category, |
| 68 'category', |
| 69 'Must be a String'); |
| 70 } |
| 71 } |
| 72 |
| 73 /// Create a task with an explicit [taskId]. This is useful if you are |
| 74 /// passing a task between isolates. Optionally you can specify a [category] |
| 75 /// name. |
| 76 TimelineTask.withTaskId(int taskId, {String category: 'Dart'}) |
| 77 : _taskId = taskId, |
| 78 category = category { |
| 79 if (taskId is! int) { |
| 80 throw new ArgumentError.value(taskId, |
| 81 'taskId', |
| 82 'Must be an int'); |
| 83 } |
| 84 if (category is! String) { |
| 85 throw new ArgumentError.value(category, |
| 86 'category', |
| 87 'Must be a String'); |
| 88 } |
| 89 } |
| 90 |
| 91 /// Start a block in this task named [name]. Optionally takes |
| 92 /// a [Map] of [arguments]. |
| 93 /// Returns an [AsyncBlock] which is used to finish this block. |
| 94 AsyncBlock start(String name, {Map arguments}) { |
| 95 if (name is! String) { |
| 96 throw new ArgumentError.value(name, |
| 97 'name', |
| 98 'Must be a String'); |
| 99 } |
| 100 var block = new AsyncBlock._(name, _taskId, category); |
| 101 if (arguments is Map) { |
| 102 block.arguments.addAll(arguments); |
| 103 } |
| 104 /// Emit start event. |
| 105 block._start(); |
| 106 return block; |
| 107 } |
| 108 |
| 109 /// Retrieve the asynchronous task's id. Can be used to construct a |
| 110 /// [TimelineTask] in another isolate. |
| 111 int get taskId => _taskId; |
| 112 final int _taskId; |
| 113 /// Retrieve the asynchronous task's category. Can be used to construct a |
| 114 /// [TimelineTask] in another isolate. |
| 115 final String category; |
| 116 } |
| 117 |
| 118 /// An asynchronous block of time on the timeline. This block can be kept |
| 119 /// open across isolate messages. |
| 120 class AsyncBlock { |
| 121 /// The category this block belongs to. |
| 122 final String category; |
| 123 /// The name of this block. |
| 124 final String name; |
| 125 /// The asynchronous task id. |
| 126 final int _taskId; |
| 127 /// An (optional) set of arguments which will be serialized to JSON and |
| 128 /// associated with this block. |
| 129 final Map arguments = {}; |
| 130 bool _finished = false; |
| 131 |
| 132 AsyncBlock._(this.name, this._taskId, this.category); |
| 133 |
| 134 // Emit the start event. |
| 135 void _start() { |
| 136 String argumentsAsJson = JSON.encode(arguments); |
| 137 _reportTaskEvent(_getTraceClock(), |
| 138 _taskId, |
| 139 'b', |
| 140 category, |
| 141 name, |
| 142 argumentsAsJson); |
| 143 } |
| 144 |
| 145 // Emit the finish event. |
| 146 void _finish() { |
| 147 _reportTaskEvent(_getTraceClock(), |
| 148 _taskId, |
| 149 'e', |
| 150 category, |
| 151 name, |
| 152 JSON.encode({})); |
| 153 } |
| 154 |
| 155 /// Finish this block. Cannot be called twice. |
| 156 void finish() { |
| 157 if (_finished) { |
| 158 throw new StateError( |
| 159 'It is illegal to call finish twice on the same AsyncBlock'); |
| 160 } |
| 161 _finished = true; |
| 162 _finish(); |
| 163 } |
| 164 |
| 165 /// Finishes this block when [future] completes. Returns a [Future] |
| 166 /// chained to [future]. |
| 167 Future finishWhenComplete(Future future) { |
| 168 if (future is! Future) { |
| 169 throw new ArgumentError.value(future, |
| 170 'future', |
| 171 'Must be a Future'); |
| 172 } |
| 173 return future.whenComplete(() { |
| 174 finish(); |
| 175 }); |
| 176 } |
| 177 } |
| 178 |
55 /// A synchronous block of time on the timeline. This block should not be | 179 /// A synchronous block of time on the timeline. This block should not be |
56 /// kept open across isolate messages. | 180 /// kept open across isolate messages. |
57 class _SyncBlock { | 181 class _SyncBlock { |
58 /// The category this block belongs to. | 182 /// The category this block belongs to. |
59 final String category = 'Dart'; | 183 final String category = 'Dart'; |
60 /// The name of this block. | 184 /// The name of this block. |
61 final String name; | 185 final String name; |
62 /// An (optional) set of arguments which will be serialized to JSON and | 186 /// An (optional) set of arguments which will be serialized to JSON and |
63 /// associated with this block. | 187 /// associated with this block. |
64 final Map arguments = {}; | 188 final Map arguments = {}; |
65 // The start time stamp. | 189 // The start time stamp. |
66 final int _start; | 190 final int _start; |
67 // Has this block been closed? | |
68 bool _closed = false; | |
69 | 191 |
70 _SyncBlock._(this.name, | 192 _SyncBlock._(this.name, |
71 this._start); | 193 this._start); |
72 | 194 |
73 /// Close this block of time. At this point, this block can no longer be | 195 /// Finish this block of time. At this point, this block can no longer be |
74 /// used. | 196 /// used. |
75 void close() { | 197 void finish() { |
76 if (_closed) { | |
77 throw new StateError( | |
78 'It is illegal to call close twice on the same _SyncBlock'); | |
79 } | |
80 _closed = true; | |
81 var end = _getTraceClock(); | 198 var end = _getTraceClock(); |
82 | 199 |
83 // Encode arguments map as JSON before reporting. | 200 // Encode arguments map as JSON before reporting. |
84 var argumentsAsJson = JSON.encode(arguments); | 201 var argumentsAsJson = JSON.encode(arguments); |
85 | 202 |
86 // Report event to runtime. | 203 // Report event to runtime. |
87 _reportCompleteEvent(_start, | 204 _reportCompleteEvent(_start, |
88 end, | 205 end, |
89 category, | 206 category, |
90 name, | 207 name, |
91 argumentsAsJson); | 208 argumentsAsJson); |
92 } | 209 } |
93 } | 210 } |
94 | 211 |
| 212 /// Returns the next async task id. |
| 213 external int _getNextAsyncId(); |
| 214 |
95 /// Returns the current value from the trace clock. | 215 /// Returns the current value from the trace clock. |
96 external int _getTraceClock(); | 216 external int _getTraceClock(); |
97 | 217 |
| 218 /// Reports an event for a task. |
| 219 external void _reportTaskEvent(int start, |
| 220 int taskId, |
| 221 String phase, |
| 222 String category, |
| 223 String name, |
| 224 String argumentsAsJson); |
| 225 |
98 /// Reports a complete synchronous event. | 226 /// Reports a complete synchronous event. |
99 external void _reportCompleteEvent(int start, | 227 external void _reportCompleteEvent(int start, |
100 int end, | 228 int end, |
101 String category, | 229 String category, |
102 String name, | 230 String name, |
103 String argumentsAsJson); | 231 String argumentsAsJson); |
OLD | NEW |