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
-
memalign: use ‘1’ to enable tracking the memalign family
If both ‘dump_fd’ and ‘dump_path’ are specified, dump_path takes precedence.
Tracking the memalign family of functions is misleading for Ruby applications, as heap page allocations can happen anywhere a Ruby object is allocated, even in the coldest code paths. Furthermore, it is rarely-used outside of the Ruby object allocator. Thus tracking memalign functions is disabled by default.
Defined Under Namespace
Classes: 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.
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]”)
866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 |
# File 'ext/mwrap/mwrap.c', line 866
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:
748 749 750 751 |
# File 'ext/mwrap/mwrap.c', line 748
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
690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 |
# File 'ext/mwrap/mwrap.c', line 690
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.
817 818 819 820 821 822 823 824 825 826 827 828 829 |
# File 'ext/mwrap/mwrap.c', line 817
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+
1030 1031 1032 1033 1034 |
# File 'ext/mwrap/mwrap.c', line 1030
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.
741 742 743 744 745 |
# File 'ext/mwrap/mwrap.c', line 741
static VALUE mwrap_reset(VALUE mod)
{
rb_thread_call_without_gvl(totals_reset, 0, 0, 0);
return Qnil;
}
|