Skip to content

Optimize interpolateTypeVars #6331

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

Merged
merged 7 commits into from
Apr 19, 2019
Merged

Conversation

odersky
Copy link
Contributor

@odersky odersky commented Apr 17, 2019

There seemed to have been a large performance regression due to its recent changes. Let's find
out whether that's really the case.

odersky added 2 commits April 17, 2019 19:02
There seemed to have been a large performance regression due to its recent changes. Let's find
out whether that's really the case.
@odersky
Copy link
Contributor Author

odersky commented Apr 17, 2019

test performance please

@dottybot
Copy link
Member

performance test scheduled: 4 job(s) in queue, 1 running.

@dottybot
Copy link
Member

Performance test finished successfully:

Visit http://dotty-bench.epfl.ch/6331/ to see the changes.

Benchmarks is based on merging with master (f09550d)

@odersky
Copy link
Contributor Author

odersky commented Apr 17, 2019

I wonder what's going on with the benchmarks? We see a lot more volatility than wee used to. This PR seems to improve the situation somewhat for Dotty compilation, but we still have no clue what caused the dramatic degradation in #6301 - it does not look that the changes in this commit were to blame alone.

EDIT: #6333 demonstrated that the changes in this commit were indeed to blame alone. The benchmarks were accurate.

@odersky
Copy link
Contributor Author

odersky commented Apr 18, 2019

test performance please

@dottybot
Copy link
Member

performance test scheduled: 1 job(s) in queue, 1 running.

 - drop -- since it is not used anymore.
 - optimize ++ by special casing empty sets and
   large, array-backed sets.
@smarter
Copy link
Member

smarter commented Apr 18, 2019

I think the bugfix is revealing some underlying bug, when compiling Dotty there's only a few cases where the old check returned false and the new returned true, but a couple of those have a crazy amount of type variables:

state: TS[7389, 7388, 7387]
state.ownedVars: 28
locked: 28

state: TS[7389, 7388, 7387]
state.ownedVars: 344
locked: 344

state: TS[7389, 7388, 7387]
state.ownedVars: 344
locked: 344

state: TS[7389, 7388, 7387]
state.ownedVars: 344
locked: 345

@odersky
Copy link
Contributor Author

odersky commented Apr 18, 2019

Would be interesting to find out for what inputs these large sets are created.

@smarter
Copy link
Member

smarter commented Apr 18, 2019

It looks like all these type variables are created using newDepTypeVar, I'm not sure how these are supposed to interact with interpolation.

@odersky
Copy link
Contributor Author

odersky commented Apr 18, 2019

It looks like all these type variables are created using newDepTypeVar, I'm not sure how these are supposed to interact with interpolation.

They get added to typerState.ownedVars and subsequently typedArg or implicit search will move them to locked. A question is whether we can garbage collect them more aggressively. I am not sure.

smarter added a commit to smarter/dotty that referenced this pull request Apr 18, 2019
@odersky
Copy link
Contributor Author

odersky commented Apr 18, 2019

It looks like all these type variables are created using newDepTypeVar, I'm not sure how these are supposed to interact with interpolation.

Yes, but what is the source file that causes so many dependent TypeVars to be created? I verified that when compiling all files in typer the maximum ownedVars set size is 9. So it must be some particular circumstance in the source that causes the set to explode.

@smarter
Copy link
Member

smarter commented Apr 18, 2019

Most seem to be either in Trees.scala or untpd.scala (apparently because of def postProcess)

@odersky
Copy link
Contributor Author

odersky commented Apr 18, 2019

That makes sense. postprocess (and finalize) are dependent methods. The question why the typevars are not collected sooner is still open.

@dottybot
Copy link
Member

Performance test finished successfully:

Visit http://dotty-bench.epfl.ch/6331/ to see the changes.

Benchmarks is based on merging with master (2eebb70)

Bring back -- but optimize it for the case where the sets
are similar.
@odersky
Copy link
Contributor Author

odersky commented Apr 18, 2019

test performance please

@dottybot
Copy link
Member

performance test scheduled: 3 job(s) in queue, 1 running.

@dottybot
Copy link
Member

Performance test finished successfully:

Visit http://dotty-bench.epfl.ch/6331/ to see the changes.

Benchmarks is based on merging with master (832b140)

@odersky
Copy link
Contributor Author

odersky commented Apr 18, 2019

OK, we are back to normal. We could still check whether we have to create so many ownedVars in the first place.

@odersky
Copy link
Contributor Author

odersky commented Apr 18, 2019

I propose to merge this now to get back a stable baseline for other performance tests.

(this /: that.toList)(_ - _)
if (this.size == 0) that
else if (that.size == 0) this
else concat(that)
Copy link
Member

Choose a reason for hiding this comment

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

Why have both concat and ++, with some extra checks in ++ ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I originally thought of putting concat in Set 1-3, so wanted to factor put the common behavior. But the way it is now a single method is better.

var j = searchStart // search thatElems in round robin fashion, starting one after latest hit
var missing = false
while (!missing && elem != thatElems(j)) {
j = (j + 1) % thatSize
Copy link
Member

Choose a reason for hiding this comment

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

% is fairly expensive in cpu cycles, I would do:

j += 1
if (j == thatSize) j = 0

val elem = this.xs(i)
var j = searchStart // search thatElems in round robin fashion, starting one after latest hit
var missing = false
while (!missing && elem != thatElems(j)) {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
while (!missing && elem != thatElems(j)) {
while (!missing && elem `ne` thatElems(j)) {

@odersky
Copy link
Contributor Author

odersky commented Apr 19, 2019

There's another use of % below for searchStart, although that one is in a less tight loop.

Yes, I saw that. I don't think we need to optimize it since it's in the outer loop.

@odersky odersky merged commit cdf5b1e into scala:master Apr 19, 2019
@liufengyun liufengyun deleted the opt-interpolate branch April 19, 2019 16:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants