def test_new_handle(self): ffi = FFI(backend=self.Backend()) o = [2, 3, 4] p = ffi.new_handle(o) assert ffi.typeof(p) == ffi.typeof("void *") assert ffi.from_handle(p) is o assert ffi.from_handle(ffi.cast("char *", p)) is o py.test.raises(RuntimeError, ffi.from_handle, ffi.NULL)
class CTC(object): """ """ def __init__(self, on_device='cpu', blank_label=0): libpath = get_ctc_lib() self.ffi = FFI() self.ffi.cdef(ctc_header()) self.ctclib = self.ffi.dlopen(libpath) supported_devices = ['cpu', 'gpu'] if on_device not in supported_devices: print("the requested device {} is not supported".format(on_device), file=sys.stderr) sys.exit(1) assign_device = 0 if on_device is 'cpu' else 1 self.options = self.ffi.new('ctcOptions*', { "loc": assign_device, "blank_label": blank_label })[0] self.size_in_bytes = self.ffi.new("size_t*") self.nout = None self.bsz = None def get_buf_size(self, ptr_to_buf): return self.ffi.sizeof( self.ffi.getctype(self.ffi.typeof(ptr_to_buf).item)) def buf_ref_from_array(self, arr): return self.ffi.from_buffer( self.ffi.buffer(self.ffi.cast('void*', arr.ptr), arr.nbytes)) def buf_ref_from_ptr(self, ptr, size): return self.ffi.from_buffer(self.ffi.buffer(ptr, size)) def get_gpu_workspace_size(self, lbl_lens, utt_lens, nout, bsz): self.nout = nout self.bsz = bsz _lbl_lens = self.ffi.cast("int*", lbl_lens.ravel().ctypes.data) _utt_lens = self.ffi.cast("int*", utt_lens.ravel().ctypes.data) status = self.ctclib.get_workspace_size(_lbl_lens, _utt_lens, self.nout, self.bsz, self.options, self.size_in_bytes) assert status is 0, "get_workspace_size() in warp-ctc failed" return self.size_in_bytes[0] def bind_to_gpu(self, acts, grads, lbls, lbl_lens, utt_lens, costs, workspace, scratch_size, stream): if stream is None: stream_ptr = self.ffi.cast('void*', 0) stream_buf_size = self.ffi.sizeof(self.ffi.new_handle(stream)) stream_buf = self.buf_ref_from_ptr(stream_ptr, stream_buf_size) else: stream_buf = self.ffi.cast("void*", stream.handle) self.options.stream = stream_buf flat_dims = np.prod(acts.shape) assert np.prod(grads.shape) == flat_dims acts_buf = self.ffi.cast("float*", self.buf_ref_from_array(acts)) grads_buf = self.ffi.cast("float*", self.buf_ref_from_array(grads)) costs_buf = self.ffi.cast("float*", self.buf_ref_from_array(costs)) warp_grads_buf_size = flat_dims * self.get_buf_size(grads_buf) warp_costs_buf_size = self.bsz * self.get_buf_size(costs_buf) warp_labels = self.ffi.cast("int*", lbls.ravel().ctypes.data) warp_label_lens = self.ffi.cast("int*", lbl_lens.ravel().ctypes.data) warp_input_lens = self.ffi.cast("int*", utt_lens.ravel().ctypes.data) workspace_buf = self.buf_ref_from_ptr( self.ffi.cast('void*', workspace), int(scratch_size)) ctc_status = self.ctclib.compute_ctc_loss(acts_buf, grads_buf, warp_labels, warp_label_lens, warp_input_lens, self.nout, self.bsz, costs_buf, workspace_buf, self.options) assert ctc_status is 0, "warp-ctc run failed" def bind_to_cpu(self, acts, lbls, utt_lens, lbl_lens, grads, costs, n_threads=1): self.options.num_threads = n_threads _, self.bsz, self.nout = acts.shape flat_dims = np.prod(acts.shape) assert np.prod(grads.shape) == flat_dims acts_buf = self.ffi.cast("float*", acts.ctypes.data) grads_buf = self.ffi.cast("float*", grads.ctypes.data) costs_buf = self.ffi.cast("float*", costs.ctypes.data) warp_grads_buf_size = flat_dims * self.get_buf_size(grads_buf) warp_costs_buf_size = self.bsz * self.get_buf_size(costs_buf) warp_labels = self.ffi.cast("int*", lbls.ravel().ctypes.data) warp_label_lens = self.ffi.cast("int*", lbl_lens.ravel().ctypes.data) warp_input_lens = self.ffi.cast("int*", utt_lens.ravel().ctypes.data) status = self.ctclib.get_workspace_size(warp_label_lens, warp_input_lens, self.nout, self.bsz, self.options, self.size_in_bytes) assert status is 0, "get_workspace_size() in warp-ctc failed" # TODO: workspace is a variable size buffer whose size is # determined during each call, so we can't initialize ahead # of time. Can we avoid this? workspace = self.ffi.new("char[]", self.size_in_bytes[0]) ctc_status = self.ctclib.compute_ctc_loss(acts_buf, grads_buf, warp_labels, warp_label_lens, warp_input_lens, self.nout, self.bsz, costs_buf, workspace, self.options) # transfer grads and costs back without copying self.ffi.memmove(grads, grads_buf, warp_grads_buf_size) grads = grads.reshape((acts.shape)) self.ffi.memmove(costs, costs_buf, warp_costs_buf_size) assert ctc_status is 0, "warp-ctc run failed"
class LibGraphqlParser: def __init__(self): self._ffi = FFI() self._ffi.cdef(CDEFS_LIBGRAPHQL) # TODO do a conf of this ? try: self._lib = self._ffi.dlopen("/usr/local/lib/libgraphqlparser.so") except OSError: self._lib = self._ffi.dlopen("/usr/local/lib/libgraphqlparser.dylib") self._lib_callbacks = self._ffi.new( "struct GraphQLAstVisitorCallbacks *" ) self._errors = self._ffi.new("char **") self._callbacks = [] self._interested_by = {} self._default_visitor_cls = Visitor self._creates_callbacks() def _create_visitor_element(self, libgraphql_type, element): try: return _LIBGRAPHQL_TYPE_TO_CLASS[libgraphql_type]( self._lib, self._ffi, element) except KeyError: pass return _VisitorElement(self._lib, self._ffi, libgraphql_type, element) def _callback_enter(self, libgraphql_type, element, udata): context = self._ffi.from_handle(udata) context.update( Visitor.IN, self._create_visitor_element(libgraphql_type, element) ) return context.continue_child def _callback_exit(self, libgraphql_type, element, udata): context = self._ffi.from_handle(udata) if context.continue_child: context.update( Visitor.OUT, self._create_visitor_element(libgraphql_type, element) ) return None def _set_callback(self, proto, func, attr): c_func = self._ffi.callback(proto)(func) # Keep the callbacks alive in this list # to keep the underlying cdata alive. # because we do it with reflexion and # not with decoration self._callbacks.append(c_func) setattr(self._lib_callbacks, attr, c_func) def _set_exit_callback(self, typee): self._set_callback( "void(struct GraphQLAst%s *, void *)" % typee[0], partial(self._callback_exit, typee[0]), "end_visit_%s" % typee[1] ) def _set_enter_callback(self, typee): self._set_callback( "int(struct GraphQLAst%s *, void *)" % typee[0], partial(self._callback_enter, typee[0]), "visit_%s" % typee[1] ) def _creates_callbacks(self): for typee in TYPES_LIBGRAPHQL: if typee[0] not in ["Name"]: self._set_enter_callback(typee) self._set_exit_callback(typee) def _parse(self, query): if isinstance(query, str): # TODO don't replace here. query = query.replace("\n", " ").encode("UTF-8") c_query = self._ffi.new("char[]", query) parsed_data = _ParsedData( self._lib.graphql_parse_string(c_query, self._errors), self._lib.graphql_node_free ) if self._errors[0] != self._ffi.NULL: # TODO specialize Exception here e = Exception( self._ffi.string(self._errors[0]).decode('UTF-8', 'replace') ) self._lib.graphql_error_free(self._errors[0]) raise e return parsed_data def parse_and_visit(self, query, ctx=None): if not ctx: ctx = self._default_visitor_cls() with self._parse(query) as parsed: self._lib.graphql_node_visit( parsed, self._lib_callbacks, self._ffi.new_handle(ctx) ) def parse_and_jsonify(self, query): with self._parse(query) as parsed: return self._ffi.string(self._lib.graphql_ast_to_json(parsed))
# -*- coding: utf-8 -*- # TODO: this does not works. from cffi import FFI ffi = FFI() ffi.cdef(""" void print_address(void *obj); """) c_lib = ffi.dlopen("./libsample2.so") class Foo(object): def __init__(self, address): self.address = address def get_address(self): return self.address print_address = c_lib.print_address instance = Foo("Foo Bar") _instance = ffi.new_handle(instance) print_address(instance)