-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Make a11y computeChildGeometry slightly faster
#177477
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
Make a11y computeChildGeometry slightly faster
#177477
Conversation
| siblingMergeGroups.addAll(childSemantics.siblingMergeGroups); | ||
| } | ||
| } | ||
| if (!contributesToSemanticsTree) { |
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.
This only changed indentation (returning early if !contributesToSemanticsTree).
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.
Code Review
This pull request introduces performance optimizations, primarily by refactoring _SemanticsGeometry.computeChildGeometry to be faster in the common case. This is achieved by adding a new MatrixUtils.multiplyInPlace helper to avoid matrix allocations. The PR also includes several smaller cleanups and refactorings across different rendering objects, which improve code clarity and style. Overall, the changes are beneficial for performance. I've found one potential logic change in the semantics clipping that might be an unintended side effect of the refactoring, which I've commented on.
| if (localSemanticsClipInParent != null) { | ||
| semanticsClipRect = localSemanticsClipInParent; | ||
| } else if (semanticsClipRect != null) { | ||
| semanticsClipRect = _intersectRects(semanticsClipRect, localPaintClipInParent); | ||
| } |
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.
There appears to be a subtle logic change in how semanticsClipRect is calculated, which might be an unintentional regression.
Previously, if describeSemanticsClip returned null, the semantics clip would fall back to being based on the paint clip. In the new implementation, if describeSemanticsClip returns null (making localSemanticsClipInParent null) and the inherited semanticsClipRect is also null, the new semanticsClipRect remains null, instead of falling back to the paint clip.
This seems to contradict the intended behavior where a null describeSemanticsClip implies using the paint clip. To restore the original logic and ensure the fallback to the paint clip occurs, consider the following change.
if (localSemanticsClipInParent != null) {
semanticsClipRect = localSemanticsClipInParent;
} else {
semanticsClipRect = _intersectRects(semanticsClipRect, localPaintClipInParent);
}| childToCommonAncestor[i - 1], | ||
| semanticsClipRect, | ||
| paintClipRect, | ||
| final RenderObject nodeParent = childToCommonAncestor[i]; |
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.
For the more common codepath the transform is now computed in the same loop and there are less inverse calculations. The overlay portal path still uses _computeClipRect but that path usually isn't as hot.
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.
Now Qun's PR is merged, we no longer needed a special path for overlayportal.
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 in theory people can still return a non-descendant node in their custom RenderObject'svisitChildrenForSemantics implementation? (But now that RenderObject.semantcsParent is gone I'm not sure if an implementation like still works).
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.
right, I don't think they can have this case where Render tree and semantics tree are differ without semanticsParent
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.
Sounds good, I don't think I've touched that code path in this patch so I'll probably replace that with an assert in a different PR.
| clipPath.add(ancestor); | ||
| ancestor = ancestor.parent; | ||
| } | ||
| final SemanticsNode? ancestorNode = ancestor?._semantics.cachedSemanticsNode; |
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.
(at first glance the ancestorNode may not have up-to-date geometry, if it is going to be merged as a sibling, and this function is being called in _updateGeometry?)
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.
dirty nodes' ensureSemantics are called from top to bottom, so ancestor should always have up to date geometry
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.
ensureSemantics
do you ensureGeometry? What if there's a merge sibling ancestor (whose geometry is updated in _updateSiblingNodesGeometries which is called in _produceSemanticsNode? The geometry of that isn't updated when ensureGeometry is called I think?
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 just realized this is grabing from cached Semantics Node, not the _SemanticsGeometry that stored in the _RenderObjectSemantics, this looks like a bug because ensureGeometry doesn't update the cached semantics node's geomtry.
_updateSiblingNodesGeometries
I think if we fixes the the code to grab from _SemanticsGeometry of the _RenderObjectSemantics this should be fine?
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 guess if this code path is now obsolete then I guess we don't really have to fix this?
| required Set<int> usedSemanticsIds, | ||
| List<SemanticsNode>? semanticsNodes, | ||
| }) { | ||
| void _buildSemanticsSubtree({required Set<int> usedSemanticsIds}) { |
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.
The semanticsNodes argument wasn't used.
…ry-slightly-faster
| /// This function does not alter the argument `a`, and is thus useful when you | ||
| /// want to left-multiply in-place. For right-multiply in-place, see | ||
| /// [Matrix4.multiply]. | ||
| static void multiplyInPlace(Matrix4 a, Matrix4 b) { |
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.
we should add a todo to clean this up
google/vector_math.dart#250
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.
created google/vector_math.dart#354. I'll see if I can bump the dependencies after that PR is merged.
| childToCommonAncestor[i - 1], | ||
| semanticsClipRect, | ||
| paintClipRect, | ||
| final RenderObject nodeParent = childToCommonAncestor[i]; |
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.
Now Qun's PR is merged, we no longer needed a special path for overlayportal.
| clipPath.add(ancestor); | ||
| ancestor = ancestor.parent; | ||
| } | ||
| final SemanticsNode? ancestorNode = ancestor?._semantics.cachedSemanticsNode; |
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.
dirty nodes' ensureSemantics are called from top to bottom, so ancestor should always have up to date geometry
|
@LongCatIsLooong FYI this has conflicts. |
…ry-slightly-faster
| ); | ||
| } | ||
| } else { | ||
| // Otherwise we have to find the closest ancestor RenderObject that |
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.
Ok I got rid of this path since RenderObject.semanticsParent is now gone so parent must be an ancestor of child.
…ry-slightly-faster
chunhtai
left a comment
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.
LGTM, just some minor comments
| } | ||
| final Rect? localPaintClipInParent = _transformRect( | ||
| nodeParent.describeApproximatePaintClip(node), | ||
| transform, // paint transform from nodeParent to parent |
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.
the comment seems to be inaccurate. Isn't this transform going to be from original child to the current ancestor?
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.
The comment was ambiguous (rephrased to "paint transform of nodeParent in relation to parent") but I think it was correct. To avoid calculating the inverse in every step we'll have to start from the parent. The transform is applied in-place at the end of each for loop so when we calculate the "local" clips the transform is still the paint transform of nodeParent instead node.
| static Rect? _transformRect( | ||
| Rect? rect, | ||
| Matrix4 transform, [ | ||
| Rect Function(Matrix4, Rect) apply = MatrixUtils.inverseTransformRect, |
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.
we should type def this
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.
Added a typedef. But I don't like the typedef because it doesn't tell me the exact signature of the function _transformRect takes unless I look it up.
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.
inline the function signature is also hard to read
…ry-slightly-faster
flutter/flutter@cc14ef5...cb7b7df 2025-11-18 [email protected] Enable UIScene Migration and update create templates (flutter/flutter#178700) 2025-11-18 Minsuk Jung Fix #160622: change containsWatchConpanion function to detect companion watch apps defined by only the project info file. (flutter/flutter#176832) 2025-11-18 [email protected] Roll Skia from 614e71550fc3 to ca906091e199 (2 revisions) (flutter/flutter#178716) 2025-11-18 [email protected] Revert "[ Tool ] Don't delete `.dart_tool/widget_preview_scaffold` during `flutter clean` (#175664)" (flutter/flutter#178672) 2025-11-18 [email protected] Add missing flutter_lints dev dependencies (flutter/flutter#178105) 2025-11-18 [email protected] Roll Skia from ec2f626cdcad to 614e71550fc3 (3 revisions) (flutter/flutter#178708) 2025-11-18 [email protected] Roll Dart SDK from a8ad764281e3 to 312845b06afc (1 revision) (flutter/flutter#178704) 2025-11-18 [email protected] Roll Skia from d7268f8245f2 to ec2f626cdcad (1 revision) (flutter/flutter#178703) 2025-11-18 [email protected] Refactor SnackBar behavior selection example to use `RadioGroup` (flutter/flutter#178618) 2025-11-18 [email protected] Add framework-side hitTestBehavior support for Semantics widget and apply to ModalRoute (flutter/flutter#177570) 2025-11-18 [email protected] Fix deprecation warning in some API examples using RadioListTile (flutter/flutter#178635) 2025-11-18 [email protected] Roll Skia from 47fd0d9b1044 to d7268f8245f2 (6 revisions) (flutter/flutter#178695) 2025-11-18 [email protected] Roll Dart SDK from cf94632d94a1 to a8ad764281e3 (1 revision) (flutter/flutter#178694) 2025-11-18 [email protected] [fuchsia] Add wrapper for zx_iob_writev (flutter/flutter#178626) 2025-11-17 [email protected] Make a11y `computeChildGeometry` slightly faster (flutter/flutter#177477) 2025-11-17 [email protected] Fix DropdownMenu width when decorationBuilder provides label (flutter/flutter#178465) 2025-11-17 [email protected] Add DropdownMenuFormField.decorationBuilder (flutter/flutter#178640) 2025-11-17 [email protected] Roll Skia from 84c83c0dfb4a to 47fd0d9b1044 (4 revisions) (flutter/flutter#178673) 2025-11-17 [email protected] Small cleanup in `AndroidTouchProcessor.java` (flutter/flutter#178574) 2025-11-17 [email protected] Remove unnecessary `final` modifier in `StandardMessageCodec.java` (flutter/flutter#178598) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC [email protected],[email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
This is not a fix for flutter#166173, it's only a by-product. The fix will be in separate PR, this includes the unrelated code changes to make that PR smaller. According to `bench_material3_semantics`, this reduces `Semantics.ensureGeometry` by ~100 μs (321.6 μs -> 228.9 μs). ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
Fixes #173097 The semantics flush is ~200 μs slower with the shortcuircut removed + #177477 (which reduces the time increase by ~ 100 μs, from 876 μs to 773 μs) I tried to introduce caching in [a different patch](https://github.com/flutter/flutter/compare/master...LongCatIsLooong:semantics-geometry?expand=1) but that patch is more risky and still needs a cleanup. 773 μs doesn't seem bad considering there were little to no geometry updates between frames before the fix. Introducing cache currently only improves `Semantics.ensureGeometry` by less than 100 μs and is much more risky / harder to ensure the correctness. ### BEFORE ``` [bench_material3_scroll_semantics] name: bench_material3_scroll_semantics SEMANTICS: (samples: 98 clean/2 outliers/100 measured/300 total) | average: 567.0510204081633 μs | outlier average: 799 μs | outlier/clean ratio: 1.4090442856885785x | noise: 13.95% Semantics.updateChildren: (samples: 91 clean/9 outliers/100 measured/300 total) | average: 58.9010989010989 μs | outlier average: 199.88888888888889 μs | outlier/clean ratio: 3.3936359867330017x | noise: 82.78% Semantics.ensureGeometry: (samples: 95 clean/5 outliers/100 measured/300 total) | average: 95.46315789473684 μs | outlier average: 299 μs | outlier/clean ratio: 3.1320983570404675x | noise: 64.29% Semantics.ensureSemanticsNode: (samples: 100 clean/0 outliers/100 measured/300 total) | average: 78.59 μs | outlier average: 78.59 μs | outlier/clean ratio: 1x | noise: 80.86% drawFrameDuration: (samples: 98 clean/2 outliers/100 measured/300 total) | average: 1685.6938775510205 μs | outlier average: 2000 μs | outlier/clean ratio: 1.1864550418285935x | noise: 7.77%``` ``` ### AFTER (with this and #177477) ``` [bench_material3_scroll_semantics] name: bench_material3_scroll_semantics SEMANTICS: (samples: 91 clean/9 outliers/100 measured/300 total) | average: 773.1098901098901 μs | outlier average: 1000 μs | outlier/clean ratio: 1.2934771793669069x | noise: 10.65% Semantics.updateChildren: (samples: 94 clean/6 outliers/100 measured/300 total) | average: 48.648936170212764 μs | outlier average: 200 μs | outlier/clean ratio: 4.111086813907719x | noise: 102.15% Semantics.ensureGeometry: (samples: 95 clean/5 outliers/100 measured/300 total) | average: 239.55789473684212 μs | outlier average: 399.6 μs | outlier/clean ratio: 1.6680727656208807x | noise: 22.05% Semantics.ensureSemanticsNode: (samples: 99 clean/1 outliers/100 measured/300 total) | average: 194.5151515151515 μs | outlier average: 400 μs | outlier/clean ratio: 2.0563950771148156x | noise: 31.31% drawFrameDuration: (samples: 95 clean/5 outliers/100 measured/300 total) | average: 1775.8315789473684 μs | outlier average: 2099.6 μs | outlier/clean ratio: 1.1823193285280729x | noise: 7.56% ``` ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This is not a fix for flutter#166173, it's only a by-product. The fix will be in separate PR, this includes the unrelated code changes to make that PR smaller. According to `bench_material3_semantics`, this reduces `Semantics.ensureGeometry` by ~100 μs (321.6 μs -> 228.9 μs). ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
Fixes flutter#173097 The semantics flush is ~200 μs slower with the shortcuircut removed + flutter#177477 (which reduces the time increase by ~ 100 μs, from 876 μs to 773 μs) I tried to introduce caching in [a different patch](https://github.com/flutter/flutter/compare/master...LongCatIsLooong:semantics-geometry?expand=1) but that patch is more risky and still needs a cleanup. 773 μs doesn't seem bad considering there were little to no geometry updates between frames before the fix. Introducing cache currently only improves `Semantics.ensureGeometry` by less than 100 μs and is much more risky / harder to ensure the correctness. ### BEFORE ``` [bench_material3_scroll_semantics] name: bench_material3_scroll_semantics SEMANTICS: (samples: 98 clean/2 outliers/100 measured/300 total) | average: 567.0510204081633 μs | outlier average: 799 μs | outlier/clean ratio: 1.4090442856885785x | noise: 13.95% Semantics.updateChildren: (samples: 91 clean/9 outliers/100 measured/300 total) | average: 58.9010989010989 μs | outlier average: 199.88888888888889 μs | outlier/clean ratio: 3.3936359867330017x | noise: 82.78% Semantics.ensureGeometry: (samples: 95 clean/5 outliers/100 measured/300 total) | average: 95.46315789473684 μs | outlier average: 299 μs | outlier/clean ratio: 3.1320983570404675x | noise: 64.29% Semantics.ensureSemanticsNode: (samples: 100 clean/0 outliers/100 measured/300 total) | average: 78.59 μs | outlier average: 78.59 μs | outlier/clean ratio: 1x | noise: 80.86% drawFrameDuration: (samples: 98 clean/2 outliers/100 measured/300 total) | average: 1685.6938775510205 μs | outlier average: 2000 μs | outlier/clean ratio: 1.1864550418285935x | noise: 7.77%``` ``` ### AFTER (with this and flutter#177477) ``` [bench_material3_scroll_semantics] name: bench_material3_scroll_semantics SEMANTICS: (samples: 91 clean/9 outliers/100 measured/300 total) | average: 773.1098901098901 μs | outlier average: 1000 μs | outlier/clean ratio: 1.2934771793669069x | noise: 10.65% Semantics.updateChildren: (samples: 94 clean/6 outliers/100 measured/300 total) | average: 48.648936170212764 μs | outlier average: 200 μs | outlier/clean ratio: 4.111086813907719x | noise: 102.15% Semantics.ensureGeometry: (samples: 95 clean/5 outliers/100 measured/300 total) | average: 239.55789473684212 μs | outlier average: 399.6 μs | outlier/clean ratio: 1.6680727656208807x | noise: 22.05% Semantics.ensureSemanticsNode: (samples: 99 clean/1 outliers/100 measured/300 total) | average: 194.5151515151515 μs | outlier average: 400 μs | outlier/clean ratio: 2.0563950771148156x | noise: 31.31% drawFrameDuration: (samples: 95 clean/5 outliers/100 measured/300 total) | average: 1775.8315789473684 μs | outlier average: 2099.6 μs | outlier/clean ratio: 1.1823193285280729x | noise: 7.56% ``` ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This is not a fix for flutter#166173, it's only a by-product. The fix will be in separate PR, this includes the unrelated code changes to make that PR smaller. According to `bench_material3_semantics`, this reduces `Semantics.ensureGeometry` by ~100 μs (321.6 μs -> 228.9 μs). ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
Fixes flutter#173097 The semantics flush is ~200 μs slower with the shortcuircut removed + flutter#177477 (which reduces the time increase by ~ 100 μs, from 876 μs to 773 μs) I tried to introduce caching in [a different patch](https://github.com/flutter/flutter/compare/master...LongCatIsLooong:semantics-geometry?expand=1) but that patch is more risky and still needs a cleanup. 773 μs doesn't seem bad considering there were little to no geometry updates between frames before the fix. Introducing cache currently only improves `Semantics.ensureGeometry` by less than 100 μs and is much more risky / harder to ensure the correctness. ### BEFORE ``` [bench_material3_scroll_semantics] name: bench_material3_scroll_semantics SEMANTICS: (samples: 98 clean/2 outliers/100 measured/300 total) | average: 567.0510204081633 μs | outlier average: 799 μs | outlier/clean ratio: 1.4090442856885785x | noise: 13.95% Semantics.updateChildren: (samples: 91 clean/9 outliers/100 measured/300 total) | average: 58.9010989010989 μs | outlier average: 199.88888888888889 μs | outlier/clean ratio: 3.3936359867330017x | noise: 82.78% Semantics.ensureGeometry: (samples: 95 clean/5 outliers/100 measured/300 total) | average: 95.46315789473684 μs | outlier average: 299 μs | outlier/clean ratio: 3.1320983570404675x | noise: 64.29% Semantics.ensureSemanticsNode: (samples: 100 clean/0 outliers/100 measured/300 total) | average: 78.59 μs | outlier average: 78.59 μs | outlier/clean ratio: 1x | noise: 80.86% drawFrameDuration: (samples: 98 clean/2 outliers/100 measured/300 total) | average: 1685.6938775510205 μs | outlier average: 2000 μs | outlier/clean ratio: 1.1864550418285935x | noise: 7.77%``` ``` ### AFTER (with this and flutter#177477) ``` [bench_material3_scroll_semantics] name: bench_material3_scroll_semantics SEMANTICS: (samples: 91 clean/9 outliers/100 measured/300 total) | average: 773.1098901098901 μs | outlier average: 1000 μs | outlier/clean ratio: 1.2934771793669069x | noise: 10.65% Semantics.updateChildren: (samples: 94 clean/6 outliers/100 measured/300 total) | average: 48.648936170212764 μs | outlier average: 200 μs | outlier/clean ratio: 4.111086813907719x | noise: 102.15% Semantics.ensureGeometry: (samples: 95 clean/5 outliers/100 measured/300 total) | average: 239.55789473684212 μs | outlier average: 399.6 μs | outlier/clean ratio: 1.6680727656208807x | noise: 22.05% Semantics.ensureSemanticsNode: (samples: 99 clean/1 outliers/100 measured/300 total) | average: 194.5151515151515 μs | outlier average: 400 μs | outlier/clean ratio: 2.0563950771148156x | noise: 31.31% drawFrameDuration: (samples: 95 clean/5 outliers/100 measured/300 total) | average: 1775.8315789473684 μs | outlier average: 2099.6 μs | outlier/clean ratio: 1.1823193285280729x | noise: 7.56% ``` ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This is not a fix for #166173, it's only a by-product. The fix will be in separate PR, this includes the unrelated code changes to make that PR smaller.
According to
bench_material3_semantics, this reducesSemantics.ensureGeometryby ~100 μs (321.6 μs -> 228.9 μs).Pre-launch Checklist
///).If you need help, consider asking for advice on the #hackers-new channel on Discord.
Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the
gemini-code-assistbot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.