Generated by Cython 0.29b1
Yellow lines hint at Python interaction.
Click on a line that starts with a "+
" to see the C code that Cython generated for it.
Raw output: test.c
001: #cython: language_level = 3
002: from cython.parallel import parallel
003: from libc.stdio cimport printf
004: """
005: GOAL: implement nogil option in cdef class (extension types)
006: and native memory manager (refcount based) that does not
007: depend on cpython's memory manager and that does not require GIL.
008:
009: HINT: look at C++ standard library (that works very nicely with Cython)
010:
011: Cython documentation if here: http://docs.cython.org/en/latest/
012:
013: Basic usage: http://docs.cython.org/en/latest/src/quickstart/build.html
014:
015: Tutorial: http://docs.cython.org/en/latest/src/tutorial/cython_tutorial.html
016:
017: Language: http://docs.cython.org/en/latest/src/userguide/language_basics.html
018:
019: Extension types: http://docs.cython.org/en/latest/src/userguide/extension_types.html
020:
021: Extension Types are the "pure cython" classes that I want to be able to
022: use without depending on cpython GIL (and in essence runtime, memory manager, etc.)
023:
024: Cython memory allocation: http://docs.cython.org/en/latest/src/tutorial/memory_allocation.html
025:
026: Parallelism: http://docs.cython.org/en/latest/src/userguide/parallelism.html
027:
028: Explains how nogil is posisble in cython for anything that
029: only relies on C libraries that are multi-threaded
030: """
031:
032:
033:
034: # cdef class SomeMemory:
+035: cdef class SomeMemory nogil:
struct __pyx_obj_4test_SomeMemory { // nogil size_t ob_refcnt; struct __pyx_vtabstruct_4test_SomeMemory *__pyx_vtab; double a; double b; }; struct __pyx_vtabstruct_4test_SomeMemory { void (*foo)(struct __pyx_obj_4test_SomeMemory *); }; static struct __pyx_vtabstruct_4test_SomeMemory *__pyx_vtabptr_4test_SomeMemory;
036: """
037: This is a cdef class which is also called
038: a extensino type. It is a kind of C struct
039: that also acts as a python object.
040:
041: We would like to be able to define "nogil"
042: extension types:
043:
044: cdef class SomeMemory nogil:
045:
046: where all methods are "nogil" and memory
047: allocation does not depend on python runtime
048: """
049: cdef double a;
050: cdef double b;
051:
+052: cdef void foo(self) nogil:
static void __pyx_f_4test_10SomeMemory_foo(struct __pyx_obj_4test_SomeMemory *__pyx_v_self) { /* … */ /* function exit code */ }
053: """
054: It is possible to define native C/Cython methods
055: that release the GIL (cool...)
056: """
+057: while 1:
while (1) {
+058: self.a += 1
__pyx_v_self->a = (__pyx_v_self->a + 1.0); }
059:
060: # Not allowed to define pure Python function in the extension type with nogil option now
061: # since we want this extension type is CPython free
062: # def baz(self):
063: # """
064: # It is also possible to define standard python
065: # methods
066: # """
067: # pass
068:
069:
070: # cdef bar(): # it is currently impossible to release GIL
+071: cdef double bar() nogil: # yet this is what we would like to
static double __pyx_f_4test_bar(void) { struct __pyx_obj_4test_SomeMemory *__pyx_v_o1 = 0; struct __pyx_obj_4test_SomeMemory *__pyx_v_o2 = 0; double __pyx_r; /* … */ /* function exit code */ __pyx_L0:; return __pyx_r; }
072: """
073: This is a pure "cython method" which we would like to
074: be able to declare with nogil option but this requires
075: to first introduce the concept of nogil in cdef class
076: """
077: # cdef SomeMemory o = SomeMemory(42.0, 3.14) # for this we need class allocation to handle memory without libpython
+078: cdef SomeMemory o1 = SomeMemory(1, 1.0)
__pyx_t_1 = (struct __pyx_obj_4test_SomeMemory *)malloc(sizeof(struct __pyx_obj_4test_SomeMemory)); __pyx_t_1->a = 1.0; __pyx_t_1->b = 1.0; __pyx_v_o1 = __pyx_t_1;
+079: cdef SomeMemory o2 = SomeMemory(2, 2.0)
__pyx_t_1 = (struct __pyx_obj_4test_SomeMemory *)malloc(sizeof(struct __pyx_obj_4test_SomeMemory)); __pyx_t_1->a = 2.0; __pyx_t_1->b = 2.0; __pyx_v_o2 = __pyx_t_1;
+080: with nogil, parallel():
{ #ifdef WITH_THREAD PyThreadState *_save; Py_UNBLOCK_THREADS __Pyx_FastGIL_Remember(); #endif /*try:*/ { { #if ((defined(__APPLE__) || defined(__OSX__)) && (defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))))) #undef likely #undef unlikely #define likely(x) (x) #define unlikely(x) (x) #endif #ifdef _OPENMP #pragma omp parallel #endif /* _OPENMP */ { /* … */ /*finally:*/ { /*normal exit:*/{ #ifdef WITH_THREAD __Pyx_FastGIL_Forget(); Py_BLOCK_THREADS #endif goto __pyx_L5; } __pyx_L5:; } }
+081: o1.foo()
__pyx_f_4test_10SomeMemory_foo(__pyx_v_o1);
+082: o2.foo()
__pyx_f_4test_10SomeMemory_foo(__pyx_v_o2); } } #if ((defined(__APPLE__) || defined(__OSX__)) && (defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))))) #undef likely #undef unlikely #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) #endif }
083: # o.foo() # and we need method selection to be independent of libpython
084: # o.foo1(2)
085: # o.a = 2.732
086: # o.fact(100)
087:
+088: return o1.a
__pyx_r = __pyx_v_o1->a; goto __pyx_L0;
089:
+090: cpdef baz():
static PyObject *__pyx_pw_4test_1baz(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused); /*proto*/ static PyObject *__pyx_f_4test_baz(CYTHON_UNUSED int __pyx_skip_dispatch) { PyObject *__pyx_r = NULL; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("baz", 0); /* … */ /* function exit code */ __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_AddTraceback("test.baz", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = 0; __pyx_L0:; __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* Python wrapper */ static PyObject *__pyx_pw_4test_1baz(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused); /*proto*/ static char __pyx_doc_4test_baz[] = "\n This method is both callable from python and pure \"cython\".\n It can call both cdef methods and usual python functions\n "; static PyObject *__pyx_pw_4test_1baz(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused) { PyObject *__pyx_r = 0; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("baz (wrapper)", 0); __pyx_r = __pyx_pf_4test_baz(__pyx_self); /* function exit code */ __Pyx_RefNannyFinishContext(); return __pyx_r; } static PyObject *__pyx_pf_4test_baz(CYTHON_UNUSED PyObject *__pyx_self) { PyObject *__pyx_r = NULL; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("baz", 0); __Pyx_XDECREF(__pyx_r); __pyx_t_1 = __pyx_f_4test_baz(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 90, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); __pyx_r = __pyx_t_1; __pyx_t_1 = 0; goto __pyx_L0; /* function exit code */ __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_AddTraceback("test.baz", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = NULL; __pyx_L0:; __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; }
091: """
092: This method is both callable from python and pure "cython".
093: It can call both cdef methods and usual python functions
094: """
+095: return bar()
__Pyx_XDECREF(__pyx_r); __pyx_t_1 = PyFloat_FromDouble(__pyx_f_4test_bar()); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 95, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); __pyx_r = __pyx_t_1; __pyx_t_1 = 0; goto __pyx_L0;
096:
+097: def bag():
/* Python wrapper */ static PyObject *__pyx_pw_4test_3bag(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused); /*proto*/ static PyMethodDef __pyx_mdef_4test_3bag = {"bag", (PyCFunction)__pyx_pw_4test_3bag, METH_NOARGS, 0}; static PyObject *__pyx_pw_4test_3bag(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused) { PyObject *__pyx_r = 0; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("bag (wrapper)", 0); __pyx_r = __pyx_pf_4test_2bag(__pyx_self); /* function exit code */ __Pyx_RefNannyFinishContext(); return __pyx_r; } static PyObject *__pyx_pf_4test_2bag(CYTHON_UNUSED PyObject *__pyx_self) { PyObject *__pyx_r = NULL; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("bag", 0); /* … */ /* function exit code */ __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_XDECREF(__pyx_t_2); __Pyx_AddTraceback("test.bag", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = NULL; __pyx_L0:; __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* … */ __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_4test_3bag, NULL, __pyx_n_s_test); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 97, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); if (PyDict_SetItem(__pyx_d, __pyx_n_s_bag, __pyx_t_1) < 0) __PYX_ERR(0, 97, __pyx_L1_error) __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; /* … */ __pyx_codeobj_ = (PyObject*)__Pyx_PyCode_New(0, 0, 0, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_test_pyx, __pyx_n_s_bag, 97, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj_)) __PYX_ERR(0, 97, __pyx_L1_error)
+098: return str(baz())
__Pyx_XDECREF(__pyx_r); __pyx_t_1 = __pyx_f_4test_baz(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 98, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); __pyx_t_2 = __Pyx_PyObject_CallOneArg(((PyObject *)(&PyUnicode_Type)), __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 98, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __pyx_r = __pyx_t_2; __pyx_t_2 = 0; goto __pyx_L0;
099:
100: # We call here a cpdef function, which calls a def function
101: # which then allocates cdef class SomeMemory
+102: print(bag())
__Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_bag); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 102, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); __pyx_t_2 = __Pyx_PyObject_CallNoArg(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 102, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_builtin_print, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 102, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+103: print("done")
__pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_print, __pyx_tuple__2, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 103, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;