memprof 0.2.9 → 0.3.0
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 +4 -0
- data/Rakefile +30 -0
- data/bin/memprof +158 -0
- data/ext/bin_api.h +6 -2
- data/ext/elf.c +146 -46
- data/ext/extconf.rb +39 -13
- data/ext/mach.c +3 -3
- data/ext/memprof.c +923 -95
- data/ext/tramp.c +2 -2
- data/ext/util.c +1 -0
- data/ext/util.h +34 -2
- data/lib/memprof/signal.rb +16 -0
- data/memprof.gemspec +5 -1
- data/spec/memprof_spec.rb +2 -2
- data/spec/memprof_uploader_spec.rb +117 -0
- metadata +35 -8
- data/lib/memprof/usr2.rb +0 -10
data/ext/extconf.rb
CHANGED
@@ -144,18 +144,41 @@ if have_header('mach-o/dyld.h')
|
|
144
144
|
# XXX How to determine this properly? RUBY_PLATFORM reports "i686-darwin10.2.0" on Snow Leopard.
|
145
145
|
add_define "_ARCH_x86_64_"
|
146
146
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
[:offset__heaps_slot__slot, "(int)&(((struct heaps_slot *)0)->slot)"],
|
151
|
-
[:offset__heaps_slot__limit, "(int)&(((struct heaps_slot *)0)->limit)"]
|
152
|
-
# "&add_freelist",
|
153
|
-
# "&rb_newobj",
|
154
|
-
# "&freelist",
|
155
|
-
# "&heaps",
|
156
|
-
# "&heaps_used"
|
147
|
+
sizes_of = [
|
148
|
+
'RVALUE',
|
149
|
+
'struct heaps_slot'
|
157
150
|
]
|
158
151
|
|
152
|
+
offsets_of = {
|
153
|
+
'struct heaps_slot' => %w[ slot limit ],
|
154
|
+
'struct BLOCK' => %w[ body var cref self klass wrapper block_obj orig_thread dyna_vars scope prev ],
|
155
|
+
'struct METHOD' => %w[ klass rklass recv id oid body ]
|
156
|
+
}
|
157
|
+
|
158
|
+
addresses_of = [
|
159
|
+
# 'add_freelist',
|
160
|
+
# 'rb_newobj',
|
161
|
+
# 'freelist',
|
162
|
+
# 'heaps',
|
163
|
+
# 'heaps_used'
|
164
|
+
]
|
165
|
+
|
166
|
+
expressions = []
|
167
|
+
|
168
|
+
sizes_of.each do |type|
|
169
|
+
name = type.sub(/^struct\s*/,'')
|
170
|
+
expressions << ["sizeof__#{name}", "sizeof(#{type})"]
|
171
|
+
end
|
172
|
+
offsets_of.each do |type, members|
|
173
|
+
name = type.sub(/^struct\s*/,'')
|
174
|
+
members.each do |member|
|
175
|
+
expressions << ["offset__#{name}__#{member}", "(size_t)&(((#{type} *)0)->#{member})"]
|
176
|
+
end
|
177
|
+
end
|
178
|
+
addresses_of.each do |name|
|
179
|
+
expressions << ["address__#{name}", "&#{name}"]
|
180
|
+
end
|
181
|
+
|
159
182
|
pid = fork{sleep}
|
160
183
|
output = IO.popen('gdb --interpreter=mi --quiet', 'w+') do |io|
|
161
184
|
io.puts "attach #{pid}"
|
@@ -175,8 +198,8 @@ if have_header('mach-o/dyld.h')
|
|
175
198
|
end
|
176
199
|
|
177
200
|
values = results.map{ |l| l[/value="(.+?)"/, 1] }
|
178
|
-
vars = Hash[ *expressions.map{|n,e| n }.zip(values).flatten
|
179
|
-
add_define "#{name}=#{val}"
|
201
|
+
vars = Hash[ *expressions.map{|n,e| n }.zip(values).flatten ].each do |name, val|
|
202
|
+
add_define "#{name}=#{val.split.first}"
|
180
203
|
end
|
181
204
|
end
|
182
205
|
|
@@ -189,7 +212,10 @@ when 'i486'
|
|
189
212
|
end
|
190
213
|
add_define "_ARCH_#{arch}_"
|
191
214
|
|
192
|
-
|
215
|
+
if ENV['MEMPROF_DEBUG'] == '1'
|
216
|
+
add_define "_MEMPROF_DEBUG"
|
217
|
+
$preload = ["\nCFLAGS = -Wall -Wextra -fPIC -ggdb3 -O0"]
|
218
|
+
end
|
193
219
|
|
194
220
|
if is_elf or is_macho
|
195
221
|
create_makefile('memprof')
|
data/ext/mach.c
CHANGED
@@ -348,7 +348,7 @@ get_symtab_string(uint32_t stroff) {
|
|
348
348
|
*/
|
349
349
|
|
350
350
|
void *
|
351
|
-
bin_find_symbol(const char *symbol, size_t *size) {
|
351
|
+
bin_find_symbol(const char *symbol, size_t *size, int search_libs) {
|
352
352
|
void *ptr = NULL;
|
353
353
|
uint32_t i, j;
|
354
354
|
|
@@ -438,12 +438,12 @@ bin_find_symbol_name(void *symbol) {
|
|
438
438
|
*/
|
439
439
|
|
440
440
|
int
|
441
|
-
bin_update_image(const char *trampee, struct tramp_st2_entry *tramp)
|
441
|
+
bin_update_image(const char *trampee, struct tramp_st2_entry *tramp, void **orig_function)
|
442
442
|
{
|
443
443
|
int ret = -1;
|
444
444
|
int i;
|
445
445
|
int header_count = _dyld_image_count();
|
446
|
-
void *trampee_addr = bin_find_symbol(trampee, NULL);
|
446
|
+
void *trampee_addr = bin_find_symbol(trampee, NULL, 0);
|
447
447
|
|
448
448
|
// Go through all the mach objects that are loaded into this process
|
449
449
|
for (i=0; i < header_count; i++) {
|
data/ext/memprof.c
CHANGED
@@ -4,14 +4,14 @@
|
|
4
4
|
#define _GNU_SOURCE
|
5
5
|
#endif
|
6
6
|
|
7
|
+
#include <assert.h>
|
8
|
+
#include <err.h>
|
7
9
|
#include <fcntl.h>
|
8
10
|
#include <stddef.h>
|
9
|
-
#include <stdio.h>
|
10
11
|
#include <stdint.h>
|
12
|
+
#include <stdio.h>
|
11
13
|
#include <stdlib.h>
|
12
14
|
#include <unistd.h>
|
13
|
-
#include <assert.h>
|
14
|
-
#include <err.h>
|
15
15
|
#include <sysexits.h>
|
16
16
|
|
17
17
|
#include <st.h>
|
@@ -23,20 +23,36 @@
|
|
23
23
|
#include "tramp.h"
|
24
24
|
#include "util.h"
|
25
25
|
|
26
|
-
|
27
26
|
/*
|
28
27
|
* bleak_house stuff
|
29
28
|
*/
|
30
29
|
static VALUE eUnsupported;
|
31
30
|
static int track_objs = 0;
|
31
|
+
static int memprof_started = 0;
|
32
32
|
static st_table *objs = NULL;
|
33
33
|
|
34
|
+
/*
|
35
|
+
* stuff needed for heap dumping
|
36
|
+
*/
|
37
|
+
static VALUE (*rb_classname)(VALUE);
|
38
|
+
static double (*rb_timeofday)();
|
39
|
+
static RUBY_DATA_FUNC *rb_bm_mark;
|
40
|
+
static RUBY_DATA_FUNC *rb_blk_free;
|
41
|
+
static RUBY_DATA_FUNC *rb_thread_mark;
|
34
42
|
struct memprof_config memprof_config;
|
35
43
|
|
44
|
+
/*
|
45
|
+
* memprof config struct init
|
46
|
+
*/
|
47
|
+
static void init_memprof_config_base();
|
48
|
+
static void init_memprof_config_extended();
|
49
|
+
|
36
50
|
struct obj_track {
|
37
51
|
VALUE obj;
|
38
52
|
char *source;
|
39
53
|
int line;
|
54
|
+
int len;
|
55
|
+
struct timeval time[];
|
40
56
|
};
|
41
57
|
|
42
58
|
static VALUE gc_hook;
|
@@ -92,7 +108,7 @@ newobj_tramp()
|
|
92
108
|
struct obj_track *tracker = NULL;
|
93
109
|
|
94
110
|
if (track_objs && objs) {
|
95
|
-
tracker = malloc(sizeof(*tracker));
|
111
|
+
tracker = malloc(sizeof(*tracker) + sizeof(struct timeval));
|
96
112
|
|
97
113
|
if (tracker) {
|
98
114
|
if (ruby_current_node && ruby_current_node->nd_file &&
|
@@ -108,6 +124,13 @@ newobj_tramp()
|
|
108
124
|
}
|
109
125
|
|
110
126
|
tracker->obj = ret;
|
127
|
+
tracker->len = 1;
|
128
|
+
|
129
|
+
/* TODO a way for the user to disallow time tracking */
|
130
|
+
if (gettimeofday(&tracker->time[0], NULL) == -1) {
|
131
|
+
perror("gettimeofday failed. Continuing anyway, error");
|
132
|
+
}
|
133
|
+
|
111
134
|
rb_gc_disable();
|
112
135
|
st_insert(objs, (st_data_t)ret, (st_data_t)tracker);
|
113
136
|
rb_gc_enable();
|
@@ -209,6 +232,13 @@ objs_to_array(st_data_t key, st_data_t record, st_data_t arg)
|
|
209
232
|
static VALUE
|
210
233
|
memprof_start(VALUE self)
|
211
234
|
{
|
235
|
+
if (!memprof_started) {
|
236
|
+
|
237
|
+
insert_tramp("rb_newobj", newobj_tramp);
|
238
|
+
insert_tramp("add_freelist", freelist_tramp);
|
239
|
+
memprof_started = 1;
|
240
|
+
}
|
241
|
+
|
212
242
|
if (track_objs == 1)
|
213
243
|
return Qfalse;
|
214
244
|
|
@@ -219,6 +249,8 @@ memprof_start(VALUE self)
|
|
219
249
|
static VALUE
|
220
250
|
memprof_stop(VALUE self)
|
221
251
|
{
|
252
|
+
/* TODO: remove trampolines and set memprof_started = 0 */
|
253
|
+
|
222
254
|
if (track_objs == 0)
|
223
255
|
return Qfalse;
|
224
256
|
|
@@ -302,11 +334,215 @@ memprof_track(int argc, VALUE *argv, VALUE self)
|
|
302
334
|
return Qnil;
|
303
335
|
}
|
304
336
|
|
337
|
+
struct memprof_malloc_stats {
|
338
|
+
size_t malloc_bytes_requested;
|
339
|
+
size_t calloc_bytes_requested;
|
340
|
+
size_t realloc_bytes_requested;
|
341
|
+
|
342
|
+
size_t malloc_bytes_actual;
|
343
|
+
size_t calloc_bytes_actual;
|
344
|
+
size_t realloc_bytes_actual;
|
345
|
+
size_t free_bytes_actual;
|
346
|
+
|
347
|
+
size_t malloc_calls;
|
348
|
+
size_t calloc_calls;
|
349
|
+
size_t realloc_calls;
|
350
|
+
size_t free_calls;
|
351
|
+
};
|
352
|
+
|
353
|
+
static struct memprof_malloc_stats memprof_malloc_stats;
|
354
|
+
static void *orig_malloc, *orig_realloc, *orig_calloc, *orig_free;
|
355
|
+
static size_t (*malloc_usable_size)(void *ptr);
|
356
|
+
|
357
|
+
static void *
|
358
|
+
malloc_tramp(size_t size)
|
359
|
+
{
|
360
|
+
void *ret = NULL;
|
361
|
+
memprof_malloc_stats.malloc_bytes_requested += size;
|
362
|
+
memprof_malloc_stats.malloc_calls++;
|
363
|
+
ret = malloc(size);
|
364
|
+
memprof_malloc_stats.malloc_bytes_actual += malloc_usable_size(ret);
|
365
|
+
return ret;
|
366
|
+
}
|
367
|
+
|
368
|
+
static void *
|
369
|
+
calloc_tramp(size_t nmemb, size_t size)
|
370
|
+
{
|
371
|
+
void *ret = NULL;
|
372
|
+
memprof_malloc_stats.calloc_bytes_requested += (nmemb * size);
|
373
|
+
memprof_malloc_stats.calloc_calls++;
|
374
|
+
ret = calloc(nmemb, size);
|
375
|
+
memprof_malloc_stats.calloc_bytes_actual += malloc_usable_size(ret);
|
376
|
+
return ret;
|
377
|
+
}
|
378
|
+
|
379
|
+
static void *
|
380
|
+
realloc_tramp(void *ptr, size_t size)
|
381
|
+
{
|
382
|
+
/* TODO need to check malloc_usable_size of before/after i guess? */
|
383
|
+
void *ret = NULL;
|
384
|
+
memprof_malloc_stats.realloc_bytes_requested += size;
|
385
|
+
memprof_malloc_stats.realloc_calls++;
|
386
|
+
ret = realloc(ptr, size);
|
387
|
+
memprof_malloc_stats.realloc_bytes_actual += malloc_usable_size(ptr);
|
388
|
+
return ret;
|
389
|
+
}
|
390
|
+
|
391
|
+
static void
|
392
|
+
free_tramp(void *ptr)
|
393
|
+
{
|
394
|
+
/* TODO use malloc_usable_size to track bytes freed? */
|
395
|
+
memprof_malloc_stats.free_bytes_actual += malloc_usable_size(ptr);
|
396
|
+
memprof_malloc_stats.free_calls++;
|
397
|
+
free(ptr);
|
398
|
+
}
|
399
|
+
|
400
|
+
static void
|
401
|
+
memprof_start_track_bytes()
|
402
|
+
{
|
403
|
+
struct tramp_st2_entry tmp;
|
404
|
+
|
405
|
+
if (!malloc_usable_size) {
|
406
|
+
if ((malloc_usable_size =
|
407
|
+
bin_find_symbol("MallocExtension_GetAllocatedSize", NULL, 1)) == NULL) {
|
408
|
+
malloc_usable_size = bin_find_symbol("malloc_usable_size", NULL, 1);
|
409
|
+
dbg_printf("tcmalloc was not found...\n");
|
410
|
+
}
|
411
|
+
assert(malloc_usable_size != NULL);
|
412
|
+
dbg_printf("malloc_usable_size: %p\n", malloc_usable_size);
|
413
|
+
}
|
414
|
+
|
415
|
+
tmp.addr = malloc_tramp;
|
416
|
+
bin_update_image("malloc", &tmp, &orig_malloc);
|
417
|
+
assert(orig_malloc != NULL);
|
418
|
+
dbg_printf("orig_malloc: %p\n", orig_malloc);
|
419
|
+
|
420
|
+
tmp.addr = realloc_tramp;
|
421
|
+
bin_update_image("realloc", &tmp, &orig_realloc);
|
422
|
+
dbg_printf("orig_realloc: %p\n", orig_realloc);
|
423
|
+
|
424
|
+
tmp.addr = calloc_tramp;
|
425
|
+
bin_update_image("calloc", &tmp, &orig_calloc);
|
426
|
+
dbg_printf("orig_calloc: %p\n", orig_calloc);
|
427
|
+
|
428
|
+
tmp.addr = free_tramp;
|
429
|
+
bin_update_image("free", &tmp, &orig_free);
|
430
|
+
assert(orig_free != NULL);
|
431
|
+
dbg_printf("orig_free: %p\n", orig_free);
|
432
|
+
}
|
433
|
+
|
434
|
+
static void
|
435
|
+
memprof_stop_track_bytes()
|
436
|
+
{
|
437
|
+
struct tramp_st2_entry tmp;
|
438
|
+
|
439
|
+
tmp.addr = orig_malloc;
|
440
|
+
bin_update_image("malloc", &tmp, NULL);
|
441
|
+
|
442
|
+
tmp.addr = orig_realloc;
|
443
|
+
bin_update_image("realloc", &tmp, NULL);
|
444
|
+
|
445
|
+
tmp.addr = orig_calloc;
|
446
|
+
bin_update_image("calloc", &tmp, NULL);
|
447
|
+
|
448
|
+
tmp.addr = orig_free;
|
449
|
+
bin_update_image("free", &tmp, NULL);
|
450
|
+
}
|
451
|
+
|
452
|
+
static void
|
453
|
+
memprof_reset_track_bytes()
|
454
|
+
{
|
455
|
+
memset(&memprof_malloc_stats, 0, sizeof(memprof_malloc_stats));
|
456
|
+
}
|
457
|
+
|
458
|
+
static VALUE
|
459
|
+
memprof_track_bytes(int argc, VALUE *argv, VALUE self)
|
460
|
+
{
|
461
|
+
if (!rb_block_given_p())
|
462
|
+
rb_raise(rb_eArgError, "block required");
|
463
|
+
|
464
|
+
memprof_start_track_bytes();
|
465
|
+
rb_yield(Qnil);
|
466
|
+
fprintf(stderr, "================ Requested ====================\n");
|
467
|
+
fprintf(stderr, "Malloced: %zd, Realloced: %zd, Calloced: %zd\n",
|
468
|
+
memprof_malloc_stats.malloc_bytes_requested, memprof_malloc_stats.realloc_bytes_requested,
|
469
|
+
memprof_malloc_stats.calloc_bytes_requested);
|
470
|
+
fprintf(stderr, "================ Actual ====================\n");
|
471
|
+
fprintf(stderr, "Malloced: %zd, Realloced: %zd, Calloced: %zd, Freed: %zd\n",
|
472
|
+
memprof_malloc_stats.malloc_bytes_actual, memprof_malloc_stats.realloc_bytes_actual,
|
473
|
+
memprof_malloc_stats.calloc_bytes_actual, memprof_malloc_stats.free_bytes_actual);
|
474
|
+
fprintf(stderr, "================ Call count ====================\n");
|
475
|
+
fprintf(stderr, "Calls to malloc: %zd, realloc: %zd, calloc: %zd, free: %zd\n",
|
476
|
+
memprof_malloc_stats.malloc_calls,
|
477
|
+
memprof_malloc_stats.realloc_calls,
|
478
|
+
memprof_malloc_stats.calloc_calls,
|
479
|
+
memprof_malloc_stats.free_calls);
|
480
|
+
|
481
|
+
memprof_reset_track_bytes();
|
482
|
+
memprof_stop_track_bytes();
|
483
|
+
return Qnil;
|
484
|
+
}
|
485
|
+
|
305
486
|
#include <yajl/yajl_gen.h>
|
306
487
|
#include <stdarg.h>
|
307
488
|
#include "env.h"
|
489
|
+
#include "rubyio.h"
|
308
490
|
#include "re.h"
|
309
491
|
|
492
|
+
#ifndef RARRAY_PTR
|
493
|
+
#define RARRAY_PTR(ary) RARRAY(ary)->ptr
|
494
|
+
#endif
|
495
|
+
|
496
|
+
#ifndef RARRAY_LEN
|
497
|
+
#define RARRAY_LEN(ary) RARRAY(ary)->len
|
498
|
+
#endif
|
499
|
+
|
500
|
+
#ifndef RSTRING_PTR
|
501
|
+
#define RSTRING_PTR(str) RSTRING(str)->ptr
|
502
|
+
#endif
|
503
|
+
|
504
|
+
#ifndef RSTRING_LEN
|
505
|
+
#define RSTRING_LEN(str) RSTRING(str)->len
|
506
|
+
#endif
|
507
|
+
|
508
|
+
/* HAX: copied from internal yajl_gen.c (PATCH yajl before building instead)
|
509
|
+
*/
|
510
|
+
|
511
|
+
typedef enum {
|
512
|
+
yajl_gen_start,
|
513
|
+
yajl_gen_map_start,
|
514
|
+
yajl_gen_map_key,
|
515
|
+
yajl_gen_map_val,
|
516
|
+
yajl_gen_array_start,
|
517
|
+
yajl_gen_in_array,
|
518
|
+
yajl_gen_complete,
|
519
|
+
yajl_gen_error
|
520
|
+
} yajl_gen_state;
|
521
|
+
|
522
|
+
struct yajl_gen_t
|
523
|
+
{
|
524
|
+
unsigned int depth;
|
525
|
+
unsigned int pretty;
|
526
|
+
const char * indentString;
|
527
|
+
yajl_gen_state state[YAJL_MAX_DEPTH];
|
528
|
+
yajl_print_t print;
|
529
|
+
void * ctx; /* yajl_buf */
|
530
|
+
/* memory allocation routines */
|
531
|
+
yajl_alloc_funcs alloc;
|
532
|
+
};
|
533
|
+
|
534
|
+
static void
|
535
|
+
yajl_gen_reset(yajl_gen gen)
|
536
|
+
{
|
537
|
+
yajl_gen_clear(gen);
|
538
|
+
assert (gen->state[gen->depth] == yajl_gen_complete);
|
539
|
+
gen->state[gen->depth] = yajl_gen_start;
|
540
|
+
gen->print(gen->ctx, "\n", 1);
|
541
|
+
}
|
542
|
+
|
543
|
+
/* END HAX
|
544
|
+
*/
|
545
|
+
|
310
546
|
static yajl_gen_status
|
311
547
|
yajl_gen_cstr(yajl_gen gen, const char * str)
|
312
548
|
{
|
@@ -335,6 +571,24 @@ yajl_gen_format(yajl_gen gen, char *format, ...)
|
|
335
571
|
return ret;
|
336
572
|
}
|
337
573
|
|
574
|
+
static yajl_gen_status
|
575
|
+
yajl_gen_id(yajl_gen gen, ID id)
|
576
|
+
{
|
577
|
+
if (id) {
|
578
|
+
if (id < 100)
|
579
|
+
return yajl_gen_format(gen, ":%c", id);
|
580
|
+
else
|
581
|
+
return yajl_gen_format(gen, ":%s", rb_id2name(id));
|
582
|
+
} else
|
583
|
+
return yajl_gen_null(gen);
|
584
|
+
}
|
585
|
+
|
586
|
+
static yajl_gen_status
|
587
|
+
yajl_gen_pointer(yajl_gen gen, void* ptr)
|
588
|
+
{
|
589
|
+
return yajl_gen_format(gen, "0x%x", ptr);
|
590
|
+
}
|
591
|
+
|
338
592
|
static yajl_gen_status
|
339
593
|
yajl_gen_value(yajl_gen gen, VALUE obj)
|
340
594
|
{
|
@@ -347,9 +601,9 @@ yajl_gen_value(yajl_gen gen, VALUE obj)
|
|
347
601
|
else if (obj == Qfalse)
|
348
602
|
return yajl_gen_bool(gen, 0);
|
349
603
|
else if (SYMBOL_P(obj))
|
350
|
-
return
|
604
|
+
return yajl_gen_id(gen, SYM2ID(obj));
|
351
605
|
else
|
352
|
-
return
|
606
|
+
return yajl_gen_pointer(gen, (void*)obj);
|
353
607
|
}
|
354
608
|
|
355
609
|
static int
|
@@ -418,7 +672,20 @@ nd_type_str(VALUE obj)
|
|
418
672
|
}
|
419
673
|
}
|
420
674
|
|
421
|
-
static
|
675
|
+
static inline void
|
676
|
+
obj_dump_class(yajl_gen gen, VALUE obj)
|
677
|
+
{
|
678
|
+
if (RBASIC(obj)->klass) {
|
679
|
+
yajl_gen_cstr(gen, "class");
|
680
|
+
yajl_gen_value(gen, RBASIC(obj)->klass);
|
681
|
+
|
682
|
+
VALUE name = rb_classname(RBASIC(obj)->klass);
|
683
|
+
if (RTEST(name)) {
|
684
|
+
yajl_gen_cstr(gen, "class_name");
|
685
|
+
yajl_gen_cstr(gen, RSTRING_PTR(name));
|
686
|
+
}
|
687
|
+
}
|
688
|
+
}
|
422
689
|
|
423
690
|
/* TODO
|
424
691
|
* look for FL_EXIVAR flag and print ivars
|
@@ -442,42 +709,307 @@ obj_dump(VALUE obj, yajl_gen gen)
|
|
442
709
|
yajl_gen_cstr(gen, tracker->source);
|
443
710
|
yajl_gen_cstr(gen, "line");
|
444
711
|
yajl_gen_integer(gen, tracker->line);
|
712
|
+
yajl_gen_cstr(gen, "time");
|
713
|
+
yajl_gen_integer(gen, (tracker->time[0].tv_sec * 1000000) + tracker->time[0].tv_usec);
|
445
714
|
}
|
446
715
|
|
447
716
|
yajl_gen_cstr(gen, "type");
|
448
717
|
switch (type=BUILTIN_TYPE(obj)) {
|
449
718
|
case T_DATA:
|
450
719
|
yajl_gen_cstr(gen, "data");
|
720
|
+
obj_dump_class(gen, obj);
|
451
721
|
|
452
|
-
if (
|
453
|
-
yajl_gen_cstr(gen, "
|
454
|
-
|
722
|
+
if (DATA_PTR(obj)) {
|
723
|
+
yajl_gen_cstr(gen, "data");
|
724
|
+
yajl_gen_pointer(gen, DATA_PTR(obj));
|
725
|
+
}
|
726
|
+
|
727
|
+
if (RDATA(obj)->dfree == (RUBY_DATA_FUNC)rb_blk_free) {
|
728
|
+
void *val;
|
729
|
+
VALUE ptr;
|
730
|
+
|
731
|
+
val = *(void**)(DATA_PTR(obj) + memprof_config.offset_BLOCK_body);
|
732
|
+
if (val) {
|
733
|
+
yajl_gen_cstr(gen, "nd_body");
|
734
|
+
yajl_gen_pointer(gen, val);
|
735
|
+
}
|
736
|
+
|
737
|
+
val = *(void**)(DATA_PTR(obj) + memprof_config.offset_BLOCK_var);
|
738
|
+
if (val) {
|
739
|
+
yajl_gen_cstr(gen, "nd_var");
|
740
|
+
yajl_gen_pointer(gen, val);
|
741
|
+
}
|
742
|
+
|
743
|
+
val = *(void**)(DATA_PTR(obj) + memprof_config.offset_BLOCK_cref);
|
744
|
+
if (val) {
|
745
|
+
yajl_gen_cstr(gen, "nd_cref");
|
746
|
+
yajl_gen_pointer(gen, val);
|
747
|
+
}
|
748
|
+
|
749
|
+
val = *(void**)(DATA_PTR(obj) + memprof_config.offset_BLOCK_dyna_vars);
|
750
|
+
if (val) {
|
751
|
+
yajl_gen_cstr(gen, "vars");
|
752
|
+
yajl_gen_pointer(gen, val);
|
753
|
+
}
|
754
|
+
|
755
|
+
val = *(void**)(DATA_PTR(obj) + memprof_config.offset_BLOCK_scope);
|
756
|
+
if (val) {
|
757
|
+
yajl_gen_cstr(gen, "scope");
|
758
|
+
yajl_gen_pointer(gen, val);
|
759
|
+
}
|
760
|
+
|
761
|
+
ptr = *(VALUE*)(DATA_PTR(obj) + memprof_config.offset_BLOCK_self);
|
762
|
+
yajl_gen_cstr(gen, "self");
|
763
|
+
yajl_gen_value(gen, ptr);
|
764
|
+
|
765
|
+
ptr = *(VALUE*)(DATA_PTR(obj) + memprof_config.offset_BLOCK_klass);
|
766
|
+
yajl_gen_cstr(gen, "klass");
|
767
|
+
yajl_gen_value(gen, ptr);
|
768
|
+
|
769
|
+
ptr = *(VALUE*)(DATA_PTR(obj) + memprof_config.offset_BLOCK_orig_thread);
|
770
|
+
yajl_gen_cstr(gen, "thread");
|
771
|
+
yajl_gen_value(gen, ptr);
|
772
|
+
|
773
|
+
ptr = *(VALUE*)(DATA_PTR(obj) + memprof_config.offset_BLOCK_wrapper);
|
774
|
+
if (RTEST(ptr)) {
|
775
|
+
yajl_gen_cstr(gen, "wrapper");
|
776
|
+
yajl_gen_value(gen, ptr);
|
777
|
+
}
|
778
|
+
|
779
|
+
ptr = *(VALUE*)(DATA_PTR(obj) + memprof_config.offset_BLOCK_block_obj);
|
780
|
+
if (RTEST(ptr)) {
|
781
|
+
yajl_gen_cstr(gen, "block");
|
782
|
+
yajl_gen_value(gen, ptr);
|
783
|
+
}
|
784
|
+
|
785
|
+
/* TODO: is .prev actually useful? refers to non-heap allocated struct BLOCKs,
|
786
|
+
* but we don't print out any information about those
|
787
|
+
*/
|
788
|
+
/*
|
789
|
+
yajl_gen_cstr(gen, "prev");
|
790
|
+
yajl_gen_array_open(gen);
|
791
|
+
val = *(void**)(DATA_PTR(obj) + memprof_config.offset_BLOCK_prev);
|
792
|
+
while (val) {
|
793
|
+
yajl_gen_pointer(gen, val);
|
794
|
+
prev = val;
|
795
|
+
val = *(void**)(ptr + memprof_config.offset_BLOCK_prev);
|
796
|
+
if (prev == val)
|
797
|
+
break;
|
798
|
+
}
|
799
|
+
yajl_gen_array_close(gen);
|
800
|
+
*/
|
801
|
+
|
802
|
+
} else if (RDATA(obj)->dmark == (RUBY_DATA_FUNC)rb_bm_mark) {
|
803
|
+
VALUE ptr;
|
804
|
+
ID id, mid;
|
805
|
+
|
806
|
+
ptr = *(VALUE*)(DATA_PTR(obj) + memprof_config.offset_METHOD_klass);
|
807
|
+
if (RTEST(ptr)) {
|
808
|
+
yajl_gen_cstr(gen, "klass");
|
809
|
+
yajl_gen_value(gen, ptr);
|
810
|
+
}
|
811
|
+
|
812
|
+
ptr = *(VALUE*)(DATA_PTR(obj) + memprof_config.offset_METHOD_rklass);
|
813
|
+
if (RTEST(ptr)) {
|
814
|
+
yajl_gen_cstr(gen, "rklass");
|
815
|
+
yajl_gen_value(gen, ptr);
|
816
|
+
}
|
817
|
+
|
818
|
+
ptr = *(VALUE*)(DATA_PTR(obj) + memprof_config.offset_METHOD_recv);
|
819
|
+
if (RTEST(ptr)) {
|
820
|
+
yajl_gen_cstr(gen, "recv");
|
821
|
+
yajl_gen_value(gen, ptr);
|
822
|
+
}
|
823
|
+
|
824
|
+
ptr = *(VALUE*)(DATA_PTR(obj) + memprof_config.offset_METHOD_body);
|
825
|
+
if (RTEST(ptr)) {
|
826
|
+
yajl_gen_cstr(gen, "node");
|
827
|
+
yajl_gen_value(gen, ptr);
|
828
|
+
}
|
829
|
+
|
830
|
+
mid = *(ID*)(DATA_PTR(obj) + memprof_config.offset_METHOD_id);
|
831
|
+
if (mid) {
|
832
|
+
yajl_gen_cstr(gen, "mid");
|
833
|
+
yajl_gen_id(gen, mid);
|
834
|
+
}
|
835
|
+
|
836
|
+
id = *(ID*)(DATA_PTR(obj) + memprof_config.offset_METHOD_oid);
|
837
|
+
if (id && id != mid) {
|
838
|
+
yajl_gen_cstr(gen, "oid");
|
839
|
+
yajl_gen_id(gen, id);
|
840
|
+
}
|
841
|
+
|
842
|
+
} else if (RDATA(obj)->dmark == (RUBY_DATA_FUNC)rb_thread_mark) {
|
843
|
+
rb_thread_t th = (rb_thread_t)DATA_PTR(obj);
|
844
|
+
|
845
|
+
if (th == rb_curr_thread) {
|
846
|
+
yajl_gen_cstr(gen, "current");
|
847
|
+
yajl_gen_bool(gen, 1);
|
848
|
+
} else {
|
849
|
+
if (th->dyna_vars) {
|
850
|
+
yajl_gen_cstr(gen, "varmap");
|
851
|
+
yajl_gen_pointer(gen, th->dyna_vars);
|
852
|
+
}
|
853
|
+
|
854
|
+
yajl_gen_cstr(gen, "node");
|
855
|
+
yajl_gen_pointer(gen, th->node);
|
856
|
+
|
857
|
+
yajl_gen_cstr(gen, "cref");
|
858
|
+
yajl_gen_pointer(gen, th->cref);
|
859
|
+
|
860
|
+
char *status;
|
861
|
+
switch (th->status) {
|
862
|
+
case THREAD_TO_KILL:
|
863
|
+
status = "to_kill";
|
864
|
+
break;
|
865
|
+
case THREAD_RUNNABLE:
|
866
|
+
status = "runnable";
|
867
|
+
break;
|
868
|
+
case THREAD_STOPPED:
|
869
|
+
status = "stopped";
|
870
|
+
break;
|
871
|
+
case THREAD_KILLED:
|
872
|
+
status = "killed";
|
873
|
+
break;
|
874
|
+
default:
|
875
|
+
status = "unknown";
|
876
|
+
}
|
877
|
+
|
878
|
+
yajl_gen_cstr(gen, "status");
|
879
|
+
yajl_gen_cstr(gen, status);
|
880
|
+
|
881
|
+
#define WAIT_FD (1<<0)
|
882
|
+
#define WAIT_SELECT (1<<1)
|
883
|
+
#define WAIT_TIME (1<<2)
|
884
|
+
#define WAIT_JOIN (1<<3)
|
885
|
+
#define WAIT_PID (1<<4)
|
886
|
+
|
887
|
+
yajl_gen_cstr(gen, "wait_for");
|
888
|
+
yajl_gen_array_open(gen);
|
889
|
+
if (th->wait_for & WAIT_FD)
|
890
|
+
yajl_gen_cstr(gen, "fd");
|
891
|
+
if (th->wait_for & WAIT_SELECT)
|
892
|
+
yajl_gen_cstr(gen, "select");
|
893
|
+
if (th->wait_for & WAIT_TIME)
|
894
|
+
yajl_gen_cstr(gen, "time");
|
895
|
+
if (th->wait_for & WAIT_JOIN)
|
896
|
+
yajl_gen_cstr(gen, "join");
|
897
|
+
if (th->wait_for & WAIT_PID)
|
898
|
+
yajl_gen_cstr(gen, "pid");
|
899
|
+
yajl_gen_array_close(gen);
|
900
|
+
|
901
|
+
if (th->wait_for & WAIT_FD) {
|
902
|
+
yajl_gen_cstr(gen, "fd");
|
903
|
+
yajl_gen_integer(gen, th->fd);
|
904
|
+
}
|
905
|
+
|
906
|
+
#define DELAY_INFTY 1E30
|
907
|
+
|
908
|
+
if (th->wait_for & WAIT_TIME) {
|
909
|
+
yajl_gen_cstr(gen, "delay");
|
910
|
+
if (th->delay == DELAY_INFTY)
|
911
|
+
yajl_gen_cstr(gen, "infinity");
|
912
|
+
else
|
913
|
+
yajl_gen_double(gen, th->delay - rb_timeofday());
|
914
|
+
}
|
915
|
+
|
916
|
+
if (th->wait_for & WAIT_JOIN) {
|
917
|
+
yajl_gen_cstr(gen, "join");
|
918
|
+
yajl_gen_value(gen, th->join->thread);
|
919
|
+
}
|
920
|
+
}
|
921
|
+
|
922
|
+
yajl_gen_cstr(gen, "priority");
|
923
|
+
yajl_gen_integer(gen, th->priority);
|
924
|
+
|
925
|
+
if (th == rb_main_thread) {
|
926
|
+
yajl_gen_cstr(gen, "main");
|
927
|
+
yajl_gen_bool(gen, 1);
|
928
|
+
}
|
929
|
+
|
930
|
+
if (th->next && th->next != rb_main_thread) {
|
931
|
+
yajl_gen_cstr(gen, "next");
|
932
|
+
yajl_gen_value(gen, th->next->thread);
|
933
|
+
}
|
934
|
+
if (th->prev && th->prev != th && (th->prev == rb_main_thread || th->prev != th->next)) {
|
935
|
+
yajl_gen_cstr(gen, "prev");
|
936
|
+
yajl_gen_value(gen, th->prev->thread);
|
937
|
+
}
|
938
|
+
|
939
|
+
if (th->locals) {
|
940
|
+
yajl_gen_cstr(gen, "variables");
|
941
|
+
yajl_gen_map_open(gen);
|
942
|
+
st_foreach(th->locals, each_ivar, (st_data_t)gen);
|
943
|
+
yajl_gen_map_close(gen);
|
944
|
+
}
|
455
945
|
|
456
|
-
yajl_gen_cstr(gen, "class_name");
|
457
|
-
VALUE name = rb_classname(RBASIC(obj)->klass);
|
458
|
-
if (RTEST(name))
|
459
|
-
yajl_gen_cstr(gen, RSTRING(name)->ptr);
|
460
|
-
else
|
461
|
-
yajl_gen_cstr(gen, 0);
|
462
946
|
}
|
463
947
|
break;
|
464
948
|
|
465
949
|
case T_STRUCT:
|
466
950
|
yajl_gen_cstr(gen, "struct");
|
467
|
-
|
468
|
-
yajl_gen_cstr(gen, "class");
|
469
|
-
yajl_gen_value(gen, RBASIC(obj)->klass);
|
470
|
-
|
471
|
-
yajl_gen_cstr(gen, "class_name");
|
472
|
-
yajl_gen_cstr(gen, rb_obj_classname(obj));
|
951
|
+
obj_dump_class(gen, obj);
|
473
952
|
break;
|
474
953
|
|
475
954
|
case T_FILE:
|
476
955
|
yajl_gen_cstr(gen, "file");
|
956
|
+
obj_dump_class(gen, obj);
|
957
|
+
|
958
|
+
OpenFile *file = RFILE(obj)->fptr;
|
959
|
+
|
960
|
+
if (file->f) {
|
961
|
+
yajl_gen_cstr(gen, "fileno");
|
962
|
+
yajl_gen_integer(gen, fileno(file->f));
|
963
|
+
}
|
964
|
+
|
965
|
+
if (file->f2) {
|
966
|
+
yajl_gen_cstr(gen, "fileno2");
|
967
|
+
yajl_gen_integer(gen, fileno(file->f2));
|
968
|
+
}
|
969
|
+
|
970
|
+
if (file->pid) {
|
971
|
+
yajl_gen_cstr(gen, "pid");
|
972
|
+
yajl_gen_integer(gen, file->pid);
|
973
|
+
}
|
974
|
+
|
975
|
+
if (file->path) {
|
976
|
+
yajl_gen_cstr(gen, "path");
|
977
|
+
yajl_gen_cstr(gen, file->path);
|
978
|
+
}
|
979
|
+
|
980
|
+
if (file->mode) {
|
981
|
+
yajl_gen_cstr(gen, "mode");
|
982
|
+
yajl_gen_array_open(gen);
|
983
|
+
if (file->mode & FMODE_READABLE)
|
984
|
+
yajl_gen_cstr(gen, "readable");
|
985
|
+
if (file->mode & FMODE_WRITABLE)
|
986
|
+
yajl_gen_cstr(gen, "writable");
|
987
|
+
if (file->mode & FMODE_READWRITE)
|
988
|
+
yajl_gen_cstr(gen, "readwrite");
|
989
|
+
if (file->mode & FMODE_APPEND)
|
990
|
+
yajl_gen_cstr(gen, "append");
|
991
|
+
if (file->mode & FMODE_CREATE)
|
992
|
+
yajl_gen_cstr(gen, "create");
|
993
|
+
if (file->mode & FMODE_BINMODE)
|
994
|
+
yajl_gen_cstr(gen, "binmode");
|
995
|
+
if (file->mode & FMODE_SYNC)
|
996
|
+
yajl_gen_cstr(gen, "sync");
|
997
|
+
if (file->mode & FMODE_WBUF)
|
998
|
+
yajl_gen_cstr(gen, "wbuf");
|
999
|
+
if (file->mode & FMODE_RBUF)
|
1000
|
+
yajl_gen_cstr(gen, "rbuf");
|
1001
|
+
if (file->mode & FMODE_WSPLIT)
|
1002
|
+
yajl_gen_cstr(gen, "wsplit");
|
1003
|
+
if (file->mode & FMODE_WSPLIT_INITIALIZED)
|
1004
|
+
yajl_gen_cstr(gen, "wsplit_initialized");
|
1005
|
+
yajl_gen_array_close(gen);
|
1006
|
+
}
|
1007
|
+
|
477
1008
|
break;
|
478
1009
|
|
479
1010
|
case T_FLOAT:
|
480
1011
|
yajl_gen_cstr(gen, "float");
|
1012
|
+
obj_dump_class(gen, obj);
|
481
1013
|
|
482
1014
|
yajl_gen_cstr(gen, "data");
|
483
1015
|
yajl_gen_double(gen, RFLOAT(obj)->value);
|
@@ -485,6 +1017,7 @@ obj_dump(VALUE obj, yajl_gen gen)
|
|
485
1017
|
|
486
1018
|
case T_BIGNUM:
|
487
1019
|
yajl_gen_cstr(gen, "bignum");
|
1020
|
+
obj_dump_class(gen, obj);
|
488
1021
|
|
489
1022
|
yajl_gen_cstr(gen, "negative");
|
490
1023
|
yajl_gen_bool(gen, RBIGNUM(obj)->sign == 0);
|
@@ -498,6 +1031,7 @@ obj_dump(VALUE obj, yajl_gen gen)
|
|
498
1031
|
|
499
1032
|
case T_MATCH:
|
500
1033
|
yajl_gen_cstr(gen, "match");
|
1034
|
+
obj_dump_class(gen, obj);
|
501
1035
|
|
502
1036
|
yajl_gen_cstr(gen, "data");
|
503
1037
|
yajl_gen_value(gen, RMATCH(obj)->str);
|
@@ -505,6 +1039,7 @@ obj_dump(VALUE obj, yajl_gen gen)
|
|
505
1039
|
|
506
1040
|
case T_REGEXP:
|
507
1041
|
yajl_gen_cstr(gen, "regexp");
|
1042
|
+
obj_dump_class(gen, obj);
|
508
1043
|
|
509
1044
|
yajl_gen_cstr(gen, "length");
|
510
1045
|
yajl_gen_integer(gen, RREGEXP(obj)->len);
|
@@ -523,8 +1058,10 @@ obj_dump(VALUE obj, yajl_gen gen)
|
|
523
1058
|
VALUE *list = &scope->local_vars[-1];
|
524
1059
|
VALUE cur = *list++;
|
525
1060
|
|
526
|
-
|
527
|
-
|
1061
|
+
if (RTEST(cur)) {
|
1062
|
+
yajl_gen_cstr(gen, "node");
|
1063
|
+
yajl_gen_value(gen, cur);
|
1064
|
+
}
|
528
1065
|
|
529
1066
|
if (n) {
|
530
1067
|
yajl_gen_cstr(gen, "variables");
|
@@ -536,7 +1073,7 @@ obj_dump(VALUE obj, yajl_gen gen)
|
|
536
1073
|
if (!rb_is_local_id(scope->local_tbl[i]))
|
537
1074
|
continue;
|
538
1075
|
|
539
|
-
|
1076
|
+
yajl_gen_id(gen, scope->local_tbl[i]);
|
540
1077
|
yajl_gen_value(gen, cur);
|
541
1078
|
}
|
542
1079
|
yajl_gen_map_close(gen);
|
@@ -559,8 +1096,8 @@ obj_dump(VALUE obj, yajl_gen gen)
|
|
559
1096
|
yajl_gen_cstr(gen, "node_code");
|
560
1097
|
yajl_gen_integer(gen, nd_type(obj));
|
561
1098
|
|
562
|
-
#define PRINT_ID(sub)
|
563
|
-
#define PRINT_VAL(sub) yajl_gen_value(gen, RNODE(obj)->sub.value)
|
1099
|
+
#define PRINT_ID(sub) yajl_gen_id(gen, RNODE(obj)->sub.id)
|
1100
|
+
#define PRINT_VAL(sub) yajl_gen_value(gen, RNODE(obj)->sub.value)
|
564
1101
|
|
565
1102
|
int nd_type = nd_type(obj);
|
566
1103
|
yajl_gen_cstr(gen, "n1");
|
@@ -580,9 +1117,18 @@ obj_dump(VALUE obj, yajl_gen gen)
|
|
580
1117
|
case NODE_GASGN:
|
581
1118
|
case NODE_DASGN_CURR:
|
582
1119
|
case NODE_BLOCK_ARG:
|
1120
|
+
case NODE_CDECL:
|
1121
|
+
case NODE_VALIAS:
|
583
1122
|
PRINT_ID(u1);
|
584
1123
|
break;
|
585
1124
|
|
1125
|
+
case NODE_OP_ASGN2:
|
1126
|
+
if (RNODE(obj)->u3.id > 1000000)
|
1127
|
+
PRINT_VAL(u1);
|
1128
|
+
else
|
1129
|
+
PRINT_ID(u1);
|
1130
|
+
break;
|
1131
|
+
|
586
1132
|
case NODE_SCOPE: {
|
587
1133
|
ID *tbl = RNODE(obj)->nd_tbl;
|
588
1134
|
yajl_gen_array_open(gen);
|
@@ -591,13 +1137,14 @@ obj_dump(VALUE obj, yajl_gen gen)
|
|
591
1137
|
int i = 3;
|
592
1138
|
|
593
1139
|
for (; i < size+1; i++) {
|
594
|
-
|
1140
|
+
yajl_gen_id(gen, tbl[i]);
|
595
1141
|
}
|
596
1142
|
}
|
597
1143
|
yajl_gen_array_close(gen);
|
598
1144
|
break;
|
599
1145
|
}
|
600
1146
|
|
1147
|
+
case NODE_IFUNC:
|
601
1148
|
case NODE_CFUNC: {
|
602
1149
|
const char *name = bin_find_symbol_name((void*)RNODE(obj)->u1.value);
|
603
1150
|
yajl_gen_format(gen, "0x%x: %s", RNODE(obj)->u1.value, name ? name : "???");
|
@@ -618,13 +1165,51 @@ obj_dump(VALUE obj, yajl_gen gen)
|
|
618
1165
|
case NODE_VCALL:
|
619
1166
|
case NODE_COLON2:
|
620
1167
|
case NODE_COLON3:
|
1168
|
+
case NODE_BACK_REF:
|
1169
|
+
case NODE_DEFS:
|
1170
|
+
case NODE_VALIAS:
|
621
1171
|
PRINT_ID(u2);
|
622
1172
|
break;
|
623
1173
|
|
1174
|
+
case NODE_OP_ASGN1:
|
1175
|
+
if (RNODE(obj)->nd_mid == 0)
|
1176
|
+
yajl_gen_cstr(gen, ":||");
|
1177
|
+
else if (RNODE(obj)->nd_mid == 1)
|
1178
|
+
yajl_gen_cstr(gen, ":&&");
|
1179
|
+
else
|
1180
|
+
PRINT_ID(u2);
|
1181
|
+
break;
|
1182
|
+
|
1183
|
+
case NODE_OP_ASGN2:
|
1184
|
+
if (RNODE(obj)->u3.id > 1000000) {
|
1185
|
+
PRINT_VAL(u2);
|
1186
|
+
} else {
|
1187
|
+
if (RNODE(obj)->nd_mid == 0)
|
1188
|
+
yajl_gen_cstr(gen, ":||");
|
1189
|
+
else if (RNODE(obj)->nd_mid == 1)
|
1190
|
+
yajl_gen_cstr(gen, ":&&");
|
1191
|
+
else
|
1192
|
+
PRINT_ID(u2);
|
1193
|
+
}
|
1194
|
+
break;
|
1195
|
+
|
1196
|
+
case NODE_DREGX:
|
1197
|
+
case NODE_DREGX_ONCE:
|
624
1198
|
case NODE_NTH_REF:
|
1199
|
+
case NODE_IFUNC:
|
1200
|
+
case NODE_CFUNC:
|
1201
|
+
case NODE_NEWLINE:
|
625
1202
|
yajl_gen_integer(gen, RNODE(obj)->u2.argc);
|
626
1203
|
break;
|
627
1204
|
|
1205
|
+
case NODE_BLOCK:
|
1206
|
+
case NODE_ARRAY:
|
1207
|
+
if (RNODE(obj)->u2.node == RNODE(obj))
|
1208
|
+
yajl_gen_null(gen);
|
1209
|
+
else
|
1210
|
+
PRINT_VAL(u2);
|
1211
|
+
break;
|
1212
|
+
|
628
1213
|
default:
|
629
1214
|
PRINT_VAL(u2);
|
630
1215
|
}
|
@@ -635,6 +1220,13 @@ obj_dump(VALUE obj, yajl_gen gen)
|
|
635
1220
|
yajl_gen_integer(gen, RNODE(obj)->u3.cnt);
|
636
1221
|
break;
|
637
1222
|
|
1223
|
+
case NODE_OP_ASGN2:
|
1224
|
+
if (RNODE(obj)->u3.id > 1000000)
|
1225
|
+
PRINT_VAL(u3);
|
1226
|
+
else
|
1227
|
+
PRINT_ID(u3);
|
1228
|
+
break;
|
1229
|
+
|
638
1230
|
default:
|
639
1231
|
PRINT_VAL(u3);
|
640
1232
|
}
|
@@ -642,9 +1234,10 @@ obj_dump(VALUE obj, yajl_gen gen)
|
|
642
1234
|
|
643
1235
|
case T_STRING:
|
644
1236
|
yajl_gen_cstr(gen, "string");
|
1237
|
+
obj_dump_class(gen, obj);
|
645
1238
|
|
646
1239
|
yajl_gen_cstr(gen, "length");
|
647
|
-
yajl_gen_integer(gen,
|
1240
|
+
yajl_gen_integer(gen, RSTRING_LEN(obj));
|
648
1241
|
|
649
1242
|
if (FL_TEST(obj, ELTS_SHARED|FL_USER3)) {
|
650
1243
|
yajl_gen_cstr(gen, "shared");
|
@@ -659,12 +1252,13 @@ obj_dump(VALUE obj, yajl_gen gen)
|
|
659
1252
|
yajl_gen_array_close(gen);
|
660
1253
|
} else {
|
661
1254
|
yajl_gen_cstr(gen, "data");
|
662
|
-
yajl_gen_string(gen, (unsigned char *)
|
1255
|
+
yajl_gen_string(gen, (unsigned char *)RSTRING_PTR(obj), RSTRING_LEN(obj));
|
663
1256
|
}
|
664
1257
|
break;
|
665
1258
|
|
666
1259
|
case T_VARMAP:
|
667
1260
|
yajl_gen_cstr(gen, "varmap");
|
1261
|
+
obj_dump_class(gen, obj);
|
668
1262
|
|
669
1263
|
struct RVarmap *vars = (struct RVarmap *)obj;
|
670
1264
|
|
@@ -676,7 +1270,7 @@ obj_dump(VALUE obj, yajl_gen gen)
|
|
676
1270
|
if (vars->id) {
|
677
1271
|
yajl_gen_cstr(gen, "data");
|
678
1272
|
yajl_gen_map_open(gen);
|
679
|
-
|
1273
|
+
yajl_gen_id(gen, vars->id);
|
680
1274
|
yajl_gen_value(gen, vars->val);
|
681
1275
|
yajl_gen_map_close(gen);
|
682
1276
|
}
|
@@ -686,23 +1280,26 @@ obj_dump(VALUE obj, yajl_gen gen)
|
|
686
1280
|
case T_MODULE:
|
687
1281
|
case T_ICLASS:
|
688
1282
|
yajl_gen_cstr(gen, type==T_CLASS ? "class" : type==T_MODULE ? "module" : "iclass");
|
1283
|
+
obj_dump_class(gen, obj);
|
689
1284
|
|
690
1285
|
yajl_gen_cstr(gen, "name");
|
691
1286
|
VALUE name = rb_classname(obj);
|
692
1287
|
if (RTEST(name))
|
693
|
-
yajl_gen_cstr(gen,
|
1288
|
+
yajl_gen_cstr(gen, RSTRING_PTR(name));
|
694
1289
|
else
|
695
1290
|
yajl_gen_cstr(gen, 0);
|
696
1291
|
|
697
1292
|
yajl_gen_cstr(gen, "super");
|
698
1293
|
yajl_gen_value(gen, RCLASS(obj)->super);
|
699
1294
|
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
1295
|
+
if (RTEST(RCLASS(obj)->super)) {
|
1296
|
+
yajl_gen_cstr(gen, "super_name");
|
1297
|
+
VALUE super_name = rb_classname(RCLASS(obj)->super);
|
1298
|
+
if (RTEST(super_name))
|
1299
|
+
yajl_gen_cstr(gen, RSTRING_PTR(super_name));
|
1300
|
+
else
|
1301
|
+
yajl_gen_cstr(gen, 0);
|
1302
|
+
}
|
706
1303
|
|
707
1304
|
if (FL_TEST(obj, FL_SINGLETON)) {
|
708
1305
|
yajl_gen_cstr(gen, "singleton");
|
@@ -716,7 +1313,7 @@ obj_dump(VALUE obj, yajl_gen gen)
|
|
716
1313
|
yajl_gen_map_close(gen);
|
717
1314
|
}
|
718
1315
|
|
719
|
-
if (
|
1316
|
+
if (RCLASS(obj)->m_tbl && RCLASS(obj)->m_tbl->num_entries) {
|
720
1317
|
yajl_gen_cstr(gen, "methods");
|
721
1318
|
yajl_gen_map_open(gen);
|
722
1319
|
st_foreach(RCLASS(obj)->m_tbl, each_ivar, (st_data_t)gen);
|
@@ -726,12 +1323,7 @@ obj_dump(VALUE obj, yajl_gen gen)
|
|
726
1323
|
|
727
1324
|
case T_OBJECT:
|
728
1325
|
yajl_gen_cstr(gen, "object");
|
729
|
-
|
730
|
-
yajl_gen_cstr(gen, "class");
|
731
|
-
yajl_gen_value(gen, RBASIC(obj)->klass);
|
732
|
-
|
733
|
-
yajl_gen_cstr(gen, "class_name");
|
734
|
-
yajl_gen_cstr(gen, rb_obj_classname(obj));
|
1326
|
+
obj_dump_class(gen, obj);
|
735
1327
|
|
736
1328
|
struct RClass *klass = RCLASS(obj);
|
737
1329
|
|
@@ -745,6 +1337,7 @@ obj_dump(VALUE obj, yajl_gen gen)
|
|
745
1337
|
|
746
1338
|
case T_ARRAY:
|
747
1339
|
yajl_gen_cstr(gen, "array");
|
1340
|
+
obj_dump_class(gen, obj);
|
748
1341
|
|
749
1342
|
struct RArray *ary = RARRAY(obj);
|
750
1343
|
|
@@ -766,6 +1359,7 @@ obj_dump(VALUE obj, yajl_gen gen)
|
|
766
1359
|
|
767
1360
|
case T_HASH:
|
768
1361
|
yajl_gen_cstr(gen, "hash");
|
1362
|
+
obj_dump_class(gen, obj);
|
769
1363
|
|
770
1364
|
struct RHash *hash = RHASH(obj);
|
771
1365
|
|
@@ -790,6 +1384,7 @@ obj_dump(VALUE obj, yajl_gen gen)
|
|
790
1384
|
|
791
1385
|
default:
|
792
1386
|
yajl_gen_cstr(gen, "unknown");
|
1387
|
+
obj_dump_class(gen, obj);
|
793
1388
|
}
|
794
1389
|
|
795
1390
|
yajl_gen_cstr(gen, "code");
|
@@ -810,11 +1405,163 @@ extern st_table *rb_global_tbl;
|
|
810
1405
|
static int
|
811
1406
|
globals_each_dump(st_data_t key, st_data_t record, st_data_t arg)
|
812
1407
|
{
|
813
|
-
|
1408
|
+
yajl_gen_id((yajl_gen)arg, (ID)key);
|
814
1409
|
yajl_gen_value((yajl_gen)arg, rb_gvar_get((void*)record));
|
815
1410
|
return ST_CONTINUE;
|
816
1411
|
}
|
817
1412
|
|
1413
|
+
static void
|
1414
|
+
memprof_dump_globals(yajl_gen gen)
|
1415
|
+
{
|
1416
|
+
yajl_gen_map_open(gen);
|
1417
|
+
|
1418
|
+
yajl_gen_cstr(gen, "_id");
|
1419
|
+
yajl_gen_cstr(gen, "globals");
|
1420
|
+
|
1421
|
+
yajl_gen_cstr(gen, "type");
|
1422
|
+
yajl_gen_cstr(gen, "globals");
|
1423
|
+
|
1424
|
+
yajl_gen_cstr(gen, "variables");
|
1425
|
+
|
1426
|
+
yajl_gen_map_open(gen);
|
1427
|
+
st_foreach(rb_global_tbl, globals_each_dump, (st_data_t)gen);
|
1428
|
+
yajl_gen_map_close(gen);
|
1429
|
+
|
1430
|
+
yajl_gen_map_close(gen);
|
1431
|
+
yajl_gen_reset(gen);
|
1432
|
+
}
|
1433
|
+
|
1434
|
+
static void
|
1435
|
+
memprof_dump_stack_frame(yajl_gen gen, struct FRAME *frame)
|
1436
|
+
{
|
1437
|
+
yajl_gen_map_open(gen);
|
1438
|
+
|
1439
|
+
yajl_gen_cstr(gen, "_id");
|
1440
|
+
yajl_gen_pointer(gen, frame);
|
1441
|
+
|
1442
|
+
yajl_gen_cstr(gen, "type");
|
1443
|
+
yajl_gen_cstr(gen, "frame");
|
1444
|
+
|
1445
|
+
yajl_gen_cstr(gen, "self");
|
1446
|
+
yajl_gen_value(gen, frame->self);
|
1447
|
+
|
1448
|
+
if (frame->last_class) {
|
1449
|
+
yajl_gen_cstr(gen, "last_class");
|
1450
|
+
yajl_gen_value(gen, frame->last_class);
|
1451
|
+
}
|
1452
|
+
|
1453
|
+
if (frame->orig_func) {
|
1454
|
+
yajl_gen_cstr(gen, "orig_func");
|
1455
|
+
yajl_gen_id(gen, frame->orig_func);
|
1456
|
+
}
|
1457
|
+
|
1458
|
+
if (frame->last_func && frame->last_func != frame->orig_func) {
|
1459
|
+
yajl_gen_cstr(gen, "last_func");
|
1460
|
+
yajl_gen_id(gen, frame->last_func);
|
1461
|
+
}
|
1462
|
+
|
1463
|
+
if (frame->node) {
|
1464
|
+
yajl_gen_cstr(gen, "node");
|
1465
|
+
yajl_gen_pointer(gen, (void*)frame->node);
|
1466
|
+
}
|
1467
|
+
|
1468
|
+
if (frame->prev) {
|
1469
|
+
yajl_gen_cstr(gen, "prev");
|
1470
|
+
yajl_gen_pointer(gen, (void*)frame->prev);
|
1471
|
+
}
|
1472
|
+
|
1473
|
+
if (frame->tmp) {
|
1474
|
+
yajl_gen_cstr(gen, "tmp");
|
1475
|
+
yajl_gen_pointer(gen, (void*)frame->tmp);
|
1476
|
+
}
|
1477
|
+
|
1478
|
+
yajl_gen_map_close(gen);
|
1479
|
+
yajl_gen_reset(gen);
|
1480
|
+
|
1481
|
+
if (frame->prev) {
|
1482
|
+
memprof_dump_stack_frame(gen, frame->prev);
|
1483
|
+
}
|
1484
|
+
}
|
1485
|
+
|
1486
|
+
static void
|
1487
|
+
memprof_dump_stack(yajl_gen gen)
|
1488
|
+
{
|
1489
|
+
memprof_dump_stack_frame(gen, ruby_frame);
|
1490
|
+
}
|
1491
|
+
|
1492
|
+
static void
|
1493
|
+
memprof_dump_lsof(yajl_gen gen)
|
1494
|
+
{
|
1495
|
+
VALUE cmd = rb_str_new2("lsof -np ");
|
1496
|
+
VALUE pid = rb_funcall(rb_mProcess, rb_intern("pid"), 0);
|
1497
|
+
rb_str_append(cmd, rb_funcall(pid, rb_intern("to_s"), 0));
|
1498
|
+
|
1499
|
+
VALUE lsof = rb_funcall(rb_cObject, '`', 1, cmd);
|
1500
|
+
if (RTEST(lsof)) {
|
1501
|
+
VALUE newline = rb_str_new2("\n");
|
1502
|
+
VALUE lines = rb_funcall(lsof, rb_intern("split"), 1, newline);
|
1503
|
+
int i;
|
1504
|
+
for (i=1; i < RARRAY_LEN(lines); i++) {
|
1505
|
+
VALUE parts = rb_funcall(RARRAY_PTR(lines)[i], rb_intern("split"), 2, Qnil, INT2FIX(9));
|
1506
|
+
|
1507
|
+
yajl_gen_map_open(gen);
|
1508
|
+
|
1509
|
+
yajl_gen_cstr(gen, "_id");
|
1510
|
+
yajl_gen_format(gen, "lsof:%d", i);
|
1511
|
+
|
1512
|
+
yajl_gen_cstr(gen, "type");
|
1513
|
+
yajl_gen_cstr(gen, "lsof");
|
1514
|
+
|
1515
|
+
yajl_gen_cstr(gen, "fd");
|
1516
|
+
yajl_gen_cstr(gen, RSTRING_PTR(RARRAY_PTR(parts)[3]));
|
1517
|
+
|
1518
|
+
yajl_gen_cstr(gen, "fd_type");
|
1519
|
+
yajl_gen_cstr(gen, RSTRING_PTR(RARRAY_PTR(parts)[4]));
|
1520
|
+
|
1521
|
+
yajl_gen_cstr(gen, "fd_name");
|
1522
|
+
yajl_gen_cstr(gen, RSTRING_PTR(RARRAY_PTR(parts)[RARRAY_LEN(parts)-1]));
|
1523
|
+
|
1524
|
+
yajl_gen_map_close(gen);
|
1525
|
+
yajl_gen_reset(gen);
|
1526
|
+
}
|
1527
|
+
}
|
1528
|
+
}
|
1529
|
+
|
1530
|
+
static void
|
1531
|
+
memprof_dump_ps(yajl_gen gen)
|
1532
|
+
{
|
1533
|
+
VALUE cmd = rb_str_new2("ps -o rss,vsize -p ");
|
1534
|
+
VALUE pid = rb_funcall(rb_mProcess, rb_intern("pid"), 0);
|
1535
|
+
rb_str_append(cmd, rb_funcall(pid, rb_intern("to_s"), 0));
|
1536
|
+
|
1537
|
+
VALUE ps = rb_funcall(rb_cObject, '`', 1, cmd);
|
1538
|
+
if (RTEST(ps)) {
|
1539
|
+
VALUE newline = rb_str_new2("\n");
|
1540
|
+
VALUE lines = rb_funcall(ps, rb_intern("split"), 1, newline);
|
1541
|
+
|
1542
|
+
if (RARRAY_LEN(lines) == 2) {
|
1543
|
+
VALUE parts = rb_funcall(RARRAY_PTR(lines)[1], rb_intern("split"), 0);
|
1544
|
+
|
1545
|
+
yajl_gen_map_open(gen);
|
1546
|
+
|
1547
|
+
yajl_gen_cstr(gen, "_id");
|
1548
|
+
yajl_gen_cstr(gen, "ps");
|
1549
|
+
|
1550
|
+
yajl_gen_cstr(gen, "type");
|
1551
|
+
yajl_gen_cstr(gen, "ps");
|
1552
|
+
|
1553
|
+
yajl_gen_cstr(gen, "rss");
|
1554
|
+
yajl_gen_cstr(gen, RSTRING_PTR(RARRAY_PTR(parts)[0]));
|
1555
|
+
|
1556
|
+
yajl_gen_cstr(gen, "vsize");
|
1557
|
+
yajl_gen_cstr(gen, RSTRING_PTR(RARRAY_PTR(parts)[1]));
|
1558
|
+
|
1559
|
+
yajl_gen_map_close(gen);
|
1560
|
+
yajl_gen_reset(gen);
|
1561
|
+
}
|
1562
|
+
}
|
1563
|
+
}
|
1564
|
+
|
818
1565
|
static void
|
819
1566
|
json_print(void *ctx, const char * str, unsigned int len)
|
820
1567
|
{
|
@@ -868,8 +1615,8 @@ memprof_dump_all(int argc, VALUE *argv, VALUE self)
|
|
868
1615
|
memprof_config.heaps_used == NULL ||
|
869
1616
|
memprof_config.sizeof_RVALUE == 0 ||
|
870
1617
|
memprof_config.sizeof_heaps_slot == 0 ||
|
871
|
-
memprof_config.offset_heaps_slot_slot ==
|
872
|
-
memprof_config.offset_heaps_slot_limit ==
|
1618
|
+
memprof_config.offset_heaps_slot_slot == SIZE_MAX ||
|
1619
|
+
memprof_config.offset_heaps_slot_limit == SIZE_MAX)
|
873
1620
|
rb_raise(eUnsupported, "not enough config data to dump heap");
|
874
1621
|
|
875
1622
|
char *heaps = *(char**)memprof_config.heaps;
|
@@ -878,12 +1625,20 @@ memprof_dump_all(int argc, VALUE *argv, VALUE self)
|
|
878
1625
|
char *p, *pend;
|
879
1626
|
int i, limit;
|
880
1627
|
VALUE str;
|
1628
|
+
char *filename = NULL;
|
1629
|
+
char *in_progress_filename = NULL;
|
881
1630
|
FILE *out = NULL;
|
882
1631
|
|
883
1632
|
rb_scan_args(argc, argv, "01", &str);
|
884
1633
|
|
885
1634
|
if (RTEST(str)) {
|
886
|
-
|
1635
|
+
filename = StringValueCStr(str);
|
1636
|
+
size_t filename_len = strlen(filename);
|
1637
|
+
in_progress_filename = alloca(filename_len + 13);
|
1638
|
+
memcpy(in_progress_filename, filename, filename_len);
|
1639
|
+
memcpy(in_progress_filename + filename_len, ".IN_PROGRESS\0", 13);
|
1640
|
+
|
1641
|
+
out = fopen(in_progress_filename, "w");
|
887
1642
|
if (!out)
|
888
1643
|
rb_raise(rb_eArgError, "unable to open output file");
|
889
1644
|
}
|
@@ -893,23 +1648,8 @@ memprof_dump_all(int argc, VALUE *argv, VALUE self)
|
|
893
1648
|
|
894
1649
|
track_objs = 0;
|
895
1650
|
|
896
|
-
|
897
|
-
|
898
|
-
yajl_gen_map_open(gen);
|
899
|
-
|
900
|
-
yajl_gen_cstr(gen, "_id");
|
901
|
-
yajl_gen_cstr(gen, "globals");
|
902
|
-
|
903
|
-
yajl_gen_cstr(gen, "type");
|
904
|
-
yajl_gen_cstr(gen, "globals");
|
905
|
-
|
906
|
-
yajl_gen_cstr(gen, "variables");
|
907
|
-
|
908
|
-
yajl_gen_map_open(gen);
|
909
|
-
st_foreach(rb_global_tbl, globals_each_dump, (st_data_t)gen);
|
910
|
-
yajl_gen_map_close(gen);
|
911
|
-
|
912
|
-
yajl_gen_map_close(gen);
|
1651
|
+
memprof_dump_globals(gen);
|
1652
|
+
memprof_dump_stack(gen);
|
913
1653
|
|
914
1654
|
for (i=0; i < heaps_used; i++) {
|
915
1655
|
p = *(char**)(heaps + (i * memprof_config.sizeof_heaps_slot) + memprof_config.offset_heaps_slot_slot);
|
@@ -919,23 +1659,23 @@ memprof_dump_all(int argc, VALUE *argv, VALUE self)
|
|
919
1659
|
while (p < pend) {
|
920
1660
|
if (RBASIC(p)->flags) {
|
921
1661
|
obj_dump((VALUE)p, gen);
|
922
|
-
|
923
|
-
yajl_gen_clear(gen);
|
924
|
-
yajl_gen_free(gen);
|
925
|
-
gen = yajl_gen_alloc2((yajl_print_t)&json_print, &conf, NULL, (void*)out);
|
926
|
-
while(fputc('\n', out ? out : stdout) == EOF);
|
1662
|
+
yajl_gen_reset(gen);
|
927
1663
|
}
|
928
1664
|
|
929
1665
|
p += memprof_config.sizeof_RVALUE;
|
930
1666
|
}
|
931
1667
|
}
|
932
1668
|
|
933
|
-
|
1669
|
+
memprof_dump_lsof(gen);
|
1670
|
+
memprof_dump_ps(gen);
|
1671
|
+
|
934
1672
|
yajl_gen_clear(gen);
|
935
1673
|
yajl_gen_free(gen);
|
936
1674
|
|
937
|
-
if (out)
|
1675
|
+
if (out) {
|
938
1676
|
fclose(out);
|
1677
|
+
rename(in_progress_filename, filename);
|
1678
|
+
}
|
939
1679
|
|
940
1680
|
track_objs = 1;
|
941
1681
|
|
@@ -945,8 +1685,8 @@ memprof_dump_all(int argc, VALUE *argv, VALUE self)
|
|
945
1685
|
static void
|
946
1686
|
init_memprof_config_base() {
|
947
1687
|
memset(&memprof_config, 0, sizeof(memprof_config));
|
948
|
-
memprof_config.offset_heaps_slot_limit =
|
949
|
-
memprof_config.offset_heaps_slot_slot =
|
1688
|
+
memprof_config.offset_heaps_slot_limit = SIZE_MAX;
|
1689
|
+
memprof_config.offset_heaps_slot_slot = SIZE_MAX;
|
950
1690
|
memprof_config.pagesize = getpagesize();
|
951
1691
|
assert(memprof_config.pagesize);
|
952
1692
|
}
|
@@ -954,7 +1694,7 @@ init_memprof_config_base() {
|
|
954
1694
|
static void
|
955
1695
|
init_memprof_config_extended() {
|
956
1696
|
/* If we don't have add_freelist, find the functions it gets inlined into */
|
957
|
-
memprof_config.add_freelist = bin_find_symbol("add_freelist", NULL);
|
1697
|
+
memprof_config.add_freelist = bin_find_symbol("add_freelist", NULL, 0);
|
958
1698
|
|
959
1699
|
/*
|
960
1700
|
* Sometimes gc_sweep gets inlined in garbage_collect
|
@@ -962,27 +1702,31 @@ init_memprof_config_extended() {
|
|
962
1702
|
*/
|
963
1703
|
if (memprof_config.add_freelist == NULL) {
|
964
1704
|
memprof_config.gc_sweep = bin_find_symbol("gc_sweep",
|
965
|
-
&memprof_config.gc_sweep_size);
|
1705
|
+
&memprof_config.gc_sweep_size, 0);
|
966
1706
|
if (memprof_config.gc_sweep == NULL)
|
967
1707
|
memprof_config.gc_sweep = bin_find_symbol("garbage_collect_0",
|
968
|
-
&memprof_config.gc_sweep_size);
|
1708
|
+
&memprof_config.gc_sweep_size, 0);
|
969
1709
|
if (memprof_config.gc_sweep == NULL)
|
970
1710
|
memprof_config.gc_sweep = bin_find_symbol("garbage_collect",
|
971
|
-
&memprof_config.gc_sweep_size);
|
1711
|
+
&memprof_config.gc_sweep_size, 0);
|
972
1712
|
|
973
1713
|
memprof_config.finalize_list = bin_find_symbol("finalize_list",
|
974
|
-
&memprof_config.finalize_list_size);
|
1714
|
+
&memprof_config.finalize_list_size, 0);
|
975
1715
|
memprof_config.rb_gc_force_recycle = bin_find_symbol("rb_gc_force_recycle",
|
976
|
-
&memprof_config.rb_gc_force_recycle_size);
|
977
|
-
memprof_config.freelist = bin_find_symbol("freelist", NULL);
|
1716
|
+
&memprof_config.rb_gc_force_recycle_size, 0);
|
1717
|
+
memprof_config.freelist = bin_find_symbol("freelist", NULL, 0);
|
978
1718
|
}
|
979
1719
|
|
980
|
-
memprof_config.classname = bin_find_symbol("classname", NULL);
|
981
|
-
memprof_config.
|
1720
|
+
memprof_config.classname = bin_find_symbol("classname", NULL, 0);
|
1721
|
+
memprof_config.timeofday = bin_find_symbol("timeofday", NULL, 0);
|
1722
|
+
memprof_config.bm_mark = bin_find_symbol("bm_mark", NULL, 0);
|
1723
|
+
memprof_config.blk_free = bin_find_symbol("blk_free", NULL, 0);
|
1724
|
+
memprof_config.thread_mark = bin_find_symbol("thread_mark", NULL, 0);
|
1725
|
+
memprof_config.rb_mark_table_add_filename = bin_find_symbol("rb_mark_table_add_filename", NULL, 0);
|
982
1726
|
|
983
1727
|
/* Stuff for dumping the heap */
|
984
|
-
memprof_config.heaps = bin_find_symbol("heaps", NULL);
|
985
|
-
memprof_config.heaps_used = bin_find_symbol("heaps_used", NULL);
|
1728
|
+
memprof_config.heaps = bin_find_symbol("heaps", NULL, 0);
|
1729
|
+
memprof_config.heaps_used = bin_find_symbol("heaps_used", NULL, 0);
|
986
1730
|
#ifdef sizeof__RVALUE
|
987
1731
|
memprof_config.sizeof_RVALUE = sizeof__RVALUE;
|
988
1732
|
#else
|
@@ -1003,6 +1747,91 @@ init_memprof_config_extended() {
|
|
1003
1747
|
#else
|
1004
1748
|
memprof_config.offset_heaps_slot_slot = bin_type_member_offset("heaps_slot", "slot");
|
1005
1749
|
#endif
|
1750
|
+
#ifdef offset__BLOCK__body
|
1751
|
+
memprof_config.offset_BLOCK_body = offset__BLOCK__body;
|
1752
|
+
#else
|
1753
|
+
memprof_config.offset_BLOCK_body = bin_type_member_offset("BLOCK", "body");
|
1754
|
+
#endif
|
1755
|
+
#ifdef offset__BLOCK__var
|
1756
|
+
memprof_config.offset_BLOCK_var = offset__BLOCK__var;
|
1757
|
+
#else
|
1758
|
+
memprof_config.offset_BLOCK_var = bin_type_member_offset("BLOCK", "var");
|
1759
|
+
#endif
|
1760
|
+
#ifdef offset__BLOCK__cref
|
1761
|
+
memprof_config.offset_BLOCK_cref = offset__BLOCK__cref;
|
1762
|
+
#else
|
1763
|
+
memprof_config.offset_BLOCK_cref = bin_type_member_offset("BLOCK", "cref");
|
1764
|
+
#endif
|
1765
|
+
#ifdef offset__BLOCK__prev
|
1766
|
+
memprof_config.offset_BLOCK_prev = offset__BLOCK__prev;
|
1767
|
+
#else
|
1768
|
+
memprof_config.offset_BLOCK_prev = bin_type_member_offset("BLOCK", "prev");
|
1769
|
+
#endif
|
1770
|
+
#ifdef offset__BLOCK__self
|
1771
|
+
memprof_config.offset_BLOCK_self = offset__BLOCK__self;
|
1772
|
+
#else
|
1773
|
+
memprof_config.offset_BLOCK_self = bin_type_member_offset("BLOCK", "self");
|
1774
|
+
#endif
|
1775
|
+
#ifdef offset__BLOCK__klass
|
1776
|
+
memprof_config.offset_BLOCK_klass = offset__BLOCK__klass;
|
1777
|
+
#else
|
1778
|
+
memprof_config.offset_BLOCK_klass = bin_type_member_offset("BLOCK", "klass");
|
1779
|
+
#endif
|
1780
|
+
#ifdef offset__BLOCK__orig_thread
|
1781
|
+
memprof_config.offset_BLOCK_orig_thread = offset__BLOCK__orig_thread;
|
1782
|
+
#else
|
1783
|
+
memprof_config.offset_BLOCK_orig_thread = bin_type_member_offset("BLOCK", "orig_thread");
|
1784
|
+
#endif
|
1785
|
+
#ifdef offset__BLOCK__wrapper
|
1786
|
+
memprof_config.offset_BLOCK_wrapper = offset__BLOCK__wrapper;
|
1787
|
+
#else
|
1788
|
+
memprof_config.offset_BLOCK_wrapper = bin_type_member_offset("BLOCK", "wrapper");
|
1789
|
+
#endif
|
1790
|
+
#ifdef offset__BLOCK__block_obj
|
1791
|
+
memprof_config.offset_BLOCK_block_obj = offset__BLOCK__block_obj;
|
1792
|
+
#else
|
1793
|
+
memprof_config.offset_BLOCK_block_obj = bin_type_member_offset("BLOCK", "block_obj");
|
1794
|
+
#endif
|
1795
|
+
#ifdef offset__BLOCK__scope
|
1796
|
+
memprof_config.offset_BLOCK_scope = offset__BLOCK__scope;
|
1797
|
+
#else
|
1798
|
+
memprof_config.offset_BLOCK_scope = bin_type_member_offset("BLOCK", "scope");
|
1799
|
+
#endif
|
1800
|
+
#ifdef offset__BLOCK__dyna_vars
|
1801
|
+
memprof_config.offset_BLOCK_dyna_vars = offset__BLOCK__dyna_vars;
|
1802
|
+
#else
|
1803
|
+
memprof_config.offset_BLOCK_dyna_vars = bin_type_member_offset("BLOCK", "dyna_vars");
|
1804
|
+
#endif
|
1805
|
+
#ifdef offset__METHOD__klass
|
1806
|
+
memprof_config.offset_METHOD_klass = offset__METHOD__klass;
|
1807
|
+
#else
|
1808
|
+
memprof_config.offset_METHOD_klass = bin_type_member_offset("METHOD", "klass");
|
1809
|
+
#endif
|
1810
|
+
#ifdef offset__METHOD__rklass
|
1811
|
+
memprof_config.offset_METHOD_rklass = offset__METHOD__rklass;
|
1812
|
+
#else
|
1813
|
+
memprof_config.offset_METHOD_rklass = bin_type_member_offset("METHOD", "rklass");
|
1814
|
+
#endif
|
1815
|
+
#ifdef offset__METHOD__recv
|
1816
|
+
memprof_config.offset_METHOD_recv = offset__METHOD__recv;
|
1817
|
+
#else
|
1818
|
+
memprof_config.offset_METHOD_recv = bin_type_member_offset("METHOD", "recv");
|
1819
|
+
#endif
|
1820
|
+
#ifdef offset__METHOD__id
|
1821
|
+
memprof_config.offset_METHOD_id = offset__METHOD__id;
|
1822
|
+
#else
|
1823
|
+
memprof_config.offset_METHOD_id = bin_type_member_offset("METHOD", "id");
|
1824
|
+
#endif
|
1825
|
+
#ifdef offset__METHOD__oid
|
1826
|
+
memprof_config.offset_METHOD_oid = offset__METHOD__oid;
|
1827
|
+
#else
|
1828
|
+
memprof_config.offset_METHOD_oid = bin_type_member_offset("METHOD", "oid");
|
1829
|
+
#endif
|
1830
|
+
#ifdef offset__METHOD__body
|
1831
|
+
memprof_config.offset_METHOD_body = offset__METHOD__body;
|
1832
|
+
#else
|
1833
|
+
memprof_config.offset_METHOD_body = bin_type_member_offset("METHOD", "body");
|
1834
|
+
#endif
|
1006
1835
|
|
1007
1836
|
int heap_errors_printed = 0;
|
1008
1837
|
|
@@ -1018,10 +1847,10 @@ init_memprof_config_extended() {
|
|
1018
1847
|
if (memprof_config.sizeof_heaps_slot == 0)
|
1019
1848
|
heap_errors_printed += fprintf(stderr,
|
1020
1849
|
"Failed to determine sizeof(heaps_slot)\n");
|
1021
|
-
if (memprof_config.offset_heaps_slot_limit ==
|
1850
|
+
if (memprof_config.offset_heaps_slot_limit == SIZE_MAX)
|
1022
1851
|
heap_errors_printed += fprintf(stderr,
|
1023
1852
|
"Failed to determine offset of heaps_slot->limit\n");
|
1024
|
-
if (memprof_config.offset_heaps_slot_slot ==
|
1853
|
+
if (memprof_config.offset_heaps_slot_slot == SIZE_MAX)
|
1025
1854
|
heap_errors_printed += fprintf(stderr,
|
1026
1855
|
"Failed to determine offset of heaps_slot->slot\n");
|
1027
1856
|
|
@@ -1086,6 +1915,7 @@ Init_memprof()
|
|
1086
1915
|
rb_define_singleton_method(memprof, "track", memprof_track, -1);
|
1087
1916
|
rb_define_singleton_method(memprof, "dump", memprof_dump, -1);
|
1088
1917
|
rb_define_singleton_method(memprof, "dump_all", memprof_dump_all, -1);
|
1918
|
+
rb_define_singleton_method(memprof, "track_bytes", memprof_track_bytes, -1);
|
1089
1919
|
|
1090
1920
|
objs = st_init_numtable();
|
1091
1921
|
init_memprof_config_base();
|
@@ -1098,15 +1928,13 @@ Init_memprof()
|
|
1098
1928
|
|
1099
1929
|
rb_classname = memprof_config.classname;
|
1100
1930
|
rb_add_freelist = memprof_config.add_freelist;
|
1931
|
+
rb_timeofday = memprof_config.timeofday;
|
1932
|
+
rb_bm_mark = memprof_config.bm_mark;
|
1933
|
+
rb_blk_free = memprof_config.blk_free;
|
1934
|
+
rb_thread_mark = memprof_config.thread_mark;
|
1101
1935
|
ptr_to_rb_mark_table_add_filename = memprof_config.rb_mark_table_add_filename;
|
1102
1936
|
|
1103
1937
|
assert(rb_classname);
|
1104
1938
|
|
1105
|
-
insert_tramp("rb_newobj", newobj_tramp);
|
1106
|
-
insert_tramp("add_freelist", freelist_tramp);
|
1107
|
-
|
1108
|
-
if (getenv("MEMPROF"))
|
1109
|
-
track_objs = 1;
|
1110
|
-
|
1111
1939
|
return;
|
1112
1940
|
}
|