bpo-29735: Optimize partial_call(): avoid tuple#516
Conversation
|
@Haypo, thanks for your PR! By analyzing the history of the files in this pull request, we identified @serhiy-storchaka, @rhettinger, @benjaminp, @abalkin and @1st1 to be potential reviewers. |
|
New benchmark results: http://bugs.python.org/issue29735#msg289579 |
serhiy-storchaka
left a comment
There was a problem hiding this comment.
May be the optimization needs more test cases for covering all code.
There was a problem hiding this comment.
I think clearing these flags is not needed.
It would be better to use PyCFunction_GET_FLAGS().
In sum this function can be written as:
return PyFunction_Check(callable) ||
(PyCFunction_Check(callable) &&
!(PyCFunction_GET_FLAGS(callable) & METH_VARARGS));
There was a problem hiding this comment.
"I think clearing these flags is not needed. It would be better to use PyCFunction_GET_FLAGS()."
Right, done. But I prefer explicit if().
There was a problem hiding this comment.
pto->fn can be changed by __setstate__().
There was a problem hiding this comment.
Since concatenating with empty tuple is optimized, perhaps these two special cases no longer needed. -10 lines of code. Could you tests this?
There was a problem hiding this comment.
I tested: removing the two special case (size==0) has no impact on performance, so I removed it.
There was a problem hiding this comment.
This can be used for all branches. -2 lines of code.
There was a problem hiding this comment.
If there are keyword arguments _PyObject_FastCallDict allocates new array for arguments. I don't know whether it is worth to optimize this case and unpack keyword arguments here. This could complicate the code too much and I don't know how large is a benefit.
There was a problem hiding this comment.
There is a corner case: dict.update() really expects a dict.
Your proposed optimizations seem complex for a little gain.
There was a problem hiding this comment.
Seems the code for merging two dicts is duplicated. Could it be shared?
There was a problem hiding this comment.
Does it before Py_SETREF(). The partial object should be consistent at the time of destroying old callable.
|
Please check that new code is covered by tests. Otherwise add new tests. |
* Add _PyObject_HasFastCall() * partial_call() now avoids temporary tuple to pass positional arguments if the callable supports the FASTCALL calling convention for positional arguments. * Fix also a performance regression in partial_call() if the callable doesn't support FASTCALL.
All code paths of partial_fastcall() and partial_call_impl() are tested by test_functools. |
serhiy-storchaka
left a comment
There was a problem hiding this comment.
I hope it is worth the complication of the code.
|
Thank you for your review @serhiy-storchaka ! |
Bumps [gidgethub](https://github.com/brettcannon/gidgethub) from 5.0.1 to 5.1.0. - [Release notes](https://github.com/brettcannon/gidgethub/releases) - [Changelog](https://github.com/brettcannon/gidgethub/blob/main/docs/changelog.rst) - [Commits](gidgethub/gidgethub@5.0.1...v5.1.0) --- updated-dependencies: - dependency-name: gidgethub dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Avoid temporary tuple to pass positional arguments.