-
Notifications
You must be signed in to change notification settings - Fork 69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add instrumentation for measuring metrics related to visit #276
base: master
Are you sure you want to change the base?
Conversation
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.
Looking good! Left a few inline comments/ideas...
@@ -205,10 +208,14 @@ class EmberApp { | |||
* only | |||
*/ | |||
async getNewApplicationInstance() { | |||
const appInstanceRetrievalStartTime = Date.now(); |
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'd generally prefer to use something with higher precision. Mind swapping to performance.now()
(docs here):
const { performance } = require('perf_hooks');
// ...snip...
const start = performance.now();
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.
+1 to performance.now()
, not only higher precision, more importantly it's using a monotonic clock therefore it is not subject to system clock skew or adjustments https://www.w3.org/TR/hr-time-2/#sec-monotonic-clock
return this.getAppInstanceInfo(app, queueObject.isItemPreBuilt); | ||
return this.getAppInstanceInfo(app, { | ||
isAppInstancePreBuilt: queueObject.isItemPreBuilt, | ||
appInstanceRetrievalTime: Date.now() - appInstanceRetrievalStartTime, |
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'd like to store the start and stops too. Also can we rename this to buildAppInstanceTiming
?
Something like:
const start = performance.now();
const queueObject = this._sandboxApplicationInstanceQueue.dequeue();
const app = await queueObject.item;
const stop = performance.now();
return this.getAppInstanceInfo(app, {
isAppInstancePreBuilt: queueObject.isItemPreBuilt,
buildAppInstanceTiming: {
start,
stop,
duration: stop - start,
}
});
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.
Rob,
Do we need all 3 of 'start', 'stop', and 'duration'?
I'd prefer either (1) 'start' and 'stop' or (2) 'start' and 'duration'. I prefer the latter option more. The reason I like it is because: (1) it's smaller (which isn't a huge deal) and (2) whenever I see all 3 I do the subtraction to make sure 'duration' = 'stop' - 'start' because I always ask myself, why would they provide all 3?
That being said, this is not such a strong opinion and if you are strongly opinionated, I'll defer.
Thanks,
Mark
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.
My reasoning here is basically that "clock time duration" isn't enough information in all cases, but in many cases it is. For example, if we just provided duration it is actually quite difficult to map the results to see how many were interleaved/overlapping/whateverTheWordIs. In general, I feel like this is in a "why not" kinda scenario (where it costs us roughly nothing to do all three, and in fact we basically have to know all three anyways in order to provide a duration). That being said, I definitely do not feel strongly about providing all 3. I think start
and duration
is probably enough info (and addresses my primary issue).
Let's call it "dealers choice", to the PR author go the spoils 😝
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.
lol okk.... i will unveil the suspense in my next commit ;)
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.
FWIW PerformanceEntry
defines startTime
and duration
@@ -236,10 +243,11 @@ class EmberApp { | |||
async _visit(path, fastbootInfo, bootOptions, result, buildSandboxPerVisit) { | |||
let shouldBuildApp = buildSandboxPerVisit || this._applicationInstance === undefined; | |||
|
|||
let { app, isSandboxPreBuilt } = shouldBuildApp | |||
let { app, appAnalytics } = shouldBuildApp |
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.
Can we call this analytics
instead of appAnalytics
?
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.
Also, can we unify these? Can we funnel both cases through a single function (e.g. buildAppInstance
or even getNewApplicationInstance
) so the rest of the code doesn't need to care about the two pathways?
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.
do you mean
? await this.getNewApplicationInstance()
: this.getAppInstanceInfo(this._applicationInstance);
should instead be
let { app, appAnalytics } = await this.getNewApplicationInstance(shouldBuildApp)
and the function would return the appropriate response
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, IMHO we should have only a single function that is responsible for understanding:
- if we should build a new instance (based on
shouldBuildApp
) - if we should build a new instance when the queue is empty and a new application instance is requested
- how to build the proper set of analytics output
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.
agreed! 👍
const instanceVisitStartTime = Date.now(); | ||
await instance.visit(path, bootOptions); | ||
result.analytics.instanceVisitTime = Date.now() - instanceVisitStartTime; |
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.
Similar to above, lets use a POJO to group multiple values:
const start = performance.now();
await instance.visit(path, bootOptions);
const stop = performance.now();
result.analytics.instanceVisitTimings = {
start,
stop,
duration: stop - start,
};
@@ -323,6 +336,7 @@ class EmberApp { | |||
|
|||
try { | |||
await this._visit(path, fastbootInfo, bootOptions, result, buildSandboxPerVisit); | |||
result.analytics.fastbootVisitTime = Date.now() - fastbootVisitStartTime; |
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.
Same as above
@suchitadoshi1987 @rwjblue have you considered to instrument |
Ya, we definitely can (and should!) add that. We should probably make an enumerated list over in #107. |
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 believe this also needs README updates as the public API of result.analytics is being changed: https://github.com/ember-fastboot/fastboot#result
return this.getAppInstanceInfo(app, queueObject.isItemPreBuilt); | ||
return this.getAppInstanceInfo(app, { | ||
isAppInstancePreBuilt: queueObject.isItemPreBuilt, | ||
appInstanceRetrievalTime: Date.now() - appInstanceRetrievalStartTime, |
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.
Instead of doing this here, shouldn't these metrics come from the queueObject
like isItemPreBuilt
? It seems a bit of an odd API where we return whether the item was pre built or built on the fly but not the metrics of the time spent for that task. In other words, we are already getting what task was dequeued but not it's timing info.
If it isn't prebuilt, it can capture the time to create the sandbox. This way the generator function takes care of creation of the object, determining the state of reterival and metrics. If the intent is to get the time taken to built the sanbox then it should come from as part of the dequeue
API IMO.
@@ -323,6 +336,7 @@ class EmberApp { | |||
|
|||
try { | |||
await this._visit(path, fastbootInfo, bootOptions, result, buildSandboxPerVisit); | |||
result.analytics.fastbootVisitTime = Date.now() - fastbootVisitStartTime; |
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 visit
end time is when finally
block is called in order capture the entire time. Is there specific reason why we are not capturing the remaining time to build the result and shoebox?
Added instrumentation to measure