JDK-6277756 : (bf) reconsider Bits.JNI_COPY_FROM/TO_ARRAY_THRESHOLD values
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.nio
  • Affected Version: 5.0
  • Priority: P4
  • Status: Closed
  • Resolution: Not an Issue
  • OS: solaris_9
  • CPU: generic
  • Submitted: 2005-05-29
  • Updated: 2018-02-28
  • Resolved: 2018-02-28
Related Reports
Relates :  
Relates :  
Relates :  
While investigating NIO DirectByteBuffer performance in our Java 2D codebase (see
6273431), I discovered some weirdness about the "empirically determined"
Bits.JNI_COPY_FROM/TO_ARRAY_THRESHOLD constants.  Those values are currently set
at 6.  The Direct<Type>Buffer classes currently use these values to determine
when the benefit from doing a bulk memcpy() operation outweigh the costs of the
JNI downcall.  Those generated classes have code like:

    public LongBuffer put(long[] src, int offset, int length) {
        if ((length << 3) > Bits.JNI_COPY_FROM_ARRAY_THRESHOLD) {
            // use JNI downcall
        } else {
            // do int-by-int copy

This approach makes sense, except I think there's a miscommunication somewhere
about the units for the THRESHOLD constants.  The code in the Direct<Type>Buffer
classes seems to think the THRESHOLD constants are specified in bytes, but
that would imply (for the example above) that we would use the JNI downcall path
only if ((length << 3) > 6), which of course will always be the case for 8-byte
values such as long and double.  Perhaps the THRESHOLD constants were determined
in units of "elements" rather than "bytes"?

When I did some experiments, I found that a good value for the THRESHOLD constants
would be something like 28 elements.  In other words, if the array to be
copied has more than 28 elements (regardless of data type), then performance
is greatly improved for the bulk get/put operations.  In some quick experiments
I found that appropriate use of the THRESHOLD constants could improve performance
by 3-4x depending on the platform.
###@###.### 2005-05-29 23:04:03 GMT
I've been bitten by this performance bug for the second time; see 6347575
for the gory details.  The issue is the same as I reported originally: the
THRESHOLD constants are defined too low, so doing a bulk get/put operation
with a small array can be significantly slower (up to 3x slower) than doing
a series of get() or put() calls.  If the THRESHOLD constants were sized
appropriately, then this performance discrepancy would not exist.  For now,
I've had to workaround this bug in my fix for 6347575 (again, read that
evaluation for more information).

Bits.c was removed in JDK 9 so I think we can close this issue.

EVALUATION When the Bits.JNI_COPY* fields were introduced in mantis, they indicated the average number of bytes which would need to be transfered before it was worth making the JNI. Of course, there have been many changes both in the JDK and in our set of supported platforms since 2002, so we should not be surprised that these values are now stale. We should attempt to find and run an appropriate set of benchmarks to reset these values.

SUGGESTED FIX Increase the size of the THRESHOLD constants, from 6 to something like 28. Also, change the Direct<Type>Buffer classes to compare the length value directly (not the "length in bytes" value). So instead of: if ((length << 3) > Bits.JNI_COPY_FROM_ARRAY_THRESHOLD) use: if (length > Bits.JNI_COPY_FROM_ARRAY_THRESHOLD) ###@###.### 2005-05-29 23:04:03 GMT