DEFINEFN void psyco_profile_threads(int start) { PyInterpreterState* istate; PyThreadState* tstate; if (!profile_function) return; istate = PyThreadState_Get()->interp; for (tstate=istate->tstate_head; tstate; tstate=tstate->next) { ceval_events_t* cev; if (!measuring_state(tstate)) continue; cev = get_cevents(tstate); if (start == !cev->current_hook) { stats_printf(("stats: %s hooks on thread %p\n", start?"adding":"removing", tstate)); profile_function(cev, start); if (!update_ceval_hooks(cev) && start) { /* cannot start, stop again */ profile_function(cev, 0); } } } }
DEFINEFN void psyco_stats_append(PyThreadState* tstate, PyFrameObject* f) { double charge; float cs_charge; int bits; time_measure_t numticks; if (!measuring_state(tstate)) return; numticks = get_measure(tstate); if (measure_is_zero(numticks) || f == NULL) return; /* f==NULL must still make a get_measure() call */ charge = ((double) charge_unit) * numticks; bits = c_random(); while (1) { PyCodeStats* cs = PyCodeStats_Get(f->f_code); cs_charge = (float)(cs->st_charge + charge); cs->st_charge = cs_charge; charge_total += charge; if (cs_charge > charge_prelimit && charge_callback) { /* update charge_prelimit */ charge_prelimit = (float)(charge_total * charge_watermark); if (cs_charge > charge_prelimit) { /* still over the up-to-date limit */ cs->st_charge = 0.0f; break; } } if (bits >= 0) return; /* triggers in about 50% of the cases */ bits <<= 1; f = f->f_back; if (!f) return; charge *= charge_parent2; } /* charge limit reached, invoke callback */ { PyObject* r; r = PyObject_CallFunction(charge_callback, "Of", f, cs_charge); if (r == NULL) { PyErr_WriteUnraisable((PyObject*) f); } else { Py_DECREF(r); } } }