@@ -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+
11831225static pthread_t sweep_lock_owner = 0 ;
11841226
11851227static 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