Profile.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. /////////////// Profile.proto ///////////////
  2. //@requires: Exceptions.c::PyErrFetchRestore
  3. //@substitute: naming
  4. // Note that cPython ignores PyTrace_EXCEPTION,
  5. // but maybe some other profilers don't.
  6. #ifndef CYTHON_PROFILE
  7. #if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_PYSTON
  8. #define CYTHON_PROFILE 0
  9. #else
  10. #define CYTHON_PROFILE 1
  11. #endif
  12. #endif
  13. #ifndef CYTHON_TRACE_NOGIL
  14. #define CYTHON_TRACE_NOGIL 0
  15. #else
  16. #if CYTHON_TRACE_NOGIL && !defined(CYTHON_TRACE)
  17. #define CYTHON_TRACE 1
  18. #endif
  19. #endif
  20. #ifndef CYTHON_TRACE
  21. #define CYTHON_TRACE 0
  22. #endif
  23. #if CYTHON_TRACE
  24. #undef CYTHON_PROFILE_REUSE_FRAME
  25. #endif
  26. #ifndef CYTHON_PROFILE_REUSE_FRAME
  27. #define CYTHON_PROFILE_REUSE_FRAME 0
  28. #endif
  29. #if CYTHON_PROFILE || CYTHON_TRACE
  30. #include "compile.h"
  31. #include "frameobject.h"
  32. #include "traceback.h"
  33. #if PY_VERSION_HEX >= 0x030b00a6
  34. #ifndef Py_BUILD_CORE
  35. #define Py_BUILD_CORE 1
  36. #endif
  37. #error #include "internal/pycore_frame.h"
  38. #endif
  39. #if CYTHON_PROFILE_REUSE_FRAME
  40. #define CYTHON_FRAME_MODIFIER static
  41. #define CYTHON_FRAME_DEL(frame)
  42. #else
  43. #define CYTHON_FRAME_MODIFIER
  44. #define CYTHON_FRAME_DEL(frame) Py_CLEAR(frame)
  45. #endif
  46. #define __Pyx_TraceDeclarations \
  47. static PyCodeObject *$frame_code_cname = NULL; \
  48. CYTHON_FRAME_MODIFIER PyFrameObject *$frame_cname = NULL; \
  49. int __Pyx_use_tracing = 0;
  50. #define __Pyx_TraceFrameInit(codeobj) \
  51. if (codeobj) $frame_code_cname = (PyCodeObject*) codeobj;
  52. #if PY_VERSION_HEX >= 0x030b00a2
  53. #define __Pyx_IsTracing(tstate, check_tracing, check_funcs) \
  54. (unlikely((tstate)->cframe->use_tracing) && \
  55. (!(check_tracing) || !(tstate)->tracing) && \
  56. (!(check_funcs) || (tstate)->c_profilefunc || (CYTHON_TRACE && (tstate)->c_tracefunc)))
  57. #define __Pyx_EnterTracing(tstate) PyThreadState_EnterTracing(tstate)
  58. #define __Pyx_LeaveTracing(tstate) PyThreadState_LeaveTracing(tstate)
  59. #elif PY_VERSION_HEX >= 0x030a00b1
  60. #define __Pyx_IsTracing(tstate, check_tracing, check_funcs) \
  61. (unlikely((tstate)->cframe->use_tracing) && \
  62. (!(check_tracing) || !(tstate)->tracing) && \
  63. (!(check_funcs) || (tstate)->c_profilefunc || (CYTHON_TRACE && (tstate)->c_tracefunc)))
  64. #define __Pyx_EnterTracing(tstate) \
  65. do { tstate->tracing++; tstate->cframe->use_tracing = 0; } while (0)
  66. #define __Pyx_LeaveTracing(tstate) \
  67. do { \
  68. tstate->tracing--; \
  69. tstate->cframe->use_tracing = ((CYTHON_TRACE && tstate->c_tracefunc != NULL) \
  70. || tstate->c_profilefunc != NULL); \
  71. } while (0)
  72. #else
  73. #define __Pyx_IsTracing(tstate, check_tracing, check_funcs) \
  74. (unlikely((tstate)->use_tracing) && \
  75. (!(check_tracing) || !(tstate)->tracing) && \
  76. (!(check_funcs) || (tstate)->c_profilefunc || (CYTHON_TRACE && (tstate)->c_tracefunc)))
  77. #define __Pyx_EnterTracing(tstate) \
  78. do { tstate->tracing++; tstate->use_tracing = 0; } while (0)
  79. #define __Pyx_LeaveTracing(tstate) \
  80. do { \
  81. tstate->tracing--; \
  82. tstate->use_tracing = ((CYTHON_TRACE && tstate->c_tracefunc != NULL) \
  83. || tstate->c_profilefunc != NULL); \
  84. } while (0)
  85. #endif
  86. #ifdef WITH_THREAD
  87. #define __Pyx_TraceCall(funcname, srcfile, firstlineno, nogil, goto_error) \
  88. if (nogil) { \
  89. if (CYTHON_TRACE_NOGIL) { \
  90. PyThreadState *tstate; \
  91. PyGILState_STATE state = PyGILState_Ensure(); \
  92. tstate = __Pyx_PyThreadState_Current; \
  93. if (__Pyx_IsTracing(tstate, 1, 1)) { \
  94. __Pyx_use_tracing = __Pyx_TraceSetupAndCall(&$frame_code_cname, &$frame_cname, tstate, funcname, srcfile, firstlineno); \
  95. } \
  96. PyGILState_Release(state); \
  97. if (unlikely(__Pyx_use_tracing < 0)) goto_error; \
  98. } \
  99. } else { \
  100. PyThreadState* tstate = PyThreadState_GET(); \
  101. if (__Pyx_IsTracing(tstate, 1, 1)) { \
  102. __Pyx_use_tracing = __Pyx_TraceSetupAndCall(&$frame_code_cname, &$frame_cname, tstate, funcname, srcfile, firstlineno); \
  103. if (unlikely(__Pyx_use_tracing < 0)) goto_error; \
  104. } \
  105. }
  106. #else
  107. #define __Pyx_TraceCall(funcname, srcfile, firstlineno, nogil, goto_error) \
  108. { PyThreadState* tstate = PyThreadState_GET(); \
  109. if (__Pyx_IsTracing(tstate, 1, 1)) { \
  110. __Pyx_use_tracing = __Pyx_TraceSetupAndCall(&$frame_code_cname, &$frame_cname, tstate, funcname, srcfile, firstlineno); \
  111. if (unlikely(__Pyx_use_tracing < 0)) goto_error; \
  112. } \
  113. }
  114. #endif
  115. #define __Pyx_TraceException() \
  116. if (likely(!__Pyx_use_tracing)); else { \
  117. PyThreadState* tstate = __Pyx_PyThreadState_Current; \
  118. if (__Pyx_IsTracing(tstate, 0, 1)) { \
  119. __Pyx_EnterTracing(tstate); \
  120. PyObject *exc_info = __Pyx_GetExceptionTuple(tstate); \
  121. if (exc_info) { \
  122. if (CYTHON_TRACE && tstate->c_tracefunc) \
  123. tstate->c_tracefunc( \
  124. tstate->c_traceobj, $frame_cname, PyTrace_EXCEPTION, exc_info); \
  125. tstate->c_profilefunc( \
  126. tstate->c_profileobj, $frame_cname, PyTrace_EXCEPTION, exc_info); \
  127. Py_DECREF(exc_info); \
  128. } \
  129. __Pyx_LeaveTracing(tstate); \
  130. } \
  131. }
  132. static void __Pyx_call_return_trace_func(PyThreadState *tstate, PyFrameObject *frame, PyObject *result) {
  133. PyObject *type, *value, *traceback;
  134. __Pyx_ErrFetchInState(tstate, &type, &value, &traceback);
  135. __Pyx_EnterTracing(tstate);
  136. if (CYTHON_TRACE && tstate->c_tracefunc)
  137. tstate->c_tracefunc(tstate->c_traceobj, frame, PyTrace_RETURN, result);
  138. if (tstate->c_profilefunc)
  139. tstate->c_profilefunc(tstate->c_profileobj, frame, PyTrace_RETURN, result);
  140. CYTHON_FRAME_DEL(frame);
  141. __Pyx_LeaveTracing(tstate);
  142. __Pyx_ErrRestoreInState(tstate, type, value, traceback);
  143. }
  144. #ifdef WITH_THREAD
  145. #define __Pyx_TraceReturn(result, nogil) \
  146. if (likely(!__Pyx_use_tracing)); else { \
  147. if (nogil) { \
  148. if (CYTHON_TRACE_NOGIL) { \
  149. PyThreadState *tstate; \
  150. PyGILState_STATE state = PyGILState_Ensure(); \
  151. tstate = __Pyx_PyThreadState_Current; \
  152. if (__Pyx_IsTracing(tstate, 0, 0)) { \
  153. __Pyx_call_return_trace_func(tstate, $frame_cname, (PyObject*)result); \
  154. } \
  155. PyGILState_Release(state); \
  156. } \
  157. } else { \
  158. PyThreadState* tstate = __Pyx_PyThreadState_Current; \
  159. if (__Pyx_IsTracing(tstate, 0, 0)) { \
  160. __Pyx_call_return_trace_func(tstate, $frame_cname, (PyObject*)result); \
  161. } \
  162. } \
  163. }
  164. #else
  165. #define __Pyx_TraceReturn(result, nogil) \
  166. if (likely(!__Pyx_use_tracing)); else { \
  167. PyThreadState* tstate = __Pyx_PyThreadState_Current; \
  168. if (__Pyx_IsTracing(tstate, 0, 0)) { \
  169. __Pyx_call_return_trace_func(tstate, $frame_cname, (PyObject*)result); \
  170. } \
  171. }
  172. #endif
  173. static PyCodeObject *__Pyx_createFrameCodeObject(const char *funcname, const char *srcfile, int firstlineno); /*proto*/
  174. static int __Pyx_TraceSetupAndCall(PyCodeObject** code, PyFrameObject** frame, PyThreadState* tstate, const char *funcname, const char *srcfile, int firstlineno); /*proto*/
  175. #else
  176. #define __Pyx_TraceDeclarations
  177. #define __Pyx_TraceFrameInit(codeobj)
  178. // mark error label as used to avoid compiler warnings
  179. #define __Pyx_TraceCall(funcname, srcfile, firstlineno, nogil, goto_error) if ((1)); else goto_error;
  180. #define __Pyx_TraceException()
  181. #define __Pyx_TraceReturn(result, nogil)
  182. #endif /* CYTHON_PROFILE */
  183. #if CYTHON_TRACE
  184. // see call_trace_protected() in CPython's ceval.c
  185. static int __Pyx_call_line_trace_func(PyThreadState *tstate, PyFrameObject *frame, int lineno) {
  186. int ret;
  187. PyObject *type, *value, *traceback;
  188. __Pyx_ErrFetchInState(tstate, &type, &value, &traceback);
  189. __Pyx_PyFrame_SetLineNumber(frame, lineno);
  190. __Pyx_EnterTracing(tstate);
  191. ret = tstate->c_tracefunc(tstate->c_traceobj, frame, PyTrace_LINE, NULL);
  192. __Pyx_LeaveTracing(tstate);
  193. if (likely(!ret)) {
  194. __Pyx_ErrRestoreInState(tstate, type, value, traceback);
  195. } else {
  196. Py_XDECREF(type);
  197. Py_XDECREF(value);
  198. Py_XDECREF(traceback);
  199. }
  200. return ret;
  201. }
  202. #ifdef WITH_THREAD
  203. #define __Pyx_TraceLine(lineno, nogil, goto_error) \
  204. if (likely(!__Pyx_use_tracing)); else { \
  205. // mark error label as used to avoid compiler warnings \
  206. if ((1)); else goto_error; \
  207. if (nogil) { \
  208. if (CYTHON_TRACE_NOGIL) { \
  209. int ret = 0; \
  210. PyThreadState *tstate; \
  211. PyGILState_STATE state = PyGILState_Ensure(); \
  212. tstate = __Pyx_PyThreadState_Current; \
  213. if (__Pyx_IsTracing(tstate, 0, 0) && tstate->c_tracefunc && $frame_cname->f_trace) { \
  214. ret = __Pyx_call_line_trace_func(tstate, $frame_cname, lineno); \
  215. } \
  216. PyGILState_Release(state); \
  217. // XXX https://github.com/cython/cython/issues/2274 \
  218. if (unlikely(ret)) { fprintf(stderr, "cython: line_trace_func returned %d\n", ret); } \
  219. } \
  220. } else { \
  221. PyThreadState* tstate = __Pyx_PyThreadState_Current; \
  222. if (__Pyx_IsTracing(tstate, 0, 0) && tstate->c_tracefunc && $frame_cname->f_trace) { \
  223. int ret = __Pyx_call_line_trace_func(tstate, $frame_cname, lineno); \
  224. // XXX https://github.com/cython/cython/issues/2274 \
  225. if (unlikely(ret)) { fprintf(stderr, "cython: line_trace_func returned %d\n", ret); } \
  226. } \
  227. } \
  228. }
  229. #else
  230. #define __Pyx_TraceLine(lineno, nogil, goto_error) \
  231. if (likely(!__Pyx_use_tracing)); else { \
  232. // mark error label as used to avoid compiler warnings \
  233. if ((1)); else goto_error; \
  234. PyThreadState* tstate = __Pyx_PyThreadState_Current; \
  235. if (__Pyx_IsTracing(tstate, 0, 0) && tstate->c_tracefunc && $frame_cname->f_trace) { \
  236. int ret = __Pyx_call_line_trace_func(tstate, $frame_cname, lineno); \
  237. // XXX https://github.com/cython/cython/issues/2274 \
  238. if (unlikely(ret)) { fprintf(stderr, "cython: line_trace_func returned %d\n", ret); } \
  239. } \
  240. }
  241. #endif
  242. #else
  243. // mark error label as used to avoid compiler warnings
  244. #define __Pyx_TraceLine(lineno, nogil, goto_error) if ((1)); else goto_error;
  245. #endif
  246. /////////////// Profile ///////////////
  247. //@substitute: naming
  248. #if CYTHON_PROFILE
  249. static int __Pyx_TraceSetupAndCall(PyCodeObject** code,
  250. PyFrameObject** frame,
  251. PyThreadState* tstate,
  252. const char *funcname,
  253. const char *srcfile,
  254. int firstlineno) {
  255. PyObject *type, *value, *traceback;
  256. int retval;
  257. if (*frame == NULL || !CYTHON_PROFILE_REUSE_FRAME) {
  258. if (*code == NULL) {
  259. *code = __Pyx_createFrameCodeObject(funcname, srcfile, firstlineno);
  260. if (*code == NULL) return 0;
  261. }
  262. *frame = PyFrame_New(
  263. tstate, /*PyThreadState *tstate*/
  264. *code, /*PyCodeObject *code*/
  265. $moddict_cname, /*PyObject *globals*/
  266. 0 /*PyObject *locals*/
  267. );
  268. if (*frame == NULL) return 0;
  269. if (CYTHON_TRACE && (*frame)->f_trace == NULL) {
  270. // this enables "f_lineno" lookup, at least in CPython ...
  271. Py_INCREF(Py_None);
  272. (*frame)->f_trace = Py_None;
  273. }
  274. #if PY_VERSION_HEX < 0x030400B1
  275. } else {
  276. (*frame)->f_tstate = tstate;
  277. #endif
  278. }
  279. __Pyx_PyFrame_SetLineNumber(*frame, firstlineno);
  280. retval = 1;
  281. __Pyx_EnterTracing(tstate);
  282. __Pyx_ErrFetchInState(tstate, &type, &value, &traceback);
  283. #if CYTHON_TRACE
  284. if (tstate->c_tracefunc)
  285. retval = tstate->c_tracefunc(tstate->c_traceobj, *frame, PyTrace_CALL, NULL) == 0;
  286. if (retval && tstate->c_profilefunc)
  287. #endif
  288. retval = tstate->c_profilefunc(tstate->c_profileobj, *frame, PyTrace_CALL, NULL) == 0;
  289. __Pyx_LeaveTracing(tstate);
  290. if (retval) {
  291. __Pyx_ErrRestoreInState(tstate, type, value, traceback);
  292. return __Pyx_IsTracing(tstate, 0, 0) && retval;
  293. } else {
  294. Py_XDECREF(type);
  295. Py_XDECREF(value);
  296. Py_XDECREF(traceback);
  297. return -1;
  298. }
  299. }
  300. static PyCodeObject *__Pyx_createFrameCodeObject(const char *funcname, const char *srcfile, int firstlineno) {
  301. PyCodeObject *py_code = 0;
  302. #if PY_MAJOR_VERSION >= 3
  303. py_code = PyCode_NewEmpty(srcfile, funcname, firstlineno);
  304. // make CPython use a fresh dict for "f_locals" at need (see GH #1836)
  305. if (likely(py_code)) {
  306. py_code->co_flags |= CO_OPTIMIZED | CO_NEWLOCALS;
  307. }
  308. #else
  309. PyObject *py_srcfile = 0;
  310. PyObject *py_funcname = 0;
  311. py_funcname = PyString_FromString(funcname);
  312. if (unlikely(!py_funcname)) goto bad;
  313. py_srcfile = PyString_FromString(srcfile);
  314. if (unlikely(!py_srcfile)) goto bad;
  315. py_code = PyCode_New(
  316. 0, /*int argcount,*/
  317. 0, /*int nlocals,*/
  318. 0, /*int stacksize,*/
  319. // make CPython use a fresh dict for "f_locals" at need (see GH #1836)
  320. CO_OPTIMIZED | CO_NEWLOCALS, /*int flags,*/
  321. $empty_bytes, /*PyObject *code,*/
  322. $empty_tuple, /*PyObject *consts,*/
  323. $empty_tuple, /*PyObject *names,*/
  324. $empty_tuple, /*PyObject *varnames,*/
  325. $empty_tuple, /*PyObject *freevars,*/
  326. $empty_tuple, /*PyObject *cellvars,*/
  327. py_srcfile, /*PyObject *filename,*/
  328. py_funcname, /*PyObject *name,*/
  329. firstlineno, /*int firstlineno,*/
  330. $empty_bytes /*PyObject *lnotab*/
  331. );
  332. bad:
  333. Py_XDECREF(py_srcfile);
  334. Py_XDECREF(py_funcname);
  335. #endif
  336. return py_code;
  337. }
  338. #endif /* CYTHON_PROFILE */