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

New setting -opt-inline-from to control where to inline from #5964

Merged
merged 5 commits into from Jul 3, 2017

Conversation

lrytz
Copy link
Member

@lrytz lrytz commented Jun 27, 2017

Deprecates -opt:l:classpath and -opt:l:project, introduces -opt:l:inline which enables cross-method optimizations. The inliner will only inline code from classes listed in -opt-inline-from, which is empty by default. So specifying only -opt:l:inline actually doesn't enable any inlining.

Proposed syntax for -opt-inline-from:

  • slices of qualified class names: List, scala.collection.List, collection.mutable, etc
  • *: longest match of identifier parts (not .)
  • **: longest match of anything
  • <sources>: allows inlining from classes being compiled in the current compilation run (implemented in a follow-up PR -opt-inline-from:<sources> to allow inlining from compilation units #5989)
  • leading ! to make a rule excluding

Examples

* classes in the empty package
scala.* classes in package scala, including the package object (scala.package$)
** any class
scala.collection.** classes in package scala.collection, or any sub-package
com.corp.**.util.* classes in a util package below com.corp, including com.corp.util.Foo
**.Util classes named Util in any package, including _root_.Util
**.*Util* classes containing Util

There's a special case to make .**. match ., so a.**.b.C matches a.b.C. Similarly, **.A matches A.

Note that we're talking about classfile names here, so a nested class foo.C#D would be foo.C$D, a module class is scala.Predef$.

More examples:

  • scalac -opt:l:inline -opt-inline-from:scala.**:com.corp.**: white-listing is recommended, because
  • Trying to exclude everything from rt.jar is not easy (and also platform-dependent)! The following is just a start, there are many more packages: **:!java.**:!javax.**:!jdk.**:!apple.**:!com.apple.**:!com.oracle.**:!com.sun.**:...
  • **:!foo.**:foo.util.**: the last matching rule counts.

Fixes scala/scala-dev#148

@scala-jenkins scala-jenkins added this to the 2.12.3 milestone Jun 27, 2017
@lrytz
Copy link
Member Author

lrytz commented Jun 27, 2017

Feedback welcome!

Todo

  • jardiff, make sure the new inliner options work as intended for our own build
  • compilation tests with various -opt-inline-from patterns

@SethTisue SethTisue added the release-notes worth highlighting in next release notes label Jun 27, 2017
@retronym
Copy link
Member

Minor nice to have: use this new glob matcher for -Yopt-log-inline / -Yopt-trace.

@retronym
Copy link
Member

Typo in commit message of c616fcb

@retronym
Copy link
Member

The proposed matcher makes it possible to inadvertently inline from in a.b.c when asking for b.c. I think we should make users explicitly ask for wildcards in prefix position, so that only **.b.c would pull in both of those.

@lrytz
Copy link
Member Author

lrytz commented Jun 28, 2017

inadvertently inline from in a.b.c when asking for b.c

I don't see what you mean here, if you say b.c, it only inlines from class c in package b, nothing else. the current implementation is what you suggest, you need **.b.c to match both b.c and a.b.c.

@retronym
Copy link
Member

I must have misunderstood: "slices of qualified class names: List, scala.collection.List, collection.mutable, etc"

@lrytz
Copy link
Member Author

lrytz commented Jun 28, 2017

Oh, that's just defining what's valid syntax

@lrytz
Copy link
Member Author

lrytz commented Jun 28, 2017

One thing I don't like is that the description of the new setting is the longest, so it will wrap if the terminal windows is not very wide..

➜  sandbox git:(inline-from) qsc -help
Usage: scalac <options> <source files>
where possible standard options include:
  -Dproperty=value                     Pass -Dproperty=value directly to the runtime system.
...
  -opt-inline-from:<patterns>          Classfile name patterns from which to allow inlining. ** = anything, * = package or class name, ! to exclude. Example: scala.**:!scala.Predef$:corp.*.util.*:corp.**.*Util*
...
  -target:<target>                     Target platform for object files. All JVM 1.5 - 1.7 targets are deprecated. Choices: (jvm-1.5,jvm-1.6,jvm-1.7,jvm-1.8), default: jvm-1.8.

@retronym
Copy link
Member

We could hide the full description of the pattern behind -opt-inline-from:help, in the same vein as:

% scala -X 2>&1 | grep lint
  -Xlint:<_,warning,-warning>      Enable or disable specific warnings: `_' for all, `-Xlint:help' to list choices.

% scala -Xlint:help
Enable or disable specific warnings
  adapted-args               Warn if an argument list is modified to match the receiver.
  nullary-unit               Warn when nullary methods return Unit.
  inaccessible               Warn about inaccessible types in method signatures.
  nullary-override           Warn when non-nullary `def f()' overrides nullary `def f'.

@lrytz
Copy link
Member Author

lrytz commented Jun 28, 2017

yeah, that will require some work on the settings infra, StringSetting doesn't support help currently

"-opt-inline-from",
"patterns",
"Classfile name patterns from which to allow inlining. ** = anything, * = package or class name, ! to exclude. Example: scala.**:!scala.Predef$:corp.*.util.*:corp.**.*Util*",
"")
Copy link
Member

Choose a reason for hiding this comment

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

Perhaps this could be a MultiStringSetting to allow multiple -opt-inline-from entries on the command line to aggregate.

scaladoc -implicits-hide is an example of a similar part of the settings UI that goes that way.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm happy to do it either way, but I don't see a big advantage of switching to MultiStringSetting

Copy link
Member

@retronym retronym Jun 29, 2017

Choose a reason for hiding this comment

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

I think the use case is to make it easy to use some base set of compiler options (e.g shared between all subprojects), and then append an extra option for some specific subproject:

  scalacOptions in sub1 += List("-opt-inline-from", "...")

Without MultiStringSetting, I beleive you'd need to perform a more complicated merge:

scalacOptions = {
  val i = scalacOptions.value.indexOf("-opt-inline-from"
  if (i < 0) scalacOptions.value ++ List("-opt-inline-from", "...")
  else scalacOptions.value.patch(i, Nil, 2) ++ List("-opt-inline-from", scalacOptions.value(i + 1) + ",...") 

Copy link
Member Author

@lrytz lrytz Jun 29, 2017

Choose a reason for hiding this comment

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

OK, that's a good point, I'll change it. The potentially confusing thing about a MultiStringSetting is that if you're using it in the last position and not in "colonated" mode, it consumes the source files. For example:

➜  sandbox git:(inline-from) ✗ scaladoc -implicits-hide Foo Bar Test.scala
>> shows usage
➜  sandbox git:(inline-from) ✗ scaladoc -implicits-hide Foo Bar -d . Test.scala
>> runs scaladoc

Copy link
Member

Choose a reason for hiding this comment

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

Hmm, that's annoying. If you know about it, you can use -- to end the opton section and move into source files.

% scaladoc -implicits-hide foo bar -- /tmp/test.scala

And the help text also guides you towards the :.

  -implicits-hide:<implicit(s)>               Hide the members inherited by the given comma separated, fully qualified implicit conversions. Add dot (.) to include default conversions.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, I tried a single - as separator, but that didn't work. I'll make sure the help text recommends the colonated mode.

Introduce the optimizer level `-opt:l:inline` and a new setting
`-opt-inline-from` to control what classes we inline from.

`-opt:l:classpath` and `-opt:l:project` continue to work in the same
way, with a deprecation warning.
Allows StringSetting to be helping.
@lrytz
Copy link
Member Author

lrytz commented Jun 29, 2017

➜  sandbox git:(inline-from) qsc -help
...
  -opt-inline-from <patterns>          Patterns for classfile names from which to allow inlining, `help` for details.
...
➜  sandbox git:(inline-from) qsc -opt-inline-from help
Patterns for classfile names from which the inliner is allowed to pull in code.
  *              Matches classes in the empty package
  **             All classes
  a.C            Class a.C
  a.*            Classes in package a
  a.**           Classes in a and in sub-packages of a
  **.Util        Classes named Util in any package (including the empty package)
  a.**.*Util*    Classes in a and sub-packages with Util in their name (including a.Util)
  a.C$D          The nested class D defined in class a.C
  scala.Predef$  The scala.Predef object

The setting accepts a colon-separated list of patterns. A leading `!` marks a pattern excluding.
The last matching pattern defines whether a classfile is included or excluded (default: excluded).
For example, `a.**:!a.b.**` includes classes in a and sub-packages, but not in a.b and sub-packages.

Note: on the command-line you might need to quote patterns containing `*` to prevent the shell
from expanding it to a list of files in the current directory.
➜  sandbox git:(inline-from)

@lrytz
Copy link
Member Author

lrytz commented Jun 29, 2017

Jardiff: I created a locker from 0c51534 (the current tip of this PR). Then:

  • using -Dstarr.version=2.12.3-bin-2c50123 (the branch point of this PR, build from scala-integration) with -opt:l:classpath, built 2.12.3-bin-0c515344a5-quick-a
  • using -Dstarr.version=2.12.3-bin-0c515344a5-locker with Seq("-opt:l:inline", "-opt-inline-from", "scala/**"), built 2.12.3-bin-0c515344a5-quick-b
for l in library reflect compiler; do echo ">>> $l <<<"; jardiff /Users/luc/.ivy2/local/org.scala-lang/scala-$l/2.12.3-bin-0c515344a5-quick-a/jars/scala-$l.jar /Users/luc/.ivy2/local/org.scala-lang/scala-$l/2.12.3-bin-0c515344a5-quick-b/jars/scala-$l.jar; done

Result here: a number of methods from the rt.jar that are no longer inlined, for example java/util/Iterator.forEachRemaining.

I also compiled lib+reflect+compiler with -Yopt-log-inline _ -opt:l:inline -opt-inline-from 'scala/**' find ../src/library ../src/reflect ../src/compiler -name '*.scala' -d a and checked the output to make sure only code from scala/ is inlined.

For curiosity, here's a histogram of inlined methods: https://gist.github.com/lrytz/6f689a78e497e7ebed966be0bcb0a36f

@retronym
Copy link
Member

Jardiff: I created a locker from 0c51534 (the current tip of this PR). Then ...

FYI, I'm working on better automation for this sort of analysis

2.12.x...retronym:topic/jardiff

@lrytz
Copy link
Member Author

lrytz commented Jun 29, 2017

I think this is ready now.

@@ -254,7 +254,7 @@ trait ScalaSettings extends AbsScalaSettings

private val inlineChoices = List(lMethod, inline)
val lInline = Choice("l:inline",
"Enable cross-method optimizations: " + inlineChoices.mkString("", ",", "."),
"Enable cross-method optimizations (note: inlining requires -opt-inlnie-from): " + inlineChoices.mkString("", ",", "."),
Copy link
Member

Choose a reason for hiding this comment

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

typo here.

Just checking: do we inline unconditionally from sources in the current run, even without -opt-inlnie-from?

Pros: a convenient default without needing
Cons: instable results depending on separate compilation

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 prefer the stability over convenience, I think.

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree, and that's the current implementation. We could bring back the functionality of -opt:l:project with a special pattern in -opt-inline-from:...:<sources>:...

Allows passing the setting multiple times, which might be useful
for multi-project builds
@retronym retronym merged commit 343a199 into scala:2.12.x Jul 3, 2017
lrytz added a commit to lrytz/sbt-scala-module that referenced this pull request Jul 6, 2017
Move jvm-specific settings from scalaModuleSettings to a new
scalaModuleSettingsJVM setting. This means that JVM projects in
scala modules now have to add bot `scalaModuleSettings` and
`scalaModuleSettingsJVM`.

Adding sbt-osgi settings in a scala-js project caused the published
jar to be empty (scala/scala-parser-combinators#119).

Upgrades sbt-osgi to the latest version.

Also anticipates the new optimizer settings in 2.12.3
(scala/scala#5964).
lrytz added a commit to lrytz/sbt-scala-module that referenced this pull request Jul 6, 2017
Move jvm-specific settings from scalaModuleSettings to a new
scalaModuleSettingsJVM setting. This means that JVM projects in
scala modules now have to add bot `scalaModuleSettings` and
`scalaModuleSettingsJVM`.

Adding sbt-osgi settings in a scala-js project caused the published
jar to be empty (scala/scala-parser-combinators#119).

Upgrades sbt-osgi to the latest version.

Also anticipates the new optimizer settings in 2.12.3
(scala/scala#5964).
lrytz added a commit to lrytz/sbt-scala-module that referenced this pull request Jul 7, 2017
Move jvm-specific settings from scalaModuleSettings to a new
scalaModuleSettingsJVM setting. This means that JVM projects in
scala modules now have to add bot `scalaModuleSettings` and
`scalaModuleSettingsJVM`.

Adding sbt-osgi settings in a scala-js project caused the published
jar to be empty (scala/scala-parser-combinators#119).

Upgrades sbt-osgi to the latest version.

Also anticipates the new optimizer settings in 2.12.3
(scala/scala#5964).
@retronym retronym mentioned this pull request Jul 7, 2017
37 tasks
@lrytz lrytz deleted the inline-from branch July 20, 2017 14:27
eparejatobes added a commit to ohnosequences/stuff that referenced this pull request Aug 12, 2017
@er1c
Copy link
Contributor

er1c commented Oct 16, 2017

The scalac doc shows : as the delimiter, but I believe this was actually implemented with a , comma - is this difference being tracked somewhere?

@lrytz
Copy link
Member Author

lrytz commented Oct 17, 2017

Patterns are separated by :. There was a mistake in the PR description here, I fixed that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
release-notes worth highlighting in next release notes
Projects
None yet
5 participants