Skip to content

Commit 8237f5e

Browse files
committed
psweep: Attempt to remove lock contention during page dequeue
1 parent bbe44b9 commit 8237f5e

1 file changed

Lines changed: 41 additions & 10 deletions

File tree

gc/default/default.c

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -502,10 +502,12 @@ typedef struct rb_heap_struct {
502502
rb_atomic_t background_sweep_steps; // only incremented/checked by sweep thread
503503
rb_nativethread_cond_t sweep_page_cond; // associated with global sweep lock
504504
rb_nativethread_lock_t swept_pages_lock;
505+
rb_nativethread_lock_t sweeping_page_lock;
505506
size_t pre_swept_slots_deferred;
506507
bool is_finished_sweeping;
507508
bool done_background_sweep;
508509
bool skip_sweep_continue; // skip current sweep continue
510+
bool dequeued_last_page;
509511
} rb_heap_t;
510512

511513
enum {
@@ -1088,6 +1090,7 @@ typedef struct lock_stats {
10881090

10891091
static lock_stats_t sweep_lock_stats = {"objspace->sweep_lock", {{0}}, 0};
10901092
static lock_stats_t swept_pages_lock_stats = {"heap->swept_pages_lock", {{0}}, 0};
1093+
static lock_stats_t sweeping_page_lock_stats = {"heap->sweeping_page_lock", {{0}}, 0};
10911094

10921095

10931096
static lock_callsite_stats_t*
@@ -1139,9 +1142,9 @@ print_lock_stats(void)
11391142
fprintf(stderr, "%-40s %-30s %12s %12s %10s\n", "Lock Name", "Callsite", "Uncontended", "Contended", "Ratio");
11401143
fprintf(stderr, "%-40s %-30s %12s %12s %10s\n", "---------", "--------", "-----------", "---------", "-----");
11411144

1142-
lock_stats_t *all_stats[] = {&sweep_lock_stats, &swept_pages_lock_stats};
1145+
lock_stats_t *all_stats[] = {&sweep_lock_stats, &swept_pages_lock_stats, &sweeping_page_lock_stats};
11431146

1144-
for (int i = 0; i < 2; i++) {
1147+
for (int i = 0; i < 3; i++) {
11451148
lock_stats_t *stats = all_stats[i];
11461149

11471150
/* Sort callsites by total contentions (descending) */
@@ -4624,8 +4627,14 @@ gc_sweep_step_worker(rb_objspace_t *objspace, rb_heap_t *heap)
46244627
return;
46254628
}
46264629
while (1) {
4630+
#if PSWEEP_LOCK_STATS > 0
4631+
instrumented_lock_acquire(&heap->sweeping_page_lock, &sweeping_page_lock_stats);
4632+
#else
4633+
rb_native_mutex_lock(&heap->sweeping_page_lock);
4634+
#endif
46274635
struct heap_page *sweep_page = heap->sweeping_page;
46284636
if (!sweep_page) {
4637+
rb_native_mutex_unlock(&heap->sweeping_page_lock);
46294638
GC_ASSERT(!heap->done_background_sweep);
46304639
GC_ASSERT(objspace->heaps_done_background_sweep < HEAP_COUNT);
46314640
heap->done_background_sweep = true;
@@ -4637,6 +4646,7 @@ gc_sweep_step_worker(rb_objspace_t *objspace, rb_heap_t *heap)
46374646
struct heap_page *next = ccan_list_next(&heap->pages, sweep_page, page_node);
46384647

46394648
if (!next) {
4649+
rb_native_mutex_unlock(&heap->sweeping_page_lock);
46404650
GC_ASSERT(!heap->done_background_sweep);
46414651
GC_ASSERT(objspace->heaps_done_background_sweep < HEAP_COUNT);
46424652
heap->done_background_sweep = true;
@@ -4647,6 +4657,7 @@ gc_sweep_step_worker(rb_objspace_t *objspace, rb_heap_t *heap)
46474657
}
46484658

46494659
heap->sweeping_page = next;
4660+
rb_native_mutex_unlock(&heap->sweeping_page_lock);
46504661
heap->pre_sweeping_page = sweep_page;
46514662

46524663
sweep_lock_unlock(&objspace->sweep_lock);
@@ -4782,6 +4793,7 @@ gc_sweep_start_heap(rb_objspace_t *objspace, rb_heap_t *heap)
47824793
heap->is_finished_sweeping = false;
47834794
heap->done_background_sweep = false;
47844795
heap->skip_sweep_continue = false;
4796+
heap->dequeued_last_page = false;
47854797

47864798
struct heap_page *page = NULL;
47874799

@@ -5037,14 +5049,17 @@ gc_sweep_dequeue_page(rb_objspace_t *objspace, rb_heap_t *heap, bool free_in_use
50375049
return cur;
50385050
}
50395051
}
5052+
else if (heap->dequeued_last_page) {
5053+
return NULL;
5054+
}
50405055

50415056
struct heap_page *page = NULL;
50425057

50435058
// Avoid taking the global sweep_lock if we can
5044-
#if PSWEEP_LOCK_STATS > 0
5059+
#if PSWEEP_LOCK_STATS > 3
50455060
instrumented_lock_acquire(&heap->swept_pages_lock, &swept_pages_lock_stats);
50465061
#else
5047-
rb_native_mutex_lock(&heap->swept_pages_lock);
5062+
rb_native_mutex_trylock(&heap->swept_pages_lock);
50485063
#endif
50495064
{
50505065
if (heap->swept_pages) {
@@ -5056,6 +5071,22 @@ gc_sweep_dequeue_page(rb_objspace_t *objspace, rb_heap_t *heap, bool free_in_use
50565071
rb_native_mutex_unlock(&heap->swept_pages_lock);
50575072
if (page) return page;
50585073

5074+
#if PSWEEP_LOCK_STATS > 0
5075+
instrumented_lock_acquire(&heap->sweeping_page_lock, &sweeping_page_lock_stats);
5076+
#else
5077+
rb_native_mutex_lock(&heap->sweeping_page_lock);
5078+
#endif
5079+
{
5080+
if (heap->sweeping_page) {
5081+
page = heap->sweeping_page; // this could be the last page
5082+
heap->sweeping_page = ccan_list_next(&heap->pages, page, page_node);
5083+
psweep_debug(0, "[gc] gc_sweep_dequeue_page: dequeued unswept page from heap(%p) (heap %ld)\n", heap, heap - heaps);
5084+
*dequeued_unswept_page = true;
5085+
}
5086+
}
5087+
rb_native_mutex_unlock(&heap->sweeping_page_lock);
5088+
if (page) return page;
5089+
50595090
sweep_lock_lock(&objspace->sweep_lock);
50605091
{
50615092
GC_ASSERT(!objspace->background_sweep_mode);
@@ -5074,14 +5105,11 @@ gc_sweep_dequeue_page(rb_objspace_t *objspace, rb_heap_t *heap, bool free_in_use
50745105
}
50755106
psweep_debug(0, "[gc] gc_sweep_dequeue_page: got nil page from heap(%p) (heap %ld) end\n", heap, heap - heaps);
50765107
}
5077-
else {
5078-
*dequeued_unswept_page = true;
5079-
page = heap->sweeping_page; // this could be the last page
5080-
heap->sweeping_page = ccan_list_next(&heap->pages, page, page_node);
5081-
psweep_debug(0, "[gc] gc_sweep_dequeue_page: dequeued unswept page from heap(%p) (heap %ld)\n", heap, heap - heaps);
5082-
}
50835108
GC_ASSERT(!objspace->background_sweep_mode);
50845109
}
5110+
if (!heap->sweeping_page && !heap->pre_sweeping_page) {
5111+
heap->dequeued_last_page = true;
5112+
}
50855113
sweep_lock_unlock(&objspace->sweep_lock);
50865114

50875115
return page;
@@ -11044,6 +11072,7 @@ rb_gc_impl_objspace_free(void *objspace_ptr)
1104411072
for (int i = 0; i < HEAP_COUNT; i++) {
1104511073
rb_heap_t *heap = &heaps[i];
1104611074
rb_native_mutex_destroy(&heap->swept_pages_lock);
11075+
rb_native_mutex_destroy(&heap->sweeping_page_lock);
1104711076
rb_native_cond_destroy(&heap->sweep_page_cond);
1104811077
heap->total_pages = 0;
1104911078
heap->total_slots = 0;
@@ -11123,6 +11152,7 @@ rb_gc_impl_after_fork(void *objspace_ptr, rb_pid_t pid)
1112311152
rb_heap_t *heap = &heaps[i];
1112411153

1112511154
rb_native_mutex_initialize(&heap->swept_pages_lock);
11155+
rb_native_mutex_initialize(&heap->sweeping_page_lock);
1112611156
rb_native_cond_initialize(&heap->sweep_page_cond);
1112711157
heap->pre_sweeping_page = NULL;
1112811158
heap->background_sweep_steps = heap->foreground_sweep_steps;
@@ -11235,6 +11265,7 @@ rb_gc_impl_objspace_init(void *objspace_ptr)
1123511265

1123611266
ccan_list_head_init(&heap->pages);
1123711267
rb_native_mutex_initialize(&heap->swept_pages_lock);
11268+
rb_native_mutex_initialize(&heap->sweeping_page_lock);
1123811269
rb_native_cond_initialize(&heap->sweep_page_cond);
1123911270
}
1124011271

0 commit comments

Comments
 (0)