cython-devel
changeset 2092:181618626844
Cython profiling
| author | Robert Bradshaw <robertwb@math.washington.edu> |
|---|---|
| date | Mon Jul 20 15:39:57 2009 -0700 (3 years ago) |
| parents | 835c9620f9ed |
| children | f96b8b73accf |
| files | Cython/Compiler/Code.py Cython/Compiler/ModuleNode.py Cython/Compiler/Naming.py Cython/Compiler/Nodes.py Cython/Compiler/Options.py |
line diff
1.1 --- a/Cython/Compiler/Code.py Thu Jul 16 02:32:52 2009 -0700
1.2 +++ b/Cython/Compiler/Code.py Mon Jul 20 15:39:57 2009 -0700
1.3 @@ -943,6 +943,15 @@
1.4 def put_finish_refcount_context(self):
1.5 self.putln("__Pyx_FinishRefcountContext();")
1.6
1.7 + def put_trace_call(self, name, pos):
1.8 + self.putln('__Pyx_TraceCall("%s", %s[%s], %s);' % (name, Naming.filetable_cname, self.lookup_filename(pos[0]), pos[1]));
1.9 +
1.10 + def put_trace_exception(self):
1.11 + self.putln("__Pyx_TraceException();")
1.12 +
1.13 + def put_trace_return(self, retvalue_cname):
1.14 + self.putln("__Pyx_TraceReturn(%s);" % retvalue_cname)
1.15 +
1.16
1.17 class PyrexCodeWriter(object):
1.18 # f file output file
2.1 --- a/Cython/Compiler/ModuleNode.py Thu Jul 16 02:32:52 2009 -0700
2.2 +++ b/Cython/Compiler/ModuleNode.py Mon Jul 20 15:39:57 2009 -0700
2.3 @@ -2480,6 +2480,7 @@
2.4 #define __Pyx_XGOTREF(r) if((r) == NULL) ; else __Pyx_GOTREF(r)
2.5 """)
2.6
2.7 +
2.8 main_method = UtilityCode(
2.9 impl = """
2.10 #if PY_MAJOR_VERSION < 3 || (!defined(WIN32) && !defined(MS_WINDOWS))
3.1 --- a/Cython/Compiler/Naming.py Thu Jul 16 02:32:52 2009 -0700
3.2 +++ b/Cython/Compiler/Naming.py Mon Jul 20 15:39:57 2009 -0700
3.3 @@ -84,6 +84,8 @@
3.4 import_star_set = pyrex_prefix + "import_star_set"
3.5 cur_scope_cname = pyrex_prefix + "cur_scope"
3.6 enc_scope_cname = pyrex_prefix + "enc_scope"
3.7 +frame_cname = pyrex_prefix + "frame"
3.8 +frame_code_cname = pyrex_prefix + "frame_code"
3.9
3.10 line_c_macro = "__LINE__"
3.11
4.1 --- a/Cython/Compiler/Nodes.py Thu Jul 16 02:32:52 2009 -0700
4.2 +++ b/Cython/Compiler/Nodes.py Mon Jul 20 15:39:57 2009 -0700
4.3 @@ -1002,6 +1002,7 @@
4.4 py_func = None
4.5 assmt = None
4.6 needs_closure = False
4.7 + modifiers = []
4.8
4.9 def analyse_default_values(self, env):
4.10 genv = env.global_scope()
4.11 @@ -1054,6 +1055,15 @@
4.12
4.13 is_getbuffer_slot = (self.entry.name == "__getbuffer__" and
4.14 self.entry.scope.is_c_class_scope)
4.15 +
4.16 + if code.globalstate.directives['profile'] is None:
4.17 + profile = 'inline' not in self.modifiers
4.18 + else:
4.19 + profile = code.globalstate.directives['profile']
4.20 + if profile and lenv.nogil:
4.21 + error(self.pos, "Cannot profile nogil function.")
4.22 + if profile:
4.23 + code.globalstate.use_utility_code(trace_utility_code)
4.24
4.25 # Generate C code for header and body of function
4.26 code.enter_cfunc_scope()
4.27 @@ -1101,6 +1111,8 @@
4.28 env.use_utility_code(force_init_threads_utility_code)
4.29 code.putln("PyGILState_STATE _save = PyGILState_Ensure();")
4.30 # ----- Automatic lead-ins for certain special functions
4.31 + if profile:
4.32 + code.put_trace_call(self.entry.name, self.pos)
4.33 if not lenv.nogil:
4.34 code.put_setup_refcount_context(self.entry.name)
4.35 if is_getbuffer_slot:
4.36 @@ -1165,6 +1177,9 @@
4.37 err_val = self.error_value()
4.38 exc_check = self.caller_will_check_exceptions()
4.39 if err_val is not None or exc_check:
4.40 + # TODO: Fix exception tracing (though currently unused by cProfile).
4.41 + # code.globalstate.use_utility_code(get_exception_tuple_utility_code)
4.42 + # code.put_trace_exception()
4.43 code.putln('__Pyx_AddTraceback("%s");' % self.entry.qualified_name)
4.44 else:
4.45 warning(self.entry.pos, "Unraisable exception in function '%s'." \
4.46 @@ -1194,9 +1209,6 @@
4.47
4.48
4.49 # ----- Non-error return cleanup
4.50 - # If you add anything here, remember to add a condition to the
4.51 - # if-test above in the error block (so that it can jump past this
4.52 - # block).
4.53 code.put_label(code.return_label)
4.54 for entry in lenv.buffer_entries:
4.55 if entry.used:
4.56 @@ -1233,6 +1245,12 @@
4.57 # We do as Python instances and coerce -1 into -2.
4.58 code.putln("if (unlikely(%s == -1) && !PyErr_Occurred()) %s = -2;" % (Naming.retval_cname, Naming.retval_cname))
4.59
4.60 + if profile:
4.61 + if self.return_type.is_pyobject:
4.62 + code.put_trace_return(Naming.retval_cname)
4.63 + else:
4.64 + code.put_trace_return("Py_None")
4.65 +
4.66 if acquire_gil:
4.67 code.putln("PyGILState_Release(_save);")
4.68
4.69 @@ -5695,6 +5713,31 @@
4.70
4.71 #------------------------------------------------------------------------------------
4.72
4.73 +get_exception_tuple_utility_code = UtilityCode(proto="""
4.74 +static PyObject *__Pyx_GetExceptionTuple(void); /*proto*/
4.75 +""",
4.76 +impl = """
4.77 +static PyObject *__Pyx_GetExceptionTuple(void) {
4.78 + PyObject *type = NULL, *value = NULL, *tb = NULL;
4.79 + if (__Pyx_GetException(&type, &value, &tb) == 0) {
4.80 + PyObject* exc_info = PyTuple_New(3);
4.81 + if (exc_info) {
4.82 + Py_INCREF(type);
4.83 + Py_INCREF(value);
4.84 + Py_INCREF(tb);
4.85 + PyTuple_SET_ITEM(exc_info, 0, type);
4.86 + PyTuple_SET_ITEM(exc_info, 1, value);
4.87 + PyTuple_SET_ITEM(exc_info, 2, tb);
4.88 + return exc_info;
4.89 + }
4.90 + }
4.91 + return NULL;
4.92 +}
4.93 +""",
4.94 +requires=[get_exception_utility_code])
4.95 +
4.96 +#------------------------------------------------------------------------------------
4.97 +
4.98 reset_exception_utility_code = UtilityCode(
4.99 proto = """
4.100 static INLINE void __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
4.101 @@ -5740,3 +5783,138 @@
4.102 """)
4.103
4.104 #------------------------------------------------------------------------------------
4.105 +
4.106 +# Note that cPython ignores PyTrace_EXCEPTION,
4.107 +# but maybe some other profilers don't.
4.108 +
4.109 +trace_utility_code = UtilityCode(proto="""
4.110 +#define CYTHON_TRACING 1
4.111 +#define CYTHON_TRACING_REUSE_FRAME 0
4.112 +
4.113 +#if CYTHON_TRACING
4.114 +
4.115 +#include "compile.h"
4.116 +#include "frameobject.h"
4.117 +#include "traceback.h"
4.118 +
4.119 +#if CYTHON_TRACING_REUSE_FRAME
4.120 +#define CYTHON_FRAME_MODIFIER static
4.121 +#define CYTHON_FRAME_DEL
4.122 +#else
4.123 +#define CYTHON_FRAME_MODIFIER
4.124 +#define CYTHON_FRAME_DEL Py_DECREF(%(FRAME)s)
4.125 +#endif
4.126 +
4.127 +#define __Pyx_TraceCall(funcname, srcfile, firstlineno) \\
4.128 +static PyCodeObject *%(FRAME_CODE)s = NULL; \\
4.129 +CYTHON_FRAME_MODIFIER PyFrameObject *%(FRAME)s = NULL; \\
4.130 +int __Pyx_use_tracing = 0; \\
4.131 +if (PyThreadState_GET()->use_tracing && PyThreadState_GET()->c_profilefunc) { \\
4.132 + __Pyx_use_tracing = __Pyx_TraceSetupAndCall(&%(FRAME_CODE)s, &%(FRAME)s, funcname, srcfile, firstlineno); \\
4.133 +}
4.134 +
4.135 +#define __Pyx_TraceException() \\
4.136 +if (__Pyx_use_tracing && PyThreadState_GET()->use_tracing && PyThreadState_GET()->c_profilefunc) { \\
4.137 + PyObject *exc_info = __Pyx_GetExceptionTuple(); \\
4.138 + if (exc_info) { \\
4.139 + PyThreadState_GET()->c_profilefunc( \\
4.140 + PyThreadState_GET()->c_profileobj, %(FRAME)s, PyTrace_EXCEPTION, exc_info); \\
4.141 + Py_DECREF(exc_info); \\
4.142 + } \\
4.143 +}
4.144 +
4.145 +#define __Pyx_TraceReturn(result) \\
4.146 +if (__Pyx_use_tracing && PyThreadState_GET()->use_tracing && PyThreadState_GET()->c_profilefunc) { \\
4.147 + PyThreadState_GET()->c_profilefunc( \\
4.148 + PyThreadState_GET()->c_profileobj, %(FRAME)s, PyTrace_RETURN, (PyObject*)result); \\
4.149 + CYTHON_FRAME_DEL; \\
4.150 +}
4.151 +
4.152 +static PyCodeObject *__Pyx_createFrameCodeObject(const char *funcname, const char *srcfile, int firstlineno); /*proto*/
4.153 +static int __Pyx_TraceSetupAndCall(PyCodeObject** code, PyFrameObject** frame, const char *funcname, const char *srcfile, int firstlineno); /*proto*/
4.154 +
4.155 +#else
4.156 +#define __Pyx_TraceCall(funcname, srcfile, firstlineno)
4.157 +#define __Pyx_TraceException()
4.158 +#define __Pyx_TraceReturn(result)
4.159 +#endif /* CYTHON_TRACING */
4.160 +"""
4.161 +% {
4.162 + "FRAME": Naming.frame_cname,
4.163 + "FRAME_CODE": Naming.frame_code_cname,
4.164 +},
4.165 +impl = """
4.166 +
4.167 +#if CYTHON_TRACING
4.168 +
4.169 +static int __Pyx_TraceSetupAndCall(PyCodeObject** code,
4.170 + PyFrameObject** frame,
4.171 + const char *funcname,
4.172 + const char *srcfile,
4.173 + int firstlineno) {
4.174 + if (*frame == NULL || !CYTHON_TRACING_REUSE_FRAME) {
4.175 + if (*code == NULL) {
4.176 + *code = __Pyx_createFrameCodeObject(funcname, srcfile, firstlineno);
4.177 + if (*code == NULL) return 0;
4.178 + }
4.179 + *frame = PyFrame_New(
4.180 + PyThreadState_GET(), /*PyThreadState *tstate*/
4.181 + *code, /*PyCodeObject *code*/
4.182 + PyModule_GetDict(%(MODULE)s), /*PyObject *globals*/
4.183 + 0 /*PyObject *locals*/
4.184 + );
4.185 + if (*frame == NULL) return 0;
4.186 + }
4.187 + else {
4.188 + (*frame)->f_tstate = PyThreadState_GET();
4.189 + }
4.190 + return PyThreadState_GET()->c_profilefunc(PyThreadState_GET()->c_profileobj, *frame, PyTrace_CALL, NULL) == 0;
4.191 +}
4.192 +
4.193 +static PyCodeObject *__Pyx_createFrameCodeObject(const char *funcname, const char *srcfile, int firstlineno) {
4.194 + PyObject *py_srcfile = 0;
4.195 + PyObject *py_funcname = 0;
4.196 + PyCodeObject *py_code = 0;
4.197 +
4.198 + #if PY_MAJOR_VERSION < 3
4.199 + py_funcname = PyString_FromString(funcname);
4.200 + py_srcfile = PyString_FromString(srcfile);
4.201 + #else
4.202 + py_funcname = PyUnicode_FromString(funcname);
4.203 + py_srcfile = PyUnicode_FromString(srcfile);
4.204 + #endif
4.205 + if (!py_funcname | !py_srcfile) goto bad;
4.206 +
4.207 + py_code = PyCode_New(
4.208 + 0, /*int argcount,*/
4.209 + #if PY_MAJOR_VERSION >= 3
4.210 + 0, /*int kwonlyargcount,*/
4.211 + #endif
4.212 + 0, /*int nlocals,*/
4.213 + 0, /*int stacksize,*/
4.214 + 0, /*int flags,*/
4.215 + %(EMPTY_BYTES)s, /*PyObject *code,*/
4.216 + %(EMPTY_TUPLE)s, /*PyObject *consts,*/
4.217 + %(EMPTY_TUPLE)s, /*PyObject *names,*/
4.218 + %(EMPTY_TUPLE)s, /*PyObject *varnames,*/
4.219 + %(EMPTY_TUPLE)s, /*PyObject *freevars,*/
4.220 + %(EMPTY_TUPLE)s, /*PyObject *cellvars,*/
4.221 + py_srcfile, /*PyObject *filename,*/
4.222 + py_funcname, /*PyObject *name,*/
4.223 + firstlineno, /*int firstlineno,*/
4.224 + %(EMPTY_BYTES)s /*PyObject *lnotab*/
4.225 + );
4.226 +
4.227 +bad:
4.228 + Py_XDECREF(py_srcfile);
4.229 + Py_XDECREF(py_funcname);
4.230 +
4.231 + return py_code;
4.232 +}
4.233 +
4.234 +#endif /* CYTHON_TRACING */
4.235 +""" % {
4.236 + 'EMPTY_TUPLE' : Naming.empty_tuple,
4.237 + 'EMPTY_BYTES' : Naming.empty_bytes,
4.238 + "MODULE": Naming.module_cname,
4.239 +})
5.1 --- a/Cython/Compiler/Options.py Thu Jul 16 02:32:52 2009 -0700
5.2 +++ b/Cython/Compiler/Options.py Mon Jul 20 15:39:57 2009 -0700
5.3 @@ -67,10 +67,11 @@
5.4 'wraparound' : True,
5.5 'c99_complex' : False, # Don't use macro wrappers for complex arith, not sure what to name this...
5.6 'callspec' : "",
5.7 + 'profile': None,
5.8 }
5.9
5.10 # Override types possibilities above, if needed
5.11 -option_types = { }
5.12 +option_types = { 'profile': bool }
5.13
5.14 for key, val in option_defaults.items():
5.15 if key not in option_types:
