diff --git a/plugins/python/profiler.c b/plugins/python/profiler.c new file mode 100644 index 00000000..13b5f626 --- /dev/null +++ b/plugins/python/profiler.c @@ -0,0 +1,23 @@ +#include "uwsgi_python.h" + +extern struct uwsgi_server uwsgi; + +int uwsgi_python_profiler_call(PyObject *obj, PyFrameObject *frame, int what, PyObject *arg) { + + switch(what) { + case PyTrace_CALL: + uwsgi_log("[uWSGI Python profiler] CALL: %s (line %d) -> %s %d args, stacksize %d\n", + PyString_AsString(frame->f_code->co_filename), + PyFrame_GetLineNumber(frame), + PyString_AsString(frame->f_code->co_name), frame->f_code->co_argcount, frame->f_code->co_stacksize); + break; + case PyTrace_C_CALL: + uwsgi_log("[uWSGI Python profiler] C CALL: %s (line %d) -> %s %d args, stacksize %d\n", + PyString_AsString(frame->f_code->co_filename), + PyFrame_GetLineNumber(frame), + PyEval_GetFuncName(arg), frame->f_code->co_argcount, frame->f_code->co_stacksize); + break; + } + + return 0; +} diff --git a/plugins/python/python_plugin.c b/plugins/python/python_plugin.c index ee46ebc3..05ee3464 100644 --- a/plugins/python/python_plugin.c +++ b/plugins/python/python_plugin.c @@ -792,6 +792,11 @@ void uwsgi_python_init_apps() { init_uwsgi_app(LOADER_EVAL, up.eval, uwsgi.wsgi_req, up.main_thread); } + if (uwsgi.profiler) { + if (!strcmp(uwsgi.profiler, "pycall")) { + PyEval_SetProfile(uwsgi_python_profiler_call, NULL); + } + } } diff --git a/plugins/python/uwsgi_python.h b/plugins/python/uwsgi_python.h index 974535dc..e4ecdad0 100644 --- a/plugins/python/uwsgi_python.h +++ b/plugins/python/uwsgi_python.h @@ -211,3 +211,5 @@ void threaded_swap_ts(struct wsgi_request *, struct uwsgi_app *); void simple_swap_ts(struct wsgi_request *, struct uwsgi_app *); void threaded_reset_ts(struct wsgi_request *, struct uwsgi_app *); void simple_reset_ts(struct wsgi_request *, struct uwsgi_app *); + +int uwsgi_python_profiler_call(PyObject *, PyFrameObject *, int, PyObject *); diff --git a/plugins/python/uwsgiplugin.py b/plugins/python/uwsgiplugin.py index 5e1396f2..1f7a7b73 100644 --- a/plugins/python/uwsgiplugin.py +++ b/plugins/python/uwsgiplugin.py @@ -3,7 +3,7 @@ import os,sys from distutils import sysconfig NAME='python' -GCC_LIST = ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule'] +GCC_LIST = ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule', 'profiler'] CFLAGS = ['-I' + sysconfig.get_python_inc(), '-I' + sysconfig.get_python_inc(plat_specific=True) ] LDFLAGS = [] diff --git a/uwsgi.c b/uwsgi.c index 56f0517d..d9252436 100644 --- a/uwsgi.c +++ b/uwsgi.c @@ -50,6 +50,7 @@ UWSGI_DECLARE_EMBEDDED_PLUGINS static struct option long_base_options[] = { {"max-vars", required_argument, 0, 'v'}, {"buffer-size", required_argument, 0, 'b'}, {"memory-report", no_argument, 0, 'm'}, + {"profiler", required_argument, 0, LONG_ARGS_PROFILER}, {"cgi-mode", no_argument, 0, 'c'}, {"abstract-socket", no_argument, 0, 'a'}, {"chmod-socket", optional_argument, 0, 'C'}, @@ -2382,6 +2383,9 @@ static int manage_base_opt(int i, char *optarg) { uwsgi.file_serve_mode = 1; } return 1; + case LONG_ARGS_PROFILER: + uwsgi.profiler = optarg; + return 1; case LONG_ARGS_INHERIT: uct = uwsgi.config_templates; if (!uct) { diff --git a/uwsgi.h b/uwsgi.h index c7491970..59588f37 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -426,6 +426,7 @@ struct uwsgi_opt { #define LONG_ARGS_VASSALS_INHERIT 17102 #define LONG_ARGS_SOCKET_PROTOCOL 17103 #define LONG_ARGS_LOG_ZEROMQ 17104 +#define LONG_ARGS_PROFILER 17105 #define UWSGI_OK 0 @@ -880,6 +881,7 @@ struct uwsgi_server { char *uidname; char *gidname; + char *profiler; char *mode; char *worker_exec;