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]”)
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 |
# File 'ext/mwrap/mwrap.c', line 1026
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;
rcu_read_lock();
t = rcu_dereference(totals);
if (!t) goto out_unlock;
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);
}
out_unlock:
rcu_read_unlock();
return val;
}
|
.clear ⇒ Object
:nodoc:
908 909 910 911 |
# File 'ext/mwrap/mwrap.c', line 908
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
846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 |
# File 'ext/mwrap/mwrap.c', line 846
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.
977 978 979 980 981 982 983 984 985 986 987 988 989 |
# File 'ext/mwrap/mwrap.c', line 977
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+
1190 1191 1192 1193 1194 |
# File 'ext/mwrap/mwrap.c', line 1190
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.
901 902 903 904 905 |
# File 'ext/mwrap/mwrap.c', line 901
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
1199 1200 1201 1202 |
# File 'ext/mwrap/mwrap.c', line 1199
static VALUE total_inc(VALUE mod)
{
return SIZET2NUM(total_bytes_inc);
}
|
.total_bytes_freed ⇒ Object
total bytes freed as tracked by mwrap
1207 1208 1209 1210 |
# File 'ext/mwrap/mwrap.c', line 1207
static VALUE total_dec(VALUE mod)
{
return SIZET2NUM(total_bytes_dec);
}
|