objectpool.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. #include "pocketpy/interpreter/objectpool.h"
  2. #include "pocketpy/config.h"
  3. #include "pocketpy/objects/object.h"
  4. #include "pocketpy/common/sstream.h"
  5. #include <assert.h>
  6. #include <stdbool.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. static PoolArena* PoolArena__new(int block_size) {
  10. assert(kPoolArenaSize % block_size == 0);
  11. int block_count = kPoolArenaSize / block_size;
  12. PoolArena* self = PK_MALLOC(sizeof(PoolArena) + sizeof(int) * block_count);
  13. self->block_size = block_size;
  14. self->block_count = block_count;
  15. self->unused_length = block_count;
  16. self->unused = PK_MALLOC(sizeof(int) * block_count);
  17. for(int i = 0; i < block_count; i++) {
  18. self->unused[i] = i;
  19. }
  20. memset(self->data, 0, kPoolArenaSize);
  21. return self;
  22. }
  23. static void PoolArena__delete(PoolArena* self) {
  24. for(int i = 0; i < self->block_count; i++) {
  25. PyObject* obj = (PyObject*)(self->data + i * self->block_size);
  26. if(obj->type != 0) PyObject__dtor(obj);
  27. }
  28. PK_FREE(self->unused);
  29. PK_FREE(self);
  30. }
  31. static void* PoolArena__alloc(PoolArena* self) {
  32. assert(self->unused_length > 0);
  33. int index = self->unused[self->unused_length - 1];
  34. self->unused_length--;
  35. return self->data + index * self->block_size;
  36. }
  37. static int PoolArena__sweep_dealloc(PoolArena* self) {
  38. int freed = 0;
  39. self->unused_length = 0;
  40. for(int i = 0; i < self->block_count; i++) {
  41. PyObject* obj = (PyObject*)(self->data + i * self->block_size);
  42. if(obj->type == 0) {
  43. // free slot
  44. self->unused[self->unused_length] = i;
  45. self->unused_length++;
  46. } else {
  47. if(!obj->gc_marked) {
  48. // not marked, need to free
  49. obj->type = 0;
  50. freed++;
  51. self->unused[self->unused_length] = i;
  52. self->unused_length++;
  53. } else {
  54. // marked, clear mark
  55. obj->gc_marked = false;
  56. }
  57. }
  58. }
  59. return freed;
  60. }
  61. static void Pool__ctor(Pool* self, int block_size) {
  62. c11_vector__ctor(&self->arenas, sizeof(PoolArena*));
  63. c11_vector__ctor(&self->no_free_arenas, sizeof(PoolArena*));
  64. self->block_size = block_size;
  65. }
  66. static void Pool__dtor(Pool* self) {
  67. c11__foreach(PoolArena*, &self->arenas, arena) PoolArena__delete(*arena);
  68. c11__foreach(PoolArena*, &self->no_free_arenas, arena) PoolArena__delete(*arena);
  69. c11_vector__dtor(&self->arenas);
  70. c11_vector__dtor(&self->no_free_arenas);
  71. }
  72. static void* Pool__alloc(Pool* self) {
  73. PoolArena* arena;
  74. if(self->arenas.length == 0) {
  75. arena = PoolArena__new(self->block_size);
  76. c11_vector__push(PoolArena*, &self->arenas, arena);
  77. } else {
  78. arena = c11_vector__back(PoolArena*, &self->arenas);
  79. }
  80. void* ptr = PoolArena__alloc(arena);
  81. if(arena->unused_length == 0) {
  82. c11_vector__pop(&self->arenas);
  83. c11_vector__push(PoolArena*, &self->no_free_arenas, arena);
  84. }
  85. return ptr;
  86. }
  87. static int Pool__sweep_dealloc(Pool* self, c11_vector* arenas, c11_vector* no_free_arenas) {
  88. c11_vector__clear(arenas);
  89. c11_vector__clear(no_free_arenas);
  90. int freed = 0;
  91. for(int i = 0; i < self->arenas.length; i++) {
  92. PoolArena* item = c11__getitem(PoolArena*, &self->arenas, i);
  93. assert(item->unused_length > 0);
  94. freed += PoolArena__sweep_dealloc(item);
  95. if(item->unused_length == item->block_count) {
  96. // all free
  97. if(arenas->length > 0) {
  98. // at least one arena
  99. PoolArena__delete(item);
  100. } else {
  101. // no arena
  102. c11_vector__push(PoolArena*, arenas, item);
  103. }
  104. } else {
  105. // some free
  106. c11_vector__push(PoolArena*, arenas, item);
  107. }
  108. }
  109. for(int i = 0; i < self->no_free_arenas.length; i++) {
  110. PoolArena* item = c11__getitem(PoolArena*, &self->no_free_arenas, i);
  111. freed += PoolArena__sweep_dealloc(item);
  112. if(item->unused_length == 0) {
  113. // still no free
  114. c11_vector__push(PoolArena*, no_free_arenas, item);
  115. } else {
  116. if(item->unused_length == item->block_count) {
  117. // all free
  118. PoolArena__delete(item);
  119. } else {
  120. // some free
  121. c11_vector__push(PoolArena*, arenas, item);
  122. }
  123. }
  124. }
  125. c11_vector__swap(&self->arenas, arenas);
  126. c11_vector__swap(&self->no_free_arenas, no_free_arenas);
  127. return freed;
  128. }
  129. void* MultiPool__alloc(MultiPool* self, int size) {
  130. if(size == 0) return NULL;
  131. int index = (size - 1) >> 5;
  132. if(index < kMultiPoolCount) {
  133. Pool* pool = &self->pools[index];
  134. return Pool__alloc(pool);
  135. }
  136. return NULL;
  137. }
  138. int MultiPool__sweep_dealloc(MultiPool* self) {
  139. c11_vector arenas;
  140. c11_vector no_free_arenas;
  141. c11_vector__ctor(&arenas, sizeof(PoolArena*));
  142. c11_vector__ctor(&no_free_arenas, sizeof(PoolArena*));
  143. int freed = 0;
  144. for(int i = 0; i < kMultiPoolCount; i++) {
  145. Pool* item = &self->pools[i];
  146. freed += Pool__sweep_dealloc(item, &arenas, &no_free_arenas);
  147. }
  148. c11_vector__dtor(&arenas);
  149. c11_vector__dtor(&no_free_arenas);
  150. return freed;
  151. }
  152. void MultiPool__ctor(MultiPool* self) {
  153. for(int i = 0; i < kMultiPoolCount; i++) {
  154. Pool__ctor(&self->pools[i], 32 * (i + 1));
  155. }
  156. }
  157. void MultiPool__dtor(MultiPool* self) {
  158. for(int i = 0; i < kMultiPoolCount; i++) {
  159. Pool__dtor(&self->pools[i]);
  160. }
  161. }
  162. c11_string* MultiPool__summary(MultiPool* self) {
  163. c11_sbuf sbuf;
  164. c11_sbuf__ctor(&sbuf);
  165. for(int i = 0; i < kMultiPoolCount; i++) {
  166. Pool* item = &self->pools[i];
  167. int total_bytes = (item->arenas.length + item->no_free_arenas.length) * kPoolArenaSize;
  168. int used_bytes = 0;
  169. for(int j = 0; j < item->arenas.length; j++) {
  170. PoolArena* arena = c11__getitem(PoolArena*, &item->arenas, j);
  171. used_bytes += (arena->block_count - arena->unused_length) * arena->block_size;
  172. }
  173. used_bytes += item->no_free_arenas.length * kPoolArenaSize;
  174. float used_pct = (float)used_bytes / total_bytes * 100;
  175. char buf[256];
  176. snprintf(buf,
  177. sizeof(buf),
  178. "Pool<%d>: len(arenas)=%d, len(no_free_arenas)=%d, %d/%d (%.1f%% used)",
  179. item->block_size,
  180. item->arenas.length,
  181. item->no_free_arenas.length,
  182. used_bytes,
  183. total_bytes,
  184. used_pct);
  185. c11_sbuf__write_cstr(&sbuf, buf);
  186. c11_sbuf__write_char(&sbuf, '\n');
  187. }
  188. return c11_sbuf__submit(&sbuf);
  189. }