RFR JDK-8164278: java.util.Base64.EncOutputStream/DecInputStream is slower than corresponding version in javax.mail package

Roger Riggs Roger.Riggs at Oracle.com
Wed Feb 14 18:08:12 UTC 2018

Hi Sherman,

I found updates in http://cr.openjdk.java.net/~sherman/8164278/webrev.04

That looks fine.

Typo:  line 1008: "neve"


On 2/7/2018 10:32 PM, Xueming Shen wrote:
> Hi Roger,
> Given the concern of the possible incompatible behavior change of over 
> reading bytes
> from the underlying stream. I decided to give up last proposed changes 
> for DecInputStream
> for now. With some "minor" cleanup and tuning I still have about 10%+ 
> improvement with
> various input size sampling. Let's address the decoder stream in 
> separate rfe later, if desired.
> The updated webrev and the jmh results are at
> http://cr.openjdk.java.net/~sherman/8164278/webrev
> http://cr.openjdk.java.net/~sherman/8164278/base64.bm
> Last version of webrev and corresponding jmh result can be found at
> http://cr.openjdk.java.net/~sherman/8164278/webrev.02
> http://cr.openjdk.java.net/~sherman/8164278/base64.bm.old
> Thanks,
> Sherman
> On 2/5/18, 6:00 PM, Xueming Shen wrote:
>> Hi,
>> Please help review the change for  JDK-8164278.
>> issue: https://bugs.openjdk.java.net/browse/JDK-8164278
>> webrev: http://cr.openjdk.java.net/~sherman/8164278/webrev
>> jmh.src: http://cr.openjdk.java.net/~sherman/8164278/Base64BM.java
>> jmh.result: http://cr.openjdk.java.net/~sherman/8164278/base64.bm
>> Base64.Decoder.decode0:
>>     Adopted the "similar" optimization approach we took in 
>> Base64.Encoder.encode0()
>>     to add a "fast path" to decode a block of 4-byte units together 
>> (current implementation
>>     decodes one single byte per while/loop. The jmh benchmark result 
>> indicates a big speed
>>     boost  (those decodeArray/Mime/Url results, from 30% to 2 times 
>> faster, depends on
>>     input size).
>> Base64.Encoder.encode0()
>>     It appears encode0() was fully optimized in 1.8. Can't get it 
>> faster :-) Tried to use
>>     Unsafe.getLong/putLong instead of byte by byte access. But it 
>> appears the 8-byte
>>     "vectorization" does not bring us enough speed up, the 
>> performance is the same as the
>>     current one. See encode00() at
>>     http://cr.openjdk.java.net/~sherman/8164278/webrev.00
>> Base64.Encoder.wrap(OutputStream)/EncOutputStream.write():
>>     If my memory serves me right, the current implementation was 
>> under the assumption that
>>     the underlying output stream probably is buffered (if invoker 
>> cares). It would be a redundant
>>     if EncOutputStream buffers bytes again. It appears this is a 
>> wrong assumption. It is much
>>     slower to write 4 bytes separately, compared to bundle them 
>> together in a byte[4] and write
>>     into underlying, even the underlying output stream is a 
>> ByteArrayOutputStream.
>>     Again, the proposed change is to add a fast path loop, as we do 
>> in encode0(), to decode/
>>     write a block of 3-byte->4-byte unites. It appears this fast loop 
>> can help the compiler to
>>     optimize away some boundary checks, therefor is much faster.
>>     The jmh result Base64BM.encodeOS suggests the new implementation 
>> is almost 4 times faster
>>     and is almost the same as java.mail's stream encoder.
>> Base64.Decoder.wrap(InputStream)/DecInputStream.read():
>>     Same as the approach we take for decode0(), to add a fast path 
>> decode block of 4-byte unites
>>     together.
>>     The jmh result Base64BM.decodeOS (the name probably should be 
>> decodeIS, for InputStream,
>>     but anyway...) shows the proposed one is 4 times faster than the 
>> existing impl and double
>>     the  java.mail (Base64BM.decodeOS_javamail) implementation.
>>     However, there is a side-effect of adding a buffering mechanism 
>> into DecInputStream. The
>>     current implementation read bytes from the underlying stream one 
>> by one, it never reads
>>     more bytes than it needs, which means it should/is supposed to 
>> just stop at the last byte
>>     that it needs to decode, when there is "=" present in the stream.
>>     With buffering, it's possible more bytes (after "=", which 
>> indicates "end of base64 stream") might
>>     be read/consumed in and buffered.  A concern? if this is indeed a 
>> concern, the only alternative
>>     might be to add a separate method to support this 
>> "faster-buffered-decoder"?
>> Thanks,
>> Sherman

More information about the core-libs-dev mailing list