RFR: 8338532: Speed up the ClassFile API MethodTypeDesc#ofDescriptor
Claes Redestad
redestad at openjdk.org
Mon Aug 19 06:32:25 UTC 2024
On Sun, 18 Aug 2024 23:04:33 GMT, Shaojin Wen <duke at openjdk.org> wrote:
>> Right, which is why we need to balance these microbenchmark speed-ups against any added static footprint and other factors. Going through fewer but less specialized methods can reduce runtime footprint and lead to quicker warmup, for example. Also, @liach pointed out elsewhere the we might be able to avoid many of these `ofDescriptor` calls with optimizations elsewhere, so perhaps let's not go overboard here and re-measure with those optimizations in place as it might make this work less impactful.
>>
>> On a related note: Running micros with `-Xint` and `-XX:TieredStopAtLevel=1` can help indicate whether some optimization will be helpful during startup or not. Often things align well, but sometimes optimizations that help peak performance make interpreted performance worse, and vice versa.
>>
>> If we're optimizing for startup the best is obviously to check on some startup benchmark of choice. A recent example (on Linux): `perf stat -r 50 java -jar benchmarks.jar org.openjdk.bench.java.lang.StringConcatStartup` or simply `make test TEST=micro:StringConcatStartup`
>>
>> FWIW I use this technique all the time to diagnose what we're doing during startup: https://cl4es.github.io/2018/11/23/Investigating-Startup-Using-Bytestacks.html - it has helped me find numerous candidates for startup optimization. Main reason I'm insisting on adding a main method to startup-centric JMH benchmarks.
>
> All calls to ofDescriptor during the startup process come from here, which cannot be avoided in a simple way.
>
>
> at java.base/jdk.internal.constant.MethodTypeDescImpl.ofDescriptor(MethodTypeDescImpl.java:142)
> at java.base/java.lang.constant.MethodTypeDesc.ofDescriptor(MethodTypeDesc.java:60)
> at java.base/jdk.internal.classfile.impl.DirectMethodBuilder.methodTypeSymbol(DirectMethodBuilder.java:88)
> at java.base/jdk.internal.classfile.impl.TerminalCodeBuilder.setupTopLocal(TerminalCodeBuilder.java:36)
> at java.base/jdk.internal.classfile.impl.DirectCodeBuilder.<init>(DirectCodeBuilder.java:133)
> at java.base/jdk.internal.classfile.impl.DirectCodeBuilder.build(DirectCodeBuilder.java:106)
> at java.base/jdk.internal.classfile.impl.DirectMethodBuilder.withCode(DirectMethodBuilder.java:123)
> at java.base/jdk.internal.classfile.impl.DirectMethodBuilder.withCode(DirectMethodBuilder.java:130)
> at java.base/java.lang.invoke.InvokerBytecodeGenerator$5.accept(InvokerBytecodeGenerator.java:589)
> at java.base/java.lang.invoke.InvokerBytecodeGenerator$5.accept(InvokerBytecodeGenerator.java:567)
> at java.base/jdk.internal.classfile.impl.DirectMethodBuilder.run(DirectMethodBuilder.java:144)
> at java.base/jdk.internal.classfile.impl.DirectClassBuilder.withMethod(DirectClassBuilder.java:106)
> at java.base/java.lang.classfile.ClassBuilder.withMethod(ClassBuilder.java:260)
> at java.base/java.lang.invoke.InvokerBytecodeGenerator.methodSetup(InvokerBytecodeGenerator.java:292)
> at java.base/java.lang.invoke.InvokerBytecodeGenerator.addMethod(InvokerBytecodeGenerator.java:567)
> at java.base/java.lang.invoke.InvokerBytecodeGenerator$4.accept(InvokerBytecodeGenerator.java:558)
> at java.base/java.lang.invoke.InvokerBytecodeGenerator$4.accept(InvokerBytecodeGenerator.java:555)
> at java.base/java.lang.invoke.InvokerBytecodeGenerator$2.accept(InvokerBytecodeGenerator.java:282)
> at java.base/java.lang.invoke.InvokerBytecodeGenerator$2.accept(InvokerBytecodeGenerator.java:276)
> at java.base/jdk.internal.classfile.impl.ClassFileImpl.build(ClassFileImpl.java:113)
> at java.base/java.lang.classfile.ClassFile.build(ClassFile.java:332)
> at java.base/java.lang.invoke.InvokerBytecodeGenerator.classFileSetup(InvokerBytecodeGenerator.java:276)
> at java.base/java.lang.invoke.InvokerBytecodeGenerator.generateCustomizedCodeBytes(InvokerBytecodeGenerator.java:555)
> at java.base/java.lang.invoke.InvokerBytecodeGenerator.generateCustomizedCode(InvokerBytecodeGenerator.java:533)
> at java.base/java.lang.i...
Hmm, based on your stacktrace I think you are running the exploded image in `build/<arch>/jdk` instead of from a final image, e.g. the one that `make jdk-image` produces in `build/<arch>/images/jdk` - the former will do a lot more stuff during startup, while the latter applies numerous link-time optimizations to reduce lambda and method handle spinning on startup. While speeding up the exploded image is a nice bonus, the runtime images should be the focus of startup optimization work.
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/20611#discussion_r1721090415
More information about the core-libs-dev
mailing list