Profile.c 17 KB

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