diff --git a/.coveragerc b/.coveragerc index 3880345..ac37284 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,3 +1,4 @@ [run] omit = setup.py + perftest_ulid2.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5609134..587a3b2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,4 +25,5 @@ jobs: python-version: '${{ matrix.python-version }}' - run: pip install pytest pytest-cov - run: py.test -vvv --cov . + - run: python perftest_ulid2.py - uses: codecov/codecov-action@v2 diff --git a/perftest_ulid2.py b/perftest_ulid2.py new file mode 100644 index 0000000..8ae38f0 --- /dev/null +++ b/perftest_ulid2.py @@ -0,0 +1,28 @@ +from __future__ import print_function +import timeit + +import ulid2 + + +def perftest(): + tmr = timeit.Timer(lambda: ulid2.generate_ulid_as_uuid()) + n_iterations = 300000 + time_taken = tmr.timeit(n_iterations) + return int(n_iterations / time_taken) + + +def main(): + results = [] + for x in range(5): + ops_per_sec = perftest() + print(x + 1, " ... ", ops_per_sec) + results.append(ops_per_sec) + n_results = len(results) + mean = sum(results) / n_results + median = sorted(results)[n_results // 2] + print("mean ops/sec ", mean) + print("median ops/sec", median) + + +if __name__ == '__main__': + main() diff --git a/ulid2.py b/ulid2.py index 0c5865a..f10337a 100644 --- a/ulid2.py +++ b/ulid2.py @@ -29,12 +29,12 @@ class InvalidULID(ValueError): def _to_binary(byte_list): - if py3: - return bytes(byte_list) - else: - return bytes(b''.join(chr(b) for b in byte_list)) + return bytes(b''.join(chr(b) for b in byte_list)) +if py3: + _to_binary = bytes + # Unrolled and optimized ULID Base32 encoding/decoding # implementations based on NUlid: # https://github.com/RobThree/NUlid/blob/5f2678b4d/NUlid/Ulid.cs#L159 @@ -173,6 +173,7 @@ def get_ulid_time(ulid): _last_entropy = None _last_timestamp = None + def generate_binary_ulid(timestamp=None, monotonic=False): """ Generate the bytes for an ULID. @@ -193,9 +194,7 @@ def generate_binary_ulid(timestamp=None, monotonic=False): timestamp = calendar.timegm(timestamp.utctimetuple()) ts = int(timestamp * 1000.0) - ts_bytes = _to_binary( - (ts >> shift) & 0xFF for shift in (40, 32, 24, 16, 8, 0) - ) + ts_bytes = struct.pack('!Q', ts)[2:] entropy = os.urandom(10) if monotonic and _last_timestamp == ts and _last_entropy is not None: while entropy < _last_entropy: