Skip to content

Commit

Permalink
Speed up performance-critical pyclibrary calls
Browse files Browse the repository at this point in the history
- Added _fast_call and _fast_get as alternatives to _check and _get
- These are less convenient, but avoid lots of pyclibrary overhead
- Replaced time-critical _check and _get calls throughout the Python codebase
  • Loading branch information
benbarsdell committed Apr 27, 2017
1 parent 56028d4 commit e9ee657
Show file tree
Hide file tree
Showing 9 changed files with 72 additions and 26 deletions.
4 changes: 2 additions & 2 deletions python/bifrost/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

from libbifrost import _bf, _check, _get
from libbifrost import _bf, _check, _get, _fast_call

def set_device(device):
if isinstance(device, int):
Expand All @@ -39,4 +39,4 @@ def get_device():
# TODO: set/get_stream

def stream_synchronize():
_check(_bf.StreamSynchronize())
_fast_call(_bf.StreamSynchronize)
6 changes: 3 additions & 3 deletions python/bifrost/fdmt.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

from libbifrost import _bf, _check, _get, _string2space
from libbifrost import _bf, _check, _get, _fast_call, _string2space
from ndarray import asarray

import ctypes
Expand Down Expand Up @@ -59,9 +59,9 @@ def get_workspace_size(self, idata, odata):
def execute_workspace(self, idata, odata, workspace_ptr, workspace_size,
negative_delays=False):
size = _bf.BFsize(workspace_size)
_check( _bf.FdmtExecute(self.obj,
_fast_call(_bf.FdmtExecute, self.obj,
asarray(idata).as_BFarray(),
asarray(odata).as_BFarray(),
negative_delays,
workspace_ptr, ctypes.pointer(size)) )
workspace_ptr, ctypes.pointer(size))
return odata
6 changes: 3 additions & 3 deletions python/bifrost/fft.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

from libbifrost import _bf, _check, _get, _string2space
from libbifrost import _bf, _check, _get, _fast_call, _string2space
from ndarray import asarray
import ctypes

Expand Down Expand Up @@ -54,9 +54,9 @@ def execute(self, iarray, oarray, inverse=False):
inverse=inverse)
def execute_workspace(self, iarray, oarray, workspace_ptr, workspace_size,
inverse=False):
_check( _bf.FftExecute(self.obj,
_fast_call(_bf.FftExecute, self.obj,
asarray(iarray).as_BFarray(),
asarray(oarray).as_BFarray(),
inverse,
workspace_ptr, workspace_size) )
workspace_ptr, workspace_size)
return oarray
44 changes: 44 additions & 0 deletions python/bifrost/libbifrost.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
# ArgumentError: argument 1: <type 'exceptions.TypeError'>: expected LP_s instance instead of LP_s
# E.g., _bf.RingSequenceGetName(<BFspan>) [should be <BFsequence>]

import ctypes

def _load_bifrost_lib():
import os
import glob
Expand Down Expand Up @@ -160,6 +162,48 @@ def _retval(f):
ret, args = f
return ret

# Note: These are much faster than _check and _get above, but less convenient
def _fast_call(f, *args):
# Note: f.func is much faster than f(*args, **kwargs)
return _check( (f.func(*args), None) )
def _fast_get(f, *args):
"""Calls the getter function f and returns the value from the last arg"""
# TODO: Is there a proper way to do this that supports general types?
DEREF = {ctypes.POINTER(t): t for t in [ctypes.c_bool,
ctypes.c_char,
ctypes.c_char_p,
ctypes.c_float,
ctypes.c_double,
ctypes.c_longdouble,
ctypes.c_int,
ctypes.c_int8,
ctypes.c_int16,
ctypes.c_int32,
ctypes.c_int64,
ctypes.c_long,
ctypes.c_longlong,
ctypes.c_short,
ctypes.c_size_t,
ctypes.c_ssize_t,
ctypes.c_uint,
ctypes.c_uint8,
ctypes.c_uint16,
ctypes.c_uint32,
ctypes.c_uint64,
ctypes.c_ulong,
ctypes.c_ulonglong,
ctypes.c_ushort,
ctypes.c_void_p,
ctypes.c_wchar,
ctypes.c_wchar_p]}
ff = f.func
retarg = -1
dtype = DEREF[ff.argtypes[retarg]]
ret_val = dtype()
args = args + (ctypes.byref(ret_val),)
_check( (ff(*args), None) )
return ret_val.value

def _string2space(s):
lut = {'auto': _bf.BF_SPACE_AUTO,
'system': _bf.BF_SPACE_SYSTEM,
Expand Down
1 change: 0 additions & 1 deletion python/bifrost/ndarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ def copy_array(dst, src):

def memset_array(dst, value):
dst_bf = asarray(dst)
#_check(_bf.ArrayMemset(dst_bf.as_BFarray(), value))
_fast_call(_bf.ArrayMemset, dst_bf.as_BFarray(), value)
return dst

Expand Down
6 changes: 3 additions & 3 deletions python/bifrost/quantize.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

from libbifrost import _bf, _check, _get
from libbifrost import _bf, _check, _get, _fast_call
from ndarray import asarray

def quantize(src, dst, scale=1.):
src_bf = asarray(src).as_BFarray()
dst_bf = asarray(dst).as_BFarray()
_check(_bf.Quantize(src_bf,
_fast_call(_bf.Quantize, src_bf,
dst_bf,
scale))
scale)
return dst
21 changes: 12 additions & 9 deletions python/bifrost/ring2.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
# TODO: Some of this code has gotten a bit hacky
# Also consider merging some of the logic into the backend

from libbifrost import _bf, _check, _get, _string2space, _space2string
from libbifrost import _bf, _check, _get, _string2space, _space2string, _fast_call, _fast_get
from DataType import DataType
from ndarray import ndarray
from copy import copy, deepcopy
Expand Down Expand Up @@ -313,7 +313,8 @@ def _set_base_obj(self, obj):
self._base_obj = ctypes.cast(obj, _bf.BFspan)
self._cache_info()
def _cache_info(self):
self._info = _get(_bf.RingSpanGetInfo(self._base_obj))
self._info = _bf.BFspan_info()
_fast_call(_bf.bfRingSpanGetInfo, self._base_obj, self._info)
@property
def ring(self):
return self._ring
Expand Down Expand Up @@ -405,7 +406,8 @@ def __init__(self,
nframe):
SpanBase.__init__(self, ring, sequence, writeable=True)
nbyte = nframe * self.tensor['frame_nbyte']
self.obj = _get(_bf.RingSpanReserve(ring=ring.obj, size=nbyte), retarg=0)
self.obj = _bf.BFwspan()
_fast_call(_bf.RingSpanReserve, self.obj, ring.obj, nbyte)
self._set_base_obj(self.obj)
self.commit_nframe = nframe
# TODO: Why do exceptions here not show up properly?
Expand All @@ -418,20 +420,21 @@ def __exit__(self, type, value, tb):
self.close()
def close(self):
commit_nbyte = self.commit_nframe * self.tensor['frame_nbyte']
_check(_bf.RingSpanCommit(self.obj, commit_nbyte))
_fast_call(_bf.RingSpanCommit, self.obj, commit_nbyte)

class ReadSpan(SpanBase):
def __init__(self, sequence, frame_offset, nframe):
SpanBase.__init__(self, sequence.ring, sequence, writeable=False)
tensor = sequence.tensor
self.obj = _get(_bf.RingSpanAcquire(sequence=sequence.obj,
offset=frame_offset*tensor['frame_nbyte'],
size=nframe*tensor['frame_nbyte']),
retarg=0)
self.obj = _bf.BFrspan()
_fast_call(_bf.RingSpanAcquire, self.obj,
sequence.obj,
frame_offset*tensor['frame_nbyte'],
nframe*tensor['frame_nbyte'])
self._set_base_obj(self.obj)
def __enter__(self):
return self
def __exit__(self, type, value, tb):
self.release()
def release(self):
_check(_bf.RingSpanRelease(self.obj))
_fast_call(_bf.RingSpanRelease, self.obj)
4 changes: 2 additions & 2 deletions python/bifrost/udp_capture.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

from libbifrost import _bf, _check, _get, _string2space, _space2string
from libbifrost import _bf, _check, _get, _fast_get, _string2space, _space2string

import ctypes
import numpy as np
Expand Down Expand Up @@ -55,7 +55,7 @@ def __enter__(self):
def __exit__(self, type, value, tb):
self.end()
def recv(self):
return _get( _bf.UdpCaptureRecv(self.obj) )
return _fast_get(_bf.UdpCaptureRecv, self.obj)
def flush(self):
_check( _bf.UdpCaptureFlush(self.obj) )
def end(self):
Expand Down
6 changes: 3 additions & 3 deletions python/bifrost/unpack.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

from libbifrost import _bf, _check, _get
from libbifrost import _bf, _check, _fast_call, _get
from ndarray import asarray

def unpack(src, dst, align_msb=False):
src_bf = asarray(src).as_BFarray()
dst_bf = asarray(dst).as_BFarray()
_check(_bf.Unpack(src_bf,
_fast_call(_bf.Unpack, src_bf,
dst_bf,
align_msb))
align_msb)
return dst

0 comments on commit e9ee657

Please sign in to comment.