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

Remove workarounds for sbt/sbt#1035 #393

Merged
merged 2 commits into from
Sep 28, 2017

Conversation

jvican
Copy link
Member

@jvican jvican commented Aug 11, 2017

The workarounds are not necessary anymore,
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6476261 has been
fixed in JDK8, which is the JDK version that Zinc demands.

We can change the target branch after this is LGTM'ed and the forward port
for 1.0.x is finished.

@jvican
Copy link
Member Author

jvican commented Aug 11, 2017

Note the ref to sbt/sbt#1035.


private[this] def convert(classes: Array[Class[_]]): Array[Type] =
classes.asInstanceOf[Array[Type]] // ok: treat Arrays as read-only
@inline private[this] def returnType(f: Field): Type = f.getGenericType
Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member Author

@jvican jvican Aug 11, 2017

Choose a reason for hiding this comment

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

Yes, it does. Inlining is extremely important and it can cause slowdowns, but in Scala code it generally yields good benefits. For example, using @inline in certain places of the Scala compiler is critical for performance (an example is all the statistics infrastructure). JVM inlining is normally not enough for Scala code because it will only inline up to 135 bytes, IIRC, and this is why the careful use of @inline is important. I saw a tweet by Jason some weeks ago claiming that increasing this bytecode limit in the JDK helps performance for Scalac.

So, coming back to your question: yes, @inline has a real-world impact. It will not make the program 20% faster in this scenario, but it's a good practice to use @inline where applicable, and I think in this case it is.

Copy link
Member Author

Choose a reason for hiding this comment

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

Note also that the use of @inline does not mean the Scala compiler will inline it. It may or may not, depending on some heuristics. But this doesn't prove my point wrong.

Copy link
Member

Choose a reason for hiding this comment

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

@cb372 gave a whole talk on this topic. What was the verdict on this topic? -optimize is better than handcrafted @inline? http://slides.com/cb372/inline-specialized-berlin-2016#/27

Copy link
Member Author

Choose a reason for hiding this comment

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

That's a benchmark of numerical computations. Those kind of benchmarks are really misleading and easy to optimize efficiently by the Hotspot, probably with not even inlining but also loop unfolding et al. To add to that, it doesn't say anything about the benchmark setup and 2.12.3 improved the optimizer and inliner, making those benchmarks (for 2.12.0-M2) useless. So I think that link has no relevance to the scenario we're dealing with here.

By the by, this scenario is clearly beneficial for inlining because we only have one call-site, and it's in the same class definition (unlike the benchmark you mention). The benefit is that we don't pay the cost of invoking these functions, while still making them logically independent if in the future we want to add more logic to them, like a fix for #389.

I think we would agree that Zinc is more similar to Scalac than to that benchmark. It is reasonable to think @inline here is beneficial, given how beneficial it is for the Scala compiler. If you want to keep having this discussion, I suggest you have it with the Scala team. They will give you better insights than I will.

That being said, it would be good that you comment on the core issue that this patch is addressing.

Copy link
Member Author

Choose a reason for hiding this comment

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

That's cool. Can you LGTM and we merge?

Copy link
Member

Choose a reason for hiding this comment

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

I'd like to get Scala team's opinion as you suggested in terms of:

  1. If it's effective to add @inline in non-optimized code, and
  2. If it's safe to call reflection like f.getGenericType from an inline. The one-argument Class.forName must never be inlined scala/bug#6789 for example says "The one-argument Class.forName must never be inlined"

Copy link
Member Author

@jvican jvican Aug 11, 2017

Choose a reason for hiding this comment

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

Wrt the first question, we can merge this and address that doubt later on. I don't think it's a blocker.

Wrt your second question, it is safe to inline f.getGenericType. The reason why you cannot inline Class.forName is because this.getClass.getClassLoader or its absence has semantics that depends on the call-site (via stack inspection). This is absolutely not the case for these methods, that rely uniquely on the reflection API and don't take any class loader as parameter.

Copy link
Contributor

Choose a reason for hiding this comment

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

Inlining getGenericType is probably safe, scala/bug#6789 a special case for forName. Note that, since 2.12.3, you have to be explicit in telling the inliner where it's allowed to inline from (scala/scala#5964).

Inlining from the JDK is probably not a good idea in general as the bytecode potentially becomes non-portable. There might be licensing issues too. Maybe that's not a problem here because that code is only compiled locally for every user and never distributed in binary.

@inline is not a hint to the heuristic, but it makes the optimizer inline unconditionally (if the method can be inlined). The heuristic applies for every method invocation.

Marking small forwarder methods @inline is usually not beneficial, the JVM handles small monomorphic methods just fine. The only potential issue with many small methods on a hot path is that they consume from the -XX:MaxInlineLevel budget.

Inlining in Scala has benefits when it can make the code easier for the VM to optimize, in particular when callsites become monomorphic or escape analysis / stack allocation starts working.

it's a good practice to use @inline where applicable

I don't agree here. For small methods like here there's no gain. For bigger methods, there's a risk of slowdown due to code size. Good practice is to use the annotation where performance benefits are measured (or known).

I once made a small experiment and removed all @inline annotations from the Scala compiler, and performance didn't change. It might be different now, we'd have to do it again. But I think the heuristics cover the main cases. As another data point, there's a stress test mode in the optimizer -Yopt-inline-heuristics:everything. If you build a compiler with that, it runs 2x slower.

In general when working on JVM performance optimization, measuring is really important. More often than not, just reasoning about it leads to changes that don't improve or even hurt performance - there are just too many factors in play.

Copy link
Contributor

Choose a reason for hiding this comment

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

Inlining from the JDK is probably not a good idea

Oh, I got this wrong, there's no inlining from the JDK here.

@dwijnand dwijnand changed the base branch from 1.0.0 to 1.x August 14, 2017 15:52
@dwijnand dwijnand modified the milestones: 1.0.1, 1.1.0 Sep 27, 2017
@jvican jvican force-pushed the classapi-improvements branch from 7ecc5df to a0e4460 Compare September 28, 2017 22:17
@jvican
Copy link
Member Author

jvican commented Sep 28, 2017

This PR has been updated and can be reviewed.

eed3si9n
eed3si9n previously approved these changes Sep 28, 2017
Copy link
Member

@eed3si9n eed3si9n left a comment

Choose a reason for hiding this comment

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

LGTM pending CI

The workarounds are not necessary anymore,
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6476261 has been
fixed in JDK8, which is the JDK version that Zinc demands.
@jvican
Copy link
Member Author

jvican commented Sep 28, 2017

Merging as code hasn't changed since last approval.

@jvican jvican merged commit 8c4b996 into sbt:1.x Sep 28, 2017
dwijnand added a commit to dwijnand/zinc that referenced this pull request Nov 22, 2017
* 1.0.x: (25 commits)
  Add yourkit acknoledgement in the README
  Add header to cached hashing spec
  Add headers to missing files
  Fix sbt#332: Add sbt-header back to the build
  Update sbt-scalafmt to 1.12
  Make classpath hashing more lightweight
  Fix sbt#442: Name hash of value class should include underlying type
  source-dependencies/value-class-underlying: fix test
  Ignore null in generic lambda tparams
  Improve and make scripted parallel
  Fix sbt#436: Remove annoying log4j scripted exception
  Fix sbt#127: Use `unexpanded` name instead of `name`
  Add pending test case for issue/127
  source-dependencies / patMat-scope workaround
  Fixes undercompilation on inheritance on same source
  Add real reproduction case for sbt#417
  Add trait-trait-212 for Scala 2.12.3
  Fix source-dependencies/sealed
  Import statement no longer needed
  Move mima exclusions to its own file
  ...

 Conflicts:
	internal/zinc-apiinfo/src/main/scala/sbt/internal/inc/ClassToAPI.scala
	zinc/src/main/scala/sbt/internal/inc/MixedAnalyzingCompiler.scala

The ClassToAPI conflict is due to:
* sbt#393 (a 1.x PR), conflicting with
* sbt#446 (a 1.0.x PR).

The MixedAnalyzingCompiler conflict is due to:
* sbt#427 (a 1.x PR), conflicting with
* sbt#452 (a 1.0.x PR).
@dwijnand dwijnand mentioned this pull request Nov 22, 2017
dwijnand added a commit to dwijnand/zinc that referenced this pull request Nov 23, 2017
* 1.0.x: (28 commits)
  Split compiler bridge tests to another subproject
  Implement compiler bridge for 2.13.0-M2
  Add yourkit acknoledgement in the README
  "sbt '++ 2.13.0-M2!' compile" does not work with sbt 1.0.0
  Add header to cached hashing spec
  Add headers to missing files
  Fix sbt#332: Add sbt-header back to the build
  Update sbt-scalafmt to 1.12
  Make classpath hashing more lightweight
  Fix sbt#442: Name hash of value class should include underlying type
  source-dependencies/value-class-underlying: fix test
  Ignore null in generic lambda tparams
  Improve and make scripted parallel
  Fix sbt#436: Remove annoying log4j scripted exception
  Fix sbt#127: Use `unexpanded` name instead of `name`
  Add pending test case for issue/127
  source-dependencies / patMat-scope workaround
  Fixes undercompilation on inheritance on same source
  Add real reproduction case for sbt#417
  Add trait-trait-212 for Scala 2.12.3
  ...

 Conflicts:
	internal/zinc-apiinfo/src/main/scala/sbt/internal/inc/ClassToAPI.scala
	project/build.properties
	zinc/src/main/scala/sbt/internal/inc/MixedAnalyzingCompiler.scala

The ClassToAPI conflict is due to:
* sbt#393 (a 1.x PR), conflicting with
* sbt#446 (a 1.0.x PR).

The build.properties conflict is due to different PRs bumping
sbt.version from 1.0.0 to 1.0.2 to 1.0.3. (sbt#413, sbt#418, sbt#453).

The MixedAnalyzingCompiler conflict is due to:
* sbt#427 (a 1.x PR), conflicting with
* sbt#452 (a 1.0.x PR).
eed3si9n pushed a commit to scala/compiler-interface that referenced this pull request Apr 23, 2019
* 1.0.x: (28 commits)
  Split compiler bridge tests to another subproject
  Implement compiler bridge for 2.13.0-M2
  Add yourkit acknoledgement in the README
  "sbt '++ 2.13.0-M2!' compile" does not work with sbt 1.0.0
  Add header to cached hashing spec
  Add headers to missing files
  Fix #332: Add sbt-header back to the build
  Update sbt-scalafmt to 1.12
  Make classpath hashing more lightweight
  Fix #442: Name hash of value class should include underlying type
  source-dependencies/value-class-underlying: fix test
  Ignore null in generic lambda tparams
  Improve and make scripted parallel
  Fix #436: Remove annoying log4j scripted exception
  Fix #127: Use `unexpanded` name instead of `name`
  Add pending test case for issue/127
  source-dependencies / patMat-scope workaround
  Fixes undercompilation on inheritance on same source
  Add real reproduction case for sbt/zinc#417
  Add trait-trait-212 for Scala 2.12.3
  ...

 Conflicts:
	internal/zinc-apiinfo/src/main/scala/sbt/internal/inc/ClassToAPI.scala
	project/build.properties
	zinc/src/main/scala/sbt/internal/inc/MixedAnalyzingCompiler.scala

The ClassToAPI conflict is due to:
* sbt/zinc#393 (a 1.x PR), conflicting with
* sbt/zinc#446 (a 1.0.x PR).

The build.properties conflict is due to different PRs bumping
sbt.version from 1.0.0 to 1.0.2 to 1.0.3. (#413, #418, #453).

The MixedAnalyzingCompiler conflict is due to:
* sbt/zinc#427 (a 1.x PR), conflicting with
* sbt/zinc#452 (a 1.0.x PR).
dwijnand added a commit to dwijnand/sbt that referenced this pull request Apr 25, 2019
* 1.0.x: (28 commits)
  Split compiler bridge tests to another subproject
  Implement compiler bridge for 2.13.0-M2
  Add yourkit acknoledgement in the README
  "sbt '++ 2.13.0-M2!' compile" does not work with sbt 1.0.0
  Add header to cached hashing spec
  Add headers to missing files
  Fix sbt#332: Add sbt-header back to the build
  Update sbt-scalafmt to 1.12
  Make classpath hashing more lightweight
  Fix sbt#442: Name hash of value class should include underlying type
  source-dependencies/value-class-underlying: fix test
  Ignore null in generic lambda tparams
  Improve and make scripted parallel
  Fix sbt#436: Remove annoying log4j scripted exception
  Fix sbt#127: Use `unexpanded` name instead of `name`
  Add pending test case for issue/127
  source-dependencies / patMat-scope workaround
  Fixes undercompilation on inheritance on same source
  Add real reproduction case for sbt/zinc#417
  Add trait-trait-212 for Scala 2.12.3
  ...

 Conflicts:
	internal/zinc-apiinfo/src/main/scala/sbt/internal/inc/ClassToAPI.scala
	project/build.properties
	zinc/src/main/scala/sbt/internal/inc/MixedAnalyzingCompiler.scala

The ClassToAPI conflict is due to:
* sbt/zinc#393 (a 1.x PR), conflicting with
* sbt/zinc#446 (a 1.0.x PR).

The build.properties conflict is due to different PRs bumping
sbt.version from 1.0.0 to 1.0.2 to 1.0.3. (sbt#413, sbt#418, sbt#453).

The MixedAnalyzingCompiler conflict is due to:
* sbt/zinc#427 (a 1.x PR), conflicting with
* sbt/zinc#452 (a 1.0.x PR).
eed3si9n pushed a commit to eed3si9n/scala that referenced this pull request May 14, 2019
* 1.0.x: (28 commits)
  Split compiler bridge tests to another subproject
  Implement compiler bridge for 2.13.0-M2
  Add yourkit acknoledgement in the README
  "sbt '++ 2.13.0-M2!' compile" does not work with sbt 1.0.0
  Add header to cached hashing spec
  Add headers to missing files
  Fix scala#332: Add sbt-header back to the build
  Update sbt-scalafmt to 1.12
  Make classpath hashing more lightweight
  Fix scala#442: Name hash of value class should include underlying type
  source-dependencies/value-class-underlying: fix test
  Ignore null in generic lambda tparams
  Improve and make scripted parallel
  Fix scala#436: Remove annoying log4j scripted exception
  Fix scala#127: Use `unexpanded` name instead of `name`
  Add pending test case for issue/127
  source-dependencies / patMat-scope workaround
  Fixes undercompilation on inheritance on same source
  Add real reproduction case for sbt/zinc#417
  Add trait-trait-212 for Scala 2.12.3
  ...

 Conflicts:
	internal/zinc-apiinfo/src/main/scala/sbt/internal/inc/ClassToAPI.scala
	project/build.properties
	zinc/src/main/scala/sbt/internal/inc/MixedAnalyzingCompiler.scala

The ClassToAPI conflict is due to:
* sbt/zinc#393 (a 1.x PR), conflicting with
* sbt/zinc#446 (a 1.0.x PR).

The build.properties conflict is due to different PRs bumping
sbt.version from 1.0.0 to 1.0.2 to 1.0.3. (scala#413, scala#418, scala#453).

The MixedAnalyzingCompiler conflict is due to:
* sbt/zinc#427 (a 1.x PR), conflicting with
* sbt/zinc#452 (a 1.0.x PR).
lrytz pushed a commit to lrytz/scala that referenced this pull request Nov 5, 2019
* 1.0.x: (28 commits)
  Split compiler bridge tests to another subproject
  Implement compiler bridge for 2.13.0-M2
  Add yourkit acknoledgement in the README
  "sbt '++ 2.13.0-M2!' compile" does not work with sbt 1.0.0
  Add header to cached hashing spec
  Add headers to missing files
  Fix scala#332: Add sbt-header back to the build
  Update sbt-scalafmt to 1.12
  Make classpath hashing more lightweight
  Fix scala#442: Name hash of value class should include underlying type
  source-dependencies/value-class-underlying: fix test
  Ignore null in generic lambda tparams
  Improve and make scripted parallel
  Fix scala#436: Remove annoying log4j scripted exception
  Fix scala#127: Use `unexpanded` name instead of `name`
  Add pending test case for issue/127
  source-dependencies / patMat-scope workaround
  Fixes undercompilation on inheritance on same source
  Add real reproduction case for sbt/zinc#417
  Add trait-trait-212 for Scala 2.12.3
  ...

 Conflicts:
	internal/zinc-apiinfo/src/main/scala/sbt/internal/inc/ClassToAPI.scala
	project/build.properties
	zinc/src/main/scala/sbt/internal/inc/MixedAnalyzingCompiler.scala

The ClassToAPI conflict is due to:
* sbt/zinc#393 (a 1.x PR), conflicting with
* sbt/zinc#446 (a 1.0.x PR).

The build.properties conflict is due to different PRs bumping
sbt.version from 1.0.0 to 1.0.2 to 1.0.3. (scala#413, scala#418, scala#453).

The MixedAnalyzingCompiler conflict is due to:
* sbt/zinc#427 (a 1.x PR), conflicting with
* sbt/zinc#452 (a 1.0.x PR).

Rewritten from sbt/zinc@e245d95
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants