Collection set is empty -> conc mark cancelled
Aleksey Shipilev
shade at redhat.com
Thu Nov 24 13:13:00 UTC 2016
Hi,
I think I ran into the interesting corner case with String intern
benchmark. In short, the workload does intern Strings to see how long it
would take to scan/update them during rootset ops.
import java.util.*;
public class TestIntern {
static List<String> list = new ArrayList<>();
public static void main(String... args) {
for (int c = 0; c < 10_000_000; c++) {
String s = "" + c + "root";
if (c % 10000 == 0) {
System.out.println(c);
}
list.add(s.intern());
}
}
}
However, with 10M strings, Shenandoah basically hiccups like this:
5270000
5280000
5290000
5300000
5310000
[14.238s][info][gc] Concurrent marking 411M->415M(502M) 268.630ms
[14.297s][info][gc] Pause Final Mark 415M->413M(502M) 58.125ms
[14.297s][info][gc] Concurrent evacuation 413M->415M(502M) 0.418ms
[14.448s][info][gc] Pause Init-Mark 150.682ms
5320000
5330000
5340000
5350000
5360000
5370000
[14.701s][info][gc] Concurrent marking 415M->419M(502M) 253.295ms
[14.759s][info][gc] Cancelled: WTF, collection set is empty
[14.759s][info][gc] Cancelling GC
[14.759s][info][gc] Pause Final Mark 419M->417M(502M) 57.575ms
[14.759s][info][gc] Concurrent evacuation 417M->417M(502M) 0.001ms
[14.901s][info][gc] Pause Init-Mark 142.134ms
[14.906s][info][gc] Concurrent marking 419M->419M(502M) 4.487ms
[14.906s][info][gc] Cancel concurrent Mark 419M->419M(502M) 0.005ms
[14.906s][info][gc] Concurrent evacuation 419M->419M(502M) 0.001ms
[14.906s][info][gc] Pause Init-Mark 0.103ms
[14.906s][info][gc] Concurrent marking 419M->419M(502M) 0.085ms
[14.906s][info][gc] Cancel concurrent Mark 419M->419M(502M) 0.004ms
[14.906s][info][gc] Concurrent evacuation 419M->419M(502M) 0.000ms
[15.051s][info][gc] Pause Init-Mark 143.952ms
That "WTF" message is new logging addition in
ShenandoahHeap::prepare_for_concurrent_evacuation()
if (_collection_set->count() == 0) {
log_info(gc)("Cancelled: WTF, collection set is empty");
cancel_concgc();
}
It seems to me that after we cancel there, we always cancel conc mark in
every upcoming collection. I instrumented all calls to cancel_concgc(),
and there are no more cancellations, so it seems we only reuse the same
set value. If I comment out cancel_concgc() in the method above, the
test starts to pass.
My question is: what's the purpose for that _collection_set->count() ==
0 check? Seems superfluous to me, because we had already had our mark,
and heading to conc evac. What are we canceling? Seems incorrect to
assume that empty collection set is somehow the detractor from the conc
mark -- like in the benchmark above, where rootset mutates, but no
garbage is effectively produced.
Or, at very least, should we reset the concgc flag somewhere else?
Thanks,
-Aleksey
More information about the shenandoah-dev
mailing list