Skip to content

Instantly share code, notes, and snippets.

@tiran
Created January 19, 2017 20:01
Show Gist options
  • Save tiran/f0f9f10791b2982937da5ed6678e76b3 to your computer and use it in GitHub Desktop.
Save tiran/f0f9f10791b2982937da5ed6678e76b3 to your computer and use it in GitHub Desktop.
Simple hashing benchmark for Python 2 and 3
#!/usr/bin/env python3
from __future__ import print_function
import os
import time
import sys
if sys.version_info.major >= 3:
timer = time.perf_counter
else:
timer = time.time
constructors = (
'_md5.md5', '_hashlib.openssl_md5',
'_sha1.sha1', '_hashlib.openssl_sha1',
'_sha256.sha224', '_hashlib.openssl_sha224',
'_sha256.sha256', '_hashlib.openssl_sha256',
'_sha512.sha384', '_hashlib.openssl_sha384',
'_sha512.sha512', '_hashlib.openssl_sha512',
'_sha3.sha3_224',
'_sha3.sha3_256',
'_sha3.sha3_384',
'_sha3.sha3_512',
'_sha3.shake_128',
'_sha3.shake_256',
'_blake2.blake2b', '_blake2.blake2s',
)
def bench(factory, rounds, data):
# warm up
h = factory(data)
args = (16,) if h.digest_size == 0 else ()
h .digest(*args)
h = factory()
start = timer()
for i in range(rounds):
h.update(data)
h.digest(*args)
return timer() - start
def main():
rounds = 256
data = os.urandom(1024*1024)
print(sys.version)
with open('/proc/cpuinfo') as f:
for line in f:
if line.startswith('model name'):
print('CPU:', line.split(':')[1].strip())
break
print("{} times 1 MiB random data".format(rounds))
print()
missing = []
for name in constructors:
modname, funcname = name.split('.')
try:
mod = __import__(modname)
except ImportError:
missing.append(name)
else:
func = getattr(mod, funcname)
dur = bench(func, rounds, data)
print('{0:<25} {1:0.0f} MiB/sec'.format(name, rounds/dur))
if missing:
print('Missing: {}'.format(', '.join(missing)))
if __name__ == '__main__':
main()
@danielloader
Copy link

danielloader commented Jan 23, 2023

#!/usr/bin/env python3
from __future__ import print_function
import os
import time
import sys
import platform

if sys.version_info.major >= 3:
    timer = time.perf_counter
else:
    timer = time.time


constructors = (
    "_md5.md5",
    "_hashlib.openssl_md5",
    "_sha1.sha1",
    "_hashlib.openssl_sha1",
    "_sha256.sha224",
    "_hashlib.openssl_sha224",
    "_sha256.sha256",
    "_hashlib.openssl_sha256",
    "_sha512.sha384",
    "_hashlib.openssl_sha384",
    "_sha512.sha512",
    "_hashlib.openssl_sha512",
    "_sha3.sha3_224",
    "_sha3.sha3_256",
    "_sha3.sha3_384",
    "_sha3.sha3_512",
    "_sha3.shake_128",
    "_sha3.shake_256",
    "_blake2.blake2b",
    "_blake2.blake2s",
)


def bench(factory, rounds, data):
    # warm up
    h = factory(data)
    args = (16,) if h.digest_size == 0 else ()
    h.digest(*args)

    h = factory()
    start = timer()
    for i in range(rounds):
        h.update(data)
    h.digest(*args)
    return timer() - start


def main():
    rounds = 256
    data = os.urandom(1024 * 1024)

    print(sys.version)
    print("CPU:", platform.platform())

    print("{} times 1 MiB random data".format(rounds))
    print()

    missing = []

    for name in constructors:
        modname, funcname = name.split(".")
        try:
            mod = __import__(modname)
        except ImportError:
            missing.append(name)
        else:
            func = getattr(mod, funcname)
            dur = bench(func, rounds, data)
            print("{0:<25} {1:0.0f} MiB/sec".format(name, rounds / dur))

    if missing:
        print("Missing: {}".format(", ".join(missing)))


if __name__ == "__main__":
    main()

For anyone who wants it to work on mac and not rely on the /proc path

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