7013347: allow crypto functions to be called inline to enhance performance
Tom Rodriguez
tom.rodriguez at oracle.com
Wed Feb 8 10:17:24 PST 2012
On Feb 8, 2012, at 12:36 AM, David Holmes wrote:
> Hi Tom,
>
> Sorry it took a while to get to this.
>
> I get the gist of what you are trying to do here. Obviously the details are quite intricate and I don't quite follow them all, but I don't have any specific issues with anything I saw.
Thanks for looking at it.
tom
>
> Aside: I expect the extra { } scope in the safepoint code came from when declarations could only appear at the start of blocks.
>
> David
>
>
> On 31/01/2012 11:49 AM, Tom Rodriguez wrote:
>> http://cr.openjdk.java.net/~never/7013347
>> 1133 lines changed: 979 ins; 56 del; 98 mod; 35796 unchg
>>
>> 7013347: allow crypto functions to be called inline to enhance performance
>> Reviewed-by:
>>
>> This is a long one.
>>
>> The synopsis of this is slightly misleading. This doens't allow
>> direct calls to native routines from Java but it does attempt to
>> reduce the overhead of using JNI for specific use cases while still
>> maintaining the safety invariants that JNI provdies. For native code
>> that runs in a bounded time JNI provides a function called
>> GetPrimtiveArrayCritical which may provide direct access to the body
>> of Java arrays of primitive. In Hotspot this is accomplished by
>> suppressing garbage collection while these pointers are exposed to
>> native code. This is accomplished with the GC_locker class which is
>> basically a readers/writers lock. Note that the GC_locker doesn't
>> suppress safepointing, just garbage collections. There are many
>> operations which require a safepoint to make forward progress, so
>> suppressing them indefinitely isn't acceptable.
>>
>> This RFE provides is a shorthand for the use of
>> GetPrimtiveArrayCritical by defining an alternate native calling
>> convention that only allows the use of primitive or arrays of
>> primtive. The native method must also be static since non-static
>> methods are passed the receiver as an argument and Java objects aren't
>> allowed. Synchronization and exceptions aren't allowed either. The
>> Java code calling these natives is fee to use all of those features so
>> it's not that onerous of a restriction.
>>
>> The benefits of this approach are that JVM can more quickly do the
>> work inline that would normally be done by the
>> GetPrimtiveArrayCritical/ReleasePrimtiveArrayCritical function calls.
>> Calling back into the JVM through JNI requires synchronization with
>> the JVM and each upcall adds a minimum overhead to the native routine.
>> This helps to reduce the overhead to a more fixed cost per call. It
>> also simplifies the work that the caller must do since synchronization
>> and exceptions aren't allowed. For now this work is being done in the
>> existing native wrapper generation but with some more simplification
>> this could be more easily inlined directly into the caller.
>>
>> The signature of the native routine follows the same name mangling as
>> normal JNI methods but they start with JavaCritical_ instead of Java_.
>> Any array arguments are unpacked into a pair of arguments, the length
>> followed by a pointer to the body of the array. If the incoming array
>> is NULL then the body pointer is NULL and the length is 0.
>>
>> Currently this is a JDK private interface while we gain some
>> experience with it but it will likely become a more standard
>> extension. It's also an optional extension so a native library is
>> required to provide the normal point in addition to the alternate
>> entry point.
>>
>> The changes consist of three parts. The first is the lookup logic
>> that finds the alternate native entry point. JNI critical natives
>> currently can only be found through dynamic lookup. JNI
>> RegisterNatives doesn't know about these functions so there's no way
>> to provide the alternate entry point.
>>
>> The second part is the lazy critical entry logic. The fix for 7129164
>> introduced code that computed the JNI active count during
>> safepointing. Now as part of that computation, if a thread is seen to
>> be in thread_in_native state and the nmethod on the top of stack is a
>> critical native wrapper, then the critical count for that thread is
>> incremented and the suspend flags are set so that when the nmethod
>> returns the native code it will call back into the runtime and do the
>> unlock of the critical native.
>>
>> The last part are the native wrappers themselves. When compiling a
>> critical native wrapper, they emit a new check of GC_locker::_needs_gc
>> and they call into the runtime if it's true. This keeps them from
>> starting new JNI critical sections if a GC has been requested. The
>> arguments are unpacked following the alternate calling convention and
>> the method is called as it normally would be.
>>
>> On return the wrapper checks the suspend flags as it normally would
>> and calls back into the runtime where is might have to block and force
>> a GC if it's the last thread exiting the GC_locker. This required
>> some slightly different handling of the final transition back to
>> thread_in_Java since we have to allow blocking.
>>
>> The wrappers are only generated differently if they are compiling a
>> critical native so it shouldn't have much effect on normal execution.
>> The only library currently taking advantage of this is the new ucrypto
>> provider on Solaris. For some crypto operations it improves
>> throughput by 20% or more because the crypto routines are fast enough
>> that the JNi overhead is significant. It's expected that other parts
>> of the JDK will take advantage of it going forward and hopefully it
>> can be tightened up further.
>>
>> Tested with new crypto provider and microbenchmark test case. Also
>> ran runthese.
>>
>>
More information about the hotspot-dev
mailing list