-
Notifications
You must be signed in to change notification settings - Fork 1
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
[LoAF] Allow for annotations for long animation frame to further help debugging #3
Comments
Thanks for posting the issue! So the way to do what you specifically asked for is: new ResizeObserverEntry(function SourceOfCode([entry]: ResizeObserverEntry[]) {
// ...
}).obeserve(target.current); And this would appear in the entry's |
This makes sense. I can make this work. For my specific case I think I would want something like const cb = ([entry]: ResizeObserverEntry[]) => {
// ...
}
Object.defineProperty(cb, 'name', { value: 'SourceOfCode' });
new ResizeObserver(cb).obeserve(target.current); |
Reopening, there are use cases where this can really be useful. CC @mmocny |
Reading the original request, I see reference to:
But later I only see reference to just making sure a nice name value is exposed. Is it actually important to somehow differentiate the "context" from which a particular callback is invoked? I'm not sure how often that would come up... Second, if you really want to control labelling, and do this in a way where the developer is explicitly provide a hint-- I wonder if just regular User Timings aren't both sufficient and more flexible? Just That way, you can measure all the time ranges for that code, but also filter to cases where it contributed to an overall long-running script within a LoAF. That said, I think it may be valuable if LoAF could do more attribution splitting automatically, on finer boundaries beyond just "tasks". For example, in cases where multiple continuations are registered on a shared promise. Or where a script calls back into previously registered handlers, but in ways where there isn't a 'hop' though some web platform api (like setTimeout) etc. One (far fetched) idea that comes to mind is perhaps any time an AsyncContext is explicitly switched, if that api ever does take off? Of course, a last option is to just rely on yield points, and use that as additional motivation for developers to just yield! |
It is, but it can also add a lot of noise. The difference here is that this is "measure but discard if it's not a LoAF".
Those are interesting ideas, I still don't see anything actionable there but let's continue the conversation. |
+1 to consider improving this use case. There are several RUM providers wrapping Callback/functions that would be flagged by LoAF as Long LoAFs triggers hiding the real Script sourceLocation information... |
New Relic RUM needs some way of informing developers that hook into the LoAF API directly that our wrapper is not the cause of their long animation frames. I was going to look at maybe just overriding the Ultimately, we need a way to direct the developer back to the offending code and I don't think having just a name is sufficient. Even if we could update the name, if the line numbers and file name still point to the RUM provider, developers will still be confused. |
Coming back to this, I think a potential way to address this is an additional attribute in {mark|measure}Options that helps filter user timing entries, with one of the options being to include those entries in the buffer only if they contribute to a LoAF (or a LoAF long-script). So a library like NewRelic as mentioned in #3 (comment) could wrap the user's function with |
It seems to me like you would have to buffer these at first, then clean up these marks and measures afterwards. Today, there is no limit to the number of marks/measures in the buffer, so overflow is not really a problem (unless so many are issued that we get into overall memory usage worries). I think that means that: just adding marks/measures, leaving them there, then filtering manually, might be sufficient? What about just a The usage would be something like:
|
As per your original proposal, Related questions:
|
Also also, there have been requests to add groups/categories/labels to User Timings multiple times for multiple purposes. I wonder if this really needs to be LoAF specific or if it could just be a generic feature like that? Then library authors could use as they see fit and might be more creative that we are here? I guess the question I would have is: is it likely that a library like NewRelic would want to consume marks/measures that were created by a different app/library or just their own? Would NewRelic want to share annotations that would be useful to consume by others? (Such that a common standard us useful?) |
cc @and-oli (maybe some overlap with DevTools extensibility) |
Right
It's suboptimal in terms of both efficiency and ergonomics. By doing this we're encouraging people to potentially add a massive amount of events to the buffer and these memory (and lookup efficiency) problems can potentially explode. It also adds a lot of noise to the performance timeline and to traces.
See above
I think not, perhaps attach them to the
Yea definitely.
Perhaps in the same callback, as in if you observe both types you'd get them concurrently? Otherwise in
I don't think this is related. One is arbitrary metadata and the other is a capturing condition.
I feel that those are parallel question. An additional thing I would propose for this type of mark/measure is that you can't mark/measure it before/after the fact, as in the timestamp has to be now or at least within the current script entry. |
All of that makes sense in isolation, it just feels needlessly coupled to LoAF data. What if I wanted to review these marks when they overlap with an Event Timing (but didn't trigger LoAF specifically because delays are from after-main-presentation) |
I agree, I think the API should be attachable to any platform entry type where it makes sense, not coupled with LoAF specificially, or at least written in a way that's extendable to do that. |
Can we evolve your proposal slightly to something like this, then?
(Wonder if this would be useful to e.g. measure all Event Timings and then only nested LoAF entries, and then only nested user timings of those...) |
Riffing on that, perhaps if we add // in your function
performance.mark(functionName, { buffered: false });
// the observer
const observer = new Performance Observer(entries => {
const [loaf] = entries.getEntriesByType("long-animation-frame");
const [script] = loaf.scripts;
const marks = entries.getOverlappingEntries(script, {type: "mark" });
});
observer.observe({type: "long-animation-frame"});
observer.observe({type: "mark" }); |
I like that! Regarding
I think we need to go back to the idea of this mark type being detached from the typical perf timeline, yet still allow limited buffering (Perhaps more constrained than typical user timings). |
Reciting internal conversation with @mmocny: I feel that turning this into a generic user-timing function has enough limitations to make it suboptimal:
So instead, I propose to go back to the original more narrow-scoped proposal, to annotate functions for use in LoAF: function addEventListenerWithWrapper(event_type, internal_function) {
const wrapped_internal_function = performance.bind(internal_function);
addEventListener(event_type, wrapped_internal_function);
} Where |
Will there be a mechanism to provide a user-defined name, or will it use |
I think we can do that but then we can't use additional arguments for |
Summarizing WG discussion:
For (1), we need something reliable like function wrapping, as custom marks/measures don't give source location. |
A shape that came to mind: // entryTypes can be LoAF, event, measure, script
const tracing = new PerformanceTracing({threshold, entryTypes, detail})
// This adds a mark/measure that gets applied to overlapping entries
// from the given list
tracing.mark(label);
tracing.measure(label);
// This creates a bound function that reports the labeled trace,
// and also appears as a `PerformanceScriptTiming` entry in LoAF
tracing.bind(wrapped_function, label)
Performance{User|LongAnimationFrame|Script|Event}Timing.traces
PerformanceTraceEntry (start, duration, name, detail) The advantage of creating a |
It can be difficult to track down the source of a particular function if that function is a common function that is used multiple times within the code base. I would like the ability to annotate a function and long animation frame would use that name instead of something generic like
ResizeObserverCallback
. In the example below, I would like the name to be eitherSourceOfCode
orResizeObserverCallback(SourceOfCode)
or something like this.I do not care about the mechanism or the syntax to achieve this.
The text was updated successfully, but these errors were encountered: