Skip to content

Conversation

@gaaclarke
Copy link
Member

@gaaclarke gaaclarke commented May 12, 2022

This clamp performs roughly 4x12x faster than dart's. I implemented it to speed up layout_bench.dart with respect to BoxConstraints. Ultimately that change was small 1%-2% but it showed that certain usages of clamp could greatly be sped up for other hypothetical use cases.

It's faster because:

  1. It avoids boxing with the num type
  2. It doesn't perform null checks
  3. It doesn't have an extra layer of indirection calling compareTo
  4. It doesn't care about the difference between 0.0 and -0.0
  5. It doesn't ever check to see if the arguments are int
  6. It doesn't support nan for min and max limits
  7. It appears to be inlined by the compiler

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.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@flutter-dashboard flutter-dashboard bot added a: animation Animation APIs a: text input Entering text in a text field or keyboard related problems f: cupertino flutter/packages/flutter/cupertino repository f: gestures flutter/packages/flutter/gestures repository. f: material design flutter/packages/flutter/material repository. f: scrolling Viewports, list views, slivers, etc. framework flutter/packages/flutter repository. See also f: labels. labels May 12, 2022
@nt4f04uNd
Copy link
Member

I wonder - is this a rare case where having an extension on double would actually be better than a standalone function?

@gaaclarke
Copy link
Member Author

I wonder - is this a rare case where having an extension on double would actually be better than a standalone function?

It definitely would have made my life easier but it's my understanding it's against the style guide.

@gaaclarke gaaclarke force-pushed the double-clamp branch 7 times, most recently from 5ed7d8b to e2a32c9 Compare May 13, 2022 22:52
@gaaclarke gaaclarke marked this pull request as ready for review May 13, 2022 22:53
Copy link
Contributor

@jonahwilliams jonahwilliams left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to have a test that ensures anyone that commits new code uses clampDouble instead of num.clamp.

See https://github.com/flutter/flutter/blob/master/dev/bots/analyze.dart for some examples of flagging code or comment patterns to fail analysis

@gaaclarke
Copy link
Member Author

It would be nice to have a test that ensures anyone that commits new code uses clampDouble instead of num.clamp.

See https://github.com/flutter/flutter/blob/master/dev/bots/analyze.dart for some examples of flagging code or comment patterns to fail analysis

Yea, I thought the same thing. I read through that script and the only step that is actually parsing any code is verifySkipTestComments which is parsing files based on the name ending with _test.dart. We need to fully parse the files in order to distinguish between clamp called on ints and clamp called on doubles. I would need to do a bit of trailblazing to make that work. It's worth probably time boxing some time to at least take a stab at it. I'll probably have to juggle things around so different steps don't parse the same files twice. This thing is just used to run a CI step once per PR?

@gaaclarke
Copy link
Member Author

@jonahwilliams does that analyze bot get run anywhere? It fails for me locally:

aaclarke-macbookpro2:flutter aaclarke$ git checkout master
Switched to branch 'master'
Your branch is behind 'origin/master' by 323 commits, and can be fast-forwarded.
  (use "git pull" to update your local branch)
aaclarke-macbookpro2:flutter aaclarke$ dart --enable-asserts run dev/bots/analyze.dart 
▌16:33:34▐ STARTING ANALYSIS
▌16:33:34▐ All tool test files end in _test.dart...
▌16:33:34▐ No sync*/async*
▌16:33:35▐ No runtimeType in toString...
▌16:33:35▐ Debug mode instead of checked mode...
▌16:33:36▐ Links for creating GitHub issues
▌16:33:37▐ Unexpected binaries...
▌16:33:38▐ Trailing spaces...
▌16:33:39▐ Deprecations...
▌16:33:40▐ Goldens...
▌16:33:41▐ Skip test comments...
Unhandled exception:
Invalid argument(s): Content produced diagnostics when parsed:
  EXPECTED_TOKEN: Expected to find '}'. - 54:18

#0      parseString (package:analyzer/dart/analysis/utilities.dart:102:5)
#1      parseFile (package:analyzer/dart/analysis/utilities.dart:46:10)
#2      _getTestSkips (file:///Users/aaclarke/dev/flutter/dev/bots/analyze.dart:528:41)
#3      verifySkipTestComments (file:///Users/aaclarke/dev/flutter/dev/bots/analyze.dart:573:34)
<asynchronous suspension>
#4      run (file:///Users/aaclarke/dev/flutter/dev/bots/analyze.dart:120:3)
<asynchronous suspension>
#5      main (file:///Users/aaclarke/dev/flutter/dev/bots/analyze.dart:52:5)
<asynchronous suspension>

@jonahwilliams
Copy link
Contributor

It runs on every CI. Try dart --enable-asserts dev/bots/analyze.dart

@dnfield
Copy link
Contributor

dnfield commented May 14, 2022

It would be nice to have a lint for this somehow. I don't think we can properly lint this without having an analyzer check for it.

@dnfield
Copy link
Contributor

dnfield commented May 14, 2022

It would also be nice if somehow the compiler can just fix this for us via TFA. @alexmarkov @a-siva

Copy link
Contributor

@dnfield dnfield left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a microbenchmark for this.

@gaaclarke
Copy link
Member Author

gaaclarke commented May 16, 2022

Please add a microbenchmark for this.

Microbenchmark added, in microbenchmarks it's actually 80x faster. (I was guessing 4x based off of what I was seeing in profiling).

@gaaclarke
Copy link
Member Author

(rebasing to hopefully flush out outstanding ci issues)

@gaaclarke
Copy link
Member Author

I'm landing this despite google testing showing up yellow. The google test was run successfully in the above CL, the rerun that just happened finished but didn't update its status yet. There is one failure there out of 2190 runs. There is one failure that isn't related to this one, but has to do with apple signing certificates.

@bernaferrari
Copy link
Contributor

bernaferrari commented May 18, 2022

I guess every single one of you has thought about this possibility, but since no one said anything, isn't it possible to fix Dart? Or at least do something there like clamp2/dangerousClamp/fastClamp, who knows? lol This is super useful. If it is too big, maybe schedule for Dart 3? I would love to see this on Dart side too.

@gaaclarke
Copy link
Member Author

I guess every single one of you has thought about this possibility, but since no one said anything, isn't it possible to fix Dart? Or at least do something there like clamp2/dangerousClamp/fastClamp, who knows? lol This is super useful. If it is too big, maybe schedule for Dart 3? I would love to see this on Dart side too.

I'm going to file a bug with them but if you look at the the reason that this is faster, not all of them could be brought into Dart. For example we ignore nan for the limits. We can do that because we know we don't care about it. Dart can't do that. That said, my understanding is that the large part of this optimization comes from avoiding num which requires polymorphism to evaluate. A solution probably requires a special case for compile-time function resolution when dealing with num types.

@eseidelGoogle
Copy link
Contributor

FYI @mraleph

@mraleph
Copy link
Member

mraleph commented May 24, 2022

@bernaferrari we are going to fix Dart (see dart-lang/sdk#40852 and dart-lang/sdk#46879), it's not going to become as fast as custom clamp implementation (because it does more checking), but we should get pretty close.

Note that while improvement looks great/important in isolation, it hardly matters unless all you do is clamping.

@gaaclarke
Copy link
Member Author

This PR resulted in a 4.2% increase in performance for stock_layout_iteration: https://flutter-flutter-perf.skia.org/e/?begin=1652777644&end=1652981286&queries=sub_result%3Dstock_layout_iteration&requestType=0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: animation Animation APIs a: text input Entering text in a text field or keyboard related problems c: contributor-productivity Team-specific productivity, code health, technical debt. f: cupertino flutter/packages/flutter/cupertino repository f: gestures flutter/packages/flutter/gestures repository. f: material design flutter/packages/flutter/material repository. f: scrolling Viewports, list views, slivers, etc. framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants