RFR JDK-6321472: Add CRC-32C API

Staffan Friberg staffan.friberg at oracle.com
Fri Oct 17 16:47:21 UTC 2014


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