From f0b7399705616c08b0f6751bd1b4e4e3d2d00ef2 Mon Sep 17 00:00:00 2001 From: Adam Reichold Date: Thu, 25 May 2023 19:57:33 +0200 Subject: [PATCH] Add benchmark showing that extract:: is costly due to PyNumber_Index trying hard. --- Cargo.toml | 4 + benches/bench_extract.rs | 169 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 benches/bench_extract.rs diff --git a/Cargo.toml b/Cargo.toml index 3a88149b..64d5969e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -169,6 +169,10 @@ harness = false name = "bench_intern" harness = false +[[bench]] +name = "bench_extract" +harness = false + [workspace] members = [ "pyo3-ffi", diff --git a/benches/bench_extract.rs b/benches/bench_extract.rs new file mode 100644 index 00000000..af454930 --- /dev/null +++ b/benches/bench_extract.rs @@ -0,0 +1,169 @@ +use criterion::{black_box, criterion_group, criterion_main, Bencher, Criterion}; + +use pyo3::{ + types::{PyDict, PyFloat, PyInt, PyString}, + IntoPy, PyAny, PyObject, Python, +}; + +fn extract_str_extract_success(bench: &mut Bencher<'_>) { + Python::with_gil(|py| { + let s = PyString::new(py, "Hello, World!") as &PyAny; + + bench.iter(|| { + let v = black_box(s).extract::<&str>().unwrap(); + black_box(v); + }); + }); +} + +fn extract_str_extract_fail(bench: &mut Bencher<'_>) { + Python::with_gil(|py| { + let d = PyDict::new(py) as &PyAny; + + bench.iter(|| match black_box(d).extract::<&str>() { + Ok(v) => panic!("should err {}", v), + Err(e) => black_box(e), + }); + }); +} + +fn extract_str_downcast_success(bench: &mut Bencher<'_>) { + Python::with_gil(|py| { + let s = PyString::new(py, "Hello, World!") as &PyAny; + + bench.iter(|| { + let py_str = black_box(s).downcast::().unwrap(); + let v = py_str.to_str().unwrap(); + black_box(v); + }); + }); +} + +fn extract_str_downcast_fail(bench: &mut Bencher<'_>) { + Python::with_gil(|py| { + let d = PyDict::new(py) as &PyAny; + + bench.iter(|| match black_box(d).downcast::() { + Ok(v) => panic!("should err {}", v), + Err(e) => black_box(e), + }); + }); +} + +fn extract_int_extract_success(bench: &mut Bencher<'_>) { + Python::with_gil(|py| { + let int_obj: PyObject = 123.into_py(py); + let int = int_obj.as_ref(py); + + bench.iter(|| { + let v = black_box(int).extract::().unwrap(); + black_box(v); + }); + }); +} + +fn extract_int_extract_fail(bench: &mut Bencher<'_>) { + Python::with_gil(|py| { + let d = PyDict::new(py) as &PyAny; + + bench.iter(|| match black_box(d).extract::() { + Ok(v) => panic!("should err {}", v), + Err(e) => black_box(e), + }); + }); +} + +fn extract_int_downcast_success(bench: &mut Bencher<'_>) { + Python::with_gil(|py| { + let int_obj: PyObject = 123.into_py(py); + let int = int_obj.as_ref(py); + + bench.iter(|| { + let py_int = black_box(int).downcast::().unwrap(); + let v = py_int.extract::().unwrap(); + black_box(v); + }); + }); +} + +fn extract_int_downcast_fail(bench: &mut Bencher<'_>) { + Python::with_gil(|py| { + let d = PyDict::new(py) as &PyAny; + + bench.iter(|| match black_box(d).downcast::() { + Ok(v) => panic!("should err {}", v), + Err(e) => black_box(e), + }); + }); +} + +fn extract_float_extract_success(bench: &mut Bencher<'_>) { + Python::with_gil(|py| { + let float_obj: PyObject = 23.42.into_py(py); + let float = float_obj.as_ref(py); + + bench.iter(|| { + let v = black_box(float).extract::().unwrap(); + black_box(v); + }); + }); +} + +fn extract_float_extract_fail(bench: &mut Bencher<'_>) { + Python::with_gil(|py| { + let d = PyDict::new(py) as &PyAny; + + bench.iter(|| match black_box(d).extract::() { + Ok(v) => panic!("should err {}", v), + Err(e) => black_box(e), + }); + }); +} + +fn extract_float_downcast_success(bench: &mut Bencher<'_>) { + Python::with_gil(|py| { + let float_obj: PyObject = 23.42.into_py(py); + let float = float_obj.as_ref(py); + + bench.iter(|| { + let py_int = black_box(float).downcast::().unwrap(); + let v = py_int.extract::().unwrap(); + black_box(v); + }); + }); +} + +fn extract_float_downcast_fail(bench: &mut Bencher<'_>) { + Python::with_gil(|py| { + let d = PyDict::new(py) as &PyAny; + + bench.iter(|| match black_box(d).downcast::() { + Ok(v) => panic!("should err {}", v), + Err(e) => black_box(e), + }); + }); +} + +fn criterion_benchmark(c: &mut Criterion) { + c.bench_function("extract_str_extract_success", extract_str_extract_success); + c.bench_function("extract_str_extract_fail", extract_str_extract_fail); + c.bench_function("extract_str_downcast_success", extract_str_downcast_success); + c.bench_function("extract_str_downcast_fail", extract_str_downcast_fail); + c.bench_function("extract_int_extract_success", extract_int_extract_success); + c.bench_function("extract_int_extract_fail", extract_int_extract_fail); + c.bench_function("extract_int_downcast_success", extract_int_downcast_success); + c.bench_function("extract_int_downcast_fail", extract_int_downcast_fail); + c.bench_function( + "extract_float_extract_success", + extract_float_extract_success, + ); + c.bench_function("extract_float_extract_fail", extract_float_extract_fail); + c.bench_function( + "extract_float_downcast_success", + extract_float_downcast_success, + ); + c.bench_function("extract_float_downcast_fail", extract_float_downcast_fail); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches);