Skip to content

Commit 364465f

Browse files
mvuksanoDiana Salsbury
authored and
Diana Salsbury
committed
feat(Scope): Instrument Scope to use User tags in Dart Obervatory
Closes dart-archive#1138
1 parent f484af3 commit 364465f

File tree

5 files changed

+85
-17
lines changed

5 files changed

+85
-17
lines changed

lib/change_detection/watch_group.dart

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
library angular.watch_group;
22

3+
import 'dart:profiler';
34
import 'package:angular/change_detection/change_detection.dart';
45
import 'dart:collection';
56

@@ -367,6 +368,8 @@ class WatchGroup implements _EvalWatchList, _WatchGroupList {
367368
class RootWatchGroup extends WatchGroup {
368369
final FieldGetterFactory _fieldGetterFactory;
369370
Watch _dirtyWatchHead, _dirtyWatchTail;
371+
List<UserTag> _detectChangesTags = [];
372+
List<UserTag> _reactionFnTags = [];
370373

371374
/**
372375
* Every time a [WatchGroup] is destroyed we increment the counter. During
@@ -378,10 +381,22 @@ class RootWatchGroup extends WatchGroup {
378381
int _removeCount = 0;
379382

380383

381-
RootWatchGroup(this._fieldGetterFactory,
382-
ChangeDetector changeDetector,
383-
Object context)
384-
: super._root(changeDetector, context);
384+
RootWatchGroup(this._fieldGetterFactory, ChangeDetector changeDetector, Object context, {
385+
bool profile: false, int ttl })
386+
: super._root(changeDetector, context) {
387+
if (profile) {
388+
_detectChangesTags = new List(ttl + 2);
389+
_reactionFnTags = new List(ttl + 2);
390+
for (int i = 0; i < ttl; i++) {
391+
_detectChangesTags[i] = new UserTag('DetectChanges / NgDigest${i}');
392+
_reactionFnTags[i] = new UserTag('ReactionFn / NgDigest${i}');
393+
}
394+
_detectChangesTags[ttl] = new UserTag('DetectChanges / NgFlush');
395+
_detectChangesTags[ttl + 1] = new UserTag('DetectChanges / NgAssert');
396+
_reactionFnTags[ttl] = new UserTag('ReactionFn / NgFlush');
397+
_reactionFnTags[ttl + 1] = new UserTag('ReactionFn / NgAssert');
398+
}
399+
}
385400

386401
RootWatchGroup get _rootGroup => this;
387402

@@ -400,7 +415,10 @@ class RootWatchGroup extends WatchGroup {
400415
ChangeLog changeLog,
401416
AvgStopwatch fieldStopwatch,
402417
AvgStopwatch evalStopwatch,
403-
AvgStopwatch processStopwatch}) {
418+
AvgStopwatch processStopwatch,
419+
num sequenceNumber}) {
420+
var previous;
421+
if (sequenceNumber != null) previous = _detectChangesTags[sequenceNumber].makeCurrent();
404422
// Process the Records from the change detector
405423
Iterator<Record<_Handler>> changedRecordIterator =
406424
(_changeDetector as ChangeDetector<_Handler>).collectChanges(
@@ -448,7 +466,13 @@ class RootWatchGroup extends WatchGroup {
448466
count++;
449467
try {
450468
if (root._removeCount == 0 || dirtyWatch._watchGroup.isAttached) {
451-
dirtyWatch.invoke();
469+
if (sequenceNumber != null) {
470+
var previous = _reactionFnTags[sequenceNumber].makeCurrent();
471+
dirtyWatch.invoke();
472+
previous.makeCurrent();
473+
} else {
474+
dirtyWatch.invoke();
475+
}
452476
}
453477
} catch (e, s) {
454478
if (exceptionHandler == null) rethrow; else exceptionHandler(e, s);
@@ -462,6 +486,7 @@ class RootWatchGroup extends WatchGroup {
462486
root._removeCount = 0;
463487
}
464488
if (processStopwatch != null) processStopwatch..stop()..increment(count);
489+
if (previous != null) previous.makeCurrent();
465490
return count;
466491
}
467492

lib/core/module_internal.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ library angular.core_internal;
33
import 'dart:async' as async;
44
import 'dart:collection';
55
import 'dart:math';
6+
import 'dart:profiler';
67
import 'package:intl/intl.dart';
78

89
import 'package:di/di.dart';

lib/core/scope.dart

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ part of angular.core_internal;
33
typedef EvalFunction0();
44
typedef EvalFunction1(context);
55

6+
final UserTag APPLY_USER_TAG = new UserTag('Apply');
7+
final UserTag FLUSH_TAG = new UserTag('NgFlush');
8+
final UserTag RUN_ASYNC_TAG = new UserTag('NgRunAsync');
9+
final UserTag DOM_READ_TAG = new UserTag('NgDomRead');
10+
final UserTag DOM_WRITE_TAG = new UserTag('NgDomWrite');
11+
final UserTag ASSERT_TAG = new UserTag('NgAssert');
12+
613
/**
714
* Injected into the listener function within [Scope.on] to provide
815
* event-specific details to the scope listener.
@@ -282,13 +289,15 @@ class Scope {
282289
}
283290

284291
dynamic apply([expression, Map locals]) {
292+
var previous = APPLY_USER_TAG.makeCurrent();
285293
_assertInternalStateConsistency();
286294
rootScope._transitionState(null, RootScope.STATE_APPLY);
287295
try {
288296
return eval(expression, locals);
289297
} catch (e, s) {
290298
rootScope._exceptionHandler(e, s);
291299
} finally {
300+
previous.makeCurrent();
292301
rootScope.._transitionState(RootScope.STATE_APPLY, null)
293302
..digest()
294303
..flush();
@@ -567,6 +576,8 @@ class RootScope extends Scope {
567576

568577
String _state;
569578

579+
final List<UserTag> _digestTags = [];
580+
570581
/**
571582
*
572583
* While processing data bindings, Angular passes through multiple states. When testing or
@@ -616,23 +627,29 @@ class RootScope extends Scope {
616627
*/
617628
String get state => _state;
618629

619-
RootScope(Object context, Parser parser, ASTParser astParser, FieldGetterFactory fieldGetterFactory,
620-
FormatterMap formatters, this._exceptionHandler, this._ttl, this._zone,
621-
ScopeStats _scopeStats)
630+
RootScope(Object context, Parser parser, ASTParser astParser,
631+
FieldGetterFactory fieldGetterFactory, FormatterMap formatters, this._exceptionHandler,
632+
ScopeDigestTTL ttl, this._zone, ScopeStats _scopeStats)
622633
: _scopeStats = _scopeStats,
634+
_ttl = ttl,
623635
_parser = parser,
624636
_astParser = astParser,
625637
super(context, null, null,
626638
new RootWatchGroup(fieldGetterFactory,
627-
new DirtyCheckingChangeDetector(fieldGetterFactory), context),
639+
new DirtyCheckingChangeDetector(fieldGetterFactory), context, profile: true,
640+
ttl: ttl.ttl),
628641
new RootWatchGroup(fieldGetterFactory,
629-
new DirtyCheckingChangeDetector(fieldGetterFactory), context),
642+
new DirtyCheckingChangeDetector(fieldGetterFactory), context, profile: true,
643+
ttl: ttl.ttl),
630644
'',
631645
_scopeStats)
632646
{
633647
_zone.onTurnDone = apply;
634648
_zone.onError = (e, s, ls) => _exceptionHandler(e, s);
635649
_zone.onScheduleMicrotask = runAsync;
650+
for(num i = 0; i <= _ttl.ttl; i++) {
651+
_digestTags.add(new UserTag('NgDigest${i}'));
652+
}
636653
}
637654

638655
RootScope get rootScope => this;
@@ -656,18 +673,21 @@ class RootScope extends Scope {
656673
* [ScopeDigestTTL].
657674
*/
658675
void digest() {
676+
int digestTTL = _ttl.ttl;
659677
_transitionState(null, STATE_DIGEST);
660678
try {
661679
var rootWatchGroup = _readWriteGroup as RootWatchGroup;
662680

663-
int digestTTL = _ttl.ttl;
681+
664682
const int LOG_COUNT = 3;
665683
List log;
666684
List digestLog;
667685
var count;
668686
ChangeLog changeLog;
669687
_scopeStats.digestStart();
670688
do {
689+
var sequenceNo = _ttl.ttl - digestTTL;
690+
var previousTag = _digestTags[sequenceNo].makeCurrent();
671691

672692
int asyncCount = _runAsyncFns();
673693

@@ -677,7 +697,8 @@ class RootScope extends Scope {
677697
changeLog: changeLog,
678698
fieldStopwatch: _scopeStats.fieldStopwatch,
679699
evalStopwatch: _scopeStats.evalStopwatch,
680-
processStopwatch: _scopeStats.processStopwatch);
700+
processStopwatch: _scopeStats.processStopwatch,
701+
sequenceNumber: sequenceNo);
681702

682703
if (digestTTL <= LOG_COUNT) {
683704
if (changeLog == null) {
@@ -690,10 +711,13 @@ class RootScope extends Scope {
690711
}
691712
}
692713
if (digestTTL == 0) {
714+
if (previousTag != null) previousTag.makeCurrent();
693715
throw 'Model did not stabilize in ${_ttl.ttl} digests. '
694-
'Last $LOG_COUNT iterations:\n${log.join('\n')}';
716+
'Last $LOG_COUNT iterations:\n${log.join('\n')}';
695717
}
718+
696719
_scopeStats.digestLoop(count);
720+
previousTag.makeCurrent();
697721
} while (count > 0 || _runAsyncHead != null);
698722
} finally {
699723
_scopeStats.digestEnd();
@@ -702,6 +726,7 @@ class RootScope extends Scope {
702726
}
703727

704728
void flush() {
729+
var previousTag = FLUSH_TAG.makeCurrent();
705730
_stats.flushStart();
706731
_transitionState(null, STATE_FLUSH);
707732
RootWatchGroup readOnlyGroup = this._readOnlyGroup as RootWatchGroup;
@@ -724,7 +749,8 @@ class RootScope extends Scope {
724749
readOnlyGroup.detectChanges(exceptionHandler:_exceptionHandler,
725750
fieldStopwatch: _scopeStats.fieldStopwatch,
726751
evalStopwatch: _scopeStats.evalStopwatch,
727-
processStopwatch: _scopeStats.processStopwatch);
752+
processStopwatch: _scopeStats.processStopwatch,
753+
sequenceNumber: _ttl.ttl);
728754
}
729755
if (_domReadHead != null) _stats.domReadStart();
730756
while (_domReadHead != null) {
@@ -741,30 +767,35 @@ class RootScope extends Scope {
741767
} while (_domWriteHead != null || _domReadHead != null || _runAsyncHead != null);
742768
_stats.flushEnd();
743769
assert((() {
770+
var previousTag = ASSERT_TAG.makeCurrent();
744771
_stats.flushAssertStart();
745772
var digestLog = [];
746773
var flushLog = [];
747774
(_readWriteGroup as RootWatchGroup).detectChanges(
748775
changeLog: (s, c, p) => digestLog.add('$s: $c <= $p'),
749776
fieldStopwatch: _scopeStats.fieldStopwatch,
750777
evalStopwatch: _scopeStats.evalStopwatch,
751-
processStopwatch: _scopeStats.processStopwatch);
778+
processStopwatch: _scopeStats.processStopwatch,
779+
sequenceNumber: _ttl.ttl + 1);
752780
(_readOnlyGroup as RootWatchGroup).detectChanges(
753781
changeLog: (s, c, p) => flushLog.add('$s: $c <= $p'),
754782
fieldStopwatch: _scopeStats.fieldStopwatch,
755783
evalStopwatch: _scopeStats.evalStopwatch,
756-
processStopwatch: _scopeStats.processStopwatch);
784+
processStopwatch: _scopeStats.processStopwatch,
785+
sequenceNumber: _ttl.ttl + 1);
757786
if (digestLog.isNotEmpty || flushLog.isNotEmpty) {
758787
throw 'Observer reaction functions should not change model. \n'
759788
'These watch changes were detected: ${digestLog.join('; ')}\n'
760789
'These observe changes were detected: ${flushLog.join('; ')}';
761790
}
762791
_stats.flushAssertEnd();
792+
previousTag.makeCurrent();
763793
return true;
764794
})());
765795
} finally {
766796
_stats.cycleEnd();
767797
_transitionState(STATE_FLUSH, null);
798+
previousTag.makeCurrent();
768799
}
769800
}
770801

@@ -773,12 +804,14 @@ class RootScope extends Scope {
773804
if (_state == STATE_FLUSH_ASSERT) {
774805
throw "Scheduling microtasks not allowed in $state state.";
775806
}
807+
var previousTag = RUN_ASYNC_TAG.makeCurrent();
776808
var chain = new _FunctionChain(fn);
777809
if (_runAsyncHead == null) {
778810
_runAsyncHead = _runAsyncTail = chain;
779811
} else {
780812
_runAsyncTail = _runAsyncTail._next = chain;
781813
}
814+
previousTag.makeCurrent();
782815
}
783816

784817
_runAsyncFns() {
@@ -797,21 +830,25 @@ class RootScope extends Scope {
797830
}
798831

799832
void domWrite(fn()) {
833+
var previousTag = DOM_WRITE_TAG.makeCurrent();
800834
var chain = new _FunctionChain(fn);
801835
if (_domWriteHead == null) {
802836
_domWriteHead = _domWriteTail = chain;
803837
} else {
804838
_domWriteTail = _domWriteTail._next = chain;
805839
}
840+
previousTag.makeCurrent();
806841
}
807842

808843
void domRead(fn()) {
844+
var previousTag = DOM_READ_TAG.makeCurrent();
809845
var chain = new _FunctionChain(fn);
810846
if (_domReadHead == null) {
811847
_domReadHead = _domReadTail = chain;
812848
} else {
813849
_domReadTail = _domReadTail._next = chain;
814850
}
851+
previousTag.makeCurrent();
815852
}
816853

817854
void destroy() {}

lib/core_dom/module_internal.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'dart:async' as async;
44
import 'dart:convert' show JSON;
55
import 'dart:html' as dom;
66
import 'dart:js' as js;
7+
import 'dart:profiler';
78

89
import 'package:di/di.dart';
910
import 'package:perf_api/perf_api.dart';

lib/core_dom/tagging_view_factory.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
part of angular.core.dom_internal;
22

3+
var ngViewTag = new UserTag('NgView');
4+
35
class TaggingViewFactory implements ViewFactory {
46
final List<TaggedElementBinder> elementBinders;
57
final List<dom.Node> templateNodes;
@@ -12,6 +14,7 @@ class TaggingViewFactory implements ViewFactory {
1214
static Key _EVENT_HANDLER_KEY = new Key(EventHandler);
1315

1416
View call(Injector injector, [List<dom.Node> nodes /* TODO: document fragment */]) {
17+
var lastTag = ngViewTag.makeCurrent();
1518
if (nodes == null) {
1619
nodes = cloneElements(templateNodes);
1720
}
@@ -22,6 +25,7 @@ class TaggingViewFactory implements ViewFactory {
2225
_link(view, nodes, injector);
2326
return view;
2427
} finally {
28+
lastTag.makeCurrent();
2529
assert(_perf.stopTimer(timerId) != false);
2630
}
2731
}

0 commit comments

Comments
 (0)