Module: BleakHouse
- Defined in:
- lib/bleak_house.rb,
lib/bleak_house/hook.rb,
lib/bleak_house/analyzer.rb,
ext/extconf.rb,
ext/snapshot.c
Defined Under Namespace
Modules: Analyzer
Constant Summary collapse
- LOGDIR =
File.('../../log', __FILE__)
- LOGFILE =
File.join(LOGDIR, 'bleak_house.log')
Class Method Summary collapse
- .execute(command) ⇒ Object
-
.ext_snapshot(_logfile, _gc_runs) ⇒ Object
Inner method; call BleakHouse.snapshot instead.
-
.heaps_length ⇒ Object
Number of allocated
heaps_slots
. -
.heaps_used ⇒ Object
Number of filled
heaps_slots
. -
.hook(gc_runs = 3) ⇒ Object
The body of the exit handler and
SIGUSR2
trap. -
.snapshot(logfile, gc_runs = 3) ⇒ Object
Walk the live, instrumented objects on the heap and write them to
logfile
. - .write_to_log(message) ⇒ Object
Class Method Details
.execute(command) ⇒ Object
14 15 16 17 18 19 |
# File 'ext/extconf.rb', line 14 def self.execute(command) unless system(command) puts File.open(LOGFILE).read exit -1 end end |
.ext_snapshot(_logfile, _gc_runs) ⇒ Object
Inner method; call BleakHouse.snapshot instead.
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'ext/snapshot.c', line 18
static VALUE ext_snapshot(VALUE self, VALUE _logfile, VALUE _gc_runs) {
Check_Type(_logfile, T_STRING);
Check_Type(_gc_runs, T_FIXNUM);
RVALUE *obj, *obj_end;
st_table_entry *sym;
struct heaps_slot * heaps = rb_gc_heap_slots();
struct st_table * sym_tbl = rb_parse_sym_tbl();
/* see if the logfile exists already */
FILE *logfile = fopen(StringValueCStr(_logfile), "r");
int is_new;
if (!(is_new = (logfile == NULL)))
fclose(logfile);
/* reopen for writing */
if ((logfile = fopen(StringValueCStr(_logfile), "w")) == NULL)
rb_raise(rb_eRuntimeError, "couldn't open snapshot file");
int filled_slots = 0;
int free_slots = 0;
int i;
int gc_runs = FIX2INT(_gc_runs);
char * chr;
for (i = 0; i < gc_runs; i++) {
/* request GC run */
rb_funcall(rb_mGC, rb_intern("start"), 0);
rb_thread_schedule();
}
fprintf(logfile, "%i GC runs performed before dump\n", gc_runs);
/* walk the heap */
for (i = 0; i < rb_gc_heaps_used(); i++) {
obj = heaps[i].slot;
obj_end = obj + heaps[i].limit;
for (; obj < obj_end; obj++) {
if (obj->as.basic.flags) { /* always 0 for freed objects */
filled_slots ++;
/* write the source file*/
if (obj->file) {
chr = obj->file;
if (*chr != '\0') {
fprintf(logfile, "%s", obj->file);
} else {
fprintf(logfile, "__empty__");
}
} else {
fprintf(logfile, "__null__");
}
/* write the source line */
fprintf(logfile, ":");
if (obj->line) {
fprintf(logfile, "%i", obj->line);
} else {
fprintf(logfile, "__null__");
}
/* write the class */
fprintf(logfile, ":");
switch (TYPE(obj)) {
case T_NONE:
fprintf(logfile, "__none__"); break;
case T_BLKTAG:
fprintf(logfile, "__blktag__"); break;
case T_UNDEF:
fprintf(logfile, "__undef__"); break;
case T_VARMAP:
fprintf(logfile, "__varmap__"); break;
case T_SCOPE:
fprintf(logfile, "__scope__"); break;
case T_NODE:
fprintf(logfile, "__node__"); break;
default:
if (!obj->as.basic.klass) {
fprintf(logfile, "__unknown__");
} else {
fprintf(logfile, rb_obj_classname((VALUE)obj));
}
}
/* write newline */
fprintf(logfile, "\n");
} else {
free_slots ++;
}
}
}
/* walk the symbol table */
/* hashed = lookup_builtin("Symbol");
for (i = 0; i < sym_tbl->num_bins; i++) {
for (sym = sym_tbl->bins[i]; sym != 0; sym = sym->next) {
fprintf(logfile, "%i,%lu\n", hashed + 1, sym->record);
}
} */
fprintf(logfile, "%i filled\n", filled_slots);
fprintf(logfile, "%i free\n", free_slots);
fclose(logfile);
return Qnil;
}
|
.heaps_length ⇒ Object
Number of allocated heaps_slots
13 14 15 |
# File 'ext/snapshot.c', line 13 static VALUE heaps_length(VALUE self) { return INT2FIX(rb_gc_heaps_length()); } |
.heaps_used ⇒ Object
Number of filled heaps_slots
8 9 10 |
# File 'ext/snapshot.c', line 8 static VALUE heaps_used(VALUE self) { return INT2FIX(rb_gc_heaps_used()); } |
.hook(gc_runs = 3) ⇒ Object
The body of the exit handler and SIGUSR2
trap. It writes a snapshot to a dumpfile named after the current Process.pid.
4 5 6 7 8 9 10 11 |
# File 'lib/bleak_house/hook.rb', line 4 def self.hook(gc_runs = 3) @count ||= 0 filename = "/tmp/bleak.%s.%03i.dump" % [Process.pid,@count] STDERR.puts "** BleakHouse: working..." BleakHouse.snapshot(filename, gc_runs) STDERR.puts "** BleakHouse: complete\n** Bleakhouse: Run 'bleak #{filename}' to analyze." @count += 1 end |
.snapshot(logfile, gc_runs = 3) ⇒ Object
Walk the live, instrumented objects on the heap and write them to logfile
. Accepts an optional number of GC runs to perform before dumping the heap.
19 20 21 |
# File 'lib/bleak_house.rb', line 19 def self.snapshot(logfile, gc_runs = 3) ext_snapshot(logfile, gc_runs) end |
.write_to_log(message) ⇒ Object
10 11 12 |
# File 'ext/extconf.rb', line 10 def self.write_to_log() File.open(LOGFILE, 'a') { |f| f.puts } end |