You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Turning on debugProfileBuildsEnabled, debugProfileLayoutsEnabled, or debugProfilePaintsEnabled causes significant performance overhead, which is why these options are disabled by default. They do make the timeline more useful, though, and there's value in figuring out if we could enable these options by default.
Open questions:
Are these options expensive because calling the timeline API so often is expensive?
Or is the majority of the expense caused by the implicit runtimeType.toString() calls that happen to log the name of the RenderObject/Widget to the timeline?
If it is the latter, could we use a kernel transformer to replace the runtimeType.toString() calls with the actual static string name of the RenderObject/Widget they are called on to make these options cheaper?
Even if we don't want to turn these options on by default, making them cheaper has the benefit that one can still make accurate performance statements from traces with these options enabled. Right now, traces with these options enabled only allow for relative statements (x is slower than y in the same trace).
One additional option is to perform some filtering of the events dispatched to only include user created widgets. This should reduce the # of events by ~10X while still solving the majority of problems. Users need to be able to tell which of their widgets is slow so they can optimize not optimize the framework itself.
For example, suppose your Widget creates a ListView that is very slow as it creates 1000 widgets in a non-lazy manner. You would still see the ListView showing up as slow but you wouldn't see the internals of the ListView. This could be accomplished with the creation location transformer modified to only track a boolean of whether the widget is created from package Flutter or not.
Fyi @bkonyi as there might also be some ways to optimize tracing in the Dart VM if the expensive element is json serialization of these events.
FWIW, #93086 makes this much worse, by doing a lot of work when adding these timeline events. If we can actually make this representative of performance in profile builds, we should make sure to hide the additional information in profile builds.
The timeline API itself isn't very expensive, assuming you're not logging tons of arguments (there's a conversion from a Dart Map -> Dart String -> copy to Malloc'd memory). If no service requests for the timeline are made, logging events shouldn't result in much of a performance hit.
For serialization, we don't deserialize the arguments JSON, so the actual JSON serialization of individual timeline events shouldn't vary much with the exception of the cost of copying the arguments string into the serialization buffer. Obviously if there's lots of timeline events in the time range requested, this can add up quite a bit and result in a very large JSON response.
It's not so much that they're expensive, so much that the overhead is a significant fraction of the actual total work done for the own-length of events we're measuring. If you walk a tree of 1000 nodes, and each node takes 1000 instructions, 20 of which are for timeline events, then you have executed 1,000,000 instructions, 20,000 of which are for the timeline, which is 2%. That's going to make the results less precise than if you only spent 20 instructions out of 980,020, however you cut it.
(I made those numbers up. I've no idea what the actual overhead is or what the actual time taken per node is.)
Historically, we have had cases where merely measuring the performance was literally the source of our performance problems. I don't really see how this can ever not be the case when measuring many short events.
Activity
jacob314 commentedon Nov 9, 2021
One additional option is to perform some filtering of the events dispatched to only include user created widgets. This should reduce the # of events by ~10X while still solving the majority of problems. Users need to be able to tell which of their widgets is slow so they can optimize not optimize the framework itself.
For example, suppose your Widget creates a ListView that is very slow as it creates 1000 widgets in a non-lazy manner. You would still see the ListView showing up as slow but you wouldn't see the internals of the ListView. This could be accomplished with the creation location transformer modified to only track a boolean of whether the widget is created from package Flutter or not.
Fyi @bkonyi as there might also be some ways to optimize tracing in the Dart VM if the expensive element is json serialization of these events.
Hixie commentedon Nov 10, 2021
FWIW, #93086 makes this much worse, by doing a lot of work when adding these timeline events. If we can actually make this representative of performance in profile builds, we should make sure to hide the additional information in profile builds.
bkonyi commentedon Nov 11, 2021
The timeline API itself isn't very expensive, assuming you're not logging tons of arguments (there's a conversion from a Dart Map -> Dart String -> copy to Malloc'd memory). If no service requests for the timeline are made, logging events shouldn't result in much of a performance hit.
For serialization, we don't deserialize the arguments JSON, so the actual JSON serialization of individual timeline events shouldn't vary much with the exception of the cost of copying the arguments string into the serialization buffer. Obviously if there's lots of timeline events in the time range requested, this can add up quite a bit and result in a very large JSON response.
Hixie commentedon Nov 11, 2021
It's not so much that they're expensive, so much that the overhead is a significant fraction of the actual total work done for the own-length of events we're measuring. If you walk a tree of 1000 nodes, and each node takes 1000 instructions, 20 of which are for timeline events, then you have executed 1,000,000 instructions, 20,000 of which are for the timeline, which is 2%. That's going to make the results less precise than if you only spent 20 instructions out of 980,020, however you cut it.
(I made those numbers up. I've no idea what the actual overhead is or what the actual time taken per node is.)
Historically, we have had cases where merely measuring the performance was literally the source of our performance problems. I don't really see how this can ever not be the case when measuring many short events.