From: Eric Wong <e@80x24.org>
To: <mwrap-public@80x24.org>
Cc: Sam Saffron <sam.saffron@gmail.com>
Subject: [PATCH 2/3] support Ruby 3.0.x
Date: Sat, 20 Aug 2022 21:35:22 +0000 [thread overview]
Message-ID: <20220820213523.18504-3-e@80x24.org> (raw)
In-Reply-To: <20220820213523.18504-1-e@80x24.org>
HEAP_PAGE_SIZE no longer estimates malloc overhead in Ruby 3.0.x,
but we can now rely on the GC::INTERNAL_CONSTANTS hash to access
the true value.
We also need to account for Ractors in 3.0+, and thus we need to
rely on thread-specific `ruby_current_ec' instead of process-wide
`ruby_current_execution_context_ptr' (which no longer exists in
3.0+).
Finally, the VM seems prone to making some small immortal
allocations in a few places we were not expecting in 2.7 and
earlier. Account for that and loosen some exact checks to
account for it.
Tested on Ruby 3.0.3 and 3.0.4
---
ext/mwrap/extconf.rb | 7 +++++++
ext/mwrap/mwrap.c | 25 +++++++++++++++++++++----
test/test_mwrap.rb | 27 ++++++++++++++++-----------
3 files changed, 44 insertions(+), 15 deletions(-)
diff --git a/ext/mwrap/extconf.rb b/ext/mwrap/extconf.rb
index e9dbb1e..254a3bb 100644
--- a/ext/mwrap/extconf.rb
+++ b/ext/mwrap/extconf.rb
@@ -25,4 +25,11 @@ else
abort 'missing __builtin_add_overflow'
end
+begin
+ if n = GC::INTERNAL_CONSTANTS[:HEAP_PAGE_SIZE]
+ $defs << "-DHEAP_PAGE_SIZE=#{n}"
+ end
+rescue NameError
+end
+
create_makefile 'mwrap'
diff --git a/ext/mwrap/mwrap.c b/ext/mwrap/mwrap.c
index 8592ea7..cd68eed 100644
--- a/ext/mwrap/mwrap.c
+++ b/ext/mwrap/mwrap.c
@@ -3,7 +3,7 @@
* License: GPL-2.0+ <https://www.gnu.org/licenses/gpl-2.0.txt>
*/
#define _LGPL_SOURCE /* allows URCU to inline some stuff */
-#include <ruby/ruby.h>
+#include <ruby.h> /* defines HAVE_RUBY_RACTOR_H on 3.0+ */
#include <ruby/thread.h>
#include <ruby/io.h>
#include <execinfo.h>
@@ -22,10 +22,24 @@
#include <urcu/rculist.h>
#include "jhash.h"
+#if __STDC_VERSION__ >= 201112
+# define MWRAP_TSD _Thread_local
+#elif defined(__GNUC__)
+# define MWRAP_TSD __thread
+#else
+# error _Thread_local nor __thread supported
+#endif
+
static ID id_uminus;
const char *rb_source_location_cstr(int *line); /* requires 2.6.0dev */
extern int __attribute__((weak)) ruby_thread_has_gvl_p(void);
+
+#ifdef HAVE_RUBY_RACTOR_H /* Ruby 3.0+ */
+extern MWRAP_TSD void * __attribute__((weak)) ruby_current_ec;
+#else /* Ruby 2.6-2.7 */
extern void * __attribute__((weak)) ruby_current_execution_context_ptr;
+# define ruby_current_ec ruby_current_execution_context_ptr
+#endif
extern void * __attribute__((weak)) ruby_current_vm_ptr; /* for rb_gc_count */
extern size_t __attribute__((weak)) rb_gc_count(void);
extern VALUE __attribute__((weak)) rb_cObject;
@@ -40,9 +54,12 @@ static size_t total_bytes_inc, total_bytes_dec;
/* match values in Ruby gc.c */
#define HEAP_PAGE_ALIGN_LOG 14
enum {
- HEAP_PAGE_ALIGN = (1UL << HEAP_PAGE_ALIGN_LOG),
+ HEAP_PAGE_ALIGN = (1UL << HEAP_PAGE_ALIGN_LOG)
+#ifndef HEAP_PAGE_SIZE /* Ruby 2.6-2.7 only */
+ ,
REQUIRED_SIZE_BY_MALLOC = (sizeof(size_t) * 5),
HEAP_PAGE_SIZE = (HEAP_PAGE_ALIGN - REQUIRED_SIZE_BY_MALLOC)
+#endif
};
#define IS_HEAP_PAGE_BODY ((struct src_loc *)-1)
@@ -75,7 +92,7 @@ static int resolving_malloc;
} \
} while (0)
-static __thread size_t locating;
+static MWRAP_TSD size_t locating;
static size_t generation;
static size_t page_size;
static struct cds_lfht *totals;
@@ -214,7 +231,7 @@ static char *int2str(int num, char *dst, size_t * size)
static int has_ec_p(void)
{
return (ruby_thread_has_gvl_p() && ruby_current_vm_ptr &&
- ruby_current_execution_context_ptr);
+ ruby_current_ec);
}
struct acc {
diff --git a/test/test_mwrap.rb b/test/test_mwrap.rb
index 48fba23..fadaef6 100644
--- a/test/test_mwrap.rb
+++ b/test/test_mwrap.rb
@@ -29,7 +29,8 @@ class TestMwrap < Test::Unit::TestCase
tmp.rewind
lines = tmp.readlines
line_1 = lines.grep(/\s-e:1\b/)[0].strip
- assert_equal '10001', line_1.split(/\s+/)[0]
+ bytes = line_1.split(/\s+/)[0].to_i
+ assert_operator bytes, :>=, 10001
end
end
@@ -42,7 +43,7 @@ class TestMwrap < Test::Unit::TestCase
res = system(env, *cmd, { 5 => tmp })
assert res, $?.inspect
tmp.rewind
- assert_match(/\b10001\s+1\s+-e:1$/, tmp.read)
+ assert_match(/\b1\d{4}\s+[1-9]\d*\s+-e:1$/, tmp.read)
env['MWRAP'] = 'dump_fd:1,dump_min:10000'
tmp.rewind
@@ -50,14 +51,14 @@ class TestMwrap < Test::Unit::TestCase
res = system(env, *cmd, { 1 => tmp })
assert res, $?.inspect
tmp.rewind
- assert_match(/\b10001\s+1\s+-e:1$/, tmp.read)
+ assert_match(/\b1\d{4}\s+[1-9]\d*\s+-e:1$/, tmp.read)
tmp.rewind
tmp.truncate(0)
env['MWRAP'] = "dump_path:#{tmp.path},dump_min:10000"
res = system(env, *cmd)
assert res, $?.inspect
- assert_match(/\b10001\s+1\s+-e:1$/, tmp.read)
+ assert_match(/\b1\d{4}\s+[1-9]\d*\s+-e:1$/, tmp.read)
tmp.rewind
tmp.truncate(0)
@@ -98,7 +99,7 @@ class TestMwrap < Test::Unit::TestCase
tmp.rewind
buf = tmp.read
assert_not_match(/\s+-e:1$/, buf)
- assert_match(/\b20001\s+1\s+-e:3$/, buf)
+ assert_match(/\b2\d{4}\s+[0-9]\d*\s+-e:3$/, buf)
end
end
@@ -176,8 +177,8 @@ class TestMwrap < Test::Unit::TestCase
-e GC.disable
-e keep=("0"*10000)
-e loc=Mwrap["-e:3"]
- -e loc.each{|size,gen|p([size,gen,count])}
- )
+ -e
+ ) + [ 'loc.each{|size,gen|p([size,gen,count]) if size > 10000}' ]
buf = IO.popen(@@env, cmd, &:read)
assert_predicate $?, :success?
assert_match(/\A\[\s*\d+,\s*\d+,\s*\d+\]\s*\z/s, buf)
@@ -230,7 +231,8 @@ class TestMwrap < Test::Unit::TestCase
loc.name == k or abort 'SourceLocation#name broken'
loc.total >= 10000 or abort 'SourceLocation#total broken'
loc.frees == 0 or abort 'SourceLocation#frees broken'
- loc.allocations == 1 or abort 'SourceLocation#allocations broken'
+ loc.allocations >= 1 or
+ abort "SourceLocation#allocations broken: #{loc.allocations}"
seen = false
loc.each do |*x| seen = x end
seen[1] == loc.total or 'SourceLocation#each broken'
@@ -240,7 +242,9 @@ class TestMwrap < Test::Unit::TestCase
freed = false
until freed
freed = true
- loc.each do freed = false end
+ loc.each do |size, gen|
+ freed = false if size >= 10000
+ end
end
loc.frees == 1 or abort 'SourceLocation#frees broken (after free)'
Float === loc.mean_lifespan or abort 'mean_lifespan broken'
@@ -264,8 +268,9 @@ class TestMwrap < Test::Unit::TestCase
assert_separately(+"#{<<~"begin;"}\n#{<<~'end;'}")
begin;
require 'mwrap'
- before = __LINE__
+ before = nil
res = Mwrap.quiet do |depth|
+ before = __LINE__
depth == 1 or abort 'depth is not 1'
('a' * 10000).clear
Mwrap.quiet { |d| d == 2 or abort 'depth is not 2' }
@@ -304,7 +309,7 @@ class TestMwrap < Test::Unit::TestCase
gen <= GC.count && gen >= 0 or abort "bad generation: #{gen}"
(0 == (addr & 16383)) or abort "addr not aligned: #{'%x' % addr}"
end
- nr == ap or abort 'HeapPageBody.each missed page'
+ nr == ap or abort "HeapPageBody.each missed page #{nr} != #{ap}"
10.times { (1..20000).to_a.map(&:to_s) }
3.times { GC.start }
Mwrap::HeapPageBody.stat(h)
next prev parent reply other threads:[~2022-08-20 21:35 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-08-20 21:35 [PATCH 0/3] Ruby 3.x support Eric Wong
2022-08-20 21:35 ` [PATCH 1/3] constify arg for totals_add_rcu Eric Wong
2022-08-20 21:35 ` Eric Wong [this message]
2022-08-20 21:35 ` [PATCH 3/3] disable HeapPageBody count test for Ruby 3.1 Eric Wong
2022-08-20 23:18 ` 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=20220820213523.18504-3-e@80x24.org \
--to=e@80x24.org \
--cc=mwrap-public@80x24.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).