heap_dump 0.0.27 → 0.0.28

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,8 +1,9 @@
1
1
  # HeapDump
2
2
 
3
- Low-level ruby heap memory dump - including data and code references.
4
- Originally written across ruby 1.9.2-p290 data structures.
3
+ Low-level ruby heap memory dump - including data and code references, useful for finding leaks.
4
+ Has no performance overhead while not active, so can be used in production environment.
5
5
 
6
+ Originally written across ruby 1.9.2-p290 data structures.
6
7
  Does work on other 1.9.2s and 1.9.3, but not well-tested yet(output is not proven to be as full etc.).
7
8
 
8
9
  Currently is under development and output format may differ.
@@ -35,6 +36,10 @@ Json contains one object per line, thus can be easily grepped.
35
36
 
36
37
  ### Injecting into live process via GDB
37
38
 
39
+ For long-running applications common and recommended usecase is to have some kind of custom action or signal handler in app itself that invokes dump.
40
+
41
+ But also dump can be invoked from gdb.
42
+
38
43
  run gdb
39
44
 
40
45
  ```bash
@@ -51,7 +56,8 @@ call heapdump_dump("mydump.json")
51
56
 
52
57
  or `call heapdump_dump(0)`, filename defaults to dump.json.
53
58
 
54
- Note that ruby-internal and yajl-ruby gems should be available to process this being injected into.
59
+ Note that yajl-ruby gem (and heap_dump itself) should be available to process this being injected into.
60
+ Also on rare ocassions process(for example if gdb attached while a signal/gc) may crash after and even during dumping, so safer way is to embed it in advance, there's no performance overhead.
55
61
 
56
62
  ### Importing dump in MongoDB
57
63
 
@@ -1,4 +1,5 @@
1
1
  #include "ruby.h"
2
+ #include "ruby/encoding.h"
2
3
  #include <stdlib.h>
3
4
  #include <stdio.h>
4
5
 
@@ -107,8 +108,8 @@ static void flush_yajl(walk_ctx_t *ctx){
107
108
 
108
109
  static inline int is_in_heap(void *ptr, void* osp);
109
110
 
110
- static inline const char* rb_builtin_type(VALUE obj){
111
- switch(BUILTIN_TYPE(obj)){
111
+ static inline const char* rb_type_str(int type){
112
+ switch(type){
112
113
  #define T(t) case t: return #t;
113
114
  T(T_NONE); T(T_NIL);
114
115
  T(T_OBJECT); T(T_CLASS); T(T_ICLASS); T(T_MODULE);
@@ -124,9 +125,16 @@ static inline const char* rb_builtin_type(VALUE obj){
124
125
  T(T_NODE); // code?
125
126
  T(T_ZOMBIE);
126
127
  #undef T
128
+ default:
129
+ return "_unknown_type_";
127
130
  }
128
131
  }
129
132
 
133
+ static inline const char* rb_builtin_type(VALUE obj){
134
+ //NOTE: only for heap objects, on embedded use (TYPE(...))
135
+ return rb_type_str(BUILTIN_TYPE(obj));
136
+ }
137
+
130
138
  #define true 1
131
139
  #define false 0
132
140
 
@@ -185,7 +193,14 @@ static void yg_id1(VALUE obj, walk_ctx_t* ctx){
185
193
  if(BUILTIN_TYPE(obj) == T_STRING && (!(RBASIC(obj)->flags & RSTRING_NOEMBED))){
186
194
  //printf("embedded string\n");
187
195
  //yajl_gen_null(ctx->yajl);
188
- yg_rstring(obj);
196
+
197
+ if(rb_enc_get_index(obj) == rb_usascii_encindex())
198
+ yg_rstring(obj);
199
+ else{
200
+ //FIXME: convert encoding/safe syms etc?
201
+ //yg_cstring("(encoded string)");
202
+ yg_rstring(obj);
203
+ }
189
204
  return;
190
205
  }
191
206
 
@@ -444,7 +459,36 @@ static inline void dump_node(NODE* obj, walk_ctx_t *ctx){
444
459
 
445
460
  static int
446
461
  dump_keyvalue(st_data_t key, st_data_t value, walk_ctx_t *ctx){
447
- yg_id((VALUE)key);
462
+ if ((VALUE)key == Qundef){
463
+ printf("undef key!\n");
464
+ // return ST_CONTINUE;
465
+ }
466
+
467
+ if(!key || (VALUE)key == Qnil){
468
+ yg_cstring("___null_key___"); //TODO: just ""?
469
+ } else {
470
+ //TODO: keys must be strings
471
+ const int type = TYPE(key);
472
+ if(type == T_SYMBOL || type == T_STRING && (!(RBASIC(key)->flags & RSTRING_NOEMBED)))
473
+ yg_id((VALUE)key);
474
+ else
475
+ {
476
+ char buf[128];
477
+ buf[sizeof(buf)-1] = 0;
478
+ switch(type){
479
+ case T_FIXNUM:
480
+ snprintf(buf, sizeof(buf)-1, "%d", FIX2INT(key));
481
+ break;
482
+ case T_FLOAT:
483
+ snprintf(buf, sizeof(buf)-1, "%lg", NUM2DBL(key));
484
+ break;
485
+ default:
486
+ snprintf(buf, sizeof(buf)-1, "__id_%ld", NUM2LONG(rb_obj_id(key)));
487
+ break;
488
+ }
489
+ yg_cstring(buf);
490
+ }
491
+ }
448
492
  yg_id((VALUE)value);
449
493
  return ST_CONTINUE;
450
494
  }
@@ -512,7 +556,7 @@ static int dump_iv_entry(ID key, VALUE value, walk_ctx_t *ctx){
512
556
  if(key_str)
513
557
  yg_cstring(key_str);
514
558
  else{
515
- printf("Null key! %d\n", key);
559
+ // printf("Null key! %d\n", key);
516
560
  yg_cstring("___null_key___");
517
561
  //yg_null();
518
562
  }
@@ -935,13 +979,32 @@ static inline void walk_live_object(VALUE obj, walk_ctx_t *ctx){
935
979
  break;
936
980
  case T_STRING:
937
981
  //TODO: limit string len!
982
+ {
983
+ int enc_i = rb_enc_get_index(obj);
984
+ rb_encoding* enc = rb_enc_from_index(enc_i);
985
+ if(enc){
986
+ ygh_cstring("encoding", enc->name);
987
+ }
988
+ //FIXME: convert encoding and dump?
989
+ //if(enc_i == rb_usascii_encindex())
990
+ //this produces warnings on dump read, but recoverable
938
991
  ygh_string("val", RSTRING_PTR(obj), (unsigned int)RSTRING_LEN(obj));
992
+ }
939
993
  break;
940
994
  case T_SYMBOL:
941
995
  ygh_cstring("val", rb_id2name(SYM2ID(obj)));
942
996
  break;
943
997
  case T_REGEXP:
998
+ {
999
+ int enc_i = rb_enc_get_index(obj);
1000
+ rb_encoding* enc = rb_enc_from_index(enc_i);
1001
+ if(enc){
1002
+ ygh_cstring("encoding", enc->name);
1003
+ }
1004
+ //FIXME: encodings?
1005
+ // if(enc_i == rb_usascii_encindex())
944
1006
  ygh_string("val", RREGEXP_SRC_PTR(obj), (unsigned int)RREGEXP_SRC_LEN(obj));
1007
+ }
945
1008
  break;
946
1009
  // T(T_MATCH);
947
1010
 
@@ -1494,7 +1557,7 @@ void heapdump_dump(const char* filename){
1494
1557
 
1495
1558
  dump_machine_context(ctx);
1496
1559
  flush_yajl(ctx);
1497
- fprintf(ctx->file, "\n");
1560
+ // fprintf(ctx->file, "\n");
1498
1561
 
1499
1562
  struct gc_list *list;
1500
1563
  /* mark protected global variables */
@@ -1521,6 +1584,7 @@ void heapdump_dump(const char* filename){
1521
1584
 
1522
1585
  yajl_gen_map_close(ctx->yajl); //id:roots
1523
1586
  flush_yajl(ctx);
1587
+ fprintf(ctx->file, "\n");
1524
1588
 
1525
1589
  //now dump all live objects
1526
1590
  printf("starting objspace walk\n");
@@ -11,8 +11,8 @@ typedef struct {
11
11
 
12
12
  //#include "encoding.h" // and this also (rb_encoding + rb_econv_t)
13
13
  //FIXME: nasty:
14
- typedef int rb_encoding;
15
- typedef struct rb_econv rb_econv_t;
14
+ // typedef int rb_encoding;
15
+ // typedef struct rb_econv rb_econv_t;
16
16
 
17
17
  typedef struct rb_io_t {
18
18
  int fd; /* file descriptor */
@@ -1,3 +1,3 @@
1
1
  module HeapDump
2
- VERSION = "0.0.27"
2
+ VERSION = "0.0.28"
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.27
4
+ version: 0.0.28
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-10 00:00:00.000000000 Z
12
+ date: 2012-11-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: debugger-ruby_core_source
@@ -105,7 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
105
  version: '0'
106
106
  segments:
107
107
  - 0
108
- hash: -130654953779884601
108
+ hash: -3488312299511292318
109
109
  requirements: []
110
110
  rubyforge_project:
111
111
  rubygems_version: 1.8.24