Skip to content

Improve performance of uuid4 function #15862

Closed

Description

@AbhiPrasad

Description

uuid4 is expensive

Image

export function uuid4(crypto = getCrypto()): string {

Activity

  1. added theissue type on Mar 27, 2025
  2. changed the issue type fromtoon Mar 27, 2025
  3. timfish commented on Apr 5, 2025

    @timfish
    Collaborator

    My testing of uuid4() on Node v20 (ie. hitting crypto.randomUUID()) suggests it takes under 0.001ms.

    Maybe crypto.randomUUID() is being polyfilled with something that isn't as good as Nodes native code? Even then, 170ms seems suspiciously high!

  4. AbhiPrasad commented on Apr 7, 2025

    @AbhiPrasad
    ContributorAuthor

    @timfish this is a sandwich view, so it's an aggregate time. Perhaps it being called so much is nothing we can avoid.

  5. timfish commented on Apr 8, 2025

    @timfish
    Collaborator

    It would certainly make it quicker if we didn't have to remove the hyphens. Or maybe there's a faster way than the regex as we know the positions of them. Ideally we'd want to avoid the extra allocation!

  6. timfish commented on Apr 8, 2025

    @timfish
    Collaborator

    Just checked develop.sentry.io and for uuids, its says:

    UUIDs are declared as either 32 character hexadecimal strings without dashes ("12c2d058d58442709aa2eca08bf20986"), or 36 character strings with dashes ("12c2d058-d584-4270-9aa2-eca08bf20986"). It is recommended to omit dashes and use UUID v4 in all cases.

    But in plenty of other places it also says it expects 32 character uuids without dashes 🤷‍♂️

    Maybe we can keep the dashes in all cases on the client but we'd give Relay extra work because they'll all need normalising to 32 characters without dashes?

  7. AbhiPrasad commented on Apr 9, 2025

    @AbhiPrasad
    ContributorAuthor

    Maybe we can keep the dashes in all cases on the client but we'd give Relay extra work because they'll all need normalising to 32 characters without dashes?

    IMO giving relay extra work is no big deal, but we do then have friction where the uuid we display in the UI is different than the logged out json from the sdk

  8. timfish commented on Oct 15, 2025

    @timfish
    Collaborator

    The following code:

    import { Bench, hrtimeNow } from 'tinybench';
    import { v4 as uuidv4 } from '@lukeed/uuid';
    
    const bench = new Bench({hrtimeNow})
    
    function tinyBundleUuid(getRandomByte) {
      return (([1e7]) + 1e3 + 4e3 + 8e3 + 1e11).replace(/[018]/g, c =>
        ((c) ^ ((getRandomByte() & 15) >> ((c) / 4))).toString(16),
      );
    }
    
    /** This is a copy of @lukeed/uuid but without injecting hyphens */
    var IDX=256, HEX=[], BUFFER;
    while (IDX--) HEX[IDX] = (IDX + 256).toString(16).substring(1);
    
    function v4NoHyphens() {
    	var i=0, num, out='';
    
    	if (!BUFFER || ((IDX + 16) > 256)) {
    		BUFFER = Array(i=256);
    		while (i--) BUFFER[i] = 256 * Math.random() | 0;
    		i = IDX = 0;
    	}
    
    	for (; i < 16; i++) {
    		num = BUFFER[IDX + i];
    		if (i==6) out += HEX[num & 15 | 64];
    		else if (i==8) out += HEX[num & 63 | 128];
    		else out += HEX[num];
    
    		// if (i & 1 && i > 1 && i < 11) out += '-';
    	}
    
    	IDX++;
    	return out;
    }
    
    bench
      .add('crypto.randomUUID()', () => {
        console.assert(crypto.randomUUID())
      })
      .add('crypto.randomUUID().replace(/-/g, "")', () => {
        console.assert(crypto.randomUUID().replace(/-/g, ''))
      }).add('crypto.getRandomValues()', () => {
        const getRandomByte = () => {
          const typedArray = new Uint8Array(1);
          crypto.getRandomValues(typedArray);
          return typedArray[0];
        };
    
        console.assert(tinyBundleUuid(getRandomByte));
      }).add('Math.random()', () => {
        let getRandomByte = () => Math.random() * 16;
    
        console.assert(tinyBundleUuid(getRandomByte));
      }).add('@lukeed/uuid', () => {
        console.assert(uuidv4())
      }).add('@lukeed/uuid (custom no hyphens)', () => {
        console.assert(v4NoHyphens())
      });
    
    await bench.run()
    
    console.log(bench.name)
    console.table(bench.table())

    Results in:

    ┌─────────┬─────────────────────────────────────────┬──────────────────┬──────────────────┬────────────────────────┬────────────────────────┬─────────┐
    │ (index) │ Task name                               │ Latency avg (ns) │ Latency med (ns) │ Throughput avg (ops/s) │ Throughput med (ops/s) │ Samples │
    ├─────────┼─────────────────────────────────────────┼──────────────────┼──────────────────┼────────────────────────┼────────────────────────┼─────────┤
    │ 0       │ 'crypto.randomUUID()'                   │ '269.64 ± 0.24%' │ '250.00 ± 0.00'  │ '3879372 ± 0.01%'      │ '4000000 ± 0'          │ 3708647 │
    │ 1       │ 'crypto.randomUUID().replace(/-/g, "")' │ '445.09 ± 6.08%' │ '417.00 ± 0.00'  │ '2377301 ± 0.01%'      │ '2398082 ± 0'          │ 2246729 │
    │ 2       │ 'crypto.getRandomValues()'              │ '32130 ± 9.11%'  │ '28083 ± 834.00' │ '35202 ± 0.07%'        │ '35609 ± 1076'         │ 31124   │
    │ 3       │ 'Math.random()'                         │ '1929.0 ± 1.02%' │ '1916.0 ± 42.00' │ '525124 ± 0.01%'       │ '521921 ± 11413'       │ 518396  │
    │ 4       │ '@lukeed/uuid'                          │ '273.79 ± 0.07%' │ '250.00 ± 0.00'  │ '3770742 ± 0.01%'      │ '4000000 ± 0'          │ 3652395 │
    │ 5       │ '@lukeed/uuid (custom no hyphens)'      │ '262.20 ± 5.68%' │ '250.00 ± 0.00'  │ '4089440 ± 0.01%'      │ '4000000 ± 0'          │ 3813889 │
    └─────────┴─────────────────────────────────────────┴──────────────────┴──────────────────┴────────────────────────┴────────────────────────┴─────────┘
    

    This suggests we should remove the crypto.getRandomValues() code completely because it's 10x slower than Math.random().

    If bundle size wasn't a concern we would probably use the modified version of @lukeed/uuid without hyphens since this is nearly twice as fast as crypto.randomUUID().replace(/-/g, "")

  9. JPeer264 commented on Jan 20, 2026

    @JPeer264
    Member

    The performance of generateTraceId is currently quite fast in all my local tests so far. Closing this since there were some improvements made in #17938

    Image
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions