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 |