OLD | NEW |
| (Empty) |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 library tracing; | |
6 | |
7 import 'dart:async'; | |
8 import 'dart:collection'; | |
9 import 'dart:convert'; | |
10 import 'dart:core'; | |
11 import 'dart:io'; | |
12 import 'dart:isolate'; | |
13 | |
14 import 'package:common/src/trace_provider_impl.dart'; | |
15 export 'package:common/src/trace_provider_impl.dart' show TraceSendTiming; | |
16 | |
17 import 'package:mojo/application.dart'; | |
18 import 'package:mojo/core.dart'; | |
19 import 'package:mojo_services/tracing/tracing.mojom.dart'; | |
20 | |
21 // Phases indicating the nature of the event in the trace log. | |
22 // These should be in sync with definitions in | |
23 // //base/trace_event/trace_event.h | |
24 const traceEventInstant = "I"; | |
25 const traceEventPhaseBegin = "B"; | |
26 const traceEventPhaseEnd = "E"; | |
27 const traceEventPhaseAsyncBegin = "S"; | |
28 const traceEventPhaseAsyncEnd = "F"; | |
29 const traceEventDuration = "X"; | |
30 | |
31 // TracingHelper is used by Dart code running in the Mojo shell in order | |
32 // to perform tracing. | |
33 class TracingHelper { | |
34 TraceProviderImpl _impl; | |
35 int _tid; | |
36 static TracingHelper _tracing; | |
37 // Construct an instance of TracingHelper from within your application's | |
38 // |initialize()| method. |appName| will be used to form a thread identifier | |
39 // for use in trace messages. If |appName| is longer than 20 characters then | |
40 // only the last 20 characters of |appName| will be used. | |
41 TracingHelper.fromApplication(Application app, String appName, | |
42 [TraceSendTiming timing = TraceSendTiming.IMMEDIATE]) { | |
43 // Masked because the tid is expected to be a 32-bit int. | |
44 _tid = [appName, Isolate.current] | |
45 .fold(7, (hash, element) => 31 * hash + element.hashCode) & | |
46 0x7fffffff; | |
47 _impl = new TraceProviderImpl(timing); | |
48 ApplicationConnection connection = app.connectToApplication("mojo:tracing"); | |
49 connection.provideService(TraceProviderName, (e) { | |
50 _impl.connect(e); | |
51 }); | |
52 assert(_tracing == null); | |
53 _tracing = this; | |
54 } | |
55 | |
56 // Factory to return the singleton instance of the TracingHelper. The isolate | |
57 // must have constructed the object using TracingHelper.fromApplication | |
58 // atleast once before using this factory. | |
59 factory TracingHelper() { | |
60 assert(_tracing != null); | |
61 return _tracing; | |
62 } | |
63 | |
64 bool isActive() { | |
65 return (_impl != null) && _impl.isActive(); | |
66 } | |
67 | |
68 // Invoke this at the beginning of a synchronous function whose | |
69 // duration you wish to trace. Invoke |end()| on the returned object. | |
70 FunctionTrace begin(String functionName, String categories, | |
71 {Map<String, String> args}) { | |
72 return _beginFunction(functionName, categories, traceEventPhaseBegin, | |
73 args: args); | |
74 } | |
75 | |
76 // Invoke this right before an asynchronous function whose duration | |
77 // you wish to trace. Invoke |end()| on the returned object. | |
78 FunctionTrace beginAsync(String functionName, String categories, | |
79 {Map<String, String> args}) { | |
80 return _beginFunction(functionName, categories, traceEventPhaseAsyncBegin, | |
81 args: args); | |
82 } | |
83 | |
84 void traceInstant(String name, String categories, | |
85 {Map<String, String> args}) { | |
86 _sendTraceMessage(name, categories, traceEventInstant, 0, args: args); | |
87 } | |
88 | |
89 void traceDuration(String name, String categories, int start, int end, | |
90 {Map<String, String> args}) { | |
91 _sendTraceMessage(name, categories, traceEventDuration, 0, | |
92 args: args, start: start, duration: end - start); | |
93 } | |
94 | |
95 FunctionTrace _beginFunction( | |
96 String functionName, String categories, String phase, | |
97 {Map<String, String> args}) { | |
98 assert(functionName != null); | |
99 final trace = new _FunctionTraceImpl( | |
100 this, isActive() ? functionName : null, categories, phase); | |
101 _sendTraceMessage(functionName, categories, phase, trace.hashCode, | |
102 args: args); | |
103 return trace; | |
104 } | |
105 | |
106 void _endFunction( | |
107 String functionName, String categories, String phase, int traceId) { | |
108 _sendTraceMessage(functionName, categories, phase, traceId); | |
109 } | |
110 | |
111 void _sendTraceMessage( | |
112 String name, String categories, String phase, int traceId, | |
113 {Map<String, String> args, int start, int duration}) { | |
114 if (isActive()) { | |
115 var time = (start != null) ? start : getTimeTicksNow(); | |
116 var map = new HashMap(); | |
117 map["name"] = name; | |
118 map["cat"] = categories; | |
119 map["ph"] = phase; | |
120 map["ts"] = time; | |
121 map["pid"] = pid; | |
122 map["tid"] = _tid; | |
123 map["id"] = traceId; | |
124 if (duration != null) { | |
125 map["dur"] = duration; | |
126 } | |
127 if (args != null) { | |
128 map["args"] = args; | |
129 } | |
130 _impl.sendTraceMessage(JSON.encode(map)); | |
131 } | |
132 } | |
133 | |
134 // A convenience method that wraps a closure in a begin-end pair of | |
135 // tracing calls. | |
136 dynamic trace(String functionName, String categories, closure(), | |
137 {Map<String, String> args}) { | |
138 FunctionTrace ft = begin(functionName, categories, args: args); | |
139 final returnValue = closure(); | |
140 ft.end(); | |
141 return returnValue; | |
142 } | |
143 | |
144 // A convenience method that wraps a closure in a begin-end pair of | |
145 // async tracing calls. The return value should either be returned or awaited. | |
146 Future traceAsync(String functionName, String categories, Future closure(), | |
147 {Map<String, String> args}) { | |
148 FunctionTrace ft = beginAsync(functionName, categories, args: args); | |
149 final Future returnValue = closure(); | |
150 returnValue.whenComplete(ft.end); | |
151 return returnValue; | |
152 } | |
153 } | |
154 | |
155 // An instance of FunctionTrace is returned from |begin()|, |beginAsync()|. | |
156 // Invoke |end()| to end the trace from every exit point in the function you are | |
157 // tracing. | |
158 abstract class FunctionTrace { | |
159 void end(); | |
160 } | |
161 | |
162 class _FunctionTraceImpl implements FunctionTrace { | |
163 TracingHelper _tracing; | |
164 String _functionName; | |
165 String _categories; | |
166 String _beginPhase; | |
167 | |
168 _FunctionTraceImpl( | |
169 this._tracing, this._functionName, this._categories, this._beginPhase) { | |
170 assert(_beginPhase == traceEventPhaseBegin || | |
171 _beginPhase == traceEventPhaseAsyncBegin); | |
172 } | |
173 | |
174 @override | |
175 void end() { | |
176 if (_functionName != null) { | |
177 if (_beginPhase == traceEventPhaseBegin) { | |
178 _tracing._endFunction( | |
179 _functionName, _categories, traceEventPhaseEnd, hashCode); | |
180 } else if (_beginPhase == traceEventPhaseAsyncBegin) { | |
181 _tracing._endFunction( | |
182 _functionName, _categories, traceEventPhaseAsyncEnd, hashCode); | |
183 } | |
184 } | |
185 } | |
186 } | |
OLD | NEW |