I was reading this post on Counted/Uncounted loops and Safepoints
.
What it tells me is that there will be safepoint polls
for Uncounted loop, meaning Uncounted loop has worse performance than Counted loop.
In the blog there's this intersting code:
// 4. Should be counted, but treated as uncounted
int i = 0;
while (++i < reps) {
// ...
}
// 5. Should be counted, but treated as uncounted
while (i++ < reps) {
// ...
}
// 6. Should be counted, and is!
while (i < reps) {
// ...
i++;
}
Which basically says doing variable increment in while
(be it i++
or ++i
) will make your loop be treated as uncounted loop.
Given this, I suppose for performance critical code, I should avoid doing this?
Additional question, is the fact that JVM won't do safepoint polls
to Counted loop because loop unrolling
? Or JVM is smart enough to not do it even without loop unrolling
?
The article looks outdated.
In the modern JDK, all 6 loops mentioned in the post are considered counted:
// 1
for (int i = 0; i < reps; i++) { ... }
// 2
for (int i = 0; i < int_reps; i+=2) { ... }
// 3
for (long l = 0; l < int_reps; i++) { ... }
// 4
int i = 0;
while (++i < reps) { ... }
// 5
while (i++ < reps) { ... }
// 6
while (i < reps) { ...; i++; }
The loop #3 with the long
variable became counted in JDK 16 (as a result of JDK-8223051
). All other loops are treated as counted since JDK 8.
I used the following program to verify this:
public class LoopTest {
public static void main(String[] args) throws Exception {
int[] array = new int[1000];
fill(array);
System.out.println(Arrays.stream(array).sum());
}
static void fill(int[] array) {
int reps = array.length;
int i = 0;
while (++i < reps) {
array[i] = i * i;
}
}
}
Run debug build of JDK with the following options:
java -Xcomp -XX:-TieredCompilation -XX:+TraceLoopOpts
-XX:CompileCommand=compileonly,LoopTest::fill
-cp ../test/out/production/test/ LoopTest
The very first line of the TraceLoopOpts
output will confirm that the loop is Counted:
Counted Loop: N140/N120 limit_check predicated counted [1,int),+1 (-1 iters)
Additional question, is the fact that JVM won't do safepoint pools to Counted loop because loop unrolling?
No, safepoint polls have nothing to do with loop unrolling.
The statement that counted loops have no safepoint poll inside is also outdated. Loop strip mining implemented in JDK 10 allows JIT compiler to split large counted loops into two nested loops: the inner (hot) one without a safepoint poll instruction, and the outer - with a safepoint poll.
E.g.
for (int i = start; i < end; i++) {
// loop
}
is transformed to something like
for (int p = start; p < end; p += 1000) {
for (int q = 0; q < 1000; q++) {
int i = p + q;
// loop
}
safepoint_poll();
}
This optimization decreases the overhead of safepoint polling, while keeping the time-to-safepoint latency small for an arbitrary large counted loop.
The up-to-date HotSpot JVM is smart enough about optimizations of most kinds of counted loops, so you don't usually need to care about this yourself.