heap_dump 0.0.6 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -17,4 +17,5 @@ test/version_tmp
17
17
  tmp
18
18
  *.bundle
19
19
  *.so
20
- *.dll
20
+ *.dll
21
+ dump.json
data/README.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # HeapDump
2
2
 
3
- TODO: Write a gem description
3
+ Low-level ruby heap memory dump - including data and code references.
4
+ Written across ruby 1.9.2-p290 data structures. Other rubies support may come later (or may not).
5
+
6
+ Currently is under development and output format may differ.
4
7
 
5
8
  ## Installation
6
9
 
@@ -18,7 +21,47 @@ Or install it yourself as:
18
21
 
19
22
  ## Usage
20
23
 
21
- TODO: Write usage instructions here
24
+ In your code call:
25
+
26
+ ```ruby
27
+
28
+ HeapDump.dump
29
+ ```
30
+
31
+ this will run GC and then create a dump.json with live heap contents.
32
+ Json contains one object per line, thus can be easily grepped.
33
+
34
+ ### Injecting into live process via GDB
35
+
36
+ run gdb
37
+
38
+ ```bash
39
+
40
+ gdb `which ruby` $YOUR_PID
41
+ ```
42
+
43
+ And then run commands like:
44
+
45
+ ```
46
+ call rb_require("/Users/vasfed/work/heap_dump/lib/heap_dump.bundle")
47
+ call heapdump_dump("mydump.json")
48
+ ```
49
+
50
+ or `call heapdump_dump(0)`, filename defaults to dump.json.
51
+
52
+ Note that ruby-internal and yajl-ruby gems should be available to process this being injected into.
53
+
54
+ ### Importing dump in MongoDB
55
+
56
+ Dump can be imported in mongo for some map-reduce, easy script access etc.
57
+
58
+ ```bash
59
+
60
+ cat dump.json | sed 's/^[,\[]//;s/\]$//;s/^{"id"/{"_id"/' | mongoimport -d database_name -c collection_name --drop --type json
61
+ ```
62
+
63
+ Note that even small dumps usually contain a few hundred thousands objects, so do not forget to add some indexes.
64
+
22
65
 
23
66
  ## Contributing
24
67
 
data/Rakefile CHANGED
@@ -3,4 +3,13 @@ require "bundler/gem_tasks"
3
3
 
4
4
 
5
5
  require 'rake/extensiontask'
6
- Rake::ExtensionTask.new('heap_dump')
6
+ Rake::ExtensionTask.new('heap_dump')
7
+
8
+ desc "Simple dump test,just to check if extension compiles and does not segfault on simple dump"
9
+ task :test => :compile do
10
+ require 'heap_dump'
11
+ puts "Dumping..."
12
+ HeapDump.dump
13
+ end
14
+
15
+ task :default => :test
@@ -3,6 +3,7 @@ require 'mkmf'
3
3
  spec = Gem::Specification.find_by_name('ruby-internal', '~>0.8.5') #FIXME: DRY (see gemfile)
4
4
  find_header('version.h', File.join(spec.gem_dir, 'ext', 'internal', 'yarv-headers'))
5
5
  find_header('yarv-headers/node.h', File.join(spec.gem_dir, 'ext', 'internal'))
6
+ find_header('internal/method/internal_method.h', File.join(spec.gem_dir, 'ext'))
6
7
 
7
8
  yajl = Gem::Specification.find_by_name('yajl-ruby', '~>1.1')
8
9
  find_header('api/yajl_gen.h', File.join(yajl.gem_dir, 'ext', 'yajl'))
@@ -15,6 +15,7 @@
15
15
 
16
16
 
17
17
  #include "yarv-headers/method.h"
18
+ #include "method/internal_method.h"
18
19
 
19
20
  #include "ruby_io.h" // need rb_io_t
20
21
 
@@ -476,7 +477,7 @@ static int dump_const_entry_i(ID key, const rb_const_entry_t *ce, walk_ctx_t *ct
476
477
  return ST_CONTINUE;
477
478
  }
478
479
 
479
- const char* iseq_type(VALUE type){
480
+ static const char* iseq_type(VALUE type){
480
481
  switch(type){
481
482
  case ISEQ_TYPE_TOP: return "top";
482
483
  case ISEQ_TYPE_METHOD: return "method";
@@ -492,7 +493,7 @@ const char* iseq_type(VALUE type){
492
493
  return "unknown";
493
494
  }
494
495
 
495
- void dump_iseq(const rb_iseq_t* iseq, walk_ctx_t *ctx){
496
+ static void dump_iseq(const rb_iseq_t* iseq, walk_ctx_t *ctx){
496
497
  if(iseq->name) ygh_rstring("name", iseq->name);
497
498
  if(iseq->filename) ygh_rstring("filename", iseq->filename);
498
499
  ygh_int("line", iseq->line_no);
@@ -520,15 +521,8 @@ void dump_iseq(const rb_iseq_t* iseq, walk_ctx_t *ctx){
520
521
  }
521
522
  }
522
523
 
523
- //!!! from 1.9.2-p290
524
- struct METHOD {
525
- VALUE recv;
526
- VALUE rclass;
527
- ID id;
528
- rb_method_entry_t me;
529
- };
530
524
 
531
- void dump_data_if_known(VALUE obj, walk_ctx_t *ctx){
525
+ static void dump_data_if_known(VALUE obj, walk_ctx_t *ctx){
532
526
 
533
527
  // VM
534
528
  // VM/env
@@ -842,11 +836,11 @@ static int objspace_walker(void *vstart, void *vend, int stride, walk_ctx_t *ctx
842
836
  // #elif defined(__i386) && defined(__GNUC__) && !defined(__native_client__)
843
837
  // #define SET_MACHINE_STACK_END(p) __asm__("movl\t%%esp, %0" : "=r" (*(p)))
844
838
  // #else
845
- NOINLINE(void rb_gc_set_stack_end(VALUE **stack_end_p));
839
+ NOINLINE(static void rb_gc_set_stack_end(VALUE **stack_end_p));
846
840
  #define SET_MACHINE_STACK_END(p) rb_gc_set_stack_end(p)
847
841
  #define USE_CONSERVATIVE_STACK_END
848
842
  // #endif
849
- void
843
+ static void
850
844
  rb_gc_set_stack_end(VALUE **stack_end_p)
851
845
  {
852
846
  VALUE stack_end;
@@ -922,6 +916,7 @@ extern st_table *rb_class_tbl;
922
916
  #endif
923
917
 
924
918
  //FIXME: this should be autoextracted from ruby
919
+ // see how this is done in ruby-internal gem
925
920
  typedef struct RVALUE {
926
921
  union {
927
922
  struct {
@@ -1241,16 +1236,17 @@ static int dump_iv_entry1(ID key, rb_const_entry_t* ce/*st_data_t val*/, walk_ct
1241
1236
  return ST_CONTINUE;
1242
1237
  }
1243
1238
 
1244
- static VALUE
1245
- rb_heapdump_dump(VALUE self, VALUE filename)
1246
- {
1239
+
1240
+ //public symbol, can be used from GDB
1241
+ void heapdump_dump(const char* filename){
1247
1242
  struct walk_ctx ctx_o, *ctx = &ctx_o;
1248
1243
  memset(ctx, 0, sizeof(*ctx));
1249
1244
 
1250
- Check_Type(filename, T_STRING);
1251
-
1252
- printf("Dump should go to %s\n", RSTRING_PTR(filename));
1253
- ctx->file = fopen(RSTRING_PTR(filename), "wt");
1245
+ if(!filename){
1246
+ filename = "dump.json";
1247
+ }
1248
+ printf("Dump should go to %s\n", filename);
1249
+ ctx->file = fopen(filename, "wt");
1254
1250
  ctx->yajl = yajl_gen_alloc(NULL,NULL);
1255
1251
  yajl_gen_array_open(ctx->yajl);
1256
1252
 
@@ -1295,18 +1291,30 @@ rb_heapdump_dump(VALUE self, VALUE filename)
1295
1291
  fclose(ctx->file);
1296
1292
 
1297
1293
  printf("Walker called %d times, seen %d live objects.\n", ctx->walker_called, ctx->live_objects);
1294
+ }
1298
1295
 
1296
+ static VALUE
1297
+ rb_heapdump_dump(VALUE self, VALUE filename)
1298
+ {
1299
+ Check_Type(filename, T_STRING);
1300
+ heapdump_dump(RSTRING_PTR(filename));
1299
1301
  return Qnil;
1300
1302
  }
1301
1303
 
1302
-
1303
1304
  void Init_heap_dump(){
1304
1305
  //ruby-internal need to be required before linking us, but just in case..
1306
+ ID require, gem;
1307
+ CONST_ID(require, "require");
1308
+ CONST_ID(gem, "gem");
1309
+ CONST_ID(classid, "__classid__");
1310
+
1311
+ rb_require("rubygems");
1312
+ rb_funcall(rb_mKernel, gem, 1, rb_str_new2("yajl-ruby"));
1313
+ rb_funcall(rb_mKernel, gem, 1, rb_str_new2("ruby-internal")); //TODO: version requirements
1305
1314
  rb_require("internal/node");
1306
1315
  rb_require("yajl");
1307
- init_node_type_descrips();
1308
1316
 
1309
- CONST_ID(classid, "__classid__");
1317
+ init_node_type_descrips();
1310
1318
 
1311
1319
  rb_mHeapDumpModule = rb_define_module("HeapDump");
1312
1320
  rb_define_singleton_method(rb_mHeapDumpModule, "dump_ext", rb_heapdump_dump, 1);
@@ -1,3 +1,3 @@
1
1
  module HeapDump
2
- VERSION = "0.0.6"
2
+ VERSION = "0.0.8"
3
3
  end
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.6
4
+ version: 0.0.8
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2012-05-30 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ruby-internal
16
- requirement: &70171206252720 !ruby/object:Gem::Requirement
16
+ requirement: &70110343222520 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 0.8.5
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70171206252720
24
+ version_requirements: *70110343222520
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: yajl-ruby
27
- requirement: &70171206251900 !ruby/object:Gem::Requirement
27
+ requirement: &70110343221760 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '1.1'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70171206251900
35
+ version_requirements: *70110343221760
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rake-compiler
38
- requirement: &70171206251120 !ruby/object:Gem::Requirement
38
+ requirement: &70110343221160 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70171206251120
46
+ version_requirements: *70110343221160
47
47
  description: dump ruby 1.9 heap contents
48
48
  email:
49
49
  - vasilyfedoseyev@gmail.com