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()
@tiran
Copy link
Author

tiran commented Jan 19, 2017

Python 3.6 X86_64 (git, enable-optimizations)

3.6.0+ (3.6:fd889884fe08, Jan 19 2017, 20:34:27) 
[GCC 6.3.1 20161221 (Red Hat 6.3.1-1)]
CPU: Intel(R) Core(TM) i7-4900MQ CPU @ 2.80GHz
256 times 1 MiB random data

_md5.md5                  684 MiB/sec
_hashlib.openssl_md5      725 MiB/sec
_sha1.sha1                487 MiB/sec
_hashlib.openssl_sha1     1017 MiB/sec
_sha256.sha224            238 MiB/sec
_hashlib.openssl_sha224   466 MiB/sec
_sha256.sha256            239 MiB/sec
_hashlib.openssl_sha256   467 MiB/sec
_sha512.sha384            328 MiB/sec
_hashlib.openssl_sha384   679 MiB/sec
_sha512.sha512            327 MiB/sec
_hashlib.openssl_sha512   678 MiB/sec
_sha3.sha3_224            356 MiB/sec
_sha3.sha3_256            332 MiB/sec
_sha3.sha3_384            255 MiB/sec
_sha3.sha3_512            180 MiB/sec
_sha3.shake_128           415 MiB/sec
_sha3.shake_256           332 MiB/sec
_blake2.blake2b           574 MiB/sec
_blake2.blake2s           458 MiB/sec

2.7.12 X86_64

2.7.12 (default, Sep 29 2016, 12:52:02) 
[GCC 6.2.1 20160916 (Red Hat 6.2.1-2)]
CPU: Intel(R) Core(TM) i7-4900MQ CPU @ 2.80GHz
256 times 1 MiB random data

_hashlib.openssl_md5      721 MiB/sec
_hashlib.openssl_sha1     1001 MiB/sec
_hashlib.openssl_sha224   463 MiB/sec
_hashlib.openssl_sha256   456 MiB/sec
_hashlib.openssl_sha384   681 MiB/sec
_hashlib.openssl_sha512   676 MiB/sec

3.5.2 X86_64

3.5.2 (default, Sep 14 2016, 11:28:32) 
[GCC 6.2.1 20160901 (Red Hat 6.2.1-1)]
CPU: Intel(R) Core(TM) i7-4900MQ CPU @ 2.80GHz
256 times 1 MiB random data

_hashlib.openssl_md5      729 MiB/sec
_hashlib.openssl_sha1     1001 MiB/sec
_hashlib.openssl_sha224   463 MiB/sec
_hashlib.openssl_sha256   462 MiB/sec
_hashlib.openssl_sha384   677 MiB/sec
_hashlib.openssl_sha512   677 MiB/sec

3.6.0 ARMv7 (RPi 3) (git without --enable-optimiziations)

3.6.0+ (default, Jan 20 2017, 10:12:49) 
[GCC 4.9.2]
CPU: ARMv7 Processor rev 4 (v7l)
256 times 1 MiB random data

_md5.md5                  141 MiB/sec
_hashlib.openssl_md5      173 MiB/sec
_sha1.sha1                73 MiB/sec
_hashlib.openssl_sha1     88 MiB/sec
_sha256.sha224            49 MiB/sec
_hashlib.openssl_sha224   64 MiB/sec
_sha256.sha256            49 MiB/sec
_hashlib.openssl_sha256   64 MiB/sec
_sha512.sha384            11 MiB/sec
_hashlib.openssl_sha384   31 MiB/sec
_sha512.sha512            11 MiB/sec
_hashlib.openssl_sha512   31 MiB/sec
_sha3.sha3_224            11 MiB/sec
_sha3.sha3_256            10 MiB/sec
_sha3.sha3_384            8 MiB/sec
_sha3.sha3_512            6 MiB/sec
_sha3.shake_128           13 MiB/sec
_sha3.shake_256           10 MiB/sec
_blake2.blake2b           24 MiB/sec
_blake2.blake2s           46 MiB/sec

3.4.2 ARMv7 (RPi 3)

3.4.2 (default, Oct 19 2014, 13:31:11) 
[GCC 4.9.1]
CPU: ARMv7 Processor rev 4 (v7l)
256 times 1 MiB random data

_md5.md5                  131 MiB/sec
_hashlib.openssl_md5      173 MiB/sec
_sha1.sha1                77 MiB/sec
_hashlib.openssl_sha1     89 MiB/sec
_sha256.sha224            55 MiB/sec
_hashlib.openssl_sha224   64 MiB/sec
_sha256.sha256            55 MiB/sec
_hashlib.openssl_sha256   64 MiB/sec
_sha512.sha384            14 MiB/sec
_hashlib.openssl_sha384   31 MiB/sec
_sha512.sha512            14 MiB/sec
_hashlib.openssl_sha512   31 MiB/sec

@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