diff --git a/src/_xxhash.c b/src/_xxhash.c index a7bc8ee..48063b9 100644 --- a/src/_xxhash.c +++ b/src/_xxhash.c @@ -82,6 +82,7 @@ _get_buffer_or_str(PyObject *obj, Py_buffer *buf, PyObject **owner) static Py_ALWAYS_INLINE int _parse_fastcall_args(PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames, const char *funcname, + int input_required, Py_buffer *buf, PyObject **buf_owner, unsigned long long *seed) { @@ -90,6 +91,7 @@ _parse_fastcall_args(PyObject *const *args, Py_ssize_t nargs, *seed = 0; buf->buf = NULL; + buf->obj = NULL; *buf_owner = NULL; /* positional args */ @@ -148,7 +150,7 @@ _parse_fastcall_args(PyObject *const *args, Py_ssize_t nargs, } } - if (!input_found) { + if (!input_found && input_required) { PyErr_Format(PyExc_TypeError, "%s() missing required argument 'input'", funcname); return -1; @@ -175,7 +177,7 @@ static PyObject *xxh32_digest(PyObject *self, PyObject *const *args, Py_buffer buf; PyObject *buf_owner; unsigned long long raw_seed; - if (_parse_fastcall_args(args, nargs, kwnames, "xxh32_digest", &buf, &buf_owner, &raw_seed) < 0) + if (_parse_fastcall_args(args, nargs, kwnames, "xxh32_digest", 1, &buf, &buf_owner, &raw_seed) < 0) return NULL; seed = (XXH32_hash_t)raw_seed; @@ -194,7 +196,7 @@ static PyObject *xxh32_intdigest(PyObject *self, PyObject *const *args, Py_buffer buf; PyObject *buf_owner; unsigned long long raw_seed; - if (_parse_fastcall_args(args, nargs, kwnames, "xxh32_intdigest", &buf, &buf_owner, &raw_seed) < 0) + if (_parse_fastcall_args(args, nargs, kwnames, "xxh32_intdigest", 1, &buf, &buf_owner, &raw_seed) < 0) return NULL; seed = (XXH32_hash_t)raw_seed; @@ -211,7 +213,7 @@ static PyObject *xxh32_hexdigest(PyObject *self, PyObject *const *args, Py_buffer buf; PyObject *buf_owner; unsigned long long raw_seed; - if (_parse_fastcall_args(args, nargs, kwnames, "xxh32_hexdigest", &buf, &buf_owner, &raw_seed) < 0) + if (_parse_fastcall_args(args, nargs, kwnames, "xxh32_hexdigest", 1, &buf, &buf_owner, &raw_seed) < 0) return NULL; seed = (XXH32_hash_t)raw_seed; @@ -245,7 +247,7 @@ static PyObject *xxh64_digest(PyObject *self, PyObject *const *args, Py_buffer buf; PyObject *buf_owner; unsigned long long raw_seed; - if (_parse_fastcall_args(args, nargs, kwnames, "xxh64_digest", &buf, &buf_owner, &raw_seed) < 0) + if (_parse_fastcall_args(args, nargs, kwnames, "xxh64_digest", 1, &buf, &buf_owner, &raw_seed) < 0) return NULL; seed = (XXH64_hash_t)raw_seed; @@ -264,7 +266,7 @@ static PyObject *xxh64_intdigest(PyObject *self, PyObject *const *args, Py_buffer buf; PyObject *buf_owner; unsigned long long raw_seed; - if (_parse_fastcall_args(args, nargs, kwnames, "xxh64_intdigest", &buf, &buf_owner, &raw_seed) < 0) + if (_parse_fastcall_args(args, nargs, kwnames, "xxh64_intdigest", 1, &buf, &buf_owner, &raw_seed) < 0) return NULL; seed = (XXH64_hash_t)raw_seed; @@ -281,7 +283,7 @@ static PyObject *xxh64_hexdigest(PyObject *self, PyObject *const *args, Py_buffer buf; PyObject *buf_owner; unsigned long long raw_seed; - if (_parse_fastcall_args(args, nargs, kwnames, "xxh64_hexdigest", &buf, &buf_owner, &raw_seed) < 0) + if (_parse_fastcall_args(args, nargs, kwnames, "xxh64_hexdigest", 1, &buf, &buf_owner, &raw_seed) < 0) return NULL; seed = (XXH64_hash_t)raw_seed; @@ -315,7 +317,7 @@ static PyObject *xxh3_64_digest(PyObject *self, PyObject *const *args, Py_buffer buf; PyObject *buf_owner; unsigned long long raw_seed; - if (_parse_fastcall_args(args, nargs, kwnames, "xxh3_64_digest", &buf, &buf_owner, &raw_seed) < 0) + if (_parse_fastcall_args(args, nargs, kwnames, "xxh3_64_digest", 1, &buf, &buf_owner, &raw_seed) < 0) return NULL; seed = (XXH64_hash_t)raw_seed; @@ -334,7 +336,7 @@ static PyObject *xxh3_64_intdigest(PyObject *self, PyObject *const *args, Py_buffer buf; PyObject *buf_owner; unsigned long long raw_seed; - if (_parse_fastcall_args(args, nargs, kwnames, "xxh3_64_intdigest", &buf, &buf_owner, &raw_seed) < 0) + if (_parse_fastcall_args(args, nargs, kwnames, "xxh3_64_intdigest", 1, &buf, &buf_owner, &raw_seed) < 0) return NULL; seed = (XXH64_hash_t)raw_seed; @@ -351,7 +353,7 @@ static PyObject *xxh3_64_hexdigest(PyObject *self, PyObject *const *args, Py_buffer buf; PyObject *buf_owner; unsigned long long raw_seed; - if (_parse_fastcall_args(args, nargs, kwnames, "xxh3_64_hexdigest", &buf, &buf_owner, &raw_seed) < 0) + if (_parse_fastcall_args(args, nargs, kwnames, "xxh3_64_hexdigest", 1, &buf, &buf_owner, &raw_seed) < 0) return NULL; seed = (XXH64_hash_t)raw_seed; @@ -385,7 +387,7 @@ static PyObject *xxh3_128_digest(PyObject *self, PyObject *const *args, Py_buffer buf; PyObject *buf_owner; unsigned long long raw_seed; - if (_parse_fastcall_args(args, nargs, kwnames, "xxh3_128_digest", &buf, &buf_owner, &raw_seed) < 0) + if (_parse_fastcall_args(args, nargs, kwnames, "xxh3_128_digest", 1, &buf, &buf_owner, &raw_seed) < 0) return NULL; seed = (XXH64_hash_t)raw_seed; @@ -404,7 +406,7 @@ static PyObject *xxh3_128_intdigest(PyObject *self, PyObject *const *args, Py_buffer buf; PyObject *buf_owner; unsigned long long raw_seed; - if (_parse_fastcall_args(args, nargs, kwnames, "xxh3_128_intdigest", &buf, &buf_owner, &raw_seed) < 0) + if (_parse_fastcall_args(args, nargs, kwnames, "xxh3_128_intdigest", 1, &buf, &buf_owner, &raw_seed) < 0) return NULL; seed = (XXH64_hash_t)raw_seed; @@ -436,7 +438,7 @@ static PyObject *xxh3_128_hexdigest(PyObject *self, PyObject *const *args, Py_buffer buf; PyObject *buf_owner; unsigned long long raw_seed; - if (_parse_fastcall_args(args, nargs, kwnames, "xxh3_128_hexdigest", &buf, &buf_owner, &raw_seed) < 0) + if (_parse_fastcall_args(args, nargs, kwnames, "xxh3_128_hexdigest", 1, &buf, &buf_owner, &raw_seed) < 0) return NULL; seed = (XXH64_hash_t)raw_seed; @@ -493,6 +495,45 @@ static void PYXXH32_do_update(PYXXH32Object *self, Py_buffer *buf) PyBuffer_Release(buf); } +static PyObject * +PYXXH32_vectorcall(PyObject *type, PyObject *const *args, + size_t nargsf, PyObject *kwnames) +{ + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); + XXH32_hash_t seed = 0; + Py_buffer buf; + PyObject *buf_owner; + unsigned long long raw_seed; + + if (_parse_fastcall_args(args, nargs, kwnames, "xxhash.xxh32()", 0, + &buf, &buf_owner, &raw_seed) < 0) + return NULL; + seed = (XXH32_hash_t)raw_seed; + + PYXXH32Object *self = (PYXXH32Object *) + ((PyTypeObject *)type)->tp_alloc((PyTypeObject *)type, 0); + if (self == NULL) { + PyBuffer_Release(&buf); + Py_XDECREF(buf_owner); + return NULL; + } + + self->xxhash_state = XXH32_createState(); + if (self->xxhash_state == NULL) { + Py_DECREF(self); + PyBuffer_Release(&buf); + Py_XDECREF(buf_owner); + return PyErr_NoMemory(); + } + self->seed = seed; + XXH32_reset(self->xxhash_state, seed); + + if (buf.obj) + PYXXH32_do_update(self, &buf); + Py_XDECREF(buf_owner); + return (PyObject *)self; +} + /* XXH32 methods */ static PyObject *PYXXH32_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) @@ -530,7 +571,7 @@ static int PYXXH32_init(PYXXH32Object *self, PyObject *args, PyObject *kwargs) self->seed = seed; XXH32_reset(self->xxhash_state, seed); - if (buf.buf) { + if (buf.obj) { PYXXH32_do_update(self, &buf); } @@ -753,7 +794,7 @@ static PyTypeObject PYXXH32Type = { 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_VECTORCALL, /* tp_flags */ PYXXH32Type_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ @@ -772,6 +813,17 @@ static PyTypeObject PYXXH32Type = { (initproc)PYXXH32_init, /* tp_init */ 0, /* tp_alloc */ PYXXH32_new, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ + PYXXH32_vectorcall, /* tp_vectorcall */ }; @@ -802,6 +854,44 @@ static void PYXXH64_do_update(PYXXH64Object *self, Py_buffer *buf) PyBuffer_Release(buf); } +static PyObject * +PYXXH64_vectorcall(PyObject *type, PyObject *const *args, + size_t nargsf, PyObject *kwnames) +{ + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); + XXH64_hash_t seed = 0; + Py_buffer buf; + PyObject *buf_owner; + unsigned long long raw_seed; + + if (_parse_fastcall_args(args, nargs, kwnames, "xxhash.xxh64()", 0, + &buf, &buf_owner, &raw_seed) < 0) + return NULL; + seed = (XXH64_hash_t)raw_seed; + + PYXXH64Object *self = (PYXXH64Object *) + ((PyTypeObject *)type)->tp_alloc((PyTypeObject *)type, 0); + if (self == NULL) { + PyBuffer_Release(&buf); + Py_XDECREF(buf_owner); + return NULL; + } + + self->xxhash_state = XXH64_createState(); + if (self->xxhash_state == NULL) { + Py_DECREF(self); + PyBuffer_Release(&buf); + Py_XDECREF(buf_owner); + return PyErr_NoMemory(); + } + self->seed = seed; + XXH64_reset(self->xxhash_state, seed); + + if (buf.obj) + PYXXH64_do_update(self, &buf); + Py_XDECREF(buf_owner); + return (PyObject *)self; +} static PyObject *PYXXH64_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { PYXXH64Object *self; @@ -837,7 +927,7 @@ static int PYXXH64_init(PYXXH64Object *self, PyObject *args, PyObject *kwargs) self->seed = seed; XXH64_reset(self->xxhash_state, seed); - if (buf.buf) { + if (buf.obj) { PYXXH64_do_update(self, &buf); } @@ -1060,7 +1150,7 @@ static PyTypeObject PYXXH64Type = { 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_VECTORCALL, /* tp_flags */ PYXXH64Type_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ @@ -1079,6 +1169,17 @@ static PyTypeObject PYXXH64Type = { (initproc)PYXXH64_init, /* tp_init */ 0, /* tp_alloc */ PYXXH64_new, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ + PYXXH64_vectorcall, /* tp_vectorcall */ }; /* XXH3_64 */ @@ -1108,6 +1209,44 @@ static void PYXXH3_64_do_update(PYXXH3_64Object *self, Py_buffer *buf) PyBuffer_Release(buf); } +static PyObject * +PYXXH3_64_vectorcall(PyObject *type, PyObject *const *args, + size_t nargsf, PyObject *kwnames) +{ + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); + XXH64_hash_t seed = 0; + Py_buffer buf; + PyObject *buf_owner; + unsigned long long raw_seed; + + if (_parse_fastcall_args(args, nargs, kwnames, "xxhash.xxh3_64()", 0, + &buf, &buf_owner, &raw_seed) < 0) + return NULL; + seed = (XXH64_hash_t)raw_seed; + + PYXXH3_64Object *self = (PYXXH3_64Object *) + ((PyTypeObject *)type)->tp_alloc((PyTypeObject *)type, 0); + if (self == NULL) { + PyBuffer_Release(&buf); + Py_XDECREF(buf_owner); + return NULL; + } + + self->xxhash_state = XXH3_createState(); + if (self->xxhash_state == NULL) { + Py_DECREF(self); + PyBuffer_Release(&buf); + Py_XDECREF(buf_owner); + return PyErr_NoMemory(); + } + self->seed = seed; + XXH3_64bits_reset_withSeed(self->xxhash_state, seed); + + if (buf.obj) + PYXXH3_64_do_update(self, &buf); + Py_XDECREF(buf_owner); + return (PyObject *)self; +} static PyObject *PYXXH3_64_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { PYXXH3_64Object *self; @@ -1143,7 +1282,7 @@ static int PYXXH3_64_init(PYXXH3_64Object *self, PyObject *args, PyObject *kwarg self->seed = seed; XXH3_64bits_reset_withSeed(self->xxhash_state, seed); - if (buf.buf) { + if (buf.obj) { PYXXH3_64_do_update(self, &buf); } @@ -1374,7 +1513,7 @@ static PyTypeObject PYXXH3_64Type = { 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_VECTORCALL, /* tp_flags */ PYXXH3_64Type_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ @@ -1393,6 +1532,17 @@ static PyTypeObject PYXXH3_64Type = { (initproc)PYXXH3_64_init, /* tp_init */ 0, /* tp_alloc */ PYXXH3_64_new, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ + PYXXH3_64_vectorcall, /* tp_vectorcall */ }; @@ -1423,6 +1573,44 @@ static void PYXXH3_128_do_update(PYXXH3_128Object *self, Py_buffer *buf) PyBuffer_Release(buf); } +static PyObject * +PYXXH3_128_vectorcall(PyObject *type, PyObject *const *args, + size_t nargsf, PyObject *kwnames) +{ + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); + XXH64_hash_t seed = 0; + Py_buffer buf; + PyObject *buf_owner; + unsigned long long raw_seed; + + if (_parse_fastcall_args(args, nargs, kwnames, "xxhash.xxh3_128()", 0, + &buf, &buf_owner, &raw_seed) < 0) + return NULL; + seed = (XXH64_hash_t)raw_seed; + + PYXXH3_128Object *self = (PYXXH3_128Object *) + ((PyTypeObject *)type)->tp_alloc((PyTypeObject *)type, 0); + if (self == NULL) { + PyBuffer_Release(&buf); + Py_XDECREF(buf_owner); + return NULL; + } + + self->xxhash_state = XXH3_createState(); + if (self->xxhash_state == NULL) { + Py_DECREF(self); + PyBuffer_Release(&buf); + Py_XDECREF(buf_owner); + return PyErr_NoMemory(); + } + self->seed = seed; + XXH3_128bits_reset_withSeed(self->xxhash_state, seed); + + if (buf.obj) + PYXXH3_128_do_update(self, &buf); + Py_XDECREF(buf_owner); + return (PyObject *)self; +} static PyObject *PYXXH3_128_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { PYXXH3_128Object *self; @@ -1458,7 +1646,7 @@ static int PYXXH3_128_init(PYXXH3_128Object *self, PyObject *args, PyObject *kwa self->seed = seed; XXH3_128bits_reset_withSeed(self->xxhash_state, seed); - if (buf.buf) { + if (buf.obj) { PYXXH3_128_do_update(self, &buf); } @@ -1706,7 +1894,7 @@ static PyTypeObject PYXXH3_128Type = { 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_VECTORCALL, /* tp_flags */ PYXXH3_128Type_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ @@ -1725,6 +1913,17 @@ static PyTypeObject PYXXH3_128Type = { (initproc)PYXXH3_128_init, /* tp_init */ 0, /* tp_alloc */ PYXXH3_128_new, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ + PYXXH3_128_vectorcall, /* tp_vectorcall */ }; /***************************************************************************** diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py index c92dc78..b915f52 100644 --- a/tests/test_benchmark.py +++ b/tests/test_benchmark.py @@ -5,16 +5,16 @@ import xxhash +SEED_32 = random.randint(0, 0xFFFFFFFF) +SEED_64 = random.randint(0, 0xFFFFFFFFFFFFFFFF) + +DATA_5B = os.urandom(5) DATA_1KB = os.urandom(1000) DATA_10KB = os.urandom(10000) -DATA_512KB = os.urandom(512000) DATA_2MB = os.urandom(2 * 1024 * 1024) -SEED_32 = random.randint(0, 0xFFFFFFFF) -SEED_64 = random.randint(0, 0xFFFFFFFFFFFFFFFF) - -# -- xxh32 oneshot -- +# ── macro bench: larger inputs where hashing dominates ─────────────── @pytest.mark.benchmark @@ -22,127 +22,6 @@ def test_xxh32_intdigest_1kb(): xxhash.xxh32_intdigest(DATA_1KB, seed=SEED_32) -@pytest.mark.benchmark -def test_xxh32_intdigest_10kb(): - xxhash.xxh32_intdigest(DATA_10KB, seed=SEED_32) - - -@pytest.mark.benchmark -def test_xxh32_intdigest_512kb(): - xxhash.xxh32_intdigest(DATA_512KB, seed=SEED_32) - - -@pytest.mark.benchmark -def test_xxh32_intdigest_2mb(): - xxhash.xxh32_intdigest(DATA_2MB, seed=SEED_32) - - -@pytest.mark.benchmark -def test_xxh32_hexdigest_1kb(): - xxhash.xxh32_hexdigest(DATA_1KB, seed=SEED_32) - - -@pytest.mark.benchmark -def test_xxh32_hexdigest_10kb(): - xxhash.xxh32_hexdigest(DATA_10KB, seed=SEED_32) - - -@pytest.mark.benchmark -def test_xxh32_hexdigest_512kb(): - xxhash.xxh32_hexdigest(DATA_512KB, seed=SEED_32) - - -@pytest.mark.benchmark -def test_xxh32_hexdigest_2mb(): - xxhash.xxh32_hexdigest(DATA_2MB, seed=SEED_32) - - -@pytest.mark.benchmark -def test_xxh32_digest_1kb(): - xxhash.xxh32_digest(DATA_1KB, seed=SEED_32) - - -@pytest.mark.benchmark -def test_xxh32_digest_10kb(): - xxhash.xxh32_digest(DATA_10KB, seed=SEED_32) - - -@pytest.mark.benchmark -def test_xxh32_digest_512kb(): - xxhash.xxh32_digest(DATA_512KB, seed=SEED_32) - - -@pytest.mark.benchmark -def test_xxh32_digest_2mb(): - xxhash.xxh32_digest(DATA_2MB, seed=SEED_32) - - -# -- xxh64 oneshot -- - - -@pytest.mark.benchmark -def test_xxh64_intdigest_1kb(): - xxhash.xxh64_intdigest(DATA_1KB, seed=SEED_64) - - -@pytest.mark.benchmark -def test_xxh64_intdigest_10kb(): - xxhash.xxh64_intdigest(DATA_10KB, seed=SEED_64) - - -@pytest.mark.benchmark -def test_xxh64_intdigest_512kb(): - xxhash.xxh64_intdigest(DATA_512KB, seed=SEED_64) - - -@pytest.mark.benchmark -def test_xxh64_intdigest_2mb(): - xxhash.xxh64_intdigest(DATA_2MB, seed=SEED_64) - - -@pytest.mark.benchmark -def test_xxh64_hexdigest_1kb(): - xxhash.xxh64_hexdigest(DATA_1KB, seed=SEED_64) - - -@pytest.mark.benchmark -def test_xxh64_hexdigest_10kb(): - xxhash.xxh64_hexdigest(DATA_10KB, seed=SEED_64) - - -@pytest.mark.benchmark -def test_xxh64_hexdigest_512kb(): - xxhash.xxh64_hexdigest(DATA_512KB, seed=SEED_64) - - -@pytest.mark.benchmark -def test_xxh64_hexdigest_2mb(): - xxhash.xxh64_hexdigest(DATA_2MB, seed=SEED_64) - - -@pytest.mark.benchmark -def test_xxh64_digest_1kb(): - xxhash.xxh64_digest(DATA_1KB, seed=SEED_64) - - -@pytest.mark.benchmark -def test_xxh64_digest_10kb(): - xxhash.xxh64_digest(DATA_10KB, seed=SEED_64) - - -@pytest.mark.benchmark -def test_xxh64_digest_512kb(): - xxhash.xxh64_digest(DATA_512KB, seed=SEED_64) - - -@pytest.mark.benchmark -def test_xxh64_digest_2mb(): - xxhash.xxh64_digest(DATA_2MB, seed=SEED_64) - - -# -- xxh3_64 oneshot -- - - @pytest.mark.benchmark def test_xxh3_64_intdigest_1kb(): xxhash.xxh3_64_intdigest(DATA_1KB, seed=SEED_64) @@ -154,533 +33,173 @@ def test_xxh3_64_intdigest_10kb(): @pytest.mark.benchmark -def test_xxh3_64_intdigest_512kb(): - xxhash.xxh3_64_intdigest(DATA_512KB, seed=SEED_64) +def test_xxh3_128_intdigest_1kb(): + xxhash.xxh3_128_intdigest(DATA_1KB, seed=SEED_64) -@pytest.mark.benchmark -def test_xxh3_64_intdigest_2mb(): - xxhash.xxh3_64_intdigest(DATA_2MB, seed=SEED_64) +# ── micro bench: tiny inputs where call overhead dominates ─────────── @pytest.mark.benchmark -def test_xxh3_64_hexdigest_1kb(): - xxhash.xxh3_64_hexdigest(DATA_1KB, seed=SEED_64) +def test_xxh32_intdigest_5b(): + xxhash.xxh32_intdigest(DATA_5B) @pytest.mark.benchmark -def test_xxh3_64_hexdigest_10kb(): - xxhash.xxh3_64_hexdigest(DATA_10KB, seed=SEED_64) +def test_xxh32_intdigest_5b_seed(): + xxhash.xxh32_intdigest(DATA_5B, seed=SEED_32) @pytest.mark.benchmark -def test_xxh3_64_hexdigest_512kb(): - xxhash.xxh3_64_hexdigest(DATA_512KB, seed=SEED_64) +def test_xxh32_intdigest_5b_seed_kw(): + xxhash.xxh32_intdigest(DATA_5B, seed=SEED_32) @pytest.mark.benchmark -def test_xxh3_64_hexdigest_2mb(): - xxhash.xxh3_64_hexdigest(DATA_2MB, seed=SEED_64) +def test_xxh64_intdigest_5b(): + xxhash.xxh64_intdigest(DATA_5B) @pytest.mark.benchmark -def test_xxh3_64_digest_1kb(): - xxhash.xxh3_64_digest(DATA_1KB, seed=SEED_64) +def test_xxh64_intdigest_5b_seed_kw(): + xxhash.xxh64_intdigest(DATA_5B, seed=SEED_64) @pytest.mark.benchmark -def test_xxh3_64_digest_10kb(): - xxhash.xxh3_64_digest(DATA_10KB, seed=SEED_64) +def test_xxh3_64_intdigest_5b(): + xxhash.xxh3_64_intdigest(DATA_5B) @pytest.mark.benchmark -def test_xxh3_64_digest_512kb(): - xxhash.xxh3_64_digest(DATA_512KB, seed=SEED_64) +def test_xxh3_64_intdigest_5b_seed_kw(): + xxhash.xxh3_64_intdigest(DATA_5B, seed=SEED_64) @pytest.mark.benchmark -def test_xxh3_64_digest_2mb(): - xxhash.xxh3_64_digest(DATA_2MB, seed=SEED_64) - - -# -- xxh3_128 oneshot -- +def test_xxh3_128_intdigest_5b(): + xxhash.xxh3_128_intdigest(DATA_5B) @pytest.mark.benchmark -def test_xxh3_128_intdigest_1kb(): - xxhash.xxh3_128_intdigest(DATA_1KB, seed=SEED_64) +def test_xxh32_hexdigest_5b(): + xxhash.xxh32_hexdigest(DATA_5B) @pytest.mark.benchmark -def test_xxh3_128_intdigest_10kb(): - xxhash.xxh3_128_intdigest(DATA_10KB, seed=SEED_64) +def test_xxh64_hexdigest_5b(): + xxhash.xxh64_hexdigest(DATA_5B) -@pytest.mark.benchmark -def test_xxh3_128_intdigest_512kb(): - xxhash.xxh3_128_intdigest(DATA_512KB, seed=SEED_64) - - -@pytest.mark.benchmark -def test_xxh3_128_intdigest_2mb(): - xxhash.xxh3_128_intdigest(DATA_2MB, seed=SEED_64) +# ── str input (tests _get_buffer_or_str UTF-8 encoding path) ──────── - -@pytest.mark.benchmark -def test_xxh3_128_hexdigest_1kb(): - xxhash.xxh3_128_hexdigest(DATA_1KB, seed=SEED_64) +DATA_STR = "hello world" @pytest.mark.benchmark -def test_xxh3_128_hexdigest_10kb(): - xxhash.xxh3_128_hexdigest(DATA_10KB, seed=SEED_64) +def test_xxh32_intdigest_str(): + xxhash.xxh32_intdigest(DATA_STR) @pytest.mark.benchmark -def test_xxh3_128_hexdigest_512kb(): - xxhash.xxh3_128_hexdigest(DATA_512KB, seed=SEED_64) +def test_xxh64_intdigest_str(): + xxhash.xxh64_intdigest(DATA_STR) @pytest.mark.benchmark -def test_xxh3_128_hexdigest_2mb(): - xxhash.xxh3_128_hexdigest(DATA_2MB, seed=SEED_64) +def test_xxh3_64_intdigest_str(): + xxhash.xxh3_64_intdigest(DATA_STR) @pytest.mark.benchmark -def test_xxh3_128_digest_1kb(): - xxhash.xxh3_128_digest(DATA_1KB, seed=SEED_64) +def test_xxh3_128_intdigest_str(): + xxhash.xxh3_128_intdigest(DATA_STR) -@pytest.mark.benchmark -def test_xxh3_128_digest_10kb(): - xxhash.xxh3_128_digest(DATA_10KB, seed=SEED_64) +# ── type constructor (tests tp_vectorcall) ────────────────────────── @pytest.mark.benchmark -def test_xxh3_128_digest_512kb(): - xxhash.xxh3_128_digest(DATA_512KB, seed=SEED_64) +def test_xxh32_ctor(): + xxhash.xxh32(DATA_STR) @pytest.mark.benchmark -def test_xxh3_128_digest_2mb(): - xxhash.xxh3_128_digest(DATA_2MB, seed=SEED_64) - - -# -- xxh32 streaming intdigest -- +def test_xxh32_ctor_seed(): + xxhash.xxh32(DATA_STR, seed=SEED_32) @pytest.mark.benchmark -def test_xxh32_streaming_intdigest_1kb(): - h = xxhash.xxh32(seed=SEED_32) - for _ in range(10): - h.update(DATA_1KB) - h.intdigest() +def test_xxh32_ctor_empty(): + xxhash.xxh32() @pytest.mark.benchmark -def test_xxh32_streaming_intdigest_10kb(): - h = xxhash.xxh32(seed=SEED_32) - for _ in range(10): - h.update(DATA_10KB) - h.intdigest() +def test_xxh64_ctor(): + xxhash.xxh64(DATA_STR, seed=SEED_64) @pytest.mark.benchmark -def test_xxh32_streaming_intdigest_512kb(): - h = xxhash.xxh32(seed=SEED_32) - for _ in range(10): - h.update(DATA_512KB) - h.intdigest() +def test_xxh3_64_ctor(): + xxhash.xxh3_64(DATA_STR, seed=SEED_64) @pytest.mark.benchmark -def test_xxh32_streaming_intdigest_2mb(): - h = xxhash.xxh32(seed=SEED_32) - for _ in range(10): - h.update(DATA_2MB) - h.intdigest() +def test_xxh3_128_ctor(): + xxhash.xxh3_128(DATA_STR, seed=SEED_64) -# -- xxh64 streaming intdigest -- +# ── 2MB throughput: hashing dominates, call overhead negligible ───── @pytest.mark.benchmark -def test_xxh64_streaming_intdigest_1kb(): - h = xxhash.xxh64(seed=SEED_64) - for _ in range(10): - h.update(DATA_1KB) - h.intdigest() - - -@pytest.mark.benchmark -def test_xxh64_streaming_intdigest_10kb(): - h = xxhash.xxh64(seed=SEED_64) - for _ in range(10): - h.update(DATA_10KB) - h.intdigest() - - -@pytest.mark.benchmark -def test_xxh64_streaming_intdigest_512kb(): - h = xxhash.xxh64(seed=SEED_64) - for _ in range(10): - h.update(DATA_512KB) - h.intdigest() +def test_xxh32_intdigest_2mb(): + xxhash.xxh32_intdigest(DATA_2MB, seed=SEED_32) @pytest.mark.benchmark -def test_xxh64_streaming_intdigest_2mb(): - h = xxhash.xxh64(seed=SEED_64) - for _ in range(10): - h.update(DATA_2MB) - h.intdigest() - - -# -- xxh3_64 streaming intdigest -- +def test_xxh64_intdigest_2mb(): + xxhash.xxh64_intdigest(DATA_2MB, seed=SEED_64) @pytest.mark.benchmark -def test_xxh3_64_streaming_intdigest_1kb(): - h = xxhash.xxh3_64(seed=SEED_64) - for _ in range(10): - h.update(DATA_1KB) - h.intdigest() +def test_xxh3_64_intdigest_2mb(): + xxhash.xxh3_64_intdigest(DATA_2MB, seed=SEED_64) @pytest.mark.benchmark -def test_xxh3_64_streaming_intdigest_10kb(): - h = xxhash.xxh3_64(seed=SEED_64) - for _ in range(10): - h.update(DATA_10KB) - h.intdigest() +def test_xxh3_128_intdigest_2mb(): + xxhash.xxh3_128_intdigest(DATA_2MB, seed=SEED_64) @pytest.mark.benchmark -def test_xxh3_64_streaming_intdigest_512kb(): - h = xxhash.xxh3_64(seed=SEED_64) - for _ in range(10): - h.update(DATA_512KB) - h.intdigest() +def test_xxh32_hexdigest_2mb(): + xxhash.xxh32_hexdigest(DATA_2MB, seed=SEED_32) @pytest.mark.benchmark -def test_xxh3_64_streaming_intdigest_2mb(): - h = xxhash.xxh3_64(seed=SEED_64) - for _ in range(10): - h.update(DATA_2MB) - h.intdigest() - - -# -- xxh3_128 streaming intdigest -- +def test_xxh3_64_hexdigest_2mb(): + xxhash.xxh3_64_hexdigest(DATA_2MB, seed=SEED_64) @pytest.mark.benchmark -def test_xxh3_128_streaming_intdigest_1kb(): - h = xxhash.xxh3_128(seed=SEED_64) - for _ in range(10): - h.update(DATA_1KB) +def test_xxh32_stream_intdigest_2mb(): + h = xxhash.xxh32(DATA_2MB, seed=SEED_32) h.intdigest() @pytest.mark.benchmark -def test_xxh3_128_streaming_intdigest_10kb(): - h = xxhash.xxh3_128(seed=SEED_64) - for _ in range(10): - h.update(DATA_10KB) +def test_xxh64_stream_intdigest_2mb(): + h = xxhash.xxh64(DATA_2MB, seed=SEED_64) h.intdigest() @pytest.mark.benchmark -def test_xxh3_128_streaming_intdigest_512kb(): - h = xxhash.xxh3_128(seed=SEED_64) - for _ in range(10): - h.update(DATA_512KB) +def test_xxh3_64_stream_intdigest_2mb(): + h = xxhash.xxh3_64(DATA_2MB, seed=SEED_64) h.intdigest() @pytest.mark.benchmark -def test_xxh3_128_streaming_intdigest_2mb(): - h = xxhash.xxh3_128(seed=SEED_64) - for _ in range(10): - h.update(DATA_2MB) +def test_xxh3_128_stream_intdigest_2mb(): + h = xxhash.xxh3_128(DATA_2MB, seed=SEED_64) h.intdigest() - - -# -- xxh32 streaming hexdigest -- - - -@pytest.mark.benchmark -def test_xxh32_streaming_hexdigest_1kb(): - h = xxhash.xxh32(seed=SEED_32) - for _ in range(10): - h.update(DATA_1KB) - h.hexdigest() - - -@pytest.mark.benchmark -def test_xxh32_streaming_hexdigest_10kb(): - h = xxhash.xxh32(seed=SEED_32) - for _ in range(10): - h.update(DATA_10KB) - h.hexdigest() - - -@pytest.mark.benchmark -def test_xxh32_streaming_hexdigest_512kb(): - h = xxhash.xxh32(seed=SEED_32) - for _ in range(10): - h.update(DATA_512KB) - h.hexdigest() - - -@pytest.mark.benchmark -def test_xxh32_streaming_hexdigest_2mb(): - h = xxhash.xxh32(seed=SEED_32) - for _ in range(10): - h.update(DATA_2MB) - h.hexdigest() - - -# -- xxh64 streaming hexdigest -- - - -@pytest.mark.benchmark -def test_xxh64_streaming_hexdigest_1kb(): - h = xxhash.xxh64(seed=SEED_64) - for _ in range(10): - h.update(DATA_1KB) - h.hexdigest() - - -@pytest.mark.benchmark -def test_xxh64_streaming_hexdigest_10kb(): - h = xxhash.xxh64(seed=SEED_64) - for _ in range(10): - h.update(DATA_10KB) - h.hexdigest() - - -@pytest.mark.benchmark -def test_xxh64_streaming_hexdigest_512kb(): - h = xxhash.xxh64(seed=SEED_64) - for _ in range(10): - h.update(DATA_512KB) - h.hexdigest() - - -@pytest.mark.benchmark -def test_xxh64_streaming_hexdigest_2mb(): - h = xxhash.xxh64(seed=SEED_64) - for _ in range(10): - h.update(DATA_2MB) - h.hexdigest() - - -# -- xxh3_64 streaming hexdigest -- - - -@pytest.mark.benchmark -def test_xxh3_64_streaming_hexdigest_1kb(): - h = xxhash.xxh3_64(seed=SEED_64) - for _ in range(10): - h.update(DATA_1KB) - h.hexdigest() - - -@pytest.mark.benchmark -def test_xxh3_64_streaming_hexdigest_10kb(): - h = xxhash.xxh3_64(seed=SEED_64) - for _ in range(10): - h.update(DATA_10KB) - h.hexdigest() - - -@pytest.mark.benchmark -def test_xxh3_64_streaming_hexdigest_512kb(): - h = xxhash.xxh3_64(seed=SEED_64) - for _ in range(10): - h.update(DATA_512KB) - h.hexdigest() - - -@pytest.mark.benchmark -def test_xxh3_64_streaming_hexdigest_2mb(): - h = xxhash.xxh3_64(seed=SEED_64) - for _ in range(10): - h.update(DATA_2MB) - h.hexdigest() - - -# -- xxh3_128 streaming hexdigest -- - - -@pytest.mark.benchmark -def test_xxh3_128_streaming_hexdigest_1kb(): - h = xxhash.xxh3_128(seed=SEED_64) - for _ in range(10): - h.update(DATA_1KB) - h.hexdigest() - - -@pytest.mark.benchmark -def test_xxh3_128_streaming_hexdigest_10kb(): - h = xxhash.xxh3_128(seed=SEED_64) - for _ in range(10): - h.update(DATA_10KB) - h.hexdigest() - - -@pytest.mark.benchmark -def test_xxh3_128_streaming_hexdigest_512kb(): - h = xxhash.xxh3_128(seed=SEED_64) - for _ in range(10): - h.update(DATA_512KB) - h.hexdigest() - - -@pytest.mark.benchmark -def test_xxh3_128_streaming_hexdigest_2mb(): - h = xxhash.xxh3_128(seed=SEED_64) - for _ in range(10): - h.update(DATA_2MB) - h.hexdigest() - - -# -- xxh32 streaming digest -- - - -@pytest.mark.benchmark -def test_xxh32_streaming_digest_1kb(): - h = xxhash.xxh32(seed=SEED_32) - for _ in range(10): - h.update(DATA_1KB) - h.digest() - - -@pytest.mark.benchmark -def test_xxh32_streaming_digest_10kb(): - h = xxhash.xxh32(seed=SEED_32) - for _ in range(10): - h.update(DATA_10KB) - h.digest() - - -@pytest.mark.benchmark -def test_xxh32_streaming_digest_512kb(): - h = xxhash.xxh32(seed=SEED_32) - for _ in range(10): - h.update(DATA_512KB) - h.digest() - - -@pytest.mark.benchmark -def test_xxh32_streaming_digest_2mb(): - h = xxhash.xxh32(seed=SEED_32) - for _ in range(10): - h.update(DATA_2MB) - h.digest() - - -# -- xxh64 streaming digest -- - - -@pytest.mark.benchmark -def test_xxh64_streaming_digest_1kb(): - h = xxhash.xxh64(seed=SEED_64) - for _ in range(10): - h.update(DATA_1KB) - h.digest() - - -@pytest.mark.benchmark -def test_xxh64_streaming_digest_10kb(): - h = xxhash.xxh64(seed=SEED_64) - for _ in range(10): - h.update(DATA_10KB) - h.digest() - - -@pytest.mark.benchmark -def test_xxh64_streaming_digest_512kb(): - h = xxhash.xxh64(seed=SEED_64) - for _ in range(10): - h.update(DATA_512KB) - h.digest() - - -@pytest.mark.benchmark -def test_xxh64_streaming_digest_2mb(): - h = xxhash.xxh64(seed=SEED_64) - for _ in range(10): - h.update(DATA_2MB) - h.digest() - - -# -- xxh3_64 streaming digest -- - - -@pytest.mark.benchmark -def test_xxh3_64_streaming_digest_1kb(): - h = xxhash.xxh3_64(seed=SEED_64) - for _ in range(10): - h.update(DATA_1KB) - h.digest() - - -@pytest.mark.benchmark -def test_xxh3_64_streaming_digest_10kb(): - h = xxhash.xxh3_64(seed=SEED_64) - for _ in range(10): - h.update(DATA_10KB) - h.digest() - - -@pytest.mark.benchmark -def test_xxh3_64_streaming_digest_512kb(): - h = xxhash.xxh3_64(seed=SEED_64) - for _ in range(10): - h.update(DATA_512KB) - h.digest() - - -@pytest.mark.benchmark -def test_xxh3_64_streaming_digest_2mb(): - h = xxhash.xxh3_64(seed=SEED_64) - for _ in range(10): - h.update(DATA_2MB) - h.digest() - - -# -- xxh3_128 streaming digest -- - - -@pytest.mark.benchmark -def test_xxh3_128_streaming_digest_1kb(): - h = xxhash.xxh3_128(seed=SEED_64) - for _ in range(10): - h.update(DATA_1KB) - h.digest() - - -@pytest.mark.benchmark -def test_xxh3_128_streaming_digest_10kb(): - h = xxhash.xxh3_128(seed=SEED_64) - for _ in range(10): - h.update(DATA_10KB) - h.digest() - - -@pytest.mark.benchmark -def test_xxh3_128_streaming_digest_512kb(): - h = xxhash.xxh3_128(seed=SEED_64) - for _ in range(10): - h.update(DATA_512KB) - h.digest() - - -@pytest.mark.benchmark -def test_xxh3_128_streaming_digest_2mb(): - h = xxhash.xxh3_128(seed=SEED_64) - for _ in range(10): - h.update(DATA_2MB) - h.digest()