Browse Source

GC improvements

Fixed several issues in the GC
gcenabled is now reference counted
Introduced gcthreshold_original to prevents GC to run more than needed
Marco Bambini 6 years ago
parent
commit
0a9e54d9af
2 changed files with 26 additions and 15 deletions
  1. 24 14
      src/runtime/gravity_vm.c
  2. 2 1
      src/runtime/gravity_vm.h

+ 24 - 14
src/runtime/gravity_vm.c

@@ -57,12 +57,13 @@ struct gravity_vm {
     vm_filter_cb        filter;                         // function called to filter objects in the cleanup process
 
     // garbage collector
-    bool                gcenabled;                      // flag to enable/disable garbage collector
+    int32_t             gcenabled;                      // flag to enable/disable garbage collector (was bool but it is now reference counted)
     gravity_int_t       memallocated;                   // total number of allocated memory
     gravity_int_t       maxmemblock;                    // maximum block memory size allowed to allocate
     gravity_object_t    *gchead;                        // head of garbage collected objects
     gravity_int_t       gcminthreshold;                 // minimum GC threshold size to avoid spending too much time in GC
     gravity_int_t       gcthreshold;                    // memory required to trigger a GC
+    gravity_int_t       gcthreshold_original;           // gcthreshold is dynamically re-computed so I msut save the original value somewhere
     gravity_float_t     gcratio;                        // ratio used in automatic recomputation of the new gcthreshold value
     gravity_int_t       gccount;                        // number of objects into GC
     gravity_object_r    graylist;                       // array of collected objects while GC is in process (gray list)
@@ -1038,10 +1039,10 @@ static bool gravity_vm_exec (gravity_vm *vm) {
                 DEFINE_STACK_VARIABLE(v1, r1);
 
                 // common NULL/UNDEFINED/BOOL/INT/FLOAT/STRING cases
-                // NULL/UNDEFINED    =>    no check
-                // BOOL/INT            =>    check n
+                // NULL/UNDEFINED   =>    no check
+                // BOOL/INT         =>    check n
                 // FLOAT            =>    check f
-                // STRING            =>    check len
+                // STRING           =>    check len
                 if (VALUE_ISA_NULL(v1) || (VALUE_ISA_UNDEFINED(v1))) {ip = COMPUTE_JUMP(value);}
                 else if (VALUE_ISA_BOOL(v1) || (VALUE_ISA_INT(v1))) {if (GETVALUE_INT(v1) == 0) ip = COMPUTE_JUMP(value);}
                 else if (VALUE_ISA_FLOAT(v1)) {if (GETVALUE_FLOAT(v1) == 0.0) ip = COMPUTE_JUMP(value);}
@@ -1422,10 +1423,8 @@ gravity_vm *gravity_vm_new (gravity_delegate_t *delegate) {
     vm->context = gravity_hash_create(DEFAULT_CONTEXT_SIZE, gravity_value_hash, gravity_value_equals, NULL, NULL);
 
     // garbage collector
-    vm->gcenabled = true;
-    vm->gcminthreshold = DEFAULT_CG_MINTHRESHOLD;
-    vm->gcthreshold = DEFAULT_CG_THRESHOLD;
-    vm->gcratio = DEFAULT_CG_RATIO;
+    gravity_gc_setenabled(vm, true);
+    gravity_gc_setvalues(vm, DEFAULT_CG_THRESHOLD, DEFAULT_CG_MINTHRESHOLD, DEFAULT_CG_RATIO);
     vm->memallocated = 0;
     vm->maxmemblock = MAX_MEMORY_BLOCK;
     marray_init(vm->graylist);
@@ -1768,7 +1767,7 @@ gravity_int_t gravity_vm_maxmemblock (gravity_vm *vm) {
 
 gravity_value_t gravity_vm_get (gravity_vm *vm, const char *key) {
     if (key) {
-        if (strcmp(key, GRAVITY_VM_GCENABLED) == 0) return VALUE_FROM_BOOL(vm->gcenabled);
+        if (strcmp(key, GRAVITY_VM_GCENABLED) == 0) return VALUE_FROM_INT(vm->gcenabled);
         if (strcmp(key, GRAVITY_VM_GCMINTHRESHOLD) == 0) return VALUE_FROM_INT(vm->gcminthreshold);
         if (strcmp(key, GRAVITY_VM_GCTHRESHOLD) == 0) return VALUE_FROM_INT(vm->gcthreshold);
         if (strcmp(key, GRAVITY_VM_GCRATIO) == 0) return VALUE_FROM_FLOAT(vm->gcratio);
@@ -1781,7 +1780,7 @@ gravity_value_t gravity_vm_get (gravity_vm *vm, const char *key) {
 
 bool gravity_vm_set (gravity_vm *vm, const char *key, gravity_value_t value) {
     if (key) {
-        if ((strcmp(key, GRAVITY_VM_GCENABLED) == 0) && VALUE_ISA_BOOL(value)) {vm->gcenabled = VALUE_AS_BOOL(value); return true;}
+        if ((strcmp(key, GRAVITY_VM_GCENABLED) == 0) && VALUE_ISA_BOOL(value)) {VALUE_AS_BOOL(value) ? ++vm->gcenabled : --vm->gcenabled ; return true;}
         if ((strcmp(key, GRAVITY_VM_GCMINTHRESHOLD) == 0) && VALUE_ISA_INT(value)) {vm->gcminthreshold = VALUE_AS_INT(value); return true;}
         if ((strcmp(key, GRAVITY_VM_GCTHRESHOLD) == 0) && VALUE_ISA_INT(value)) {vm->gcthreshold = VALUE_AS_INT(value); return true;}
         if ((strcmp(key, GRAVITY_VM_GCRATIO) == 0) && VALUE_ISA_FLOAT(value)) {vm->gcratio = VALUE_AS_FLOAT(value); return true;}
@@ -2025,6 +2024,13 @@ static void gravity_gray_hash (gravity_hash_t *hashtable, gravity_value_t key, g
 
 // MARK: -
 
+void gravity_gc_setvalues (gravity_vm *vm, gravity_int_t threshold, gravity_int_t minthreshold, gravity_float_t ratio) {
+    vm->gcminthreshold = (minthreshold) ? minthreshold : DEFAULT_CG_MINTHRESHOLD;
+    vm->gcthreshold = (threshold) ? threshold : DEFAULT_CG_THRESHOLD;
+    vm->gcratio = (ratio) ? ratio : DEFAULT_CG_RATIO;
+    vm->gcthreshold_original = vm->gcthreshold;
+}
+
 static void gravity_gc_transform (gravity_hash_t *hashtable, gravity_value_t key, gravity_value_t *value, void *data) {
     #pragma unused (hashtable)
 
@@ -2087,7 +2093,7 @@ static void gravity_gc_transfer_object (gravity_vm *vm, gravity_object_t *obj) {
 }
 
 static void gravity_gc_transfer (gravity_vm *vm, gravity_object_t *obj) {
-    if (vm->gcenabled) {
+    if (vm->gcenabled > 0) {
         #if GRAVITY_GC_STRESSTEST
         // check if ptr is already in the list
         gravity_object_t **ptr = &vm->gchead;
@@ -2105,6 +2111,7 @@ static void gravity_gc_transfer (gravity_vm *vm, gravity_object_t *obj) {
     }
 
     gravity_gc_transfer_object(vm, obj);
+    gravity_vm_memupdate(vm, gravity_object_size(vm, obj));
 }
 
 static void gravity_gc_sweep (gravity_vm *vm) {
@@ -2159,11 +2166,14 @@ void gravity_gc_start (gravity_vm *vm) {
     // dynamically update gcthreshold
     vm->gcthreshold = (gravity_int_t)(vm->memallocated + (vm->memallocated * vm->gcratio / 100));
     if (vm->gcthreshold < vm->gcminthreshold) vm->gcthreshold = vm->gcminthreshold;
-
+    
+    // this line prevents GC to run more than needed
+    if (vm->gcthreshold < vm->gcthreshold_original) vm->gcthreshold = vm->gcthreshold_original;
+    
     #if GRAVITY_GC_STATS
     nanotime_t tend = nanotime();
     double gctime = millitime(tstart, tend);
-    printf("GC %lu before, %lu after (%lu collected - %lu objects), next at %lu. Took %.3fs.\n",
+    printf("GC %lu before, %lu after (%lu collected - %lu objects), next at %lu. Took %.2fms.\n",
            (unsigned long)membefore,
            (unsigned long)vm->memallocated,
            (membefore > vm->memallocated) ? (unsigned long)(membefore - vm->memallocated) : 0,
@@ -2231,7 +2241,7 @@ static void gravity_gc_cleanup (gravity_vm *vm) {
 }
 
 void gravity_gc_setenabled (gravity_vm *vm, bool enabled) {
-    vm->gcenabled = enabled;
+    (enabled) ? ++vm->gcenabled : --vm->gcenabled ;
 }
 
 void gravity_gc_push (gravity_vm *vm, gravity_object_t *obj) {

+ 2 - 1
src/runtime/gravity_vm.h

@@ -58,7 +58,8 @@ GRAVITY_API void                gravity_gc_start (gravity_vm* vm);
 GRAVITY_API void                gravity_gc_setenabled (gravity_vm* vm, bool enabled);
 GRAVITY_API void                gravity_gc_push (gravity_vm *vm, gravity_object_t *obj);
 GRAVITY_API void                gravity_gc_pop (gravity_vm *vm);
-
+GRAVITY_API void                gravity_gc_setvalues (gravity_vm *vm, gravity_int_t threshold, gravity_int_t minthreshold, gravity_float_t ratio);
+    
 GRAVITY_API void                gravity_vm_transfer (gravity_vm* vm, gravity_object_t *obj);
 GRAVITY_API void                gravity_vm_cleanup (gravity_vm* vm);
 GRAVITY_API void                gravity_vm_filter (gravity_vm* vm, vm_filter_cb cleanup_filter);