#include "wrap_cl.h" #include "pyhelper.h" #include "clobj.h" #include #include #include #include #include #include #ifndef __PYOPENCL_ERROR_H #define __PYOPENCL_ERROR_H namespace pyopencl { // {{{ error class clerror : public std::runtime_error { private: const char *m_routine; cl_int m_code; public: clerror(const char *rout, cl_int c, const char *msg="") : std::runtime_error(msg), m_routine(rout), m_code(c) { std::cout << rout <<";" << msg<< ";" << c << std::endl; } PYOPENCL_INLINE const char* routine() const { return m_routine; } PYOPENCL_INLINE cl_int code() const { return m_code; } PYOPENCL_INLINE bool is_out_of_memory() const { return (code() == CL_MEM_OBJECT_ALLOCATION_FAILURE || code() == CL_OUT_OF_RESOURCES || code() == CL_OUT_OF_HOST_MEMORY); } }; // }}} // {{{ tracing and error reporting template struct __CLArgGetter { template static PYOPENCL_INLINE auto get(T&& clarg) -> decltype(clarg.convert()) { return clarg.convert(); } }; template struct __CLFinish { static PYOPENCL_INLINE void call(T, bool) { } }; template struct __CLFinish().finish(true)))> { static PYOPENCL_INLINE void call(T v, bool converted) { v.finish(converted); } }; template struct __CLPost { static PYOPENCL_INLINE void call(T) { } }; template struct __CLPost().post()))> { static PYOPENCL_INLINE void call(T v) { v.post(); } }; template struct is_out_arg : std::false_type {}; template struct is_out_arg::is_out> > : std::true_type {}; template struct __CLPrintOut { static PYOPENCL_INLINE void call(T, std::ostream&) { } }; template struct __CLPrintOut::value> > { static inline void call(T v, std::ostream &stm) { stm << ", "; v.print(stm, true); } }; template struct __CLPrint { static inline void call(T v, std::ostream &stm, bool &&first) { if (!first) { stm << ", "; } else { first = false; } if (is_out_arg::value) { stm << "{out}"; } v.print(stm); } }; template class Caller, size_t n, typename T> struct __CLCall { template static PYOPENCL_INLINE void call(T &&t, Ts&&... ts) { __CLCall::call(std::forward(t), std::forward(ts)...); Caller(t))>::call(std::get(t), std::forward(ts)...); } }; template class Caller, typename T> struct __CLCall { template static PYOPENCL_INLINE void call(T &&t, Ts&&... ts) { Caller(t))>::call(std::get<0>(t), std::forward(ts)...); } }; template class CLArgPack : public ArgPack { template void _print_trace(T &res, const char *name) { typename CLArgPack::tuple_base *that = this; std::cerr << name << "("; __CLCall<__CLPrint, sizeof...(Types) - 1, decltype(*that)>::call(*that, std::cerr, true); std::cerr << ") = (ret: " << res; __CLCall<__CLPrintOut, sizeof...(Types) - 1, decltype(*that)>::call(*that, std::cerr); std::cerr << ")" << std::endl; } public: using ArgPack::ArgPack; template PYOPENCL_INLINE auto clcall(Func func, const char *name) -> decltype(this->template call<__CLArgGetter>(func)) { auto res = this->template call<__CLArgGetter>(func); if (DEBUG_ON) { _print_trace(res, name); } return res; } PYOPENCL_INLINE void finish() { typename CLArgPack::tuple_base *that = this; __CLCall<__CLFinish, sizeof...(Types) - 1, decltype(*that)>::call(*that, false); __CLCall<__CLPost, sizeof...(Types) - 1, decltype(*that)>::call(*that); __CLCall<__CLFinish, sizeof...(Types) - 1, decltype(*that)>::call(*that, true); } }; template static PYOPENCL_INLINE CLArgPack...> make_clargpack(Types&&... args) { return CLArgPack...>(std::forward(args)...); } template static PYOPENCL_INLINE void call_guarded(cl_int (*func)(ArgTypes...), const char *name, ArgTypes2&&... args) { auto argpack = make_clargpack(std::forward(args)...); cl_int status_code = argpack.clcall(func, name); if (status_code != CL_SUCCESS) { throw clerror(name, status_code); } argpack.finish(); } template PYOPENCL_USE_RESULT static PYOPENCL_INLINE T call_guarded(T (*func)(ArgTypes...), const char *name, ArgTypes2&&... args) { cl_int status_code = CL_SUCCESS; auto status_arg = buf_arg(status_code); auto argpack = make_clargpack(std::forward(args)..., status_arg); T res = argpack.clcall(func, name); if (status_code != CL_SUCCESS) { throw clerror(name, status_code); } argpack.finish(); return res; } #define pyopencl_call_guarded(func, args...) \ pyopencl::call_guarded(func, #func, args) template static PYOPENCL_INLINE void call_guarded_cleanup(cl_int (*func)(ArgTypes...), const char *name, ArgTypes2&&... args) { auto argpack = make_clargpack(std::forward(args)...); cl_int status_code = argpack.clcall(func, name); if (status_code != CL_SUCCESS) { std::cerr << ("PyOpenCL WARNING: a clean-up operation failed " "(dead context maybe?)") << std::endl << name << " failed with code " << status_code << std::endl; } else { argpack.finish(); } } #define pyopencl_call_guarded_cleanup(func, args...) \ pyopencl::call_guarded_cleanup(func, #func, args) PYOPENCL_USE_RESULT static PYOPENCL_INLINE ::error* c_handle_error(std::function func) noexcept { try { func(); return nullptr; } catch (const clerror &e) { auto err = (::error*)malloc(sizeof(::error)); err->routine = strdup(e.routine()); err->msg = strdup(e.what()); err->code = e.code(); err->other = 0; return err; } catch (const std::exception &e) { /* non-pyopencl exceptions need to be converted as well */ auto err = (::error*)malloc(sizeof(::error)); err->other = 1; err->msg = strdup(e.what()); return err; } } template static PYOPENCL_INLINE auto retry_mem_error(Func func) -> decltype(func()) { try { return func(); } catch (clerror &e) { if (PYOPENCL_LIKELY(!e.is_out_of_memory()) || !py::gc()) { throw; } } return func(); } // }}} } #endif