/Python/pyarena.c

http://unladen-swallow.googlecode.com/ · C · 220 lines · 138 code · 21 blank · 61 comment · 13 complexity · ad086412dee59c953a905a99f52f547c MD5 · raw file

  1. #include "Python.h"
  2. #include "pyarena.h"
  3. /* A simple arena block structure.
  4. Measurements with standard library modules suggest the average
  5. allocation is about 20 bytes and that most compiles use a single
  6. block.
  7. TODO(jhylton): Think about a realloc API, maybe just for the last
  8. allocation?
  9. */
  10. #define DEFAULT_BLOCK_SIZE 8192
  11. #define ALIGNMENT 8
  12. #define ALIGNMENT_MASK (ALIGNMENT - 1)
  13. #define ROUNDUP(x) (((x) + ALIGNMENT_MASK) & ~ALIGNMENT_MASK)
  14. typedef struct _block {
  15. /* Total number of bytes owned by this block available to pass out.
  16. * Read-only after initialization. The first such byte starts at
  17. * ab_mem.
  18. */
  19. size_t ab_size;
  20. /* Total number of bytes already passed out. The next byte available
  21. * to pass out starts at ab_mem + ab_offset.
  22. */
  23. size_t ab_offset;
  24. /* An arena maintains a singly-linked, NULL-terminated list of
  25. * all blocks owned by the arena. These are linked via the
  26. * ab_next member.
  27. */
  28. struct _block *ab_next;
  29. /* Pointer to the first allocatable byte owned by this block. Read-
  30. * only after initialization.
  31. */
  32. void *ab_mem;
  33. } block;
  34. /* The arena manages two kinds of memory, blocks of raw memory
  35. and a list of PyObject* pointers. PyObjects are decrefed
  36. when the arena is freed.
  37. */
  38. struct _arena {
  39. /* Pointer to the first block allocated for the arena, never NULL.
  40. It is used only to find the first block when the arena is
  41. being freed.
  42. */
  43. block *a_head;
  44. /* Pointer to the block currently used for allocation. It's
  45. ab_next field should be NULL. If it is not-null after a
  46. call to block_alloc(), it means a new block has been allocated
  47. and a_cur should be reset to point it.
  48. */
  49. block *a_cur;
  50. /* A Python list object containing references to all the PyObject
  51. pointers associated with this area. They will be DECREFed
  52. when the arena is freed.
  53. */
  54. PyObject *a_objects;
  55. #if defined(Py_DEBUG)
  56. /* Debug output */
  57. size_t total_allocs;
  58. size_t total_size;
  59. size_t total_blocks;
  60. size_t total_block_size;
  61. size_t total_big_blocks;
  62. #endif
  63. };
  64. static block *
  65. block_new(size_t size)
  66. {
  67. /* Allocate header and block as one unit.
  68. ab_mem points just past header. */
  69. block *b = (block *)malloc(sizeof(block) + size);
  70. if (!b)
  71. return NULL;
  72. b->ab_size = size;
  73. b->ab_mem = (void *)(b + 1);
  74. b->ab_next = NULL;
  75. b->ab_offset = ROUNDUP((Py_uintptr_t)(b->ab_mem)) -
  76. (Py_uintptr_t)(b->ab_mem);
  77. return b;
  78. }
  79. static void
  80. block_free(block *b) {
  81. while (b) {
  82. block *next = b->ab_next;
  83. free(b);
  84. b = next;
  85. }
  86. }
  87. static void *
  88. block_alloc(block *b, size_t size)
  89. {
  90. void *p;
  91. assert(b);
  92. size = ROUNDUP(size);
  93. if (b->ab_offset + size > b->ab_size) {
  94. /* If we need to allocate more memory than will fit in
  95. the default block, allocate a one-off block that is
  96. exactly the right size. */
  97. /* TODO(jhylton): Think about space waste at end of block */
  98. block *newbl = block_new(
  99. size < DEFAULT_BLOCK_SIZE ?
  100. DEFAULT_BLOCK_SIZE : size);
  101. if (!newbl)
  102. return NULL;
  103. assert(!b->ab_next);
  104. b->ab_next = newbl;
  105. b = newbl;
  106. }
  107. assert(b->ab_offset + size <= b->ab_size);
  108. p = (void *)(((char *)b->ab_mem) + b->ab_offset);
  109. b->ab_offset += size;
  110. return p;
  111. }
  112. PyArena *
  113. PyArena_New()
  114. {
  115. PyArena* arena = (PyArena *)malloc(sizeof(PyArena));
  116. if (!arena)
  117. return (PyArena*)PyErr_NoMemory();
  118. arena->a_head = block_new(DEFAULT_BLOCK_SIZE);
  119. arena->a_cur = arena->a_head;
  120. if (!arena->a_head) {
  121. free((void *)arena);
  122. return (PyArena*)PyErr_NoMemory();
  123. }
  124. arena->a_objects = PyList_New(0);
  125. if (!arena->a_objects) {
  126. block_free(arena->a_head);
  127. free((void *)arena);
  128. return (PyArena*)PyErr_NoMemory();
  129. }
  130. #if defined(Py_DEBUG)
  131. arena->total_allocs = 0;
  132. arena->total_size = 0;
  133. arena->total_blocks = 1;
  134. arena->total_block_size = DEFAULT_BLOCK_SIZE;
  135. arena->total_big_blocks = 0;
  136. #endif
  137. return arena;
  138. }
  139. void
  140. PyArena_Free(PyArena *arena)
  141. {
  142. int r;
  143. assert(arena);
  144. #if defined(Py_DEBUG)
  145. /*
  146. fprintf(stderr,
  147. "alloc=%d size=%d blocks=%d block_size=%d big=%d objects=%d\n",
  148. arena->total_allocs, arena->total_size, arena->total_blocks,
  149. arena->total_block_size, arena->total_big_blocks,
  150. PyList_Size(arena->a_objects));
  151. */
  152. #endif
  153. block_free(arena->a_head);
  154. /* This property normally holds, except when the code being compiled
  155. is sys.getobjects(0), in which case there will be two references.
  156. assert(arena->a_objects->ob_refcnt == 1);
  157. */
  158. /* Clear all the elements from the list. This is necessary
  159. to guarantee that they will be DECREFed. */
  160. r = PyList_SetSlice(arena->a_objects,
  161. 0, PyList_GET_SIZE(arena->a_objects), NULL);
  162. assert(r == 0);
  163. assert(PyList_GET_SIZE(arena->a_objects) == 0);
  164. Py_DECREF(arena->a_objects);
  165. free(arena);
  166. }
  167. void *
  168. PyArena_Malloc(PyArena *arena, size_t size)
  169. {
  170. void *p = block_alloc(arena->a_cur, size);
  171. if (!p)
  172. return PyErr_NoMemory();
  173. #if defined(Py_DEBUG)
  174. arena->total_allocs++;
  175. arena->total_size += size;
  176. #endif
  177. /* Reset cur if we allocated a new block. */
  178. if (arena->a_cur->ab_next) {
  179. arena->a_cur = arena->a_cur->ab_next;
  180. #if defined(Py_DEBUG)
  181. arena->total_blocks++;
  182. arena->total_block_size += arena->a_cur->ab_size;
  183. if (arena->a_cur->ab_size > DEFAULT_BLOCK_SIZE)
  184. ++arena->total_big_blocks;
  185. #endif
  186. }
  187. return p;
  188. }
  189. int
  190. PyArena_AddPyObject(PyArena *arena, PyObject *obj)
  191. {
  192. int r = PyList_Append(arena->a_objects, obj);
  193. if (r >= 0) {
  194. Py_DECREF(obj);
  195. }
  196. return r;
  197. }