summaryrefslogtreecommitdiff
path: root/transient_heap.c
diff options
context:
space:
mode:
authorKoichi Sasada <ko1@atdot.net>2020-12-05 06:15:17 +0900
committerKoichi Sasada <ko1@atdot.net>2020-12-07 08:28:36 +0900
commit307732ccee7f9f28f8422bab2f839da021d8cdec (patch)
treef39ec33d41cbcbaf07bcc1a8d34dc3047357ca6e /transient_heap.c
parentb67b24d0f5e78481e6a306881b6858f0dec996ba (diff)
downloadruby-307732ccee7f9f28f8422bab2f839da021d8cdec.tar.gz
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.
Diffstat (limited to 'transient_heap.c')
-rw-r--r--transient_heap.c136
1 files changed, 69 insertions, 67 deletions
diff --git a/transient_heap.c b/transient_heap.c
index 357e4a4656..5b6fd89889 100644
--- a/transient_heap.c
+++ b/transient_heap.c
@@ -364,74 +364,72 @@ transient_heap_allocatable_header(struct transient_heap* theap, size_t size)
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
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 transient_heap_marking\n");
- }
- else {
- VALUE gc_disabled = rb_gc_disable_no_rest();
+ if (theap->total_marked_objects == 0) return;
+ if (ruby_single_main_ractor == NULL) rb_bug("not single ractor mode");
+ if (theap->status == transient_heap_marking) {
+ if (TRANSIENT_HEAP_DEBUG >= 1) fprintf(stderr, "!! transient_heap_evacuate: skip while transient_heap_marking\n");
+ }
+ else {
+ VALUE gc_disabled = rb_gc_disable_no_rest();
+ {
struct transient_heap_block* block;
RUBY_DEBUG_LOG("start gc_disabled:%d", RTEST(gc_disabled));
@@ -825,12 +823,16 @@ transient_heap_evacuate(void *dmy)
transient_heap_verify(theap);
transient_heap_update_status(theap, transient_heap_none);
-
- if (gc_disabled != Qtrue) rb_gc_enable();
- RUBY_DEBUG_LOG("finish", 0);
}
+ if (gc_disabled != Qtrue) rb_gc_enable();
+ RUBY_DEBUG_LOG("finish", 0);
}
- RB_VM_LOCK_LEAVE();
+}
+
+void
+rb_transient_heap_evacuate(void)
+{
+ transient_heap_evacuate(NULL);
}
static void
@@ -964,9 +966,9 @@ rb_transient_heap_finish_marking(void)
struct transient_heap* theap = transient_heap_get();
- if (TRANSIENT_HEAP_DEBUG >= 1) fprintf(stderr, "!! rb_transient_heap_finish_marking objects:%d, marked:%d\n",
- theap->total_objects,
- theap->total_marked_objects);
+ RUBY_DEBUG_LOG("objects:%d, marked:%d",
+ theap->total_objects,
+ theap->total_marked_objects);
if (TRANSIENT_HEAP_DEBUG >= 2) transient_heap_dump(theap);
TH_ASSERT(theap->total_objects >= theap->total_marked_objects);