RFR 8066397 Remove network-related seed initialization code in ThreadLocal/SplittableRandom
roger riggs
roger.riggs at oracle.com
Wed Dec 3 14:14:26 UTC 2014
Hi Peter,
A few questions and comments:
- Can/should this function be fit into one of the existing classes?
- Is more than one instance needed?
Seed material seems to be needed only as a one-shot so a simpler
implementation that opens,
uses and closes would leave fewer leftovers (and not introduce a new
finalizer use).
- The Windows native code could be simpler if the hCryptProv
was returned from the init function and passed as an argument where
needed in getBytes and close .
- The static checking tool we use will complain about JNI functions that may
throw exceptions if those exceptions are not checked for.
For example, SystemRandomImpl_md.c:80.
The macros in jni_util.h like CHECK_NULL, CHECK_NULL_RETURN can be used.
Thanks, Roger
On 12/2/2014 11:42 AM, Peter Levart wrote:
> On 12/02/2014 11:02 AM, Paul Sandoz wrote:
>> Hi,
>>
>> Please find below a patch to remove the networking code computing a
>> seed in ThreadLocal/SplittableRandom.
>>
>> We thought it a good idea at the time :-) but subsequently on certain
>> platforms this results in very high initalization costs that can
>> propagate to other classes such as ConcurrentSkipList*.
>>
>> The short-term solution is to remove this code and fallback just
>> using current system time. This needs to be back-ported to 8u40.
>>
>> A longer term solution is to provide a simple public API to get
>> access to some seed bytes that is optimal for the underlying
>> platform, for example, based on Peter's investigations. For linux
>> /dev/urandom is sufficient as a source of bytes. The main problem
>> seems to be Windows. It would also be nice to back-port to say 8u60
>> using a private API and update TLR/SR.
>
> Hi,
>
> Here's a proof of concept for an API that just delegates to
> system-provided "cryptographically secure" (as declared by the
> system(s)) pseudo random number generator:
>
> http://cr.openjdk.java.net/~plevart/jdk9-dev/SystemRandom/webrev.01/
>
> On UNIX-es this uses /dev/urandom (which is non-blocking and uses
> system entropy at least for it's seed):
>
> http://en.wikipedia.org/?title=/dev/random
>
> On Windows it uses MS Crypto API's function CryptGenRandom (the JNI
> code is ripped from the sun.security.provider.NativeSeedGenerator),
> which also seeds from various system sources of entropy:
>
> http://en.wikipedia.org/wiki/CryptGenRandom
>
> http://msdn.microsoft.com/en-us/library/windows/desktop/aa379942%28v=vs.85%29.aspx
>
>
> The initialization overhead is low on UNIX (the enclosed test run on
> 64 bit Fedora 20, i7 PC):
>
> SystemRandomTest... (8 bytes / invocation)
> 1st invocation: 112315 ns, result: [25, 61, -12, -106, 75, -7, -73, -55]
> Following 1000000 invocations: 0.636644474 s, (636 ns/invocation)
>
> The same test run on 32 bit Windows 7 (as VirtualBox guest on the same
> machine):
>
> SystemRandomTest... (8 bytes / invocation)
> 1st invocation: 4880788 ns, result: [-32, 53, -31, 62, 51, 83, 9, -5]
> Following 1000000 invocations: 1.761087512 s, (1761 ns/invocation)
>
> I think the initialization on Windows has an initial latency of approx
> 5ms because it has to initialize the whole MS Crypto API with it's
> providers. But CryptGenRandom, which is part of this API, actually
> delegates it's work to RtlGenRandom function:
>
> http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694%28v=vs.85%29.aspx
>
>
> ...which might have lower initialization costs. Unfortunately, the
> wording in the Microsoft document states that it might be removed in
> the future. Perhaps we could try to use it and fallback to
> CryptGenRandom if it is not available...
>
>
> Regards, Peter
>
>
>>
>> Paul.
>>
>> [1] https://bugs.openjdk.java.net/browse/JDK-8060435
>>
>> diff -r 1b599b4755bd
>> src/java.base/share/classes/java/util/SplittableRandom.java
>> --- a/src/java.base/share/classes/java/util/SplittableRandom.java Mon
>> Dec 01 17:59:39 2014 -0800
>> +++ b/src/java.base/share/classes/java/util/SplittableRandom.java Tue
>> Dec 02 10:53:47 2014 +0100
>> @@ -237,34 +237,7 @@
>> s = (s << 8) | ((long)(seedBytes[i]) & 0xffL);
>> return s;
>> }
>> - long h = 0L;
>> - try {
>> - Enumeration<NetworkInterface> ifcs =
>> - NetworkInterface.getNetworkInterfaces();
>> - boolean retry = false; // retry once if
>> getHardwareAddress is null
>> - while (ifcs.hasMoreElements()) {
>> - NetworkInterface ifc = ifcs.nextElement();
>> - if (!ifc.isVirtual()) { // skip fake addresses
>> - byte[] bs = ifc.getHardwareAddress();
>> - if (bs != null) {
>> - int n = bs.length;
>> - int m = Math.min(n >>> 1, 4);
>> - for (int i = 0; i < m; ++i)
>> - h = (h << 16) ^ (bs[i] << 8) ^ bs[n-1-i];
>> - if (m < 4)
>> - h = (h << 8) ^ bs[n-1-m];
>> - h = mix64(h);
>> - break;
>> - }
>> - else if (!retry)
>> - retry = true;
>> - else
>> - break;
>> - }
>> - }
>> - } catch (Exception ignore) {
>> - }
>> - return (h ^ mix64(System.currentTimeMillis()) ^
>> + return (mix64(System.currentTimeMillis()) ^
>> mix64(System.nanoTime()));
>> }
>> diff -r 1b599b4755bd
>> src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java
>> ---
>> a/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java
>> Mon Dec 01 17:59:39 2014 -0800
>> +++
>> b/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java
>> Tue Dec 02 10:53:47 2014 +0100
>> @@ -147,34 +147,7 @@
>> s = (s << 8) | ((long)(seedBytes[i]) & 0xffL);
>> return s;
>> }
>> - long h = 0L;
>> - try {
>> - Enumeration<NetworkInterface> ifcs =
>> - NetworkInterface.getNetworkInterfaces();
>> - boolean retry = false; // retry once if
>> getHardwareAddress is null
>> - while (ifcs.hasMoreElements()) {
>> - NetworkInterface ifc = ifcs.nextElement();
>> - if (!ifc.isVirtual()) { // skip fake addresses
>> - byte[] bs = ifc.getHardwareAddress();
>> - if (bs != null) {
>> - int n = bs.length;
>> - int m = Math.min(n >>> 1, 4);
>> - for (int i = 0; i < m; ++i)
>> - h = (h << 16) ^ (bs[i] << 8) ^ bs[n-1-i];
>> - if (m < 4)
>> - h = (h << 8) ^ bs[n-1-m];
>> - h = mix64(h);
>> - break;
>> - }
>> - else if (!retry)
>> - retry = true;
>> - else
>> - break;
>> - }
>> - }
>> - } catch (Exception ignore) {
>> - }
>> - return (h ^ mix64(System.currentTimeMillis()) ^
>> + return (mix64(System.currentTimeMillis()) ^
>> mix64(System.nanoTime()));
>> }
>
More information about the core-libs-dev
mailing list