From: Eric Wong <e@80x24.org>
To: Sam Saffron <sam.saffron@gmail.com>
Cc: ruby-talk@ruby-lang.org, mwrap-public@80x24.org
Subject: Re: [ANN] mwrap 2.0.0 mwrap - LD_PRELOAD malloc wrapper for Ruby
Date: Thu, 26 Jul 2018 02:46:01 +0000 [thread overview]
Message-ID: <20180726024601.ievg7jdr7blgtff6@dcvr> (raw)
In-Reply-To: <CAAtdryPDZjXo0QWPznKgRnd7+jQPMBFBOQdfM31KWGUVgGPWeg@mail.gmail.com>
Sam Saffron <sam.saffron@gmail.com> wrote:
> Just to clarify here, I mean 2 single global totals, not a per row
> kind of thing.
>
> On Thu, Jul 26, 2018 at 11:36 AM, Sam Saffron <sam.saffron@gmail.com> wrote:
> > I am using mwrap to debug a little leak at the moment, one feature
> > request I do have though is a tally of totals.
> >
> > It would be nice if it could keep track of total allocated and total
> > released. That way if my RSS is bloating I can tell if it is due to
> > fragmentation or if it is due to a genuine leak really quick.
Something like the patch below? (Barely tested)
Since mwrap doesn't track its own memory usage; this might be
useful if you have a lot of cold code paths doing allocations,
since RSS might not stabilize quickly in that case.
Also, if there's a leaker using a malloc wrapper like Ruby's
xmalloc (e.g. https://bugs.ruby-lang.org/issues/14929 ) ; mwrap
won't make it easy to track down since it can only safely see
the one level up the call stack (using GCC's __builtin_return_address
with a non-zero level isn't safe)
diff --git a/ext/mwrap/mwrap.c b/ext/mwrap/mwrap.c
index acc8960..9bb44d0 100644
--- a/ext/mwrap/mwrap.c
+++ b/ext/mwrap/mwrap.c
@@ -32,6 +32,8 @@ extern size_t __attribute__((weak)) rb_gc_count(void);
extern VALUE __attribute__((weak)) rb_cObject;
extern VALUE __attribute__((weak)) rb_yield(VALUE);
+static size_t total_bytes_inc, total_bytes_dec;
+
/* true for glibc/dlmalloc/ptmalloc, not sure about jemalloc */
#define ASSUMED_MALLOC_ALIGNMENT (sizeof(void *) * 2)
@@ -327,6 +329,8 @@ static struct src_loc *update_stats_rcu_lock(size_t size, uintptr_t caller)
if (caa_unlikely(!totals)) return 0;
if (locating++) goto out; /* do not recurse into another *alloc */
+ uatomic_add(&total_bytes_inc, size);
+
rcu_read_lock();
if (has_ec_p()) {
int line;
@@ -390,6 +394,7 @@ void free(void *p)
if (l) {
size_t age = generation - h->as.live.gen;
+ uatomic_add(&total_bytes_dec, h->size);
uatomic_set(&h->size, 0);
uatomic_add(&l->frees, 1);
uatomic_add(&l->age_total, age);
@@ -710,12 +715,16 @@ static VALUE mwrap_dump(int argc, VALUE * argv, VALUE mod)
return Qnil;
}
+/* The whole operation is not remotely atomic... */
static void *totals_reset(void *ign)
{
struct cds_lfht *t;
struct cds_lfht_iter iter;
struct src_loc *l;
+ uatomic_set(&total_bytes_inc, 0);
+ uatomic_set(&total_bytes_dec, 0);
+
rcu_read_lock();
t = rcu_dereference(totals);
cds_lfht_for_each_entry(t, &iter, l, hnode) {
@@ -1033,6 +1042,16 @@ static VALUE mwrap_quiet(VALUE mod)
return rb_ensure(rb_yield, SIZET2NUM(cur), reset_locating, 0);
}
+static VALUE total_inc(VALUE mod)
+{
+ return SIZET2NUM(total_bytes_inc);
+}
+
+static VALUE total_dec(VALUE mod)
+{
+ return SIZET2NUM(total_bytes_dec);
+}
+
/*
* Document-module: Mwrap
*
@@ -1084,6 +1103,8 @@ void Init_mwrap(void)
rb_define_singleton_method(mod, "each", mwrap_each, -1);
rb_define_singleton_method(mod, "[]", mwrap_aref, 1);
rb_define_singleton_method(mod, "quiet", mwrap_quiet, 0);
+ rb_define_singleton_method(mod, "total_bytes_allocated", total_inc, 0);
+ rb_define_singleton_method(mod, "total_bytes_freed", total_dec, 0);
rb_define_method(cSrcLoc, "each", src_loc_each, 0);
rb_define_method(cSrcLoc, "frees", src_loc_frees, 0);
rb_define_method(cSrcLoc, "allocations", src_loc_allocations, 0);
diff --git a/test/test_mwrap.rb b/test/test_mwrap.rb
index 8425c35..d112b4e 100644
--- a/test/test_mwrap.rb
+++ b/test/test_mwrap.rb
@@ -272,4 +272,15 @@ class TestMwrap < Test::Unit::TestCase
res == :foo or abort 'Mwrap.quiet did not return block result'
end;
end
+
+ def test_total_bytes
+ assert_separately(+"#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ require 'mwrap'
+ Mwrap.total_bytes_allocated > 0 or abort 'nothing allocated'
+ Mwrap.total_bytes_freed > 0 or abort 'nothing freed'
+ Mwrap.total_bytes_allocated > Mwrap.total_bytes_freed or
+ abort 'freed more than allocated'
+ end;
+ end
end
next prev parent reply other threads:[~2018-07-26 2:46 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-07-20 9:25 [PATCH] mwrap 2.0.0 mwrap - LD_PRELOAD malloc wrapper for Ruby Eric Wong
2018-07-20 9:34 ` [ANN] " Eric Wong
2018-07-26 1:36 ` Sam Saffron
2018-07-26 1:37 ` Sam Saffron
2018-07-26 2:46 ` Eric Wong [this message]
2018-07-26 5:02 ` Sam Saffron
2018-07-26 6:21 ` Eric Wong
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://80x24.org/mwrap/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180726024601.ievg7jdr7blgtff6@dcvr \
--to=e@80x24.org \
--cc=mwrap-public@80x24.org \
--cc=ruby-talk@ruby-lang.org \
--cc=sam.saffron@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/mwrap.git/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).