diff --git a/doc/benchmarks.rst b/doc/benchmarks.rst index 09c7abc4..7413c41f 100644 --- a/doc/benchmarks.rst +++ b/doc/benchmarks.rst @@ -108,6 +108,11 @@ See `pyaes `_: A pure-Python implementation of the AES block cipher algorithm and the common modes of operation (CBC, CFB, CTR, ECB and OFB). +deepcopy +-------- + +Benchmark the Python `copy.deepcopy` method. The `deepcopy` method is +performed on a nested dictionary and a dataclass. deltablue --------- diff --git a/pyperformance/data-files/benchmarks/MANIFEST b/pyperformance/data-files/benchmarks/MANIFEST index a52cb7a1..f2338845 100644 --- a/pyperformance/data-files/benchmarks/MANIFEST +++ b/pyperformance/data-files/benchmarks/MANIFEST @@ -5,6 +5,7 @@ name metafile chameleon chaos crypto_pyaes +deepcopy deltablue django_template dulwich_log diff --git a/pyperformance/data-files/benchmarks/bm_deepcopy/pyproject.toml b/pyperformance/data-files/benchmarks/bm_deepcopy/pyproject.toml new file mode 100644 index 00000000..5da44754 --- /dev/null +++ b/pyperformance/data-files/benchmarks/bm_deepcopy/pyproject.toml @@ -0,0 +1,9 @@ +[project] +name = "pyperformance_bm_deepcopy" +requires-python = ">=3.8" +dependencies = ["pyperf"] +urls = {repository = "https://github.com/python/pyperformance"} +dynamic = ["version"] + +[tool.pyperformance] +name = "deepcopy" diff --git a/pyperformance/data-files/benchmarks/bm_deepcopy/run_benchmark.py b/pyperformance/data-files/benchmarks/bm_deepcopy/run_benchmark.py new file mode 100644 index 00000000..c706a306 --- /dev/null +++ b/pyperformance/data-files/benchmarks/bm_deepcopy/run_benchmark.py @@ -0,0 +1,88 @@ +""" +Benchmark to measure performance of the python builtin method copy.deepcopy + +Performance is tested on a nested dictionary and a dataclass + +Author: Pieter Eendebak + +""" +import copy +import pyperf +from dataclasses import dataclass + + +@dataclass +class A: + string: str + lst: list + boolean: bool + + +def benchmark_reduce(n): + """ Benchmark where the __reduce__ functionality is used """ + class C(object): + def __init__(self): + self.a = 1 + self.b = 2 + + def __reduce__(self): + return (C, (), self.__dict__) + + def __setstate__(self, state): + self.__dict__.update(state) + c = C() + + t0 = pyperf.perf_counter() + for ii in range(n): + _ = copy.deepcopy(c) + dt = pyperf.perf_counter() - t0 + return dt + + +def benchmark_memo(n): + """ Benchmark where the memo functionality is used """ + A = [1] * 100 + data = {'a': (A, A, A), 'b': [A] * 100} + + t0 = pyperf.perf_counter() + for ii in range(n): + _ = copy.deepcopy(data) + dt = pyperf.perf_counter() - t0 + return dt + + +def benchmark(n): + """ Benchmark on some standard data types """ + a = { + 'list': [1, 2, 3, 43], + 't': (1 ,2, 3), + 'str': 'hello', + 'subdict': {'a': True} + } + dc = A('hello', [1, 2, 3], True) + + dt = 0 + for ii in range(n): + for jj in range(30): + t0 = pyperf.perf_counter() + _ = copy.deepcopy(a) + dt += pyperf.perf_counter() - t0 + for s in ['red', 'blue', 'green']: + dc.string = s + for kk in range(5): + dc.lst[0] = kk + for b in [True, False]: + dc.boolean = b + t0 = pyperf.perf_counter() + _ = copy.deepcopy(dc) + dt += pyperf.perf_counter() - t0 + return dt + + +if __name__ == "__main__": + runner = pyperf.Runner() + runner.metadata['description'] = "deepcopy benchmark" + + runner.bench_time_func('deepcopy', benchmark) + runner.bench_time_func('deepcopy_reduce', benchmark_reduce) + runner.bench_time_func('deepcopy_memo', benchmark_memo)