|
| 1 | +"""Generator for pseudorandom 64-bit integers. |
| 2 | +
|
| 3 | +Implements the xorshift* algorithm with a non-linear transformation |
| 4 | +(multiplication) applied to the result. |
| 5 | +
|
| 6 | +This implementation uses the recommended constants from Numerical Recipes |
| 7 | +Chapter 7 (Ranq1 algorithm). |
| 8 | +
|
| 9 | +According to TPV, the period is approx. 1.8 x 10^19. So it should not be used |
| 10 | +by an application that makes more than 10^12 calls. |
| 11 | +
|
| 12 | +To put this into perspective: we cap the max number of traces at 1k/s let's be |
| 13 | +conservative and say each trace contains 100 spans. |
| 14 | +
|
| 15 | +That's 100k spans/second which would be 100k + 1 calls to this fn per second. |
| 16 | +
|
| 17 | +That's 10,000,000 seconds until we hit the period. That's 115 days of |
| 18 | +100k spans/second (with no application restart) until the period is reached. |
| 19 | +
|
| 20 | +
|
| 21 | +rand64bits() is thread-safe as it is written in C and is interfaced with via |
| 22 | +a single Python step. This is the same mechanism in which CPython achieves |
| 23 | +thread-safety: |
| 24 | +https://github.com/python/cpython/blob/8d21aa21f2cbc6d50aab3f420bb23be1d081dac4/Lib/random.py#L37-L38 |
| 25 | +
|
| 26 | +
|
| 27 | +Python 2.7: |
| 28 | +Name (time in ns) Min Max Mean StdDev Median IQR Outliers OPS (Kops/s) Rounds Iterations |
| 29 | +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 30 | +rand64bits 144.1789 (1.01) 221.2596 (1.0) 155.5800 (1.0) 15.4198 (1.0) 151.3100 (1.00) 7.6687 (1.0) 4;6 6,427.5628 (1.0) 61 100000 |
| 31 | +random.SystemRandom().getrandbits 1,626.8015 (11.37) 2,178.9074 (9.85) 1,766.1762 (11.35) 133.8990 (8.68) 1,714.4561 (11.35) 113.9164 (14.85) 11;8 566.1949 (0.09) 60 10000 |
| 32 | +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 33 | +
|
| 34 | +
|
| 35 | +Python 3.7: |
| 36 | +Name (time in ns) Min Max Mean StdDev Median IQR Outliers OPS (Mops/s) Rounds Iterations |
| 37 | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 38 | +rand64bits 167.5956 (1.0) 211.3155 (1.0) 190.2803 (1.0) 9.5815 (1.0) 187.7187 (1.0) 11.4513 (1.0) 15;1 5.2554 (1.0) 52 100000 |
| 39 | +random.randbits 222.7103 (1.33) 367.4459 (1.74) 250.2699 (1.32) 26.5930 (2.78) 242.1607 (1.29) 26.4550 (2.31) 6;1 3.9957 (0.76) 36 100000 |
| 40 | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 41 | +""" |
| 42 | +from libc.stdint cimport uint64_t |
| 43 | + |
| 44 | +from ddtrace import compat |
| 45 | + |
| 46 | + |
| 47 | +cdef uint64_t x = compat.getrandbits(64) ^ 4101842887655102017 |
| 48 | + |
| 49 | + |
| 50 | +def rand64bits(): |
| 51 | + global x |
| 52 | + x ^= x >> 21 |
| 53 | + x ^= x << 35 |
| 54 | + x ^= x >> 4 |
| 55 | + return x * <uint64_t>2685821657736338717 |
0 commit comments