On Tue, 20 May 2025 13:35:32 GMT, kieran-farrell <d...@openjdk.org> wrote:

>> src/java.base/share/classes/java/util/UUID.java line 219:
>> 
>>> 217:         randomBytes[8] |= (byte) 0x80;
>>> 218: 
>>> 219:         return new UUID(randomBytes);
>> 
>> This could remove the allocation by composing the high and low longs using 
>> shifts and binary operations and ng.next().
>> Can the sub-microsecond value just be truncated and avoid the expensive 
>> divide operation?
>
>> Can the sub-microsecond value just be truncated and avoid the expensive 
>> divide operation?'
> 
> method 3 of secion 6.2 of 
> https://www.rfc-editor.org/rfc/rfc9562.html#name-monotonicity-and-counters 
> states 
> 
>> start with the portion of the timestamp expressed as a fraction of the 
>> clock's tick value (fraction of a millisecond for UUIDv7). Compute the count 
>> of possible values that can be represented in the available bit space, 4096 
>> for the UUIDv7 rand_a field. Using floating point or scaled integer 
>> arithmetic, multiply this fraction of a millisecond value by 4096 and round 
>> down (toward zero) to an integer result to arrive at a number between 0 and 
>> the maximum allowed for the indicated bits, which sorts monotonically based 
>> on time. '
> 
> so i think we might have to keep the division? though i re-shuffled the 
> equation to 
> 
> `int nsBits = (int) ((nsTime % 1_000_000) / 1_000_000.0 * 4096);`
> 
> which gives scaled integer division rather than floating point and gave a 
> very slight imporved perfomance to 143.758 ± 2.135  ns/op

> This could remove the allocation by composing the high and low longs using 
> shifts and binary operations and ng.next().

do you mean to create the UUID using most and least significant bytes? if so, 
I've tried out some variations, i found creating the 64 bit lsb with 
ng.nextLong() brings a large pefomance decrease over using the nextBytes 
method, but the below implemntation keeping with the nextByte(byte[]) api 
brings a performance increase to 121.128 ± 30.486  ns/op, though the code might 
appear a little roundabout.


    public static UUID timestampUUID() {
        long msTime = System.currentTimeMillis();
        long nsTime = System.nanoTime();

        // Scale sub-ms nanoseconds to a 12-bit value
        int nsBits = (int) ((nsTime % 1_000_000L) * 4096L / 1_000_000L);

        // Compose the 64 most significant bits: [48-bit msTime | 4-bit version 
| 12-bit nsBits]
        long mostSigBits =
                ((msTime & 0xFFFFFFFFFFFFL) << 16) |
                        (0x7L << 12) |
                        nsBits;

        // Generate 8 random bytes for least significant bits
        byte[] randomBytes = new byte[8];
        SecureRandom ng = UUID.Holder.numberGenerator;
        ng.nextBytes(randomBytes);

        long leastSigBits = 0;
        for (int i = 0; i < 8; i++) {
            leastSigBits = (leastSigBits << 8) | (randomBytes[i] & 0xFF);
        }

        // Set variant (bits 62–63) to '10'
        leastSigBits &= 0x3FFFFFFFFFFFFFFFL;
        leastSigBits |= 0x8000000000000000L;

        return new UUID(mostSigBits, leastSigBits);
    }

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/25303#discussion_r2098044396

Reply via email to