diff options
-rw-r--r-- | ChangeLog | 35 | ||||
-rw-r--r-- | cont.c | 3 | ||||
-rw-r--r-- | ext/objspace/objspace.c | 132 | ||||
-rw-r--r-- | gc.c | 200 | ||||
-rw-r--r-- | internal.h | 1 | ||||
-rw-r--r-- | variable.c | 2 | ||||
-rw-r--r-- | vm.c | 4 |
7 files changed, 247 insertions, 130 deletions
@@ -1,3 +1,38 @@ +Tue Nov 5 13:37:19 2013 Koichi Sasada <[email protected]> + + * gc.c: add support to estimate increase of oldspace memory usage. + This is another approach to solve an issue discussed at r43530. + This feature is diabled as default. + + This feature measures an increment of memory consuption by oldgen + objects. It measures memory consumption for each objects when + the object is promoted. However, measurement of memory consumption + is not accurate now. So that this measurement is `estimation'. + + To implement this feature, move memsize_of() function from + ext/objspace/objspace.c and expose rb_obj_memsize_of(). + + Some memsize() functions for T_DATA (T_TYPEDDATA) have problem to + measure memory size, so that we ignores T_DATA objects now. + For example, some functions skip NULL check for pointer. + + The macro RGENGC_ESTIMATE_OLDSPACE enables/disables this feature, + and turned off as default. + + We need to compare 3gen GC and this feature carefully. + (it is possible to enable both feature) + We need a help to compare them. + + * internal.h: expose rb_obj_memsize_of(). + + * ext/objspace/objspace.c: use rb_obj_memsize_of() function. + + * cont.c (fiber_memsize): fix to check NULL. + + * variable.c (autoload_memsize): ditto. + + * vm.c (vm_memsize): ditto. + Tue Nov 5 04:03:07 2013 Koichi Sasada <[email protected]> * gc.c (GC_MALLOC_LIMIT_MAX): fix default value 512MB -> 384MB. @@ -351,7 +351,8 @@ fiber_memsize(const void *ptr) size_t size = 0; if (ptr) { size = sizeof(*fib); - if (fib->cont.type != ROOT_FIBER_CONTEXT) { + if (fib->cont.type != ROOT_FIBER_CONTEXT && + fib->cont.saved_thread.local_storage != NULL) { size += st_memsize(fib->cont.saved_thread.local_storage); } size += cont_memsize(&fib->cont); diff --git a/ext/objspace/objspace.c b/ext/objspace/objspace.c index b0df466ee3..82a743ba5c 100644 --- a/ext/objspace/objspace.c +++ b/ext/objspace/objspace.c @@ -18,131 +18,9 @@ #include <ruby/re.h> #include "node.h" #include "gc.h" -#include "regint.h" #include "internal.h" -size_t rb_str_memsize(VALUE); -size_t rb_ary_memsize(VALUE); -size_t rb_io_memsize(const rb_io_t *); -size_t rb_generic_ivar_memsize(VALUE); -size_t rb_objspace_data_type_memsize(VALUE obj); - -static size_t -memsize_of(VALUE obj) -{ - size_t size = 0; - - if (SPECIAL_CONST_P(obj)) { - return 0; - } - - if (FL_TEST(obj, FL_EXIVAR)) { - size += rb_generic_ivar_memsize(obj); - } - - switch (BUILTIN_TYPE(obj)) { - case T_OBJECT: - if (!(RBASIC(obj)->flags & ROBJECT_EMBED) && - ROBJECT(obj)->as.heap.ivptr) { - size += ROBJECT(obj)->as.heap.numiv * sizeof(VALUE); - } - break; - case T_MODULE: - case T_CLASS: - if (RCLASS_M_TBL(obj)) { - size += st_memsize(RCLASS_M_TBL(obj)); - } - if (RCLASS_IV_TBL(obj)) { - size += st_memsize(RCLASS_IV_TBL(obj)); - } - if (RCLASS_IV_INDEX_TBL(obj)) { - size += st_memsize(RCLASS_IV_INDEX_TBL(obj)); - } - if (RCLASS(obj)->ptr->iv_tbl) { - size += st_memsize(RCLASS(obj)->ptr->iv_tbl); - } - if (RCLASS(obj)->ptr->const_tbl) { - size += st_memsize(RCLASS(obj)->ptr->const_tbl); - } - size += sizeof(rb_classext_t); - break; - case T_STRING: - size += rb_str_memsize(obj); - break; - case T_ARRAY: - size += rb_ary_memsize(obj); - break; - case T_HASH: - if (RHASH(obj)->ntbl) { - size += st_memsize(RHASH(obj)->ntbl); - } - break; - case T_REGEXP: - if (RREGEXP(obj)->ptr) { - size += onig_memsize(RREGEXP(obj)->ptr); - } - break; - case T_DATA: - size += rb_objspace_data_type_memsize(obj); - break; - case T_MATCH: - if (RMATCH(obj)->rmatch) { - struct rmatch *rm = RMATCH(obj)->rmatch; - size += onig_region_memsize(&rm->regs); - size += sizeof(struct rmatch_offset) * rm->char_offset_num_allocated; - size += sizeof(struct rmatch); - } - break; - case T_FILE: - if (RFILE(obj)->fptr) { - size += rb_io_memsize(RFILE(obj)->fptr); - } - break; - case T_RATIONAL: - case T_COMPLEX: - break; - case T_ICLASS: - /* iClass shares table with the module */ - break; - - case T_FLOAT: - break; - - case T_BIGNUM: - if (!(RBASIC(obj)->flags & RBIGNUM_EMBED_FLAG) && RBIGNUM_DIGITS(obj)) { - size += RBIGNUM_LEN(obj) * sizeof(BDIGIT); - } - break; - case T_NODE: - switch (nd_type(obj)) { - case NODE_SCOPE: - if (RNODE(obj)->u1.tbl) { - /* TODO: xfree(RANY(obj)->as.node.u1.tbl); */ - } - break; - case NODE_ALLOCA: - /* TODO: xfree(RANY(obj)->as.node.u1.node); */ - ; - } - break; /* no need to free iv_tbl */ - - case T_STRUCT: - if ((RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK) == 0 && - RSTRUCT(obj)->as.heap.ptr) { - size += sizeof(VALUE) * RSTRUCT_LEN(obj); - } - break; - - case T_ZOMBIE: - break; - - default: - rb_bug("objspace/memsize_of(): unknown data type 0x%x(%p)", - BUILTIN_TYPE(obj), (void*)obj); - } - - return size; -} +size_t rb_obj_memsize_of(VALUE); /* * call-seq: @@ -160,7 +38,7 @@ memsize_of(VALUE obj) static VALUE memsize_of_m(VALUE self, VALUE obj) { - return SIZET2NUM(memsize_of(obj)); + return SIZET2NUM(rb_obj_memsize_of(obj)); } struct total_data { @@ -187,7 +65,7 @@ total_i(void *vstart, void *vend, size_t stride, void *ptr) continue; default: if (data->klass == 0 || rb_obj_is_kind_of(v, data->klass)) { - data->total += memsize_of(v); + data->total += rb_obj_memsize_of(v); } } } @@ -254,7 +132,7 @@ cos_i(void *vstart, void *vend, size_t stride, void *data) for (;v != (VALUE)vend; v += stride) { if (RBASIC(v)->flags) { - counts[BUILTIN_TYPE(v)] += memsize_of(v); + counts[BUILTIN_TYPE(v)] += rb_obj_memsize_of(v); } } return 0; @@ -637,7 +515,7 @@ static size_t iow_size(const void *ptr) { VALUE obj = (VALUE)ptr; - return memsize_of(obj); + return rb_obj_memsize_of(obj); } static const rb_data_type_t iow_data_type = { @@ -89,6 +89,7 @@ rb_gc_guarded_ptr(volatile VALUE *ptr) #ifndef GC_HEAP_GROWTH_MAX #define GC_HEAP_GROWTH_MAX 0 /* 0 is disable */ #endif + #ifndef GC_MALLOC_LIMIT #define GC_MALLOC_LIMIT (16 /* 16 MB */ * 1024 * 1024 /* 1MB */) #endif @@ -99,6 +100,16 @@ rb_gc_guarded_ptr(volatile VALUE *ptr) #define GC_MALLOC_LIMIT_GROWTH_FACTOR 2.0 #endif +#ifndef GC_HEAP_OLDSPACE_MIN +#define GC_HEAP_OLDSPACE_MIN (16 /* 16 MB */ * 1024 * 1024 /* 1MB */) +#endif +#ifndef GC_HEAP_OLDSPACE_GROWTH_FACTOR +#define GC_HEAP_OLDSPACE_GROWTH_FACTOR 1.8 +#endif +#ifndef GC_HEAP_OLDSPACE_MAX +#define GC_HEAP_OLDSPACE_MAX (384 /* 384 MB */ * 1024 * 1024 /* 1MB */) +#endif + typedef struct { unsigned int initial_heap_min_slots; unsigned int initial_heap_min_free_slots; @@ -172,6 +183,16 @@ static ruby_gc_params_t initial_params = { #define RGENGC_THREEGEN 0 #endif +/* RGENGC_ESTIMATE_OLDSPACE + * Enable/disable to estimate increase size of oldspace. + * If estimation exceeds threashold, then will invoke full GC. + * 0: disable estimation. + * 1: enable estimation. + */ +#ifndef RGENGC_ESTIMATE_OLDSPACE +#define RGENGC_ESTIMATE_OLDSPACE 0 +#endif + #else /* USE_RGENGC */ #define RGENGC_DEBUG 0 #define RGENGC_CHECK_MODE 0 @@ -455,6 +476,11 @@ typedef struct rb_objspace { size_t young_object_count; #endif +#if RGENGC_ESTIMATE_OLDSPACE + size_t oldspace_increase; + size_t oldspace_increase_limit; +#endif + #if RGENGC_CHECK_MODE >= 2 /* for check mode */ VALUE parent_object; @@ -612,6 +638,8 @@ static void gc_mark(rb_objspace_t *objspace, VALUE ptr); static void gc_mark_maybe(rb_objspace_t *objspace, VALUE ptr); static void gc_mark_children(rb_objspace_t *objspace, VALUE ptr); +static size_t obj_memsize_of(VALUE obj, int use_tdata); + static double getrusage_time(void); static inline void gc_prof_setup_new_record(rb_objspace_t *objspace, int reason); static inline void gc_prof_timer_start(rb_objspace_t *); @@ -656,6 +684,8 @@ check_gen_consistency(VALUE obj) int promoted_flag = FL_TEST2(obj, FL_PROMOTED); rb_objspace_t *objspace = &rb_objspace; + obj_memsize_of((VALUE)obj, FALSE); + if (!is_pointer_to_heap(objspace, (void *)obj)) { rb_bug("check_gen_consistency: %p (%s) is not Ruby object.", (void *)obj, obj_type_name(obj)); } @@ -816,6 +846,10 @@ rb_objspace_alloc(void) malloc_limit = initial_malloc_limit; ruby_gc_stress = ruby_initial_gc_stress; +#if RGENGC_ESTIMATE_OLDSPACE + objspace->rgengc.oldspace_increase_limit = GC_HEAP_OLDSPACE_MIN; +#endif + return objspace; } #endif @@ -2316,6 +2350,137 @@ rb_obj_id(VALUE obj) return nonspecial_obj_id(obj); } +size_t rb_str_memsize(VALUE); +size_t rb_ary_memsize(VALUE); +size_t rb_io_memsize(const rb_io_t *); +size_t rb_generic_ivar_memsize(VALUE); +#include "regint.h" + +static size_t +obj_memsize_of(VALUE obj, int use_tdata) +{ + size_t size = 0; + + if (SPECIAL_CONST_P(obj)) { + return 0; + } + + if (FL_TEST(obj, FL_EXIVAR)) { + size += rb_generic_ivar_memsize(obj); + } + + switch (BUILTIN_TYPE(obj)) { + case T_OBJECT: + if (!(RBASIC(obj)->flags & ROBJECT_EMBED) && + ROBJECT(obj)->as.heap.ivptr) { + size += ROBJECT(obj)->as.heap.numiv * sizeof(VALUE); + } + break; + case T_MODULE: + case T_CLASS: + if (RCLASS_M_TBL(obj)) { + size += st_memsize(RCLASS_M_TBL(obj)); + } + if (RCLASS_EXT(obj)) { + if (RCLASS_IV_TBL(obj)) { + size += st_memsize(RCLASS_IV_TBL(obj)); + } + if (RCLASS_IV_INDEX_TBL(obj)) { + size += st_memsize(RCLASS_IV_INDEX_TBL(obj)); + } + if (RCLASS(obj)->ptr->iv_tbl) { + size += st_memsize(RCLASS(obj)->ptr->iv_tbl); + } + if (RCLASS(obj)->ptr->const_tbl) { + size += st_memsize(RCLASS(obj)->ptr->const_tbl); + } + size += sizeof(rb_classext_t); + } + break; + case T_STRING: + size += rb_str_memsize(obj); + break; + case T_ARRAY: + size += rb_ary_memsize(obj); + break; + case T_HASH: + if (RHASH(obj)->ntbl) { + size += st_memsize(RHASH(obj)->ntbl); + } + break; + case T_REGEXP: + if (RREGEXP(obj)->ptr) { + size += onig_memsize(RREGEXP(obj)->ptr); + } + break; + case T_DATA: + if (use_tdata) size += rb_objspace_data_type_memsize(obj); + break; + case T_MATCH: + if (RMATCH(obj)->rmatch) { + struct rmatch *rm = RMATCH(obj)->rmatch; + size += onig_region_memsize(&rm->regs); + size += sizeof(struct rmatch_offset) * rm->char_offset_num_allocated; + size += sizeof(struct rmatch); + } + break; + case T_FILE: + if (RFILE(obj)->fptr) { + size += rb_io_memsize(RFILE(obj)->fptr); + } + break; + case T_RATIONAL: + case T_COMPLEX: + break; + case T_ICLASS: + /* iClass shares table with the module */ + break; + + case T_FLOAT: + break; + + case T_BIGNUM: + if (!(RBASIC(obj)->flags & RBIGNUM_EMBED_FLAG) && RBIGNUM_DIGITS(obj)) { + size += RBIGNUM_LEN(obj) * sizeof(BDIGIT); + } + break; + case T_NODE: + switch (nd_type(obj)) { + case NODE_SCOPE: + if (RNODE(obj)->u1.tbl) { + /* TODO: xfree(RANY(obj)->as.node.u1.tbl); */ + } + break; + case NODE_ALLOCA: + /* TODO: xfree(RANY(obj)->as.node.u1.node); */ + ; + } + break; /* no need to free iv_tbl */ + + case T_STRUCT: + if ((RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK) == 0 && + RSTRUCT(obj)->as.heap.ptr) { + size += sizeof(VALUE) * RSTRUCT_LEN(obj); + } + break; + + case T_ZOMBIE: + break; + + default: + rb_bug("objspace/memsize_of(): unknown data type 0x%x(%p)", + BUILTIN_TYPE(obj), (void*)obj); + } + + return size; +} + +size_t +rb_obj_memsize_of(VALUE obj) +{ + return obj_memsize_of(obj, TRUE); +} + static int set_zero(st_data_t key, st_data_t val, st_data_t arg) { @@ -2691,6 +2856,27 @@ gc_after_sweep(rb_objspace_t *objspace) #endif } +#if RGENGC_ESTIMATE_OLDSPACE + if (objspace->rgengc.oldspace_increase > objspace->rgengc.oldspace_increase_limit) { + objspace->rgengc.need_major_gc = TRUE; + objspace->rgengc.oldspace_increase_limit *= GC_HEAP_OLDSPACE_GROWTH_FACTOR; + objspace->rgengc.oldspace_increase = 0; + if (objspace->rgengc.oldspace_increase_limit > GC_HEAP_OLDSPACE_MAX) { + objspace->rgengc.oldspace_increase_limit = GC_HEAP_OLDSPACE_MAX; + } + } + else { + objspace->rgengc.oldspace_increase_limit /= ((GC_HEAP_OLDSPACE_GROWTH_FACTOR - 1)/10 + 1); + if (objspace->rgengc.oldspace_increase_limit < GC_HEAP_OLDSPACE_MIN) { + objspace->rgengc.oldspace_increase_limit = GC_HEAP_OLDSPACE_MIN; + } + } + if (0) fprintf(stderr, "%d\t%d\t%u\t%u\t%d\n", (int)rb_gc_count(), objspace->rgengc.need_major_gc, + (unsigned int)objspace->rgengc.oldspace_increase, + (unsigned int)objspace->rgengc.oldspace_increase_limit, + (unsigned int)GC_HEAP_OLDSPACE_MAX); +#endif + gc_prof_set_heap_info(objspace); heap_pages_free_unused_pages(objspace); @@ -3420,6 +3606,11 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr) /* infant -> old */ objspace->rgengc.old_object_count++; objspace->rgengc.parent_object_is_old = TRUE; + +#if RGENGC_ESTIMATE_OLDSPACE + objspace->rgengc.oldspace_increase += obj_memsize_of((VALUE)obj, FALSE); +#endif + #endif rgengc_report(3, objspace, "gc_mark_children: promote infant -> young %p (%s).\n", (void *)obj, obj_type_name((VALUE)obj)); } @@ -3431,6 +3622,9 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr) /* young -> old */ RVALUE_PROMOTE_YOUNG((VALUE)obj); objspace->rgengc.old_object_count++; +#if RGENGC_ESTIMATE_OLDSPACE + objspace->rgengc.oldspace_increase += obj_memsize_of((VALUE)obj, FALSE); +#endif rgengc_report(3, objspace, "gc_mark_children: promote young -> old %p (%s).\n", (void *)obj, obj_type_name((VALUE)obj)); } else { @@ -5044,6 +5238,12 @@ rb_gc_set_params(void) get_envparam_int ("RUBY_GC_MALLOC_LIMIT", &initial_malloc_limit, 0); get_envparam_int ("RUBY_GC_MALLOC_LIMIT_MAX", &initial_malloc_limit_max, 0); get_envparam_double("RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR", &initial_malloc_limit_growth_factor, 1.0); + + /* + get_envparam_int("RUBY_GC_HEAP_OLDSPACE_MIN", &initial_oldspace_min, 0); + get_envparam_int("RUBY_GC_HEAP_OLDSPACE_MAX", &initial_oldspace_max, 0); + get_envparam_int("RUBY_GC_HEAP_OLDSPACE_GROWTH_FACTOR", &initial_oldspace_growth_factor, 0); + */ } void diff --git a/internal.h b/internal.h index 77e2bd090b..20a813ca79 100644 --- a/internal.h +++ b/internal.h @@ -819,6 +819,7 @@ st_table *rb_st_copy(VALUE obj, struct st_table *orig_tbl); /* gc.c */ size_t rb_gc_count(); +size_t rb_obj_memsize_of(VALUE); RUBY_SYMBOL_EXPORT_END diff --git a/variable.c b/variable.c index 1c7bfb030f..a1bb36e088 100644 --- a/variable.c +++ b/variable.c @@ -1529,7 +1529,7 @@ static size_t autoload_memsize(const void *ptr) { const st_table *tbl = ptr; - return st_memsize(tbl); + return tbl ? st_memsize(tbl) : 0; } static const rb_data_type_t autoload_data_type = { @@ -1673,7 +1673,9 @@ vm_memsize(const void *ptr) if (ptr) { const rb_vm_t *vmobj = ptr; size_t size = sizeof(rb_vm_t); - size += st_memsize(vmobj->living_threads); + if (vmobj->living_threads) { + size += st_memsize(vmobj->living_threads); + } if (vmobj->defined_strings) { size += DEFINED_EXPR * sizeof(VALUE); } |