Hi Martin!
On 2017-02-01 20:48, Martin Buchholz wrote:
I agree with the startup improvement goal.
The need to do:
+ case "ALPHA": return ALPHABETIC();
is pretty horrible (but we do worse in the name of performance). We'd
like to be able to simply do:
return Character::isAlphabetic;
but probably we're stymied by hotspot's eagerness being per-method, not
per-statement.
I'm not sure I agree it's *that* horrible, but maybe I've grown
accustomed to somewhat horrible code... :-)
And no, while hotspot might the bytecode for a method eagerly, I'm
pretty sure the bootstrap method, which does the actual lambda
initialization and replace the instruction at the callsite, is not run
until executing the statement.
So, while I guess we could write "case "ALPHA": return
Character::isAlphabetic;" and get the same net result, I haven't
checked if that means we'd go through the hoop of spinning up that call
site at each location (ending up with the same thing) or if javac helps
ensure it'll be done at most once here.
As tests have been thoroughly run on this and time is running out,
I'd prefer contemplating cleaner/nicer ways of writing this particular
patch for 10 if you don't mind.
Is the long-term solution to make hotspot's lambda initialization even lazier?
I guess it'd be interesting to try make lambdas like these (which
aren't used just after initialization) even lazier by emitting, say,
some thin MutableCallSite that defers real initialization to first use,
but not sure if feasible or if it'd even pay off except for cases like
these where you generate a lot of lambdas / method references but don't
use them right away. I'm sure others have thought more about this than
me.
Somewhat orthogonally I do have plans to continue work on the static
pre-generation jlink plugin I introduced as part of 8086045, along with
other micro-optimizations to the involved java.lang.invoke code. This
helps make each call site lighter to spin up.
AOT might help, too, but stumbles once we actually have to generate a
new class dynamically, so it's not competing with the things we can
do with jlink currently...
All in all I'm sure we can inch closer and closer to negligible startup
overhead given time and dedication.
/Claes
On Wed, Feb 1, 2017 at 9:00 AM, Claes Redestad
<[email protected] <mailto:[email protected]>> wrote:
Hi,
changes to java.util.regex in 9+119 has been cause for a number of
startup
regressions due to early use of lambdas, which has both helped motivate
work to reduce the overall cost of lambda initialization[1], while
in other
cases the use of regexes could be reconsidered (VersionProps).
While this work and workarounds has helped a lot, the changes to
java.util.regex can still be the cause of noticeable regressions[2] when
using regular expressions that depend on predicates defined in
java.util.regex.CharPredicate, simply because of how this class eagerly
creates a substantial amount of lambdas during clinit.
This patch makes the initialization lazy, which improves startup metrics
without affecting performance of regular use.
Bug: https://bugs.openjdk.java.net/browse/JDK-8160302
<https://bugs.openjdk.java.net/browse/JDK-8160302>
Webrev: http://cr.openjdk.java.net/~redestad/8160302/webrev.01/
<http://cr.openjdk.java.net/~redestad/8160302/webrev.01/>
Thanks!
/Claes
PS. Yes, I know final is redundant on static methods, and realized I
forgot
to remove them after turning constants into methods, but looking at
again
it seems there's a convention of defining static methods final in
this code
already, so unless there is a lot of outrage I'd like to defer
cleaning up this
particular bikeshed.
[1] https://bugs.openjdk.java.net/browse/JDK-8086045
<https://bugs.openjdk.java.net/browse/JDK-8086045>
[2] 12-15ms startup regressions due to generating and loading up to 60
loaded classes, more early JIT compilations etc..