-
Notifications
You must be signed in to change notification settings - Fork 21
Add Java-side cache with large-request bypass for native RNG #1221
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,6 +16,16 @@ public final class ExtendedRandom { | |
| OCKContext ockContext; | ||
| final long ockPRNGContextId; | ||
|
|
||
| // 128KB cache ? | ||
| private static final int MEGABYTE_CACHE_SIZE = 128 * 1024; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this be a configurable size. By default one megabyte seems reasonable to me given your findings. |
||
|
|
||
| // 16KB threshold ? | ||
| private static final int BYPASS_THRESHOLD = 16 * 1024; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the threshold trying to accomplish? Seems like if the user wants more randoms then is in the cache then we would then make a trip to the native layer to fill the cache at that time and then return the bytes to the caller. This would save some complexity for now. |
||
|
|
||
| private byte[] megaByteCache; | ||
| private int cachePos; // Next unread index in cache | ||
| private int megaByteCacheLength; | ||
|
|
||
| public static ExtendedRandom getInstance(OCKContext ockContext, String algName, OpenJCEPlusProvider provider) | ||
| throws OCKException { | ||
| if (ockContext == null) { | ||
|
|
@@ -45,9 +55,42 @@ public synchronized void nextBytes(byte[] bytes) throws OCKException { | |
| if (bytes == null) { | ||
| throw new IllegalArgumentException("bytes is null"); | ||
| } | ||
| int len = bytes.length; | ||
| if (len == 0) { | ||
| return; | ||
| } | ||
|
|
||
| if (bytes.length > 0) { | ||
| // 1) LARGE REQUEST BYPASS: | ||
| // Fill destination directly to avoid cache->dest copy cost. | ||
| if (len >= BYPASS_THRESHOLD) { | ||
| NativeInterface.EXTRAND_nextBytes(ockContext.getId(), ockPRNGContextId, bytes); | ||
|
|
||
| // Invalidate cache so next small request refills fresh. | ||
| cachePos = megaByteCacheLength = 0; | ||
| return; | ||
| } | ||
|
|
||
| // 2) SMALL/MEDIUM REQUEST: | ||
| // Serve from cache, refilling as needed. | ||
| int outPos = 0; | ||
| int remaining = len; | ||
|
|
||
| while (remaining > 0) { | ||
| int available = megaByteCacheLength - cachePos; | ||
|
|
||
| // If cache is empty (or not initialized), refill it. | ||
| if (available <= 0) { | ||
| refillMegaByteCache(); | ||
| available = megaByteCacheLength - cachePos; | ||
| } | ||
|
|
||
| // Copy as much as we can from cache into output. | ||
| int toCopy = Math.min(available, remaining); | ||
| System.arraycopy(megaByteCache, cachePos, bytes, outPos, toCopy); | ||
|
|
||
| cachePos += toCopy; | ||
| outPos += toCopy; | ||
| remaining -= toCopy; | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -75,4 +118,16 @@ private Runnable cleanOCKResources(long ockPRNGContextId, OCKContext ockContext) | |
| } | ||
| }; | ||
| } | ||
|
|
||
| private void refillMegaByteCache() throws OCKException { | ||
| if (megaByteCache == null) { | ||
| megaByteCache = new byte[MEGABYTE_CACHE_SIZE]; | ||
jasonkatonica marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| // Fill the entire cache from native. | ||
| NativeInterface.EXTRAND_nextBytes(ockContext.getId(), ockPRNGContextId, megaByteCache); | ||
|
|
||
| cachePos = 0; | ||
| megaByteCacheLength = megaByteCache.length; | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need any additional testing in our test buckets to test randoms from the cache right around the boundary limits for our cache?