[前][次][番号順一覧][スレッド一覧]

ruby-changes:51491

From: ko1 <ko1@a...>
Date: Wed, 20 Jun 2018 16:53:37 +0900 (JST)
Subject: [ruby-changes:51491] ko1:r63701 (trunk): Introduce `USE_GC_MALLOC_OBJ_INFO_DETAILS`. [Feature #14857]

ko1	2018-06-20 16:53:29 +0900 (Wed, 20 Jun 2018)

  New Revision: 63701

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=63701

  Log:
    Introduce `USE_GC_MALLOC_OBJ_INFO_DETAILS`. [Feature #14857]
    
    * include/ruby/defines.h: introduce `USE_GC_MALLOC_OBJ_INFO_DETAILS`
      to show malloc statistics by replace ruby_xmalloc() and so on with
      macros.
    
    * gc.c (struct malloc_obj_info): introduced to save per-malloc information.

  Modified files:
    trunk/gc.c
    trunk/include/ruby/defines.h
Index: include/ruby/defines.h
===================================================================
--- include/ruby/defines.h	(revision 63700)
+++ include/ruby/defines.h	(revision 63701)
@@ -203,12 +203,89 @@ RUBY_SYMBOL_EXPORT_BEGIN https://github.com/ruby/ruby/blob/trunk/include/ruby/defines.h#L203
 # define RUBY_ATTR_ALLOC_SIZE(params)
 #endif
 
-void *xmalloc(size_t) RUBY_ATTR_ALLOC_SIZE((1));
-void *xmalloc2(size_t,size_t) RUBY_ATTR_ALLOC_SIZE((1,2));
-void *xcalloc(size_t,size_t) RUBY_ATTR_ALLOC_SIZE((1,2));
-void *xrealloc(void*,size_t) RUBY_ATTR_ALLOC_SIZE((2));
-void *xrealloc2(void*,size_t,size_t) RUBY_ATTR_ALLOC_SIZE((2,3));
-void xfree(void*);
+void *ruby_xmalloc(size_t) RUBY_ATTR_ALLOC_SIZE((1));
+void *ruby_xmalloc2(size_t,size_t) RUBY_ATTR_ALLOC_SIZE((1,2));
+void *ruby_xcalloc(size_t,size_t) RUBY_ATTR_ALLOC_SIZE((1,2));
+void *ruby_xrealloc(void*,size_t) RUBY_ATTR_ALLOC_SIZE((2));
+void *ruby_xrealloc2(void*,size_t,size_t) RUBY_ATTR_ALLOC_SIZE((2,3));
+void ruby_xfree(void*);
+
+#ifndef USE_GC_MALLOC_OBJ_INFO_DETAILS
+#define USE_GC_MALLOC_OBJ_INFO_DETAILS 0
+#endif
+
+#if USE_GC_MALLOC_OBJ_INFO_DETAILS
+
+void *ruby_xmalloc_body(size_t) RUBY_ATTR_ALLOC_SIZE((1));
+void *ruby_xmalloc2_body(size_t,size_t) RUBY_ATTR_ALLOC_SIZE((1,2));
+void *ruby_xcalloc_body(size_t,size_t) RUBY_ATTR_ALLOC_SIZE((1,2));
+void *ruby_xrealloc_body(void*,size_t) RUBY_ATTR_ALLOC_SIZE((2));
+void *ruby_xrealloc2_body(void*,size_t,size_t) RUBY_ATTR_ALLOC_SIZE((2,3));
+
+#define ruby_xmalloc(s1)            ruby_xmalloc_with_location(s1, __FILE__, __LINE__)
+#define ruby_xmalloc2(s1, s2)       ruby_xmalloc2_with_location(s1, s2, __FILE__, __LINE__)
+#define ruby_xcalloc(s1, s2)        ruby_xcalloc_with_location(s1, s2, __FILE__, __LINE__)
+#define ruby_xrealloc(ptr, s1)      ruby_xrealloc_with_location(ptr, s1, __FILE__, __LINE__)
+#define ruby_xrealloc2(ptr, s1, s2) ruby_xrealloc2_with_location(ptr, s1, s2, __FILE__, __LINE__)
+
+extern const char *ruby_malloc_info_file;
+extern int ruby_malloc_info_line;
+
+static inline void *
+ruby_xmalloc_with_location(size_t s, const char *file, int line)
+{
+    void *ptr;
+    ruby_malloc_info_file = file;
+    ruby_malloc_info_line = line;
+    ptr = ruby_xmalloc_body(s);
+    ruby_malloc_info_file = NULL;
+    return ptr;
+}
+
+static inline void *
+ruby_xmalloc2_with_location(size_t s1, size_t s2, const char *file, int line)
+{
+    void *ptr;
+    ruby_malloc_info_file = file;
+    ruby_malloc_info_line = line;
+    ptr = ruby_xmalloc2_body(s1, s2);
+    ruby_malloc_info_file = NULL;
+    return ptr;
+}
+
+static inline void *
+ruby_xcalloc_with_location(size_t s1, size_t s2, const char *file, int line)
+{
+    void *ptr;
+    ruby_malloc_info_file = file;
+    ruby_malloc_info_line = line;
+    ptr = ruby_xcalloc_body(s1, s2);
+    ruby_malloc_info_file = NULL;
+    return ptr;
+}
+
+static inline void *
+ruby_xrealloc_with_location(void *ptr, size_t s, const char *file, int line)
+{
+    void *rptr;
+    ruby_malloc_info_file = file;
+    ruby_malloc_info_line = line;
+    rptr = ruby_xrealloc_body(ptr, s);
+    ruby_malloc_info_file = NULL;
+    return rptr;
+}
+
+static inline void *
+ruby_xrealloc2_with_location(void *ptr, size_t s1, size_t s2, const char *file, int line)
+{
+    void *rptr;
+    ruby_malloc_info_file = file;
+    ruby_malloc_info_line = line;
+    rptr = ruby_xrealloc2_body(ptr, s1, s2);
+    ruby_malloc_info_file = NULL;
+    return rptr;
+}
+#endif
 
 #define STRINGIZE(expr) STRINGIZE0(expr)
 #ifndef STRINGIZE0
Index: gc.c
===================================================================
--- gc.c	(revision 63700)
+++ gc.c	(revision 63701)
@@ -313,7 +313,7 @@ int ruby_rgengc_debug; https://github.com/ruby/ruby/blob/trunk/gc.c#L313
 #define GC_ENABLE_LAZY_SWEEP   1
 #endif
 #ifndef CALC_EXACT_MALLOC_SIZE
-#define CALC_EXACT_MALLOC_SIZE 0
+#define CALC_EXACT_MALLOC_SIZE USE_GC_MALLOC_OBJ_INFO_DETAILS
 #endif
 #if defined(HAVE_MALLOC_USABLE_SIZE) || CALC_EXACT_MALLOC_SIZE > 0
 #ifndef MALLOC_ALLOCATED_SIZE
@@ -7886,13 +7886,27 @@ objspace_malloc_increase(rb_objspace_t * https://github.com/ruby/ruby/blob/trunk/gc.c#L7886
 #endif
 }
 
+struct malloc_obj_info { /* 4 words */
+    size_t size;
+#if USE_GC_MALLOC_OBJ_INFO_DETAILS
+    size_t gen;
+    const char *file;
+    size_t line;
+#endif
+};
+
+#if USE_GC_MALLOC_OBJ_INFO_DETAILS
+const char *ruby_malloc_info_file;
+int ruby_malloc_info_line;
+#endif
+
 static inline size_t
 objspace_malloc_prepare(rb_objspace_t *objspace, size_t size)
 {
     if (size == 0) size = 1;
 
 #if CALC_EXACT_MALLOC_SIZE
-    size += sizeof(size_t);
+    size += sizeof(struct malloc_obj_info);
 #endif
 
     return size;
@@ -7905,8 +7919,18 @@ objspace_malloc_fixup(rb_objspace_t *obj https://github.com/ruby/ruby/blob/trunk/gc.c#L7919
     objspace_malloc_increase(objspace, mem, size, 0, MEMOP_TYPE_MALLOC);
 
 #if CALC_EXACT_MALLOC_SIZE
-    ((size_t *)mem)[0] = size;
-    mem = (size_t *)mem + 1;
+    {
+        struct malloc_obj_info *info = mem;
+        info->size = size;
+#if USE_GC_MALLOC_OBJ_INFO_DETAILS
+        info->gen = objspace->profile.count;
+        info->file = ruby_malloc_info_file;
+        info->line = info->file ? ruby_malloc_info_line : 0;
+#else
+        info->file = NULL;
+#endif
+        mem = info + 1;
+    }
 #endif
 
     return mem;
@@ -7964,9 +7988,12 @@ objspace_xrealloc(rb_objspace_t *objspac https://github.com/ruby/ruby/blob/trunk/gc.c#L7988
     }
 
 #if CALC_EXACT_MALLOC_SIZE
-    new_size += sizeof(size_t);
-    ptr = (size_t *)ptr - 1;
-    old_size = ((size_t *)ptr)[0];
+    {
+        struct malloc_obj_info *info = (struct malloc_obj_info *)ptr - 1;
+        new_size += sizeof(struct malloc_obj_info);
+        ptr = info;
+        old_size = info->size;
+    }
 #endif
 
     old_size = objspace_malloc_size(objspace, ptr, old_size);
@@ -7974,8 +8001,11 @@ objspace_xrealloc(rb_objspace_t *objspac https://github.com/ruby/ruby/blob/trunk/gc.c#L8001
     new_size = objspace_malloc_size(objspace, mem, new_size);
 
 #if CALC_EXACT_MALLOC_SIZE
-    ((size_t *)mem)[0] = new_size;
-    mem = (size_t *)mem + 1;
+    {
+        struct malloc_obj_info *info = mem;
+        info->size = new_size;
+        mem = info + 1;
+    }
 #endif
 
     objspace_malloc_increase(objspace, mem, new_size, old_size, MEMOP_TYPE_REALLOC);
@@ -7983,12 +8013,116 @@ objspace_xrealloc(rb_objspace_t *objspac https://github.com/ruby/ruby/blob/trunk/gc.c#L8013
     return mem;
 }
 
+#if CALC_EXACT_MALLOC_SIZE
+#if USE_GC_MALLOC_OBJ_INFO_DETAILS
+
+#define MALLOC_INFO_GEN_SIZE 100
+#define MALLOC_INFO_SIZE_SIZE 10
+static size_t malloc_info_gen_cnt[MALLOC_INFO_GEN_SIZE];
+static size_t malloc_info_gen_size[MALLOC_INFO_GEN_SIZE];
+static size_t malloc_info_size[MALLOC_INFO_SIZE_SIZE+1];
+static st_table *malloc_info_file_table;
+
+static int
+mmalloc_info_file_i(st_data_t key, st_data_t val, st_data_t dmy)
+{
+    const char *file = (void *)key;
+    const size_t *data = (void *)val;
+
+    fprintf(stderr, "%s\t%d\t%d\n", file, (int)data[0], (int)data[1]);
+
+    return ST_CONTINUE;
+}
+
+__attribute__((destructor))
+static void
+malloc_info_show_results(void)
+{
+    int i;
+
+    fprintf(stderr, "* malloc_info gen statistics\n");
+    for (i=0; i<MALLOC_INFO_GEN_SIZE; i++) {
+        if (i == MALLOC_INFO_GEN_SIZE-1) {
+            fprintf(stderr, "more\t%d\t%d\n", (int)malloc_info_gen_cnt[i], (int)malloc_info_gen_size[i]);
+        }
+        else {
+            fprintf(stderr, "%d\t%d\t%d\n", i, (int)malloc_info_gen_cnt[i], (int)malloc_info_gen_size[i]);
+        }
+    }
+
+    fprintf(stderr, "* malloc_info size statistics\n");
+    for (i=0; i<MALLOC_INFO_SIZE_SIZE; i++) {
+        int s = 16 << i;
+        fprintf(stderr, "%d\t%d\n", (int)s, (int)malloc_info_size[i]);
+    }
+    fprintf(stderr, "more\t%d\n", (int)malloc_info_size[i]);
+
+    if (malloc_info_file_table) {
+        fprintf(stderr, "* malloc_info file statistics\n");
+        st_foreach(malloc_info_file_table, mmalloc_info_file_i, 0);
+    }
+}
+#endif
+#endif
+
 static void
 objspace_xfree(rb_objspace_t *objspace, void *ptr, size_t old_size)
 {
 #if CALC_EXACT_MALLOC_SIZE
-    ptr = ((size_t *)ptr) - 1;
-    old_size = ((size_t*)ptr)[0];
+    struct malloc_obj_info *info = (struct malloc_obj_info *)ptr - 1;
+    ptr = info;
+    old_size = info->size;
+
+#if USE_GC_MALLOC_OBJ_INFO_DETAILS
+    {
+        int gen = (int)(objspace->profile.count - info->gen);
+        int gen_index = gen >= MALLOC_INFO_GEN_SIZE ? MALLOC_INFO_GEN_SIZE-1 : gen;
+        int i;
+
+        malloc_info_gen_cnt[gen_index]++;
+        malloc_info_gen_size[gen_index] += info->size;
+
+        for (i=0; i<MALLOC_INFO_SIZE_SIZE; i++) {
+            size_t s = 16 << i;
+            if (info->size <= s) {
+                malloc_info_size[i]++;
+                goto found;
+            }
+        }
+        malloc_info_size[i]++;
+      found:;
+
+        {
+            st_data_t key = (st_data_t)info->file;
+            size_t *data;
+
+            if (malloc_info_file_table == NULL) {
+                malloc_info_file_table = st_init_numtable_with_size(1024);
+            }
+            if (st_lookup(malloc_info_file_table, key, (st_data_t *)&data)) {
+                /* hit */
+            }
+            else {
+                data = malloc(sizeof(size_t) * 2);
+                if (data == NULL) rb_bug("objspace_xfree: can not allocate memory");
+                data[0] = data[1] = 0;
+                st_insert(malloc_info_file_table, key, (st_data_t)data);
+            }
+            data[0] ++;
+            data[1] += info->size;
+        };
+#if 0 /* verbose output */
+        if (gen >= 2) {
+            if (info->file) {
+                fprintf(stderr, "free - size:%d, gen:%d, pos: %s:%d\n", (int)info->size, gen, info->file, (int)info->line);
+            }
+            else {
+                fprintf(stderr, "free - size:%d, gen:%d\n", (int)info->size, gen);
+            }
+        }
+#endif
+    }
+#endif
 #endif
     old_size = objspace_malloc_size(objspace, ptr, old_size);
 
@@ -8004,7 +8138,7 @@ ruby_xmalloc0(size_t size) https://github.com/ruby/ruby/blob/trunk/gc.c#L8138
 }
 
 void *
-ruby_xmalloc(size_t size)
+ruby_xmalloc_body(size_t size)
 {
     if ((ssize_t)size < 0) {
 	negative_size_allocation_error("too large allocation size");
@@ -8021,7 +8155,7 @@ ruby_malloc_size_overflow(size_t count, https://github.com/ruby/ruby/blob/trunk/gc.c#L8155
 }
 
 void *
-ruby_xmalloc2(size_t n, size_t size)
+ruby_xmalloc2_body(size_t n, size_t size)
 {
     return objspace_xmalloc0(&rb_objspace, xmalloc2_size(n, size));
 }
@@ -8037,7 +8171,7 @@ objspace_xcalloc(rb_objspace_t *objspace https://github.com/ruby/ruby/blob/trunk/gc.c#L8171
 }
 
 void *
-ruby_xcalloc(size_t n, size_t size)
+ruby_xcalloc_body(size_t n, size_t size)
 {
     return objspace_xcalloc(&rb_objspace, xmalloc2_size(n, size));
 }
@@ -8056,7 +8190,7 @@ ruby_sized_xrealloc(void *ptr, size_t ne https://github.com/ruby/ruby/blob/trunk/gc.c#L8190
 }
 
 void *
-ruby_xrealloc(void *ptr, size_t new_size)
+ruby_xrealloc_body(void *ptr, size_t new_size)
 {
     return ruby_sized_xrealloc(ptr, new_size, 0);
 }
@@ -8075,7 +8209,7 @@ ruby_sized_xrealloc2(void *ptr, size_t n https://github.com/ruby/ruby/blob/trunk/gc.c#L8209
 }
 
 void *
-ruby_xrealloc2(void *ptr, size_t n, size_t size)
+ruby_xrealloc2_body(void *ptr, size_t n, size_t size)
 {
     return ruby_sized_xrealloc2(ptr, n, size, 0);
 }
@@ -8105,13 +8239,16 @@ ruby_mimmalloc(size_t size) https://github.com/ruby/ruby/blob/trunk/gc.c#L8239
 {
     void *mem;
 #if CALC_EXACT_MALLOC_SIZE
-    size += sizeof(size_t);
+    size += sizeof(struct malloc_obj_info);
 #endif
     mem = malloc(size);
 #if CALC_EXACT_MALLOC_SIZE
     /* set 0 for consistency of allocated_size/allocations */
-    ((size_t *)mem)[0] = 0;
-    mem = (size_t *)mem + 1;
+    {
+        struct malloc_obj_info *info = mem;
+        info->size = 0;
+        mem = info + 1;
+    }
 #endif
     return mem;
 }
@@ -8119,11 +8256,11 @@ ruby_mimmalloc(size_t size) https://github.com/ruby/ruby/blob/trunk/gc.c#L8256
 void
 ruby_mimfree(void *ptr)
 {
-    size_t *mem = (size_t *)ptr;
 #if CALC_EXACT_MALLOC_SIZE
-    mem = mem - 1;
+    struct malloc_obj_info *info = (struct malloc_obj_info *)ptr - 1;
+    ptr = info;
 #endif
-    free(mem);
+    free(ptr);
 }
 
 void *
@@ -9745,3 +9882,70 @@ Init_GC(void) https://github.com/ruby/ruby/blob/trunk/gc.c#L9882
 	OBJ_FREEZE(opts);
     }
 }
+
+#ifdef ruby_xmalloc
+#undef ruby_xmalloc
+#endif
+#ifdef ruby_xmalloc2
+#undef ruby_xmalloc2
+#endif
+#ifdef ruby_xcalloc
+#undef ruby_xcalloc
+#endif
+#ifdef ruby_xrealloc
+#undef ruby_xrealloc
+#endif
+#ifdef ruby_xrealloc2
+#undef ruby_xrealloc2
+#endif
+
+void *
+ruby_xmalloc(size_t size)
+{
+#if USE_GC_MALLOC_OBJ_INFO_DETAILS
+    ruby_malloc_info_file = __FILE__;
+    ruby_malloc_info_line = __LINE__;
+#endif
+    return ruby_xmalloc_body(size);
+}
+
+void *
+ruby_xmalloc2(size_t n, size_t size)
+{
+#if USE_GC_MALLOC_OBJ_INFO_DETAILS
+    ruby_malloc_info_file = __FILE__;
+    ruby_malloc_info_line = __LINE__;
+#endif
+    return ruby_xmalloc2_body(n, size);
+}
+
+void *
+ruby_xcalloc(size_t n, size_t size)
+{
+#if USE_GC_MALLOC_OBJ_INFO_DETAILS
+    ruby_malloc_info_file = __FILE__;
+    ruby_malloc_info_line = __LINE__;
+#endif
+    return ruby_xcalloc_body(n, size);
+}
+
+void *
+ruby_xrealloc(void *ptr, size_t new_size)
+{
+#if USE_GC_MALLOC_OBJ_INFO_DETAILS
+    ruby_malloc_info_file = __FILE__;
+    ruby_malloc_info_line = __LINE__;
+#endif
+    return ruby_xrealloc_body(ptr, new_size);
+}
+
+void *
+ruby_xrealloc2(void *ptr, size_t n, size_t new_size)
+{
+#if USE_GC_MALLOC_OBJ_INFO_DETAILS
+    ruby_malloc_info_file = __FILE__;
+    ruby_malloc_info_line = __LINE__;
+#endif
+    return ruby_xrealloc2_body(ptr, n, new_size);
+}
+

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]