~ubuntu-branches/ubuntu/maverick/python3.1/maverick

« back to all changes in this revision

Viewing changes to Modules/_lsprof.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2009-03-23 00:01:27 UTC
  • Revision ID: james.westby@ubuntu.com-20090323000127-5fstfxju4ufrhthq
Tags: upstream-3.1~a1+20090322
ImportĀ upstreamĀ versionĀ 3.1~a1+20090322

Show diffs side-by-side

added added

removed removed

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