From 26566195fe41c82e590d27e2e9c0ebc1ccf7485b Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 20 Jul 2014 10:19:51 -0400 Subject: Start implementing coroutine tracing in C tracer, will be hard :( --HG-- branch : c-coroutine --- coverage/tracer.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'coverage/tracer.c') diff --git a/coverage/tracer.c b/coverage/tracer.c index ca8d61c1..bfebf1d4 100644 --- a/coverage/tracer.c +++ b/coverage/tracer.c @@ -66,6 +66,7 @@ typedef struct { /* Python objects manipulated directly by the Collector class. */ PyObject * should_trace; PyObject * warn; + PyObject * coroutine_id_func; PyObject * data; PyObject * should_trace_cache; PyObject * arcs; @@ -138,6 +139,7 @@ CTracer_init(CTracer *self, PyObject *args_unused, PyObject *kwds_unused) self->should_trace = NULL; self->warn = NULL; + self->coroutine_id_func = NULL; self->data = NULL; self->should_trace_cache = NULL; self->arcs = NULL; @@ -171,6 +173,7 @@ CTracer_dealloc(CTracer *self) Py_XDECREF(self->should_trace); Py_XDECREF(self->warn); + Py_XDECREF(self->coroutine_id_func); Py_XDECREF(self->data); Py_XDECREF(self->should_trace_cache); @@ -250,6 +253,18 @@ CTracer_record_pair(CTracer *self, int l1, int l2) return ret; } +/* Get the proper data_stack to use. In Python, defaultdict makes this easier. */ +static int +CTracer_get_data_stack(CTracer *self) +{ + if (self->coroutine_id_func) { + } + else { + } + + return RET_OK; +} + /* * The Trace Function */ @@ -610,6 +625,9 @@ CTracer_members[] = { { "warn", T_OBJECT, offsetof(CTracer, warn), 0, PyDoc_STR("Function for issuing warnings.") }, + { "coroutine_id_func", T_OBJECT, offsetof(CTracer, coroutine_id_func), 0, + PyDoc_STR("Function for determining coroutine context") }, + { "data", T_OBJECT, offsetof(CTracer, data), 0, PyDoc_STR("The raw dictionary of trace data.") }, -- cgit v1.2.1 From a8ace9db7e4ba7fbcf2a068b8f1e52fee5a3624a Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 20 Jul 2014 20:31:12 -0400 Subject: Refactor some C tracer code in prep for data stacks --HG-- branch : c-coroutine --- coverage/tracer.c | 116 +++++++++++++++++++++++++++--------------------------- 1 file changed, 59 insertions(+), 57 deletions(-) (limited to 'coverage/tracer.c') diff --git a/coverage/tracer.c b/coverage/tracer.c index bfebf1d4..3cf8c81d 100644 --- a/coverage/tracer.c +++ b/coverage/tracer.c @@ -54,10 +54,23 @@ frame. */ typedef struct { - PyObject * file_data; /* PyMem_Malloc'ed, a borrowed ref. */ + /* The current file_data dictionary. Borrowed. */ + PyObject * file_data; + + /* The line number of the last line recorded, for tracing arcs. + -1 means there was no previous line, as when entering a code object. + */ int last_line; } DataStackEntry; +/* A data stack is a dynamically allocated vector of DataStackEntry's. */ +typedef struct { + int depth; /* The index of the last-used entry in stack. */ + int alloc; /* number of entries allocated at stack. */ + /* The file data at each level, or NULL if not recording. */ + DataStackEntry * stack; +} DataStack; + /* The CTracer type. */ typedef struct { @@ -87,19 +100,11 @@ typedef struct { the keys are line numbers. In both cases, the value is irrelevant (None). */ - /* The index of the last-used entry in data_stack. */ - int depth; - /* The file data at each level, or NULL if not recording. */ - DataStackEntry * data_stack; - int data_stack_alloc; /* number of entries allocated at data_stack. */ - /* The current file_data dictionary. Borrowed. */ - PyObject * cur_file_data; + DataStack data_stack; - /* The line number of the last line recorded, for tracing arcs. - -1 means there was no previous line, as when entering a code object. - */ - int last_line; + /* The current file's data stack entry, copied from the stack. */ + DataStackEntry cur_entry; /* The parent frame for the last exception event, to fix missing returns. */ PyFrameObject * last_exc_back; @@ -147,17 +152,17 @@ CTracer_init(CTracer *self, PyObject *args_unused, PyObject *kwds_unused) self->started = 0; self->tracing_arcs = 0; - self->depth = -1; - self->data_stack = PyMem_Malloc(STACK_DELTA*sizeof(DataStackEntry)); - if (self->data_stack == NULL) { + self->data_stack.depth = -1; + self->data_stack.stack = PyMem_Malloc(STACK_DELTA*sizeof(DataStackEntry)); + if (self->data_stack.stack == NULL) { STATS( self->stats.errors++; ) PyErr_NoMemory(); return RET_ERROR; } - self->data_stack_alloc = STACK_DELTA; + self->data_stack.alloc = STACK_DELTA; - self->cur_file_data = NULL; - self->last_line = -1; + self->cur_entry.file_data = NULL; + self->cur_entry.last_line = -1; self->last_exc_back = NULL; @@ -177,7 +182,7 @@ CTracer_dealloc(CTracer *self) Py_XDECREF(self->data); Py_XDECREF(self->should_trace_cache); - PyMem_Free(self->data_stack); + PyMem_Free(self->data_stack.stack); Py_TYPE(self)->tp_free((PyObject*)self); } @@ -232,7 +237,7 @@ showlog(int depth, int lineno, PyObject * filename, const char * msg) static const char * what_sym[] = {"CALL", "EXC ", "LINE", "RET "}; #endif -/* Record a pair of integers in self->cur_file_data. */ +/* Record a pair of integers in self->cur_entry.file_data. */ static int CTracer_record_pair(CTracer *self, int l1, int l2) { @@ -240,7 +245,7 @@ CTracer_record_pair(CTracer *self, int l1, int l2) PyObject * t = Py_BuildValue("(ii)", l1, l2); if (t != NULL) { - if (PyDict_SetItem(self->cur_file_data, t, Py_None) < 0) { + if (PyDict_SetItem(self->cur_entry.file_data, t, Py_None) < 0) { STATS( self->stats.errors++; ) ret = RET_ERROR; } @@ -309,16 +314,15 @@ CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unuse we'll need to keep more of the missed frame's state. */ STATS( self->stats.missed_returns++; ) - if (self->depth >= 0) { - if (self->tracing_arcs && self->cur_file_data) { - if (CTracer_record_pair(self, self->last_line, -self->last_exc_firstlineno) < 0) { + if (self->data_stack.depth >= 0) { + if (self->tracing_arcs && self->cur_entry.file_data) { + if (CTracer_record_pair(self, self->cur_entry.last_line, -self->last_exc_firstlineno) < 0) { return RET_ERROR; } } - SHOWLOG(self->depth, frame->f_lineno, frame->f_code->co_filename, "missedreturn"); - self->cur_file_data = self->data_stack[self->depth].file_data; - self->last_line = self->data_stack[self->depth].last_line; - self->depth--; + SHOWLOG(self->data_stack.depth, frame->f_lineno, frame->f_code->co_filename, "missedreturn"); + self->cur_entry = self->data_stack.stack[self->data_stack.depth]; + self->data_stack.depth--; } } self->last_exc_back = NULL; @@ -329,25 +333,24 @@ CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unuse case PyTrace_CALL: /* 0 */ STATS( self->stats.calls++; ) /* Grow the stack. */ - self->depth++; - if (self->depth >= self->data_stack_alloc) { + self->data_stack.depth++; + if (self->data_stack.depth >= self->data_stack.alloc) { STATS( self->stats.stack_reallocs++; ) /* We've outgrown our data_stack array: make it bigger. */ - int bigger = self->data_stack_alloc + STACK_DELTA; - DataStackEntry * bigger_data_stack = PyMem_Realloc(self->data_stack, bigger * sizeof(DataStackEntry)); + int bigger = self->data_stack.alloc + STACK_DELTA; + DataStackEntry * bigger_data_stack = PyMem_Realloc(self->data_stack.stack, bigger * sizeof(DataStackEntry)); if (bigger_data_stack == NULL) { STATS( self->stats.errors++; ) PyErr_NoMemory(); - self->depth--; + self->data_stack.depth--; return RET_ERROR; } - self->data_stack = bigger_data_stack; - self->data_stack_alloc = bigger; + self->data_stack.stack = bigger_data_stack; + self->data_stack.alloc = bigger; } /* Push the current state on the stack. */ - self->data_stack[self->depth].file_data = self->cur_file_data; - self->data_stack[self->depth].last_line = self->last_line; + self->data_stack.stack[self->data_stack.depth] = self->cur_entry; /* Check if we should trace this line. */ filename = frame->f_code->co_filename; @@ -399,50 +402,49 @@ CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unuse return RET_ERROR; } } - self->cur_file_data = file_data; + self->cur_entry.file_data = file_data; /* Make the frame right in case settrace(gettrace()) happens. */ Py_INCREF(self); frame->f_trace = (PyObject*)self; - SHOWLOG(self->depth, frame->f_lineno, filename, "traced"); + SHOWLOG(self->data_stack.depth, frame->f_lineno, filename, "traced"); } else { - self->cur_file_data = NULL; - SHOWLOG(self->depth, frame->f_lineno, filename, "skipped"); + self->cur_entry.file_data = NULL; + SHOWLOG(self->data_stack.depth, frame->f_lineno, filename, "skipped"); } Py_DECREF(tracename); Py_DECREF(disposition); - self->last_line = -1; + self->cur_entry.last_line = -1; break; case PyTrace_RETURN: /* 3 */ STATS( self->stats.returns++; ) /* A near-copy of this code is above in the missing-return handler. */ - if (self->depth >= 0) { - if (self->tracing_arcs && self->cur_file_data) { + if (self->data_stack.depth >= 0) { + if (self->tracing_arcs && self->cur_entry.file_data) { int first = frame->f_code->co_firstlineno; - if (CTracer_record_pair(self, self->last_line, -first) < 0) { + if (CTracer_record_pair(self, self->cur_entry.last_line, -first) < 0) { return RET_ERROR; } } - SHOWLOG(self->depth, frame->f_lineno, frame->f_code->co_filename, "return"); - self->cur_file_data = self->data_stack[self->depth].file_data; - self->last_line = self->data_stack[self->depth].last_line; - self->depth--; + SHOWLOG(self->data_stack.depth, frame->f_lineno, frame->f_code->co_filename, "return"); + self->cur_entry = self->data_stack.stack[self->data_stack.depth]; + self->data_stack.depth--; } break; case PyTrace_LINE: /* 2 */ STATS( self->stats.lines++; ) - if (self->depth >= 0) { - SHOWLOG(self->depth, frame->f_lineno, frame->f_code->co_filename, "line"); - if (self->cur_file_data) { + if (self->data_stack.depth >= 0) { + SHOWLOG(self->data_stack.depth, frame->f_lineno, frame->f_code->co_filename, "line"); + if (self->cur_entry.file_data) { /* We're tracing in this frame: record something. */ if (self->tracing_arcs) { /* Tracing arcs: key is (last_line,this_line). */ - if (CTracer_record_pair(self, self->last_line, frame->f_lineno) < 0) { + if (CTracer_record_pair(self, self->cur_entry.last_line, frame->f_lineno) < 0) { return RET_ERROR; } } @@ -453,7 +455,7 @@ CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unuse STATS( self->stats.errors++; ) return RET_ERROR; } - ret = PyDict_SetItem(self->cur_file_data, this_line, Py_None); + ret = PyDict_SetItem(self->cur_entry.file_data, this_line, Py_None); Py_DECREF(this_line); if (ret < 0) { STATS( self->stats.errors++; ) @@ -461,7 +463,7 @@ CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unuse } } } - self->last_line = frame->f_lineno; + self->cur_entry.last_line = frame->f_lineno; } break; @@ -577,7 +579,7 @@ CTracer_start(CTracer *self, PyObject *args_unused) PyEval_SetTrace((Py_tracefunc)CTracer_trace, (PyObject*)self); self->started = 1; self->tracing_arcs = self->arcs && PyObject_IsTrue(self->arcs); - self->last_line = -1; + self->cur_entry.last_line = -1; /* start() returns a trace function usable with sys.settrace() */ Py_INCREF(self); @@ -609,7 +611,7 @@ CTracer_get_stats(CTracer *self) "new_files", self->stats.new_files, "missed_returns", self->stats.missed_returns, "stack_reallocs", self->stats.stack_reallocs, - "stack_alloc", self->data_stack_alloc, + "stack_alloc", self->data_stack.alloc, "errors", self->stats.errors ); #else -- cgit v1.2.1 From 873b19b457aaf4d2cfac90a1179e4b3581a44bc8 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Fri, 25 Jul 2014 08:00:02 -0600 Subject: Refactor DataStack code into its own functions --HG-- branch : c-coroutine --- coverage/tracer.c | 118 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 79 insertions(+), 39 deletions(-) (limited to 'coverage/tracer.c') diff --git a/coverage/tracer.c b/coverage/tracer.c index 3cf8c81d..28b0a757 100644 --- a/coverage/tracer.c +++ b/coverage/tracer.c @@ -102,6 +102,7 @@ typedef struct { */ DataStack data_stack; + DataStack * pdata_stack; /* The current file's data stack entry, copied from the stack. */ DataStackEntry cur_entry; @@ -125,8 +126,51 @@ typedef struct { #endif /* COLLECT_STATS */ } CTracer; + #define STACK_DELTA 100 +static int +DataStack_init(CTracer *self, DataStack *pdata_stack) +{ + pdata_stack->depth = -1; + pdata_stack->stack = PyMem_Malloc(STACK_DELTA*sizeof(DataStackEntry)); + if (pdata_stack->stack == NULL) { + STATS( self->stats.errors++; ) + PyErr_NoMemory(); + return RET_ERROR; + } + pdata_stack->alloc = STACK_DELTA; + return RET_OK; +} + +static void +DataStack_dealloc(CTracer *self, DataStack *pdata_stack) +{ + PyMem_Free(pdata_stack->stack); +} + +static int +DataStack_grow(CTracer *self, DataStack *pdata_stack) +{ + pdata_stack->depth++; + if (pdata_stack->depth >= pdata_stack->alloc) { + STATS( self->stats.stack_reallocs++; ) + /* We've outgrown our data_stack array: make it bigger. */ + int bigger = pdata_stack->alloc + STACK_DELTA; + DataStackEntry * bigger_data_stack = PyMem_Realloc(pdata_stack->stack, bigger * sizeof(DataStackEntry)); + if (bigger_data_stack == NULL) { + STATS( self->stats.errors++; ) + PyErr_NoMemory(); + pdata_stack->depth--; + return RET_ERROR; + } + pdata_stack->stack = bigger_data_stack; + pdata_stack->alloc = bigger; + } + return RET_OK; +} + + static int CTracer_init(CTracer *self, PyObject *args_unused, PyObject *kwds_unused) { @@ -152,14 +196,10 @@ CTracer_init(CTracer *self, PyObject *args_unused, PyObject *kwds_unused) self->started = 0; self->tracing_arcs = 0; - self->data_stack.depth = -1; - self->data_stack.stack = PyMem_Malloc(STACK_DELTA*sizeof(DataStackEntry)); - if (self->data_stack.stack == NULL) { - STATS( self->stats.errors++; ) - PyErr_NoMemory(); + if (DataStack_init(self, &self->data_stack)) { return RET_ERROR; } - self->data_stack.alloc = STACK_DELTA; + self->pdata_stack = &self->data_stack; self->cur_entry.file_data = NULL; self->cur_entry.last_line = -1; @@ -182,7 +222,7 @@ CTracer_dealloc(CTracer *self) Py_XDECREF(self->data); Py_XDECREF(self->should_trace_cache); - PyMem_Free(self->data_stack.stack); + DataStack_dealloc(self, &self->data_stack); Py_TYPE(self)->tp_free((PyObject*)self); } @@ -258,16 +298,19 @@ CTracer_record_pair(CTracer *self, int l1, int l2) return ret; } -/* Get the proper data_stack to use. In Python, defaultdict makes this easier. */ +/* Set self->pdata_stack to the proper data_stack to use. In Python, defaultdict makes this easier. */ static int -CTracer_get_data_stack(CTracer *self) +CTracer_set_pdata_stack(CTracer *self) { + self->pdata_stack = &self->data_stack; + return RET_OK; +/* if (self->coroutine_id_func) { } else { + return &self->data_stack; } - - return RET_OK; +*/ } /* @@ -314,15 +357,18 @@ CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unuse we'll need to keep more of the missed frame's state. */ STATS( self->stats.missed_returns++; ) - if (self->data_stack.depth >= 0) { + if (CTracer_set_pdata_stack(self)) { + return RET_ERROR; + } + if (self->pdata_stack->depth >= 0) { if (self->tracing_arcs && self->cur_entry.file_data) { if (CTracer_record_pair(self, self->cur_entry.last_line, -self->last_exc_firstlineno) < 0) { return RET_ERROR; } } - SHOWLOG(self->data_stack.depth, frame->f_lineno, frame->f_code->co_filename, "missedreturn"); - self->cur_entry = self->data_stack.stack[self->data_stack.depth]; - self->data_stack.depth--; + SHOWLOG(self->pdata_stack->depth, frame->f_lineno, frame->f_code->co_filename, "missedreturn"); + self->cur_entry = self->pdata_stack->stack[self->pdata_stack->depth]; + self->pdata_stack->depth--; } } self->last_exc_back = NULL; @@ -333,24 +379,15 @@ CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unuse case PyTrace_CALL: /* 0 */ STATS( self->stats.calls++; ) /* Grow the stack. */ - self->data_stack.depth++; - if (self->data_stack.depth >= self->data_stack.alloc) { - STATS( self->stats.stack_reallocs++; ) - /* We've outgrown our data_stack array: make it bigger. */ - int bigger = self->data_stack.alloc + STACK_DELTA; - DataStackEntry * bigger_data_stack = PyMem_Realloc(self->data_stack.stack, bigger * sizeof(DataStackEntry)); - if (bigger_data_stack == NULL) { - STATS( self->stats.errors++; ) - PyErr_NoMemory(); - self->data_stack.depth--; - return RET_ERROR; - } - self->data_stack.stack = bigger_data_stack; - self->data_stack.alloc = bigger; + if (CTracer_set_pdata_stack(self)) { + return RET_ERROR; + } + if (DataStack_grow(self, self->pdata_stack)) { + return RET_ERROR; } /* Push the current state on the stack. */ - self->data_stack.stack[self->data_stack.depth] = self->cur_entry; + self->pdata_stack->stack[self->pdata_stack->depth] = self->cur_entry; /* Check if we should trace this line. */ filename = frame->f_code->co_filename; @@ -406,11 +443,11 @@ CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unuse /* Make the frame right in case settrace(gettrace()) happens. */ Py_INCREF(self); frame->f_trace = (PyObject*)self; - SHOWLOG(self->data_stack.depth, frame->f_lineno, filename, "traced"); + SHOWLOG(self->pdata_stack->depth, frame->f_lineno, filename, "traced"); } else { self->cur_entry.file_data = NULL; - SHOWLOG(self->data_stack.depth, frame->f_lineno, filename, "skipped"); + SHOWLOG(self->pdata_stack->depth, frame->f_lineno, filename, "skipped"); } Py_DECREF(tracename); @@ -422,7 +459,10 @@ CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unuse case PyTrace_RETURN: /* 3 */ STATS( self->stats.returns++; ) /* A near-copy of this code is above in the missing-return handler. */ - if (self->data_stack.depth >= 0) { + if (CTracer_set_pdata_stack(self)) { + return RET_ERROR; + } + if (self->pdata_stack->depth >= 0) { if (self->tracing_arcs && self->cur_entry.file_data) { int first = frame->f_code->co_firstlineno; if (CTracer_record_pair(self, self->cur_entry.last_line, -first) < 0) { @@ -430,16 +470,16 @@ CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unuse } } - SHOWLOG(self->data_stack.depth, frame->f_lineno, frame->f_code->co_filename, "return"); - self->cur_entry = self->data_stack.stack[self->data_stack.depth]; - self->data_stack.depth--; + SHOWLOG(self->pdata_stack->depth, frame->f_lineno, frame->f_code->co_filename, "return"); + self->cur_entry = self->pdata_stack->stack[self->pdata_stack->depth]; + self->pdata_stack->depth--; } break; case PyTrace_LINE: /* 2 */ STATS( self->stats.lines++; ) - if (self->data_stack.depth >= 0) { - SHOWLOG(self->data_stack.depth, frame->f_lineno, frame->f_code->co_filename, "line"); + if (self->pdata_stack->depth >= 0) { + SHOWLOG(self->pdata_stack->depth, frame->f_lineno, frame->f_code->co_filename, "line"); if (self->cur_entry.file_data) { /* We're tracing in this frame: record something. */ if (self->tracing_arcs) { @@ -611,7 +651,7 @@ CTracer_get_stats(CTracer *self) "new_files", self->stats.new_files, "missed_returns", self->stats.missed_returns, "stack_reallocs", self->stats.stack_reallocs, - "stack_alloc", self->data_stack.alloc, + "stack_alloc", self->pdata_stack->alloc, "errors", self->stats.errors ); #else -- cgit v1.2.1 From 7f041a2e34847a3e871d4968decfe2a4231a7498 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 26 Jul 2014 15:28:23 -0600 Subject: Finish implementation of coroutine_id_func in C tracer, but it doesn't make gevent better. --HG-- branch : c-coroutine --- coverage/tracer.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 77 insertions(+), 15 deletions(-) (limited to 'coverage/tracer.c') diff --git a/coverage/tracer.c b/coverage/tracer.c index 28b0a757..f2d0e628 100644 --- a/coverage/tracer.c +++ b/coverage/tracer.c @@ -30,6 +30,7 @@ #define MyText_AS_BYTES(o) PyUnicode_AsASCIIString(o) #define MyText_AS_STRING(o) PyBytes_AS_STRING(o) #define MyInt_FromLong(l) PyLong_FromLong(l) +#define MyInt_AsLong(o) PyLong_AsLong(o) #define MyType_HEAD_INIT PyVarObject_HEAD_INIT(NULL, 0) @@ -40,6 +41,7 @@ #define MyText_AS_BYTES(o) (Py_INCREF(o), o) #define MyText_AS_STRING(o) PyString_AS_STRING(o) #define MyInt_FromLong(l) PyInt_FromLong(l) +#define MyInt_AsLong(o) PyInt_AsLong(o) #define MyType_HEAD_INIT PyObject_HEAD_INIT(NULL) 0, @@ -101,7 +103,12 @@ typedef struct { (None). */ - DataStack data_stack; + DataStack data_stack; /* Used if we aren't doing coroutines. */ + PyObject * data_stack_index; /* Used if we are doing coroutines. */ + DataStack * data_stacks; + int data_stacks_alloc; + int data_stacks_used; + DataStack * pdata_stack; /* The current file's data stack entry, copied from the stack. */ @@ -133,13 +140,8 @@ static int DataStack_init(CTracer *self, DataStack *pdata_stack) { pdata_stack->depth = -1; - pdata_stack->stack = PyMem_Malloc(STACK_DELTA*sizeof(DataStackEntry)); - if (pdata_stack->stack == NULL) { - STATS( self->stats.errors++; ) - PyErr_NoMemory(); - return RET_ERROR; - } - pdata_stack->alloc = STACK_DELTA; + pdata_stack->stack = NULL; + pdata_stack->alloc = 0; return RET_OK; } @@ -199,6 +201,16 @@ CTracer_init(CTracer *self, PyObject *args_unused, PyObject *kwds_unused) if (DataStack_init(self, &self->data_stack)) { return RET_ERROR; } + self->data_stack_index = PyDict_New(); + if (self->data_stack_index == NULL) { + STATS( self->stats.errors++; ) + return RET_ERROR; + } + + self->data_stacks = NULL; + self->data_stacks_alloc = 0; + self->data_stacks_used = 0; + self->pdata_stack = &self->data_stack; self->cur_entry.file_data = NULL; @@ -223,6 +235,14 @@ CTracer_dealloc(CTracer *self) Py_XDECREF(self->should_trace_cache); DataStack_dealloc(self, &self->data_stack); + if (self->data_stacks) { + for (int i = 0; i < self->data_stacks_used; i++) { + DataStack_dealloc(self, self->data_stacks + i); + } + PyMem_Free(self->data_stacks); + } + + Py_XDECREF(self->data_stack_index); Py_TYPE(self)->tp_free((PyObject*)self); } @@ -298,19 +318,61 @@ CTracer_record_pair(CTracer *self, int l1, int l2) return ret; } -/* Set self->pdata_stack to the proper data_stack to use. In Python, defaultdict makes this easier. */ +/* Set self->pdata_stack to the proper data_stack to use. */ static int CTracer_set_pdata_stack(CTracer *self) { - self->pdata_stack = &self->data_stack; - return RET_OK; -/* - if (self->coroutine_id_func) { + if (self->coroutine_id_func != Py_None) { + PyObject * co_obj = NULL; + PyObject * stack_index = NULL; + long the_index = 0; + + co_obj = PyObject_CallObject(self->coroutine_id_func, NULL); + if (co_obj == NULL) { + return RET_ERROR; + } + stack_index = PyDict_GetItem(self->data_stack_index, co_obj); + if (stack_index == NULL) { + /* A new coroutine object. Make a new data stack. */ + the_index = self->data_stacks_used; + stack_index = MyInt_FromLong(the_index); + if (PyDict_SetItem(self->data_stack_index, co_obj, stack_index) < 0) { + /* TODO */ + Py_XDECREF(co_obj); + Py_XDECREF(stack_index); + return RET_ERROR; + } + self->data_stacks_used++; + if (self->data_stacks_used >= self->data_stacks_alloc) { + int bigger = self->data_stacks_alloc + 10; + DataStack * bigger_stacks = PyMem_Realloc(self->data_stacks, bigger * sizeof(DataStack)); + if (bigger_stacks == NULL) { + STATS( self->stats.errors++; ) + PyErr_NoMemory(); + Py_XDECREF(co_obj); + Py_XDECREF(stack_index); + return RET_ERROR; + } + self->data_stacks = bigger_stacks; + self->data_stacks_alloc = bigger; + } + DataStack_init(self, &self->data_stacks[the_index]); + } + else { + Py_INCREF(stack_index); + the_index = MyInt_AsLong(stack_index); + } + + self->pdata_stack = &self->data_stacks[the_index]; + + Py_XDECREF(co_obj); + Py_XDECREF(stack_index); } else { - return &self->data_stack; + self->pdata_stack = &self->data_stack; } -*/ + + return RET_OK; } /* -- cgit v1.2.1 From b33bba1f032530c7f5d4e1aee43b15b84239b816 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 26 Jul 2014 15:36:22 -0600 Subject: Remove a TODO --HG-- branch : c-coroutine --- coverage/tracer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'coverage/tracer.c') diff --git a/coverage/tracer.c b/coverage/tracer.c index f2d0e628..3131d7df 100644 --- a/coverage/tracer.c +++ b/coverage/tracer.c @@ -337,7 +337,7 @@ CTracer_set_pdata_stack(CTracer *self) the_index = self->data_stacks_used; stack_index = MyInt_FromLong(the_index); if (PyDict_SetItem(self->data_stack_index, co_obj, stack_index) < 0) { - /* TODO */ + STATS( self->stats.errors++; ) Py_XDECREF(co_obj); Py_XDECREF(stack_index); return RET_ERROR; -- cgit v1.2.1 From 0891e02eb490494ee40a7f840e4ab9fd6b3d2d7b Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 6 Sep 2014 14:24:15 -0400 Subject: Move dispositions closer to useful plugins --- coverage/tracer.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'coverage/tracer.c') diff --git a/coverage/tracer.c b/coverage/tracer.c index ca8d61c1..c0066046 100644 --- a/coverage/tracer.c +++ b/coverage/tracer.c @@ -260,6 +260,7 @@ CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unuse PyObject * filename = NULL; PyObject * tracename = NULL; PyObject * disposition = NULL; + PyObject * disp_trace = NULL; #if WHAT_LOG || TRACE_LOG PyObject * ascii = NULL; #endif @@ -358,13 +359,28 @@ CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unuse Py_INCREF(disposition); } - /* If tracename is a string, then we're supposed to trace. */ - tracename = PyObject_GetAttrString(disposition, "filename"); - if (tracename == NULL) { + disp_trace = PyObject_GetAttrString(disposition, "trace"); + if (disp_trace == NULL) { STATS( self->stats.errors++; ) Py_DECREF(disposition); return RET_ERROR; } + + tracename = Py_None; + Py_INCREF(tracename); + + if (disp_trace == Py_True) { + /* If tracename is a string, then we're supposed to trace. */ + tracename = PyObject_GetAttrString(disposition, "source_filename"); + if (tracename == NULL) { + STATS( self->stats.errors++; ) + Py_DECREF(disposition); + Py_DECREF(disp_trace); + return RET_ERROR; + } + } + Py_DECREF(disp_trace); + if (MyText_Check(tracename)) { PyObject * file_data = PyDict_GetItem(self->data, tracename); if (file_data == NULL) { -- cgit v1.2.1 From 941eeb588459098a85266b4c5d176d6deed2eb53 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 14 Sep 2014 16:44:21 -0400 Subject: Progress on plugins --- coverage/tracer.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'coverage/tracer.c') diff --git a/coverage/tracer.c b/coverage/tracer.c index c0066046..5370fef1 100644 --- a/coverage/tracer.c +++ b/coverage/tracer.c @@ -67,6 +67,7 @@ typedef struct { PyObject * should_trace; PyObject * warn; PyObject * data; + PyObject * plugin_data; PyObject * should_trace_cache; PyObject * arcs; @@ -139,6 +140,7 @@ CTracer_init(CTracer *self, PyObject *args_unused, PyObject *kwds_unused) self->should_trace = NULL; self->warn = NULL; self->data = NULL; + self->plugin_data = NULL; self->should_trace_cache = NULL; self->arcs = NULL; @@ -172,6 +174,7 @@ CTracer_dealloc(CTracer *self) Py_XDECREF(self->should_trace); Py_XDECREF(self->warn); Py_XDECREF(self->data); + Py_XDECREF(self->plugin_data); Py_XDECREF(self->should_trace_cache); PyMem_Free(self->data_stack); @@ -383,6 +386,9 @@ CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unuse if (MyText_Check(tracename)) { PyObject * file_data = PyDict_GetItem(self->data, tracename); + PyObject * disp_plugin = NULL; + PyObject * disp_plugin_name = NULL; + if (file_data == NULL) { file_data = PyDict_New(); if (file_data == NULL) { @@ -399,6 +405,34 @@ CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unuse Py_DECREF(disposition); return RET_ERROR; } + + if (self->plugin_data != NULL) { + /* If the disposition mentions a plugin, record that. */ + disp_plugin = PyObject_GetAttrString(disposition, "plugin"); + if (disp_plugin == NULL) { + STATS( self->stats.errors++; ) + Py_DECREF(tracename); + Py_DECREF(disposition); + return RET_ERROR; + } + if (disp_plugin != Py_None) { + disp_plugin_name = PyObject_GetAttrString(disp_plugin, "__name__"); + Py_DECREF(disp_plugin); + if (disp_plugin_name == NULL) { + STATS( self->stats.errors++; ) + Py_DECREF(tracename); + Py_DECREF(disposition); + return RET_ERROR; + } + ret = PyDict_SetItem(self->plugin_data, tracename, disp_plugin_name); + Py_DECREF(disp_plugin_name); + if (ret < 0) { + Py_DECREF(tracename); + Py_DECREF(disposition); + return RET_ERROR; + } + } + } } self->cur_file_data = file_data; /* Make the frame right in case settrace(gettrace()) happens. */ @@ -629,6 +663,9 @@ CTracer_members[] = { { "data", T_OBJECT, offsetof(CTracer, data), 0, PyDoc_STR("The raw dictionary of trace data.") }, + { "plugin_data", T_OBJECT, offsetof(CTracer, plugin_data), 0, + PyDoc_STR("Mapping from filename to plugin name.") }, + { "should_trace_cache", T_OBJECT, offsetof(CTracer, should_trace_cache), 0, PyDoc_STR("Dictionary caching should_trace results.") }, -- cgit v1.2.1 From 4d56a2afeed4da640b47b6a881de494cd3465561 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Wed, 17 Sep 2014 21:58:27 -0400 Subject: It's always worthwhile to get rid of trailing spaces --- coverage/tracer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'coverage/tracer.c') diff --git a/coverage/tracer.c b/coverage/tracer.c index cb242219..a6ade3f6 100644 --- a/coverage/tracer.c +++ b/coverage/tracer.c @@ -365,7 +365,7 @@ CTracer_set_pdata_stack(CTracer *self) Py_INCREF(stack_index); the_index = MyInt_AsLong(stack_index); } - + self->pdata_stack = &self->data_stacks[the_index]; Py_XDECREF(co_obj); -- cgit v1.2.1 From 0f28946543966ae1265ec2345c7eeb3b31186136 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Fri, 19 Sep 2014 10:52:07 -0400 Subject: Be struct about C declaration rules. Travis cares... --- coverage/tracer.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'coverage/tracer.c') diff --git a/coverage/tracer.c b/coverage/tracer.c index a6ade3f6..5bf5c462 100644 --- a/coverage/tracer.c +++ b/coverage/tracer.c @@ -226,6 +226,8 @@ CTracer_init(CTracer *self, PyObject *args_unused, PyObject *kwds_unused) static void CTracer_dealloc(CTracer *self) { + int i; + if (self->started) { PyEval_SetTrace(NULL, NULL); } @@ -239,7 +241,7 @@ CTracer_dealloc(CTracer *self) DataStack_dealloc(self, &self->data_stack); if (self->data_stacks) { - for (int i = 0; i < self->data_stacks_used; i++) { + for (i = 0; i < self->data_stacks_used; i++) { DataStack_dealloc(self, self->data_stacks + i); } PyMem_Free(self->data_stacks); -- cgit v1.2.1