[issue26814] Add a new _PyObject_CallStack() function which avoids the creation of a tuple or dict for arguments

2016-04-21 Thread Larry Hastings

Larry Hastings added the comment:

Yes, I've been working on a patch to do this as well.  I called the calling 
convention METH_RAW, to go alongside METH_ZERO METH_O etc.  My calling 
convention was exactly the same as yours: PyObject *(PyObject *o, PyObject 
**stack, int na, int nk).  I only had to modify two functions in ceval.c to 
support it: ext_do_call() and call_function().

And yes, the overarching goal was to have Argument Clinic generate custom 
argument parsing code for every function.  Supporting the calling convention 
was the easy part; generating code was quite complicated.  I believe I got a 
very simple version of it working at one point, supporting positional 
parameters only, with some optional arguments.  Parsing arguments by hand gets 
very complicated indeed when you introduce keyword arguments.

I haven't touched this patch in most of a year.  I hope to return to it 
someday.  In the meantime it's fine by me if you add support for this and 
rewrite some functions by hand to use it.

p.s. My last name has two S's.  If you continue to leave off one of them, I 
shall remove one from yours, Mr. TINNER.

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue26814] Add a new _PyObject_CallStack() function which avoids the creation of a tuple or dict for arguments

2016-04-21 Thread Serhiy Storchaka

Serhiy Storchaka added the comment:

With call_stack-2.patch attribute access in namedtuple is only 25% slower than 
attribute access in ordinary Python object! Definitely this this worth to 
continue to experiment!

But adding new slot to PyTypeObject sets the bar too high. Try to use your 
function to speed up all cases mentioned in issue23507: sorted()/list.sort(), 
min() and max() with the key argument, filter(), map(), some iterators from 
itertools (groupby(), dropwhile(), takewhile(), accumulate(), filterfalse()), 
thin wrappers around special method (round(), math.floor(), etc). Use it in 
wrappers around PyObject_Call() like PyObject_CallFunctionObjArgs(). May be 
this will cause an effect even on some macrobenchmarks.

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue26814] Add a new _PyObject_CallStack() function which avoids the creation of a tuple or dict for arguments

2016-04-21 Thread STINNER Victor

STINNER Victor added the comment:

call_stack-2.patch: A little bit more complete patch, it adds a tp_call_stack 
field to PyTypeObject an use it in _PyObject_CallStack().

Updated microbenchmark on Python 3.6, best of 3 runs:

./python -m timeit -r 11 -s "from collections import namedtuple as n; a = 
n('n', 'a b c')(1, 2, 3)" -- "a.a; a.a; a.a; a.a; a.a; a.a; a.a; a.a; a.a; a.a; 
a.a; a.a; a.a; a.a; a.a; a.a; a.a; a.a; a.a"

* Python 3.6 unpatched: 0.968 usec
* call_stack.patch: 1.27 usec
* Python 3.6 with property_descr_get() of Python 3.4: 1.32 usec
* call_stack-2.patch: 0.664 usec

call_stack-2.patch makes this micro-benchmark 31% faster, not bad! It also 
makes calls to C functions almost 2x as fast if you replace current unoptimized 
calls with _PyObject_CallStack()!!

IHMO we should continue to experiment, making function calls 2x faster is worth 
it ;-)


Serhiy: "See also issue23507. May be your function help to optimize filter(), 
map(), sorted()?"

IMHO the API is generic enough to be usable in a lot of cases.


Serhiy: "Is there any use of this function with keyword arguments?"

Calling functions with keywords is probably the least common case for function 
calls in C code. But I would like to provide a fast function to call with 
keywords. Maybe we need two functions just to make the API cleaner? The 
difference would just be that "int k" would be omitted?

I proposed an API (PyObject **stack, int na, int nk) based on the current code 
in Python/ceval.c. I'm not sure that it's the best API ever :-)

In fact, there is already PyObject_CallFunctionObjArgs() which can be modified 
to reuse internally _PyObject_CallStack(), and its API is maybe more convenient 
than my proposed API.

--
Added file: http://bugs.python.org/file42550/call_stack-2.patch

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue26814] Add a new _PyObject_CallStack() function which avoids the creation of a tuple or dict for arguments

2016-04-21 Thread Serhiy Storchaka

Serhiy Storchaka added the comment:

See also issue23507. May be your function help to optimize filter(), map(), 
sorted()?

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue26814] Add a new _PyObject_CallStack() function which avoids the creation of a tuple or dict for arguments

2016-04-21 Thread STINNER Victor

STINNER Victor added the comment:

Microbenchmark on Python 3.6, best of 3 runs:

./python -m timeit -r 11 -s "from collections import namedtuple as n; a = 
n('n', 'a b c')(1, 2, 3)" -- "a.a; a.a; a.a; a.a; a.a; a.a; a.a; a.a; a.a; a.a; 
a.a; a.a; a.a; a.a; a.a; a.a; a.a; a.a; a.a"

* Python 3.6 unpatched: 0.968 usec
* call_stack.patch: 1.27 usec
* Python 3.6 with property_descr_get() of Python 3.4: 1.32 usec

"Python 3.6 with property_descr_get() of Python 3.4": replace the current 
optimization with "return PyObject_CallFunctionObjArgs(gs->prop_get, obj, 
NULL);".

Oh, in fact the tested code calls a property where the final function is 
operator.itemgetter(0). _PyObject_CallStack() creates a temporary tuple to call 
PyObject_Call() which calls func->ob_type->tp_call, itemgetter_call().

Problem: tp_call API uses (PyObject *args, PyObject *kwargs). It doesn't accept 
directly a stack (a C array of PyObject*). And it may be more difficult to 
modify tp_call.

In short, my patch disables the optimization on property with my current 
incomplete implementation.

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue26814] Add a new _PyObject_CallStack() function which avoids the creation of a tuple or dict for arguments

2016-04-21 Thread Serhiy Storchaka

Serhiy Storchaka added the comment:

"Stack" in the function name looks a little confusing. I understand that this 
is related to the stack of bytecode interpreter, but this looks as raising 
pretty deep implementation detail. The way of packing positional and keyword 
arguments in the continuous array is not clear. Wouldn't be better to provide 
separate arguments for positional and keyword arguments?

What is the performance effect of using this function? For example compare the 
performance of namedtuple's attribute access of current code, the code with 
with this patch, and unoptimized code in 3.4:

./python -m timeit -r 11 -s "from collections import namedtuple as n; a = 
n('n', 'a b c')(1, 2, 3)" -- "a.a"

Is there any use of this function with keyword arguments?

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue26814] Add a new _PyObject_CallStack() function which avoids the creation of a tuple or dict for arguments

2016-04-21 Thread STINNER Victor

Changes by STINNER Victor :


--
nosy: +yselivanov

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue26814] Add a new _PyObject_CallStack() function which avoids the creation of a tuple or dict for arguments

2016-04-21 Thread STINNER Victor

New submission from STINNER Victor:

Attached patch adds the following new function:

   PyObject* _PyObject_CallStack(PyObject *func,
 PyObject **stack, 
 int na, int nk);

where na is the number of positional arguments and nk is the number of (key, 
pair) arguments stored in the stack.

Example of C code to call a function with one positional argument:

PyObject *stack[1];
stack[0] = arg;
return _PyObject_CallStack(func, stack, 1, 0);

Simple, isn't it?

The difference with PyObject_Call() is that its API avoids the creation of a 
tuple and a dictionary to pass parameters to functions when possible. 
Currently, the temporary tuple and dict can be avoided to call Python functions 
(nice, isn't it?) and C function declared with METH_O (not the most common API, 
but many functions are declared like that).

The patch only modifies property_descr_set() to test the feature, but I'm sure 
that *a lot* of C code can be modified to use this new function to beneift from 
its optimization.

Should we make this new _PyObject_CallStack() function official: call it 
PyObject_CallStack() (without the understand prefix) or experiment it in 
CPython 3.6 and decide later to make it public? If it's made private, it will 
require a large replacement patch later to replace all calls to 
_PyObject_CallStack() with PyObject_CallStack() (strip the underscore prefix).

The next step is to add a new METH_STACK flag to pass parameters to C functions 
using a similar API (PyObject **stack, int na, int nk) and modify the argument 
clinic to use this new API.

Thanks to Larry Hasting who gave me the idea in a previous edition of Pycon US 
;-)

This issue was created after the discussion on issue #26811 which is an issue 
in a micro-optimization in property_descr_set() to avoid the creation of a 
tuple: it caches a private tuple inside property_descr_set().

--
files: call_stack.patch
keywords: patch
messages: 263899
nosy: haypo, larry, rhettinger, serhiy.storchaka
priority: normal
severity: normal
status: open
title: Add a new _PyObject_CallStack() function which avoids the creation of a 
tuple or dict for arguments
type: performance
versions: Python 3.6
Added file: http://bugs.python.org/file42549/call_stack.patch

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com