Skip to content

Fix inefficieny in the presence of aliasing. #984

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 5 commits into from
Nov 30, 2015

Conversation

odersky
Copy link
Contributor

@odersky odersky commented Nov 29, 2015

The change to do compareAlias early caused a dramatic slowdown of compilation

compileStdLib went from 45 sec to 230 sec. The problem were many redundant tests
when every member of an alias chain was compared to every other.

The new scheme follows alias chains to their end before doing anything else. Review by @smarter

secondTry(tp1, tp2)
implicit val ctx: Context = this.ctx
tp2.info match {
case info2: TypeAlias => firstTry(tp1, info2.alias)
Copy link
Member

Choose a reason for hiding this comment

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

It seems like you could avoid a bunch of recursive calls to firstTry by using a utility function like:

def dealiasTypeRef(tp: TypeRef): Type =
  if (tp.symbol.isClass) tp
  else tp.info match {
   case TypeAlias(alias: TypeRef) => dealiasTypeRef(alias)
   case TypeAlias(alias) => alias
   case _ => tp
  }

@smarter
Copy link
Member

smarter commented Nov 29, 2015

/rebuild

@odersky
Copy link
Contributor Author

odersky commented Nov 29, 2015

Yes, but would this be faster? I noticed we had some deteriorations in
compiler performance lately. compileStdLib was the poster child. But even
after the fix, compile dotty went up from 66 to 81 seconds. I guess we
should keep a watchful eye on this and do some measurements everytime we
touch core code.

On Sun, Nov 29, 2015 at 5:47 PM, Guillaume Martres <notifications@github.com

wrote:

/rebuild


Reply to this email directly or view it on GitHub
#984 (comment).

Martin Odersky
EPFL

@smarter
Copy link
Member

smarter commented Nov 29, 2015

It should be as fast, but less recursive calls mean less risk of deep subtype errors

@smarter
Copy link
Member

smarter commented Nov 29, 2015

stderr: error: could not lock config file .git/config: No space left on device

@SethTisue @adriaanm : Help 😦

@odersky
Copy link
Contributor Author

odersky commented Nov 29, 2015

Note that the two calls in question are tailcalls anyway.

@smarter
Copy link
Member

smarter commented Nov 29, 2015

Note that the two calls in question are tailcalls anyway.

Yes, but firstTry cannot be tailcall-optimized so they still consume stack space, if you try to annotate it with @tailrec you'll see:

TypeComparer.scala:235: could not optimize @tailrec annotated method firstTry: it contains a recursive call not in tail position
       secondTry(tp1, tp2)
                ^

@odersky
Copy link
Contributor Author

odersky commented Nov 29, 2015

@smarter Yes, you are right. It's not a recognized as a tailcall because it
comes from a nested method.

One thing we could try is simply call firstTry with dealiased types. That
way we could avoid the
distinctions in firstTry itself. Do you want to try that and see how it
affects performance?

On Sun, Nov 29, 2015 at 6:13 PM, Guillaume Martres <notifications@github.com

wrote:

Note that the two calls in question are tailcalls anyway.

Yes, but firstTry cannot be tailcall-optimized so they still consume
stack space, if you try to annotate it with @tailrec you'll see:

TypeComparer.scala:235: could not optimize @tailrec annotated method firstTry: it contains a recursive call not in tail position
secondTry(tp1, tp2)
^


Reply to this email directly or view it on GitHub
#984 (comment).

Martin Odersky
EPFL

@smarter
Copy link
Member

smarter commented Nov 29, 2015

I just tried it and it seems to be about as fast as your patch, I'll make a PR

@smarter
Copy link
Member

smarter commented Nov 29, 2015

@odersky : I made a commit to avoid the recursive calls to compareNamed, feel free to add it to this PR: https://github.com/smarter/dotty/commits/optimize-subtyping

@@ -417,29 +414,11 @@ class TypeApplications(val self: Type) extends AnyVal {

/** If this is the image of a type argument to type parameter `tparam`,
Copy link
Member

Choose a reason for hiding this comment

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

This still refers to tparam even though tparam is not a parameter of this method anymore. I think the comment could be simplified to just If this is the image of a type argument for a type parameter, recover the type argument, otherwise NoType., although I'd appreciate it if you could explain the meaning of image in the documentation.

@smarter
Copy link
Member

smarter commented Nov 30, 2015

Otherwise LGTM.

@odersky
Copy link
Contributor Author

odersky commented Nov 30, 2015

Could you do the change and commit please? It's currently hard for me to
make the context switch. Thanks!

On Mon, Nov 30, 2015 at 3:47 PM, Guillaume Martres <notifications@github.com

wrote:

Otherwise LGTM.


Reply to this email directly or view it on GitHub
#984 (comment).

Martin Odersky
EPFL

@smarter
Copy link
Member

smarter commented Nov 30, 2015

Sure!

@smarter
Copy link
Member

smarter commented Nov 30, 2015

/rebuild

2 similar comments
@smarter
Copy link
Member

smarter commented Nov 30, 2015

/rebuild

@smarter
Copy link
Member

smarter commented Nov 30, 2015

/rebuild

odersky and others added 5 commits November 30, 2015 17:31
…pilation

compileStdLib went from 45 sec to 230 sec. The problem were many redundant tests
when every member of an alias chain was compared to every other.

The new scheme follows alias chains to their end before doing anything else.
I noted a slowdown of about 25% (66sec -> 81sec) when compiling dotty even
after the subtype optimization (before it was 117sec).
I tracked it down to the traceIndented fix which avoided questions to be evaluated
twice. But it also caused the question to be evaluated
Making the val lazy fixed the problem.
It turns out it's not needed because now all type arguments are
expressed as aliases. Interestingly dropping this feature shaved
20% off the time off junit tests. Which seems to indicate that the
handling of type application is really performance critical.
@SethTisue
Copy link
Member

I will go fix the disk space problem now.

@smarter
Copy link
Member

smarter commented Nov 30, 2015

@SethTisue : Hurray, thanks :)

@SethTisue
Copy link
Member

/rebuild

smarter added a commit that referenced this pull request Nov 30, 2015
Fix inefficieny in the presence of aliasing.
@smarter smarter merged commit 1125646 into scala:master Nov 30, 2015
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