Index: pkg/dev_compiler/tool/input_sdk/lib/developer/timeline.dart |
diff --git a/pkg/dev_compiler/tool/input_sdk/lib/developer/timeline.dart b/pkg/dev_compiler/tool/input_sdk/lib/developer/timeline.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b6118af6eabf3a337c7f9a5b1a36b864e1e7798d |
--- /dev/null |
+++ b/pkg/dev_compiler/tool/input_sdk/lib/developer/timeline.dart |
@@ -0,0 +1,328 @@ |
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+part of dart.developer; |
+ |
+const bool _isProduct = const bool.fromEnvironment("dart.vm.product"); |
+ |
+typedef dynamic TimelineSyncFunction(); |
+typedef Future TimelineAsyncFunction(); |
+ |
+/// Add to the timeline. |
+class Timeline { |
+ /// Start a synchronous operation labeled [name]. Optionally takes |
+ /// a [Map] of [arguments]. This operation must be finished before |
+ /// returning to the event queue. |
+ static void startSync(String name, {Map arguments}) { |
+ if (_isProduct) { |
+ return; |
+ } |
+ if (name is! String) { |
+ throw new ArgumentError.value(name, |
+ 'name', |
+ 'Must be a String'); |
+ } |
+ if (!_isDartStreamEnabled()) { |
+ // Push a null onto the stack and return. |
+ _stack.add(null); |
+ return; |
+ } |
+ var block = new _SyncBlock._(name, _getTraceClock(), _getThreadCpuClock()); |
+ if (arguments is Map) { |
+ block._appendArguments(arguments); |
+ } |
+ _stack.add(block); |
+ } |
+ |
+ /// Finish the last synchronous operation that was started. |
+ static void finishSync() { |
+ if (_isProduct) { |
+ return; |
+ } |
+ if (_stack.length == 0) { |
+ throw new StateError( |
+ 'Uneven calls to startSync and finishSync'); |
+ } |
+ // Pop top item off of stack. |
+ var block = _stack.removeLast(); |
+ if (block == null) { |
+ // Dart stream was disabled when startSync was called. |
+ return; |
+ } |
+ // Finish it. |
+ block.finish(); |
+ } |
+ |
+ /// Emit an instant event. |
+ static void instantSync(String name, {Map arguments}) { |
+ if (_isProduct) { |
+ return; |
+ } |
+ if (name is! String) { |
+ throw new ArgumentError.value(name, |
+ 'name', |
+ 'Must be a String'); |
+ } |
+ if (!_isDartStreamEnabled()) { |
+ // Stream is disabled. |
+ return; |
+ } |
+ Map instantArguments; |
+ if (arguments is Map) { |
+ instantArguments = new Map.from(arguments); |
+ } |
+ _reportInstantEvent(_getTraceClock(), |
+ 'Dart', |
+ name, |
+ _argumentsAsJson(instantArguments)); |
+ } |
+ |
+ |
+ /// A utility method to time a synchronous [function]. Internally calls |
+ /// [function] bracketed by calls to [startSync] and [finishSync]. |
+ static dynamic timeSync(String name, |
+ TimelineSyncFunction function, |
+ {Map arguments}) { |
+ startSync(name, arguments: arguments); |
+ try { |
+ return function(); |
+ } finally { |
+ finishSync(); |
+ } |
+ } |
+ |
+ /// The current time stamp from the clock used by the timeline. Units are |
+ /// microseconds. |
+ static int get now => _getTraceClock(); |
+ static final List<_SyncBlock> _stack = new List<_SyncBlock>(); |
+ static final int _isolateId = _getIsolateNum(); |
+ static final String _isolateIdString = _isolateId.toString(); |
+} |
+ |
+/// An asynchronous task on the timeline. An asynchronous task can have many |
+/// (nested) synchronous operations. Synchronous operations can live longer than |
+/// the current isolate event. To pass a [TimelineTask] to another isolate, |
+/// you must first call [pass] to get the task id and then construct a new |
+/// [TimelineTask] in the other isolate. |
+class TimelineTask { |
+ /// Create a task. [taskId] will be set by the system. |
+ TimelineTask() |
+ : _taskId = _getNextAsyncId() { |
+ } |
+ |
+ /// Create a task with an explicit [taskId]. This is useful if you are |
+ /// passing a task from one isolate to another. |
+ TimelineTask.withTaskId(int taskId) |
+ : _taskId = taskId { |
+ if (taskId is! int) { |
+ throw new ArgumentError.value(taskId, |
+ 'taskId', |
+ 'Must be an int'); |
+ } |
+ } |
+ |
+ /// Start a synchronous operation within this task named [name]. |
+ /// Optionally takes a [Map] of [arguments]. |
+ void start(String name, {Map arguments}) { |
+ if (_isProduct) { |
+ return; |
+ } |
+ if (name is! String) { |
+ throw new ArgumentError.value(name, |
+ 'name', |
+ 'Must be a String'); |
+ } |
+ var block = new _AsyncBlock._(name, _taskId); |
+ if (arguments is Map) { |
+ block._appendArguments(arguments); |
+ } |
+ _stack.add(block); |
+ block._start(); |
+ } |
+ |
+ /// Emit an instant event for this task. |
+ void instant(String name, {Map arguments}) { |
+ if (_isProduct) { |
+ return; |
+ } |
+ if (name is! String) { |
+ throw new ArgumentError.value(name, |
+ 'name', |
+ 'Must be a String'); |
+ } |
+ Map instantArguments; |
+ if (arguments is Map) { |
+ instantArguments = new Map.from(arguments); |
+ } |
+ _reportTaskEvent(_getTraceClock(), |
+ _taskId, |
+ 'n', |
+ 'Dart', |
+ name, |
+ _argumentsAsJson(instantArguments)); |
+ } |
+ |
+ /// Finish the last synchronous operation that was started. |
+ void finish() { |
+ if (_isProduct) { |
+ return; |
+ } |
+ if (_stack.length == 0) { |
+ throw new StateError( |
+ 'Uneven calls to start and finish'); |
+ } |
+ // Pop top item off of stack. |
+ var block = _stack.removeLast(); |
+ block._finish(); |
+ } |
+ |
+ /// Retrieve the [TimelineTask]'s task id. Will throw an exception if the |
+ /// stack is not empty. |
+ int pass() { |
+ if (_stack.length > 0) { |
+ throw new StateError( |
+ 'You cannot pass a TimelineTask without finishing all started ' |
+ 'operations'); |
+ } |
+ int r = _taskId; |
+ return r; |
+ } |
+ |
+ final int _taskId; |
+ final List<_AsyncBlock> _stack = []; |
+} |
+ |
+/// An asynchronous block of time on the timeline. This block can be kept |
+/// open across isolate messages. |
+class _AsyncBlock { |
+ /// The category this block belongs to. |
+ final String category = 'Dart'; |
+ /// The name of this block. |
+ final String name; |
+ /// The asynchronous task id. |
+ final int _taskId; |
+ /// An (optional) set of arguments which will be serialized to JSON and |
+ /// associated with this block. |
+ Map _arguments; |
+ |
+ _AsyncBlock._(this.name, this._taskId); |
+ |
+ // Emit the start event. |
+ void _start() { |
+ _reportTaskEvent(_getTraceClock(), |
+ _taskId, |
+ 'b', |
+ category, |
+ name, |
+ _argumentsAsJson(_arguments)); |
+ } |
+ |
+ // Emit the finish event. |
+ void _finish() { |
+ _reportTaskEvent(_getTraceClock(), |
+ _taskId, |
+ 'e', |
+ category, |
+ name, |
+ _argumentsAsJson(null)); |
+ } |
+ |
+ void _appendArguments(Map arguments) { |
+ if (_arguments == null) { |
+ _arguments = {}; |
+ } |
+ _arguments.addAll(arguments); |
+ } |
+} |
+ |
+/// A synchronous block of time on the timeline. This block should not be |
+/// kept open across isolate messages. |
+class _SyncBlock { |
+ /// The category this block belongs to. |
+ final String category = 'Dart'; |
+ /// The name of this block. |
+ final String name; |
+ /// An (optional) set of arguments which will be serialized to JSON and |
+ /// associated with this block. |
+ Map _arguments; |
+ // The start time stamp. |
+ final int _start; |
+ // The start time stamp of the thread cpu clock. |
+ final int _startCpu; |
+ |
+ _SyncBlock._(this.name, |
+ this._start, |
+ this._startCpu); |
+ |
+ /// Finish this block of time. At this point, this block can no longer be |
+ /// used. |
+ void finish() { |
+ // Report event to runtime. |
+ _reportCompleteEvent(_start, |
+ _startCpu, |
+ category, |
+ name, |
+ _argumentsAsJson(_arguments)); |
+ } |
+ |
+ void _appendArguments(Map arguments) { |
+ if (arguments == null) { |
+ return; |
+ } |
+ if (_arguments == null) { |
+ _arguments = {}; |
+ } |
+ _arguments.addAll(arguments); |
+ } |
+} |
+ |
+String _fastPathArguments; |
+String _argumentsAsJson(Map arguments) { |
+ if ((arguments == null) || (arguments.length == 0)) { |
+ // Fast path no arguments. Avoid calling JSON.encode. |
+ if (_fastPathArguments == null) { |
+ _fastPathArguments = '{"isolateNumber":"${Timeline._isolateId}"}'; |
+ } |
+ return _fastPathArguments; |
+ } |
+ // Add isolateNumber to arguments map. |
+ arguments['isolateNumber'] = Timeline._isolateIdString; |
+ return JSON.encode(arguments); |
+} |
+ |
+/// Returns true if the Dart Timeline stream is enabled. |
+external bool _isDartStreamEnabled(); |
+ |
+/// Returns the next async task id. |
+external int _getNextAsyncId(); |
+ |
+/// Returns the current value from the trace clock. |
+external int _getTraceClock(); |
+ |
+/// Returns the current value from the thread CPU usage clock. |
+external int _getThreadCpuClock(); |
+ |
+/// Returns the isolate's main port number. |
+external int _getIsolateNum(); |
+ |
+/// Reports an event for a task. |
+external void _reportTaskEvent(int start, |
+ int taskId, |
+ String phase, |
+ String category, |
+ String name, |
+ String argumentsAsJson); |
+ |
+/// Reports a complete synchronous event. |
+external void _reportCompleteEvent(int start, |
+ int startCpu, |
+ String category, |
+ String name, |
+ String argumentsAsJson); |
+ |
+/// Reports an instant event. |
+external void _reportInstantEvent(int start, |
+ String category, |
+ String name, |
+ String argumentsAsJson); |