ruby-changes:63978
From: Koichi <ko1@a...>
Date: Mon, 7 Dec 2020 08:28:59 +0900 (JST)
Subject: [ruby-changes:63978] 307732ccee (master): cancel theap on multi-ractors
https://git.ruby-lang.org/ruby.git/commit/?id=307732ccee From 307732ccee7f9f28f8422bab2f839da021d8cdec Mon Sep 17 00:00:00 2001 From: Koichi Sasada <ko1@a...> Date: Sat, 5 Dec 2020 06:15:17 +0900 Subject: cancel theap on multi-ractors accessing theap needs complicating synchronization but it reduce performance on multi-ractor mode. So simply stop using theap on multi-ractor mode. In future, theap should be replaced with more cleaver memory strategy. diff --git a/common.mk b/common.mk index b334056..158828a 100644 --- a/common.mk +++ b/common.mk @@ -10384,6 +10384,7 @@ ractor.$(OBJEXT): {$(VPATH)}subst.h https://github.com/ruby/ruby/blob/trunk/common.mk#L10384 ractor.$(OBJEXT): {$(VPATH)}thread.h ractor.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h ractor.$(OBJEXT): {$(VPATH)}thread_native.h +ractor.$(OBJEXT): {$(VPATH)}transient_heap.h ractor.$(OBJEXT): {$(VPATH)}variable.h ractor.$(OBJEXT): {$(VPATH)}vm_core.h ractor.$(OBJEXT): {$(VPATH)}vm_debug.h diff --git a/ractor.c b/ractor.c index 1ed0272..49a92a2 100644 --- a/ractor.c +++ b/ractor.c @@ -14,6 +14,7 @@ https://github.com/ruby/ruby/blob/trunk/ractor.c#L14 #include "internal/struct.h" #include "variable.h" #include "gc.h" +#include "transient_heap.h" VALUE rb_cRactor; static VALUE rb_eRactorError; @@ -1127,16 +1128,33 @@ ractor_next_id(void) https://github.com/ruby/ruby/blob/trunk/ractor.c#L1128 } static void -vm_insert_ractor0(rb_vm_t *vm, rb_ractor_t *r) +vm_insert_ractor0(rb_vm_t *vm, rb_ractor_t *r, bool single_ractor_mode) { RUBY_DEBUG_LOG("r:%u ractor.cnt:%u++", r->id, vm->ractor.cnt); - VM_ASSERT(!rb_multi_ractor_p() || RB_VM_LOCKED_P()); + VM_ASSERT(single_ractor_mode || RB_VM_LOCKED_P()); list_add_tail(&vm->ractor.set, &r->vmlr_node); vm->ractor.cnt++; } static void +cancel_single_ractor_mode(void) +{ + // enable multi-ractor mode + RUBY_DEBUG_LOG("enable multi-ractor mode", 0); + + rb_gc_start(); + rb_transient_heap_evacuate(); + + if (rb_warning_category_enabled_p(RB_WARN_CATEGORY_EXPERIMENTAL)) { + rb_warn("Ractor is experimental, and the behavior may change in future versions of Ruby! " + "Also there are many implementation issues."); + } + + ruby_single_main_ractor = NULL; +} + +static void vm_insert_ractor(rb_vm_t *vm, rb_ractor_t *r) { VM_ASSERT(ractor_status_p(r, ractor_created)); @@ -1144,29 +1162,22 @@ vm_insert_ractor(rb_vm_t *vm, rb_ractor_t *r) https://github.com/ruby/ruby/blob/trunk/ractor.c#L1162 if (rb_multi_ractor_p()) { RB_VM_LOCK(); { - vm_insert_ractor0(vm, r); + vm_insert_ractor0(vm, r, false); vm_ractor_blocking_cnt_inc(vm, r, __FILE__, __LINE__); } RB_VM_UNLOCK(); } else { - vm_insert_ractor0(vm, r); - - if (vm->ractor.cnt == 1) { + if (vm->ractor.cnt == 0) { // main ractor + vm_insert_ractor0(vm, r, true); ractor_status_set(r, ractor_blocking); ractor_status_set(r, ractor_running); } else { + cancel_single_ractor_mode(); + vm_insert_ractor0(vm, r, true); vm_ractor_blocking_cnt_inc(vm, r, __FILE__, __LINE__); - - // enable multi-ractor mode - RUBY_DEBUG_LOG("enable multi-ractor mode", 0); - ruby_single_main_ractor = NULL; - - if (rb_warning_category_enabled_p(RB_WARN_CATEGORY_EXPERIMENTAL)) { - rb_warn("Ractor is experimental, and the behavior may change in future versions of Ruby! Also there are many implementation issues."); - } } } } diff --git a/transient_heap.c b/transient_heap.c index 357e4a4..5b6fd89 100644 --- a/transient_heap.c +++ b/transient_heap.c @@ -364,74 +364,72 @@ transient_heap_allocatable_header(struct transient_heap* theap, size_t size) https://github.com/ruby/ruby/blob/trunk/transient_heap.c#L364 void * rb_transient_heap_alloc(VALUE obj, size_t req_size) { - void *ret; + // only on single main ractor + if (ruby_single_main_ractor == NULL) return NULL; - RB_VM_LOCK_ENTER(); - { - struct transient_heap* theap = transient_heap_get(); - size_t size = ROUND_UP(req_size + sizeof(struct transient_alloc_header), TRANSIENT_HEAP_ALLOC_ALIGN); + void *ret; + struct transient_heap* theap = transient_heap_get(); + size_t size = ROUND_UP(req_size + sizeof(struct transient_alloc_header), TRANSIENT_HEAP_ALLOC_ALIGN); - TH_ASSERT(RB_TYPE_P(obj, T_ARRAY) || - RB_TYPE_P(obj, T_OBJECT) || - RB_TYPE_P(obj, T_STRUCT) || - RB_TYPE_P(obj, T_HASH)); /* supported types */ + TH_ASSERT(RB_TYPE_P(obj, T_ARRAY) || + RB_TYPE_P(obj, T_OBJECT) || + RB_TYPE_P(obj, T_STRUCT) || + RB_TYPE_P(obj, T_HASH)); /* supported types */ - if (size > TRANSIENT_HEAP_ALLOC_MAX) { - if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: [too big: %ld] %s\n", (long)size, rb_obj_info(obj)); - ret = NULL; - } + if (size > TRANSIENT_HEAP_ALLOC_MAX) { + if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: [too big: %ld] %s\n", (long)size, rb_obj_info(obj)); + ret = NULL; + } #if TRANSIENT_HEAP_DEBUG_DONT_PROMOTE == 0 - else if (RB_OBJ_PROMOTED_RAW(obj)) { - if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: [promoted object] %s\n", rb_obj_info(obj)); - ret = NULL; - } + else if (RB_OBJ_PROMOTED_RAW(obj)) { + if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: [promoted object] %s\n", rb_obj_info(obj)); + ret = NULL; + } #else - else if (RBASIC_CLASS(obj) == 0) { - if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: [hidden object] %s\n", rb_obj_info(obj)); - ret = NULL; - } + else if (RBASIC_CLASS(obj) == 0) { + if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: [hidden object] %s\n", rb_obj_info(obj)); + ret = NULL; + } #endif - else { - struct transient_alloc_header *header = transient_heap_allocatable_header(theap, size); - if (header) { - void *ptr; + else { + struct transient_alloc_header *header = transient_heap_allocatable_header(theap, size); + if (header) { + void *ptr; - /* header is poisoned to prevent buffer overflow, should - * unpoison first... */ - asan_unpoison_memory_region(header, sizeof *header, true); + /* header is poisoned to prevent buffer overflow, should + * unpoison first... */ + asan_unpoison_memory_region(header, sizeof *header, true); - header->size = size; - header->magic = TRANSIENT_HEAP_ALLOC_MAGIC; - header->next_marked_index = TRANSIENT_HEAP_ALLOC_MARKING_FREE; - header->obj = obj; /* TODO: can we eliminate it? */ + header->size = size; + header->magic = TRANSIENT_HEAP_ALLOC_MAGIC; + header->next_marked_index = TRANSIENT_HEAP_ALLOC_MARKING_FREE; + header->obj = obj; /* TODO: can we eliminate it? */ - /* header is fixed; shall poison again */ - asan_poison_memory_region(header, sizeof *header); - ptr = header + 1; + /* header is fixed; shall poison again */ + asan_poison_memory_region(header, sizeof *header); + ptr = header + 1; - theap->total_objects++; /* statistics */ + theap->total_objects++; /* statistics */ #if TRANSIENT_HEAP_DEBUG_DONT_PROMOTE - if (RB_OBJ_PROMOTED_RAW(obj)) { - transient_heap_promote_add(theap, obj); - } + if (RB_OBJ_PROMOTED_RAW(obj)) { + transient_heap_promote_add(theap, obj); + } #endif - if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: header:%p ptr:%p size:%d obj:%s\n", (void *)header, ptr, (int)size, rb_obj_info(obj)); + if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: header:%p ptr:%p size:%d obj:%s\n", (void *)header, ptr, (int)size, rb_obj_info(obj)); - RB_DEBUG_COUNTER_INC(theap_alloc); + RB_DEBUG_COUNTER_INC(theap_alloc); - /* ptr is set up; OK to unpoison. */ - asan_unpoison_memory_region(ptr, size - sizeof *header, true); - ret = ptr; - } - else { - if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: [no enough space: %ld] %s\n", (long)size, rb_obj_info(obj)); - RB_DEBUG_COUNTER_INC(theap_alloc_fail); - ret = NULL; - } + /* ptr is set up; OK to unpoison. */ + asan_unpoison_memory_region(ptr, size - sizeof *header, true); + ret = ptr; + } + else { + if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: [no enough space: %ld] %s\n", (long)size, rb_obj_info(obj)); + RB_DEBUG_COUNTER_INC(theap_alloc_fail); + ret = NULL; } } - RB_VM_LOCK_LEAVE(); return ret; } @@ -775,16 +773,16 @@ transient_heap_update_status(struct transient_heap* theap, enum transient_heap_s https://github.com/ruby/ruby/blob/trunk/transient_heap.c#L773 static void transient_heap_evacuate(void *dmy) { - RB_VM_LOCK_ENTER(); - rb_vm_barrier(); - { - struct transient_heap* theap = transient_heap_get(); + struct transient_heap* theap = transient_heap_get(); - if (theap->status == transient_heap_marking) { - if (TRANSIENT_HEAP_DEBUG >= 1) fprintf(stderr, "!! transient_heap_evacuate: skip while transie (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/