heap_dump 0.0.25 → 0.0.26
Sign up to get free protection for your applications and to get access to all the features.
- 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
|