Skip to content

Commit d91cc7f

Browse files
committed
psweep: Change direction of heap iteration during first incremental sweep step
There's less contention this way.
1 parent 8237f5e commit d91cc7f

1 file changed

Lines changed: 68 additions & 11 deletions

File tree

gc/default/default.c

Lines changed: 68 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,6 +1180,48 @@ print_lock_stats(void)
11801180
}
11811181
#endif /* PSWEEP_LOCK_STATS > 0 */
11821182

1183+
#if PSWEEP_LOCK_STATS > 0
1184+
/*
1185+
* Sweep step contention stats: first incremental step (gc_sweep) vs
1186+
* subsequent steps (gc_sweep_continue), tracking swept_pages_lock trylock
1187+
* success/failure to see if the first step has disproportionate contention.
1188+
*/
1189+
typedef struct sweep_step_contention {
1190+
size_t step_count;
1191+
size_t swept_pages_trylock_success;
1192+
size_t swept_pages_trylock_fail;
1193+
} sweep_step_contention_t;
1194+
1195+
/* [0] = first step (gc_sweep), [1] = continue step (gc_sweep_continue) */
1196+
static sweep_step_contention_t step_contention[2] = {{0}};
1197+
static int current_step_type = 0;
1198+
1199+
static void
1200+
print_sweep_step_contention(void)
1201+
{
1202+
fprintf(stderr, "\n=== Sweep Step Contention (first step vs continue) ===\n");
1203+
fprintf(stderr, "%-30s %15s %15s\n", "", "First Step", "Continue");
1204+
fprintf(stderr, "%-30s %15s %15s\n", "", "----------", "--------");
1205+
1206+
fprintf(stderr, "%-30s %15zu %15zu\n", "step_count",
1207+
step_contention[0].step_count, step_contention[1].step_count);
1208+
fprintf(stderr, "%-30s %15zu %15zu\n", "trylock_success",
1209+
step_contention[0].swept_pages_trylock_success, step_contention[1].swept_pages_trylock_success);
1210+
fprintf(stderr, "%-30s %15zu %15zu\n", "trylock_fail",
1211+
step_contention[0].swept_pages_trylock_fail, step_contention[1].swept_pages_trylock_fail);
1212+
1213+
{
1214+
size_t total0 = step_contention[0].swept_pages_trylock_success + step_contention[0].swept_pages_trylock_fail;
1215+
size_t total1 = step_contention[1].swept_pages_trylock_success + step_contention[1].swept_pages_trylock_fail;
1216+
fprintf(stderr, "%-30s %14.2f%% %14.2f%%\n", "trylock_fail_ratio",
1217+
total0 > 0 ? (double)step_contention[0].swept_pages_trylock_fail / total0 * 100.0 : 0,
1218+
total1 > 0 ? (double)step_contention[1].swept_pages_trylock_fail / total1 * 100.0 : 0);
1219+
}
1220+
1221+
fprintf(stderr, "=====================================================\n\n");
1222+
}
1223+
#endif /* PSWEEP_LOCK_STATS > 0 (sweep step contention) */
1224+
11831225
static pthread_t sweep_lock_owner = 0;
11841226

11851227
static inline void
@@ -1248,6 +1290,9 @@ heap_is_sweep_done(rb_objspace_t *objspace, rb_heap_t *heap)
12481290
if (heap->sweeping_page) {
12491291
return false;
12501292
}
1293+
else if (heap->dequeued_last_page) {
1294+
return true;
1295+
}
12511296

12521297
bool done;
12531298
sweep_lock_lock(&objspace->sweep_lock);
@@ -5056,19 +5101,22 @@ gc_sweep_dequeue_page(rb_objspace_t *objspace, rb_heap_t *heap, bool free_in_use
50565101
struct heap_page *page = NULL;
50575102

50585103
// Avoid taking the global sweep_lock if we can
5059-
#if PSWEEP_LOCK_STATS > 3
5060-
instrumented_lock_acquire(&heap->swept_pages_lock, &swept_pages_lock_stats);
5061-
#else
5062-
rb_native_mutex_trylock(&heap->swept_pages_lock);
5104+
if (rb_native_mutex_trylock(&heap->swept_pages_lock) == 0) {
5105+
#if PSWEEP_LOCK_STATS > 0
5106+
step_contention[current_step_type].swept_pages_trylock_success++;
50635107
#endif
5064-
{
50655108
if (heap->swept_pages) {
50665109
page = heap->swept_pages;
50675110
psweep_debug(0, "[gc] gc_sweep_dequeue_page: got page:%p from heap(%p)->swept_pages (swept_pages lock) (heap %ld)\n", page, heap, heap - heaps);
50685111
heap->swept_pages = page->free_next;
50695112
}
5113+
rb_native_mutex_unlock(&heap->swept_pages_lock);
50705114
}
5071-
rb_native_mutex_unlock(&heap->swept_pages_lock);
5115+
#if PSWEEP_LOCK_STATS > 0
5116+
else {
5117+
step_contention[current_step_type].swept_pages_trylock_fail++;
5118+
}
5119+
#endif
50725120
if (page) return page;
50735121

50745122
#if PSWEEP_LOCK_STATS > 0
@@ -5106,9 +5154,9 @@ gc_sweep_dequeue_page(rb_objspace_t *objspace, rb_heap_t *heap, bool free_in_use
51065154
psweep_debug(0, "[gc] gc_sweep_dequeue_page: got nil page from heap(%p) (heap %ld) end\n", heap, heap - heaps);
51075155
}
51085156
GC_ASSERT(!objspace->background_sweep_mode);
5109-
}
5110-
if (!heap->sweeping_page && !heap->pre_sweeping_page) {
5111-
heap->dequeued_last_page = true;
5157+
if (!heap->sweeping_page && !heap->pre_sweeping_page && !heap->swept_pages) {
5158+
heap->dequeued_last_page = true;
5159+
}
51125160
}
51135161
sweep_lock_unlock(&objspace->sweep_lock);
51145162

@@ -5393,7 +5441,7 @@ gc_sweep_rest(rb_objspace_t *objspace)
53935441
}
53945442
sweep_lock_unlock(&objspace->sweep_lock);
53955443

5396-
for (int i = 0; i < HEAP_COUNT; i++) {
5444+
for (int i = HEAP_COUNT-1; i >= 0; i--) {
53975445
rb_heap_t *heap = &heaps[i];
53985446

53995447
while (!heap_is_sweep_done(objspace, heap)) {
@@ -5462,6 +5510,10 @@ gc_sweep_continue(rb_objspace_t *objspace, rb_heap_t *sweep_heap)
54625510
}
54635511
sweep_lock_unlock(&objspace->sweep_lock);
54645512

5513+
#if PSWEEP_LOCK_STATS > 0
5514+
current_step_type = 1;
5515+
step_contention[1].step_count++;
5516+
#endif
54655517
for (int i = 0; i < HEAP_COUNT; i++) {
54665518
rb_heap_t *heap = &heaps[i];
54675519

@@ -5651,7 +5703,11 @@ gc_sweep(rb_objspace_t *objspace)
56515703
}
56525704
else {
56535705
/* Sweep every size pool. */
5654-
for (int i = 0; i < HEAP_COUNT; i++) {
5706+
#if PSWEEP_LOCK_STATS > 0
5707+
current_step_type = 0;
5708+
step_contention[0].step_count++;
5709+
#endif
5710+
for (int i = HEAP_COUNT-1; i >= 0; i--) {
56555711
rb_heap_t *heap = &heaps[i];
56565712
gc_sweep_step(objspace, heap);
56575713
}
@@ -11043,6 +11099,7 @@ rb_gc_impl_objspace_free(void *objspace_ptr)
1104311099
#if PSWEEP_LOCK_STATS > 0
1104411100
/* Print lock contention statistics before freeing */
1104511101
print_lock_stats();
11102+
print_sweep_step_contention();
1104611103
#endif
1104711104

1104811105
#if PSWEEP_COLLECT_TIMINGS > 0

0 commit comments

Comments
 (0)