-
Notifications
You must be signed in to change notification settings - Fork 248
feat(WatchGroup): Allow measuring cost of running reaction functions and #1148
Conversation
mvuksano
commented
Jun 12, 2014
void addTime(ReactionFnStatsEntry entry) { | ||
try { | ||
stats[count++] = entry; | ||
} on RangeError { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
using exceptions for control flow? why not check if stats length is lower than count++?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, exceptions are very expensive. Change to range check.
I don't know enough about the previous conversations about this feature, but the current implementation looks pretty heavy weight. wouldn't a sufficient goal be to report just two number - the total cost of reactions per digest and total number of reactions per digest? we could then report this along with dirty checking and flush. |
Why aren't there any tests included with this PR? |
Where is |
@jeffbcross I'm still refactoring this. It's actually been renamed to ExecutionStats. I should be done with refactorings soon. |
Great! Are you adding tests as you refactor? |
Yes, I will do that. Is there any specific behaviour that you'd like to see how to use? Or was this just a general question? |
A few reasons for asking about tests:
|
void showEvalStats(ExecutionStats fnStats) { | ||
_printLine('Time (us)', 'Fn/Name'); | ||
fnStats.getEvalStats().forEach((ExecutionEntry entry) { | ||
var text = (entry.value as EvalWatchRecord).fn != null ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mhevery What would be useful information to display about EvalWatchRecord?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, figured out that EvalWatchRecord.toString will do just fine.
@mhevery Could you have a look at this. There's still some more work to be done here but feedback would be useful. I'm doubt that extracting info from EvalWatchRecord using mirrors is a good idea. If not, what's your suggestion? |
Mirrors seems like a bad idea... They will increase the size of compiled code... |
|
||
Iterable<ExecutionEntry> getReactionFnStats() { | ||
_shrinkDirtyWatch(); | ||
return dirtyWatchStats.getRange(0, _capacity); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should all the get<...>()
be true getters ?
reporting it. To be able to measure cost of reaction function, dirty check and/or dirty watch one needs to define ExecutionStats. ExecutionStats is configured using ExecutionStatsConfig object. This object can be used to define how many records to display when showing the stats, what's the minimum threshold (in microseconds) for a record to be considered as relevant as well as to enable and disable tracking the stats. One can define ExecutionStats, ExectionStatsEmitter and ExecutionStatsConfig like: m..bind(ExectionStats) ..bind(ExectionStatsEmitter) ..bind(ExectionStatsConfig, toFactory: (i) => new ExectionStats(...)) The results can be displayed using ngStats object. To obtain a reference to an ngStats object type (in the console): ng = ngStats(); To display maxNumber (defined using ExectionStatsConfig object) of the most expensive reaction functions type: ng.showReactionFnStats(); To display maxNumber of most expensive evals type: ng.showEvalStats(); To display maxNumber of most expensive dirty checks type: ng.showDirtyCheckStats(); One can use ng.enable() method to enable tracking and ng.disable() method to disable trackin. To clear the results use ng.reset() method. To achieve least performance impact on the application make sure that the ExectionStats is null. m..bind(ExectionStats, toValue: null); That way no extra objects will be created and the impact on the actual application will be minimal.
@@ -312,7 +315,19 @@ class DirtyCheckingChangeDetector<H> extends DirtyCheckingChangeDetectorGroup<H> | |||
int count = 0; | |||
while (current != null) { | |||
try { | |||
if (current.check()) changeTail = changeTail._nextChange = current; | |||
if (executionStats != null && executionStats.config.enabled) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a better way to do this is to duplicate the whole while loop. One while loop is instrumented and the other is not.
The stats objects should be injected in the constructor and should have on off switch which would then control which while loop to chose. That way one could turn on/off the stats during the lifetime.
@chirayuk Do we still need this or does your change supersedes this one? |
Superseded by @chirayuk's wor. |