heap_dump 0.0.25 → 0.0.26
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 +1 -0
- data/README.md +3 -1
- data/ext/heap_dump/extconf.rb +5 -0
- data/ext/heap_dump/heap_dump.c +55 -383
- data/ext/heap_dump/specific/ruby-1.9.2/fiber.h +48 -0
- data/ext/heap_dump/specific/ruby-1.9.2/gc_internal.h +192 -0
- data/ext/heap_dump/specific/ruby-1.9.2/internal_constant.h +10 -0
- data/ext/heap_dump/specific/ruby-1.9.2/internal_typed_data.h +45 -0
- data/ext/heap_dump/specific/ruby-1.9.3/fiber.h +53 -0
- data/ext/heap_dump/specific/ruby-1.9.3/gc_internal.h +191 -0
- data/ext/heap_dump/specific/ruby-1.9.3/internal_typed_data.h +51 -0
- data/heap_dump.gemspec +1 -1
- data/lib/heap_dump/version.rb +1 -1
- metadata +11 -4
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
# HeapDump
|
2
2
|
|
3
3
|
Low-level ruby heap memory dump - including data and code references.
|
4
|
-
|
4
|
+
Originally written across ruby 1.9.2-p290 data structures.
|
5
|
+
|
6
|
+
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.).
|
5
7
|
|
6
8
|
Currently is under development and output format may differ.
|
7
9
|
|
data/ext/heap_dump/extconf.rb
CHANGED
@@ -31,6 +31,10 @@ spec = instance_eval(File.read(gemspec), gemspec).dependencies.find{|d|d.name ==
|
|
31
31
|
yajl = find_gem_dir(spec.name, spec.requirement)
|
32
32
|
find_header('api/yajl_gen.h', File.join(yajl, 'ext', 'yajl'))
|
33
33
|
|
34
|
+
#TODO: inject ruby version
|
35
|
+
unless find_header("gc_internal.h", File.join(File.dirname(__FILE__),'specific', "ruby-#{RUBY_VERSION}")) && have_header("gc_internal.h")
|
36
|
+
raise "Do not have internal structs for your ruby version"
|
37
|
+
end
|
34
38
|
|
35
39
|
hdrs = proc {
|
36
40
|
res = %w{
|
@@ -45,6 +49,7 @@ hdrs = proc {
|
|
45
49
|
#optional:
|
46
50
|
%w{
|
47
51
|
constant.h
|
52
|
+
internal.h
|
48
53
|
}.each{|h| have_header(h)}
|
49
54
|
|
50
55
|
res
|
data/ext/heap_dump/heap_dump.c
CHANGED
@@ -4,19 +4,10 @@
|
|
4
4
|
|
5
5
|
|
6
6
|
#ifdef HAVE_CONSTANT_H
|
7
|
-
//have this in 1.9.3
|
7
|
+
//have this in 1.9.3
|
8
8
|
#include "constant.h"
|
9
9
|
#else
|
10
|
-
|
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;
|
10
|
+
#include "internal_constant.h"
|
20
11
|
#endif
|
21
12
|
|
22
13
|
#include "node.h"
|
@@ -24,10 +15,25 @@
|
|
24
15
|
// #include "atomic.h"
|
25
16
|
#include "iseq.h"
|
26
17
|
|
18
|
+
#ifdef HAVE_INTERNAL_H
|
19
|
+
#include "internal.h"
|
20
|
+
#else
|
27
21
|
#define RCLASS_EXT(c) (RCLASS(c)->ptr)
|
22
|
+
#endif
|
28
23
|
|
29
24
|
#define NODE_OP_ASGN2_ARG NODE_LAST + 1
|
30
25
|
|
26
|
+
#ifndef FALSE
|
27
|
+
# define FALSE 0
|
28
|
+
#elif FALSE
|
29
|
+
# error FALSE must be false
|
30
|
+
#endif
|
31
|
+
#ifndef TRUE
|
32
|
+
# define TRUE 1
|
33
|
+
#elif !TRUE
|
34
|
+
# error TRUE must be true
|
35
|
+
#endif
|
36
|
+
|
31
37
|
#include "method.h"
|
32
38
|
|
33
39
|
#include "ruby_io.h" // need rb_io_t
|
@@ -40,6 +46,18 @@
|
|
40
46
|
|
41
47
|
// simple test - rake compile && bundle exec ruby -e 'require "heap_dump"; HeapDump.dump'
|
42
48
|
|
49
|
+
|
50
|
+
#ifdef HAVE_GC_INTERNAL_H
|
51
|
+
#include "gc_internal.h"
|
52
|
+
#else
|
53
|
+
#error No internal gc header for your ruby
|
54
|
+
//TODO: just do not dump something?
|
55
|
+
#endif
|
56
|
+
|
57
|
+
#include "fiber.h"
|
58
|
+
#include "internal_typed_data.h"
|
59
|
+
|
60
|
+
|
43
61
|
static VALUE rb_mHeapDumpModule;
|
44
62
|
|
45
63
|
static ID classid;
|
@@ -86,7 +104,7 @@ static void flush_yajl(walk_ctx_t *ctx){
|
|
86
104
|
}
|
87
105
|
}
|
88
106
|
|
89
|
-
static inline int
|
107
|
+
static inline int is_in_heap(void *ptr, void* osp);
|
90
108
|
|
91
109
|
static inline const char* rb_builtin_type(VALUE obj){
|
92
110
|
switch(BUILTIN_TYPE(obj)){
|
@@ -351,7 +369,7 @@ static void dump_node_refs(NODE* obj, walk_ctx_t* ctx){
|
|
351
369
|
unsigned long n = obj->u3.cnt;
|
352
370
|
while (n--) {
|
353
371
|
//v = *x;
|
354
|
-
// if (
|
372
|
+
// if (is_in_heap((void *)v), objspace) {
|
355
373
|
// //gc_mark(objspace, v, 0);
|
356
374
|
yg_id(*x);
|
357
375
|
// }
|
@@ -383,12 +401,12 @@ static void dump_node_refs(NODE* obj, walk_ctx_t* ctx){
|
|
383
401
|
//iteration func - blocks,procs,lambdas etc:
|
384
402
|
case NODE_IFUNC: //NEN_CFNC, NEN_TVAL, NEN_STATE? / u2 seems to be data for func(context?)
|
385
403
|
//printf("IFUNC NODE: %p %p %p\n", obj->nd_cfnc, obj->u2.node, (void*)obj->nd_aid /*u3 - aid id- - aka frame_this_func?*/);
|
386
|
-
if(
|
404
|
+
if(is_in_heap(obj->u2.node, 0)){
|
387
405
|
//printf("in heap: %p\n", obj->u2.node);
|
388
406
|
//TODO: do we need to dump it inline?
|
389
407
|
yg_id((VALUE)obj->u2.node);
|
390
408
|
}
|
391
|
-
if(
|
409
|
+
if(is_in_heap( (void*)obj->nd_aid, 0)){
|
392
410
|
//printf("in heap: %p\n", (void*)obj->nd_aid);
|
393
411
|
yg_id(obj->nd_aid);
|
394
412
|
}
|
@@ -403,9 +421,9 @@ static void dump_node_refs(NODE* obj, walk_ctx_t* ctx){
|
|
403
421
|
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);
|
404
422
|
}
|
405
423
|
|
406
|
-
// if (
|
407
|
-
// if (
|
408
|
-
// if (
|
424
|
+
// if (is_in_heap(obj->as.node.u1.node, objspace)) { gc_mark(objspace, (VALUE)obj->as.node.u1.node, lev); }
|
425
|
+
// if (is_in_heap(obj->as.node.u2.node, objspace)) { gc_mark(objspace, (VALUE)obj->as.node.u2.node, lev); }
|
426
|
+
// if (is_in_heap(obj->as.node.u3.node, objspace)) { gc_mark(objspace, (VALUE)obj->as.node.u3.node, lev); }
|
409
427
|
|
410
428
|
//yg_id((VALUE)obj->u1.node);
|
411
429
|
//yg_id((VALUE)obj->u2.node);
|
@@ -586,58 +604,6 @@ static void dump_block(const rb_block_t* block, walk_ctx_t *ctx){
|
|
586
604
|
}
|
587
605
|
|
588
606
|
|
589
|
-
#define CAPTURE_JUST_VALID_VM_STACK 1
|
590
|
-
|
591
|
-
enum context_type {
|
592
|
-
CONTINUATION_CONTEXT = 0,
|
593
|
-
FIBER_CONTEXT = 1,
|
594
|
-
ROOT_FIBER_CONTEXT = 2
|
595
|
-
};
|
596
|
-
|
597
|
-
typedef struct rb_context_struct {
|
598
|
-
enum context_type type;
|
599
|
-
VALUE self;
|
600
|
-
int argc;
|
601
|
-
VALUE value;
|
602
|
-
VALUE *vm_stack;
|
603
|
-
#ifdef CAPTURE_JUST_VALID_VM_STACK
|
604
|
-
size_t vm_stack_slen; /* length of stack (head of th->stack) */
|
605
|
-
size_t vm_stack_clen; /* length of control frames (tail of th->stack) */
|
606
|
-
#endif
|
607
|
-
VALUE *machine_stack;
|
608
|
-
VALUE *machine_stack_src;
|
609
|
-
#ifdef __ia64
|
610
|
-
VALUE *machine_register_stack;
|
611
|
-
VALUE *machine_register_stack_src;
|
612
|
-
int machine_register_stack_size;
|
613
|
-
#endif
|
614
|
-
rb_thread_t saved_thread;
|
615
|
-
rb_jmpbuf_t jmpbuf;
|
616
|
-
size_t machine_stack_size;
|
617
|
-
} rb_context_t;
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
enum fiber_status {
|
622
|
-
CREATED,
|
623
|
-
RUNNING,
|
624
|
-
TERMINATED
|
625
|
-
};
|
626
|
-
|
627
|
-
///TODO: move this out
|
628
|
-
typedef struct rb_fiber_struct {
|
629
|
-
rb_context_t cont;
|
630
|
-
VALUE prev;
|
631
|
-
enum fiber_status status;
|
632
|
-
struct rb_fiber_struct *prev_fiber;
|
633
|
-
struct rb_fiber_struct *next_fiber;
|
634
|
-
} rb_fiber_t;
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
607
|
|
642
608
|
static void yg_fiber_status(enum fiber_status status, walk_ctx_t* ctx){
|
643
609
|
switch(status){
|
@@ -660,7 +626,7 @@ static void dump_locations(VALUE* p, long int n, walk_ctx_t *ctx){
|
|
660
626
|
VALUE* x = p;
|
661
627
|
while(n--){
|
662
628
|
VALUE v = *x;
|
663
|
-
if(
|
629
|
+
if(is_in_heap((void*)v, NULL)) //TODO: sometimes thread is known, may get its th->vm->objspace (in case there's a few)
|
664
630
|
yg_id(v);
|
665
631
|
x++;
|
666
632
|
}
|
@@ -683,15 +649,6 @@ vm_dump_each_thread_func(st_data_t key, VALUE obj, walk_ctx_t *ctx){
|
|
683
649
|
return ST_CONTINUE;
|
684
650
|
}
|
685
651
|
|
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
|
-
|
695
652
|
|
696
653
|
static void dump_data_if_known(VALUE obj, walk_ctx_t *ctx){
|
697
654
|
|
@@ -757,9 +714,9 @@ static void dump_data_if_known(VALUE obj, walk_ctx_t *ctx){
|
|
757
714
|
ygh_int("method_id", data->id);
|
758
715
|
|
759
716
|
yg_cstring("method");
|
760
|
-
if(data
|
717
|
+
if(METHOD_DEFINITIONP(data)){
|
761
718
|
//printf("methof def %p\n", &data->me);
|
762
|
-
dump_method_definition_as_value(data
|
719
|
+
dump_method_definition_as_value(METHOD_DEFINITIONP(data), ctx);
|
763
720
|
//printf("meth end\n");
|
764
721
|
}
|
765
722
|
return;
|
@@ -794,27 +751,6 @@ static void dump_data_if_known(VALUE obj, walk_ctx_t *ctx){
|
|
794
751
|
return;
|
795
752
|
}
|
796
753
|
|
797
|
-
//FIXME: autogen this:
|
798
|
-
struct enumerator {
|
799
|
-
VALUE obj;
|
800
|
-
ID meth;
|
801
|
-
VALUE args;
|
802
|
-
VALUE fib;
|
803
|
-
VALUE dst;
|
804
|
-
VALUE lookahead;
|
805
|
-
VALUE feedvalue;
|
806
|
-
VALUE stop_exc;
|
807
|
-
};
|
808
|
-
|
809
|
-
struct generator {
|
810
|
-
VALUE proc;
|
811
|
-
};
|
812
|
-
|
813
|
-
struct yielder {
|
814
|
-
VALUE proc;
|
815
|
-
};
|
816
|
-
// end of fixme
|
817
|
-
|
818
754
|
if(!strcmp("enumerator", typename)){
|
819
755
|
struct enumerator *ptr = RTYPEDDATA_DATA(obj);
|
820
756
|
ygh_id("obj", ptr->obj);
|
@@ -929,12 +865,6 @@ static void dump_data_if_known(VALUE obj, walk_ctx_t *ctx){
|
|
929
865
|
return;
|
930
866
|
}
|
931
867
|
|
932
|
-
//FIXME: autogen this from ruby (this copied from 1.9.2p290)
|
933
|
-
struct thgroup {
|
934
|
-
int enclosed;
|
935
|
-
VALUE group;
|
936
|
-
};
|
937
|
-
|
938
868
|
if(!strcmp("thgroup", typename)){
|
939
869
|
const struct thgroup* gr = RTYPEDDATA_DATA(obj);
|
940
870
|
ygh_id("group", gr->group);
|
@@ -1150,10 +1080,11 @@ static inline void walk_live_object(VALUE obj, walk_ctx_t *ctx){
|
|
1150
1080
|
case T_DATA: // data of extensions + raw bytecode etc., refs undumpable? maybe in some way mess with mark callback? (need to intercept rb_gc_mark :( )
|
1151
1081
|
if(RTYPEDDATA_P(obj)){
|
1152
1082
|
ygh_cstring("type_name", RTYPEDDATA_TYPE(obj)->wrap_struct_name);
|
1153
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1083
|
+
#if HAVE_RB_DATA_TYPE_T_FUNCTION
|
1084
|
+
if(RTYPEDDATA_TYPE(obj)->function.dsize) ygh_int("size", RTYPEDDATA_TYPE(obj)->function.dsize(RTYPEDDATA_DATA(obj)));
|
1085
|
+
#else
|
1086
|
+
if(RTYPEDDATA_TYPE(obj)->dsize) ygh_int("size", RTYPEDDATA_TYPE(obj)->dsize(RTYPEDDATA_DATA(obj)));
|
1087
|
+
#endif
|
1157
1088
|
dump_data_if_known(obj, ctx);
|
1158
1089
|
}
|
1159
1090
|
break;
|
@@ -1255,276 +1186,15 @@ ruby_get_stack_grow_direction(volatile VALUE *addr)
|
|
1255
1186
|
|
1256
1187
|
#define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
|
1257
1188
|
|
1258
|
-
extern st_table *rb_class_tbl;
|
1259
|
-
|
1260
1189
|
|
1261
1190
|
/////////////
|
1262
|
-
#define MARK_STACK_MAX 1024
|
1263
|
-
|
1264
|
-
#ifndef CALC_EXACT_MALLOC_SIZE
|
1265
|
-
#define CALC_EXACT_MALLOC_SIZE 0
|
1266
|
-
#endif
|
1267
|
-
#include "ruby/re.h"
|
1268
|
-
|
1269
|
-
#ifndef FALSE
|
1270
|
-
# define FALSE 0
|
1271
|
-
#elif FALSE
|
1272
|
-
# error FALSE must be false
|
1273
|
-
#endif
|
1274
|
-
#ifndef TRUE
|
1275
|
-
# define TRUE 1
|
1276
|
-
#elif !TRUE
|
1277
|
-
# error TRUE must be true
|
1278
|
-
#endif
|
1279
|
-
|
1280
|
-
//FIXME: this should be autoextracted from ruby
|
1281
|
-
// see how this is done in ruby-internal gem
|
1282
|
-
typedef struct RVALUE {
|
1283
|
-
union {
|
1284
|
-
struct {
|
1285
|
-
VALUE flags; /* always 0 for freed obj */
|
1286
|
-
struct RVALUE *next;
|
1287
|
-
} free;
|
1288
|
-
struct RBasic basic;
|
1289
|
-
struct RObject object;
|
1290
|
-
struct RClass klass;
|
1291
|
-
struct RFloat flonum;
|
1292
|
-
struct RString string;
|
1293
|
-
struct RArray array;
|
1294
|
-
struct RRegexp regexp;
|
1295
|
-
struct RHash hash;
|
1296
|
-
struct RData data;
|
1297
|
-
struct RTypedData typeddata;
|
1298
|
-
struct RStruct rstruct;
|
1299
|
-
struct RBignum bignum;
|
1300
|
-
struct RFile file;
|
1301
|
-
struct RNode node;
|
1302
|
-
struct RMatch match;
|
1303
|
-
struct RRational rational;
|
1304
|
-
struct RComplex complex;
|
1305
|
-
} as;
|
1306
|
-
#ifdef GC_DEBUG
|
1307
|
-
const char *file;
|
1308
|
-
int line;
|
1309
|
-
#endif
|
1310
|
-
} RVALUE;
|
1311
|
-
|
1312
|
-
typedef struct gc_profile_record {
|
1313
|
-
double gc_time;
|
1314
|
-
double gc_mark_time;
|
1315
|
-
double gc_sweep_time;
|
1316
|
-
double gc_invoke_time;
|
1317
|
-
|
1318
|
-
size_t heap_use_slots;
|
1319
|
-
size_t heap_live_objects;
|
1320
|
-
size_t heap_free_objects;
|
1321
|
-
size_t heap_total_objects;
|
1322
|
-
size_t heap_use_size;
|
1323
|
-
size_t heap_total_size;
|
1324
|
-
|
1325
|
-
int have_finalize;
|
1326
|
-
int is_marked;
|
1327
|
-
|
1328
|
-
size_t allocate_increase;
|
1329
|
-
size_t allocate_limit;
|
1330
|
-
} gc_profile_record;
|
1331
|
-
|
1332
|
-
struct heaps_slot {
|
1333
|
-
void *membase;
|
1334
|
-
RVALUE *slot;
|
1335
|
-
size_t limit;
|
1336
|
-
uintptr_t *bits;
|
1337
|
-
RVALUE *freelist;
|
1338
|
-
struct heaps_slot *next;
|
1339
|
-
struct heaps_slot *prev;
|
1340
|
-
struct heaps_slot *free_next;
|
1341
|
-
};
|
1342
|
-
|
1343
|
-
struct heaps_header {
|
1344
|
-
struct heaps_slot *base;
|
1345
|
-
uintptr_t *bits;
|
1346
|
-
};
|
1347
|
-
|
1348
|
-
struct sorted_heaps_slot {
|
1349
|
-
RVALUE *start;
|
1350
|
-
RVALUE *end;
|
1351
|
-
struct heaps_slot *slot;
|
1352
|
-
};
|
1353
|
-
|
1354
|
-
struct heaps_free_bitmap {
|
1355
|
-
struct heaps_free_bitmap *next;
|
1356
|
-
};
|
1357
|
-
|
1358
|
-
struct gc_list {
|
1359
|
-
VALUE *varptr;
|
1360
|
-
struct gc_list *next;
|
1361
|
-
};
|
1362
|
-
|
1363
|
-
|
1364
|
-
// typedef struct rb_objspace {
|
1365
|
-
// struct {
|
1366
|
-
// size_t limit;
|
1367
|
-
// size_t increase;
|
1368
|
-
// //FIXME: this should match ruby settings
|
1369
|
-
// //#if CALC_EXACT_MALLOC_SIZE
|
1370
|
-
// size_t allocated_size;
|
1371
|
-
// size_t allocations;
|
1372
|
-
// //#endif
|
1373
|
-
// } malloc_params;
|
1374
|
-
|
1375
|
-
// struct {
|
1376
|
-
// size_t increment;
|
1377
|
-
// struct heaps_slot *ptr;
|
1378
|
-
// struct heaps_slot *sweep_slots;
|
1379
|
-
// struct heaps_slot *free_slots;
|
1380
|
-
// struct sorted_heaps_slot *sorted;
|
1381
|
-
// size_t length;
|
1382
|
-
// size_t used;
|
1383
|
-
// struct heaps_free_bitmap *free_bitmap;
|
1384
|
-
// RVALUE *range[2];
|
1385
|
-
// RVALUE *freed;
|
1386
|
-
// size_t live_num;
|
1387
|
-
// size_t free_num;
|
1388
|
-
// size_t free_min;
|
1389
|
-
// size_t final_num;
|
1390
|
-
// size_t do_heap_free;
|
1391
|
-
// } heap;
|
1392
|
-
|
1393
|
-
// struct {
|
1394
|
-
// int dont_gc;
|
1395
|
-
// int dont_lazy_sweep;
|
1396
|
-
// int during_gc;
|
1397
|
-
// rb_atomic_t finalizing;
|
1398
|
-
// } flags;
|
1399
|
-
|
1400
|
-
// struct {
|
1401
|
-
// st_table *table;
|
1402
|
-
// RVALUE *deferred;
|
1403
|
-
// } final;
|
1404
|
-
|
1405
|
-
// struct {
|
1406
|
-
// VALUE buffer[MARK_STACK_MAX];
|
1407
|
-
// VALUE *ptr;
|
1408
|
-
// int overflow;
|
1409
|
-
// } markstack;
|
1410
|
-
|
1411
|
-
// struct {
|
1412
|
-
// int run;
|
1413
|
-
// gc_profile_record *record;
|
1414
|
-
// size_t count;
|
1415
|
-
// size_t size;
|
1416
|
-
// double invoke_time;
|
1417
|
-
// } profile;
|
1418
|
-
|
1419
|
-
// struct gc_list *global_list;
|
1420
|
-
// size_t count;
|
1421
|
-
// int gc_stress;
|
1422
|
-
// } rb_objspace_t;
|
1423
|
-
|
1424
|
-
|
1425
|
-
// 1.9.2-p290:
|
1426
|
-
typedef struct rb_objspace {
|
1427
|
-
struct {
|
1428
|
-
size_t limit;
|
1429
|
-
size_t increase;
|
1430
|
-
#if CALC_EXACT_MALLOC_SIZE
|
1431
|
-
size_t allocated_size;
|
1432
|
-
size_t allocations;
|
1433
|
-
#endif
|
1434
|
-
} malloc_params;
|
1435
|
-
struct {
|
1436
|
-
size_t increment;
|
1437
|
-
struct heaps_slot *ptr;
|
1438
|
-
size_t length;
|
1439
|
-
size_t used;
|
1440
|
-
RVALUE *freelist;
|
1441
|
-
RVALUE *range[2];
|
1442
|
-
RVALUE *freed;
|
1443
|
-
} heap;
|
1444
|
-
struct {
|
1445
|
-
int dont_gc;
|
1446
|
-
int during_gc;
|
1447
|
-
} flags;
|
1448
|
-
struct {
|
1449
|
-
st_table *table;
|
1450
|
-
RVALUE *deferred;
|
1451
|
-
} final;
|
1452
|
-
struct {
|
1453
|
-
VALUE buffer[MARK_STACK_MAX];
|
1454
|
-
VALUE *ptr;
|
1455
|
-
int overflow;
|
1456
|
-
} markstack;
|
1457
|
-
struct {
|
1458
|
-
int run;
|
1459
|
-
gc_profile_record *record;
|
1460
|
-
size_t count;
|
1461
|
-
size_t size;
|
1462
|
-
double invoke_time;
|
1463
|
-
} profile;
|
1464
|
-
struct gc_list *global_list;
|
1465
|
-
unsigned int count;
|
1466
|
-
int gc_stress;
|
1467
|
-
} rb_objspace_t;
|
1468
|
-
|
1469
|
-
#define malloc_limit objspace->malloc_params.limit
|
1470
|
-
#define malloc_increase objspace->malloc_params.increase
|
1471
|
-
#define heaps objspace->heap.ptr
|
1472
|
-
#define heaps_length objspace->heap.length
|
1473
|
-
#define heaps_used objspace->heap.used
|
1474
|
-
#define lomem objspace->heap.range[0]
|
1475
|
-
#define himem objspace->heap.range[1]
|
1476
|
-
#define heaps_inc objspace->heap.increment
|
1477
|
-
#define heaps_freed objspace->heap.freed
|
1478
|
-
#define dont_gc objspace->flags.dont_gc
|
1479
|
-
#define during_gc objspace->flags.during_gc
|
1480
|
-
#define finalizing objspace->flags.finalizing
|
1481
|
-
#define finalizer_table objspace->final.table
|
1482
|
-
#define deferred_final_list objspace->final.deferred
|
1483
|
-
#define mark_stack objspace->markstack.buffer
|
1484
|
-
#define mark_stack_ptr objspace->markstack.ptr
|
1485
|
-
#define mark_stack_overflow objspace->markstack.overflow
|
1486
|
-
#define global_List objspace->global_list
|
1487
|
-
|
1488
|
-
#define RANY(o) ((RVALUE*)(o))
|
1489
|
-
|
1490
|
-
static inline int
|
1491
|
-
is_pointer_to_heap(void *ptr, void* osp)
|
1492
|
-
{
|
1493
|
-
rb_objspace_t *objspace = osp;
|
1494
|
-
if(!ptr) return false;
|
1495
|
-
if(!objspace) objspace = GET_THREAD()->vm->objspace;
|
1496
1191
|
|
1497
|
-
register RVALUE *p = RANY(ptr);
|
1498
|
-
//register struct sorted_heaps_slot *heap;
|
1499
|
-
register size_t hi, lo, mid;
|
1500
1192
|
|
1501
|
-
|
1502
|
-
|
1503
|
-
|
1504
|
-
|
1505
|
-
|
1506
|
-
if ((VALUE)p % sizeof(RVALUE) != 0) return FALSE;
|
1507
|
-
//printf("ptr %p align correct\n", ptr);
|
1508
|
-
|
1509
|
-
//1.9.2-p290
|
1510
|
-
/* check if p looks like a pointer using bsearch*/
|
1511
|
-
lo = 0;
|
1512
|
-
hi = heaps_used;
|
1513
|
-
while (lo < hi) {
|
1514
|
-
mid = (lo + hi) / 2;
|
1515
|
-
register struct heaps_slot *heap;
|
1516
|
-
heap = &heaps[mid];
|
1517
|
-
if (heap->slot <= p) {
|
1518
|
-
if (p < heap->slot + heap->limit)
|
1519
|
-
return TRUE;
|
1520
|
-
lo = mid + 1;
|
1521
|
-
}
|
1522
|
-
else {
|
1523
|
-
hi = mid;
|
1524
|
-
}
|
1525
|
-
}
|
1526
|
-
//printf("not found");
|
1527
|
-
return FALSE;
|
1193
|
+
static inline int is_in_heap(void *ptr, void* osp){
|
1194
|
+
rb_objspace_t *objspace = osp;
|
1195
|
+
if(!ptr) return false;
|
1196
|
+
if(!objspace) objspace = GET_THREAD()->vm->objspace;
|
1197
|
+
return is_pointer_to_heap(objspace, ptr);
|
1528
1198
|
}
|
1529
1199
|
|
1530
1200
|
|
@@ -1581,7 +1251,7 @@ vm_backtrace_each(const rb_thread_t *th, int lev, void (*init)(void *), rb_backt
|
|
1581
1251
|
}
|
1582
1252
|
else if (RUBYVM_CFUNC_FRAME_P(cfp)) {
|
1583
1253
|
ID id;
|
1584
|
-
|
1254
|
+
|
1585
1255
|
|
1586
1256
|
if (NIL_P(file)) file = ruby_engine_name;
|
1587
1257
|
if (cfp->me->def)
|
@@ -1735,7 +1405,7 @@ static void dump_machine_context(walk_ctx_t *ctx){
|
|
1735
1405
|
//printf("registers\n");
|
1736
1406
|
while (n--) {
|
1737
1407
|
VALUE v = *(x++);
|
1738
|
-
if(
|
1408
|
+
if(is_in_heap((void*)v, NULL))
|
1739
1409
|
yg_id(v);
|
1740
1410
|
}
|
1741
1411
|
yajl_gen_array_close(ctx->yajl);
|
@@ -1751,7 +1421,7 @@ static void dump_machine_context(walk_ctx_t *ctx){
|
|
1751
1421
|
VALUE v = *(x++);
|
1752
1422
|
//printf("val: %p\n", (void*)v);
|
1753
1423
|
//FIXME: other objspace (not default one?)
|
1754
|
-
if(
|
1424
|
+
if(is_in_heap((void*)v, NULL)) {
|
1755
1425
|
//printf("ON heap\n");
|
1756
1426
|
yg_id(v);
|
1757
1427
|
}
|
@@ -1773,7 +1443,7 @@ static int dump_iv_entry1(ID key, rb_const_entry_t* ce/*st_data_t val*/, walk_ct
|
|
1773
1443
|
|
1774
1444
|
//printf("name %s\n", RSTRING_PTR(rb_class_path(rb_class_real_checked(value))));
|
1775
1445
|
|
1776
|
-
//if(
|
1446
|
+
//if(is_in_heap(value, NULL)){
|
1777
1447
|
//printf("on heap\n");
|
1778
1448
|
yg_id(value);
|
1779
1449
|
//}
|
@@ -1827,6 +1497,7 @@ void heapdump_dump(const char* filename){
|
|
1827
1497
|
//printf("global %p\n", v);
|
1828
1498
|
}
|
1829
1499
|
|
1500
|
+
#ifdef HAVE_RB_CLASS_TBL
|
1830
1501
|
yg_cstring("classes");
|
1831
1502
|
yajl_gen_array_open(ctx->yajl);
|
1832
1503
|
printf("classes\n");
|
@@ -1835,6 +1506,7 @@ void heapdump_dump(const char* filename){
|
|
1835
1506
|
else printf("no classes\n");
|
1836
1507
|
yajl_gen_array_close(ctx->yajl);
|
1837
1508
|
flush_yajl(ctx);
|
1509
|
+
#endif
|
1838
1510
|
|
1839
1511
|
//try_dump_generic_ivars();
|
1840
1512
|
|
@@ -0,0 +1,48 @@
|
|
1
|
+
//1.9.2
|
2
|
+
|
3
|
+
#define CAPTURE_JUST_VALID_VM_STACK 1
|
4
|
+
|
5
|
+
enum context_type {
|
6
|
+
CONTINUATION_CONTEXT = 0,
|
7
|
+
FIBER_CONTEXT = 1,
|
8
|
+
ROOT_FIBER_CONTEXT = 2
|
9
|
+
};
|
10
|
+
|
11
|
+
typedef struct rb_context_struct {
|
12
|
+
enum context_type type;
|
13
|
+
VALUE self;
|
14
|
+
int argc;
|
15
|
+
VALUE value;
|
16
|
+
VALUE *vm_stack;
|
17
|
+
#ifdef CAPTURE_JUST_VALID_VM_STACK
|
18
|
+
size_t vm_stack_slen; /* length of stack (head of th->stack) */
|
19
|
+
size_t vm_stack_clen; /* length of control frames (tail of th->stack) */
|
20
|
+
#endif
|
21
|
+
VALUE *machine_stack;
|
22
|
+
VALUE *machine_stack_src;
|
23
|
+
#ifdef __ia64
|
24
|
+
VALUE *machine_register_stack;
|
25
|
+
VALUE *machine_register_stack_src;
|
26
|
+
int machine_register_stack_size;
|
27
|
+
#endif
|
28
|
+
rb_thread_t saved_thread;
|
29
|
+
rb_jmpbuf_t jmpbuf;
|
30
|
+
size_t machine_stack_size;
|
31
|
+
} rb_context_t;
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
enum fiber_status {
|
36
|
+
CREATED,
|
37
|
+
RUNNING,
|
38
|
+
TERMINATED
|
39
|
+
};
|
40
|
+
|
41
|
+
typedef struct rb_fiber_struct {
|
42
|
+
rb_context_t cont;
|
43
|
+
VALUE prev;
|
44
|
+
enum fiber_status status;
|
45
|
+
struct rb_fiber_struct *prev_fiber;
|
46
|
+
struct rb_fiber_struct *next_fiber;
|
47
|
+
} rb_fiber_t;
|
48
|
+
|
@@ -0,0 +1,192 @@
|
|
1
|
+
//extracted from ruby 1.9.2 p290, should be compatible with all 1.9.2's
|
2
|
+
|
3
|
+
//TODO: does conflict with ruby framework?
|
4
|
+
#include "ruby/re.h"
|
5
|
+
|
6
|
+
//FIXME: this should be autoextracted from ruby
|
7
|
+
// see how this is done in ruby-internal gem
|
8
|
+
|
9
|
+
|
10
|
+
#define MARK_STACK_MAX 1024
|
11
|
+
|
12
|
+
#ifndef CALC_EXACT_MALLOC_SIZE
|
13
|
+
#define CALC_EXACT_MALLOC_SIZE 0
|
14
|
+
#endif
|
15
|
+
|
16
|
+
typedef struct RVALUE {
|
17
|
+
union {
|
18
|
+
struct {
|
19
|
+
VALUE flags; /* always 0 for freed obj */
|
20
|
+
struct RVALUE *next;
|
21
|
+
} free;
|
22
|
+
struct RBasic basic;
|
23
|
+
struct RObject object;
|
24
|
+
struct RClass klass;
|
25
|
+
struct RFloat flonum;
|
26
|
+
struct RString string;
|
27
|
+
struct RArray array;
|
28
|
+
struct RRegexp regexp;
|
29
|
+
struct RHash hash;
|
30
|
+
struct RData data;
|
31
|
+
struct RTypedData typeddata;
|
32
|
+
struct RStruct rstruct;
|
33
|
+
struct RBignum bignum;
|
34
|
+
struct RFile file;
|
35
|
+
struct RNode node;
|
36
|
+
struct RMatch match;
|
37
|
+
struct RRational rational;
|
38
|
+
struct RComplex complex;
|
39
|
+
} as;
|
40
|
+
#ifdef GC_DEBUG
|
41
|
+
const char *file;
|
42
|
+
int line;
|
43
|
+
#endif
|
44
|
+
} RVALUE;
|
45
|
+
|
46
|
+
typedef struct gc_profile_record {
|
47
|
+
double gc_time;
|
48
|
+
double gc_mark_time;
|
49
|
+
double gc_sweep_time;
|
50
|
+
double gc_invoke_time;
|
51
|
+
|
52
|
+
size_t heap_use_slots;
|
53
|
+
size_t heap_live_objects;
|
54
|
+
size_t heap_free_objects;
|
55
|
+
size_t heap_total_objects;
|
56
|
+
size_t heap_use_size;
|
57
|
+
size_t heap_total_size;
|
58
|
+
|
59
|
+
int have_finalize;
|
60
|
+
int is_marked;
|
61
|
+
|
62
|
+
size_t allocate_increase;
|
63
|
+
size_t allocate_limit;
|
64
|
+
} gc_profile_record;
|
65
|
+
|
66
|
+
struct heaps_slot {
|
67
|
+
void *membase;
|
68
|
+
RVALUE *slot;
|
69
|
+
size_t limit;
|
70
|
+
uintptr_t *bits;
|
71
|
+
RVALUE *freelist;
|
72
|
+
struct heaps_slot *next;
|
73
|
+
struct heaps_slot *prev;
|
74
|
+
struct heaps_slot *free_next;
|
75
|
+
};
|
76
|
+
|
77
|
+
struct heaps_header {
|
78
|
+
struct heaps_slot *base;
|
79
|
+
uintptr_t *bits;
|
80
|
+
};
|
81
|
+
|
82
|
+
struct sorted_heaps_slot {
|
83
|
+
RVALUE *start;
|
84
|
+
RVALUE *end;
|
85
|
+
struct heaps_slot *slot;
|
86
|
+
};
|
87
|
+
|
88
|
+
struct heaps_free_bitmap {
|
89
|
+
struct heaps_free_bitmap *next;
|
90
|
+
};
|
91
|
+
|
92
|
+
struct gc_list {
|
93
|
+
VALUE *varptr;
|
94
|
+
struct gc_list *next;
|
95
|
+
};
|
96
|
+
|
97
|
+
|
98
|
+
// 1.9.2-p290:
|
99
|
+
typedef struct rb_objspace {
|
100
|
+
struct {
|
101
|
+
size_t limit;
|
102
|
+
size_t increase;
|
103
|
+
#if CALC_EXACT_MALLOC_SIZE
|
104
|
+
size_t allocated_size;
|
105
|
+
size_t allocations;
|
106
|
+
#endif
|
107
|
+
} malloc_params;
|
108
|
+
struct {
|
109
|
+
size_t increment;
|
110
|
+
struct heaps_slot *ptr;
|
111
|
+
size_t length;
|
112
|
+
size_t used;
|
113
|
+
RVALUE *freelist;
|
114
|
+
RVALUE *range[2];
|
115
|
+
RVALUE *freed;
|
116
|
+
} heap;
|
117
|
+
struct {
|
118
|
+
int dont_gc;
|
119
|
+
int during_gc;
|
120
|
+
} flags;
|
121
|
+
struct {
|
122
|
+
st_table *table;
|
123
|
+
RVALUE *deferred;
|
124
|
+
} final;
|
125
|
+
struct {
|
126
|
+
VALUE buffer[MARK_STACK_MAX];
|
127
|
+
VALUE *ptr;
|
128
|
+
int overflow;
|
129
|
+
} markstack;
|
130
|
+
struct {
|
131
|
+
int run;
|
132
|
+
gc_profile_record *record;
|
133
|
+
size_t count;
|
134
|
+
size_t size;
|
135
|
+
double invoke_time;
|
136
|
+
} profile;
|
137
|
+
struct gc_list *global_list;
|
138
|
+
unsigned int count;
|
139
|
+
int gc_stress;
|
140
|
+
} rb_objspace_t;
|
141
|
+
|
142
|
+
//
|
143
|
+
#define RANY(o) ((RVALUE*)(o))
|
144
|
+
|
145
|
+
#define malloc_limit objspace->malloc_params.limit
|
146
|
+
#define malloc_increase objspace->malloc_params.increase
|
147
|
+
#define heaps objspace->heap.ptr
|
148
|
+
#define heaps_length objspace->heap.length
|
149
|
+
#define heaps_used objspace->heap.used
|
150
|
+
#define lomem objspace->heap.range[0]
|
151
|
+
#define himem objspace->heap.range[1]
|
152
|
+
#define heaps_inc objspace->heap.increment
|
153
|
+
#define heaps_freed objspace->heap.freed
|
154
|
+
#define dont_gc objspace->flags.dont_gc
|
155
|
+
#define during_gc objspace->flags.during_gc
|
156
|
+
#define finalizing objspace->flags.finalizing
|
157
|
+
#define finalizer_table objspace->final.table
|
158
|
+
#define deferred_final_list objspace->final.deferred
|
159
|
+
#define mark_stack objspace->markstack.buffer
|
160
|
+
#define mark_stack_ptr objspace->markstack.ptr
|
161
|
+
#define mark_stack_overflow objspace->markstack.overflow
|
162
|
+
#define global_List objspace->global_list
|
163
|
+
|
164
|
+
|
165
|
+
//1.9.2-p290
|
166
|
+
static inline int
|
167
|
+
is_pointer_to_heap(rb_objspace_t *objspace, void *ptr)
|
168
|
+
{
|
169
|
+
register RVALUE *p = RANY(ptr);
|
170
|
+
register struct heaps_slot *heap;
|
171
|
+
register size_t hi, lo, mid;
|
172
|
+
|
173
|
+
if (p < lomem || p > himem) return FALSE;
|
174
|
+
if ((VALUE)p % sizeof(RVALUE) != 0) return FALSE;
|
175
|
+
|
176
|
+
/* check if p looks like a pointer using bsearch*/
|
177
|
+
lo = 0;
|
178
|
+
hi = heaps_used;
|
179
|
+
while (lo < hi) {
|
180
|
+
mid = (lo + hi) / 2;
|
181
|
+
heap = &heaps[mid];
|
182
|
+
if (heap->slot <= p) {
|
183
|
+
if (p < heap->slot + heap->limit)
|
184
|
+
return TRUE;
|
185
|
+
lo = mid + 1;
|
186
|
+
}
|
187
|
+
else {
|
188
|
+
hi = mid;
|
189
|
+
}
|
190
|
+
}
|
191
|
+
return FALSE;
|
192
|
+
}
|
@@ -0,0 +1,45 @@
|
|
1
|
+
//FIXME: autogen this from ruby (this copied from 1.9.2p290)
|
2
|
+
struct thgroup {
|
3
|
+
int enclosed;
|
4
|
+
VALUE group;
|
5
|
+
};
|
6
|
+
|
7
|
+
|
8
|
+
//
|
9
|
+
|
10
|
+
struct enumerator {
|
11
|
+
VALUE obj;
|
12
|
+
ID meth;
|
13
|
+
VALUE args;
|
14
|
+
VALUE fib;
|
15
|
+
VALUE dst;
|
16
|
+
VALUE lookahead;
|
17
|
+
VALUE feedvalue;
|
18
|
+
VALUE stop_exc;
|
19
|
+
};
|
20
|
+
|
21
|
+
struct generator {
|
22
|
+
VALUE proc;
|
23
|
+
};
|
24
|
+
|
25
|
+
struct yielder {
|
26
|
+
VALUE proc;
|
27
|
+
};
|
28
|
+
|
29
|
+
//
|
30
|
+
struct METHOD {
|
31
|
+
VALUE recv;
|
32
|
+
VALUE rclass;
|
33
|
+
ID id;
|
34
|
+
rb_method_entry_t me;
|
35
|
+
};
|
36
|
+
|
37
|
+
//
|
38
|
+
|
39
|
+
#define METHOD_DEFINITIONP(m) m->me.def
|
40
|
+
|
41
|
+
#define HAVE_RB_CLASS_TBL 1
|
42
|
+
//class.c:
|
43
|
+
extern st_table *rb_class_tbl;
|
44
|
+
|
45
|
+
extern VALUE ruby_engine_name;
|
@@ -0,0 +1,53 @@
|
|
1
|
+
//1.9.3
|
2
|
+
//from cont.c:
|
3
|
+
|
4
|
+
#define CAPTURE_JUST_VALID_VM_STACK 1
|
5
|
+
|
6
|
+
enum context_type {
|
7
|
+
CONTINUATION_CONTEXT = 0,
|
8
|
+
FIBER_CONTEXT = 1,
|
9
|
+
ROOT_FIBER_CONTEXT = 2
|
10
|
+
};
|
11
|
+
|
12
|
+
typedef struct rb_context_struct {
|
13
|
+
enum context_type type;
|
14
|
+
VALUE self;
|
15
|
+
int argc;
|
16
|
+
VALUE value;
|
17
|
+
VALUE *vm_stack;
|
18
|
+
#ifdef CAPTURE_JUST_VALID_VM_STACK
|
19
|
+
size_t vm_stack_slen; /* length of stack (head of th->stack) */
|
20
|
+
size_t vm_stack_clen; /* length of control frames (tail of th->stack) */
|
21
|
+
#endif
|
22
|
+
VALUE *machine_stack;
|
23
|
+
VALUE *machine_stack_src;
|
24
|
+
#ifdef __ia64
|
25
|
+
VALUE *machine_register_stack;
|
26
|
+
VALUE *machine_register_stack_src;
|
27
|
+
int machine_register_stack_size;
|
28
|
+
#endif
|
29
|
+
rb_thread_t saved_thread;
|
30
|
+
rb_jmpbuf_t jmpbuf;
|
31
|
+
size_t machine_stack_size;
|
32
|
+
} rb_context_t;
|
33
|
+
|
34
|
+
enum fiber_status {
|
35
|
+
CREATED,
|
36
|
+
RUNNING,
|
37
|
+
TERMINATED
|
38
|
+
};
|
39
|
+
|
40
|
+
typedef struct rb_fiber_struct {
|
41
|
+
rb_context_t cont;
|
42
|
+
VALUE prev;
|
43
|
+
enum fiber_status status;
|
44
|
+
struct rb_fiber_struct *prev_fiber;
|
45
|
+
struct rb_fiber_struct *next_fiber;
|
46
|
+
#if FIBER_USE_NATIVE
|
47
|
+
#ifdef _WIN32
|
48
|
+
void *fib_handle;
|
49
|
+
#else
|
50
|
+
ucontext_t context;
|
51
|
+
#endif
|
52
|
+
#endif
|
53
|
+
} rb_fiber_t;
|
@@ -0,0 +1,191 @@
|
|
1
|
+
//TODO: does conflict with ruby framework?
|
2
|
+
#include "ruby/re.h"
|
3
|
+
|
4
|
+
//gc.c
|
5
|
+
|
6
|
+
#define MARK_STACK_MAX 1024
|
7
|
+
//
|
8
|
+
/* for GC profile */
|
9
|
+
#define GC_PROFILE_MORE_DETAIL 0
|
10
|
+
typedef struct gc_profile_record {
|
11
|
+
double gc_time;
|
12
|
+
double gc_mark_time;
|
13
|
+
double gc_sweep_time;
|
14
|
+
double gc_invoke_time;
|
15
|
+
|
16
|
+
size_t heap_use_slots;
|
17
|
+
size_t heap_live_objects;
|
18
|
+
size_t heap_free_objects;
|
19
|
+
size_t heap_total_objects;
|
20
|
+
size_t heap_use_size;
|
21
|
+
size_t heap_total_size;
|
22
|
+
|
23
|
+
int have_finalize;
|
24
|
+
int is_marked;
|
25
|
+
|
26
|
+
size_t allocate_increase;
|
27
|
+
size_t allocate_limit;
|
28
|
+
} gc_profile_record;
|
29
|
+
//
|
30
|
+
|
31
|
+
typedef struct RVALUE {
|
32
|
+
union {
|
33
|
+
struct {
|
34
|
+
VALUE flags; /* always 0 for freed obj */
|
35
|
+
struct RVALUE *next;
|
36
|
+
} free;
|
37
|
+
struct RBasic basic;
|
38
|
+
struct RObject object;
|
39
|
+
struct RClass klass;
|
40
|
+
struct RFloat flonum;
|
41
|
+
struct RString string;
|
42
|
+
struct RArray array;
|
43
|
+
struct RRegexp regexp;
|
44
|
+
struct RHash hash;
|
45
|
+
struct RData data;
|
46
|
+
struct RTypedData typeddata;
|
47
|
+
struct RStruct rstruct;
|
48
|
+
struct RBignum bignum;
|
49
|
+
struct RFile file;
|
50
|
+
struct RNode node;
|
51
|
+
struct RMatch match;
|
52
|
+
struct RRational rational;
|
53
|
+
struct RComplex complex;
|
54
|
+
} as;
|
55
|
+
#ifdef GC_DEBUG
|
56
|
+
const char *file;
|
57
|
+
int line;
|
58
|
+
#endif
|
59
|
+
} RVALUE;
|
60
|
+
|
61
|
+
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CYGWIN__)
|
62
|
+
#pragma pack(pop)
|
63
|
+
#endif
|
64
|
+
|
65
|
+
struct heaps_slot {
|
66
|
+
void *membase;
|
67
|
+
RVALUE *slot;
|
68
|
+
size_t limit;
|
69
|
+
struct heaps_slot *next;
|
70
|
+
struct heaps_slot *prev;
|
71
|
+
};
|
72
|
+
|
73
|
+
struct sorted_heaps_slot {
|
74
|
+
RVALUE *start;
|
75
|
+
RVALUE *end;
|
76
|
+
struct heaps_slot *slot;
|
77
|
+
};
|
78
|
+
|
79
|
+
struct gc_list {
|
80
|
+
VALUE *varptr;
|
81
|
+
struct gc_list *next;
|
82
|
+
};
|
83
|
+
|
84
|
+
#define CALC_EXACT_MALLOC_SIZE 0
|
85
|
+
|
86
|
+
typedef struct rb_objspace {
|
87
|
+
struct {
|
88
|
+
size_t limit;
|
89
|
+
size_t increase;
|
90
|
+
#if CALC_EXACT_MALLOC_SIZE
|
91
|
+
size_t allocated_size;
|
92
|
+
size_t allocations;
|
93
|
+
#endif
|
94
|
+
} malloc_params;
|
95
|
+
struct {
|
96
|
+
size_t increment;
|
97
|
+
struct heaps_slot *ptr;
|
98
|
+
struct heaps_slot *sweep_slots;
|
99
|
+
struct sorted_heaps_slot *sorted;
|
100
|
+
size_t length;
|
101
|
+
size_t used;
|
102
|
+
RVALUE *freelist;
|
103
|
+
RVALUE *range[2];
|
104
|
+
RVALUE *freed;
|
105
|
+
size_t live_num;
|
106
|
+
size_t free_num;
|
107
|
+
size_t free_min;
|
108
|
+
size_t final_num;
|
109
|
+
size_t do_heap_free;
|
110
|
+
} heap;
|
111
|
+
struct {
|
112
|
+
int dont_gc;
|
113
|
+
int dont_lazy_sweep;
|
114
|
+
int during_gc;
|
115
|
+
} flags;
|
116
|
+
struct {
|
117
|
+
st_table *table;
|
118
|
+
RVALUE *deferred;
|
119
|
+
} final;
|
120
|
+
struct {
|
121
|
+
VALUE buffer[MARK_STACK_MAX];
|
122
|
+
VALUE *ptr;
|
123
|
+
int overflow;
|
124
|
+
} markstack;
|
125
|
+
struct {
|
126
|
+
int run;
|
127
|
+
gc_profile_record *record;
|
128
|
+
size_t count;
|
129
|
+
size_t size;
|
130
|
+
double invoke_time;
|
131
|
+
} profile;
|
132
|
+
struct gc_list *global_list;
|
133
|
+
size_t count;
|
134
|
+
int gc_stress;
|
135
|
+
} rb_objspace_t;
|
136
|
+
|
137
|
+
//
|
138
|
+
|
139
|
+
#define malloc_limit objspace->malloc_params.limit
|
140
|
+
#define malloc_increase objspace->malloc_params.increase
|
141
|
+
#define heaps objspace->heap.ptr
|
142
|
+
#define heaps_length objspace->heap.length
|
143
|
+
#define heaps_used objspace->heap.used
|
144
|
+
#define freelist objspace->heap.freelist
|
145
|
+
#define lomem objspace->heap.range[0]
|
146
|
+
#define himem objspace->heap.range[1]
|
147
|
+
#define heaps_inc objspace->heap.increment
|
148
|
+
#define heaps_freed objspace->heap.freed
|
149
|
+
#define dont_gc objspace->flags.dont_gc
|
150
|
+
#define during_gc objspace->flags.during_gc
|
151
|
+
#define finalizer_table objspace->final.table
|
152
|
+
#define deferred_final_list objspace->final.deferred
|
153
|
+
#define mark_stack objspace->markstack.buffer
|
154
|
+
#define mark_stack_ptr objspace->markstack.ptr
|
155
|
+
#define mark_stack_overflow objspace->markstack.overflow
|
156
|
+
#define global_List objspace->global_list
|
157
|
+
#define ruby_gc_stress objspace->gc_stress
|
158
|
+
#define initial_malloc_limit initial_params.initial_malloc_limit
|
159
|
+
#define initial_heap_min_slots initial_params.initial_heap_min_slots
|
160
|
+
#define initial_free_min initial_params.initial_free_min
|
161
|
+
|
162
|
+
//
|
163
|
+
#define RANY(o) ((RVALUE*)(o))
|
164
|
+
//
|
165
|
+
static inline int
|
166
|
+
is_pointer_to_heap(rb_objspace_t *objspace, void *ptr)
|
167
|
+
{
|
168
|
+
register RVALUE *p = RANY(ptr);
|
169
|
+
register struct sorted_heaps_slot *heap;
|
170
|
+
register size_t hi, lo, mid;
|
171
|
+
|
172
|
+
if (p < lomem || p > himem) return FALSE;
|
173
|
+
if ((VALUE)p % sizeof(RVALUE) != 0) return FALSE;
|
174
|
+
|
175
|
+
/* check if p looks like a pointer using bsearch*/
|
176
|
+
lo = 0;
|
177
|
+
hi = heaps_used;
|
178
|
+
while (lo < hi) {
|
179
|
+
mid = (lo + hi) / 2;
|
180
|
+
heap = &objspace->heap.sorted[mid];
|
181
|
+
if (heap->start <= p) {
|
182
|
+
if (p < heap->end)
|
183
|
+
return TRUE;
|
184
|
+
lo = mid + 1;
|
185
|
+
}
|
186
|
+
else {
|
187
|
+
hi = mid;
|
188
|
+
}
|
189
|
+
}
|
190
|
+
return FALSE;
|
191
|
+
}
|
@@ -0,0 +1,51 @@
|
|
1
|
+
//FIXME: autogen this from ruby (this copied from 1.9.3p194)
|
2
|
+
|
3
|
+
// thread.c:
|
4
|
+
struct thgroup {
|
5
|
+
int enclosed;
|
6
|
+
VALUE group;
|
7
|
+
};
|
8
|
+
|
9
|
+
// enumerator.c:
|
10
|
+
struct enumerator {
|
11
|
+
VALUE obj;
|
12
|
+
ID meth;
|
13
|
+
VALUE args;
|
14
|
+
VALUE fib;
|
15
|
+
VALUE dst;
|
16
|
+
VALUE lookahead;
|
17
|
+
VALUE feedvalue;
|
18
|
+
VALUE stop_exc;
|
19
|
+
};
|
20
|
+
|
21
|
+
//
|
22
|
+
struct generator {
|
23
|
+
VALUE proc;
|
24
|
+
};
|
25
|
+
|
26
|
+
struct yielder {
|
27
|
+
VALUE proc;
|
28
|
+
};
|
29
|
+
|
30
|
+
|
31
|
+
// proc.c:
|
32
|
+
struct METHOD {
|
33
|
+
VALUE recv;
|
34
|
+
VALUE rclass;
|
35
|
+
ID id;
|
36
|
+
rb_method_entry_t *me;
|
37
|
+
struct unlinked_method_entry_list_entry *ume;
|
38
|
+
};
|
39
|
+
|
40
|
+
//
|
41
|
+
#define METHOD_DEFINITIONP(m) (m->me ? m->me->def : NULL)
|
42
|
+
|
43
|
+
//class.c:
|
44
|
+
// #define HAVE_RB_CLASS_TBL 1
|
45
|
+
//For som reason this fails to link on 1.9.3 :(
|
46
|
+
// extern st_table *rb_class_tbl;
|
47
|
+
|
48
|
+
#define ruby_current_thread ((rb_thread_t *)RTYPEDDATA_DATA(rb_thread_current()))
|
49
|
+
|
50
|
+
//FIXME: get global const for it: rb_define_global_const("RUBY_ENGINE", ruby_engine_name = MKSTR(engine));
|
51
|
+
#define ruby_engine_name Qnil
|
data/heap_dump.gemspec
CHANGED
@@ -15,7 +15,7 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.require_paths = ["lib"]
|
16
16
|
gem.version = HeapDump::VERSION
|
17
17
|
|
18
|
-
gem.required_ruby_version = '~>1.9.
|
18
|
+
gem.required_ruby_version = '~>1.9.2'
|
19
19
|
#gem.platform = Gem::Platform::CURRENT # other than osx - maybe later
|
20
20
|
|
21
21
|
gem.extensions = "ext/heap_dump/extconf.rb"
|
data/lib/heap_dump/version.rb
CHANGED
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.
|
4
|
+
version: 0.0.26
|
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-10-
|
12
|
+
date: 2012-10-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: debugger-ruby_core_source
|
@@ -75,6 +75,13 @@ files:
|
|
75
75
|
- ext/heap_dump/extconf.rb
|
76
76
|
- ext/heap_dump/heap_dump.c
|
77
77
|
- ext/heap_dump/ruby_io.h
|
78
|
+
- ext/heap_dump/specific/ruby-1.9.2/fiber.h
|
79
|
+
- ext/heap_dump/specific/ruby-1.9.2/gc_internal.h
|
80
|
+
- ext/heap_dump/specific/ruby-1.9.2/internal_constant.h
|
81
|
+
- ext/heap_dump/specific/ruby-1.9.2/internal_typed_data.h
|
82
|
+
- ext/heap_dump/specific/ruby-1.9.3/fiber.h
|
83
|
+
- ext/heap_dump/specific/ruby-1.9.3/gc_internal.h
|
84
|
+
- ext/heap_dump/specific/ruby-1.9.3/internal_typed_data.h
|
78
85
|
- heap_dump.gemspec
|
79
86
|
- lib/heap_dump.rb
|
80
87
|
- lib/heap_dump/version.rb
|
@@ -89,7 +96,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
89
96
|
requirements:
|
90
97
|
- - ~>
|
91
98
|
- !ruby/object:Gem::Version
|
92
|
-
version: 1.9.
|
99
|
+
version: 1.9.2
|
93
100
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
101
|
none: false
|
95
102
|
requirements:
|
@@ -98,7 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
98
105
|
version: '0'
|
99
106
|
segments:
|
100
107
|
- 0
|
101
|
-
hash: -
|
108
|
+
hash: -4211610270399320096
|
102
109
|
requirements: []
|
103
110
|
rubyforge_project:
|
104
111
|
rubygems_version: 1.8.24
|