Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make copy.deepcopy faster for slice objects #100817

Closed
sobolevn opened this issue Jan 7, 2023 · 2 comments
Closed

Make copy.deepcopy faster for slice objects #100817

sobolevn opened this issue Jan 7, 2023 · 2 comments
Assignees
Labels
performance Performance or resource usage type-feature A feature request or enhancement

Comments

@sobolevn
Copy link
Member

sobolevn commented Jan 7, 2023

slice

Right now slice objects are deepcopied using __reduce__ defined as:

static PyObject *
slice_reduce(PySliceObject* self, PyObject *Py_UNUSED(ignored))
{
return Py_BuildValue("O(OOO)", Py_TYPE(self), self->start, self->stop, self->step);
}

It is one of last branches of deepcopy logic:

cpython/Lib/copy.py

Lines 120 to 157 in 26ff436

def deepcopy(x, memo=None, _nil=[]):
"""Deep copy operation on arbitrary Python objects.
See the module's __doc__ string for more info.
"""
if memo is None:
memo = {}
d = id(x)
y = memo.get(d, _nil)
if y is not _nil:
return y
cls = type(x)
copier = _deepcopy_dispatch.get(cls)
if copier is not None:
y = copier(x, memo)
else:
if issubclass(cls, type):
y = _deepcopy_atomic(x, memo)
else:
copier = getattr(x, "__deepcopy__", None)
if copier is not None:
y = copier(memo)
else:
reductor = dispatch_table.get(cls)
if reductor:
rv = reductor(x)
else:
reductor = getattr(x, "__reduce_ex__", None)
if reductor is not None:
rv = reductor(4)
else:
reductor = getattr(x, "__reduce__", None)
if reductor:
rv = reductor()

But, since slice is an immutable type without nested structures, we can optimize its deepcopy as:

d[slice] = _deepcopy_atomic

Before:

» pyperf timeit --setup 'from copy import deepcopy; s = slice(1,10,2)' 'deepcopy(s)'
.....................
Mean +- std dev: 3.46 us +- 0.18 us

After:

» pyperf timeit --setup 'from copy import deepcopy; s = slice(1,10,2)' 'deepcopy(s)'
.....................
Mean +- std dev: 277 ns +- 3 ns

Looks like a good speedup for just a single line!
Noticed while working on #100815

PR is incoming.

Linked PRs

@sobolevn sobolevn added type-feature A feature request or enhancement performance Performance or resource usage labels Jan 7, 2023
@sobolevn sobolevn self-assigned this Jan 7, 2023
sobolevn added a commit to sobolevn/cpython that referenced this issue Jan 7, 2023
@sobolevn sobolevn closed this as completed Jan 7, 2023
@sobolevn
Copy link
Member Author

sobolevn commented Jan 7, 2023

Closing, see #100818

@AlexWaygood AlexWaygood closed this as not planned Won't fix, can't repro, duplicate, stale Jan 7, 2023
@eendebakpt
Copy link
Contributor

@sobolevn PR #100817 makes the deepcopy faster, which also has a positive effect on the speed of the slice deep copy:

Main:

$ ./python -m pyperf timeit --setup 'from copy import deepcopy; s = slice(1,10,2)' 'deepcopy(s)'
.....................
Mean +- std dev: 2.96 us +- 0.05 us

PR 100817

 $ ./python -m pyperf timeit --setup 'from copy import deepcopy; s = slice(1,10,2)' 'deepcopy(s)'
.....................
Mean +- std dev: 2.47 us +- 0.07 us

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
performance Performance or resource usage type-feature A feature request or enhancement
Projects
None yet
Development

No branches or pull requests

3 participants