heap_dump 0.0.6 → 0.0.8

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
@@ -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