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 typedef Future TimelineAsyncFunction(); |
8 | 9 |
9 /// Add to the timeline. | 10 /// Add to the timeline. |
10 class Timeline { | 11 class Timeline { |
11 /// Start a synchronous operation labeled [name]. Optionally takes | 12 /// Start a synchronous operation labeled [name]. Optionally takes |
12 /// a [Map] of [arguments]. This operation must be finished before | 13 /// a [Map] of [arguments]. This operation must be finished before |
13 /// returning to the event queue. | 14 /// returning to the event queue. |
14 static void startSync(String name, {Map arguments}) { | 15 static void startSync(String name, {Map arguments}) { |
15 if (name is! String) { | 16 if (name is! String) { |
16 throw new ArgumentError.value(name, | 17 throw new ArgumentError.value(name, |
17 'name', | 18 'name', |
(...skipping 11 matching lines...) Expand all Loading... |
29 if (_stack.length == 0) { | 30 if (_stack.length == 0) { |
30 throw new StateError( | 31 throw new StateError( |
31 'Uneven calls to startSync and finishSync'); | 32 'Uneven calls to startSync and finishSync'); |
32 } | 33 } |
33 // Pop top item off of stack. | 34 // Pop top item off of stack. |
34 var block = _stack.removeLast(); | 35 var block = _stack.removeLast(); |
35 // Finish it. | 36 // Finish it. |
36 block.finish(); | 37 block.finish(); |
37 } | 38 } |
38 | 39 |
| 40 /// Emit an instant event. |
| 41 static void instantSync(String name, {Map arguments}) { |
| 42 if (name is! String) { |
| 43 throw new ArgumentError.value(name, |
| 44 'name', |
| 45 'Must be a String'); |
| 46 } |
| 47 Map instantArguments = { |
| 48 'isolateNumber': '${Timeline._isolateId}' |
| 49 }; |
| 50 if (arguments is Map) { |
| 51 instantArguments.addAll(arguments); |
| 52 } |
| 53 String argumentsAsJson = JSON.encode(instantArguments); |
| 54 _reportInstantEvent(_getTraceClock(), |
| 55 'Dart', |
| 56 name, |
| 57 argumentsAsJson); |
| 58 } |
| 59 |
| 60 |
39 /// A utility method to time a synchronous [function]. Internally calls | 61 /// A utility method to time a synchronous [function]. Internally calls |
40 /// [function] bracketed by calls to [startSync] and [finishSync]. | 62 /// [function] bracketed by calls to [startSync] and [finishSync]. |
41 static dynamic timeSync(String name, | 63 static dynamic timeSync(String name, |
42 TimelineSyncFunction function, | 64 TimelineSyncFunction function, |
43 {Map arguments}) { | 65 {Map arguments}) { |
44 startSync(name, arguments: arguments); | 66 startSync(name, arguments: arguments); |
45 try { | 67 try { |
46 return function(); | 68 return function(); |
47 } finally { | 69 } finally { |
48 finishSync(); | 70 finishSync(); |
49 } | 71 } |
50 } | 72 } |
51 | 73 |
52 static final List<_SyncBlock> _stack = new List<_SyncBlock>(); | 74 static final List<_SyncBlock> _stack = new List<_SyncBlock>(); |
53 | 75 |
54 static final int _isolateId = _getIsolateNum(); | 76 static final int _isolateId = _getIsolateNum(); |
55 } | 77 } |
56 | 78 |
57 /// An asynchronous task on the timeline. Asynchronous tasks can live | 79 /// An asynchronous task on the timeline. An asynchronous task can have many |
58 /// longer than the current event and can even be shared between isolates. | 80 /// (nested) synchronous operations. Synchronous operations can live longer than |
59 /// An asynchronous task can have many (nested) blocks. To share a | 81 /// the current isolate event. To pass a [TimelineTask] to another isolate, |
60 /// [TimelineTask] across isolates, you must construct a [TimelineTask] in | 82 /// you must first call [pass] to get the task id and then construct a new |
61 /// both isolates using the same [taskId] and [category]. | 83 /// [TimelineTask] in the other isolate. |
62 class TimelineTask { | 84 class TimelineTask { |
63 /// Create a task. [taskId] will be set by the system. | 85 /// Create a task. [taskId] will be set by the system. |
64 /// Optionally you can specify a [category] name. | 86 TimelineTask() |
65 TimelineTask({String category: 'Dart'}) | 87 : _taskId = _getNextAsyncId() { |
66 : _taskId = _getNextAsyncId(), | |
67 category = category { | |
68 if (category is! String) { | |
69 throw new ArgumentError.value(category, | |
70 'category', | |
71 'Must be a String'); | |
72 } | |
73 } | 88 } |
74 | 89 |
75 /// Create a task with an explicit [taskId]. This is useful if you are | 90 /// Create a task with an explicit [taskId]. This is useful if you are |
76 /// passing a task between isolates. Optionally you can specify a [category] | 91 /// passing a task from one isolate to another. |
77 /// name. | 92 TimelineTask.withTaskId(int taskId) |
78 TimelineTask.withTaskId(int taskId, {String category: 'Dart'}) | 93 : _taskId = taskId { |
79 : _taskId = taskId, | |
80 category = category { | |
81 if (taskId is! int) { | 94 if (taskId is! int) { |
82 throw new ArgumentError.value(taskId, | 95 throw new ArgumentError.value(taskId, |
83 'taskId', | 96 'taskId', |
84 'Must be an int'); | 97 'Must be an int'); |
85 } | 98 } |
86 if (category is! String) { | |
87 throw new ArgumentError.value(category, | |
88 'category', | |
89 'Must be a String'); | |
90 } | |
91 } | 99 } |
92 | 100 |
93 /// Start a block in this task named [name]. Optionally takes | 101 /// Start a synchronous operation within this task named [name]. |
94 /// a [Map] of [arguments]. | 102 /// Optionally takes a [Map] of [arguments]. |
95 /// Returns an [AsyncBlock] which is used to finish this block. | 103 void start(String name, {Map arguments}) { |
96 AsyncBlock start(String name, {Map arguments}) { | |
97 if (name is! String) { | 104 if (name is! String) { |
98 throw new ArgumentError.value(name, | 105 throw new ArgumentError.value(name, |
99 'name', | 106 'name', |
100 'Must be a String'); | 107 'Must be a String'); |
101 } | 108 } |
102 var block = new AsyncBlock._(name, _taskId, category); | 109 var block = new _AsyncBlock._(name, _taskId); |
103 if (arguments is Map) { | 110 if (arguments is Map) { |
104 block.arguments.addAll(arguments); | 111 block.arguments.addAll(arguments); |
105 } | 112 } |
106 /// Emit start event. | 113 _stack.add(block); |
107 block._start(); | 114 block._start(); |
108 return block; | |
109 } | 115 } |
110 | 116 |
111 /// Retrieve the asynchronous task's id. Can be used to construct a | 117 /// Emit an instant event for this task. |
112 /// [TimelineTask] in another isolate. | 118 void instant(String name, {Map arguments}) { |
113 int get taskId => _taskId; | 119 if (name is! String) { |
| 120 throw new ArgumentError.value(name, |
| 121 'name', |
| 122 'Must be a String'); |
| 123 } |
| 124 Map instantArguments = { |
| 125 'isolateNumber': '${Timeline._isolateId}' |
| 126 }; |
| 127 if (arguments is Map) { |
| 128 instantArguments.addAll(arguments); |
| 129 } |
| 130 String argumentsAsJson = JSON.encode(instantArguments); |
| 131 _reportTaskEvent(_getTraceClock(), |
| 132 _taskId, |
| 133 'n', |
| 134 'Dart', |
| 135 name, |
| 136 argumentsAsJson); |
| 137 } |
| 138 |
| 139 /// Finish the last synchronous operation that was started. |
| 140 void finish() { |
| 141 if (_stack.length == 0) { |
| 142 throw new StateError( |
| 143 'Uneven calls to start and finish'); |
| 144 } |
| 145 // Pop top item off of stack. |
| 146 var block = _stack.removeLast(); |
| 147 block._finish(); |
| 148 } |
| 149 |
| 150 /// Retrieve the [TimelineTask]'s task id. Will throw an exception if the |
| 151 /// stack is not empty. |
| 152 int pass() { |
| 153 if (_stack.length > 0) { |
| 154 throw new StateError( |
| 155 'You cannot pass a TimelineTask without finishing all started ' |
| 156 'operations'); |
| 157 } |
| 158 int r = _taskId; |
| 159 return r; |
| 160 } |
| 161 |
114 final int _taskId; | 162 final int _taskId; |
115 /// Retrieve the asynchronous task's category. Can be used to construct a | 163 final List<_AsyncBlock> _stack = []; |
116 /// [TimelineTask] in another isolate. | |
117 final String category; | |
118 } | 164 } |
119 | 165 |
120 /// An asynchronous block of time on the timeline. This block can be kept | 166 /// An asynchronous block of time on the timeline. This block can be kept |
121 /// open across isolate messages. | 167 /// open across isolate messages. |
122 class AsyncBlock { | 168 class _AsyncBlock { |
123 /// The category this block belongs to. | 169 /// The category this block belongs to. |
124 final String category; | 170 final String category = 'Dart'; |
125 /// The name of this block. | 171 /// The name of this block. |
126 final String name; | 172 final String name; |
127 /// The asynchronous task id. | 173 /// The asynchronous task id. |
128 final int _taskId; | 174 final int _taskId; |
129 /// An (optional) set of arguments which will be serialized to JSON and | 175 /// An (optional) set of arguments which will be serialized to JSON and |
130 /// associated with this block. | 176 /// associated with this block. |
131 final Map arguments = {}; | 177 final Map arguments = {}; |
132 bool _finished = false; | |
133 | 178 |
134 AsyncBlock._(this.name, this._taskId, this.category); | 179 _AsyncBlock._(this.name, this._taskId); |
135 | 180 |
136 // Emit the start event. | 181 // Emit the start event. |
137 void _start() { | 182 void _start() { |
138 arguments['isolateNumber'] = '${Timeline._isolateId}'; | 183 arguments['isolateNumber'] = '${Timeline._isolateId}'; |
139 String argumentsAsJson = JSON.encode(arguments); | 184 String argumentsAsJson = JSON.encode(arguments); |
140 _reportTaskEvent(_getTraceClock(), | 185 _reportTaskEvent(_getTraceClock(), |
141 _taskId, | 186 _taskId, |
142 'b', | 187 'b', |
143 category, | 188 category, |
144 name, | 189 name, |
145 argumentsAsJson); | 190 argumentsAsJson); |
146 } | 191 } |
147 | 192 |
148 // Emit the finish event. | 193 // Emit the finish event. |
149 void _finish() { | 194 void _finish() { |
150 _reportTaskEvent(_getTraceClock(), | 195 _reportTaskEvent(_getTraceClock(), |
151 _taskId, | 196 _taskId, |
152 'e', | 197 'e', |
153 category, | 198 category, |
154 name, | 199 name, |
155 JSON.encode({})); | 200 JSON.encode({})); |
156 } | 201 } |
157 | |
158 /// Finish this block. Cannot be called twice. | |
159 void finish() { | |
160 if (_finished) { | |
161 throw new StateError( | |
162 'It is illegal to call finish twice on the same AsyncBlock'); | |
163 } | |
164 _finished = true; | |
165 _finish(); | |
166 } | |
167 | |
168 /// Finishes this block when [future] completes. Returns a [Future] | |
169 /// chained to [future]. | |
170 Future finishWhenComplete(Future future) { | |
171 if (future is! Future) { | |
172 throw new ArgumentError.value(future, | |
173 'future', | |
174 'Must be a Future'); | |
175 } | |
176 return future.whenComplete(() { | |
177 finish(); | |
178 }); | |
179 } | |
180 } | 202 } |
181 | 203 |
182 /// A synchronous block of time on the timeline. This block should not be | 204 /// A synchronous block of time on the timeline. This block should not be |
183 /// kept open across isolate messages. | 205 /// kept open across isolate messages. |
184 class _SyncBlock { | 206 class _SyncBlock { |
185 /// The category this block belongs to. | 207 /// The category this block belongs to. |
186 final String category = 'Dart'; | 208 final String category = 'Dart'; |
187 /// The name of this block. | 209 /// The name of this block. |
188 final String name; | 210 final String name; |
189 /// An (optional) set of arguments which will be serialized to JSON and | 211 /// An (optional) set of arguments which will be serialized to JSON and |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
230 String category, | 252 String category, |
231 String name, | 253 String name, |
232 String argumentsAsJson); | 254 String argumentsAsJson); |
233 | 255 |
234 /// Reports a complete synchronous event. | 256 /// Reports a complete synchronous event. |
235 external void _reportCompleteEvent(int start, | 257 external void _reportCompleteEvent(int start, |
236 int end, | 258 int end, |
237 String category, | 259 String category, |
238 String name, | 260 String name, |
239 String argumentsAsJson); | 261 String argumentsAsJson); |
| 262 |
| 263 /// Reports an instant event. |
| 264 external void _reportInstantEvent(int start, |
| 265 String category, |
| 266 String name, |
| 267 String argumentsAsJson); |
OLD | NEW |