Class: BleakHouse::Logger

Inherits:
Object
  • Object
show all
Defined in:
lib/bleak_house/logger/mem_usage.rb,
ext/bleak_house/logger/snapshot.c

Instance Method Summary collapse

Instance Method Details

#heaps_lengthObject

Length of the struct heaps_slots allocated



13
14
15
# File 'ext/bleak_house/logger/snapshot.c', line 13

static VALUE heaps_length(VALUE self) {
  return INT2FIX(rb_gc_heaps_length());
}

#heaps_usedObject

Number of struct heaps_slots used



8
9
10
# File 'ext/bleak_house/logger/snapshot.c', line 8

static VALUE heaps_used(VALUE self) {
  return INT2FIX(rb_gc_heaps_used());
}

#mem_usageObject

Returns an array of the running process’s real and virtual memory usage, in kilobytes.



7
8
9
10
# File 'lib/bleak_house/logger/mem_usage.rb', line 7

def mem_usage
  a = `ps -o vsz,rss -p #{Process.pid}`.split(/\s+/)[-2..-1].map{|el| el.to_i}
  [a.first - a.last, a.last]
end

#snapshot(_logfile, tag, _specials) ⇒ Object

Count the live objects on the heap and in the symbol table and write a CSV frame to _logfile. Set _specials = true if you also want to count AST nodes and var scopes; otherwise, use false. Note that common classes in the CSV output are hashed to small integers in order to save space.



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
# File 'ext/bleak_house/logger/snapshot.c', line 18

static VALUE snapshot(VALUE self, VALUE _logfile, VALUE tag, VALUE _specials) {
  Check_Type(_logfile, T_STRING);
  Check_Type(tag, T_STRING);

  RVALUE *obj, *obj_end;
  st_table_entry *sym, *sym_end;
  
  struct heaps_slot * heaps = rb_gc_heap_slots();
  struct st_table * sym_tbl = rb_parse_sym_tbl();

  int specials = RTEST(_specials);
  int hashed;

  /* 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), "a+")) == NULL)
    rb_raise(rb_eRuntimeError, "couldn't open snapshot file");

  /* write the time */
  fprintf(logfile, "-1,%i\n", time(0));
  
  /* get and write the memory usage */
  VALUE mem = rb_funcall(self, rb_intern("mem_usage"), 0);
  fprintf(logfile, "-2,%i\n", NUM2INT(RARRAY_PTR(mem)[0]));
  fprintf(logfile, "-3,%i\n", NUM2INT(RARRAY_PTR(mem)[1]));
  
  int current_pos = 0;  
  int filled_slots = 0;
  int free_slots = 0;

  /* write the tag header */
  fprintf(logfile, "-4,%s\n", StringValueCStr(tag));

  int i, j;
  
  /* 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 ++;
        switch (TYPE(obj)) {
          case T_NONE:
              hashed = BUILTINS_SIZE + 0; break;
          case T_BLKTAG:
              hashed = BUILTINS_SIZE + 1; break;
          case T_UNDEF:
              hashed = BUILTINS_SIZE + 2; break;
          case T_VARMAP:
              hashed = BUILTINS_SIZE + 3; break;
          case T_SCOPE:
              hashed = BUILTINS_SIZE + 4; break;
          case T_NODE:
              hashed = BUILTINS_SIZE + 5; break;
          default:
            if (!obj->as.basic.klass) {
              hashed = BUILTINS_SIZE + 6;
            } else {
              hashed = lookup_builtin(rb_obj_classname((VALUE)obj));
            }
        }
        /* write to log */
        if (hashed < 0) {
          /* regular classname */
          fprintf(logfile, "%s,%lu\n", rb_obj_classname((VALUE)obj), FIX2ULONG(rb_obj_id((VALUE)obj)));
        } else {
          /* builtins key */
          if (specials || hashed < BUILTINS_SIZE) {
            /* 0 is not used for 'hashed' because Ruby's to_i turns any String into 0 */
            fprintf(logfile, "%i,%lu\n", hashed + 1, FIX2ULONG(rb_obj_id((VALUE)obj)));
          }
        }
      } 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, "-5,%i\n", filled_slots);
  fprintf(logfile, "-6,%i\n", free_slots);
  fclose(logfile);
    
  rb_funcall(rb_mGC, rb_intern("start"), 0); /* request GC run */
  return Qtrue;
}