ruby-changes:28922
From: ko1 <ko1@a...>
Date: Tue, 28 May 2013 12:36:46 +0900 (JST)
Subject: [ruby-changes:28922] ko1:r40974 (trunk): * ext/objspace/object_tracing.c: fix a bug reported at
ko1 2013-05-28 12:36:34 +0900 (Tue, 28 May 2013) New Revision: 40974 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=40974 Log: * ext/objspace/object_tracing.c: fix a bug reported at "[ruby-core:55182] [ruby-trunk - Bug #8456][Open] Sugfault in Ruby Head" Care about the case TracePoint#path #=> `nil'. * ext/objspace/object_tracing.c: add two new methods: * ObjectSpace.allocation_class_path(o) * ObjectSpace.allocation_method_id(o) They are not useful for Object.new because they are always "Class" and :new. To trace more useful information, we need to maintain call-tree using call/return hooks, which is implemented by ll-prof <http://sunagae.net/wiki/doku.php?id=software:llprof> * test/objspace/test_objspace.rb: add a test. Modified files: trunk/ChangeLog trunk/ext/objspace/object_tracing.c trunk/test/objspace/test_objspace.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 40973) +++ ChangeLog (revision 40974) @@ -1,3 +1,20 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Tue May 28 12:31:21 2013 Koichi Sasada <ko1@a...> + + * ext/objspace/object_tracing.c: fix a bug reported at + "[ruby-core:55182] [ruby-trunk - Bug #8456][Open] Sugfault in Ruby Head" + Care about the case TracePoint#path #=> `nil'. + + * ext/objspace/object_tracing.c: add two new methods: + * ObjectSpace.allocation_class_path(o) + * ObjectSpace.allocation_method_id(o) + They are not useful for Object.new because they are always + "Class" and :new. + To trace more useful information, we need to maintain call-tree + using call/return hooks, which is implemented by + ll-prof <http://sunagae.net/wiki/doku.php?id=software:llprof> + + * test/objspace/test_objspace.rb: add a test. + Tue May 28 11:30:02 2013 Nobuyoshi Nakada <nobu@r...> * ext/extmk.rb (extmake): leave makefiles untouched if the content is Index: ext/objspace/object_tracing.c =================================================================== --- ext/objspace/object_tracing.c (revision 40973) +++ ext/objspace/object_tracing.c (revision 40974) @@ -22,18 +22,61 @@ struct traceobj_arg { https://github.com/ruby/ruby/blob/trunk/ext/objspace/object_tracing.c#L22 VALUE newobj_trace; VALUE freeobj_trace; st_table *object_table; - st_table *path_table; + st_table *str_table; struct traceobj_arg *prev_traceobj_arg; }; struct traceobj_arg *traceobj_arg; /* TODO: do not use GLOBAL VARIABLE!!! */ struct allocation_info { - char *path; + const char *path; unsigned long line; + const char *class_path; + VALUE mid; size_t generation; }; +static const char * +make_unique_str(st_table *tbl, const char *str, int len) +{ + if (!str) { + return NULL; + } + else { + st_data_t n; + char *result; + + if (st_lookup(tbl, (st_data_t)str, &n)) { + st_insert(tbl, (st_data_t)str, n+1); + st_get_key(tbl, (st_data_t)str, (st_data_t *)&result); + } + else { + result = (char *)ruby_xmalloc(len+1); + strncpy(result, str, len); + result[len] = 0; + st_add_direct(tbl, (st_data_t)result, 1); + } + return result; + } +} + +static void +delete_unique_str(st_table *tbl, const char *str) +{ + if (str) { + st_data_t n; + + st_lookup(tbl, (st_data_t)str, &n); + if (n == 1) { + st_delete(tbl, (st_data_t *)&str, 0); + ruby_xfree((char *)str); + } + else { + st_insert(tbl, (st_data_t)str, n-1); + } + } +} + static void newobj_i(VALUE tpval, void *data) { @@ -42,29 +85,18 @@ newobj_i(VALUE tpval, void *data) https://github.com/ruby/ruby/blob/trunk/ext/objspace/object_tracing.c#L85 VALUE obj = rb_tracearg_object(tparg); VALUE path = rb_tracearg_path(tparg); VALUE line = rb_tracearg_lineno(tparg); - long path_len = RSTRING_LEN(path); + VALUE mid = rb_tracearg_method_id(tparg); + VALUE klass = rb_tracearg_defined_class(tparg); struct allocation_info *info = (struct allocation_info *)ruby_xmalloc(sizeof(struct allocation_info)); - char *path_cstr = ruby_xmalloc(path_len + 1); - char *path_stored_cstr; - - strncpy(path_cstr, RSTRING_PTR(path), path_len); - path_cstr[path_len] = 0; - - if (st_get_key(arg->path_table, (st_data_t)path_cstr, (st_data_t *)&path_stored_cstr)) { - st_data_t n; - st_lookup(arg->path_table, (st_data_t)path_stored_cstr, &n); - st_insert(arg->path_table, (st_data_t)path_stored_cstr, n+1); - ruby_xfree(path_cstr); - path_cstr = path_stored_cstr; - } - else { - st_add_direct(arg->path_table, (st_data_t)path_cstr, 1); - } + const char *path_cstr = RTEST(path) ? make_unique_str(arg->str_table, RSTRING_PTR(path), RSTRING_LEN(path)) : 0; + VALUE class_path = RTEST(klass) ? rb_class_path(klass) : Qnil; + const char *class_path_cstr = RTEST(class_path) ? make_unique_str(arg->str_table, RSTRING_PTR(class_path), RSTRING_LEN(class_path)) : 0; info->path = path_cstr; info->line = NUM2INT(line); + info->mid = mid; + info->class_path = class_path_cstr; info->generation = rb_gc_count(); - st_insert(arg->path_table, (st_data_t)path_cstr, 0); st_insert(arg->object_table, (st_data_t)obj, (st_data_t)info); } @@ -75,17 +107,10 @@ freeobj_i(VALUE tpval, void *data) https://github.com/ruby/ruby/blob/trunk/ext/objspace/object_tracing.c#L107 rb_trace_arg_t *tparg = rb_tracearg_from_tracepoint(tpval); VALUE obj = rb_tracearg_object(tparg); struct allocation_info *info; - st_data_t n; - if (st_delete(arg->object_table, (st_data_t *)&obj, (st_data_t *)&info)) { - st_lookup(arg->path_table, (st_data_t)info->path, &n); - if (n == 1) { - st_delete(arg->path_table, (st_data_t *)&info->path, 0); - ruby_xfree(info->path); - } - else { - st_insert(arg->path_table, (st_data_t)info->path, n-1); - } + if (st_delete(arg->object_table, (st_data_t *)&obj, (st_data_t *)&info)) { + delete_unique_str(arg->str_table, info->path); + delete_unique_str(arg->str_table, info->class_path); ruby_xfree(info); } } @@ -111,9 +136,9 @@ stop_trace_object_allocations(void *data https://github.com/ruby/ruby/blob/trunk/ext/objspace/object_tracing.c#L136 rb_tracepoint_disable(arg->newobj_trace); rb_tracepoint_disable(arg->freeobj_trace); st_foreach(arg->object_table, free_values_i, 0); - st_foreach(arg->path_table, free_keys_i, 0); + st_foreach(arg->str_table, free_keys_i, 0); st_free_table(arg->object_table); - st_free_table(arg->path_table); + st_free_table(arg->str_table); traceobj_arg = arg->prev_traceobj_arg; return Qnil; @@ -127,7 +152,7 @@ trace_object_allocations(VALUE objspace) https://github.com/ruby/ruby/blob/trunk/ext/objspace/object_tracing.c#L152 arg.newobj_trace = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_NEWOBJ, newobj_i, &arg); arg.freeobj_trace = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_FREEOBJ, freeobj_i, &arg); arg.object_table = st_init_numtable(); - arg.path_table = st_init_strtable(); + arg.str_table = st_init_strtable(); arg.prev_traceobj_arg = traceobj_arg; traceobj_arg = &arg; @@ -155,7 +180,7 @@ allocation_sourcefile(VALUE objspace, VA https://github.com/ruby/ruby/blob/trunk/ext/objspace/object_tracing.c#L180 { struct allocation_info *info = allocation_info(obj); if (info) { - return rb_str_new2(info->path); + return info->path ? rb_str_new2(info->path) : Qnil; } else { return Qnil; @@ -175,6 +200,30 @@ allocation_sourceline(VALUE objspace, VA https://github.com/ruby/ruby/blob/trunk/ext/objspace/object_tracing.c#L200 } static VALUE +allocation_class_path(VALUE objspace, VALUE obj) +{ + struct allocation_info *info = allocation_info(obj); + if (info) { + return info->class_path ? rb_str_new2(info->class_path) : Qnil; + } + else { + return Qnil; + } +} + +static VALUE +allocation_method_id(VALUE objspace, VALUE obj) +{ + struct allocation_info *info = allocation_info(obj); + if (info) { + return info->mid; + } + else { + return Qnil; + } +} + +static VALUE allocation_generation(VALUE objspace, VALUE obj) { struct allocation_info *info = allocation_info(obj); @@ -192,5 +241,7 @@ Init_object_tracing(VALUE rb_mObjSpace) https://github.com/ruby/ruby/blob/trunk/ext/objspace/object_tracing.c#L241 rb_define_module_function(rb_mObjSpace, "trace_object_allocations", trace_object_allocations, 0); rb_define_module_function(rb_mObjSpace, "allocation_sourcefile", allocation_sourcefile, 1); rb_define_module_function(rb_mObjSpace, "allocation_sourceline", allocation_sourceline, 1); + rb_define_module_function(rb_mObjSpace, "allocation_class_path", allocation_class_path, 1); + rb_define_module_function(rb_mObjSpace, "allocation_method_id", allocation_method_id, 1); rb_define_module_function(rb_mObjSpace, "allocation_generation", allocation_generation, 1); } Index: test/objspace/test_objspace.rb =================================================================== --- test/objspace/test_objspace.rb (revision 40973) +++ test/objspace/test_objspace.rb (revision 40974) @@ -112,18 +112,31 @@ class TestObjSpace < Test::Unit::TestCas https://github.com/ruby/ruby/blob/trunk/test/objspace/test_objspace.rb#L112 def test_traceobject o0 = Object.new ObjectSpace.trace_object_allocations{ - o1 = Object.new; line1 = __LINE__ - o2 = "a"+"b" ; line2 = __LINE__ - o3 = [1, 2] ; line3 = __LINE__ + o1 = Object.new; line1 = __LINE__; c1 = GC.count + o2 = "xyzzy" ; line2 = __LINE__; c2 = GC.count + o3 = [1, 2] ; line3 = __LINE__; c3 = GC.count assert_equal(nil, ObjectSpace.allocation_sourcefile(o0)) assert_equal(nil, ObjectSpace.allocation_sourceline(o0)) - assert_equal(__FILE__, ObjectSpace.allocation_sourcefile(o1)) + assert_equal(nil, ObjectSpace.allocation_generation(o0)) + assert_equal(line1, ObjectSpace.allocation_sourceline(o1)) + assert_equal(__FILE__, ObjectSpace.allocation_sourcefile(o1)) + assert_equal(c1, ObjectSpace.allocation_generation(o1)) + assert_equal(Class.name, ObjectSpace.allocation_class_path(o1)) + assert_equal(:new, ObjectSpace.allocation_method_id(o1)) + assert_equal(__FILE__, ObjectSpace.allocation_sourcefile(o2)) assert_equal(line2, ObjectSpace.allocation_sourceline(o2)) + assert_equal(c2, ObjectSpace.allocation_generation(o2)) + assert_equal(self.class.name, ObjectSpace.allocation_class_path(o2)) + assert_equal(__method__, ObjectSpace.allocation_method_id(o2)) + assert_equal(__FILE__, ObjectSpace.allocation_sourcefile(o3)) assert_equal(line3, ObjectSpace.allocation_sourceline(o3)) + assert_equal(c3, ObjectSpace.allocation_generation(o3)) + assert_equal(self.class.name, ObjectSpace.allocation_class_path(o3)) + assert_equal(__method__, ObjectSpace.allocation_method_id(o3)) } end end -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/