diff --git a/benchmark/web/wtf.dart b/benchmark/web/wtf.dart index eb398a27f..1b389c321 100644 --- a/benchmark/web/wtf.dart +++ b/benchmark/web/wtf.dart @@ -1,11 +1,11 @@ library wtf_test_app; -import 'package:angular/wtf.dart'; +import 'package:angular/tracing.dart'; import 'dart:html'; import 'dart:js' show context; main() { - traceInit(context); + traceDetectWTF(context); var _main = traceCreateScope('main()'); var _querySelector = traceCreateScope('Node#querySelector()'); var _DivElement = traceCreateScope('DivElement()'); @@ -21,7 +21,7 @@ main() { traceLeave(s); s = traceEnter(_ElementText); - div.text = 'Hello WTF! (enabled: ${wtfEnabled})'; + div.text = 'Hello WTF! (enabled: ${traceEnabled})'; traceLeave(s); s = traceEnter(_NodeAppend); diff --git a/lib/angular.dart b/lib/angular.dart index d79b93b3d..8674068db 100644 --- a/lib/angular.dart +++ b/lib/angular.dart @@ -5,6 +5,7 @@ export 'package:angular/application.dart'; export 'package:angular/core/module.dart'; export 'package:angular/directive/module.dart'; export 'package:angular/core/annotation.dart'; +export 'package:angular/tracing.dart'; export 'package:angular/introspection.dart' hide elementExpando, publishToJavaScript; export 'package:angular/formatter/module.dart'; diff --git a/lib/application.dart b/lib/application.dart index f4068cd71..5e39c4a09 100644 --- a/lib/application.dart +++ b/lib/application.dart @@ -82,7 +82,7 @@ import 'package:angular/directive/module.dart'; import 'package:angular/formatter/module_internal.dart'; import 'package:angular/routing/module.dart'; import 'package:angular/introspection.dart'; -import 'package:angular/wtf.dart'; +import 'package:angular/ng_tracing.dart'; import 'package:angular/core_dom/static_keys.dart'; import 'package:angular/core_dom/directive_injector.dart'; @@ -130,7 +130,6 @@ class AngularModule extends Module { * applicationFactory to bootstrap your Angular application. * */ -var _Application_run = traceCreateScope('Application#run()'); abstract class Application { static _find(String selector, [dom.Element defaultElement]) { var element = dom.document.querySelector(selector); @@ -152,7 +151,7 @@ abstract class Application { dom.Element selector(String selector) => element = _find(selector); Application(): element = _find('[ng-app]', dom.window.document.documentElement) { - traceInit(context); + traceDetectWTF(context); modules.add(ngModule); ngModule..bind(VmTurnZone, toValue: zone) ..bind(Application, toValue: this) @@ -175,7 +174,7 @@ abstract class Application { } Injector run() { - var scope = traceEnter(_Application_run); + var scope = traceEnter(Application_bootstrap); try { publishToJavaScript(); return zone.run(() { diff --git a/lib/change_detection/watch_group.dart b/lib/change_detection/watch_group.dart index 82e4052b9..1ce3ca194 100644 --- a/lib/change_detection/watch_group.dart +++ b/lib/change_detection/watch_group.dart @@ -2,18 +2,12 @@ library angular.watch_group; import 'package:angular/change_detection/change_detection.dart'; import 'dart:collection'; -import 'package:angular/wtf.dart'; +import 'package:angular/ng_tracing.dart'; part 'linked_list.dart'; part 'ast.dart'; part 'prototype_map.dart'; -var _WatchGroup_detect = traceCreateScope('WatchGroup#detect()'); -var _WatchGroup_fields = traceCreateScope('WatchGroup#field()'); -var _WatchGroup_field_handler = traceCreateScope('WatchGroup#field_handler()'); -var _WatchGroup_eval = traceCreateScope('WatchGroup#eval()'); -var _WatchGroup_reaction = traceCreateScope('WatchGroup#reaction()'); - /** * A function that is notified of changes to the model. * @@ -399,15 +393,13 @@ class RootWatchGroup extends WatchGroup { AvgStopwatch evalStopwatch, AvgStopwatch processStopwatch}) { // Process the Records from the change detector - var sDetect = traceEnter(_WatchGroup_detect); - var s = traceEnter(_WatchGroup_fields); + var sDetect = traceEnter(ChangeDetector_check); + var sFields = traceEnter(ChangeDetector_fields); Iterator> changedRecordIterator = (_changeDetector as ChangeDetector<_Handler>).collectChanges( exceptionHandler:exceptionHandler, stopwatch: fieldStopwatch); - traceLeave(s); if (processStopwatch != null) processStopwatch.start(); - s = traceEnter(_WatchGroup_field_handler); while (changedRecordIterator.moveNext()) { var record = changedRecordIterator.current; if (changeLog != null) changeLog(record.handler.expression, @@ -415,13 +407,13 @@ class RootWatchGroup extends WatchGroup { record.previousValue); record.handler.onChange(record); } - traceLeave(s); + traceLeave(sFields); if (processStopwatch != null) processStopwatch.stop(); if (evalStopwatch != null) evalStopwatch.start(); // Process our own function evaluations _EvalWatchRecord evalRecord = _evalWatchHead; - s = traceEnter(_WatchGroup_eval); + var sEval = traceEnter(ChangeDetector_eval); int evalCount = 0; while (evalRecord != null) { try { @@ -437,14 +429,14 @@ class RootWatchGroup extends WatchGroup { evalRecord = evalRecord._nextEvalWatch; } - traceLeave(s); + traceLeave(sEval); traceLeave(sDetect); if (evalStopwatch != null) evalStopwatch..stop()..increment(evalCount); // Because the handler can forward changes between each other synchronously // We need to call reaction functions asynchronously. This processes the // asynchronous reaction function queue. - s = traceEnter(_WatchGroup_reaction); + var sReaction = traceEnter(ChangeDetector_reaction); int count = 0; if (processStopwatch != null) processStopwatch.start(); Watch dirtyWatch = _dirtyWatchHead; @@ -468,7 +460,7 @@ class RootWatchGroup extends WatchGroup { _dirtyWatchTail = null; root._removeCount = 0; } - traceLeave(s); + traceLeaveVal(sReaction, count); if (processStopwatch != null) processStopwatch..stop()..increment(count); return count; } @@ -514,7 +506,12 @@ class Watch { void invoke() { if (_deleted || !_dirty) return; _dirty = false; - reactionFn(_record.currentValue, _record.previousValue); + var s = traceEnabled ? traceEnter1(ChangeDetector_invoke, expression) : null; + try { + reactionFn(_record.currentValue, _record.previousValue); + } finally { + if (traceEnabled) traceLeave(s); + } } void remove() { diff --git a/lib/core/module_internal.dart b/lib/core/module_internal.dart index 2ad07a969..a024f1480 100644 --- a/lib/core/module_internal.dart +++ b/lib/core/module_internal.dart @@ -11,7 +11,7 @@ import 'package:di/annotations.dart'; import 'package:angular/core/parser/parser.dart'; import 'package:angular/core/parser/lexer.dart'; import 'package:angular/utils.dart'; -import 'package:angular/wtf.dart'; +import 'package:angular/ng_tracing.dart'; import 'package:angular/core/annotation_src.dart'; diff --git a/lib/core/scope.dart b/lib/core/scope.dart index a8a286f41..2f0060901 100644 --- a/lib/core/scope.dart +++ b/lib/core/scope.dart @@ -3,14 +3,6 @@ part of angular.core_internal; typedef EvalFunction0(); typedef EvalFunction1(context); -var _Scope_apply = traceCreateScope('Scope#apply()'); -var _Scope_digest = traceCreateScope('Scope#digest()'); -var _Scope_flush = traceCreateScope('Scope#flush()'); -var _Scope_domWrite = traceCreateScope('Scope#domWrite()'); -var _Scope_domRead = traceCreateScope('Scope#domRead()'); -var _Scope_assert = traceCreateScope('Scope#assert()'); -var _Scope_runAsync = traceCreateScope('Scope#runAsync()'); -var _Scope_createChild = traceCreateScope('Scope#createChild()'); /** * Injected into the listener function within [Scope.on] to provide event-specific details to the * scope listener. @@ -338,7 +330,7 @@ class Scope { /// Creates a child [Scope] with the given [childContext] Scope createChild(Object childContext) { - var s = traceEnter(_Scope_createChild); + var s = traceEnter(Scope_createChild); assert(isAttached); var child = new Scope(childContext, rootScope, this, _readWriteGroup.newGroup(childContext), @@ -746,7 +738,7 @@ class RootScope extends Scope { try { do { if (_domWriteHead != null) _stats.domWriteStart(); - var s = traceEnter(_Scope_domWrite); + var s = traceEnter(Scope_domWrite); while (_domWriteHead != null) { try { _domWriteHead.fn(); @@ -766,7 +758,7 @@ class RootScope extends Scope { processStopwatch: _scopeStats.processStopwatch); } if (_domReadHead != null) _stats.domReadStart(); - s = traceEnter(_Scope_domRead); + s = traceEnter(Scope_domRead); while (_domReadHead != null) { try { _domReadHead.fn(); @@ -823,7 +815,7 @@ class RootScope extends Scope { } _runAsyncFns() { - var s = traceEnter(_Scope_runAsync); + var s = traceEnter(Scope_execAsync); var count = 0; while (_runAsyncHead != null) { try { @@ -865,10 +857,10 @@ class RootScope extends Scope { _state = to; if (_state_wtf_scope != null) traceLeave(_state_wtf_scope); var wtfScope = null; - if (to == STATE_APPLY) wtfScope = _Scope_apply; - else if (to == STATE_DIGEST) wtfScope = _Scope_digest; - else if (to == STATE_FLUSH) wtfScope = _Scope_flush; - else if (to == STATE_FLUSH_ASSERT) wtfScope = _Scope_assert; + if (to == STATE_APPLY) wtfScope = Scope_apply; + else if (to == STATE_DIGEST) wtfScope = Scope_digest; + else if (to == STATE_FLUSH) wtfScope = Scope_flush; + else if (to == STATE_FLUSH_ASSERT) wtfScope = Scope_assert; _state_wtf_scope = wtfScope == null ? null : traceEnter(wtfScope); } } diff --git a/lib/core/zone.dart b/lib/core/zone.dart index f0ea4aa03..01dc6aa13 100644 --- a/lib/core/zone.dart +++ b/lib/core/zone.dart @@ -39,9 +39,6 @@ class LongStackTrace { } } -var _VmTurnZone_onRunBase = traceCreateScope('VmTurnZone#onRun()'); -var _VmTurnZone_onScheduleMicrotask = traceCreateScope('VmTurnZone#onScheduleMicrotask()'); - /** * A [Zone] wrapper that lets you schedule tasks after its private microtask * queue is exhausted but before the next "turn", i.e. event loop iteration. @@ -92,7 +89,7 @@ class VmTurnZone { var _currentlyInTurn = false; dynamic _onRunBase(async.Zone self, async.ZoneDelegate delegate, async.Zone zone, fn()) { - var scope = traceEnter(_VmTurnZone_onRunBase); + var scope = traceEnter(VmTurnZone_run); _runningInTurn++; try { if (!_currentlyInTurn) { @@ -120,7 +117,7 @@ class VmTurnZone { _onRunBase(self, delegate, zone, () => delegate.runUnary(zone, fn, args)); void _onScheduleMicrotask(async.Zone self, async.ZoneDelegate delegate, async.Zone zone, fn()) { - var s = traceEnter(_VmTurnZone_onScheduleMicrotask); + var s = traceEnter(VmTurnZone_scheduleMicrotask); try { onScheduleMicrotask(() => delegate.run(zone, fn)); if (_runningInTurn == 0 && !_inFinishTurn) _finishTurn(zone, delegate); diff --git a/lib/core_dom/compiler.dart b/lib/core_dom/compiler.dart index 8f9557121..00cc82691 100644 --- a/lib/core_dom/compiler.dart +++ b/lib/core_dom/compiler.dart @@ -1,7 +1,5 @@ part of angular.core.dom_internal; -var _Compiler_call = traceCreateScope('Compiler#call()'); -var _Compiler_subTemplate = traceCreateScope('Compiler#subTemplate()'); @Injectable() class Compiler implements Function { @@ -11,7 +9,7 @@ class Compiler implements Function { Compiler(this._perf, this._expando); ViewFactory call(List elements, DirectiveMap directives) { - var s = traceEnter(_Compiler_call); + var s = traceEnter(Compiler_compile); var timerId; assert((timerId = _perf.startTimer('ng.compile', _html(elements))) != false); final elementBinders = []; @@ -141,7 +139,7 @@ class Compiler implements Function { DirectiveRef directiveRef, ElementBinder transcludedElementBinder, DirectiveMap directives) { - var s = traceEnter(_Compiler_subTemplate); + var s = traceEnter(Compiler_template); var anchorName = directiveRef.annotation.selector + (directiveRef.value != null ? '=' + directiveRef.value : ''); diff --git a/lib/core_dom/element_binder.dart b/lib/core_dom/element_binder.dart index 5c90afe77..f7aefb5c9 100644 --- a/lib/core_dom/element_binder.dart +++ b/lib/core_dom/element_binder.dart @@ -1,7 +1,5 @@ part of angular.core.dom_internal; -var _ElementBinder_directive = traceCreateScope('ElementBinder#createDirective(ascii name)'); -var _ElementBinder_setupBindings = traceCreateScope('ElementBinder#setupBindings(ascii name)'); class TemplateElementBinder extends ElementBinder { final DirectiveRef template; @@ -193,19 +191,13 @@ class ElementBinder { for(var i = 0; i < _usableDirectiveRefs.length; i++) { DirectiveRef ref = _usableDirectiveRefs[i]; var key = ref.typeKey; - var wtfArgs = wtfEnabled ? [ref.typeKey.toString()] : null; + var directiveName = traceEnabled ? ref.typeKey.toString() : null; if (identical(key, TEXT_MUSTACHE_KEY) || identical(key, ATTR_MUSTACHE_KEY)) continue; - s = traceEnter(_ElementBinder_directive, wtfArgs); + s = traceEnter1(Directive_create, directiveName); var directive; try { directive = directiveInjector.getByKey(ref.typeKey); - } finally { - traceLeave(s); - } - - s = traceEnter(_ElementBinder_setupBindings, wtfArgs); - try { if (ref.annotation is Controller) { scope.parentScope.context[(ref.annotation as Controller).publishAs] = directive; } diff --git a/lib/core_dom/http.dart b/lib/core_dom/http.dart index e8dcc17bc..e015b6654 100644 --- a/lib/core_dom/http.dart +++ b/lib/core_dom/http.dart @@ -445,7 +445,7 @@ class Http { cache, timeout }) { - var range = wtfEnabled ? traceAsyncStart('http:$method', url) : null; + var range = traceEnabled ? traceAsyncStart('http:$method', url) : null; if (timeout != null) { throw ['timeout not implemented']; } @@ -545,7 +545,7 @@ class Http { var result = chainResult is async.Future ? chainResult : new async.Future.value(chainResult); - if (wtfEnabled) { + if (traceEnabled) { return new async.Future(() { traceAsyncEnd(range); return result; diff --git a/lib/core_dom/module_internal.dart b/lib/core_dom/module_internal.dart index 151721689..72f7e06d0 100644 --- a/lib/core_dom/module_internal.dart +++ b/lib/core_dom/module_internal.dart @@ -22,7 +22,7 @@ export 'package:angular/core_dom/directive_injector.dart' show DirectiveInjector import 'package:angular/change_detection/watch_group.dart' show Watch, PrototypeMap; import 'package:angular/change_detection/ast_parser.dart'; import 'package:angular/core/registry.dart'; -import 'package:angular/wtf.dart'; +import 'package:angular/ng_tracing.dart'; import 'package:angular/directive/module.dart' show NgBaseCss; import 'dart:collection'; diff --git a/lib/core_dom/shadow_dom_component_factory.dart b/lib/core_dom/shadow_dom_component_factory.dart index b6c5ae242..cb7b69f8d 100644 --- a/lib/core_dom/shadow_dom_component_factory.dart +++ b/lib/core_dom/shadow_dom_component_factory.dart @@ -1,8 +1,5 @@ part of angular.core.dom_internal; -var _ComponentFactory_call = traceCreateScope('ComponentFactory#call()'); -var _ComponentFactory_styles = traceCreateScope('ComponentFactory#styles()'); - abstract class ComponentFactory { BoundComponentFactory bind(DirectiveRef ref, directives); } @@ -134,7 +131,7 @@ class BoundShadowDomComponentFactory implements BoundComponentFactory { Function call(dom.Element element) { return (DirectiveInjector injector, Scope scope, NgBaseCss baseCss, EventHandler eventHandler) { - var s = traceEnter(_ComponentFactory_call); + var s = traceEnter(View_createComponent); try { var shadowScope = scope.createChild(new HashMap()); // Isolate ComponentDirectiveInjector shadowInjector; @@ -203,7 +200,7 @@ class BoundShadowDomComponentFactory implements BoundComponentFactory { _insertCss(List cssList, dom.ShadowRoot shadowRoot, [dom.Node insertBefore = null]) { - var s = traceEnter(_ComponentFactory_styles); + var s = traceEnter(View_styles); for(int i = 0; i < cssList.length; i++) { var styleElement = cssList[i]; if (styleElement != null) { diff --git a/lib/core_dom/view_factory.dart b/lib/core_dom/view_factory.dart index a3e2f07d5..9fbd1246e 100644 --- a/lib/core_dom/view_factory.dart +++ b/lib/core_dom/view_factory.dart @@ -1,8 +1,5 @@ part of angular.core.dom_internal; -var _ViewFactory_call = traceCreateScope('ViewFactory#call(ascii html)'); -var _ViewFactory_bind = traceCreateScope('ViewFactory#bind()'); -var _ViewFactory_querySelectorAll = traceCreateScope('ViewFactory#querySelectorAll()'); /** * BoundViewFactory is a [ViewFactory] which does not need Injector because @@ -27,14 +24,14 @@ class ViewFactory implements Function { final List templateNodes; final List nodeLinkingInfos; final Profiler _perf; - List _wtfArgs; + String _debugHtml; ViewFactory(templateNodes, this.elementBinders, this._perf) : nodeLinkingInfos = computeNodeLinkingInfos(templateNodes), templateNodes = templateNodes { - if (wtfEnabled) { - _wtfArgs = [templateNodes.map((dom.Node e) { + if (traceEnabled) { + _debugHtml = templateNodes.map((dom.Node e) { if (e is dom.Element) { return (e as dom.Element).outerHtml; } else if (e is dom.Comment) { @@ -42,7 +39,7 @@ class ViewFactory implements Function { } else { return e.text; } - }).toList().join('')]; + }).toList().join(''); } } @@ -54,7 +51,7 @@ class ViewFactory implements Function { View call(Scope scope, DirectiveInjector directiveInjector, [List nodes /* TODO: document fragment */]) { - var s = traceEnter(_ViewFactory_call, _wtfArgs); + var s = traceEnter1(View_create, _debugHtml); assert(scope != null); if (nodes == null) { nodes = cloneElements(templateNodes); @@ -62,9 +59,7 @@ class ViewFactory implements Function { Animate animate = directiveInjector.getByKey(ANIMATE_KEY); EventHandler eventHandler = directiveInjector.getByKey(EVENT_HANDLER_KEY); var view = new View(nodes, scope, eventHandler); - var sBind = traceEnter(_ViewFactory_bind); _link(view, scope, nodes, eventHandler, animate, directiveInjector); - traceLeave(sBind); traceLeave(s); return view; @@ -124,9 +119,7 @@ class ViewFactory implements Function { } if (linkingInfo.ngBindingChildren) { - var s = traceEnter(_ViewFactory_querySelectorAll); var elts = (node as dom.Element).querySelectorAll('.ng-binding'); - traceLeave(s); for (int j = 0; j < elts.length; j++, elementBinderIndex++) { TaggedElementBinder tagged = elementBinders[elementBinderIndex]; _bindTagged(tagged, elementBinderIndex, rootInjector, elementInjectors, diff --git a/lib/ng_tracing.dart b/lib/ng_tracing.dart new file mode 100644 index 000000000..d50992986 --- /dev/null +++ b/lib/ng_tracing.dart @@ -0,0 +1,4 @@ +library angular.tracing.all; + +export 'package:angular/tracing.dart'; +export 'package:angular/ng_tracing_scopes.dart'; diff --git a/lib/ng_tracing_scopes.dart b/lib/ng_tracing_scopes.dart new file mode 100644 index 000000000..6c0d9a4f6 --- /dev/null +++ b/lib/ng_tracing_scopes.dart @@ -0,0 +1,188 @@ +/** + * Tracing scopes in AngularDart. + * + * This library contains the scope definitions used in AngularDart for tracing purposes. + */ +library angular.tracing.ng; + +import 'package:angular/tracing.dart'; + +/** + * Name: `Application#bootstrap()` + * + * Designates a bootstrapping of AngularDart application in response to [Application.run()]. + * It usually contains compilation of templates and initial [Scope.apply()] + */ +final Application_bootstrap = traceCreateScope('Application#bootstrap()'); + + + + +/** + * Name: `ChangeDetector#check()` + * + * Designates where AngularDart detects changes in the model. + * The checking is further subdivided into these sections: + * - `ChangeDetector#fields()` looking for changes in object fields. + * - `ChangeDetector#eval()` looking for changes by invoking functions. + */ +final ChangeDetector_check = traceCreateScope('ChangeDetector#check()'); + +/** + * Name: `ChangeDetector#fields()` + * + * Designates where AngularDart looks for changes in the model by differencing fields in watch + * expressions. + */ +final ChangeDetector_fields = traceCreateScope('ChangeDetector#fields()'); + +/** + * Name: `ChangeDetector#eval()` + * + * Designates where AngularDart looks for changes in the model by invoking functions in watch + * expressions. + */ +final ChangeDetector_eval = traceCreateScope('ChangeDetector#eval()'); + +/** + * Name: `ChangeDetector#reaction()` + * + * Designates time spent processing the changes which were detected in `ChangeDetector#check()`. + */ +final ChangeDetector_reaction = traceCreateScope('ChangeDetector#reaction()'); + +/** + * Name: `ChangeDetector#reaction()` + * + * Designates time spent processing the individual expressions in `ChangeDetector#reaction()`. + */ +final ChangeDetector_invoke = traceCreateScope('ChangeDetector#invoke(ascii expression)'); + + + + +/** + * Name: `Scope#apply()` + * + * When processing events angular transitions through stages in this sequence: + * + * - `Scope#apply()` + * - `Scope#digest()` + * - `Scope#flush()` + * - `Scope#domWrite()` + * - `Scope#domRead()` + * - `Scope#assert()` + */ +final Scope_apply = traceCreateScope('Scope#apply()'); + +/** + * Name: `Scope#digest()` + * + * Process non-DOM changes in the model. + */ +final Scope_digest = traceCreateScope('Scope#digest()'); + +/** + * Name: `Scope#flush()` + * + * Process DOM changes in the model. + */ +final Scope_flush = traceCreateScope('Scope#flush()'); + +/** + * Name: `Scope#domWrite()` + * + * Process DOM write coalescence queue. + */ +final Scope_domWrite = traceCreateScope('Scope#domWrite()'); + +/** + * Name: `Scope#domRead()` + * + * Process DOM read coalescence queue. + */ +final Scope_domRead = traceCreateScope('Scope#domRead()'); + +/** + * Name: `Scope#assert()` + * + * When asserts are enabled, verify that the `Scope#flush()` is idempotent, meaning it did + * not make any further model changes. + */ +final Scope_assert = traceCreateScope('Scope#assert()'); + + +/** + * Name: `Scope#execAsync()` + * + * Process asynchronous microtask queue. + */ +final Scope_execAsync = traceCreateScope('Scope#execAsync()'); + +/** + * Name: `Scope#create()` + * + * Create new Scope. + */ +final Scope_createChild = traceCreateScope('Scope#create()'); + +/** + * Name: `VmTurnZone#run()` + * + * Designates VM turn boundary, which ensures that Model changes get processed. + */ +final VmTurnZone_run = traceCreateScope('VmTurnZone#run()'); + +/** + * Name: `VmTurnZone#scheduleMicrotask()` + * + * Designates where new microtasks are scheduled. This is usually in response to creating [Future]s. + */ +final VmTurnZone_scheduleMicrotask = traceCreateScope('VmTurnZone#scheduleMicrotask()'); + + +/** + * Name: `Compiler#compile()` + * + * Designates where template HTML is compiled. Compilation is a process of walking the DOM and + * finding all of the directives. + */ +final Compiler_compile = traceCreateScope('Compiler#compile()'); + +/** + * Name: `Compiler#template()` + * + * Designates `@Template` directive needs to compile its children. For example `ng-repeat`. + */ +final Compiler_template = traceCreateScope('Compiler#template()'); + +/** + * Name: `View#create(ascii html)` + * + * Designates new views are created. + */ +final View_create = traceCreateScope('View#create(ascii html)'); + +/** + * Name: `View#createComponent()` + * + * Designates components are created in a view. Components are treated differently than + * other directives because they require creation of shadow scope and shadow DOM. + */ +final View_createComponent = traceCreateScope('View#createComponent()'); + +/** + * Name: `View#styles()` + * + * Designates where styles are inserted into component. + */ +final View_styles = traceCreateScope('View#styles()'); + + +/** + * Name: `Directive#create(ascii name)` + * + * Designates a particular directive is created. This includes the setting up of bindings for + * the directive. + */ +final Directive_create = traceCreateScope('Directive#create(ascii name)'); diff --git a/lib/tracing.dart b/lib/tracing.dart new file mode 100644 index 000000000..92ac903df --- /dev/null +++ b/lib/tracing.dart @@ -0,0 +1,186 @@ +/** + * Tracing for AngularDart framework and applications. + * + * The tracing API hooks up to either [WTF](http://google.github.io/tracing-framework/) or + * [Dart Observatory](https://www.dartlang.org/tools/observatory/). + */ +library angular.tracing; + +import "dart:profiler"; + +bool traceEnabled = false; +dynamic /* JsObject */ _trace; +dynamic /* JsObject */ _events; +dynamic /* JsFunction */ _createScope; +dynamic /* JsFunction */ _enterScope; +dynamic /* JsFunction */ _leaveScope; +dynamic /* JsFunction */ _beginTimeRange; +dynamic /* JsFunction */ _endTimeRange; +final List _arg1 = [null]; +final List _arg2 = [null, null]; + +/** + * Use this method to detect if [WTF](http://google.github.io/tracing-framework/) has been enabled. + * + * To make sure that this library can be used DartVM where no JavaScript is available this + * method needs to be called with JavaScript context. + * + * If the method is not called or if WTF has not been detected that the tracing defaults to + * Dart Observatory. + * + * import "dart:js" show context; + * + * detectWTF(context); + */ +traceDetectWTF(dynamic /* JsObject */ context) { + if (context.hasProperty('wtf')) { + dynamic /* JsObject */ wtf = context['wtf']; + if (wtf.hasProperty('trace')) { + traceEnabled = true; + _trace = wtf['trace']; + _events = _trace['events']; + _createScope = _events['createScope']; + _enterScope = _trace['enterScope']; + _leaveScope = _trace['leaveScope']; + _beginTimeRange = _trace['beginTimeRange']; + _endTimeRange = _trace['endTimeRange']; + } + + } +} + +/** + * Create trace scope. Scopes must be strictly nested and are analogous to stack frames, but + * do not have to follow the stack frames. Instead it is recommended that they follow logical + * nesting. + */ +dynamic /* JsFunction */ traceCreateScope(signature, [flags]) { + if (traceEnabled) { + _arg2[0] = signature; + _arg2[1] = flags; + return _createScope.apply(_arg2, thisArg: _events); + } else { + return new UserTag(signature); + } +} + +/** + * Used to mark scope entry. + * + * final myScope = traceCreateScope('myMethod'); + * + * someMethod() { + * var s = traceEnter(myScope); + * try { + * // do something + * } finally { + * traceLeave(s); + * } + * } + */ +dynamic /* JsObject */ traceEnter(dynamic /* JsFunction */ scope) { + if (traceEnabled) { + return scope.apply(const []); + } else { + return scope.makeCurrent(); + } +} + +/** + * Used to mark scope entry which logs single argument. + * + * final myScope = traceCreateScope('myMethod'); + * + * someMethod() { + * var s = traceEnter(myScope); + * try { + * // do something + * } finally { + * traceLeave(s); + * } + * } + */ +dynamic /* JsObject */ traceEnter1(dynamic /* JsFunction */ scope, arg1) { + if (traceEnabled) { + _arg1[0] = arg1; + return scope.apply(_arg1); + } else { + return scope.makeCurrent(); + } +} + +/** + * Used to mark scope exit. + * + * var myScope = traceCreateScope('myMethod'); + * + * someMethod() { + * var s = traceEnter(myScope); + * try { + * // do something + * } finally { + * traceLeave(s); + * } + * } + */ +dynamic /* JsObject */ traceLeave(dynamic /* JsObject */ scope) { + if (traceEnabled) { + _arg1[0] = scope; + _leaveScope.apply(_arg1, thisArg: _trace); + } else { + scope.makeCurrent(); + } +} + +/** + * Used to mark scope exit. + * + * var myScope = traceCreateScope('myMethod'); + * + * someMethod() { + * var s = traceEnter(myScope); + * try { + * // do something + * } finally { + * traceLeave(s); + * } + * } + */ +dynamic /* JsObject */ traceLeaveVal(dynamic /* JsObject */ scope, dynamic returnValue) { + if (traceEnabled) { + _arg2[0] = scope; + _arg2[1] = returnValue; + _leaveScope.apply(_arg2, thisArg: _trace); + } else { + scope.makeCurrent(); + } +} + +/** + * Used to mark Async start. Async are similar to scope but they don't have to be strictly nested. + * Async ranges only work if WTF has been enabled. + * + * someMethod() { + * var s = traceAsyncStart('HTTP:GET', 'some.url'); + * var future = new Future.delay(5).then((_) { + * traceAsyncEnd(s); + * }); + * } + */ +dynamic /* JsObject */ traceAsyncStart(String rangeType, String action) { + if (traceEnabled) { + _arg2[0] = rangeType; + _arg2[1] = action; + return _beginTimeRange.apply(_arg2, thisArg: _trace); + } + return null; +} + +dynamic /* JsObject */ traceAsyncEnd(dynamic /* JsObject */ range) { + if (traceEnabled) { + _arg1[0] = range; + return _endTimeRange.apply(_arg1, thisArg: _trace); + } + return null; +} + diff --git a/lib/wtf.dart b/lib/wtf.dart deleted file mode 100644 index b21b1152c..000000000 --- a/lib/wtf.dart +++ /dev/null @@ -1,85 +0,0 @@ -library angular.wtf; - -import "dart:profiler"; - -bool wtfEnabled = false; -dynamic /* JsObject */ _trace; -dynamic /* JsObject */ _events; -dynamic /* JsFunction */ _createScope; -dynamic /* JsFunction */ _enterScope; -dynamic /* JsFunction */ _leaveScope; -dynamic /* JsFunction */ _beginTimeRange; -dynamic /* JsFunction */ _endTimeRange; -final List _arg1 = [null]; -final List _arg2 = [null, null]; - -/** - * Use this method to initialize the WTF. It would be - * nice if this file could depend on dart:js, but that would - * make it not possible to refer to it in Dart VM. For this - * reason we expect the init caller to pass in the context - * JsObject. - */ -traceInit(dynamic /* JsObject */ context) { - if (context.hasProperty('wtf')) { - dynamic /* JsObject */ wtf = context['wtf']; - if (wtf.hasProperty('trace')) { - wtfEnabled = true; - _trace = wtf['trace']; - _events = _trace['events']; - _createScope = _events['createScope']; - _enterScope = _trace['enterScope']; - _leaveScope = _trace['leaveScope']; - _beginTimeRange = _trace['beginTimeRange']; - _endTimeRange = _trace['endTimeRange']; - } - - } -} - -// WTF.trace.events.createScope(string signature, opt_flags) -dynamic /* JsFunction */ traceCreateScope(signature, [flags]) { - if (wtfEnabled) { - _arg2[0] = signature; - _arg2[1] = flags; - return _createScope.apply(_arg2, thisArg: _events); - } else { - return new UserTag(signature); - } -} - -dynamic /* JsObject */ traceEnter(dynamic /* JsFunction */ scope, [args = const []]) { - if (wtfEnabled) { - return scope.apply(args); - } else { - return scope.makeCurrent(); - } -} - -dynamic /* JsObject */ traceLeave(dynamic /* JsObject */ scope) { - if (wtfEnabled) { - _arg1[0] = scope; - _leaveScope.apply(_arg1, thisArg: _trace); - } else { - scope.makeCurrent(); - } -} - -// WTF.trace.beginTimeRange('my.Type:job', actionName); -dynamic /* JsObject */ traceAsyncStart(String rangeType, String action) { - if (wtfEnabled) { - _arg2[0] = rangeType; - _arg2[1] = action; - return _beginTimeRange.apply(_arg2, thisArg: _trace); - } - return null; -} - -dynamic /* JsObject */ traceAsyncEnd(dynamic /* JsObject */ range) { - if (wtfEnabled) { - _arg1[0] = range; - return _endTimeRange.apply(_arg1, thisArg: _trace); - } - return null; -} - diff --git a/scripts/generate-documentation.sh b/scripts/generate-documentation.sh index a3da72af6..0cbd1a132 100755 --- a/scripts/generate-documentation.sh +++ b/scripts/generate-documentation.sh @@ -30,7 +30,9 @@ cat README-orig.md | sed "1s/^AngularDart.*/AngularDart/" > README.md lib/routing/module.dart \ lib/mock/module.dart \ lib/perf/module.dart \ - lib/di/module.dart + lib/di/module.dart \ + lib/tracing.dart \ + lib/ng_tracing_scopes.dart ) # Revert the temp copy of the README.md file diff --git a/test/angular_spec.dart b/test/angular_spec.dart index f3ee12120..5aff5c145 100644 --- a/test/angular_spec.dart +++ b/test/angular_spec.dart @@ -247,6 +247,13 @@ main() { "angular.routing.RouteProvider", "angular.routing.RouteViewFactory", "angular.routing.RoutingModule", + "angular.tracing.traceDetectWTF", + "angular.tracing.traceCreateScope", + "angular.tracing.traceAsyncStart", + "angular.tracing.traceEnter", + "angular.tracing.wtfEnabled", + "angular.tracing.traceAsyncEnd", + "angular.tracing.traceLeave", "angular.watch_group.PrototypeMap", "angular.watch_group.ReactionFn", "angular.watch_group.Watch",