diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2021-10-14 20:03:20 -0400 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2021-10-14 20:03:20 -0400 |
commit | ec9070f1387e9713236f3b8c47447df44447df23 (patch) | |
tree | 7e88dde62527a0f9a8595e97776346b5f63d5b58 /coverage/ctracer/tracer.c | |
parent | a1101953f253754514e74d3d648c4d4ef9c0ad6c (diff) | |
download | python-coveragepy-git-ec9070f1387e9713236f3b8c47447df44447df23.tar.gz |
perf: reduce the overhead of recording branches
Diffstat (limited to 'coverage/ctracer/tracer.c')
-rw-r--r-- | coverage/ctracer/tracer.c | 30 |
1 files changed, 23 insertions, 7 deletions
diff --git a/coverage/ctracer/tracer.c b/coverage/ctracer/tracer.c index 00d9f106..cf5bebb1 100644 --- a/coverage/ctracer/tracer.c +++ b/coverage/ctracer/tracer.c @@ -174,22 +174,38 @@ static int CTracer_record_pair(CTracer *self, int l1, int l2) { int ret = RET_ERROR; - - PyObject * t = NULL; - - t = Py_BuildValue("(ii)", l1, l2); - if (t == NULL) { + PyObject * packed_obj = NULL; + uint64 packed = 0; + + // Conceptually, data is a set of tuples (l1, l2), but that literally + // making a set of tuples would require us to construct a tuple just to + // see if we'd already recorded an arc. On many-times-executed code, + // that would mean we construct a tuple, find the tuple is already in the + // set, then discard the tuple. We can avoid that overhead by packing + // the two line numbers into one integer instead. + // See collector.py:flush_data for the Python code that unpacks this. + if (l1 < 0) { + packed |= (1LL << 40); + l1 = -l1; + } + if (l2 < 0) { + packed |= (1LL << 41); + l2 = -l2; + } + packed |= (((uint64)l2) << 20) + (uint64)l1; + packed_obj = PyLong_FromUnsignedLongLong(packed); + if (packed_obj == NULL) { goto error; } - if (PySet_Add(self->pcur_entry->file_data, t) < 0) { + if (PySet_Add(self->pcur_entry->file_data, packed_obj) < 0) { goto error; } ret = RET_OK; error: - Py_XDECREF(t); + Py_XDECREF(packed_obj); return ret; } |