Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Lock free hash set for fstrings #12921

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions benchmark/ractor_string_fstring.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
type: lib/benchmark_driver/runner/ractor
benchmark:
ractor_fstring_random: |
i = 0
str = "same".dup
while i < 2000000
-(i.to_s.freeze)
i += 1
end
ractor_fstring_same: |
i = 0
str = "same".dup
while i < 2000000
-str
i += 1
end
loop_count: 1
ractor: 4
16 changes: 16 additions & 0 deletions benchmark/string_fstring.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
benchmark:
fstring_random: |
i = 0
str = "same".dup
while i < 5_000_000
-(i.to_s.freeze)
i += 1
end
fstring_same: |
i = 0
str = "same".dup
while i < 10_000_000
-str
i += 1
end
loop_count: 1
15 changes: 15 additions & 0 deletions bootstraptest/test_ractor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1580,6 +1580,21 @@ class C
}.map{|r| r.take}.join
}

assert_equal "ok", %Q{
N = #{N}
a, b = 2.times.map{
Ractor.new{
N.times.map{|i| -(i.to_s)}
}
}.map{|r| r.take}
N.times do |i|
unless a[i].equal?(b[i])
raise [a[i], b[i]].inspect
end
end
:ok
}

# Generic ivtbl
n = N/2
assert_equal "#{n}#{n}", %Q{
Expand Down
1 change: 1 addition & 0 deletions eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ ruby_setup(void)
Init_BareVM();
rb_vm_encoded_insn_data_table_init();
Init_vm_objects();
Init_fstring_table();

EC_PUSH_TAG(GET_EC());
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
Expand Down
21 changes: 8 additions & 13 deletions gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ rb_gc_shutdown_call_finalizer_p(VALUE obj)
if (rb_obj_is_mutex(obj)) return false;
if (rb_obj_is_fiber(obj)) return false;
if (rb_obj_is_main_ractor(obj)) return false;
if (rb_obj_is_fstring_table(obj)) return false;

return true;

Expand Down Expand Up @@ -1216,11 +1217,7 @@ rb_gc_obj_free_vm_weak_references(VALUE obj)
switch (BUILTIN_TYPE(obj)) {
case T_STRING:
if (FL_TEST(obj, RSTRING_FSTR)) {
st_data_t fstr = (st_data_t)obj;
st_delete(rb_vm_fstring_table(), &fstr, NULL);
RB_DEBUG_COUNTER_INC(obj_str_fstr);

FL_UNSET(obj, RSTRING_FSTR);
rb_gc_free_fstring(obj);
}
break;
case T_SYMBOL:
Expand Down Expand Up @@ -3532,6 +3529,7 @@ vm_weak_table_frozen_strings_foreach(st_data_t key, st_data_t value, st_data_t d
return retval;
}

void rb_fstring_foreach_with_replace(st_foreach_check_callback_func *func, st_update_callback_func *replace, st_data_t arg);
void
rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback,
vm_table_update_callback_func update_callback,
Expand Down Expand Up @@ -3594,14 +3592,11 @@ rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback,
break;
}
case RB_GC_VM_FROZEN_STRINGS_TABLE: {
if (vm->frozen_strings) {
st_foreach_with_replace(
vm->frozen_strings,
vm_weak_table_frozen_strings_foreach,
vm_weak_table_foreach_update_weak_key,
(st_data_t)&foreach_data
);
}
rb_fstring_foreach_with_replace(
vm_weak_table_frozen_strings_foreach,
vm_weak_table_foreach_update_weak_key,
(st_data_t)&foreach_data
);
break;
}
default:
Expand Down
43 changes: 43 additions & 0 deletions include/ruby/atomic.h
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,19 @@ typedef unsigned int rb_atomic_t;
#define RUBY_ATOMIC_PTR_CAS(var, oldval, newval) \
RBIMPL_CAST(rbimpl_atomic_ptr_cas((void **)&(var), (void *)(oldval), (void *)(newval)))

/**
* Identical to #RUBY_ATOMIC_SET, except it expects its arguments are
* ::VALUE. There are cases where ::rb_atomic_t is 32bit while ::VALUE is
* 64bit. This should be used for pointer related operations to support such
* platforms.
*
* @param var A variable of ::VALUE.
* @param val Value to set.
* @post `var` holds `val`.
*/
#define RUBY_ATOMIC_VALUE_SET(var, val) \
rbimpl_atomic_value_set(&(var), (val))

/**
* Identical to #RUBY_ATOMIC_EXCHANGE, except it expects its arguments are
* ::VALUE. There are cases where ::rb_atomic_t is 32bit while ::VALUE is
Expand Down Expand Up @@ -730,6 +743,23 @@ rbimpl_atomic_size_exchange(volatile size_t *ptr, size_t val)
#endif
}

RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
rbimpl_atomic_size_set(volatile size_t *ptr, size_t val)
{
#if 0

#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
__atomic_store_n(ptr, val, __ATOMIC_SEQ_CST);

#else
rbimpl_atomic_size_exchange(ptr, val);

#endif
}

RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
Expand Down Expand Up @@ -772,6 +802,19 @@ rbimpl_atomic_value_exchange(volatile VALUE *ptr, VALUE val)
return RBIMPL_CAST((VALUE)sret);
}

RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
rbimpl_atomic_value_set(volatile VALUE *ptr, VALUE val)
{
RBIMPL_STATIC_ASSERT(sizeof_value, sizeof *ptr == sizeof(size_t));

const size_t sval = RBIMPL_CAST((size_t)val);
volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr);
rbimpl_atomic_size_set(sptr, sval);
}

RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
Expand Down
3 changes: 3 additions & 0 deletions internal/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ VALUE rb_setup_fake_str(struct RString *fake_str, const char *name, long len, rb
RUBY_SYMBOL_EXPORT_END

VALUE rb_fstring_new(const char *ptr, long len);
void rb_gc_free_fstring(VALUE obj);
bool rb_obj_is_fstring_table(VALUE obj);
void Init_fstring_table();
VALUE rb_obj_as_string_result(VALUE str, VALUE obj);
VALUE rb_str_opt_plus(VALUE x, VALUE y);
VALUE rb_str_concat_literals(size_t num, const VALUE *strary);
Expand Down
1 change: 0 additions & 1 deletion internal/vm.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ void rb_vm_check_redefinition_by_prepend(VALUE klass);
int rb_vm_check_optimizable_mid(VALUE mid);
VALUE rb_yield_refine_block(VALUE refinement, VALUE refinements);
VALUE ruby_vm_special_exception_copy(VALUE);
PUREFUNC(st_table *rb_vm_fstring_table(void));

void rb_lastline_set_up(VALUE val, unsigned int up);

Expand Down
Loading
Loading