RFR (L): 8230706: Waiting on completion of strong nmethod processing causes long pause times with G1
Kim Barrett
kim.barrett at oracle.com
Wed Oct 9 21:23:16 UTC 2019
> On Oct 8, 2019, at 7:48 PM, Kim Barrett <kim.barrett at oracle.com> wrote:
> src/hotspot/share/gc/g1/g1CollectedHeap.cpp
> 3874 if (collector_state()->in_initial_mark_gc()) {
> 3875 remark_strong_nmethods(per_thread_states);
> 3876 }
>
> I think this additional task and the associated pending strong nmethod
> sets in the pss can be eliminated by using a 2-bit tag and a more
> complex state machine earlier.
I thought about this some more and have some improvements to the
previous pseudo-code, including eliminating the loop in
strong_processor. More careful consideration of the possible states
showed them to be more limited than I'd previously thought they were.
I hadn't noticed the benefit from delaying weak_processor's push onto
the global list and combining it with the transition to the "weak
done" state.
States, encoded in the link member of nmethod N:
- unclaimed: NULL
- weak: N, tag 00
- weak done: NEXT, tag 01
- weak, need strong: N, tag 10
- strong: NEXT, tag 11
where NEXT is the next nmethod in the global list, or N if it is the
last entry, e.g. self-loop indicates end of list.
weak_processor(n):
if n->link != NULL:
# already claimed; nothing to do here.
return
elif not replace_if_null(tagged(n, 0), &n->link):
# just claimed by another thread; nothing to do here.
return
# successfully claimed for weak processing.
assert n->link == tagged(n, 0)
do_weak_processing(n)
# push onto global list. self-loop end of list to avoid tagged NULL.
# not pushing onto global list until ready to mark weak processing
# done significantly simplifies the set of states.
next = xchg(n, &_list_head)
if next == NULL: next = n
# try to install end of list + weak done tag.
if cmpxchg(tagged(next, 1), &n->link, tagged(n, 0)) == tagged(n, 0):
return
# failed, which means some other thread added strong request.
assert n->link == tagged(n, 2)
# do deferred strong processing.
n->link = tagged(next, 3)
do_strong_processing(n)
strong_processor(n):
raw_next = cmpxchg(tagged(n, 3), &n->link, NULL)
if raw_next == NULL:
# successfully claimed for strong processing.
do_strong_processing(n)
# push onto global list. self-loop end of list to avoid tagged NULL.
next = xchg(n, &_list_head)
if next == NULL: next = n
n->link = tagged(next, 3)
return
# claim failed. figure out why and handle it.
next = strip_tag(raw_next)
if raw_next == next: # (raw_next - next) == 0
# claim failed because being weak processed (state == "weak").
# try to request deferred strong processing.
assert next == tagged(n, 0)
raw_next = cmpxchg(tagged(n, 2), &n->link, next)
if (raw_next == next):
# successfully requested deferred strong processing.
return
# failed because of a concurrent transition.
# no longer in "weak" state.
next = strip_tag(raw_next)
if (raw_next - next) >= 2:
# already claimed for strong processing or requested for such.
return
# weak processing is complete.
# raw_next: tag == 1, NEXT == next list entry or N
if cmpxchg(tagged(NEXT, 3), &N->link, raw_next) == raw_next:
# claimed "weak done" to "strong".
do_strong_processing(N)
# if claim failed then some other thread got it.
More information about the hotspot-gc-dev
mailing list