Index: sdk/lib/developer/timeline.dart |
diff --git a/sdk/lib/developer/timeline.dart b/sdk/lib/developer/timeline.dart |
index 0b7cd41e6b8852544795335419037410933c3da5..3f9ef56fe072b59217cddc9cf7360b9e3401defb 100644 |
--- a/sdk/lib/developer/timeline.dart |
+++ b/sdk/lib/developer/timeline.dart |
@@ -9,12 +9,94 @@ const bool _isProduct = const bool.fromEnvironment("dart.vm.product"); |
typedef dynamic TimelineSyncFunction(); |
typedef Future TimelineAsyncFunction(); |
+/// A class to represent Flow events. |
+/// |
+/// [Flow] objects are used to thread flow events between timeline slices, |
+/// for example, those created with the [Timeline] class below. Adding |
+/// [Flow] objects cause arrows to be drawn between slices in Chrome's trace |
+/// viewer. The arrows start at e.g [Timeline] events that are passed a |
+/// [Flow.begin] object, go through [Timeline] events that are passed a |
+/// [Flow.step] object, and end at [Timeline] events that are passed a |
+/// [Flow.end] object, all having the same [Flow.id]. For example: |
+/// |
+/// ```dart |
+/// var flow = Flow.begin(); |
+/// Timeline.timeSync('flow_test', () { |
+/// doSomething(); |
+/// }, flow: flow); |
+/// |
+/// Timeline.timeSync('flow_test', () { |
+/// doSomething(); |
+/// }, flow: Flow.step(flow.id)); |
+/// |
+/// Timeline.timeSync('flow_test', () { |
+/// doSomething(); |
+/// }, flow: Flow.end(flow.id)); |
+/// ``` |
+class Flow { |
+ // These values must be kept in sync with the enum "EventType" in |
+ // runtime/vm/timeline.h. |
+ static const int _begin = 9; |
+ static const int _step = 10; |
+ static const int _end = 11; |
+ |
+ final int _type; |
+ |
+ /// The flow id of the flow event. |
+ final int id; |
+ |
+ Flow._(this._type, this.id); |
+ |
+ /// A "begin" Flow event. |
+ /// |
+ /// When passed to a [Timeline] method, generates a "begin" Flow event. |
+ /// If [id] is not provided, an id that conflicts with no other Dart-generated |
+ /// flow id's will be generated. |
+ static Flow begin({int id}) { |
+ return new Flow._(_begin, id ?? _getNextAsyncId()); |
+ } |
+ |
+ /// A "step" Flow event. |
+ /// |
+ /// When passed to a [Timeline] method, generates a "step" Flow event. |
+ /// The [id] argument is required. It can come either from another [Flow] |
+ /// event, or some id that comes from the environment. |
+ static Flow step(int id) => new Flow._(_step, id); |
+ |
+ /// An "end" Flow event. |
+ /// |
+ /// When passed to a [Timeline] method, generates a "end" Flow event. |
+ /// The [id] argument is required. It can come either from another [Flow] |
+ /// event, or some id that comes from the environment. |
+ static Flow end(int id) => new Flow._(_end, id); |
+} |
+ |
/// Add to the timeline. |
+/// |
+/// [Timeline]'s methods add synchronous events to the timeline. When |
+/// generating a timeline in Chrome's tracing format, using [Timeline] generates |
+/// "Complete" events. [Timeline]'s [startSync] and [endSync] can be used |
+/// explicitly, or implicitly by wrapping a closure in [timeSync]. For exmaple: |
+/// |
+/// ```dart |
+/// Timeline.startSync("Doing Something"); |
+/// doSomething(); |
+/// Timeline.finishSync(); |
+/// ``` |
+/// |
+/// Or: |
+/// |
+/// ```dart |
+/// Timeline.timeSync("Doing Something", () { |
+/// doSomething(); |
+/// }); |
+/// ``` |
class Timeline { |
/// Start a synchronous operation labeled [name]. Optionally takes |
- /// a [Map] of [arguments]. This operation must be finished before |
+ /// a [Map] of [arguments]. This slice may also optionally be associated with |
+ /// a [Flow] event. This operation must be finished before |
/// returning to the event queue. |
- static void startSync(String name, {Map arguments}) { |
+ static void startSync(String name, {Map arguments, Flow flow}) { |
if (_isProduct) { |
return; |
} |
@@ -30,6 +112,9 @@ class Timeline { |
if (arguments is Map) { |
block._appendArguments(arguments); |
} |
+ if (flow is Flow) { |
+ block.flow = flow; |
+ } |
_stack.add(block); |
} |
@@ -74,8 +159,8 @@ class Timeline { |
/// 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); |
+ {Map arguments, Flow flow}) { |
+ startSync(name, arguments: arguments, flow: flow); |
try { |
return function(); |
} finally { |
@@ -225,6 +310,9 @@ class _SyncBlock { |
// The start time stamp of the thread cpu clock. |
final int _startCpu; |
+ /// An (optional) flow event associated with this block. |
+ Flow _flow; |
+ |
_SyncBlock._(this.name, this._start, this._startCpu); |
/// Finish this block of time. At this point, this block can no longer be |
@@ -233,6 +321,10 @@ class _SyncBlock { |
// Report event to runtime. |
_reportCompleteEvent( |
_start, _startCpu, category, name, _argumentsAsJson(_arguments)); |
+ if (_flow != null) { |
+ _reportFlowEvent(_start, _startCpu, category, name, _flow._type, _flow.id, |
+ _argumentsAsJson(null)); |
+ } |
} |
void _appendArguments(Map arguments) { |
@@ -244,6 +336,10 @@ class _SyncBlock { |
} |
_arguments.addAll(arguments); |
} |
+ |
+ void set flow(Flow f) { |
+ _flow = f; |
+ } |
} |
String _fastPathArguments; |
@@ -283,6 +379,10 @@ external void _reportTaskEvent(int start, int taskId, String phase, |
external void _reportCompleteEvent(int start, int startCpu, String category, |
String name, String argumentsAsJson); |
+/// Reports a flow event. |
+external void _reportFlowEvent(int start, int startCpu, String category, |
+ String name, int type, int id, String argumentsAsJson); |
+ |
/// Reports an instant event. |
external void _reportInstantEvent( |
int start, String category, String name, String argumentsAsJson); |