-
-
Notifications
You must be signed in to change notification settings - Fork 31.9k
gh-112919: Speed-up datetime, date and time.replace() #112921
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
gh-112919: Speed-up datetime, date and time.replace() #112921
Conversation
36b9549
to
fff4ae4
Compare
Use argument clinic and call new_* functions directly. This speeds up these functions 6x to 7.5x when calling with keyword arguments. Before: $ python -m timeit -s "from datetime import datetime; dt = datetime.now()" "dt.replace(microsecond=0)" 500000 loops, best of 5: 501 nsec per loop $ python -m timeit -s "from datetime import date; d = date.today()" "d.replace(day=1)" 1000000 loops, best of 5: 273 nsec per loop $ python -m timeit -s "from datetime import time; t = time()" "t.replace(microsecond=0)" 1000000 loops, best of 5: 338 nsec per loop After: $ python -m timeit -s "from datetime import datetime; dt = datetime.now()" "dt.replace(microsecond=0)" 5000000 loops, best of 5: 65.9 nsec per loop $ python -m timeit -s "from datetime import date; d = date.today()" "d.replace(day=1)" 5000000 loops, best of 5: 45.6 nsec per loop $ python -m timeit -s "from datetime import time; t = time()" "t.replace(microsecond=0)" 5000000 loops, best of 5: 51 nsec per loop
ca3b11f
to
53a9b6f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general LGTM, but please generate also __replace__
methods.
DATETIME_DATE_REPLACE_METHODDEF | ||
|
||
{"__replace__", _PyCFunction_CAST(date_replace), METH_VARARGS | METH_KEYWORDS}, | ||
{"__replace__", _PyCFunction_CAST(datetime_date_replace), METH_FASTCALL | METH_KEYWORDS}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is an issue here. DATETIME_DATE_REPLACE_METHODDEF can be changed with different options of Argument Clinic (for example when we experiment with the limited C API). The generated datetime_date_replace
can no longer be compatible with manually written entry for __replace__
.
The simplest way to fix this is to add separate definition for __replace__
:
/*[clinic input]
datetime.date.__replace__ = datetime.date.replace
[clinic start generated code]*/
static PyObject *
datetime_date___replace___impl(PyDateTime_Date *self, int year, int month,
int day)
/*[clinic end generated code: output=bfb97f926e24f201 input=1b2cac755dfa9b40]*/
{
return new_date_ex(year, month, day, Py_TYPE(self));
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand correctly, this means that the bodies of all replace() functions need to be duplicated. This means that all future changes to that code will need to be done twice, which is a bad thing. (The functions may seem trivial, but I'm already working on a further change to address #89039.) This will also generate the argument parsing code twice, which will bloat executable size. A better approach would be to add some syntax to argument clinic to generate the second METHODDEF.
Also, note that I copied this approach from code.__replace__
, so if this is not right, code.__replace__
needs to be changed as well.
@serhiy-storchaka thank you for the review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
Well, let merge it as is, and make the code more independent from Argument Clinic changes in other issue. Otherwise we risk to forget about this PR.
…-112921) Use argument clinic and call new_* functions directly. This speeds up these functions 6x to 7.5x when calling with keyword arguments.
Thanks @eltoder for the PR, and @serhiy-storchaka for merging it 🌮🎉.. I'm working now to backport this PR to: 3.11. |
Thanks @eltoder for the PR, and @serhiy-storchaka for merging it 🌮🎉.. I'm working now to backport this PR to: 3.12. |
Sorry, @eltoder and @serhiy-storchaka, I could not cleanly backport this to
|
Sorry, @eltoder and @serhiy-storchaka, I could not cleanly backport this to
|
…ythonGH-112921) Use argument clinic and call new_* functions directly. This speeds up these functions 6x to 7.5x when calling with keyword arguments. (cherry picked from commit 1f515e8) Co-authored-by: Eugene Toder <[email protected]>
GH-115344 is a backport of this pull request to the 3.12 branch. |
Thanks, nice change! |
Use argument clinic and call new_* functions directly. This speeds up these functions 6x to 7.5x when calling with keyword arguments.
Before:
After: