POWER9: Is there a way to improve the random number generation on PPC64?
Volker Simonis
volker.simonis at gmail.com
Tue Dec 5 08:16:20 UTC 2017
On Tue, Dec 5, 2017 at 12:24 AM, Gustavo Romero
<gromero at linux.vnet.ibm.com> wrote:
> Hi Volker,
>
> On 04-12-2017 12:00, Volker Simonis wrote:
>> The solution is quite simple (took me a while though as well to see it
>> :) - you have to define the intrinsic with the correct access flags.
>> I.e.
>
> Pretty cool!
>
> Thanks a lot for the help and the quick answer :-)
>
>
>> do_intrinsic(_darn, securerandom, darn_name,
>> serializePropertiesToByteArray_signature, F_R)
>>
>> instead of using "F_S" as you did in your first attempt. The access
>> flags are defined at the bottom of vmSymbols.hpp:
>>
>> F_R, // !static ?native !synchronized (R="regular")
>> F_S, // static ?native !synchronized
>>
>> If they don't correspond to the actual function, it won't be matched.
>>
>> If you'll do this right you'll get the following error:
>>
>> Compiler intrinsic is defined for method
>> [java.security.SecureRandom.darn()[B], but the method is not annotated
>> with @HotSpotIntrinsicCandidate. Exiting.
>>
>> which can be pacified by using "-XX:-CheckIntrinisics" or better by
>> using the @HotSpotIntrinsicCandidate annotation on the
>> SEcureRandom.darn()
>
> Right. I also had to tweak the darn() intrinsic to return a 'long' instead of
> a byte array just for quickly avoid dealing with any allocation inside it. The
> prototype worked fine on interpreted mode. As expected it generated an illegal
> instruction on P8 but returned 50 random numbers on P9 without getting blocked
> :-) So test [0] that uses SecureRandom.generateSeed() blocks from time to time
> (both on BM and VM it blocks always on a second run), but test [1] which uses
> SecureRandom.darn() never blocks:
>
> http://cr.openjdk.java.net/~gromero/logs/darn_prototype.log
>
> Here is the final change for reference (hs + corelib):
>
> https://github.com/gromero/darn/blob/a8ea0802018b0c4de946b548d4ede4bfc5fb6451/patches/darn_prototype.patch
>
> I intend to implement the fallback now and run it against DayTrade7 bench, if
> you have any other idea on how to test it, please let me know.
>
What is "DayTrade7 bench" ? I don't know it and a quick Google search
didn't returned anything useful.
>
>> Notice that in the real implementation you won't be able to add a
>> public method to SecureRandom.
>
> Yup, I'm aware of it. Initially I thought I could keep all the changes in
> arch-specific files but due to the need to fallback to a Java method if 'darn'
> intrinsic fails I understand that there is no way to not touch .java files. In
> that case your suggestion is to create an entire new provider by adding a new on
> to ./java.base/share/classes/com/sun/crypto/provider and listing it in
> java.security, for instance?
>
Probably yes, but I'm not sure about it as well. I think once you have
a complete implementation you should start a new thread on the
security mailing list (and maybe CC hostspot-dev) to ask about the
expert's opinions. As Intel also has the similar 'randr' instruction
since quite some time it may be reasonable to create a special
provider which is intended to intrinsically use the native CPU
instructions if available and fall back to the default implementation
otherwise. I think Vladimir Kozlov from the HotSpot team has tried to
build something similar for 'randr' some time ago so I'm sure you'll
get some good comments and advices :)
>
> Regards,
> Gustavo
>
> [0] https://github.com/gromero/darn/blob/eee8f0a480d7fd5cf6a307d3e7520e867d784ba3/patches/seed_current.java
> [1] https://github.com/gromero/darn/blob/0591eaf338664222c2cd26188d56fdb5a56883ea/patches/seed_darn.java
>
>> Regards,
>> Volker
>>
>>
>> On Fri, Dec 1, 2017 at 10:44 PM, Gustavo Romero
>> <gromero at linux.vnet.ibm.com> wrote:
>>> Hi Volker,
>>>
>>> On 29-11-2017 11:21, Volker Simonis wrote:
>>>> On Wed, Nov 29, 2017 at 2:04 PM, Gustavo Romero
>>>> <gromero at linux.vnet.ibm.com> wrote:
>>>>> Hi Volker,
>>>>>
>>>>> On 24-11-2017 20:04, Volker Simonis wrote:
>>>>>> in one of my talks [1,2] I have an example on how to intrinsify
>>>>>> Random.nextInt() in C2 by using the Intel 'rdrandl' instruction. But
>>>>>> please notice that this is just a "toy" example - it is not production
>>>>>> ready. In fact I think the right way would be to create a new
>>>>>> SecureRandom provider where you may implement "engineNextBytes" by
>>>>>> using the new Power instruction (maybe by calling a native function).
>>>>>> This special implementation of "engineNextBytes" could then be
>>>>>> intrinsified as described in the talk.
>>>>>
>>>>> I've implemented a simple interpreter intrinsic for 'darn' for a given
>>>>> class/method provided by the user, similarly to what you did for
>>>>> Helloword.sayHello() in your example. Thanks! I'm now looking for the correct
>>>>> way to call back from the intrinsic a Java method to act as a fallback method,
>>>>> since ISA says [1]:
>>>>>
>>>>> When the error value is obtained [i.e. 'darn' did not return a random number],
>>>>> software is expected to repeat the operation. If a non-error value has not been
>>>>> obtained after several attempts, a software random number generation method
>>>>> should be used. The recommended number of attempts may be implementation
>>>>> specific. In the absence of other guidance, ten attempts should be adequate.
>>>>>
>>>>> and so I need to call back from the intrinsic, let's say, SecureRandom.netInt()
>>>>> non-intrinsified method after about 10 failures to get the random number so it
>>>>> can take over the task again. You did something like that here:
>>>>>
>>>>> https://github.com/simonis/JBreak2016/blob/master/examples/hs_patches/JBreak_HelloWorldIntrinsic.patch#L55
>>>>>
>>>>> but for fputs() from libc.
>>>>>
>>>>> Do you know if it's possible to call, for instance, a loaded method like
>>>>> SecureRandom.nextInt() from the instrinsic?
>>>>>
>>>>
>>>> I don't think that would be easy to do (if possible at all).
>>>>
>>>> The correct way to handle such situations would be to define a Java
>>>> method with the exact semantics of your 'darn' instruction. All the
>>>> other logic should be implemented in Java. So for example you would
>>>> implement SecureRandom.darn() and call it from engineNextBytes(). At
>>>> the call site of darn() you check the error value and dispatch to the
>>>> corresponding Java implementation if necessary.
>>>
>>> I've implemented a Java SecureRandom.darn() method [1]. I works as expected,
>>> i.e. it returns 8 bytes of fake random number (using [3] example). However, when
>>> I proceeded to intrinsify it [2, 0] as I did for the method provided by the user
>>> (similarly to your HelloWorld example and for a user provided darn() method as I
>>> mentioned previously) I hit the following check:
>>>
>>> Compiler intrinsic is defined for method [_darn: static SecureRandom.darn()[B], but the method is not available in class [java/security/SecureRandom]. Exiting.
>>>
>>> SecureRandom.darn() signature looks correct and I know that
>>> java/security/SecureRandom::darn() is present in core libs because before trying
>>> to intrinsify it worked ok (I've got the 8 bytes of fake random number - using
>>> darning.java, below in references) and also 'javap' shows it's in .class:
>>>
>>> gromero at gromero16:~/hg/jdk10/hs$ javap -c -s ./build/linux-ppc64le-normal-server-slowdebug/jdk/modules/java.base/java/security/SecureRandom.class | fgrep -i darn
>>> public byte[] darn();
>>>
>>> I thought that no additional hack was necessary to get that intrinsic working as
>>> it's in core libs, hence nothing like this is needed:
>>>
>>> https://github.com/simonis/JBreak2016/blob/master/examples/hs_patches/JBreak2JavaZone.patch#L57-L59
>>>
>>> On the other hand if I add @HotSpotIntrinsicCandidate to SecureRandom.darn() I
>>> get:
>>>
>>> Method [java.security.SecureRandom.darn()[B] is annotated with @HotSpotIntrinsicCandidate, but no compiler intrinsic is defined for the method. Exiting.
>>>
>>> Any clue on what I'm missing? Is it correct to assume that since darn() now
>>> is in core libs no check is necessary?
>>>
>>> Thanks a lot!
>>>
>>> Regards,
>>> Gustavo
>>>
>>> The hs patches:
>>>
>>> [0] https://github.com/gromero/darn/blob/master/patches/0_darn_macroassembler.patch
>>> [1] https://github.com/gromero/darn/blob/master/patches/1_SecureRandom_darn_Java.patch
>>> [2] https://github.com/gromero/darn/blob/master/patches/2_SecureRandom_darn_intrinsic.patch
>>>
>>> and the test-case:
>>>
>>> [3] https://github.com/gromero/darn/blob/master/patches/darning.java
>>>
>>>>> Thanks!
>>>>>
>>>>> Regards,
>>>>> Gustavo
>>>>>
>>>>>> Also, before you start this, please contact the security mailing list
>>>>>> just to make sure you're not going into the wrong direction (I'm not a
>>>>>> security expert :)
>>>>>>
>>>>>> Regards,
>>>>>> Volker
>>>>>>
>>>>>> [1] https://vimeo.com/182074382
>>>>>> [2] https://rawgit.com/simonis/JBreak2016/master/jbreak2016.xhtml#/
>>>>>>
>>>>>> On Fri, Nov 24, 2017 at 12:58 PM, Gustavo Romero
>>>>>> <gromero at linux.vnet.ibm.com> wrote:
>>>>>>> Hi,
>>>>>>>
>>>>>>> POWER9 processors introduced a new single instruction to generate a random
>>>>>>> number called 'darn' (Deliver A Random Number) [1, 2]. The random number
>>>>>>> generator behind this instruction is NIST SP800-90B and SP800-90C compliant and
>>>>>>> provides a minimum of 0.5 bits of entropy per bit. That instruction is as simple
>>>>>>> as "darn RT, L", where RT is general 64-bit purpose register and L is a 2-bit
>>>>>>> operand to select the random number format. One can call 'darn' many times to
>>>>>>> obtain a new random number each time.
>>>>>>>
>>>>>>> Initially I think it can help on the improving (throughput) of SecureRandom.generateSeed()
>>>>>>> method & friends from JCE (NativePRNG provider). If that holds, so it has to
>>>>>>> be done both for Interpreter and JIT.
>>>>>>>
>>>>>>> Currently generateSeed() from NativePRNG basically reads from /dev/random by
>>>>>>> default (which blocks from time to time) or /dev/urandom if instructed to do so.
>>>>>>> Could somebody please help me to figure out the appropriate place to exploit
>>>>>>> such a P9 instruction for interpreted mode, given that code for generateSeed()
>>>>>>> is pure Java and behind scenes just opens /dev/random file and reads from
>>>>>>> it? For instance, is it correct to exploit it on a C/C++ code and attach that
>>>>>>> by means of a JNI?
>>>>>>>
>>>>>>> Finally, for JITed mode, I think that a way to exploit such a feature would be
>>>>>>> by matching an specific sub-tree in Ideal Graph and from that emit a `darn`
>>>>>>> instruction, however I could not figure one sound sub-tree with known nodes
>>>>>>> (AddI, LoadN, Parm, etc) that could be matched for that purpose. How do porters
>>>>>>> usually proceed in this case?
>>>>>>>
>>>>>>> Any comments shedding some light on that is much appreciated.
>>>>>>>
>>>>>>> Thanks and best regards,
>>>>>>> Gustavo
>>>>>>>
>>>>>>> [1] https://www.docdroid.net/tWT7hjD/powerisa-v30.pdf, p. 79
>>>>>>> [2] https://openpowerfoundation.org/?resource_lib=power-isa-version-3-0
>>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
>
More information about the ppc-aix-port-dev
mailing list