4 ms·
Maybe I'm missing something, but I'm very surprised that the JVM would be implementing atomic increment with a loop that does "lock cmpxchg", retrying if it fai
by haberman 14y ago
Maybe I'm missing something, but I'm very surprised that the JVM would be implementing atomic increment with a loop that does "lock cmpxchg", retrying if it fails. The same can be accomplished much more easily (and safely, and probably with better performance) with "lock add".
For example, take this C program which uses the GCC atomic builtin __sync_add_and_fetch():
void f(int *x) { __sync_add_and_fetch(x, 1); }
This compiles into:
lock add DWORD PTR [rdi],0x1
ret
cmpxchg is also vulnerable to the ABA problem (http://en.wikipedia.org/wiki/ABA_problem http://en.wikipedia.org/wiki/ABA_problem), which the "lock add" approach is not.
"inc" is also an instruction best avoided these days, since it doesn't update all of the flags and can therefore cause an EFLAGS stall (http://stackoverflow.com/questions/12163610/why-inc-and-add-1-have-different-performances http://stackoverflow.com/questions/12163610/why-inc-and-add-...)
- tomjen3 14y agoI think what you are missing with the ABA problem is that it doesn't apply as it is the expected behaviour from the point of view of the programmer.
- haberman 14y agoIn this case it doesn't make a difference, but in many cases it does, which is a reason to avoid CAS() if you can.
- ibisum 14y agoI forget which, but there is some "uses compxchg" criteria for some certification levels in, for example CENELEC and other normatives that the JVM still has to maintain its foothold on. This is to assist with discovery mostly, because its an explicit instruction which can be traced.
- stephencanon 14y agoThe partial flags update stall to which INC is vulnerable is tiny -- on the order of 10 cycles -- and generally not a significant factor except in tiny loops with carried flag dependencies that are executed millions of times. Also, the stall has been largely eliminated on recent Intel µarchs (Sandybridge and later). That said, ADD is no worse and sometimes better, so there's really no good reason to use INC.
- haberman 14y ago> Also, the stall has been largely eliminated on recent Intel µarchs (Sandybridge and later). How is that accomplished? Isn't the stall required by definition, since the partial flags update creates extra data dependencies?
- stephencanon 14y agoIntel hasn't published much documentation on the precise architectural techniques that are used; examples 3-25 and 3-26 and the surrounding text in their optimization manual give a vague description ("In Intel microarchitecture code name Sandy Bridge, the cost of partial flag access is replaced by the insertion of a micro-op instead of a stall.") and include and example of a code sequence that would incur such a stall on earlier µarchs but is faster than a sequence that avoids the stall on Sandy Bridge. One simple and common optimization is to perform register rename on the flags register. More often than not, the flags updated by INC or DEC are simply overwritten by a later arithmetic instruction without ever being used; simple rename can eliminate the stall in these cases. Another simple optimization would be for the front-end perform macro-op fusion of an INC or DEC with a following branch that is known to only use the flag bits written by the INC; then the fused macro-op can issue without waiting on the other flag bits, and avoid stalling control flow. However, I have no inside knowledge about what particular changes Intel made or didn't made to remove this particular hazard; I only know that it seems to have been nearly entirely eliminated.
- pron 14y agoThis has been fixed very recently: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7023898 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7023898