diff -r a290885ec0da Doc/c-api/long.rst --- a/Doc/c-api/long.rst Sun May 10 21:20:01 2015 -0400 +++ b/Doc/c-api/long.rst Mon May 11 16:46:42 2015 +0300 @@ -260,3 +260,10 @@ All integers are implemented as "long" i If *pylong* cannot be converted, an :exc:`OverflowError` will be raised. This is only assured to produce a usable :c:type:`void` pointer for values created with :c:func:`PyLong_FromVoidPtr`. + +.. c:function:: int PyLong_ClearFreeList() + + Clear the integer free list. Return the number of items that could not + be freed. + + .. versionadded:: 3.5 diff -r a290885ec0da Include/longobject.h --- a/Include/longobject.h Sun May 10 21:20:01 2015 -0400 +++ b/Include/longobject.h Mon May 11 16:46:42 2015 +0300 @@ -198,6 +198,13 @@ PyAPI_FUNC(int) _PyLong_FormatAdvancedWr PyAPI_FUNC(unsigned long) PyOS_strtoul(const char *, char **, int); PyAPI_FUNC(long) PyOS_strtol(const char *, char **, int); +/* free list api */ +PyAPI_FUNC(int) PyLong_ClearFreeList(void); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(void) _PyLong_DebugMallocStats(FILE* out); +#endif + #ifdef __cplusplus } #endif diff -r a290885ec0da Modules/gcmodule.c --- a/Modules/gcmodule.c Sun May 10 21:20:01 2015 -0400 +++ b/Modules/gcmodule.c Mon May 11 16:46:42 2015 +0300 @@ -892,6 +892,7 @@ clear_freelists(void) (void)PyList_ClearFreeList(); (void)PyDict_ClearFreeList(); (void)PySet_ClearFreeList(); + (void)PyLong_ClearFreeList(); } /* This is the main function. Read this to understand how the diff -r a290885ec0da Objects/longobject.c --- a/Objects/longobject.c Sun May 10 21:20:01 2015 -0400 +++ b/Objects/longobject.c Mon May 11 16:46:42 2015 +0300 @@ -70,6 +70,17 @@ maybe_small_long(PyLongObject *v) #define maybe_small_long(val) (val) #endif +/* Speed optimization to avoid frequent malloc/free of small ints */ +#ifndef PyLong_MAXFREELIST +# define PyLong_MAXFREELIST 100 +#endif + +static PyLongObject *free_list = NULL; +static int numfree = 0; +#ifdef COUNT_ALLOCS +Py_ssize_t fast_int_allocs; +#endif + /* If a freshly-allocated int is already shared, it must be a small integer, so negating it must go to PyLong_FromLong */ Py_LOCAL_INLINE(void) @@ -183,21 +194,30 @@ PyLongObject * _PyLong_New(Py_ssize_t size) { PyLongObject *result; - /* Number of bytes needed is: offsetof(PyLongObject, ob_digit) + - sizeof(digit)*size. Previous incarnations of this code used - sizeof(PyVarObject) instead of the offsetof, but this risks being - incorrect in the presence of padding between the PyVarObject header - and the digits. */ - if (size > (Py_ssize_t)MAX_LONG_DIGITS) { - PyErr_SetString(PyExc_OverflowError, - "too many digits in integer"); - return NULL; - } - result = PyObject_MALLOC(offsetof(PyLongObject, ob_digit) + - size*sizeof(digit)); - if (!result) { - PyErr_NoMemory(); - return NULL; + if (size == 1 && (result = free_list) != NULL) { + free_list = (PyLongObject *)Py_TYPE(result); + numfree--; +#ifdef COUNT_ALLOCS + fast_int_allocs++; +#endif + } + else { + /* Number of bytes needed is: offsetof(PyLongObject, ob_digit) + + sizeof(digit)*size. Previous incarnations of this code used + sizeof(PyVarObject) instead of the offsetof, but this risks being + incorrect in the presence of padding between the PyVarObject header + and the digits. */ + if (size > (Py_ssize_t)MAX_LONG_DIGITS) { + PyErr_SetString(PyExc_OverflowError, + "too many digits in integer"); + return NULL; + } + result = PyObject_MALLOC(offsetof(PyLongObject, ob_digit) + + size*sizeof(digit)); + if (!result) { + PyErr_NoMemory(); + return NULL; + } } return (PyLongObject*)PyObject_INIT_VAR(result, &PyLong_Type, size); } @@ -249,7 +269,7 @@ PyLong_FromLong(long ival) } /* Fast path for single-digit ints */ - if (!(abs_ival >> PyLong_SHIFT)) { + if (abs_ival < (1UL << PyLong_SHIFT)) { v = _PyLong_New(1); if (v) { Py_SIZE(v) = sign; @@ -259,9 +279,9 @@ PyLong_FromLong(long ival) return (PyObject*)v; } -#if PyLong_SHIFT==15 +#if 2*PyLong_SHIFT < 8*PY_LONG_SIZE /* 2 digits */ - if (!(abs_ival >> 2*PyLong_SHIFT)) { + if (abs_ival < (1UL << 2*PyLong_SHIFT)) { v = _PyLong_New(2); if (v) { Py_SIZE(v) = 2*sign; @@ -2719,6 +2739,16 @@ PyLong_AsDouble(PyObject *v) static void long_dealloc(PyObject *v) { + if (PyLong_CheckExact(v)) { + Py_ssize_t size = Py_SIZE(v); + if ((size == 1 || size == -1) && + numfree < PyLong_MAXFREELIST) { + Py_TYPE(v) = (PyTypeObject *)free_list; + free_list = (PyLongObject *)v; + numfree++; + return; + } + } Py_TYPE(v)->tp_free(v); } @@ -5113,15 +5143,42 @@ int void PyLong_Fini(void) { + (void)PyLong_ClearFreeList(); /* Integers are currently statically allocated. Py_DECREF is not needed, but Python must forget about the reference or multiple reinitializations will fail. */ #if NSMALLNEGINTS + NSMALLPOSINTS > 0 - int i; - PyLongObject *v = small_ints; - for (i = 0; i < NSMALLNEGINTS + NSMALLPOSINTS; i++, v++) { - _Py_DEC_REFTOTAL; - _Py_ForgetReference((PyObject*)v); + { + int i; + PyLongObject *v = small_ints; + for (i = 0; i < NSMALLNEGINTS + NSMALLPOSINTS; i++, v++) { + _Py_DEC_REFTOTAL; + _Py_ForgetReference((PyObject*)v); + } } #endif } + +int +PyLong_ClearFreeList(void) +{ + PyLongObject *f = free_list, *next; + int freelist_size = numfree; + free_list = NULL; + numfree = 0; + while (f) { + next = (PyLongObject*) Py_TYPE(f); + PyObject_FREE(f); + f = next; + } + return freelist_size; +} + +/* Print summary info about the state of the optimized allocator */ +void +_PyLong_DebugMallocStats(FILE *out) +{ + _PyDebugAllocatorStats(out, + "free PyLongObject", + numfree, _PyObject_VAR_SIZE(&PyLong_Type, 1)); +} diff -r a290885ec0da Objects/object.c --- a/Objects/object.c Sun May 10 21:20:01 2015 -0400 +++ b/Objects/object.c Mon May 11 16:46:42 2015 +0300 @@ -103,7 +103,7 @@ static PyTypeObject *type_list; once the last object is deallocated. */ static int unlist_types_without_objects; extern Py_ssize_t tuple_zero_allocs, fast_tuple_allocs; -extern Py_ssize_t quick_int_allocs, quick_neg_int_allocs; +extern Py_ssize_t quick_int_allocs, quick_neg_int_allocs, fast_int_allocs; extern Py_ssize_t null_strings, one_strings; void dump_counts(FILE* f) @@ -119,9 +119,10 @@ dump_counts(FILE* f) fprintf(f, "fast tuple allocs: %" PY_FORMAT_SIZE_T "d, " "empty: %" PY_FORMAT_SIZE_T "d\n", fast_tuple_allocs, tuple_zero_allocs); - fprintf(f, "fast int allocs: pos: %" PY_FORMAT_SIZE_T "d, " - "neg: %" PY_FORMAT_SIZE_T "d\n", - quick_int_allocs, quick_neg_int_allocs); + fprintf(f, "fast int allocs: %" PY_FORMAT_SIZE_T "d, " + "small pos: %" PY_FORMAT_SIZE_T "d, " + "small neg: %" PY_FORMAT_SIZE_T "d\n", + fast_int_allocs, quick_int_allocs, quick_neg_int_allocs); fprintf(f, "null strings: %" PY_FORMAT_SIZE_T "d, " "1-strings: %" PY_FORMAT_SIZE_T "d\n", null_strings, one_strings); @@ -1838,6 +1839,7 @@ void _PyFloat_DebugMallocStats(out); _PyFrame_DebugMallocStats(out); _PyList_DebugMallocStats(out); + _PyLong_DebugMallocStats(out); _PyMethod_DebugMallocStats(out); _PyTuple_DebugMallocStats(out); }