RFR JDK-6321472: Add CRC-32C API

Stanimir Simeonoff stanimir at riflexo.com
Fri Oct 17 18:44:49 UTC 2014


Actually I was under the impression I had included the list. Getting it
done w now.

Overall if you want speed you go unsafe (bit sad) as the JIT may not remove
the bound checks off the ByteBuffer. Unsafe is pretty ugly overall, though
and personally I try to avoid it giving up performance.

On 64bit machines you might be better off with java.nio.LongBuffer instead.

Stanimir


On Fri, Oct 17, 2014 at 9:06 PM, Staffan Friberg <staffan.friberg at oracle.com
> wrote:

>  Hi Stanimir,
>
> Thanks for you idea, do you mind re-replying with reply all so it goes to
> the list? Or I can simply reply to myself and include your comment.
>
> I forgot to add in my previous email that one of the follow up items for
> this will be to implement intrinsics that uses available hardware
> instructions, having a method that takes the buffer address will make that
> much easier which is another reason to stay with the current implementation.
>
> Thanks,
> Staffan
>
>
> On 10/17/2014 10:06 AM, Stanimir Simeonoff wrote:
>
>   Hi Staffan
>
>  The actual "trick" is using ByteBuffer.asIntBuffer() while the address is
> properly aligned. It's not the most intuitive approach but you get the read
> stuff.
>
>  Cheers
>  Stanimir
>
>
> On Fri, Oct 17, 2014 at 7:47 PM, Staffan Friberg <
> staffan.friberg at oracle.com> wrote:
>
>>  On 10/17/2014 01:46 AM, Peter Levart wrote:
>>
>>>
>>> On 10/17/2014 03:42 AM, Staffan Friberg wrote:
>>>
>>>> Hi,
>>>>
>>>> This RFE adds a CRC-32C class. It implements Checksum so it will have
>>>> the same API CRC-32, but use a different polynomial when calculating the
>>>> CRC checksum.
>>>>
>>>> CRC-32C implementation uses slicing-by-8 to achieve high performance
>>>> when calculating the CRC value.
>>>>
>>>> A part from adding the new class, java.util.zip.CRC32C, I have also
>>>> added two default methods to Checksum. These are methods that were added to
>>>> Adler32 and CRC32 in JDK 8 but before default methods were added, which was
>>>> why they were only added to the implementors and not the interface.
>>>>
>>>> Bug: https://bugs.openjdk.java.net/browse/JDK-6321472
>>>> Webrev: http://cr.openjdk.java.net/~sfriberg/JDK-6321472/webrev.00
>>>>
>>>> I have started a CCC request for the changes, but was asked to get
>>>> feedback from the core libs group before finalizing the request in case
>>>> there are any API or Javadoc changes suggested.
>>>>
>>>> Thanks,
>>>> Staffan
>>>>
>>>
>>> Hi Staffan,
>>>
>>> I can see CRC32C.reflect(int) method reverses the bits in 32 bit int
>>> value. You could use Integer.reverse(int) instead.
>>>
>>> The CRC32C.swap32(int) method is (almost) exactly the same as
>>> Integer.reverseBytes(int) and equivalent.
>>>
>>> I wonder if handling ByteBuffer could be simplified. You could leverage
>>> it's own byte order manipulation by temporarily setting (and resetting
>>> afterwards) ByteBuffer.order() and then use ByteBuffer.getInt() to extract
>>> 32 bits at a time for your algorithm. This could get you the optimal
>>> variant of algorithm for both kinds of buffers (direct or byte[] based).
>>> Perhaps even the byte[] based variant of algorithm could be implemented by
>>> wrapping the array with ByteBuffer, passing it to common private method,
>>> and relying on the escape analysis of Hotspot to allocate the
>>> HeapByteBuffer wrapper object on stack.
>>>
>>> Regards, Peter
>>>
>>>   Hi Peter,
>>
>> Thanks for reviewing.
>>
>> I have switched to the Integer methods. Was looking through that API but
>> I was too stuck with the reflect and swap names so I missed the reverse
>> methods... :)
>>
>> As Vitaly noted in his email the wrapped case runs much slower. Going
>> through the generated code it looks like the getInt method actually read
>> four bytes and then builds and int from them, unless we have some intrinsic
>> replacing that code.
>>
>> Bits.java
>>     static int getIntL(long a) {
>>         return makeInt(_get(a + 3),
>>                        _get(a + 2),
>>                        _get(a + 1),
>>                        _get(a    ));
>>     }
>>
>>     static private int makeInt(byte b3, byte b2, byte b1, byte b0) {
>>         return (((b3       ) << 24) |
>>                 ((b2 & 0xff) << 16) |
>>                 ((b1 & 0xff) <<  8) |
>>                 ((b0 & 0xff)      ));
>>     }
>>
>> It looks like the same holds true for DirectByteBuffers unless you are on
>> x86 which supports unaligned reads. So I think aligning and using Unsafe is
>> the best option here for performance.
>>
>> DirectByteBuffer.java
>>     private int getInt(long a) {
>>         if (unaligned) {
>>             int x = unsafe.getInt(a);
>>             return (nativeByteOrder ? x : Bits.swap(x));
>>         }
>>         return Bits.getInt(a, bigEndian);
>>     }
>>
>> Bits.java
>>     static boolean unaligned() {
>>         if (unalignedKnown)
>>             return unaligned;
>>         String arch = AccessController.doPrivileged(
>>             new sun.security.action.GetPropertyAction("os.arch"));
>>         unaligned = arch.equals("i386") || arch.equals("x86")
>>             || arch.equals("amd64") || arch.equals("x86_64");
>>         unalignedKnown = true;
>>         return unaligned;
>>     }
>>
>> Regards,
>> Staffan
>>
>
>
>



More information about the core-libs-dev mailing list