heap_dump 0.0.24 → 0.0.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore CHANGED
@@ -18,4 +18,7 @@ tmp
18
18
  *.bundle
19
19
  *.so
20
20
  *.dll
21
- dump.json
21
+ dump.json
22
+ Makefile
23
+ *.o
24
+ mkmf.log
@@ -1,4 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ #encoding: utf-8
3
+
1
4
  require 'mkmf'
5
+ require 'debugger/ruby_core_source'
2
6
 
3
7
  def find_spec name,*requirements
4
8
  return Gem::Specification.find_by_name(name, *requirements) if Gem::Specification.respond_to? :find_by_name
@@ -19,12 +23,35 @@ def find_gem_dir(name, *req)
19
23
  gem.full_gem_path
20
24
  end
21
25
 
22
- dir = find_gem_dir('ruby-internal', '~>0.8.5') #FIXME: DRY (see gemfile)
23
- find_header('version.h', File.join(dir, 'ext', 'internal', 'yarv-headers'))
24
- find_header('yarv-headers/node.h', File.join(dir, 'ext', 'internal'))
25
- find_header('internal/method/internal_method.h', File.join(dir, 'ext'))
26
26
 
27
- yajl = find_gem_dir('yajl-ruby', '~>1.1')
27
+ gemspec = File.expand_path(File.join(File.dirname(__FILE__), '../../heap_dump.gemspec'))
28
+ spec = instance_eval(File.read(gemspec), gemspec).dependencies.find{|d|d.name == 'yajl-ruby'}
29
+ #$defs.push(format("-DREQUIRED_YAJL_VERSION=\\"%s\\"", spec.requirement)) #does not work in this form :(
30
+
31
+ yajl = find_gem_dir(spec.name, spec.requirement)
28
32
  find_header('api/yajl_gen.h', File.join(yajl, 'ext', 'yajl'))
29
33
 
30
- create_makefile('heap_dump')
34
+
35
+ hdrs = proc {
36
+ res = %w{
37
+ vm_core.h
38
+ iseq.h
39
+ node.h
40
+ method.h
41
+ }.all?{|hdr| have_header(hdr)}
42
+ # atomic.h
43
+ # constant.h
44
+
45
+ #optional:
46
+ %w{
47
+ constant.h
48
+ }.each{|h| have_header(h)}
49
+
50
+ res
51
+ }
52
+
53
+ dir_config("ruby") # allow user to pass in non-standard core include directory
54
+
55
+ if !Debugger::RubyCoreSource::create_makefile_with_core(hdrs, "heap_dump")
56
+ exit(1)
57
+ end
@@ -3,25 +3,35 @@
3
3
  #include <stdio.h>
4
4
 
5
5
 
6
- #include "yarv-headers/constant.h"
7
- #include "yarv-headers/node.h"
8
- #include "yarv-headers/vm_core.h"
9
- #include "yarv-headers/atomic.h"
10
- #include "yarv-headers/iseq.h"
11
-
12
- //#undef RCLASS_IV_TBL
13
- //#include "yarv-headers/internal.h"
6
+ #ifdef HAVE_CONSTANT_H
7
+ //have this in 1.9.3+, for future compatibility
8
+ #include "constant.h"
9
+ #else
10
+ //from 1.9.2
11
+ typedef enum {
12
+ CONST_PUBLIC = 0x00,
13
+ CONST_PRIVATE = 0x01
14
+ } rb_const_flag_t;
15
+
16
+ typedef struct rb_const_entry_struct {
17
+ rb_const_flag_t flag;
18
+ VALUE value; /* should be mark */
19
+ } rb_const_entry_t;
20
+ #endif
21
+
22
+ #include "node.h"
23
+ #include "vm_core.h"
24
+ // #include "atomic.h"
25
+ #include "iseq.h"
26
+
14
27
  #define RCLASS_EXT(c) (RCLASS(c)->ptr)
15
28
 
29
+ #define NODE_OP_ASGN2_ARG NODE_LAST + 1
16
30
 
17
- #include "yarv-headers/method.h"
18
- #include "method/internal_method.h"
31
+ #include "method.h"
19
32
 
20
33
  #include "ruby_io.h" // need rb_io_t
21
34
 
22
- #include "node/ruby_internal_node.h"
23
- #include "node/node_type_descrip.c"
24
-
25
35
  #include "api/yajl_gen.h"
26
36
 
27
37
  #ifndef RUBY_VM
@@ -163,6 +173,26 @@ static void yg_id1(VALUE obj, walk_ctx_t* ctx){
163
173
  yg_int(NUM2LONG(rb_obj_id(obj)));
164
174
  }
165
175
 
176
+ const char* node_type_name(const NODE* obj){
177
+ #define N(n) case NODE_##n: return #n;
178
+ switch(nd_type(obj)){
179
+ N(ALIAS)
180
+ #ifdef HAVE_NODE_ALLOCA
181
+ N(ALLOCA)
182
+ #endif
183
+ N(AND) N(ARGS) N(ARGSCAT) N(ARGSPUSH) N(ARRAY) N(ATTRASGN) N(BACK_REF) N(BEGIN) N(BLOCK) N(BLOCK_ARG) N(BLOCK_PASS) N(BMETHOD) N(BREAK)
184
+ N(CALL) N(CASE) N(CDECL) N(CLASS) N(COLON2) N(COLON3) N(CONST) N(CVAR) N(CVASGN) N(CVDECL) N(DASGN) N(DASGN_CURR) N(DEFINED) N(DEFN)
185
+ N(DEFS) N(DOT2) N(DOT3) N(DREGX) N(DREGX_ONCE) N(DSTR) N(DSYM) N(DVAR) N(DXSTR) N(ENSURE) N(EVSTR) N(FALSE) N(FCALL) N(FLIP2) N(FLIP3)
186
+ N(FOR) N(GASGN) N(GVAR) N(HASH) N(IASGN) N(IF) N(IFUNC) N(ITER) N(IVAR) N(LASGN) N(LIT) N(LVAR) N(MASGN) N(MATCH) N(MATCH2) N(MATCH3)
187
+ N(MEMO) N(MODULE) N(NEXT) N(NIL) N(NTH_REF) N(OPT_N) N(OP_ASGN1) N(OP_ASGN2) N(OP_ASGN2_ARG) N(OP_ASGN_AND) N(OP_ASGN_OR) N(OR) N(POSTEXE)
188
+ N(REDO) N(RESBODY) N(RESCUE) N(RETRY) N(RETURN) N(SCLASS) N(SCOPE) N(SELF) N(SPLAT) N(STR) N(SUPER) N(TO_ARY) N(TRUE) N(UNDEF) N(UNTIL)
189
+ N(VALIAS) N(VCALL) N(WHEN) N(WHILE) N(XSTR) N(YIELD) N(ZARRAY) N(ZSUPER) N(LAST)
190
+ default:
191
+ return "unknown";
192
+ };
193
+ #undef N
194
+ }
195
+
166
196
 
167
197
  static void dump_node_refs(NODE* obj, walk_ctx_t* ctx){
168
198
  switch (nd_type(obj)) {
@@ -369,9 +399,8 @@ static void dump_node_refs(NODE* obj, walk_ctx_t* ctx){
369
399
  default: /* unlisted NODE */
370
400
  //FIXME: check pointers!
371
401
 
372
- {const Node_Type_Descrip* descrip = node_type_descrips[nd_type(obj)];
373
-
374
- printf("UNKNOWN NODE TYPE %d(%s): %p %p %p\n", nd_type(obj), descrip ? descrip->name : "unknown", (void*)obj->u1.node, (void*)obj->u2.node, (void*)obj->u3.node);
402
+ {
403
+ printf("UNKNOWN NODE TYPE %d(%s): %p %p %p\n", nd_type(obj), node_type_name(obj), (void*)obj->u1.node, (void*)obj->u2.node, (void*)obj->u3.node);
375
404
  }
376
405
 
377
406
  // if (is_pointer_to_heap(objspace, obj->as.node.u1.node)) { gc_mark(objspace, (VALUE)obj->as.node.u1.node, lev); }
@@ -385,10 +414,8 @@ static void dump_node_refs(NODE* obj, walk_ctx_t* ctx){
385
414
  }
386
415
 
387
416
  static inline void dump_node(NODE* obj, walk_ctx_t *ctx){
388
- const Node_Type_Descrip* descrip = node_type_descrips[nd_type(obj)]; // node_type_descrip(nd_type(obj)) raises exception on unknown 65, 66 and 92
389
-
390
417
  ygh_int("nd_type", nd_type(obj));
391
- ygh_cstring("nd_type_str", descrip ? descrip->name : "unknown");
418
+ ygh_cstring("nd_type_str", node_type_name(obj));
392
419
 
393
420
  yg_cstring("refs");
394
421
  yajl_gen_array_open(ctx->yajl);
@@ -542,17 +569,18 @@ static void dump_block(const rb_block_t* block, walk_ctx_t *ctx){
542
569
  yg_cstring("iseq");
543
570
  yajl_gen_map_open(ctx->yajl);
544
571
  //FIXME: id may be different (due to RBasic fields)!!!
545
- ygh_id("id", block->iseq);
572
+ ygh_id("id", (VALUE)block->iseq);
546
573
  dump_iseq(block->iseq, ctx);
547
574
  yajl_gen_map_close(ctx->yajl);
548
575
  } else {
549
- ygh_id("iseq", block->iseq);
576
+ ygh_id("iseq", (VALUE)block->iseq);
550
577
  }
551
578
 
552
579
  ygh_id("self", block->self);
553
580
 
554
- ygh_id("lfp", block->lfp);
555
- ygh_id("dfp", block->dfp);
581
+ //FIXME: these are pointers to some memory, may be dumped more clever
582
+ ygh_id("lfp", (VALUE)block->lfp);
583
+ ygh_id("dfp", (VALUE)block->dfp);
556
584
  //lfp = local frame pointer? local_num elems?
557
585
  // dfp = ?
558
586
  }
@@ -627,19 +655,19 @@ static void yg_fiber_type(enum context_type status, walk_ctx_t* ctx){
627
655
  }
628
656
  }
629
657
 
630
- static void dump_locations(VALUE* p, int n, walk_ctx_t *ctx){
658
+ static void dump_locations(VALUE* p, long int n, walk_ctx_t *ctx){
631
659
  if(n > 0){
632
660
  VALUE* x = p;
633
661
  while(n--){
634
662
  VALUE v = *x;
635
- if(is_pointer_to_heap(v, NULL)) //TODO: sometimes thread is known, may get its th->vm->objspace (in case there's a few)
663
+ if(is_pointer_to_heap((void*)v, NULL)) //TODO: sometimes thread is known, may get its th->vm->objspace (in case there's a few)
636
664
  yg_id(v);
637
665
  x++;
638
666
  }
639
667
  }
640
668
  }
641
669
 
642
- static void dump_thread(rb_thread_t* th, walk_ctx_t *ctx);
670
+ static void dump_thread(const rb_thread_t* th, walk_ctx_t *ctx);
643
671
 
644
672
 
645
673
  vm_dump_each_thread_func(st_data_t key, VALUE obj, walk_ctx_t *ctx){
@@ -655,6 +683,15 @@ vm_dump_each_thread_func(st_data_t key, VALUE obj, walk_ctx_t *ctx){
655
683
  return ST_CONTINUE;
656
684
  }
657
685
 
686
+ //FIXME: parse this from ruby source!
687
+ struct METHOD {
688
+ //for 1.9.2 only
689
+ VALUE recv;
690
+ VALUE rclass;
691
+ ID id;
692
+ rb_method_entry_t me;
693
+ };
694
+
658
695
 
659
696
  static void dump_data_if_known(VALUE obj, walk_ctx_t *ctx){
660
697
 
@@ -686,7 +723,7 @@ static void dump_data_if_known(VALUE obj, walk_ctx_t *ctx){
686
723
  const st_table *tbl = RTYPEDDATA_DATA(obj);
687
724
  yg_cstring("val");
688
725
  yajl_gen_map_open(ctx->yajl);
689
- st_foreach(tbl, dump_method_entry_i, (st_data_t)ctx);
726
+ st_foreach((st_table *)tbl, dump_method_entry_i, (st_data_t)ctx); //removing const, but this should not affect hash
690
727
  yajl_gen_map_close(ctx->yajl);
691
728
  return;
692
729
  }
@@ -817,7 +854,7 @@ static void dump_data_if_known(VALUE obj, walk_ctx_t *ctx){
817
854
  if (vm->living_threads) {
818
855
  yg_cstring("threads");
819
856
  yg_array();
820
- st_foreach(vm->living_threads, vm_dump_each_thread_func, ctx);
857
+ st_foreach(vm->living_threads, vm_dump_each_thread_func, (st_data_t)ctx);
821
858
  yg_array_end();
822
859
  }
823
860
  // rb_gc_mark_locations(vm->special_exceptions, vm->special_exceptions + ruby_special_error_count);
@@ -1493,8 +1530,9 @@ is_pointer_to_heap(void *ptr, void* osp)
1493
1530
 
1494
1531
 
1495
1532
  static int
1496
- dump_backtrace(walk_ctx_t *ctx, VALUE file, int line, VALUE method)
1533
+ dump_backtrace(void* data, VALUE file, int line, VALUE method)
1497
1534
  {
1535
+ walk_ctx_t *ctx = data;
1498
1536
  yg_map();
1499
1537
  const char *filename = NIL_P(file) ? "<ruby>" : RSTRING_PTR(file);
1500
1538
 
@@ -1515,7 +1553,7 @@ dump_backtrace(walk_ctx_t *ctx, VALUE file, int line, VALUE method)
1515
1553
  //TODO: autogen, this func is just copied from vm.c
1516
1554
  //typedef int rb_backtrace_iter_func(void *, VALUE, int, VALUE);
1517
1555
  static int
1518
- vm_backtrace_each(rb_thread_t *th, int lev, void (*init)(void *), rb_backtrace_iter_func *iter, void *arg)
1556
+ vm_backtrace_each(const rb_thread_t *th, int lev, void (*init)(void *), rb_backtrace_iter_func *iter, void *arg)
1519
1557
  {
1520
1558
  const rb_control_frame_t *limit_cfp = th->cfp;
1521
1559
  const rb_control_frame_t *cfp = (void *)(th->stack + th->stack_size);
@@ -1558,7 +1596,7 @@ vm_backtrace_each(rb_thread_t *th, int lev, void (*init)(void *), rb_backtrace_i
1558
1596
  return TRUE;
1559
1597
  }
1560
1598
 
1561
- static void dump_thread(rb_thread_t* th, walk_ctx_t *ctx){
1599
+ static void dump_thread(const rb_thread_t* th, walk_ctx_t *ctx){
1562
1600
  if(th->stack){
1563
1601
  VALUE *p = th->stack;
1564
1602
  VALUE *sp = th->cfp->sp;
@@ -1655,7 +1693,7 @@ static void dump_thread(rb_thread_t* th, walk_ctx_t *ctx){
1655
1693
  yg_cstring("local_storage");
1656
1694
  yajl_gen_array_open(ctx->yajl);
1657
1695
  if(th->local_storage){
1658
- st_foreach(th->local_storage, dump_iv_entry, ctx); //?
1696
+ st_foreach(th->local_storage, dump_iv_entry, (st_data_t)ctx); //?
1659
1697
  }
1660
1698
  yajl_gen_array_close(ctx->yajl);
1661
1699
 
@@ -1834,12 +1872,8 @@ void Init_heap_dump(){
1834
1872
 
1835
1873
  rb_require("rubygems");
1836
1874
  rb_funcall(rb_mKernel, gem, 1, rb_str_new2("yajl-ruby"));
1837
- rb_funcall(rb_mKernel, gem, 1, rb_str_new2("ruby-internal")); //TODO: version requirements
1838
- rb_require("internal/node");
1839
1875
  rb_require("yajl");
1840
1876
 
1841
- init_node_type_descrips();
1842
-
1843
1877
  rb_mHeapDumpModule = rb_define_module("HeapDump");
1844
1878
  rb_define_singleton_method(rb_mHeapDumpModule, "dump_ext", rb_heapdump_dump, 1);
1845
1879
  }
data/heap_dump.gemspec CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |gem|
20
20
 
21
21
  gem.extensions = "ext/heap_dump/extconf.rb"
22
22
 
23
- gem.add_dependency "ruby-internal", '~>0.8.5'
23
+ gem.add_dependency "debugger-ruby_core_source"
24
24
  gem.add_dependency 'yajl-ruby', '~>1.1'
25
25
  gem.add_development_dependency "rake-compiler"
26
26
  end
@@ -1,3 +1,3 @@
1
1
  module HeapDump
2
- VERSION = "0.0.24"
2
+ VERSION = "0.0.25"
3
3
  end
data/lib/heap_dump.rb CHANGED
@@ -1,9 +1,5 @@
1
1
  require "heap_dump/version"
2
2
 
3
- # need to require ruby-internal before our extension so that these extensions are loaded and linked
4
- require 'internal/node'
5
- require 'yajl'
6
-
7
3
  require 'rbconfig'
8
4
  require "heap_dump.#{RbConfig::CONFIG['DLEXT']}"
9
5
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: heap_dump
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.24
4
+ version: 0.0.25
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,22 +9,27 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-13 00:00:00.000000000Z
12
+ date: 2012-10-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: ruby-internal
16
- requirement: &70182669210140 !ruby/object:Gem::Requirement
15
+ name: debugger-ruby_core_source
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
- - - ~>
19
+ - - ! '>='
20
20
  - !ruby/object:Gem::Version
21
- version: 0.8.5
21
+ version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70182669210140
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: yajl-ruby
27
- requirement: &70182669209560 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
35
  - - ~>
@@ -32,10 +37,15 @@ dependencies:
32
37
  version: '1.1'
33
38
  type: :runtime
34
39
  prerelease: false
35
- version_requirements: *70182669209560
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '1.1'
36
46
  - !ruby/object:Gem::Dependency
37
47
  name: rake-compiler
38
- requirement: &70182669209100 !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
39
49
  none: false
40
50
  requirements:
41
51
  - - ! '>='
@@ -43,7 +53,12 @@ dependencies:
43
53
  version: '0'
44
54
  type: :development
45
55
  prerelease: false
46
- version_requirements: *70182669209100
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
47
62
  description: Ruby 1.9 heap contents dumper
48
63
  email:
49
64
  - vasilyfedoseyev@gmail.com
@@ -81,12 +96,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
81
96
  - - ! '>='
82
97
  - !ruby/object:Gem::Version
83
98
  version: '0'
99
+ segments:
100
+ - 0
101
+ hash: -3428409175290370269
84
102
  requirements: []
85
103
  rubyforge_project:
86
- rubygems_version: 1.8.15
104
+ rubygems_version: 1.8.24
87
105
  signing_key:
88
106
  specification_version: 3
89
107
  summary: Allows to dump heap to track reference leaks, including leaks in proc contexts
90
108
  and fibers
91
109
  test_files: []
92
- has_rdoc: