Major speedup for module inheritance, thanks to Pyrex! The 'codeIndex()' object and associated iterators are now in C, and the speedup is quite visible. It's still not as fast as I'd like, but the next step would be to rewrite 'prepForSimulation()' in Pyrex, and it's a lot more complex than the 'codeIndex' class. Unfortunately, you can't just copy your code into a .pyx file and expect a speedup; you have to think in C even if the syntax is Pythonic. Nonetheless, module inheritance spent so much time in the old 'codeIndex.__init__' method that it was worth the hour or two it took to convert. Added support for Pyrex.Distutils to automatically build from .pyx; if you're using 'mingw32' and Greg hasn't released my fixes yet, you may want to edit setup.py to force it to compile from .c files instead and run 'pyrexc' manually against the '.pyx' files. If you want to tinker with the 'pyx' source files, you'll want to install Pyrex 0.4.6 or better.
cdef extern from "Python.h": void* PyMem_Malloc(int n) except NULL void* PyMem_Realloc(void *p, int n) except NULL void PyMem_Free(void *p) int PyObject_AsReadBuffer(object obj, void **buffer, int *buffer_len) except -1 cdef extern from "opcode.h": unsigned char HAS_ARG(unsigned char op) enum: EXTENDED_ARG cdef class codeIndex cdef class opIter: cdef codeIndex cidx cdef int pos def __init__(self, codeIndex cidx, int pos): self.cidx = cidx self.pos = pos def __iter__(self): return self def __next__(self): cdef int pos cdef codeIndex c pos = self.pos if self.pos == -1: raise StopIteration c = self.cidx # XXX Pyrex croaks on self.cidx.opcodeChain[] self.pos = c.opcodeChain[pos] return pos cdef class codeIndex: """Useful indexes over a code object opcodeLocations[op] -- list of instruction numbers with 'op' as opcode opcode[i] -- the i'th instruction's opcode operand[i] -- the i'th instruction's operand (or None) offset[i] -- location of the i'th instruction byteLine[b] -- source line number that generated byte 'b' """ cdef object code cdef int *opcodeHeads, *operands, *offsets, *byteLines, *opcodeChain cdef unsigned char *opcodes cdef int length, codelen def __new__(self, codeObject): self.opcodeHeads=NULL self.opcodeChain=NULL self.operands=NULL self.offsets=NULL self.byteLines=NULL self.opcodes=NULL def __dealloc__(self): if self.opcodeHeads: PyMem_Free(self.opcodeHeads) if self.opcodeChain: PyMem_Free(self.opcodeChain) if self.operands: PyMem_Free(self.operands) if self.offsets: PyMem_Free(self.offsets) if self.byteLines: PyMem_Free(self.byteLines) if self.opcodes: PyMem_Free(self.opcodes) def __init__(self, codeObject): self.code = codeObject cdef int l, s, arg, end, start, p cdef unsigned char *ca cdef unsigned char op PyObject_AsReadBuffer(codeObject.co_code, <void **>(&ca), &l) s = l * sizeof(int) self.opcodeHeads = <int *>PyMem_Malloc(256 * sizeof(int)) self.opcodeChain = <int *>PyMem_Malloc(s) self.operands = <int *>PyMem_Malloc(s) self.offsets = <int *>PyMem_Malloc(s) self.byteLines = <int *>PyMem_Malloc(s) self.opcodes = <unsigned char *>PyMem_Malloc(l) p = 0 end = 0 start = end while end < l: op = ca[start] if HAS_ARG(op): arg = ca[start+1] | ca[start+2]<<8 if op==EXTENDED_ARG: op = ca[start+3] end = start+6 arg = arg << 16 arg = arg + (ca[start+4] | ca[start+5]<<8) else: end = start+3 else: arg = 0 end = start+1 self.opcodes[p] = op self.operands[p] = arg self.offsets[p] = start p = p+1 start = end self.length = p self.codelen = l PyObject_AsReadBuffer(codeObject.co_lnotab, <void **>(&ca), &end) p = 0 arg = codeObject.co_firstlineno start = 0 while p<end: for s from 0 <= s < ca[p]: self.byteLines[start+s] = arg start = start + ca[p] arg = arg + ca[p+1] p = p + 2 while start<l: self.byteLines[start]=arg start = start + 1 for s from 0 <= s < 256: self.opcodeHeads[s] = -1 p = self.length while p: p = p - 1 op = self.opcodes[p] self.opcodeChain[p] = self.opcodeHeads[op] self.opcodeHeads[op] = p def opcodeLocations(self, int op): if op<0 or op>255: raise IndexError, op return opIter(self, self.opcodeHeads[op]) def operand(self, int p): if p<0 or p>=self.length: raise IndexError, p return self.operands[p] def opcode(self, int p): if p<0 or p>=self.length: raise IndexError, p return self.opcodes[p] def offset(self, int p): if p<0 or p>=self.length: raise IndexError, p return self.offsets[p] def byteLine(self, int p): if p<0 or p>=self.codelen: raise IndexError, p return self.byteLines[p]
cvs-admin@eby-sarna.com Powered by ViewCVS 1.0-dev |
ViewCVS and CVS Help |