heap.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. #include "pocketpy/interpreter/heap.h"
  2. #include "pocketpy/config.h"
  3. #include "pocketpy/interpreter/objectpool.h"
  4. #include "pocketpy/objects/base.h"
  5. #include "pocketpy/pocketpy.h"
  6. #include <assert.h>
  7. void ManagedHeap__ctor(ManagedHeap* self) {
  8. MultiPool__ctor(&self->small_objects);
  9. c11_vector__ctor(&self->large_objects, sizeof(PyObject*));
  10. c11_vector__ctor(&self->gc_roots, sizeof(PyObject*));
  11. for(int i = 0; i < c11__count_array(self->freed_ma); i++) {
  12. self->freed_ma[i] = PK_GC_MIN_THRESHOLD;
  13. }
  14. self->gc_threshold = PK_GC_MIN_THRESHOLD;
  15. self->gc_counter = 0;
  16. self->gc_enabled = true;
  17. }
  18. void ManagedHeap__dtor(ManagedHeap* self) {
  19. // small_objects
  20. MultiPool__dtor(&self->small_objects);
  21. // large_objects
  22. for(int i = 0; i < self->large_objects.length; i++) {
  23. PyObject* obj = c11__getitem(PyObject*, &self->large_objects, i);
  24. PyObject__dtor(obj);
  25. PK_FREE(obj);
  26. }
  27. c11_vector__dtor(&self->large_objects);
  28. c11_vector__dtor(&self->gc_roots);
  29. }
  30. void ManagedHeap__collect_if_needed(ManagedHeap* self) {
  31. if(!self->gc_enabled) return;
  32. if(self->gc_counter < self->gc_threshold) return;
  33. int freed = ManagedHeap__collect(self);
  34. // adjust `gc_threshold` based on `freed_ma`
  35. self->freed_ma[0] = self->freed_ma[1];
  36. self->freed_ma[1] = self->freed_ma[2];
  37. self->freed_ma[2] = freed;
  38. int avg_freed = (self->freed_ma[0] + self->freed_ma[1] + self->freed_ma[2]) / 3;
  39. const int upper = PK_GC_MIN_THRESHOLD * 16;
  40. const int lower = PK_GC_MIN_THRESHOLD / 2;
  41. float free_ratio = (float)avg_freed / self->gc_threshold;
  42. int new_threshold = self->gc_threshold * (1.5f / free_ratio);
  43. // printf("gc_threshold=%d, avg_freed=%d, new_threshold=%d\n", self->gc_threshold, avg_freed,
  44. // new_threshold);
  45. self->gc_threshold = c11__min(c11__max(new_threshold, lower), upper);
  46. }
  47. int ManagedHeap__collect(ManagedHeap* self) {
  48. self->gc_counter = 0;
  49. ManagedHeap__mark(self);
  50. int freed = ManagedHeap__sweep(self);
  51. // printf("GC: collected %d objects\n", freed);
  52. return freed;
  53. }
  54. int ManagedHeap__sweep(ManagedHeap* self) {
  55. // small_objects
  56. int small_freed = MultiPool__sweep_dealloc(&self->small_objects);
  57. // large_objects
  58. int large_living_count = 0;
  59. for(int i = 0; i < self->large_objects.length; i++) {
  60. PyObject* obj = c11__getitem(PyObject*, &self->large_objects, i);
  61. if(obj->gc_marked) {
  62. obj->gc_marked = false;
  63. c11__setitem(PyObject*, &self->large_objects, large_living_count, obj);
  64. large_living_count++;
  65. } else {
  66. PyObject__dtor(obj);
  67. PK_FREE(obj);
  68. }
  69. }
  70. // shrink `self->large_objects`
  71. int large_freed = self->large_objects.length - large_living_count;
  72. self->large_objects.length = large_living_count;
  73. // printf("large_freed=%d\n", large_freed);
  74. // printf("small_freed=%d\n", small_freed);
  75. return small_freed + large_freed;
  76. }
  77. PyObject* ManagedHeap__gcnew(ManagedHeap* self, py_Type type, int slots, int udsize) {
  78. assert(slots >= 0 || slots == -1);
  79. PyObject* obj;
  80. // header + slots + udsize
  81. int size = sizeof(PyObject) + PK_OBJ_SLOTS_SIZE(slots) + udsize;
  82. if(size <= kPoolMaxBlockSize) {
  83. obj = MultiPool__alloc(&self->small_objects, size);
  84. assert(obj != NULL);
  85. } else {
  86. obj = PK_MALLOC(size);
  87. c11_vector__push(PyObject*, &self->large_objects, obj);
  88. }
  89. obj->type = type;
  90. obj->gc_marked = false;
  91. obj->slots = slots;
  92. // initialize slots or dict
  93. if(slots >= 0) {
  94. memset(obj->flex, 0, slots * sizeof(py_TValue));
  95. } else {
  96. float load_factor = (type == tp_type || type == tp_module) ? PK_TYPE_ATTR_LOAD_FACTOR
  97. : PK_INST_ATTR_LOAD_FACTOR;
  98. NameDict__ctor((void*)obj->flex, load_factor);
  99. }
  100. self->gc_counter++;
  101. return obj;
  102. }