Card mark steal (dotnet/coreclr#25986)
Implement card marking stealing for better work balance in Server GC.
One of the last stages in the mark_phase is to mark objects referenced from older generations. This stage is often slow compared to the other stages, and it is also often somewhat unbalanced, i.e. some GC threads finish their work significantly sooner than others. The change also applies to the relocate_phase, but that phase usually takes significantly less time.
This change implements thread-safe enumeration of older generations by dividing them into chunks (2 MB in 64-bits, 1 MB in 32-bits), and arranges it so threads finishing work early will help on other heaps. Each thread grabs a chunk and then looks through the card table section corresponding to this chunk. When it's done with a chunk, it grabs the next one and so on.
There are changes at multiple levels:
- at the top level, mark_phase and relocate_phase contain changes to check for work already done for both the heap associated with the thread and other heaps.
- these routines call mark_through_cards_for_segments and mark_through_cards_for_large_objects which contain code to walk through the older generations in chunks.
- ultimately card_marking_enumerator::move_next implements the thread safe enumeration, supplying chunks, and gc_heap::find_next_chunk supplies a chunk where all card bits are set.
Commit migrated from https://github.com/dotnet/coreclr/commit/
5ca444ce55137d60f2fb033d8a110ce8b3e70df3