| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 1 | #include "Python.h" | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 2 | #include "frameobject.h" | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 3 | #include "rotatingtree.h" | 
 | 4 |  | 
 | 5 | #if !defined(HAVE_LONG_LONG) | 
 | 6 | #error "This module requires long longs!" | 
 | 7 | #endif | 
 | 8 |  | 
 | 9 | /*** Selection of a high-precision timer ***/ | 
 | 10 |  | 
 | 11 | #ifdef MS_WINDOWS | 
 | 12 |  | 
 | 13 | #include <windows.h> | 
 | 14 |  | 
 | 15 | static PY_LONG_LONG | 
 | 16 | hpTimer(void) | 
 | 17 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 18 |     LARGE_INTEGER li; | 
 | 19 |     QueryPerformanceCounter(&li); | 
 | 20 |     return li.QuadPart; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 21 | } | 
 | 22 |  | 
 | 23 | static double | 
 | 24 | hpTimerUnit(void) | 
 | 25 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 26 |     LARGE_INTEGER li; | 
 | 27 |     if (QueryPerformanceFrequency(&li)) | 
 | 28 |         return 1.0 / li.QuadPart; | 
 | 29 |     else | 
 | 30 |         return 0.000001;  /* unlikely */ | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 31 | } | 
 | 32 |  | 
 | 33 | #else  /* !MS_WINDOWS */ | 
 | 34 |  | 
 | 35 | #ifndef HAVE_GETTIMEOFDAY | 
 | 36 | #error "This module requires gettimeofday() on non-Windows platforms!" | 
 | 37 | #endif | 
 | 38 |  | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 39 | #include <sys/resource.h> | 
 | 40 | #include <sys/times.h> | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 41 |  | 
 | 42 | static PY_LONG_LONG | 
 | 43 | hpTimer(void) | 
 | 44 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 45 |     struct timeval tv; | 
 | 46 |     PY_LONG_LONG ret; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 47 | #ifdef GETTIMEOFDAY_NO_TZ | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 48 |     gettimeofday(&tv); | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 49 | #else | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 50 |     gettimeofday(&tv, (struct timezone *)NULL); | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 51 | #endif | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 52 |     ret = tv.tv_sec; | 
 | 53 |     ret = ret * 1000000 + tv.tv_usec; | 
 | 54 |     return ret; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 55 | } | 
 | 56 |  | 
 | 57 | static double | 
 | 58 | hpTimerUnit(void) | 
 | 59 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 60 |     return 0.000001; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 61 | } | 
 | 62 |  | 
 | 63 | #endif  /* MS_WINDOWS */ | 
 | 64 |  | 
 | 65 | /************************************************************/ | 
 | 66 | /* Written by Brett Rosen and Ted Czotter */ | 
 | 67 |  | 
 | 68 | struct _ProfilerEntry; | 
 | 69 |  | 
 | 70 | /* represents a function called from another function */ | 
 | 71 | typedef struct _ProfilerSubEntry { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 72 |     rotating_node_t header; | 
 | 73 |     PY_LONG_LONG tt; | 
 | 74 |     PY_LONG_LONG it; | 
 | 75 |     long callcount; | 
 | 76 |     long recursivecallcount; | 
 | 77 |     long recursionLevel; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 78 | } ProfilerSubEntry; | 
 | 79 |  | 
 | 80 | /* represents a function or user defined block */ | 
 | 81 | typedef struct _ProfilerEntry { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 82 |     rotating_node_t header; | 
 | 83 |     PyObject *userObj; /* PyCodeObject, or a descriptive str for builtins */ | 
 | 84 |     PY_LONG_LONG tt; /* total time in this entry */ | 
 | 85 |     PY_LONG_LONG it; /* inline time in this entry (not in subcalls) */ | 
 | 86 |     long callcount; /* how many times this was called */ | 
 | 87 |     long recursivecallcount; /* how many times called recursively */ | 
 | 88 |     long recursionLevel; | 
 | 89 |     rotating_node_t *calls; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 90 | } ProfilerEntry; | 
 | 91 |  | 
 | 92 | typedef struct _ProfilerContext { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 93 |     PY_LONG_LONG t0; | 
 | 94 |     PY_LONG_LONG subt; | 
 | 95 |     struct _ProfilerContext *previous; | 
 | 96 |     ProfilerEntry *ctxEntry; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 97 | } ProfilerContext; | 
 | 98 |  | 
 | 99 | typedef struct { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 100 |     PyObject_HEAD | 
 | 101 |     rotating_node_t *profilerEntries; | 
 | 102 |     ProfilerContext *currentProfilerContext; | 
 | 103 |     ProfilerContext *freelistProfilerContext; | 
 | 104 |     int flags; | 
 | 105 |     PyObject *externalTimer; | 
 | 106 |     double externalTimerUnit; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 107 | } ProfilerObject; | 
 | 108 |  | 
 | 109 | #define POF_ENABLED     0x001 | 
 | 110 | #define POF_SUBCALLS    0x002 | 
 | 111 | #define POF_BUILTINS    0x004 | 
 | 112 | #define POF_NOMEMORY    0x100 | 
 | 113 |  | 
| Neal Norwitz | 227b533 | 2006-03-22 09:28:35 +0000 | [diff] [blame] | 114 | static PyTypeObject PyProfiler_Type; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 115 |  | 
 | 116 | #define PyProfiler_Check(op) PyObject_TypeCheck(op, &PyProfiler_Type) | 
| Christian Heimes | 90aa764 | 2007-12-19 02:45:37 +0000 | [diff] [blame] | 117 | #define PyProfiler_CheckExact(op) (Py_TYPE(op) == &PyProfiler_Type) | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 118 |  | 
 | 119 | /*** External Timers ***/ | 
 | 120 |  | 
 | 121 | #define DOUBLE_TIMER_PRECISION   4294967296.0 | 
 | 122 | static PyObject *empty_tuple; | 
 | 123 |  | 
 | 124 | static PY_LONG_LONG CallExternalTimer(ProfilerObject *pObj) | 
 | 125 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 126 |     PY_LONG_LONG result; | 
 | 127 |     PyObject *o = PyObject_Call(pObj->externalTimer, empty_tuple, NULL); | 
 | 128 |     if (o == NULL) { | 
 | 129 |         PyErr_WriteUnraisable(pObj->externalTimer); | 
 | 130 |         return 0; | 
 | 131 |     } | 
 | 132 |     if (pObj->externalTimerUnit > 0.0) { | 
 | 133 |         /* interpret the result as an integer that will be scaled | 
 | 134 |            in profiler_getstats() */ | 
 | 135 |         result = PyLong_AsLongLong(o); | 
 | 136 |     } | 
 | 137 |     else { | 
 | 138 |         /* interpret the result as a double measured in seconds. | 
 | 139 |            As the profiler works with PY_LONG_LONG internally | 
 | 140 |            we convert it to a large integer */ | 
 | 141 |         double val = PyFloat_AsDouble(o); | 
 | 142 |         /* error handling delayed to the code below */ | 
 | 143 |         result = (PY_LONG_LONG) (val * DOUBLE_TIMER_PRECISION); | 
 | 144 |     } | 
 | 145 |     Py_DECREF(o); | 
 | 146 |     if (PyErr_Occurred()) { | 
 | 147 |         PyErr_WriteUnraisable(pObj->externalTimer); | 
 | 148 |         return 0; | 
 | 149 |     } | 
 | 150 |     return result; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 151 | } | 
 | 152 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 153 | #define CALL_TIMER(pObj)        ((pObj)->externalTimer ?                \ | 
 | 154 |                                         CallExternalTimer(pObj) :       \ | 
 | 155 |                                         hpTimer()) | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 156 |  | 
 | 157 | /*** ProfilerObject ***/ | 
 | 158 |  | 
 | 159 | static PyObject * | 
 | 160 | normalizeUserObj(PyObject *obj) | 
 | 161 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 162 |     PyCFunctionObject *fn; | 
 | 163 |     if (!PyCFunction_Check(obj)) { | 
 | 164 |         Py_INCREF(obj); | 
 | 165 |         return obj; | 
 | 166 |     } | 
 | 167 |     /* Replace built-in function objects with a descriptive string | 
 | 168 |        because of built-in methods -- keeping a reference to | 
 | 169 |        __self__ is probably not a good idea. */ | 
 | 170 |     fn = (PyCFunctionObject *)obj; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 171 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 172 |     if (fn->m_self == NULL) { | 
 | 173 |         /* built-in function: look up the module name */ | 
 | 174 |         PyObject *mod = fn->m_module; | 
| Victor Stinner | 7edb5df | 2011-06-20 14:59:53 +0200 | [diff] [blame] | 175 |         PyObject *modname = NULL; | 
 | 176 |         if (mod != NULL) { | 
 | 177 |             if (PyUnicode_Check(mod)) { | 
 | 178 |                 modname = mod; | 
 | 179 |                 Py_INCREF(modname); | 
 | 180 |             } | 
 | 181 |             else if (PyModule_Check(mod)) { | 
 | 182 |                 modname = PyModule_GetNameObject(mod); | 
 | 183 |                 if (modname == NULL) | 
 | 184 |                     PyErr_Clear(); | 
| Alexander Belopolsky | e239d23 | 2010-12-08 23:31:48 +0000 | [diff] [blame] | 185 |             } | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 186 |         } | 
| Victor Stinner | 7edb5df | 2011-06-20 14:59:53 +0200 | [diff] [blame] | 187 |         if (modname != NULL) { | 
| Victor Stinner | bd303c1 | 2013-11-07 23:07:29 +0100 | [diff] [blame] | 188 |             if (PyUnicode_CompareWithASCIIString(modname, "builtins") != 0) { | 
| Victor Stinner | 7edb5df | 2011-06-20 14:59:53 +0200 | [diff] [blame] | 189 |                 PyObject *result; | 
 | 190 |                 result = PyUnicode_FromFormat("<%U.%s>", modname, | 
 | 191 |                                               fn->m_ml->ml_name); | 
 | 192 |                 Py_DECREF(modname); | 
 | 193 |                 return result; | 
| Alexander Belopolsky | 532d091 | 2010-12-10 18:14:16 +0000 | [diff] [blame] | 194 |             } | 
| Victor Stinner | 7edb5df | 2011-06-20 14:59:53 +0200 | [diff] [blame] | 195 |             Py_DECREF(modname); | 
| Alexander Belopolsky | 532d091 | 2010-12-10 18:14:16 +0000 | [diff] [blame] | 196 |         } | 
| Victor Stinner | 7edb5df | 2011-06-20 14:59:53 +0200 | [diff] [blame] | 197 |         return PyUnicode_FromFormat("<%s>", fn->m_ml->ml_name); | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 198 |     } | 
 | 199 |     else { | 
 | 200 |         /* built-in method: try to return | 
 | 201 |             repr(getattr(type(__self__), __name__)) | 
 | 202 |         */ | 
 | 203 |         PyObject *self = fn->m_self; | 
 | 204 |         PyObject *name = PyUnicode_FromString(fn->m_ml->ml_name); | 
 | 205 |         if (name != NULL) { | 
 | 206 |             PyObject *mo = _PyType_Lookup(Py_TYPE(self), name); | 
 | 207 |             Py_XINCREF(mo); | 
 | 208 |             Py_DECREF(name); | 
 | 209 |             if (mo != NULL) { | 
 | 210 |                 PyObject *res = PyObject_Repr(mo); | 
 | 211 |                 Py_DECREF(mo); | 
 | 212 |                 if (res != NULL) | 
 | 213 |                     return res; | 
 | 214 |             } | 
 | 215 |         } | 
 | 216 |         PyErr_Clear(); | 
 | 217 |         return PyUnicode_FromFormat("<built-in method %s>", | 
 | 218 |                                     fn->m_ml->ml_name); | 
 | 219 |     } | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 220 | } | 
 | 221 |  | 
 | 222 | static ProfilerEntry* | 
 | 223 | newProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj) | 
 | 224 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 225 |     ProfilerEntry *self; | 
| Victor Stinner | b640491 | 2013-07-07 16:21:41 +0200 | [diff] [blame] | 226 |     self = (ProfilerEntry*) PyMem_Malloc(sizeof(ProfilerEntry)); | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 227 |     if (self == NULL) { | 
 | 228 |         pObj->flags |= POF_NOMEMORY; | 
 | 229 |         return NULL; | 
 | 230 |     } | 
 | 231 |     userObj = normalizeUserObj(userObj); | 
 | 232 |     if (userObj == NULL) { | 
 | 233 |         PyErr_Clear(); | 
| Victor Stinner | b640491 | 2013-07-07 16:21:41 +0200 | [diff] [blame] | 234 |         PyMem_Free(self); | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 235 |         pObj->flags |= POF_NOMEMORY; | 
 | 236 |         return NULL; | 
 | 237 |     } | 
 | 238 |     self->header.key = key; | 
 | 239 |     self->userObj = userObj; | 
 | 240 |     self->tt = 0; | 
 | 241 |     self->it = 0; | 
 | 242 |     self->callcount = 0; | 
 | 243 |     self->recursivecallcount = 0; | 
 | 244 |     self->recursionLevel = 0; | 
 | 245 |     self->calls = EMPTY_ROTATING_TREE; | 
 | 246 |     RotatingTree_Add(&pObj->profilerEntries, &self->header); | 
 | 247 |     return self; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 248 | } | 
 | 249 |  | 
 | 250 | static ProfilerEntry* | 
 | 251 | getEntry(ProfilerObject *pObj, void *key) | 
 | 252 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 253 |     return (ProfilerEntry*) RotatingTree_Get(&pObj->profilerEntries, key); | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 254 | } | 
 | 255 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 256 | static ProfilerSubEntry * | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 257 | getSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry) | 
 | 258 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 259 |     return (ProfilerSubEntry*) RotatingTree_Get(&caller->calls, | 
 | 260 |                                                 (void *)entry); | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 261 | } | 
 | 262 |  | 
 | 263 | static ProfilerSubEntry * | 
 | 264 | newSubEntry(ProfilerObject *pObj,  ProfilerEntry *caller, ProfilerEntry* entry) | 
 | 265 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 266 |     ProfilerSubEntry *self; | 
| Victor Stinner | b640491 | 2013-07-07 16:21:41 +0200 | [diff] [blame] | 267 |     self = (ProfilerSubEntry*) PyMem_Malloc(sizeof(ProfilerSubEntry)); | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 268 |     if (self == NULL) { | 
 | 269 |         pObj->flags |= POF_NOMEMORY; | 
 | 270 |         return NULL; | 
 | 271 |     } | 
 | 272 |     self->header.key = (void *)entry; | 
 | 273 |     self->tt = 0; | 
 | 274 |     self->it = 0; | 
 | 275 |     self->callcount = 0; | 
 | 276 |     self->recursivecallcount = 0; | 
 | 277 |     self->recursionLevel = 0; | 
 | 278 |     RotatingTree_Add(&caller->calls, &self->header); | 
 | 279 |     return self; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 280 | } | 
 | 281 |  | 
 | 282 | static int freeSubEntry(rotating_node_t *header, void *arg) | 
 | 283 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 284 |     ProfilerSubEntry *subentry = (ProfilerSubEntry*) header; | 
| Victor Stinner | b640491 | 2013-07-07 16:21:41 +0200 | [diff] [blame] | 285 |     PyMem_Free(subentry); | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 286 |     return 0; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 287 | } | 
 | 288 |  | 
 | 289 | static int freeEntry(rotating_node_t *header, void *arg) | 
 | 290 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 291 |     ProfilerEntry *entry = (ProfilerEntry*) header; | 
 | 292 |     RotatingTree_Enum(entry->calls, freeSubEntry, NULL); | 
 | 293 |     Py_DECREF(entry->userObj); | 
| Victor Stinner | b640491 | 2013-07-07 16:21:41 +0200 | [diff] [blame] | 294 |     PyMem_Free(entry); | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 295 |     return 0; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 296 | } | 
 | 297 |  | 
 | 298 | static void clearEntries(ProfilerObject *pObj) | 
 | 299 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 300 |     RotatingTree_Enum(pObj->profilerEntries, freeEntry, NULL); | 
 | 301 |     pObj->profilerEntries = EMPTY_ROTATING_TREE; | 
 | 302 |     /* release the memory hold by the ProfilerContexts */ | 
 | 303 |     if (pObj->currentProfilerContext) { | 
| Victor Stinner | b640491 | 2013-07-07 16:21:41 +0200 | [diff] [blame] | 304 |         PyMem_Free(pObj->currentProfilerContext); | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 305 |         pObj->currentProfilerContext = NULL; | 
 | 306 |     } | 
 | 307 |     while (pObj->freelistProfilerContext) { | 
 | 308 |         ProfilerContext *c = pObj->freelistProfilerContext; | 
 | 309 |         pObj->freelistProfilerContext = c->previous; | 
| Victor Stinner | b640491 | 2013-07-07 16:21:41 +0200 | [diff] [blame] | 310 |         PyMem_Free(c); | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 311 |     } | 
 | 312 |     pObj->freelistProfilerContext = NULL; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 313 | } | 
 | 314 |  | 
 | 315 | static void | 
 | 316 | initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry) | 
 | 317 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 318 |     self->ctxEntry = entry; | 
 | 319 |     self->subt = 0; | 
 | 320 |     self->previous = pObj->currentProfilerContext; | 
 | 321 |     pObj->currentProfilerContext = self; | 
 | 322 |     ++entry->recursionLevel; | 
 | 323 |     if ((pObj->flags & POF_SUBCALLS) && self->previous) { | 
 | 324 |         /* find or create an entry for me in my caller's entry */ | 
 | 325 |         ProfilerEntry *caller = self->previous->ctxEntry; | 
 | 326 |         ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry); | 
 | 327 |         if (subentry == NULL) | 
 | 328 |             subentry = newSubEntry(pObj, caller, entry); | 
 | 329 |         if (subentry) | 
 | 330 |             ++subentry->recursionLevel; | 
 | 331 |     } | 
 | 332 |     self->t0 = CALL_TIMER(pObj); | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 333 | } | 
 | 334 |  | 
 | 335 | static void | 
 | 336 | Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry) | 
 | 337 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 338 |     PY_LONG_LONG tt = CALL_TIMER(pObj) - self->t0; | 
 | 339 |     PY_LONG_LONG it = tt - self->subt; | 
 | 340 |     if (self->previous) | 
 | 341 |         self->previous->subt += tt; | 
 | 342 |     pObj->currentProfilerContext = self->previous; | 
 | 343 |     if (--entry->recursionLevel == 0) | 
 | 344 |         entry->tt += tt; | 
 | 345 |     else | 
 | 346 |         ++entry->recursivecallcount; | 
 | 347 |     entry->it += it; | 
 | 348 |     entry->callcount++; | 
 | 349 |     if ((pObj->flags & POF_SUBCALLS) && self->previous) { | 
 | 350 |         /* find or create an entry for me in my caller's entry */ | 
 | 351 |         ProfilerEntry *caller = self->previous->ctxEntry; | 
 | 352 |         ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry); | 
 | 353 |         if (subentry) { | 
 | 354 |             if (--subentry->recursionLevel == 0) | 
 | 355 |                 subentry->tt += tt; | 
 | 356 |             else | 
 | 357 |                 ++subentry->recursivecallcount; | 
 | 358 |             subentry->it += it; | 
 | 359 |             ++subentry->callcount; | 
 | 360 |         } | 
 | 361 |     } | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 362 | } | 
 | 363 |  | 
 | 364 | static void | 
 | 365 | ptrace_enter_call(PyObject *self, void *key, PyObject *userObj) | 
 | 366 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 367 |     /* entering a call to the function identified by 'key' | 
 | 368 |        (which can be a PyCodeObject or a PyMethodDef pointer) */ | 
 | 369 |     ProfilerObject *pObj = (ProfilerObject*)self; | 
 | 370 |     ProfilerEntry *profEntry; | 
 | 371 |     ProfilerContext *pContext; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 372 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 373 |     /* In the case of entering a generator expression frame via a | 
 | 374 |      * throw (gen_send_ex(.., 1)), we may already have an | 
 | 375 |      * Exception set here. We must not mess around with this | 
 | 376 |      * exception, and some of the code under here assumes that | 
 | 377 |      * PyErr_* is its own to mess around with, so we have to | 
 | 378 |      * save and restore any current exception. */ | 
 | 379 |     PyObject *last_type, *last_value, *last_tb; | 
 | 380 |     PyErr_Fetch(&last_type, &last_value, &last_tb); | 
| Thomas Wouters | 89d996e | 2007-09-08 17:39:28 +0000 | [diff] [blame] | 381 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 382 |     profEntry = getEntry(pObj, key); | 
 | 383 |     if (profEntry == NULL) { | 
 | 384 |         profEntry = newProfilerEntry(pObj, key, userObj); | 
 | 385 |         if (profEntry == NULL) | 
 | 386 |             goto restorePyerr; | 
 | 387 |     } | 
 | 388 |     /* grab a ProfilerContext out of the free list */ | 
 | 389 |     pContext = pObj->freelistProfilerContext; | 
 | 390 |     if (pContext) { | 
 | 391 |         pObj->freelistProfilerContext = pContext->previous; | 
 | 392 |     } | 
 | 393 |     else { | 
 | 394 |         /* free list exhausted, allocate a new one */ | 
 | 395 |         pContext = (ProfilerContext*) | 
| Victor Stinner | b640491 | 2013-07-07 16:21:41 +0200 | [diff] [blame] | 396 |             PyMem_Malloc(sizeof(ProfilerContext)); | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 397 |         if (pContext == NULL) { | 
 | 398 |             pObj->flags |= POF_NOMEMORY; | 
 | 399 |             goto restorePyerr; | 
 | 400 |         } | 
 | 401 |     } | 
 | 402 |     initContext(pObj, pContext, profEntry); | 
| Thomas Wouters | 89d996e | 2007-09-08 17:39:28 +0000 | [diff] [blame] | 403 |  | 
 | 404 | restorePyerr: | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 405 |     PyErr_Restore(last_type, last_value, last_tb); | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 406 | } | 
 | 407 |  | 
 | 408 | static void | 
 | 409 | ptrace_leave_call(PyObject *self, void *key) | 
 | 410 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 411 |     /* leaving a call to the function identified by 'key' */ | 
 | 412 |     ProfilerObject *pObj = (ProfilerObject*)self; | 
 | 413 |     ProfilerEntry *profEntry; | 
 | 414 |     ProfilerContext *pContext; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 415 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 416 |     pContext = pObj->currentProfilerContext; | 
 | 417 |     if (pContext == NULL) | 
 | 418 |         return; | 
 | 419 |     profEntry = getEntry(pObj, key); | 
 | 420 |     if (profEntry) { | 
 | 421 |         Stop(pObj, pContext, profEntry); | 
 | 422 |     } | 
 | 423 |     else { | 
 | 424 |         pObj->currentProfilerContext = pContext->previous; | 
 | 425 |     } | 
 | 426 |     /* put pContext into the free list */ | 
 | 427 |     pContext->previous = pObj->freelistProfilerContext; | 
 | 428 |     pObj->freelistProfilerContext = pContext; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 429 | } | 
 | 430 |  | 
 | 431 | static int | 
 | 432 | profiler_callback(PyObject *self, PyFrameObject *frame, int what, | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 433 |                   PyObject *arg) | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 434 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 435 |     switch (what) { | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 436 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 437 |     /* the 'frame' of a called function is about to start its execution */ | 
 | 438 |     case PyTrace_CALL: | 
 | 439 |         ptrace_enter_call(self, (void *)frame->f_code, | 
 | 440 |                                 (PyObject *)frame->f_code); | 
 | 441 |         break; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 442 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 443 |     /* the 'frame' of a called function is about to finish | 
 | 444 |        (either normally or with an exception) */ | 
 | 445 |     case PyTrace_RETURN: | 
 | 446 |         ptrace_leave_call(self, (void *)frame->f_code); | 
 | 447 |         break; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 448 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 449 |     /* case PyTrace_EXCEPTION: | 
 | 450 |         If the exception results in the function exiting, a | 
 | 451 |         PyTrace_RETURN event will be generated, so we don't need to | 
 | 452 |         handle it. */ | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 453 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 454 |     /* the Python function 'frame' is issuing a call to the built-in | 
 | 455 |        function 'arg' */ | 
 | 456 |     case PyTrace_C_CALL: | 
 | 457 |         if ((((ProfilerObject *)self)->flags & POF_BUILTINS) | 
 | 458 |             && PyCFunction_Check(arg)) { | 
 | 459 |             ptrace_enter_call(self, | 
 | 460 |                               ((PyCFunctionObject *)arg)->m_ml, | 
 | 461 |                               arg); | 
 | 462 |         } | 
 | 463 |         break; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 464 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 465 |     /* the call to the built-in function 'arg' is returning into its | 
 | 466 |        caller 'frame' */ | 
 | 467 |     case PyTrace_C_RETURN:              /* ...normally */ | 
 | 468 |     case PyTrace_C_EXCEPTION:           /* ...with an exception set */ | 
 | 469 |         if ((((ProfilerObject *)self)->flags & POF_BUILTINS) | 
 | 470 |             && PyCFunction_Check(arg)) { | 
 | 471 |             ptrace_leave_call(self, | 
 | 472 |                               ((PyCFunctionObject *)arg)->m_ml); | 
 | 473 |         } | 
 | 474 |         break; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 475 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 476 |     default: | 
 | 477 |         break; | 
 | 478 |     } | 
 | 479 |     return 0; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 480 | } | 
 | 481 |  | 
 | 482 | static int | 
 | 483 | pending_exception(ProfilerObject *pObj) | 
 | 484 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 485 |     if (pObj->flags & POF_NOMEMORY) { | 
 | 486 |         pObj->flags -= POF_NOMEMORY; | 
 | 487 |         PyErr_SetString(PyExc_MemoryError, | 
 | 488 |                         "memory was exhausted while profiling"); | 
 | 489 |         return -1; | 
 | 490 |     } | 
 | 491 |     return 0; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 492 | } | 
 | 493 |  | 
 | 494 | /************************************************************/ | 
 | 495 |  | 
 | 496 | static PyStructSequence_Field profiler_entry_fields[] = { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 497 |     {"code",         "code object or built-in function name"}, | 
 | 498 |     {"callcount",    "how many times this was called"}, | 
 | 499 |     {"reccallcount", "how many times called recursively"}, | 
 | 500 |     {"totaltime",    "total time in this entry"}, | 
 | 501 |     {"inlinetime",   "inline time in this entry (not in subcalls)"}, | 
 | 502 |     {"calls",        "details of the calls"}, | 
 | 503 |     {0} | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 504 | }; | 
 | 505 |  | 
 | 506 | static PyStructSequence_Field profiler_subentry_fields[] = { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 507 |     {"code",         "called code object or built-in function name"}, | 
 | 508 |     {"callcount",    "how many times this is called"}, | 
 | 509 |     {"reccallcount", "how many times this is called recursively"}, | 
 | 510 |     {"totaltime",    "total time spent in this call"}, | 
 | 511 |     {"inlinetime",   "inline time (not in further subcalls)"}, | 
 | 512 |     {0} | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 513 | }; | 
 | 514 |  | 
 | 515 | static PyStructSequence_Desc profiler_entry_desc = { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 516 |     "_lsprof.profiler_entry", /* name */ | 
 | 517 |     NULL, /* doc */ | 
 | 518 |     profiler_entry_fields, | 
 | 519 |     6 | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 520 | }; | 
 | 521 |  | 
 | 522 | static PyStructSequence_Desc profiler_subentry_desc = { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 523 |     "_lsprof.profiler_subentry", /* name */ | 
 | 524 |     NULL, /* doc */ | 
 | 525 |     profiler_subentry_fields, | 
 | 526 |     5 | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 527 | }; | 
 | 528 |  | 
| Thomas Wouters | 49fd7fa | 2006-04-21 10:40:58 +0000 | [diff] [blame] | 529 | static int initialized; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 530 | static PyTypeObject StatsEntryType; | 
 | 531 | static PyTypeObject StatsSubEntryType; | 
 | 532 |  | 
 | 533 |  | 
 | 534 | typedef struct { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 535 |     PyObject *list; | 
 | 536 |     PyObject *sublist; | 
 | 537 |     double factor; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 538 | } statscollector_t; | 
 | 539 |  | 
 | 540 | static int statsForSubEntry(rotating_node_t *node, void *arg) | 
 | 541 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 542 |     ProfilerSubEntry *sentry = (ProfilerSubEntry*) node; | 
 | 543 |     statscollector_t *collect = (statscollector_t*) arg; | 
 | 544 |     ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key; | 
 | 545 |     int err; | 
 | 546 |     PyObject *sinfo; | 
 | 547 |     sinfo = PyObject_CallFunction((PyObject*) &StatsSubEntryType, | 
 | 548 |                                   "((Olldd))", | 
 | 549 |                                   entry->userObj, | 
 | 550 |                                   sentry->callcount, | 
 | 551 |                                   sentry->recursivecallcount, | 
 | 552 |                                   collect->factor * sentry->tt, | 
 | 553 |                                   collect->factor * sentry->it); | 
 | 554 |     if (sinfo == NULL) | 
 | 555 |         return -1; | 
 | 556 |     err = PyList_Append(collect->sublist, sinfo); | 
 | 557 |     Py_DECREF(sinfo); | 
 | 558 |     return err; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 559 | } | 
 | 560 |  | 
 | 561 | static int statsForEntry(rotating_node_t *node, void *arg) | 
 | 562 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 563 |     ProfilerEntry *entry = (ProfilerEntry*) node; | 
 | 564 |     statscollector_t *collect = (statscollector_t*) arg; | 
 | 565 |     PyObject *info; | 
 | 566 |     int err; | 
 | 567 |     if (entry->callcount == 0) | 
 | 568 |         return 0;   /* skip */ | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 569 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 570 |     if (entry->calls != EMPTY_ROTATING_TREE) { | 
 | 571 |         collect->sublist = PyList_New(0); | 
 | 572 |         if (collect->sublist == NULL) | 
 | 573 |             return -1; | 
 | 574 |         if (RotatingTree_Enum(entry->calls, | 
 | 575 |                               statsForSubEntry, collect) != 0) { | 
 | 576 |             Py_DECREF(collect->sublist); | 
 | 577 |             return -1; | 
 | 578 |         } | 
 | 579 |     } | 
 | 580 |     else { | 
 | 581 |         Py_INCREF(Py_None); | 
 | 582 |         collect->sublist = Py_None; | 
 | 583 |     } | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 584 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 585 |     info = PyObject_CallFunction((PyObject*) &StatsEntryType, | 
 | 586 |                                  "((OllddO))", | 
 | 587 |                                  entry->userObj, | 
 | 588 |                                  entry->callcount, | 
 | 589 |                                  entry->recursivecallcount, | 
 | 590 |                                  collect->factor * entry->tt, | 
 | 591 |                                  collect->factor * entry->it, | 
 | 592 |                                  collect->sublist); | 
 | 593 |     Py_DECREF(collect->sublist); | 
 | 594 |     if (info == NULL) | 
 | 595 |         return -1; | 
 | 596 |     err = PyList_Append(collect->list, info); | 
 | 597 |     Py_DECREF(info); | 
 | 598 |     return err; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 599 | } | 
 | 600 |  | 
 | 601 | PyDoc_STRVAR(getstats_doc, "\ | 
 | 602 | getstats() -> list of profiler_entry objects\n\ | 
 | 603 | \n\ | 
 | 604 | Return all information collected by the profiler.\n\ | 
 | 605 | Each profiler_entry is a tuple-like object with the\n\ | 
 | 606 | following attributes:\n\ | 
 | 607 | \n\ | 
 | 608 |     code          code object\n\ | 
 | 609 |     callcount     how many times this was called\n\ | 
 | 610 |     reccallcount  how many times called recursively\n\ | 
 | 611 |     totaltime     total time in this entry\n\ | 
 | 612 |     inlinetime    inline time in this entry (not in subcalls)\n\ | 
 | 613 |     calls         details of the calls\n\ | 
 | 614 | \n\ | 
 | 615 | The calls attribute is either None or a list of\n\ | 
 | 616 | profiler_subentry objects:\n\ | 
 | 617 | \n\ | 
 | 618 |     code          called code object\n\ | 
 | 619 |     callcount     how many times this is called\n\ | 
 | 620 |     reccallcount  how many times this is called recursively\n\ | 
 | 621 |     totaltime     total time spent in this call\n\ | 
 | 622 |     inlinetime    inline time (not in further subcalls)\n\ | 
 | 623 | "); | 
 | 624 |  | 
 | 625 | static PyObject* | 
 | 626 | profiler_getstats(ProfilerObject *pObj, PyObject* noarg) | 
 | 627 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 628 |     statscollector_t collect; | 
 | 629 |     if (pending_exception(pObj)) | 
 | 630 |         return NULL; | 
 | 631 |     if (!pObj->externalTimer) | 
 | 632 |         collect.factor = hpTimerUnit(); | 
 | 633 |     else if (pObj->externalTimerUnit > 0.0) | 
 | 634 |         collect.factor = pObj->externalTimerUnit; | 
 | 635 |     else | 
 | 636 |         collect.factor = 1.0 / DOUBLE_TIMER_PRECISION; | 
 | 637 |     collect.list = PyList_New(0); | 
 | 638 |     if (collect.list == NULL) | 
 | 639 |         return NULL; | 
 | 640 |     if (RotatingTree_Enum(pObj->profilerEntries, statsForEntry, &collect) | 
 | 641 |         != 0) { | 
 | 642 |         Py_DECREF(collect.list); | 
 | 643 |         return NULL; | 
 | 644 |     } | 
 | 645 |     return collect.list; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 646 | } | 
 | 647 |  | 
 | 648 | static int | 
 | 649 | setSubcalls(ProfilerObject *pObj, int nvalue) | 
 | 650 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 651 |     if (nvalue == 0) | 
 | 652 |         pObj->flags &= ~POF_SUBCALLS; | 
 | 653 |     else if (nvalue > 0) | 
 | 654 |         pObj->flags |=  POF_SUBCALLS; | 
 | 655 |     return 0; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 656 | } | 
 | 657 |  | 
 | 658 | static int | 
 | 659 | setBuiltins(ProfilerObject *pObj, int nvalue) | 
 | 660 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 661 |     if (nvalue == 0) | 
 | 662 |         pObj->flags &= ~POF_BUILTINS; | 
 | 663 |     else if (nvalue > 0) { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 664 |         pObj->flags |=  POF_BUILTINS; | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 665 |     } | 
 | 666 |     return 0; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 667 | } | 
 | 668 |  | 
 | 669 | PyDoc_STRVAR(enable_doc, "\ | 
 | 670 | enable(subcalls=True, builtins=True)\n\ | 
 | 671 | \n\ | 
 | 672 | Start collecting profiling information.\n\ | 
 | 673 | If 'subcalls' is True, also records for each function\n\ | 
 | 674 | statistics separated according to its current caller.\n\ | 
 | 675 | If 'builtins' is True, records the time spent in\n\ | 
 | 676 | built-in functions separately from their caller.\n\ | 
 | 677 | "); | 
 | 678 |  | 
 | 679 | static PyObject* | 
 | 680 | profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds) | 
 | 681 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 682 |     int subcalls = -1; | 
 | 683 |     int builtins = -1; | 
 | 684 |     static char *kwlist[] = {"subcalls", "builtins", 0}; | 
 | 685 |     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable", | 
 | 686 |                                      kwlist, &subcalls, &builtins)) | 
 | 687 |         return NULL; | 
 | 688 |     if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0) | 
 | 689 |         return NULL; | 
 | 690 |     PyEval_SetProfile(profiler_callback, (PyObject*)self); | 
 | 691 |     self->flags |= POF_ENABLED; | 
 | 692 |     Py_INCREF(Py_None); | 
 | 693 |     return Py_None; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 694 | } | 
 | 695 |  | 
 | 696 | static void | 
 | 697 | flush_unmatched(ProfilerObject *pObj) | 
 | 698 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 699 |     while (pObj->currentProfilerContext) { | 
 | 700 |         ProfilerContext *pContext = pObj->currentProfilerContext; | 
 | 701 |         ProfilerEntry *profEntry= pContext->ctxEntry; | 
 | 702 |         if (profEntry) | 
 | 703 |             Stop(pObj, pContext, profEntry); | 
 | 704 |         else | 
 | 705 |             pObj->currentProfilerContext = pContext->previous; | 
 | 706 |         if (pContext) | 
| Victor Stinner | b640491 | 2013-07-07 16:21:41 +0200 | [diff] [blame] | 707 |             PyMem_Free(pContext); | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 708 |     } | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 709 |  | 
 | 710 | } | 
 | 711 |  | 
 | 712 | PyDoc_STRVAR(disable_doc, "\ | 
 | 713 | disable()\n\ | 
 | 714 | \n\ | 
 | 715 | Stop collecting profiling information.\n\ | 
 | 716 | "); | 
 | 717 |  | 
 | 718 | static PyObject* | 
 | 719 | profiler_disable(ProfilerObject *self, PyObject* noarg) | 
 | 720 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 721 |     self->flags &= ~POF_ENABLED; | 
 | 722 |     PyEval_SetProfile(NULL, NULL); | 
 | 723 |     flush_unmatched(self); | 
 | 724 |     if (pending_exception(self)) | 
 | 725 |         return NULL; | 
 | 726 |     Py_INCREF(Py_None); | 
 | 727 |     return Py_None; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 728 | } | 
 | 729 |  | 
 | 730 | PyDoc_STRVAR(clear_doc, "\ | 
 | 731 | clear()\n\ | 
 | 732 | \n\ | 
 | 733 | Clear all profiling information collected so far.\n\ | 
 | 734 | "); | 
 | 735 |  | 
 | 736 | static PyObject* | 
 | 737 | profiler_clear(ProfilerObject *pObj, PyObject* noarg) | 
 | 738 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 739 |     clearEntries(pObj); | 
 | 740 |     Py_INCREF(Py_None); | 
 | 741 |     return Py_None; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 742 | } | 
 | 743 |  | 
 | 744 | static void | 
 | 745 | profiler_dealloc(ProfilerObject *op) | 
 | 746 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 747 |     if (op->flags & POF_ENABLED) | 
 | 748 |         PyEval_SetProfile(NULL, NULL); | 
 | 749 |     flush_unmatched(op); | 
 | 750 |     clearEntries(op); | 
 | 751 |     Py_XDECREF(op->externalTimer); | 
 | 752 |     Py_TYPE(op)->tp_free(op); | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 753 | } | 
 | 754 |  | 
 | 755 | static int | 
 | 756 | profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw) | 
 | 757 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 758 |     PyObject *o; | 
 | 759 |     PyObject *timer = NULL; | 
 | 760 |     double timeunit = 0.0; | 
 | 761 |     int subcalls = 1; | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 762 |     int builtins = 1; | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 763 |     static char *kwlist[] = {"timer", "timeunit", | 
 | 764 |                                    "subcalls", "builtins", 0}; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 765 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 766 |     if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odii:Profiler", kwlist, | 
 | 767 |                                      &timer, &timeunit, | 
 | 768 |                                      &subcalls, &builtins)) | 
 | 769 |         return -1; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 770 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 771 |     if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0) | 
 | 772 |         return -1; | 
 | 773 |     o = pObj->externalTimer; | 
 | 774 |     pObj->externalTimer = timer; | 
 | 775 |     Py_XINCREF(timer); | 
 | 776 |     Py_XDECREF(o); | 
 | 777 |     pObj->externalTimerUnit = timeunit; | 
 | 778 |     return 0; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 779 | } | 
 | 780 |  | 
 | 781 | static PyMethodDef profiler_methods[] = { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 782 |     {"getstats",    (PyCFunction)profiler_getstats, | 
 | 783 |                     METH_NOARGS,                        getstats_doc}, | 
 | 784 |     {"enable",          (PyCFunction)profiler_enable, | 
 | 785 |                     METH_VARARGS | METH_KEYWORDS,       enable_doc}, | 
 | 786 |     {"disable",         (PyCFunction)profiler_disable, | 
 | 787 |                     METH_NOARGS,                        disable_doc}, | 
 | 788 |     {"clear",           (PyCFunction)profiler_clear, | 
 | 789 |                     METH_NOARGS,                        clear_doc}, | 
 | 790 |     {NULL, NULL} | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 791 | }; | 
 | 792 |  | 
 | 793 | PyDoc_STRVAR(profiler_doc, "\ | 
 | 794 | Profiler(custom_timer=None, time_unit=None, subcalls=True, builtins=True)\n\ | 
 | 795 | \n\ | 
 | 796 |     Builds a profiler object using the specified timer function.\n\ | 
 | 797 |     The default timer is a fast built-in one based on real time.\n\ | 
 | 798 |     For custom timer functions returning integers, time_unit can\n\ | 
 | 799 |     be a float specifying a scale (i.e. how long each integer unit\n\ | 
 | 800 |     is, in seconds).\n\ | 
 | 801 | "); | 
 | 802 |  | 
| Neal Norwitz | 227b533 | 2006-03-22 09:28:35 +0000 | [diff] [blame] | 803 | static PyTypeObject PyProfiler_Type = { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 804 |     PyVarObject_HEAD_INIT(NULL, 0) | 
 | 805 |     "_lsprof.Profiler",                     /* tp_name */ | 
 | 806 |     sizeof(ProfilerObject),                 /* tp_basicsize */ | 
 | 807 |     0,                                      /* tp_itemsize */ | 
 | 808 |     (destructor)profiler_dealloc,           /* tp_dealloc */ | 
 | 809 |     0,                                      /* tp_print */ | 
 | 810 |     0,                                      /* tp_getattr */ | 
 | 811 |     0,                                      /* tp_setattr */ | 
 | 812 |     0,                                      /* tp_reserved */ | 
 | 813 |     0,                                      /* tp_repr */ | 
 | 814 |     0,                                      /* tp_as_number */ | 
 | 815 |     0,                                      /* tp_as_sequence */ | 
 | 816 |     0,                                      /* tp_as_mapping */ | 
 | 817 |     0,                                      /* tp_hash */ | 
 | 818 |     0,                                      /* tp_call */ | 
 | 819 |     0,                                      /* tp_str */ | 
 | 820 |     0,                                      /* tp_getattro */ | 
 | 821 |     0,                                      /* tp_setattro */ | 
 | 822 |     0,                                      /* tp_as_buffer */ | 
 | 823 |     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ | 
 | 824 |     profiler_doc,                           /* tp_doc */ | 
 | 825 |     0,                                      /* tp_traverse */ | 
 | 826 |     0,                                      /* tp_clear */ | 
 | 827 |     0,                                      /* tp_richcompare */ | 
 | 828 |     0,                                      /* tp_weaklistoffset */ | 
 | 829 |     0,                                      /* tp_iter */ | 
 | 830 |     0,                                      /* tp_iternext */ | 
 | 831 |     profiler_methods,                       /* tp_methods */ | 
 | 832 |     0,                                      /* tp_members */ | 
 | 833 |     0,                                      /* tp_getset */ | 
 | 834 |     0,                                      /* tp_base */ | 
 | 835 |     0,                                      /* tp_dict */ | 
 | 836 |     0,                                      /* tp_descr_get */ | 
 | 837 |     0,                                      /* tp_descr_set */ | 
 | 838 |     0,                                      /* tp_dictoffset */ | 
 | 839 |     (initproc)profiler_init,                /* tp_init */ | 
 | 840 |     PyType_GenericAlloc,                    /* tp_alloc */ | 
 | 841 |     PyType_GenericNew,                      /* tp_new */ | 
 | 842 |     PyObject_Del,                           /* tp_free */ | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 843 | }; | 
 | 844 |  | 
 | 845 | static PyMethodDef moduleMethods[] = { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 846 |     {NULL, NULL} | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 847 | }; | 
 | 848 |  | 
| Martin v. Löwis | 1a21451 | 2008-06-11 05:26:20 +0000 | [diff] [blame] | 849 |  | 
 | 850 | static struct PyModuleDef _lsprofmodule = { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 851 |     PyModuleDef_HEAD_INIT, | 
 | 852 |     "_lsprof", | 
 | 853 |     "Fast profiler", | 
 | 854 |     -1, | 
 | 855 |     moduleMethods, | 
 | 856 |     NULL, | 
 | 857 |     NULL, | 
 | 858 |     NULL, | 
 | 859 |     NULL | 
| Martin v. Löwis | 1a21451 | 2008-06-11 05:26:20 +0000 | [diff] [blame] | 860 | }; | 
 | 861 |  | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 862 | PyMODINIT_FUNC | 
| Martin v. Löwis | 1a21451 | 2008-06-11 05:26:20 +0000 | [diff] [blame] | 863 | PyInit__lsprof(void) | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 864 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 865 |     PyObject *module, *d; | 
 | 866 |     module = PyModule_Create(&_lsprofmodule); | 
 | 867 |     if (module == NULL) | 
 | 868 |         return NULL; | 
 | 869 |     d = PyModule_GetDict(module); | 
 | 870 |     if (PyType_Ready(&PyProfiler_Type) < 0) | 
 | 871 |         return NULL; | 
 | 872 |     PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type); | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 873 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 874 |     if (!initialized) { | 
| Victor Stinner | 1c8f059 | 2013-07-22 22:24:54 +0200 | [diff] [blame] | 875 |         if (PyStructSequence_InitType2(&StatsEntryType, | 
 | 876 |                                        &profiler_entry_desc) < 0) | 
 | 877 |             return NULL; | 
 | 878 |         if (PyStructSequence_InitType2(&StatsSubEntryType, | 
 | 879 |                                        &profiler_subentry_desc) < 0) | 
 | 880 |             return NULL; | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 881 |     } | 
 | 882 |     Py_INCREF((PyObject*) &StatsEntryType); | 
 | 883 |     Py_INCREF((PyObject*) &StatsSubEntryType); | 
 | 884 |     PyModule_AddObject(module, "profiler_entry", | 
 | 885 |                        (PyObject*) &StatsEntryType); | 
 | 886 |     PyModule_AddObject(module, "profiler_subentry", | 
 | 887 |                        (PyObject*) &StatsSubEntryType); | 
 | 888 |     empty_tuple = PyTuple_New(0); | 
 | 889 |     initialized = 1; | 
 | 890 |     return module; | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 891 | } |