Home > Mobile >  Is `while ( i < someInt)` considered uncounted loop?
Is `while ( i < someInt)` considered uncounted loop?

Time:06-26

I was reading this post on Counted/Uncounted loops and Safepoints.
What it tells me is that there will be safepoint pools 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 pools to Counted loop because loop unrolling? Or JVM is smart enough to not do it even without loop unrolling?

CodePudding user response:

The problem with the blog posting you linked to is that the author does not state clearly what versions of Java they are looking at.

Details of the placement of safe points are definitely JVM version specific. If simple (and realistic) examples can be identified where the placement is bad, then I would imagine that the Java maintainers will figure out how to make the optimizer smarter. So to know (before hand) if the problem is going to affect you, you would to know you are using the same JVM version as the author. Apparently, the bytecode compiler version is also significant ... according to the comments below the posting


Q: Should you modify your coding style to avoid the cases that are (according to the blog posting) mishandled?

A: My advice would be in general - No:

  1. The problem may have been fixed already in the Java version you are using.
  2. The problem may be fixed in a newer version of Java, or a soon-to-be-released future version. (Upgrading would be less effort than overhauling your code.)
  3. Until you have written your code and benchmarked it with realistic data, you don't know if the problem will actually affect your application ... significantly.

However, if you >do< benchmark your application and you >do< find that that the safe-point problem has a measurable effect, by all means tweak the loops in your application that are 1) affected, and 2) hotspots. (But not all of your loops! That would probably be a waste of time.)

In short ... beware of premature optimization.

CodePudding user response:

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.

  • Related