[Python-Dev] Time for the yearly list.append() panic
Tim Peters
tim.one@home.com
Fri, 25 May 2001 15:06:16 -0400
c.l.py has rediscovered the quadratic-time worst-case behavior of list.append(). That is, do list.append(x) in a long
loop. Linux users don't see anything particularly bad no matter how big the loop. WinNT eventually displays clear
quadratic-time behavior. Win9x dies surprisingly early with a MemoryError, despite gobs of memory free: turns out
Win9x allocates hundreds of virtual heaps, isn't able to coalesce them, and you actually run out of *address space* (the
whole 2GB user space gets fragmented beyond hope). People on other platforms have reported other bad behaviors over the
years.
I don't want to argue about this again <wink>, I just want to know whether the patch below slows anything down on your
oddball box. It increases the over-allocation amount in several more layers. Also replaces integer * and / in the
over-allocation computation by bit operations (integer / in particular is very slow on *some* boxes).
Long-term we should teach PyMalloc about Python's realloc() abuses and craft a cooperative solution.
Index: Objects/listobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/listobject.c,v
retrieving revision 2.92
diff -c -r2.92 listobject.c
*** Objects/listobject.c 2001/02/12 22:06:02 2.92
--- Objects/listobject.c 2001/05/25 19:04:07
***************
*** 9,24 ****
#include <sys/types.h> /* For size_t */
#endif
! #define ROUNDUP(n, PyTryBlock) \
! ((((n)+(PyTryBlock)-1)/(PyTryBlock))*(PyTryBlock))
static int
roundupsize(int n)
{
! if (n < 500)
return ROUNDUP(n, 10);
else
! return ROUNDUP(n, 100);
}
#define NRESIZE(var, type, nitems) PyMem_RESIZE(var, type, roundupsize(nitems))
--- 9,30 ----
#include <sys/types.h> /* For size_t */
#endif
! #define ROUNDUP(n, nbits) \
! ( ((n) + (1<<(nbits)) - 1) >> (nbits) << (nbits) )
static int
roundupsize(int n)
{
! if ((n >> 9) == 0)
! return ROUNDUP(n, 3);
! else if ((n >> 13) == 0)
! return ROUNDUP(n, 7);
! else if ((n >> 17) == 0)
return ROUNDUP(n, 10);
+ else if ((n >> 20) == 0)
+ return ROUNDUP(n, 13);
else
! return ROUNDUP(n, 18);
}
#define NRESIZE(var, type, nitems) PyMem_RESIZE(var, type, roundupsize(nitems))