objectpool.c 6.6 KB

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