Skip to content

Commit cd4b27f

Browse files
Merge #3183
3183: Add benchmark showing that extract::<i64> is costly due to PyNumber_Index trying hard. r=davidhewitt a=adamreichold The benchmarks from #3182 to keep around for later and to play around with. Co-authored-by: Adam Reichold <adam.reichold@t-online.de>
2 parents 0e50338 + f0b7399 commit cd4b27f

File tree

2 files changed

+173
-0
lines changed

2 files changed

+173
-0
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,10 @@ harness = false
169169
name = "bench_intern"
170170
harness = false
171171

172+
[[bench]]
173+
name = "bench_extract"
174+
harness = false
175+
172176
[workspace]
173177
members = [
174178
"pyo3-ffi",

benches/bench_extract.rs

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
use criterion::{black_box, criterion_group, criterion_main, Bencher, Criterion};
2+
3+
use pyo3::{
4+
types::{PyDict, PyFloat, PyInt, PyString},
5+
IntoPy, PyAny, PyObject, Python,
6+
};
7+
8+
fn extract_str_extract_success(bench: &mut Bencher<'_>) {
9+
Python::with_gil(|py| {
10+
let s = PyString::new(py, "Hello, World!") as &PyAny;
11+
12+
bench.iter(|| {
13+
let v = black_box(s).extract::<&str>().unwrap();
14+
black_box(v);
15+
});
16+
});
17+
}
18+
19+
fn extract_str_extract_fail(bench: &mut Bencher<'_>) {
20+
Python::with_gil(|py| {
21+
let d = PyDict::new(py) as &PyAny;
22+
23+
bench.iter(|| match black_box(d).extract::<&str>() {
24+
Ok(v) => panic!("should err {}", v),
25+
Err(e) => black_box(e),
26+
});
27+
});
28+
}
29+
30+
fn extract_str_downcast_success(bench: &mut Bencher<'_>) {
31+
Python::with_gil(|py| {
32+
let s = PyString::new(py, "Hello, World!") as &PyAny;
33+
34+
bench.iter(|| {
35+
let py_str = black_box(s).downcast::<PyString>().unwrap();
36+
let v = py_str.to_str().unwrap();
37+
black_box(v);
38+
});
39+
});
40+
}
41+
42+
fn extract_str_downcast_fail(bench: &mut Bencher<'_>) {
43+
Python::with_gil(|py| {
44+
let d = PyDict::new(py) as &PyAny;
45+
46+
bench.iter(|| match black_box(d).downcast::<PyString>() {
47+
Ok(v) => panic!("should err {}", v),
48+
Err(e) => black_box(e),
49+
});
50+
});
51+
}
52+
53+
fn extract_int_extract_success(bench: &mut Bencher<'_>) {
54+
Python::with_gil(|py| {
55+
let int_obj: PyObject = 123.into_py(py);
56+
let int = int_obj.as_ref(py);
57+
58+
bench.iter(|| {
59+
let v = black_box(int).extract::<i64>().unwrap();
60+
black_box(v);
61+
});
62+
});
63+
}
64+
65+
fn extract_int_extract_fail(bench: &mut Bencher<'_>) {
66+
Python::with_gil(|py| {
67+
let d = PyDict::new(py) as &PyAny;
68+
69+
bench.iter(|| match black_box(d).extract::<i64>() {
70+
Ok(v) => panic!("should err {}", v),
71+
Err(e) => black_box(e),
72+
});
73+
});
74+
}
75+
76+
fn extract_int_downcast_success(bench: &mut Bencher<'_>) {
77+
Python::with_gil(|py| {
78+
let int_obj: PyObject = 123.into_py(py);
79+
let int = int_obj.as_ref(py);
80+
81+
bench.iter(|| {
82+
let py_int = black_box(int).downcast::<PyInt>().unwrap();
83+
let v = py_int.extract::<i64>().unwrap();
84+
black_box(v);
85+
});
86+
});
87+
}
88+
89+
fn extract_int_downcast_fail(bench: &mut Bencher<'_>) {
90+
Python::with_gil(|py| {
91+
let d = PyDict::new(py) as &PyAny;
92+
93+
bench.iter(|| match black_box(d).downcast::<PyInt>() {
94+
Ok(v) => panic!("should err {}", v),
95+
Err(e) => black_box(e),
96+
});
97+
});
98+
}
99+
100+
fn extract_float_extract_success(bench: &mut Bencher<'_>) {
101+
Python::with_gil(|py| {
102+
let float_obj: PyObject = 23.42.into_py(py);
103+
let float = float_obj.as_ref(py);
104+
105+
bench.iter(|| {
106+
let v = black_box(float).extract::<f64>().unwrap();
107+
black_box(v);
108+
});
109+
});
110+
}
111+
112+
fn extract_float_extract_fail(bench: &mut Bencher<'_>) {
113+
Python::with_gil(|py| {
114+
let d = PyDict::new(py) as &PyAny;
115+
116+
bench.iter(|| match black_box(d).extract::<f64>() {
117+
Ok(v) => panic!("should err {}", v),
118+
Err(e) => black_box(e),
119+
});
120+
});
121+
}
122+
123+
fn extract_float_downcast_success(bench: &mut Bencher<'_>) {
124+
Python::with_gil(|py| {
125+
let float_obj: PyObject = 23.42.into_py(py);
126+
let float = float_obj.as_ref(py);
127+
128+
bench.iter(|| {
129+
let py_int = black_box(float).downcast::<PyFloat>().unwrap();
130+
let v = py_int.extract::<f64>().unwrap();
131+
black_box(v);
132+
});
133+
});
134+
}
135+
136+
fn extract_float_downcast_fail(bench: &mut Bencher<'_>) {
137+
Python::with_gil(|py| {
138+
let d = PyDict::new(py) as &PyAny;
139+
140+
bench.iter(|| match black_box(d).downcast::<PyFloat>() {
141+
Ok(v) => panic!("should err {}", v),
142+
Err(e) => black_box(e),
143+
});
144+
});
145+
}
146+
147+
fn criterion_benchmark(c: &mut Criterion) {
148+
c.bench_function("extract_str_extract_success", extract_str_extract_success);
149+
c.bench_function("extract_str_extract_fail", extract_str_extract_fail);
150+
c.bench_function("extract_str_downcast_success", extract_str_downcast_success);
151+
c.bench_function("extract_str_downcast_fail", extract_str_downcast_fail);
152+
c.bench_function("extract_int_extract_success", extract_int_extract_success);
153+
c.bench_function("extract_int_extract_fail", extract_int_extract_fail);
154+
c.bench_function("extract_int_downcast_success", extract_int_downcast_success);
155+
c.bench_function("extract_int_downcast_fail", extract_int_downcast_fail);
156+
c.bench_function(
157+
"extract_float_extract_success",
158+
extract_float_extract_success,
159+
);
160+
c.bench_function("extract_float_extract_fail", extract_float_extract_fail);
161+
c.bench_function(
162+
"extract_float_downcast_success",
163+
extract_float_downcast_success,
164+
);
165+
c.bench_function("extract_float_downcast_fail", extract_float_downcast_fail);
166+
}
167+
168+
criterion_group!(benches, criterion_benchmark);
169+
criterion_main!(benches);

0 commit comments

Comments
 (0)