473,382 Members | 1,329 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,382 software developers and data experts.

Accessing =?utf-8?b?X19zbG90c19f?= from C

Hi,

I'd like to be able to access an attribute of a particular Python
object as fast as possible from some C code.

I wondered if using __slots__ to store the attribute would allow me to
do this in a faster way.

The reason I'd like to do this is because I need to access the
attribute inside a loop within some C code, and I find that the
attribute lookup using the 'PyObject_GetAttrString' call is far slower
than any of the subsequent calculations I perform in C.

Using the 'PyObject_GetAttrString' function to get the attribute, I
find it is slightly faster when the attribute is a slot than when it
isn't, but that the attribute lookup remains the performance-limiting
factor.

Additionally, if I instead build a list of the attributes first and
pass that to the C code, using the 'PyList_GetItem' function to access
each item, the performance improves significantly. I'd rather be able
to access the information from C, instead of building the list
externally.

As far as I can tell, nothing is documented about accessing __slot__
members in a special way from C, but perhaps someone knows how to do
it anyway?

To be more specific, below is an example of what I'm talking about. I
use SciPy's weave to inline C code, but I assume that doesn't make any
difference to my problem.

Thanks for any suggestions,
Chris

class MyObject(object):

__slots__ = ['attr_one']

def __init__(self,attr_one=1.0):
self.attr_one = attr_one
import weave
def test_loop(myobjects):

rows,cols = len(myobjects),len(myobjects[0])

code = """
for (int r=0; r<rows; ++r) {
PyObject *myobjects_row = PyList_GetItem(myobjects,r);
for (int l=0; l<cols; ++l) {
PyObject *myobject = PyList_GetItem(myobjects_row,l);
// any faster way when attr_one is a slot?
PyObject *attr_one_obj=PyObject_GetAttrString(myobject,"att r_one");

// more computations involving attr_one; just print for now...
double attr_one = PyFloat_AsDouble(attr_one_obj);
printf("%f\\n",attr_one);
}
}
"""
weave.inline(code,['myobjects','rows','cols'],local_dict=locals(),verbose=1)
test_list = [[MyObject(0.0),MyObject(1.0)],[MyObject(2.0),MyObject(3.0)]]

test_loop(test_list)
Sep 10 '08 #1
10 1578
[ You can use the capi-sig for questions like this; see
http://mail.python.org/mailman/listinfo/capi-sig ]

Chris <ce****@users.sourceforge.netwrites:
I'd like to be able to access an attribute of a particular Python
object as fast as possible from some C code.

I wondered if using __slots__ to store the attribute would allow me to
do this in a faster way.

The reason I'd like to do this is because I need to access the
attribute inside a loop within some C code, and I find that the
attribute lookup using the 'PyObject_GetAttrString' call is far slower
than any of the subsequent calculations I perform in C.
PyObject_GetAttrString is convenient, but it creates a Python string
only so it can intern it (and in most cases throw away the freshly
created version). For maximum efficiency, pre-create the string
object using PyString_InternFromString, and use that with
PyObject_GetAttr.
Sep 11 '08 #2
Hrvoje Niksic <hniksic <atxemacs.orgwrites:
....
[ You can use the capi-sig for questions like this; see
http://mail.python.org/mailman/listinfo/capi-sig ]
Thanks, I had no idea about that.
PyObject_GetAttrString is convenient, but it creates a Python string
only so it can intern it (and in most cases throw away the freshly
created version). For maximum efficiency, pre-create the string
object using PyString_InternFromString, and use that with
PyObject_GetAttr.
Yes, we'd thought of that too, but it doesn't seem to be an important
factor compared to the actual attribute lookup.

Thanks for the advice,
Chris

Sep 11 '08 #3
On Sep 10, 7:41 am, Chris <ceb...@users.sourceforge.netwrote:
Hi,

I'd like to be able to access an attribute of a particular Python
object as fast as possible from some C code.

I wondered if using __slots__ to store the attribute would allow me to
do this in a faster way.

The reason I'd like to do this is because I need to access the
attribute inside a loop within some C code, and I find that the
attribute lookup using the 'PyObject_GetAttrString' call is far slower
than any of the subsequent calculations I perform in C.

Using the 'PyObject_GetAttrString' function to get the attribute, I
find it is slightly faster when the attribute is a slot than when it
isn't, but that the attribute lookup remains the performance-limiting
factor.
You can determine the offset the of the slot in the object structure
by
querying the member descriptor of the type object.

descr = GetAttrString(cls,"varname");
offset = descr->d_member->offset;
slotvar = (PyObject*)(((char*)obj)+offset)

There might be some macros to simplify this.

Use at your own risk.
Carl Banks
Sep 11 '08 #4
Carl Banks <pavlovevidence <atgmail.comwrites:
....
You can determine the offset the of the slot in the object structure
by
querying the member descriptor of the type object.
That sounds like just the kind of thing we were looking for - thanks!
descr = GetAttrString(cls,"varname");
offset = descr->d_member->offset;
slotvar = (PyObject*)(((char*)obj)+offset)
Unfortunately, I am inexperienced at this kind of thing, so I wasn't
able to get something working. Maybe someone could tell me what's
wrong with the code below (it gives the error "'struct _object' has no
member named 'd_member'")?

PyObject *descr = PyObject_GetAttrString(x,"attr_one");
int offset = descr->d_member->offset;
PyObject* slotvar = (PyObject*)(((char*)obj)+offset);

where x is the class and attr_one is a slot (the full example is
appended to this message). I guessed the type of offset; I'm not sure
what it should be.

I couldn't find any information about d_member on the web.

There might be some macros to simplify this.
Sorry to say that I also have no idea about where to find such macros!
Maybe I should continue this thread on capi-sig?
Thanks for your help,
Chris
class MyObject(object):

__slots__ = ['attr_one']

def __init__(self,attr_one=1.0):
self.attr_one = attr_one

import weave
def test():

x = MyObject

code = """
PyObject *descr = PyObject_GetAttrString(x,"attr_one");
int offset = descr->d_member->offset;
//PyObject* slotvar = (PyObject*)(((char*)obj)+offset);
"""
weave.inline(code,['x'],local_dict=locals(),verbose=1)

test()
Sep 12 '08 #5
Hrvoje Niksic <hniksic <atxemacs.orgwrites:
....
Chris <ceball <atusers.sourceforge.netwrites:
PyObject_GetAttrString is convenient, but it creates a Python string
only so it can intern it (and in most cases throw away the freshly
created version). For maximum efficiency, pre-create the string
object using PyString_InternFromString, and use that with
PyObject_GetAttr.
Yes, we'd thought of that too, but it doesn't seem to be an
important factor compared to the actual attribute lookup.

I'd like to see your test code.
Thanks for your interest in this. My test code is a whole function
that's part of a big simulator, unfortunately! I need to use the data
structures created by the simulator as part of the testing. While the
source is freely available*, that doesn't make it easy for others to
run the tests...

In my experience, as long as you're
accessing simple slots, you should notice a difference.
(I'm not sure what you mean by a 'simple slot'. The slot we're
accessing is a numpy array.)

Sorry I wasn't clear before - we do notice a difference, but not as
big a difference as when we access the attributes (arrays) from a
pre-built list. Below are timings from running the simulator
(i.e. calling the function in question many times) using the three
approaches (GetAttrString, GetAttr, and instead using a list and
GetItem; times outside parentheses are from a stopwatch; times in
parentheses are from Python's cProfile module):
- GetAttrString: 55 seconds (58 seconds)
inside the loop:
PyObject *weights_obj = PyObject_GetAttrString(obj,"attr_one");
- GetAttr: 46 seconds (46 seconds)
outside the loop:
PyObject *name = PyString_FromString("attr_one");

inside the loop:
PyObject *obj = PyObject_GetAttr(obj,name);
- PyList_GetItem: 35 seconds (37 seconds)
So, of course, you are right to say that we should notice a
difference! But speed is critical for us here.

Incidentally, what we have is a simulator written entirely in Python,
but we also provide optimized C versions of some parts of it. These C
parts must be entirely optional.

Here is a test program that shows a 4.6 time speedup simply by
switching from PyObject_GetAttrString to PyObject_GetAttr:
Thanks for the illustration. While I didn't run your code myself,
I did try to study it. Illustrations like that are very helpful.
Chris
* from http://topographica.org/

Sep 12 '08 #6
Chris <ce****@users.sourceforge.netwrites:
>In my experience, as long as you're
accessing simple slots, you should notice a difference.

(I'm not sure what you mean by a 'simple slot'.
I mean a slot defined by __slots__ = slot1, slot2, slot3, ..., without
descriptors or specific __getattribute__ code on top of that.
- GetAttr: 46 seconds (46 seconds)
outside the loop:
PyObject *name = PyString_FromString("attr_one");
I think you should be using PyString_InternFromString, but it will
probably still be slower than PyList_GET_ITEM, which is still much
simpler. The next optimization is the one proposed by Carl, which
should yield speed comparable to PyList_GET_ITEM. See my response in
that subthread for details.
Sep 12 '08 #7
Chris <ce****@users.sourceforge.netwrites:
>descr = GetAttrString(cls,"varname");
offset = descr->d_member->offset;
slotvar = (PyObject*)(((char*)obj)+offset)

Unfortunately, I am inexperienced at this kind of thing, so I wasn't
able to get something working. Maybe someone could tell me what's
wrong with the code below (it gives the error "'struct _object' has no
member named 'd_member'")?
You are getting that error because Carl forgot to cast the descriptor
to the appropriate C type, in this case PyMemberDescrObject. The last
line is also incorrect, I think. Try something like this:

PyObject *descr = PyObject_GetAttrString(x,"attr_one");
int offset = ((PyMemberDescrObject *) descr)->d_member->offset;
PyObject *slotvar = *(PyObject **)(((char *) obj) + offset);
Sep 12 '08 #8
Hrvoje Niksic <hn*****@xemacs.orgwrites:
Chris <ce****@users.sourceforge.netwrites:
>>descr = GetAttrString(cls,"varname");
offset = descr->d_member->offset;
slotvar = (PyObject*)(((char*)obj)+offset)

Unfortunately, I am inexperienced at this kind of thing, so I wasn't
able to get something working. Maybe someone could tell me what's
wrong with the code below (it gives the error "'struct _object' has no
member named 'd_member'")?

You are getting that error because Carl forgot to cast the descriptor
to the appropriate C type, in this case PyMemberDescrObject. The last
line is also incorrect, I think. Try something like this:

PyObject *descr = PyObject_GetAttrString(x,"attr_one");
Also note that x should be your object's type, i.e. o->ob_type cast to
PyObject *. The complete incantation would be:

// outside the loop
PyObject *descr = PyObject_GetAttrString((PyObject *) obj->ob_type,
"attr_one");
if (!descr)
return NULL;
int offset = ((PyMemberDescrObject *) descr)->d_member->offset;
Py_DECREF(descr);

// inside the loop
PyObject *value = *(PyObject **)((char *)obj + offset);
if (!value) {
PyErr_SetString(PyExc_AttributeError, "attribute missing");
return NULL;
}
// Remember to Py_INCREF(value) before using it and Py_DECREF it after
// using it. Otherwise if the object changes its slot to something
// else, you might be using a dead object.

With this code, accessing the value is practically free once the
offset is calculated. Here is a bench3 function updated to use this
strategy:

static PyObject *
bench3(PyObject *ignored, PyObject *obj)
{
PyObject *descr = PyObject_GetAttrString((PyObject *) obj->ob_type,
"abcdef");
if (!descr)
return NULL;

// Here you should also assert that PyObject_TypeCheck(descr,
// PyMemberDescr_Type) holds true. Since PyMemberDescr_Type is static,
// you'll have to get it by stashing away ob_type of a value known to be
// the descriptor. This is left as excercise to the reader.

int offset = ((PyMemberDescrObject *) descr)->d_member->offset;
Py_DECREF(descr);

int i;
PyObject *volatile attr; // 'volatile' for benchmarking, prevents gcc
// from optimizing away the loop
for (i = 0; i < 1000000; i++) {
attr = *(PyObject **)((char *)obj + offset);
}
Py_INCREF(attr);
return attr; // to prove that we retrieved the correct value
}
>>t0 = time.time(); attr.bench3(o); t1 = time.time()
1
>>t1-t0
0.00071597099304199219 # for 1,000,000 iterations, as cheap as it gets
Sep 12 '08 #9
On Sep 12, 10:01*am, Hrvoje Niksic <hnik...@xemacs.orgwrote:
Chris <ceb...@users.sourceforge.netwrites:
descr = GetAttrString(cls,"varname");
offset = descr->d_member->offset;
slotvar = (PyObject*)(((char*)obj)+offset)
Unfortunately, I am inexperienced at this kind of thing, so I wasn't
able to get something working. Maybe someone could tell me what's
wrong with the code below (it gives the error "'struct _object' has no
member named 'd_member'")?

You are getting that error because Carl forgot to cast the descriptor
to the appropriate C type, in this case PyMemberDescrObject. *The last
line is also incorrect, I think.
Yep, was in too much of a hurry to waste too much time showing how to
do something slightly dubious.

The offsetof() macro would help for the third line (in fact, it's the
recommended standard way since there are some C implmentions,
somewhere, that the pointer artithmetic method fails).
Carl Banks
Sep 12 '08 #10
Hrvoje Niksic <hniksic <atxemacs.orgwrites:
....
You are getting that error because Carl forgot to cast the descriptor
to the appropriate C type, in this case PyMemberDescrObject. The last
line is also incorrect, I think. Try something like this:
....

The code you gave was great, thanks! Now we have done exactly what we
wanted, and have fast access from C to two particular attributes of
instances of a particular class.

We use that fast access in optimized versions of pure-Python
components of our simulator.

Chris
Sep 16 '08 #11

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: George Grodentzik | last post by:
I created a typed dataset from which I am trying to access the data. When I use the following code to access a row string name =dataset.person.firstName I receive an error...
4
by: Bradley Grant | last post by:
Does anyone out there know of where I could find some C# example programs for accessing USB Devices. There just does not seem to be much out there on this subject. Even after doing a Google,...
6
by: Charlie | last post by:
Hi: The code to add items to shopping cart is a seperate class file so I don't have to keep repeating it. If I want to be able to access session data in this class, which class should I base it...
0
by: Remco | last post by:
I am having troubles accessing an asp.net mobile web application. When I run the page on my wap-enabled mobile phone (or with an wap emulator like www.wapsilon.com), I get an error message saying:...
0
by: Joergen Bech | last post by:
Fairly new to ASP.NET 1.1. Getting the error below when running application on a web server outside of my control, but only the first time I run it: 1. After a long period of inactivity (or...
5
by: Daniel Corbett | last post by:
I am trying to save a file dynamically created in a webpage. I get the following headers, but cannot figure out how to save the attachment. I am basically trying to replicate what internet...
0
by: Doug Caldwell | last post by:
Hi! ** Accessing the USGS Web Service Using Python ** I am trying to access the US Geological Survey's gazetteer SOAP web service using Python to find the locations of all the places with the...
4
by: SteveT | last post by:
I am wanting to populate several treeviews, one for the <TRs> group and one for the <TGsgroup. Is there a simplier way to populate the Treeview than the one I did below? It seems difficult to...
1
by: Christian Heimes | last post by:
Peter Robinson schrieb: As John already said: UTF-8 ain't unicode. UTF-8 is an encoding similar to ASCII or Latin-1 but different in its inner workings. A single character may be encoded by up...
1
Plater
by: Plater | last post by:
I have a webservice that claims the following: SOAP 1.1 The following is a sample SOAP 1.1 request and response. The placeholders shown need to be replaced with actual values. POST...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.