📄 _hotshot.c
字号:
{
int tdelta;
#ifdef MS_WIN32
hs_time tv;
hs_time diff;
GETTIMEOFDAY(&tv);
diff = tv - self->prev_timeofday;
tdelta = (int)diff;
#else
struct timeval tv;
GETTIMEOFDAY(&tv);
if (tv.tv_sec == self->prev_timeofday.tv_sec)
tdelta = tv.tv_usec - self->prev_timeofday.tv_usec;
else
tdelta = ((tv.tv_sec - self->prev_timeofday.tv_sec) * 1000000
+ tv.tv_usec);
#endif
self->prev_timeofday = tv;
return tdelta;
}
/* The workhorse: the profiler callback function. */
static int
profiler_callback(ProfilerObject *self, PyFrameObject *frame, int what,
PyObject *arg)
{
int tdelta = -1;
int fileno;
if (self->frametimings)
tdelta = get_tdelta(self);
switch (what) {
case PyTrace_CALL:
fileno = get_fileno(self, frame->f_code);
if (fileno < 0)
return -1;
if (pack_enter(self, fileno, tdelta,
frame->f_code->co_firstlineno) < 0)
return -1;
break;
case PyTrace_RETURN:
if (pack_exit(self, tdelta) < 0)
return -1;
break;
default:
/* should never get here */
break;
}
return 0;
}
/* Alternate callback when we want PyTrace_LINE events */
static int
tracer_callback(ProfilerObject *self, PyFrameObject *frame, int what,
PyObject *arg)
{
int fileno;
switch (what) {
case PyTrace_CALL:
fileno = get_fileno(self, frame->f_code);
if (fileno < 0)
return -1;
return pack_enter(self, fileno,
self->frametimings ? get_tdelta(self) : -1,
frame->f_code->co_firstlineno);
case PyTrace_RETURN:
return pack_exit(self, get_tdelta(self));
case PyTrace_LINE:
if (self->linetimings)
return pack_lineno_tdelta(self, frame->f_lineno, get_tdelta(self));
else
return pack_lineno(self, frame->f_lineno);
default:
/* ignore PyTrace_EXCEPTION */
break;
}
return 0;
}
/* A couple of useful helper functions. */
#ifdef MS_WIN32
static LARGE_INTEGER frequency = {0, 0};
#endif
static unsigned long timeofday_diff = 0;
static unsigned long rusage_diff = 0;
static void
calibrate(void)
{
hs_time tv1, tv2;
#ifdef MS_WIN32
hs_time diff;
QueryPerformanceFrequency(&frequency);
#endif
GETTIMEOFDAY(&tv1);
while (1) {
GETTIMEOFDAY(&tv2);
#ifdef MS_WIN32
diff = tv2 - tv1;
if (diff != 0) {
timeofday_diff = (unsigned long)diff;
break;
}
#else
if (tv1.tv_sec != tv2.tv_sec || tv1.tv_usec != tv2.tv_usec) {
if (tv1.tv_sec == tv2.tv_sec)
timeofday_diff = tv2.tv_usec - tv1.tv_usec;
else
timeofday_diff = (1000000 - tv1.tv_usec) + tv2.tv_usec;
break;
}
#endif
}
#if defined(MS_WIN32) || defined(macintosh)
rusage_diff = -1;
#else
{
struct rusage ru1, ru2;
getrusage(RUSAGE_SELF, &ru1);
while (1) {
getrusage(RUSAGE_SELF, &ru2);
if (ru1.ru_utime.tv_sec != ru2.ru_utime.tv_sec) {
rusage_diff = ((1000000 - ru1.ru_utime.tv_usec)
+ ru2.ru_utime.tv_usec);
break;
}
else if (ru1.ru_utime.tv_usec != ru2.ru_utime.tv_usec) {
rusage_diff = ru2.ru_utime.tv_usec - ru1.ru_utime.tv_usec;
break;
}
else if (ru1.ru_stime.tv_sec != ru2.ru_stime.tv_sec) {
rusage_diff = ((1000000 - ru1.ru_stime.tv_usec)
+ ru2.ru_stime.tv_usec);
break;
}
else if (ru1.ru_stime.tv_usec != ru2.ru_stime.tv_usec) {
rusage_diff = ru2.ru_stime.tv_usec - ru1.ru_stime.tv_usec;
break;
}
}
}
#endif
}
static void
do_start(ProfilerObject *self)
{
self->active = 1;
GETTIMEOFDAY(&self->prev_timeofday);
if (self->lineevents)
PyEval_SetTrace((Py_tracefunc) tracer_callback, (PyObject *)self);
else
PyEval_SetProfile((Py_tracefunc) profiler_callback, (PyObject *)self);
}
static void
do_stop(ProfilerObject *self)
{
if (self->active) {
self->active = 0;
if (self->lineevents)
PyEval_SetTrace(NULL, NULL);
else
PyEval_SetProfile(NULL, NULL);
}
if (self->index > 0) {
/* Best effort to dump out any remaining data. */
flush_data(self);
}
}
static int
is_available(ProfilerObject *self)
{
if (self->active) {
PyErr_SetString(ProfilerError, "profiler already active");
return 0;
}
if (self->logfp == NULL) {
PyErr_SetString(ProfilerError, "profiler already closed");
return 0;
}
return 1;
}
/* Profiler object interface methods. */
static char addinfo__doc__[] =
"addinfo(key, value)\n"
"Insert an ADD_INFO record into the log.";
static PyObject *
profiler_addinfo(ProfilerObject *self, PyObject *args)
{
PyObject *result = NULL;
char *key, *value;
if (PyArg_ParseTuple(args, "ss:addinfo", &key, &value)) {
if (self->logfp == NULL)
PyErr_SetString(ProfilerError, "profiler already closed");
else {
if (pack_add_info(self, key, value) == 0) {
result = Py_None;
Py_INCREF(result);
}
}
}
return result;
}
static char close__doc__[] =
"close()\n"
"Shut down this profiler and close the log files, even if its active.";
static PyObject *
profiler_close(ProfilerObject *self, PyObject *args)
{
PyObject *result = NULL;
if (PyArg_ParseTuple(args, ":close")) {
do_stop(self);
if (self->logfp != NULL) {
fclose(self->logfp);
self->logfp = NULL;
}
Py_INCREF(Py_None);
result = Py_None;
}
return result;
}
static char runcall__doc__[] =
"runcall(callable[, args[, kw]]) -> callable()\n"
"Profile a specific function call, returning the result of that call.";
static PyObject *
profiler_runcall(ProfilerObject *self, PyObject *args)
{
PyObject *result = NULL;
PyObject *callargs = NULL;
PyObject *callkw = NULL;
PyObject *callable;
if (PyArg_ParseTuple(args, "O|OO:runcall",
&callable, &callargs, &callkw)) {
if (is_available(self)) {
do_start(self);
result = PyEval_CallObjectWithKeywords(callable, callargs, callkw);
do_stop(self);
}
}
return result;
}
static char runcode__doc__[] =
"runcode(code, globals[, locals])\n"
"Execute a code object while collecting profile data. If locals is\n"
"omitted, globals is used for the locals as well.";
static PyObject *
profiler_runcode(ProfilerObject *self, PyObject *args)
{
PyObject *result = NULL;
PyCodeObject *code;
PyObject *globals;
PyObject *locals = NULL;
if (PyArg_ParseTuple(args, "O!O!|O:runcode",
&PyCode_Type, &code,
&PyDict_Type, &globals,
&locals)) {
if (is_available(self)) {
if (locals == NULL || locals == Py_None)
locals = globals;
else if (!PyDict_Check(locals)) {
PyErr_SetString(PyExc_TypeError,
"locals must be a dictionary or None");
return NULL;
}
do_start(self);
result = PyEval_EvalCode(code, globals, locals);
do_stop(self);
#if 0
if (!PyErr_Occurred()) {
result = Py_None;
Py_INCREF(result);
}
#endif
}
}
return result;
}
static char start__doc__[] =
"start()\n"
"Install this profiler for the current thread.";
static PyObject *
profiler_start(ProfilerObject *self, PyObject *args)
{
PyObject *result = NULL;
if (PyArg_ParseTuple(args, ":start")) {
if (is_available(self)) {
do_start(self);
result = Py_None;
Py_INCREF(result);
}
}
return result;
}
static char stop__doc__[] =
"stop()\n"
"Remove this profiler from the current thread.";
static PyObject *
profiler_stop(ProfilerObject *self, PyObject *args)
{
PyObject *result = NULL;
if (PyArg_ParseTuple(args, ":stop")) {
if (!self->active)
PyErr_SetString(ProfilerError, "profiler not active");
else {
do_stop(self);
result = Py_None;
Py_INCREF(result);
}
}
return result;
}
/* Python API support. */
static void
profiler_dealloc(ProfilerObject *self)
{
do_stop(self);
if (self->logfp != NULL)
fclose(self->logfp);
Py_XDECREF(self->filemap);
Py_XDECREF(self->logfilename);
PyObject_Del((PyObject *)self);
}
/* Always use METH_VARARGS even though some of these could be METH_NOARGS;
* this allows us to maintain compatibility with Python versions < 2.2
* more easily, requiring only the changes to the dispatcher to be made.
*/
static PyMethodDef profiler_methods[] = {
{"addinfo", (PyCFunction)profiler_addinfo, METH_VARARGS, addinfo__doc__},
{"close", (PyCFunction)profiler_close, METH_VARARGS, close__doc__},
{"runcall", (PyCFunction)profiler_runcall, METH_VARARGS, runcall__doc__},
{"runcode", (PyCFunction)profiler_runcode, METH_VARARGS, runcode__doc__},
{"start", (PyCFunction)profiler_start, METH_VARARGS, start__doc__},
{"stop", (PyCFunction)profiler_stop, METH_VARARGS, stop__doc__},
{NULL, NULL}
};
/* Use a table even though there's only one "simple" member; this allows
* __members__ and therefore dir() to work.
*/
static struct memberlist profiler_members[] = {
{"closed", T_INT, -1, READONLY},
{"frametimings", T_LONG, offsetof(ProfilerObject, linetimings), READONLY},
{"lineevents", T_LONG, offsetof(ProfilerObject, lineevents), READONLY},
{"linetimings", T_LONG, offsetof(ProfilerObject, linetimings), READONLY},
{NULL}
};
static PyObject *
profiler_getattr(ProfilerObject *self, char *name)
{
PyObject *result;
if (strcmp(name, "closed") == 0) {
result = (self->logfp == NULL) ? Py_True : Py_False;
Py_INCREF(result);
}
else {
result = PyMember_Get((char *)self, profiler_members, name);
if (result == NULL) {
PyErr_Clear();
result = Py_FindMethod(profiler_methods, (PyObject *)self, name);
}
}
return result;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -