Skip to content
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

Consider rolling back optimizations for List, collections from 2.11 compiler tuning to the collections themselves. #8240

Closed
scabug opened this issue Feb 5, 2014 · 11 comments
Assignees
Milestone

Comments

@scabug
Copy link

scabug commented Feb 5, 2014

I found that using specialized code rather than:

List#{map, collect, nonEmpty, isEmpty}

gave small but measurable performance wins the compiler on hot paths.

Hypothoses:

  • calling nonEmpty incurs a megamorphic cost that JIT can't inline its way around.
  • allocating a ListBuffer when mapping over an already empty list is wasteful

We should see if we could reproduce these results in a compiler-free microbenchmark of collections and roll the improvements back.

Care must be taken when introducing overloads in List that we don't go backwards in call sites that oscilate between a variety of collections (in the compiler we almost always use List).

@scabug
Copy link
Author

scabug commented Feb 5, 2014

Imported From: https://issues.scala-lang.org/browse/SI-8240?orig=1
Reporter: @retronym
Affected Versions: 2.11.0-M8

@scabug
Copy link
Author

scabug commented Feb 9, 2014

@Ichoran said:
Moved up the schedule for this to 2.11.0.RC1. Since this is supposed to be a performance release, if we can in fact give a big improvement in a very commonly used data structure like List, this would be great. Will push off until later if it is not a clear win in all reasonable scenarios.

@scabug
Copy link
Author

scabug commented Feb 9, 2014

@Ichoran said:
The PR with Jason's custom methods is at scala/scala#3444

@scabug
Copy link
Author

scabug commented Feb 10, 2014

@Ichoran said:
eq Nil doesn't work very well, but avoiding the generic List.ReusableCBF for building in map is an amazing boost, 5x or so. No evidence of megamorphism penalty in mixed cases. (Probably because we already have that penalty from List.ReusableCBF vs other ReusableCBFs.)

@scabug
Copy link
Author

scabug commented Feb 10, 2014

@Ichoran said:
scala/scala#3498

@scabug
Copy link
Author

scabug commented Feb 10, 2014

@pavelpavlov said:

calling nonEmpty incurs a megamorphic cost that JIT can't inline its way around.
We can define isEmpty, nonEmpty as:

class List[T] {
override final def isEmpty = this eq Nil
override final def nonEmpty = this ne Nil
}

@scabug
Copy link
Author

scabug commented Feb 10, 2014

@pavelpavlov said:
Also it would be good to teach the compiler to recognize non-overriden methods in sealed classes and to mark them automatically as final in bytecode

@scabug
Copy link
Author

scabug commented Feb 10, 2014

@retronym said:
Just as context: my original change tread lightly on the collections proper, opting instead to directly use specialized methods in the compiler. This was just to minimize risk of performance regressions. Now that Rex has a bit of time to take his benchmarking prowess to the problem, we can indeed define nonEmpty/isEmpty that way, and change the compiler to rollback some of my changes. But some of that might still have to wait until after 2.11.0.

@scabug
Copy link
Author

scabug commented Feb 10, 2014

@Ichoran said:
I saw no performance benefit from changing isEmpty. I didn't bother checking nonEmpty.

@scabug
Copy link
Author

scabug commented Feb 14, 2014

@Ichoran said (edited on Feb 14, 2014 3:17:39 AM UTC):
(Comment went to the wrong issue due to a connectivity issue. C'mon JIRA--most people can get this right these days!)

@scabug
Copy link
Author

scabug commented Feb 16, 2014

@adriaanm said:
scala/scala#3498

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

No branches or pull requests

2 participants