Module: Mwrap
- Defined in:
- ext/mwrap/mwrap.c,
ext/mwrap/mwrap.c
Overview
require ‘mwrap’
Mwrap has a dual function as both a Ruby C extension and LD_PRELOAD wrapper. As a Ruby C extension, it exposes a limited Ruby API. To be effective at gathering status, mwrap must be loaded as a LD_PRELOAD (using the mwrap(1) executable makes it easy)
ENVIRONMENT
The “MWRAP” environment variable contains a comma-delimited list of key:value options for automatically dumping at program exit.
-
dump_fd: a writable FD to dump to
-
dump_path: a path to dump to, the file is opened in O_APPEND mode
-
dump_min: the minimum allocation size (total) to dump
-
dump_heap: mask of heap_page_body statistics to dump
If both ‘dump_fd’ and ‘dump_path’ are specified, dump_path takes precedence.
dump_heap bitmask
-
0x01 - summary stats (same info as HeapPageBody.stat)
-
0x02 - all live heaps (similar to HeapPageBody.each)
-
0x04 - skip non-heap_page_body-related output
Defined Under Namespace
Classes: HeapPageBody, SourceLocation
Class Method Summary collapse
-
.[](loc) ⇒ Object
Mwrap -> Mwrap::SourceLocation.
-
.clear ⇒ Object
:nodoc:.
-
.dump(*args) ⇒ Object
Mwrap.dump([ [, min]] -> nil.
-
.each(*args) ⇒ Object
Mwrap.each() do |location,total,allocations,frees,age_total,max_lifespan| …
-
.quiet ⇒ Object
Mwrap.quiet do |depth| # expensive sort/calculate/emitting results of Mwrap.each # affecting statistics of the rest of the app end.
-
.reset ⇒ Object
Mwrap.reset -> nil.
-
.total_bytes_allocated ⇒ Object
total bytes allocated as tracked by mwrap.
-
.total_bytes_freed ⇒ Object
total bytes freed as tracked by mwrap.
Class Method Details
.[](loc) ⇒ Object
Mwrap -> Mwrap::SourceLocation
Returns the associated Mwrap::SourceLocation given the location
String. location
is either a Ruby source location path:line (e.g. “/path/to/foo.rb:5”) or a hexadecimal memory address with square-braces part yielded by Mwrap.dump (e.g. “[0xdeadbeef]”)
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 |
# File 'ext/mwrap/mwrap.c', line 1057
static VALUE mwrap_aref(VALUE mod, VALUE loc)
{
const char *str = StringValueCStr(loc);
int len = RSTRING_LENINT(loc);
struct src_loc *k = 0;
uintptr_t p;
struct cds_lfht_iter iter;
struct cds_lfht_node *cur;
struct cds_lfht *t;
struct src_loc *l;
VALUE val = Qnil;
if (extract_addr(str, len, (void **)&p)) {
k = (void *)kbuf;
memcpy(k->k, &p, sizeof(p));
k->capa = 0;
k->hval = jhash(k->k, sizeof(p), 0xdeadbeef);
} else {
k = (void *)kbuf;
memcpy(k->k, str, len + 1);
k->capa = len + 1;
k->hval = jhash(k->k, k->capa, 0xdeadbeef);
}
if (!k) return val;
t = CMM_LOAD_SHARED(totals);
if (!t) return val;
rcu_read_lock();
cds_lfht_lookup(t, k->hval, loc_eq, k, &iter);
cur = cds_lfht_iter_get_node(&iter);
if (cur) {
l = caa_container_of(cur, struct src_loc, hnode);
val = TypedData_Wrap_Struct(cSrcLoc, &src_loc_type, l);
}
rcu_read_unlock();
return val;
}
|
.clear ⇒ Object
:nodoc:
939 940 941 942 |
# File 'ext/mwrap/mwrap.c', line 939
static VALUE mwrap_clear(VALUE mod)
{
return mwrap_reset(mod);
}
|
.dump(*args) ⇒ Object
Mwrap.dump([ [, min]] -> nil
Dumps the current totals to io
which must be an IO object (StringIO and similar are not supported). Total sizes smaller than or equal to min
are skipped.
The output is space-delimited by 3 columns:
total_size call_count location
877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 |
# File 'ext/mwrap/mwrap.c', line 877
static VALUE mwrap_dump(int argc, VALUE * argv, VALUE mod)
{
VALUE io, min;
struct dump_arg a;
rb_io_t *fptr;
rb_scan_args(argc, argv, "02", &io, &min);
if (NIL_P(io))
/* library may be linked w/o Ruby */
io = *((VALUE *)dlsym(RTLD_DEFAULT, "rb_stderr"));
a.min = NIL_P(min) ? 0 : NUM2SIZET(min);
io = rb_io_get_io(io);
io = rb_io_get_write_io(io);
GetOpenFile(io, fptr);
a.fp = rb_io_stdio_file(fptr);
rb_thread_call_without_gvl(dump_to_file, &a, 0, 0);
RB_GC_GUARD(io);
return Qnil;
}
|
.each(*args) ⇒ Object
Mwrap.each() do |location,total,allocations,frees,age_total,max_lifespan|
...
end
Yields each entry of the of the table to a caller-supplied block. min
may be specified to filter out lines with total
bytes equal-to-or-smaller-than the supplied minimum.
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 |
# File 'ext/mwrap/mwrap.c', line 1008
static VALUE mwrap_each(int argc, VALUE * argv, VALUE mod)
{
VALUE min;
struct dump_arg a;
rb_scan_args(argc, argv, "01", &min);
a.min = NIL_P(min) ? 0 : NUM2SIZET(min);
++locating;
rcu_read_lock();
return rb_ensure(dump_each_rcu, (VALUE)&a, rcu_unlock_ensure, 0);
}
|
.quiet ⇒ Object
Mwrap.quiet do |depth|
# expensive sort/calculate/emitting results of Mwrap.each
# affecting statistics of the rest of the app
end
Stops allocation tracking inside the block. This is useful for monitoring code which calls other Mwrap (or ObjectSpace/GC) functions which unavoidably allocate memory.
This feature was added in mwrap 2.0.0+
1220 1221 1222 1223 1224 |
# File 'ext/mwrap/mwrap.c', line 1220
static VALUE mwrap_quiet(VALUE mod)
{
size_t cur = ++locating;
return rb_ensure(rb_yield, SIZET2NUM(cur), reset_locating, 0);
}
|
.reset ⇒ Object
Mwrap.reset -> nil
Resets the the total tables by zero-ing all counters. This resets all statistics. This is not an atomic operation as other threads (outside of GVL) may increment counters.
932 933 934 935 936 |
# File 'ext/mwrap/mwrap.c', line 932
static VALUE mwrap_reset(VALUE mod)
{
rb_thread_call_without_gvl(totals_reset, 0, 0, 0);
return Qnil;
}
|
.total_bytes_allocated ⇒ Object
total bytes allocated as tracked by mwrap
1229 1230 1231 1232 |
# File 'ext/mwrap/mwrap.c', line 1229
static VALUE total_inc(VALUE mod)
{
return SIZET2NUM(total_bytes_inc);
}
|
.total_bytes_freed ⇒ Object
total bytes freed as tracked by mwrap
1237 1238 1239 1240 |
# File 'ext/mwrap/mwrap.c', line 1237
static VALUE total_dec(VALUE mod)
{
return SIZET2NUM(total_bytes_dec);
}
|