Repository navigation
Optimize setIsVolatile for Path #58870
Description
Internal: b/174239851
We had some performance issue that's related with SkPath::setIsVolatile before: #17889. That issue was closed because Skia introduced CCPR and it has a nice performance even without setIsVolatile.
Unfortunately, CCPR was later disabled #17889 (comment) and we're seeing this issue again.
In particular, here's a comparison of our cubic_bezier_perf__timeline_summary benchmark with and without setIsVolatile (using 8b201b9 and flutter-team-archive/engine@1482d9b):
| without setIsVolatile | with setIsVolatile | |
|---|---|---|
| 90th_percentile_frame_rasterizer_time_millis | 24.108 | 13.95 |
| 99th_percentile_frame_rasterizer_time_millis | 47.098 | 18.366 |
In addition to the speed improvement, setIsVolatile(true) should also improve the memory usage as Skia will no longer cache the volatile paths.
As path animations get more and more popular through Rive/Flare among our customers such as "customer: money (g3)" and "customer: dream (g3)", having setIsVolatile may become more and more beneficial (see, e.g., #57686).
Activity
liyuqian commentedon Jun 6, 2020
CC @Hixie @chinmaygarde, we probably should revive flutter-team-archive/engine#5560.
Luckily, we have better ways to test memory now (thanks to @dnfield @terrylucas @iskakaushik @AlbertWang0116). To figure out whether we should
setIsVolatile(true)by default, we could use our new tools to benchmark the CPU, GPU, and memory usage of thiscubic_bezier_perfbenchmark or some other more realistic Rive/Flare animations.Also CC @pcsosinski @zoeyfan @mehmetf @jasonch99 to see how customers think about this issue, and what priority it has.
dnfield commentedon Jun 6, 2020
What if we just set the path as volatile until we actually draw it, after which we don't expect to modify it anymore?
liyuqian commentedon Jun 6, 2020
@dnfield :
setIsVolatileis kind of likesetIsDrawingOnlyOncewhich disables Skia to cache the path mask. So even if a path is not modified later, if that path is only drawn once,setIsVolatilestill saves a lot of performance.dnfield commentedon Jun 6, 2020
Once as in only to one SkPicture, or once as in the picture is drawn only once?
I'm not sure how a flutter developer would ever know whether to set this flag or not.
Hixie commentedon Jun 6, 2020
This is why we haven't exposed flags like this in the past. Unless we can solve this problem, we will definitely have people setting the flag at the wrong time and making things worse.
liyuqian commentedon Jun 8, 2020
Once as in the picture is drawn only once.
I think we should set the default value to best fit most people, and leave an option for experts who will run benchmarks and figure out what's best for their use cases (e.g., Rive engineers).
Following Ian's earlier suggestion of introducing a new class, do you think the following class would be clear enough?
Hixie commentedon Jun 8, 2020
I 100% guarantee that such an API will be used by non-experts incorrectly. Here's a non-exhaustive list of ways it could happen:
We should avoid having APIs that are traps like this. Otherwise, what will happen is five years from now we'll be making this API a no-op because people misuse it so much that it's better to just ignore calls to the API and use heuristics than it is to honor the API. (And we won't be able to remove it because that would break too many apps, so it'll just be a vestigial API.)
As an aside, introducing a new subclass for Path might turn every call to Path from a direct dispatch to a polymorphic dispatch, we should check with the VM folks.
[-]Expose setIsVolatile for Path[/-][+]Optimize setIsVolatile for Path[/+]liyuqian commentedon Jun 8, 2020
I see. So it seems that our goal is to setIsVolatile internally using some heuristics, and not expose an API for developers?
The information needed for making the heuristic decision seems to be only available on the Skia level. @reed-at-google @bsalomon : can Skia set the path as volatile by default, and turn it to non-volatile once the path is rasterized multiple times? To preserve the old behavior, we could only enable that heuristics under some opt-in flag such as
SkPath::setDynamicVolatility.To @Hixie : sorry that I remember something wrong. Your suggestion was not about a new class, but a new constructor for
Path. So it should be something likePath.makeVolatileand we shouldn't have the polymorphic dispatch problem?Finally, we can always just
setIsVolatile(true)for all paths in Flutter if it's at least better thansetIsVolatile(false)for all paths in Flutter. Hence I'm renaming this issue's title from "Expose setIsVolatile for Path" to "Optimize setIsVolatile for Path".Hixie commentedon Jun 8, 2020
I don't know enough about setIsVolatile to say what out goal should be, just that it's one of those mysterious APIs that I predict will get misused. :-)
Re the polymorphic dispatch thing, it's probably worth doing a one-off benchmark to see what the impact is. There's almost certainly areas of our framework where we fall prey to this problem today, might be a good place to look for optimizations in general if it's an actual thing.
20 remaining items
liyuqian commentedon Nov 19, 2020
I see. So if a path gets destructed in 1 frame, but ends up being recorded and re-rasterized in multiple frames with the same SkPicture, your approach will still mark it as volatile, and pay some potential performance cost? Do you have a number comparison like #58870 (comment) ?
dnfield commentedon Nov 19, 2020
Yes -
baseline
after
And it substantially reduces graphics memory usage on the rive-app/example.
liyuqian commentedon Nov 21, 2020
Cool! I wonder if you can also add a per-frame-tracing that counts how many paths are volatile and how many paths are non-volatile in flutter-team-archive/engine#22620? I think it might be useful to better understand the behavior and debug future performance changes.
thecalamiity commentedon Dec 12, 2020
Looks like PR was merged
dnfield commentedon Dec 12, 2020
Was reverted, should be relanded again soon though
dnfield commentedon Dec 21, 2020
Had to be reverted again - the implementation caused non-deterministic screen diff test behavior. Should be fixable.
github-actions commentedon Aug 8, 2021
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of
flutter doctor -vand a minimal reproduction of the issue.