Skip to content

Commit 1b89579

Browse files
committed
Add ctypes and ctypes_argtypes benchmarks
1 parent 1d2c09d commit 1b89579

File tree

9 files changed

+184
-0
lines changed

9 files changed

+184
-0
lines changed

doc/benchmarks.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,16 @@ the AES block cipher algorithm and the common modes of operation (CBC, CFB,
109109
CTR, ECB and OFB).
110110

111111

112+
ctypes
113+
------
114+
115+
Benchmark to measure the function call overhead of calling C functions using ctypes.
116+
117+
The `ctypes` benchmark lets `ctypes` infer the argument types from the passed in
118+
values. The `ctypes_argtypes` benchmark `explicitly specifies the argument types
119+
<https://docs.python.org/3.10/library/ctypes.html?highlight=ctypes#specifying-the-required-argument-types-function-prototypes>`_,
120+
which is slower than inferred argument types.
121+
112122
deltablue
113123
---------
114124

pyperformance/data-files/benchmarks/MANIFEST

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ name metafile
55
chameleon <local>
66
chaos <local>
77
crypto_pyaes <local>
8+
ctypes <local>
9+
ctypes_argtypes <local:ctypes>
810
deltablue <local>
911
django_template <local>
1012
dulwich_log <local>
@@ -62,6 +64,7 @@ xml_etree <local>
6264
#apps
6365
#math
6466
#template
67+
#extension
6568

6669

6770
[group default]
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[project]
2+
name = "pyperformance_bm_ctypes_argtypes"
3+
requires-python = ">=3.8"
4+
dependencies = ["pyperf"]
5+
urls = {repository = "https://github.com/python/pyperformance"}
6+
dynamic = ["version"]
7+
8+
[tool.pyperformance]
9+
name = "ctypes_argtypes"
10+
tags = "extension"
11+
runscript = "run_benchmark_argtypes.py"
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
void void_foo_void(void) {
2+
3+
}
4+
5+
int int_foo_int(int a) {
6+
return a + 1;
7+
}
8+
9+
void void_foo_int(int a) {
10+
11+
}
12+
13+
void void_foo_int_int(int a, int b) {
14+
15+
}
16+
17+
void void_foo_int_int_int(int a, int b, int c) {
18+
19+
}
20+
21+
void void_foo_int_int_int_int(int a, int b, int c, int d) {
22+
23+
}
24+
25+
void void_foo_constchar(const char* str) {
26+
27+
}
28+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[project]
2+
name = "pyperformance_bm_ctypes"
3+
requires-python = ">=3.8"
4+
dependencies = ["pyperf"]
5+
urls = {repository = "https://github.com/python/pyperformance"}
6+
dynamic = ["version"]
7+
8+
[tool.pyperformance]
9+
name = "ctypes"
10+
tags = "extension"
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
"""
2+
Test the function call overhead of ctypes.
3+
"""
4+
import pyperf
5+
6+
7+
import ctypes
8+
import importlib.util
9+
10+
11+
spec = importlib.util.find_spec("bm_ctypes.cmodule")
12+
if spec is None:
13+
raise ImportError("Can't find bm_ctypes.cmodule shared object file")
14+
ext = ctypes.cdll.LoadLibrary(spec.origin)
15+
16+
17+
def benchmark(n):
18+
void_foo_void = ext.void_foo_void
19+
int_foo_int = ext.int_foo_int
20+
void_foo_int = ext.void_foo_int
21+
void_foo_int_int = ext.void_foo_int_int
22+
void_foo_int_int_int = ext.void_foo_int_int_int
23+
void_foo_int_int_int_int = ext.void_foo_int_int_int_int
24+
void_foo_constchar = ext.void_foo_constchar
25+
26+
# Test calling the functions using the implied arguments mechanism
27+
28+
for i in range(n):
29+
void_foo_void()
30+
int_foo_int(1)
31+
void_foo_int(1)
32+
void_foo_int_int(1, 2)
33+
void_foo_int_int_int(1, 2, 3)
34+
void_foo_int_int_int_int(1, 2, 3, 4)
35+
void_foo_constchar(b"bytes")
36+
37+
38+
if __name__ == "__main__":
39+
runner = pyperf.Runner()
40+
runner.metadata["description"] = "ctypes function call overhead benchmark"
41+
42+
runner.bench_func("ctypes", benchmark, 1000000)
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
"""
2+
Test the function call overhead of ctypes with specified arguments.
3+
"""
4+
import pyperf
5+
6+
7+
import ctypes
8+
import importlib.util
9+
10+
11+
spec = importlib.util.find_spec("bm_ctypes.cmodule")
12+
if spec is None:
13+
raise ImportError("Can't find bm_ctypes.cmodule shared object file")
14+
ext = ctypes.cdll.LoadLibrary(spec.origin)
15+
16+
17+
def benchmark(n):
18+
void_foo_void = ext.void_foo_void
19+
void_foo_void.argtypes = []
20+
void_foo_void.restype = None
21+
22+
int_foo_int = ext.void_foo_int
23+
int_foo_int.argtypes = [ctypes.c_int]
24+
int_foo_int.restype = ctypes.c_int
25+
26+
void_foo_int = ext.void_foo_int
27+
void_foo_int.argtypes = [ctypes.c_int]
28+
void_foo_int.restype = None
29+
30+
void_foo_int_int = ext.void_foo_int_int
31+
void_foo_int_int.argtypes = [ctypes.c_int, ctypes.c_int]
32+
void_foo_int_int.restype = None
33+
34+
void_foo_int_int_int = ext.void_foo_int_int_int
35+
void_foo_int_int_int.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_int]
36+
void_foo_int_int_int.restype = None
37+
38+
void_foo_int_int_int_int = ext.void_foo_int_int_int_int
39+
void_foo_int_int_int_int.argtypes = [
40+
ctypes.c_int,
41+
ctypes.c_int,
42+
ctypes.c_int,
43+
ctypes.c_int,
44+
]
45+
void_foo_int_int_int_int.restype = None
46+
47+
void_foo_constchar = ext.void_foo_constchar
48+
void_foo_constchar.argtypes = [ctypes.c_char_p]
49+
void_foo_constchar.restype = None
50+
51+
# Test calling the functions using the specified arguments mechanism
52+
53+
for i in range(n):
54+
void_foo_void()
55+
int_foo_int(1)
56+
void_foo_int(1)
57+
void_foo_int_int(1, 2)
58+
void_foo_int_int_int(1, 2, 3)
59+
void_foo_int_int_int_int(1, 2, 3, 4)
60+
void_foo_constchar(b"bytes")
61+
62+
63+
if __name__ == "__main__":
64+
runner = pyperf.Runner()
65+
runner.metadata[
66+
"description"
67+
] = "ctypes function call overhead, with specified arguments, benchmark"
68+
69+
runner.bench_func("ctypes", benchmark, 1000000)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from distutils.core import setup, Extension
2+
3+
# Compile the C shared object containing functions to call through ctypes. It
4+
# isn't technically a Python C extension, but this is the easiest way to build
5+
# it in a cross-platform way.
6+
7+
setup(
8+
name="pyperformance_bm_ctypes",
9+
ext_modules=[Extension("bm_ctypes.cmodule", sources=["cmodule.c"])],
10+
package_dir={"bm_ctypes": "src"},
11+
)

pyperformance/data-files/benchmarks/bm_ctypes/src/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)