heap_dump 0.0.27 → 0.0.28

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