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