heap_dump 0.0.24 → 0.0.25

Sign up to get free protection for your applications and to get access to all the features.
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: