Commit 02c0a74c authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #1178 from undingen/perf_refcounting

add tuple free list and don't update boxed frame on exit when it's not used
parents 8b004563 fd83f41a
...@@ -185,7 +185,6 @@ public: ...@@ -185,7 +185,6 @@ public:
} }
static int clear(Box* self) noexcept { static int clear(Box* self) noexcept {
BoxedFrame* o = static_cast<BoxedFrame*>(self); BoxedFrame* o = static_cast<BoxedFrame*>(self);
assert(o->hasExited());
Py_CLEAR(o->_back); Py_CLEAR(o->_back);
Py_CLEAR(o->_code); Py_CLEAR(o->_code);
Py_CLEAR(o->_globals); Py_CLEAR(o->_globals);
...@@ -264,7 +263,9 @@ extern "C" void deinitFrame(FrameInfo* frame_info) { ...@@ -264,7 +263,9 @@ extern "C" void deinitFrame(FrameInfo* frame_info) {
cur_thread_state.frame_info = frame_info->back; cur_thread_state.frame_info = frame_info->back;
BoxedFrame* frame = frame_info->frame_obj; BoxedFrame* frame = frame_info->frame_obj;
if (frame) { if (frame) {
frame->handleFrameExit(); // we don't have to call handleFrameExit() if are the only owner because we will clear it in the next line..
if (frame->ob_refcnt > 1)
frame->handleFrameExit();
Py_CLEAR(frame_info->frame_obj); Py_CLEAR(frame_info->frame_obj);
} }
......
...@@ -27,6 +27,11 @@ ...@@ -27,6 +27,11 @@
namespace pyston { namespace pyston {
#if PyTuple_MAXSAVESIZE > 0
BoxedTuple* BoxedTuple::free_list[PyTuple_MAXSAVESIZE];
int BoxedTuple::numfree[PyTuple_MAXSAVESIZE];
#endif
extern "C" Box* createTuple(int64_t nelts, Box** elts) { extern "C" Box* createTuple(int64_t nelts, Box** elts) {
return BoxedTuple::create(nelts, elts); return BoxedTuple::create(nelts, elts);
} }
...@@ -725,7 +730,22 @@ extern "C" void _PyTuple_MaybeUntrack(PyObject* op) noexcept { ...@@ -725,7 +730,22 @@ extern "C" void _PyTuple_MaybeUntrack(PyObject* op) noexcept {
} }
extern "C" int PyTuple_ClearFreeList() noexcept { extern "C" int PyTuple_ClearFreeList() noexcept {
return 0; // number of entries cleared int freelist_size = 0;
#if PyTuple_MAXSAVESIZE > 0
int i;
for (i = 1; i < PyTuple_MAXSAVESIZE; i++) {
PyTupleObject* p = (PyTupleObject*)BoxedTuple::free_list[i];
freelist_size += BoxedTuple::numfree[i];
BoxedTuple::free_list[i] = NULL;
BoxedTuple::numfree[i] = 0;
while (p) {
PyTupleObject* q = p;
p = (PyTupleObject*)(p->ob_item[0]);
PyObject_GC_Del(q);
}
}
#endif
return freelist_size;
} }
void setupTuple() { void setupTuple() {
......
...@@ -3780,7 +3780,7 @@ void HiddenClass::dump() noexcept { ...@@ -3780,7 +3780,7 @@ void HiddenClass::dump() noexcept {
} }
} }
static void tupledealloc(PyTupleObject* op) noexcept { void BoxedTuple::dealloc(PyTupleObject* op) noexcept {
Py_ssize_t i; Py_ssize_t i;
Py_ssize_t len = Py_SIZE(op); Py_ssize_t len = Py_SIZE(op);
PyObject_GC_UnTrack(op); PyObject_GC_UnTrack(op);
...@@ -3789,10 +3789,11 @@ static void tupledealloc(PyTupleObject* op) noexcept { ...@@ -3789,10 +3789,11 @@ static void tupledealloc(PyTupleObject* op) noexcept {
while (--i >= 0) while (--i >= 0)
Py_XDECREF(op->ob_item[i]); Py_XDECREF(op->ob_item[i]);
#if PyTuple_MAXSAVESIZE > 0 #if PyTuple_MAXSAVESIZE > 0
if (len < PyTuple_MAXSAVESIZE && numfree[len] < PyTuple_MAXFREELIST && Py_TYPE(op) == &PyTuple_Type) { if (likely(len < PyTuple_MAXSAVESIZE && BoxedTuple::numfree[len] < PyTuple_MAXFREELIST
&& ((BoxedTuple*)op)->cls == tuple_cls)) {
op->ob_item[0] = (PyObject*)free_list[len]; op->ob_item[0] = (PyObject*)free_list[len];
numfree[len]++; numfree[len]++;
free_list[len] = op; free_list[len] = (BoxedTuple*)op;
goto done; /* return */ goto done; /* return */
} }
#endif #endif
...@@ -4247,7 +4248,7 @@ void setupRuntime() { ...@@ -4247,7 +4248,7 @@ void setupRuntime() {
// Not sure why CPython defines sizeof(PyTupleObject) to include one element, // Not sure why CPython defines sizeof(PyTupleObject) to include one element,
// but we copy that, which means we have to subtract that extra pointer to get the tp_basicsize: // but we copy that, which means we have to subtract that extra pointer to get the tp_basicsize:
tuple_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedTuple) - sizeof(Box*), false, "tuple", true, tuple_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedTuple) - sizeof(Box*), false, "tuple", true,
(destructor)tupledealloc, NULL, true, (traverseproc)tupletraverse, NOCLEAR); (destructor)BoxedTuple::dealloc, NULL, true, (traverseproc)tupletraverse, NOCLEAR);
tuple_cls->tp_flags |= Py_TPFLAGS_TUPLE_SUBCLASS; tuple_cls->tp_flags |= Py_TPFLAGS_TUPLE_SUBCLASS;
tuple_cls->tp_itemsize = sizeof(Box*); tuple_cls->tp_itemsize = sizeof(Box*);
......
...@@ -695,7 +695,16 @@ static_assert(offsetof(BoxedList, elts) == offsetof(PyListObject, ob_item), ""); ...@@ -695,7 +695,16 @@ static_assert(offsetof(BoxedList, elts) == offsetof(PyListObject, ob_item), "");
static_assert(offsetof(GCdArray, elts) == 0, ""); static_assert(offsetof(GCdArray, elts) == 0, "");
static_assert(offsetof(BoxedList, capacity) == offsetof(PyListObject, allocated), ""); static_assert(offsetof(BoxedList, capacity) == offsetof(PyListObject, allocated), "");
#define PyTuple_MAXSAVESIZE 20 /* Largest tuple to save on free list */
#define PyTuple_MAXFREELIST 2000 /* Maximum number of tuples of each size to save */
extern "C" int PyTuple_ClearFreeList() noexcept;
class BoxedTuple : public BoxVar { class BoxedTuple : public BoxVar {
private:
#if PyTuple_MAXSAVESIZE > 0
static BoxedTuple* free_list[PyTuple_MAXSAVESIZE];
static int numfree[PyTuple_MAXSAVESIZE];
#endif
public: public:
static BoxedTuple* create(int64_t size) { static BoxedTuple* create(int64_t size) {
if (size == 0) { if (size == 0) {
...@@ -834,7 +843,7 @@ public: ...@@ -834,7 +843,7 @@ public:
return BoxVar::operator new(size, cls, nitems); return BoxVar::operator new(size, cls, nitems);
} }
void* operator new(size_t size, size_t nitems) __attribute__((visibility("default"))) { void* operator new(size_t /*size*/, size_t nitems) __attribute__((visibility("default"))) {
ALLOC_STATS_VAR(tuple_cls) ALLOC_STATS_VAR(tuple_cls)
assert(tuple_cls->tp_alloc == PyType_GenericAlloc); assert(tuple_cls->tp_alloc == PyType_GenericAlloc);
...@@ -843,11 +852,31 @@ public: ...@@ -843,11 +852,31 @@ public:
assert(tuple_cls->is_pyston_class); assert(tuple_cls->is_pyston_class);
assert(tuple_cls->attrs_offset == 0); assert(tuple_cls->attrs_offset == 0);
BoxVar* rtn = static_cast<BoxVar*>(PyObject_GC_NewVar(BoxedTuple, &PyTuple_Type, nitems)); BoxedTuple* op = NULL;
assert(rtn); #if PyTuple_MAXSAVESIZE > 0
_PyObject_GC_TRACK(rtn); if (likely(nitems < PyTuple_MAXSAVESIZE && (op = free_list[nitems]) != NULL)) {
free_list[nitems] = (BoxedTuple*)op->elts[0];
return rtn; numfree[nitems]--;
/* Inline PyObject_InitVar */
#ifdef Py_TRACE_REFS
Py_SIZE(op) = nitems;
Py_TYPE(op) = &PyTuple_Type;
#endif
_Py_NewReference((PyObject*)op);
} else
#endif
{
Py_ssize_t nbytes = nitems * sizeof(PyObject*);
/* Check for overflow */
if (unlikely(nbytes / sizeof(PyObject*) != (size_t)nitems
|| (nbytes > PY_SSIZE_T_MAX - sizeof(PyTupleObject) - sizeof(PyObject*)))) {
return PyErr_NoMemory();
}
op = PyObject_GC_NewVar(BoxedTuple, &PyTuple_Type, nitems);
}
_PyObject_GC_TRACK(op);
return (PyObject*)op;
} }
private: private:
...@@ -871,6 +900,9 @@ public: ...@@ -871,6 +900,9 @@ public:
Box* elts[0]; Box* elts[0];
Box* _elts[1]; Box* _elts[1];
}; };
static void dealloc(PyTupleObject* op) noexcept;
friend int PyTuple_ClearFreeList() noexcept;
}; };
static_assert(sizeof(BoxedTuple) == sizeof(PyTupleObject), ""); static_assert(sizeof(BoxedTuple) == sizeof(PyTupleObject), "");
static_assert(offsetof(BoxedTuple, ob_size) == offsetof(PyTupleObject, ob_size), ""); static_assert(offsetof(BoxedTuple, ob_size) == offsetof(PyTupleObject, ob_size), "");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment