Skip to content

SI-6723 Don't count @inline methods when computing the inline budget #4041

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

Closed
wants to merge 1 commit into from

Conversation

lrytz
Copy link
Member

@lrytz lrytz commented Oct 9, 2014

Otherwise the inlining budged exceeds when many @inline methods are
invoked. This triggers inline warnings for those that aren't inlined
anymore.

@scala-jenkins scala-jenkins added this to the 2.11.4 milestone Oct 9, 2014
@@ -0,0 +1 @@
-optimize -Xfatal-warnings
Copy link
Member

Choose a reason for hiding this comment

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

Did you also intend to have -Yinline-warnings enabled?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's not necessary, there's a one-line warning: there were 16 inliner warnings; re-run with -Yinline-warnings for details.

Copy link
Member

Choose a reason for hiding this comment

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

Okay.

Perhaps it would be more self documenting of the tests intent though? Alternatively, add comment to the test (e.g. "should not create inliner warnings")

@lrytz lrytz modified the milestones: 2.11.4, 2.11.5 Oct 14, 2014
Otherwise the inlining budged exceeds when many `@inline` methods are
invoked. This triggers inline warnings for those that aren't inlined
anymore.
@lrytz
Copy link
Member Author

lrytz commented Nov 4, 2014

added -Yinline-warnings to the flags file, ping @retronym

@retronym
Copy link
Member

retronym commented Nov 5, 2014

Here's a bytecode diff of scala-{compiler,library}.jar after bootstrapping with this change.

http://rawgit.com/retronym/6e6b2899c02be2918afe/raw/out.html

(Load into Sublime and set the syntax mode to diff for easier reading)

We should take a look at this to get a feeling for the risk of this change (will over-inlining hurt some performance somewhere?)

/cc @Ichoran

To create these:

[diff "javap"]
    textconv = /Users/jason/code/libscala/git-java/textconv-javap
    cachetextconv = true
[diff "jar-toc"]
    textconv = /Users/jason/code/libscala/git-java/textconv-jar
    cachetextconv = true
  • check the "before" a JAR and and its contents into a temporary git repository
  • do the same for the "after" version
  • Run git show.

@retronym
Copy link
Member

retronym commented Nov 5, 2014

That diff suggests that the bytecode for scala-library was unchanged. Maybe that's right, but please feel free to reproduce these results to see if I've messed up the comparison.

% ls -la *.jar # new
-rw-r--r--  1 jason  wheel  13393196 Nov  5 15:09 scala-compiler.jar
-rw-r--r--  1 jason  wheel   5473883 Nov  5 15:09 scala-library.jar
  /tmp/git git checkout head~1
Note: checking out 'head~1'.

HEAD is now at 9ea9f98... baseline
$ /tmp/git ls -la *.jar # old
-rw-r--r--  1 jason  wheel  13483778 Nov  5 15:24 scala-compiler.jar
-rw-r--r--  1 jason  wheel   5473883 Nov  5 15:24 scala-library.jar

@lrytz
Copy link
Member Author

lrytz commented Nov 10, 2014

An extensive scientific study under my supervision could not show any performance regression in the following use case.

Both compilers were built with build-opt, a full (locker & quick) bootstrap.

# before the patch
lucmac:sandbox luc$ for i in {1..3}; do rm -rf out/*; time ../build-before/pack/bin/scalac -optimize `find ../src/library -name '*.scala'` -d out/; done
real    0m50.541s
real    0m51.599s
real    0m51.415s

# with the patch
lucmac:sandbox luc$ for i in {1..3}; do rm -rf out/*; time ../build-after/pack/bin/scalac -optimize `find ../src/library -name '*.scala'` -d out/; done
real    0m48.831s
real    0m50.892s
real    0m50.766s

@adriaanm
Copy link
Contributor

@retronym, shall we merge or delay?

@adriaanm
Copy link
Contributor

I'll merge the last 2.11.5 PRs my Monday morning, if they have been LGTM'ed by then.

@Ichoran
Copy link
Contributor

Ichoran commented Dec 20, 2014

Is there a possibility for infinite expansion with this patch? I.e. what happens to

final class Foo {
  @inline def bar(x: Int): Int = if (x <= 0) x else baz(x)-1
  @inline def baz(x: Int): Int = if (x >= 100) 100 else bar(x)
  def quux = bar(101)
}

Other than infinite recursive inlining (or exceeding maximum method bytecode size), I wouldn't worry about over-inlining @inlined methods. In particular, you want a chain of forwarders 100 deep to all disappear.

@lrytz
Copy link
Member Author

lrytz commented Dec 21, 2014

Ugh, thanks for pointing that out. Indeed the example causes an infinite loop.

Another problem with skipping the budged is unlimited exponential expansion:

final class Foo {
  @inline def a: Int = 1
  @inline def b: Int = a + a
  @inline def c: Int = b + b
  @inline def d: Int = c + c
  def e: Int = d + d // 16 times the body of a
}

Maybe a better solution than counting the number of inlines would be to limit the size / growth of the target method.

@lrytz lrytz modified the milestones: 2.11.6, 2.11.5 Dec 21, 2014
@Ichoran
Copy link
Contributor

Ichoran commented Dec 22, 2014

@lrytz - I am not sure that it is wrong to have exponential expansion if people really annotate things to be inlined that way. I like the idea of instead limiting the size of the target method (probably with multiple thresholds: don't exceed max method size, don't expand total size of the method more than X, don't expand any individual function call more than Y (note that inlining could actually shrink the size if it allows you to skip boxing)).

@retronym
Copy link
Member

retronym commented Jan 4, 2015

Sorry about the slow response on this one. Looks like @Ichoran and @lrytz have honed in on the tricky cases in the meantime.

@inlined
Copy link

inlined commented Jan 14, 2015

Not sure why you're singling me out of your budget. Ah well

@lrytz
Copy link
Member Author

lrytz commented Jan 14, 2015

:)

@retronym
Copy link
Member

retronym commented Feb 3, 2015

@lrytz I'm going to close this one, please reopen when we find a way past the infinite inlining problem and have a grip on the not-quite-infinite-but-still-worryingly-large inlining problem.

@retronym retronym closed this Feb 3, 2015
@retronym
Copy link
Member

retronym commented Feb 8, 2015

I've been taking a cursory look at the inliner in OpenJDK's C1 compiler. I spotted a few things that are relevant to this PR.

They also have an annotation to force inlining of a method: java.lang.invoke.ForceInline (for internal use only) and via a command line option -XX:CompileCommand=inline,Class::method.

This forced inlining is yoked with -XX:MaxForceInlineLevel, which is hard-defaulted to 100 and only tweakable in debug builds of the JVM.

MaxForceInlineLevel

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.

6 participants