On Fri, 30 Aug 2024 19:39:32 GMT, Shaojin Wen <s...@openjdk.org> wrote:

>> Use fast path for ascii characters 1 to 127 to improve the performance of 
>> writing Utf8Entry to BufferWriter.
>
> Shaojin Wen has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   optimize Utf8EntryImpl#writeTo(UTF)

So this small win now comes from reserving space up front (possibly excessively 
so) and writing directly to the byte-array, avoiding excessive `reserveSpace` 
calls - right? A bit underwhelming, maybe.

I also think there's a pre-existing bug here: the max length _in bytes_ of a 
UTF-8 classfile entry is 65535, but we're checking `s.length() < 65535` (which 
is only correct if the string is ascii). Perhaps this code need to do what 
`DataOutputStream.writeUTF(String)` does and calculate the length in bytes up 
front.

Did you profile the microbenchmark to see that the `Utf8EntryImpl#writeTo` is 
actually a bottleneck in this test? I took a peek and it seems to be doing 
mostly other things, and when I've run this test a few times it seems there's 
quite a bit of run-to-run variance. I think we need a more focused 
microbenchmark to say anything about the writeUTF method.

A quick, easy and portable profiling technique that doesn't depend on any 
external tools: `make test TEST="micro:Utf8EntryWriteTo" MICRO="OPTIONS=-p 
charType=ascii -f 1 -i 50 -prof jfr"` (bumping -i to get enough samples, -f 1 
since the test runner would overwrite recordings from multiple forks). 

The run will just take a recording and print something like:

JFR profiler results:
  
<path>/org.openjdk.bench.java.lang.classfile.Utf8EntryWriteTo.writeTo-AverageTime-charType-ascii/profile.jfr


Then use JMC or the built-in jfr tool to inspect the recording. E.g. 
`build/<arch>/images/jdk/bin/jfr view hot-methods 
<path>/org.openjdk.bench.java.lang.classfile.Utf8EntryWriteTo.writeTo-AverageTime-charType-ascii//profile.jfr`
 is quite useful:

                                          Java Methods that Executes the Most

Method                                                                          
                        Samples Percent
-------------------------------------------------------------------------------------------------------
 ------- -------
jdk.internal.classfile.impl.SplitConstantPool.entryByIndex(int)                 
                            280   8,03%
jdk.internal.classfile.impl.RawBytecodeHelper.rawNext()                         
                            263   7,54%
jdk.internal.util.ArraysSupport.unsignedHashCode(int, byte[], int, int)         
                            215   6,17%
jdk.internal.classfile.impl.EntryMap.firstToken(int)                            
                            210   6,02%
jdk.internal.classfile.impl.StackMapGenerator.detectFrameOffsets()              
                            165   4,73%
java.lang.String.equals(Object)                                                 
                            165   4,73%
jdk.internal.classfile.impl.SplitConstantPool.findEntry(int, AbstractPoolEntry, 
AbstractPoolEntry)          109   3,13%
jdk.internal.classfile.impl.SplitConstantPool.findEntry(int, AbstractPoolEntry) 
                            104   2,98%
jdk.internal.classfile.impl.StackMapGenerator.processMethod()                   
                             85   2,44%
java.lang.classfile.constantpool.ConstantPoolBuilder.nameAndTypeEntry(String, 
MethodTypeDesc)                83   2,38%
java.lang.String.<init>(byte[], byte)                                           
                             76   2,18%
jdk.internal.classfile.impl.SplitConstantPool.map()                             
                             72   2,07%
jdk.internal.classfile.impl.BufWriterImpl.reserveSpace(int)                     
                             69   1,98%
jdk.internal.classfile.impl.AbstractPoolEntry$Utf8EntryImpl.toString()          
                             64   1,84%
jdk.internal.classfile.impl.SplitConstantPool.tryFindUtf8(int, String)          
                             63   1,81%
jdk.internal.classfile.impl.StackMapGenerator.processInvokeInstructions(...)    
                             57   1,64%
java.nio.Buffer.checkIndex(int)                                                 
                             54   1,55%
java.lang.classfile.constantpool.ConstantPoolBuilder.classEntry(ClassDesc)      
                             53   1,52%
jdk.internal.classfile.impl.SplitConstantPool$2.fetchElement(int)               
                             52   1,49%
jdk.internal.classfile.impl.AbstractPoolEntry$Utf8EntryImpl.hashCode()          
                             49   1,41%
java.lang.classfile.CodeBuilder.invoke(Opcode, ClassDesc, String, 
MethodTypeDesc, boolean)                   48   1,38%
jdk.internal.classfile.impl.AbstractPoolEntry.maybeClone(ConstantPoolBuilder, 
PoolEntry)                     46   1,32%
jdk.internal.classfile.impl.SplitConstantPool.maybeCloneUtf8Entry(Utf8Entry)    
                             45   1,29%
jdk.internal.classfile.impl.StackMapGenerator.processBlock(RawBytecodeHelper)   
                             40   1,15%
java.util.Arrays.copyOfRange(byte[], int, int)                                  
                             40   1,15%```

-------------

PR Comment: https://git.openjdk.org/jdk/pull/20772#issuecomment-2322975213
PR Comment: https://git.openjdk.org/jdk/pull/20772#issuecomment-2323337370

Reply via email to