objectpool.c 6.7 KB

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