336 lines
16 KiB
C
336 lines
16 KiB
C
/////////////// Profile.proto ///////////////
|
|
//@requires: Exceptions.c::PyErrFetchRestore
|
|
//@substitute: naming
|
|
|
|
// Note that cPython ignores PyTrace_EXCEPTION,
|
|
// but maybe some other profilers don't.
|
|
|
|
#ifndef CYTHON_PROFILE
|
|
#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_PYSTON
|
|
#define CYTHON_PROFILE 0
|
|
#else
|
|
#define CYTHON_PROFILE 1
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef CYTHON_TRACE_NOGIL
|
|
#define CYTHON_TRACE_NOGIL 0
|
|
#else
|
|
#if CYTHON_TRACE_NOGIL && !defined(CYTHON_TRACE)
|
|
#define CYTHON_TRACE 1
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef CYTHON_TRACE
|
|
#define CYTHON_TRACE 0
|
|
#endif
|
|
|
|
#if CYTHON_TRACE
|
|
#undef CYTHON_PROFILE_REUSE_FRAME
|
|
#endif
|
|
|
|
#ifndef CYTHON_PROFILE_REUSE_FRAME
|
|
#define CYTHON_PROFILE_REUSE_FRAME 0
|
|
#endif
|
|
|
|
#if CYTHON_PROFILE || CYTHON_TRACE
|
|
|
|
#include "compile.h"
|
|
#include "frameobject.h"
|
|
#include "traceback.h"
|
|
|
|
#if CYTHON_PROFILE_REUSE_FRAME
|
|
#define CYTHON_FRAME_MODIFIER static
|
|
#define CYTHON_FRAME_DEL(frame)
|
|
#else
|
|
#define CYTHON_FRAME_MODIFIER
|
|
#define CYTHON_FRAME_DEL(frame) Py_CLEAR(frame)
|
|
#endif
|
|
|
|
#define __Pyx_TraceDeclarations \
|
|
static PyCodeObject *$frame_code_cname = NULL; \
|
|
CYTHON_FRAME_MODIFIER PyFrameObject *$frame_cname = NULL; \
|
|
int __Pyx_use_tracing = 0;
|
|
|
|
#define __Pyx_TraceFrameInit(codeobj) \
|
|
if (codeobj) $frame_code_cname = (PyCodeObject*) codeobj;
|
|
|
|
#ifdef WITH_THREAD
|
|
#define __Pyx_TraceCall(funcname, srcfile, firstlineno, nogil, goto_error) \
|
|
if (nogil) { \
|
|
if (CYTHON_TRACE_NOGIL) { \
|
|
PyThreadState *tstate; \
|
|
PyGILState_STATE state = PyGILState_Ensure(); \
|
|
tstate = __Pyx_PyThreadState_Current; \
|
|
if (unlikely(tstate->use_tracing) && !tstate->tracing && \
|
|
(tstate->c_profilefunc || (CYTHON_TRACE && tstate->c_tracefunc))) { \
|
|
__Pyx_use_tracing = __Pyx_TraceSetupAndCall(&$frame_code_cname, &$frame_cname, tstate, funcname, srcfile, firstlineno); \
|
|
} \
|
|
PyGILState_Release(state); \
|
|
if (unlikely(__Pyx_use_tracing < 0)) goto_error; \
|
|
} \
|
|
} else { \
|
|
PyThreadState* tstate = PyThreadState_GET(); \
|
|
if (unlikely(tstate->use_tracing) && !tstate->tracing && \
|
|
(tstate->c_profilefunc || (CYTHON_TRACE && tstate->c_tracefunc))) { \
|
|
__Pyx_use_tracing = __Pyx_TraceSetupAndCall(&$frame_code_cname, &$frame_cname, tstate, funcname, srcfile, firstlineno); \
|
|
if (unlikely(__Pyx_use_tracing < 0)) goto_error; \
|
|
} \
|
|
}
|
|
#else
|
|
#define __Pyx_TraceCall(funcname, srcfile, firstlineno, nogil, goto_error) \
|
|
{ PyThreadState* tstate = PyThreadState_GET(); \
|
|
if (unlikely(tstate->use_tracing) && !tstate->tracing && \
|
|
(tstate->c_profilefunc || (CYTHON_TRACE && tstate->c_tracefunc))) { \
|
|
__Pyx_use_tracing = __Pyx_TraceSetupAndCall(&$frame_code_cname, &$frame_cname, tstate, funcname, srcfile, firstlineno); \
|
|
if (unlikely(__Pyx_use_tracing < 0)) goto_error; \
|
|
} \
|
|
}
|
|
#endif
|
|
|
|
#define __Pyx_TraceException() \
|
|
if (likely(!__Pyx_use_tracing)); else { \
|
|
PyThreadState* tstate = __Pyx_PyThreadState_Current; \
|
|
if (tstate->use_tracing && \
|
|
(tstate->c_profilefunc || (CYTHON_TRACE && tstate->c_tracefunc))) { \
|
|
tstate->tracing++; \
|
|
tstate->use_tracing = 0; \
|
|
PyObject *exc_info = __Pyx_GetExceptionTuple(tstate); \
|
|
if (exc_info) { \
|
|
if (CYTHON_TRACE && tstate->c_tracefunc) \
|
|
tstate->c_tracefunc( \
|
|
tstate->c_traceobj, $frame_cname, PyTrace_EXCEPTION, exc_info); \
|
|
tstate->c_profilefunc( \
|
|
tstate->c_profileobj, $frame_cname, PyTrace_EXCEPTION, exc_info); \
|
|
Py_DECREF(exc_info); \
|
|
} \
|
|
tstate->use_tracing = 1; \
|
|
tstate->tracing--; \
|
|
} \
|
|
}
|
|
|
|
static void __Pyx_call_return_trace_func(PyThreadState *tstate, PyFrameObject *frame, PyObject *result) {
|
|
PyObject *type, *value, *traceback;
|
|
__Pyx_ErrFetchInState(tstate, &type, &value, &traceback);
|
|
tstate->tracing++;
|
|
tstate->use_tracing = 0;
|
|
if (CYTHON_TRACE && tstate->c_tracefunc)
|
|
tstate->c_tracefunc(tstate->c_traceobj, frame, PyTrace_RETURN, result);
|
|
if (tstate->c_profilefunc)
|
|
tstate->c_profilefunc(tstate->c_profileobj, frame, PyTrace_RETURN, result);
|
|
CYTHON_FRAME_DEL(frame);
|
|
tstate->use_tracing = 1;
|
|
tstate->tracing--;
|
|
__Pyx_ErrRestoreInState(tstate, type, value, traceback);
|
|
}
|
|
|
|
#ifdef WITH_THREAD
|
|
#define __Pyx_TraceReturn(result, nogil) \
|
|
if (likely(!__Pyx_use_tracing)); else { \
|
|
if (nogil) { \
|
|
if (CYTHON_TRACE_NOGIL) { \
|
|
PyThreadState *tstate; \
|
|
PyGILState_STATE state = PyGILState_Ensure(); \
|
|
tstate = __Pyx_PyThreadState_Current; \
|
|
if (tstate->use_tracing) { \
|
|
__Pyx_call_return_trace_func(tstate, $frame_cname, (PyObject*)result); \
|
|
} \
|
|
PyGILState_Release(state); \
|
|
} \
|
|
} else { \
|
|
PyThreadState* tstate = __Pyx_PyThreadState_Current; \
|
|
if (tstate->use_tracing) { \
|
|
__Pyx_call_return_trace_func(tstate, $frame_cname, (PyObject*)result); \
|
|
} \
|
|
} \
|
|
}
|
|
#else
|
|
#define __Pyx_TraceReturn(result, nogil) \
|
|
if (likely(!__Pyx_use_tracing)); else { \
|
|
PyThreadState* tstate = __Pyx_PyThreadState_Current; \
|
|
if (tstate->use_tracing) { \
|
|
__Pyx_call_return_trace_func(tstate, $frame_cname, (PyObject*)result); \
|
|
} \
|
|
}
|
|
#endif
|
|
|
|
static PyCodeObject *__Pyx_createFrameCodeObject(const char *funcname, const char *srcfile, int firstlineno); /*proto*/
|
|
static int __Pyx_TraceSetupAndCall(PyCodeObject** code, PyFrameObject** frame, PyThreadState* tstate, const char *funcname, const char *srcfile, int firstlineno); /*proto*/
|
|
|
|
#else
|
|
|
|
#define __Pyx_TraceDeclarations
|
|
#define __Pyx_TraceFrameInit(codeobj)
|
|
// mark error label as used to avoid compiler warnings
|
|
#define __Pyx_TraceCall(funcname, srcfile, firstlineno, nogil, goto_error) if ((1)); else goto_error;
|
|
#define __Pyx_TraceException()
|
|
#define __Pyx_TraceReturn(result, nogil)
|
|
|
|
#endif /* CYTHON_PROFILE */
|
|
|
|
#if CYTHON_TRACE
|
|
// see call_trace_protected() in CPython's ceval.c
|
|
static int __Pyx_call_line_trace_func(PyThreadState *tstate, PyFrameObject *frame, int lineno) {
|
|
int ret;
|
|
PyObject *type, *value, *traceback;
|
|
__Pyx_ErrFetchInState(tstate, &type, &value, &traceback);
|
|
__Pyx_PyFrame_SetLineNumber(frame, lineno);
|
|
tstate->tracing++;
|
|
tstate->use_tracing = 0;
|
|
ret = tstate->c_tracefunc(tstate->c_traceobj, frame, PyTrace_LINE, NULL);
|
|
tstate->use_tracing = 1;
|
|
tstate->tracing--;
|
|
if (likely(!ret)) {
|
|
__Pyx_ErrRestoreInState(tstate, type, value, traceback);
|
|
} else {
|
|
Py_XDECREF(type);
|
|
Py_XDECREF(value);
|
|
Py_XDECREF(traceback);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
#ifdef WITH_THREAD
|
|
#define __Pyx_TraceLine(lineno, nogil, goto_error) \
|
|
if (likely(!__Pyx_use_tracing)); else { \
|
|
if (nogil) { \
|
|
if (CYTHON_TRACE_NOGIL) { \
|
|
int ret = 0; \
|
|
PyThreadState *tstate; \
|
|
PyGILState_STATE state = PyGILState_Ensure(); \
|
|
tstate = __Pyx_PyThreadState_Current; \
|
|
if (unlikely(tstate->use_tracing && tstate->c_tracefunc && $frame_cname->f_trace)) { \
|
|
ret = __Pyx_call_line_trace_func(tstate, $frame_cname, lineno); \
|
|
} \
|
|
PyGILState_Release(state); \
|
|
if (unlikely(ret)) goto_error; \
|
|
} \
|
|
} else { \
|
|
PyThreadState* tstate = __Pyx_PyThreadState_Current; \
|
|
if (unlikely(tstate->use_tracing && tstate->c_tracefunc && $frame_cname->f_trace)) { \
|
|
int ret = __Pyx_call_line_trace_func(tstate, $frame_cname, lineno); \
|
|
if (unlikely(ret)) goto_error; \
|
|
} \
|
|
} \
|
|
}
|
|
#else
|
|
#define __Pyx_TraceLine(lineno, nogil, goto_error) \
|
|
if (likely(!__Pyx_use_tracing)); else { \
|
|
PyThreadState* tstate = __Pyx_PyThreadState_Current; \
|
|
if (unlikely(tstate->use_tracing && tstate->c_tracefunc && $frame_cname->f_trace)) { \
|
|
int ret = __Pyx_call_line_trace_func(tstate, $frame_cname, lineno); \
|
|
if (unlikely(ret)) goto_error; \
|
|
} \
|
|
}
|
|
#endif
|
|
#else
|
|
// mark error label as used to avoid compiler warnings
|
|
#define __Pyx_TraceLine(lineno, nogil, goto_error) if ((1)); else goto_error;
|
|
#endif
|
|
|
|
/////////////// Profile ///////////////
|
|
//@substitute: naming
|
|
|
|
#if CYTHON_PROFILE
|
|
|
|
static int __Pyx_TraceSetupAndCall(PyCodeObject** code,
|
|
PyFrameObject** frame,
|
|
PyThreadState* tstate,
|
|
const char *funcname,
|
|
const char *srcfile,
|
|
int firstlineno) {
|
|
PyObject *type, *value, *traceback;
|
|
int retval;
|
|
if (*frame == NULL || !CYTHON_PROFILE_REUSE_FRAME) {
|
|
if (*code == NULL) {
|
|
*code = __Pyx_createFrameCodeObject(funcname, srcfile, firstlineno);
|
|
if (*code == NULL) return 0;
|
|
}
|
|
*frame = PyFrame_New(
|
|
tstate, /*PyThreadState *tstate*/
|
|
*code, /*PyCodeObject *code*/
|
|
$moddict_cname, /*PyObject *globals*/
|
|
0 /*PyObject *locals*/
|
|
);
|
|
if (*frame == NULL) return 0;
|
|
if (CYTHON_TRACE && (*frame)->f_trace == NULL) {
|
|
// this enables "f_lineno" lookup, at least in CPython ...
|
|
Py_INCREF(Py_None);
|
|
(*frame)->f_trace = Py_None;
|
|
}
|
|
#if PY_VERSION_HEX < 0x030400B1
|
|
} else {
|
|
(*frame)->f_tstate = tstate;
|
|
#endif
|
|
}
|
|
__Pyx_PyFrame_SetLineNumber(*frame, firstlineno);
|
|
retval = 1;
|
|
tstate->tracing++;
|
|
tstate->use_tracing = 0;
|
|
__Pyx_ErrFetchInState(tstate, &type, &value, &traceback);
|
|
#if CYTHON_TRACE
|
|
if (tstate->c_tracefunc)
|
|
retval = tstate->c_tracefunc(tstate->c_traceobj, *frame, PyTrace_CALL, NULL) == 0;
|
|
if (retval && tstate->c_profilefunc)
|
|
#endif
|
|
retval = tstate->c_profilefunc(tstate->c_profileobj, *frame, PyTrace_CALL, NULL) == 0;
|
|
tstate->use_tracing = (tstate->c_profilefunc ||
|
|
(CYTHON_TRACE && tstate->c_tracefunc));
|
|
tstate->tracing--;
|
|
if (retval) {
|
|
__Pyx_ErrRestoreInState(tstate, type, value, traceback);
|
|
return tstate->use_tracing && retval;
|
|
} else {
|
|
Py_XDECREF(type);
|
|
Py_XDECREF(value);
|
|
Py_XDECREF(traceback);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
static PyCodeObject *__Pyx_createFrameCodeObject(const char *funcname, const char *srcfile, int firstlineno) {
|
|
PyCodeObject *py_code = 0;
|
|
|
|
#if PY_MAJOR_VERSION >= 3
|
|
py_code = PyCode_NewEmpty(srcfile, funcname, firstlineno);
|
|
// make CPython use a fresh dict for "f_locals" at need (see GH #1836)
|
|
if (likely(py_code)) {
|
|
py_code->co_flags |= CO_OPTIMIZED | CO_NEWLOCALS;
|
|
}
|
|
#else
|
|
PyObject *py_srcfile = 0;
|
|
PyObject *py_funcname = 0;
|
|
|
|
py_funcname = PyString_FromString(funcname);
|
|
if (unlikely(!py_funcname)) goto bad;
|
|
py_srcfile = PyString_FromString(srcfile);
|
|
if (unlikely(!py_srcfile)) goto bad;
|
|
|
|
py_code = PyCode_New(
|
|
0, /*int argcount,*/
|
|
0, /*int nlocals,*/
|
|
0, /*int stacksize,*/
|
|
// make CPython use a fresh dict for "f_locals" at need (see GH #1836)
|
|
CO_OPTIMIZED | CO_NEWLOCALS, /*int flags,*/
|
|
$empty_bytes, /*PyObject *code,*/
|
|
$empty_tuple, /*PyObject *consts,*/
|
|
$empty_tuple, /*PyObject *names,*/
|
|
$empty_tuple, /*PyObject *varnames,*/
|
|
$empty_tuple, /*PyObject *freevars,*/
|
|
$empty_tuple, /*PyObject *cellvars,*/
|
|
py_srcfile, /*PyObject *filename,*/
|
|
py_funcname, /*PyObject *name,*/
|
|
firstlineno, /*int firstlineno,*/
|
|
$empty_bytes /*PyObject *lnotab*/
|
|
);
|
|
|
|
bad:
|
|
Py_XDECREF(py_srcfile);
|
|
Py_XDECREF(py_funcname);
|
|
#endif
|
|
|
|
return py_code;
|
|
}
|
|
|
|
#endif /* CYTHON_PROFILE */
|