mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8192943: Optimize atomic accumulators using VarHandle getAndSet
Reviewed-by: martin, psandoz, chegar
This commit is contained in:
parent
0b3b384a27
commit
00d1900dc9
5 changed files with 113 additions and 117 deletions
|
@ -105,20 +105,20 @@ public class DoubleAccumulator extends Striped64 implements Serializable {
|
||||||
* @param x the value
|
* @param x the value
|
||||||
*/
|
*/
|
||||||
public void accumulate(double x) {
|
public void accumulate(double x) {
|
||||||
Cell[] as; long b, v, r; int m; Cell a;
|
Cell[] cs; long b, v, r; int m; Cell c;
|
||||||
if ((as = cells) != null
|
if ((cs = cells) != null
|
||||||
|| ((r = doubleToRawLongBits
|
|| ((r = doubleToRawLongBits
|
||||||
(function.applyAsDouble(longBitsToDouble(b = base), x))) != b
|
(function.applyAsDouble(longBitsToDouble(b = base), x))) != b
|
||||||
&& !casBase(b, r))) {
|
&& !casBase(b, r))) {
|
||||||
boolean uncontended = true;
|
boolean uncontended = true;
|
||||||
if (as == null
|
if (cs == null
|
||||||
|| (m = as.length - 1) < 0
|
|| (m = cs.length - 1) < 0
|
||||||
|| (a = as[getProbe() & m]) == null
|
|| (c = cs[getProbe() & m]) == null
|
||||||
|| !(uncontended =
|
|| !(uncontended =
|
||||||
((r = doubleToRawLongBits
|
((r = doubleToRawLongBits
|
||||||
(function.applyAsDouble
|
(function.applyAsDouble
|
||||||
(longBitsToDouble(v = a.value), x))) == v)
|
(longBitsToDouble(v = c.value), x))) == v)
|
||||||
|| a.cas(v, r)))
|
|| c.cas(v, r)))
|
||||||
doubleAccumulate(x, function, uncontended);
|
doubleAccumulate(x, function, uncontended);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,13 +133,13 @@ public class DoubleAccumulator extends Striped64 implements Serializable {
|
||||||
* @return the current value
|
* @return the current value
|
||||||
*/
|
*/
|
||||||
public double get() {
|
public double get() {
|
||||||
Cell[] as = cells;
|
Cell[] cs = cells;
|
||||||
double result = longBitsToDouble(base);
|
double result = longBitsToDouble(base);
|
||||||
if (as != null) {
|
if (cs != null) {
|
||||||
for (Cell a : as)
|
for (Cell c : cs)
|
||||||
if (a != null)
|
if (c != null)
|
||||||
result = function.applyAsDouble
|
result = function.applyAsDouble
|
||||||
(result, longBitsToDouble(a.value));
|
(result, longBitsToDouble(c.value));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -153,12 +153,12 @@ public class DoubleAccumulator extends Striped64 implements Serializable {
|
||||||
* updating.
|
* updating.
|
||||||
*/
|
*/
|
||||||
public void reset() {
|
public void reset() {
|
||||||
Cell[] as = cells;
|
Cell[] cs = cells;
|
||||||
base = identity;
|
base = identity;
|
||||||
if (as != null) {
|
if (cs != null) {
|
||||||
for (Cell a : as)
|
for (Cell c : cs)
|
||||||
if (a != null)
|
if (c != null)
|
||||||
a.reset(identity);
|
c.reset(identity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,14 +173,12 @@ public class DoubleAccumulator extends Striped64 implements Serializable {
|
||||||
* @return the value before reset
|
* @return the value before reset
|
||||||
*/
|
*/
|
||||||
public double getThenReset() {
|
public double getThenReset() {
|
||||||
Cell[] as = cells;
|
Cell[] cs = cells;
|
||||||
double result = longBitsToDouble(base);
|
double result = longBitsToDouble(getAndSetBase(identity));
|
||||||
base = identity;
|
if (cs != null) {
|
||||||
if (as != null) {
|
for (Cell c : cs) {
|
||||||
for (Cell a : as) {
|
if (c != null) {
|
||||||
if (a != null) {
|
double v = longBitsToDouble(c.getAndSet(identity));
|
||||||
double v = longBitsToDouble(a.value);
|
|
||||||
a.reset(identity);
|
|
||||||
result = function.applyAsDouble(result, v);
|
result = function.applyAsDouble(result, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,15 +87,15 @@ public class DoubleAdder extends Striped64 implements Serializable {
|
||||||
* @param x the value to add
|
* @param x the value to add
|
||||||
*/
|
*/
|
||||||
public void add(double x) {
|
public void add(double x) {
|
||||||
Cell[] as; long b, v; int m; Cell a;
|
Cell[] cs; long b, v; int m; Cell c;
|
||||||
if ((as = cells) != null ||
|
if ((cs = cells) != null ||
|
||||||
!casBase(b = base,
|
!casBase(b = base,
|
||||||
Double.doubleToRawLongBits
|
Double.doubleToRawLongBits
|
||||||
(Double.longBitsToDouble(b) + x))) {
|
(Double.longBitsToDouble(b) + x))) {
|
||||||
boolean uncontended = true;
|
boolean uncontended = true;
|
||||||
if (as == null || (m = as.length - 1) < 0 ||
|
if (cs == null || (m = cs.length - 1) < 0 ||
|
||||||
(a = as[getProbe() & m]) == null ||
|
(c = cs[getProbe() & m]) == null ||
|
||||||
!(uncontended = a.cas(v = a.value,
|
!(uncontended = c.cas(v = c.value,
|
||||||
Double.doubleToRawLongBits
|
Double.doubleToRawLongBits
|
||||||
(Double.longBitsToDouble(v) + x))))
|
(Double.longBitsToDouble(v) + x))))
|
||||||
doubleAccumulate(x, null, uncontended);
|
doubleAccumulate(x, null, uncontended);
|
||||||
|
@ -115,12 +115,12 @@ public class DoubleAdder extends Striped64 implements Serializable {
|
||||||
* @return the sum
|
* @return the sum
|
||||||
*/
|
*/
|
||||||
public double sum() {
|
public double sum() {
|
||||||
Cell[] as = cells;
|
Cell[] cs = cells;
|
||||||
double sum = Double.longBitsToDouble(base);
|
double sum = Double.longBitsToDouble(base);
|
||||||
if (as != null) {
|
if (cs != null) {
|
||||||
for (Cell a : as)
|
for (Cell c : cs)
|
||||||
if (a != null)
|
if (c != null)
|
||||||
sum += Double.longBitsToDouble(a.value);
|
sum += Double.longBitsToDouble(c.value);
|
||||||
}
|
}
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
@ -133,12 +133,12 @@ public class DoubleAdder extends Striped64 implements Serializable {
|
||||||
* known that no threads are concurrently updating.
|
* known that no threads are concurrently updating.
|
||||||
*/
|
*/
|
||||||
public void reset() {
|
public void reset() {
|
||||||
Cell[] as = cells;
|
Cell[] cs = cells;
|
||||||
base = 0L; // relies on fact that double 0 must have same rep as long
|
base = 0L; // relies on fact that double 0 must have same rep as long
|
||||||
if (as != null) {
|
if (cs != null) {
|
||||||
for (Cell a : as)
|
for (Cell c : cs)
|
||||||
if (a != null)
|
if (c != null)
|
||||||
a.reset();
|
c.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,16 +153,12 @@ public class DoubleAdder extends Striped64 implements Serializable {
|
||||||
* @return the sum
|
* @return the sum
|
||||||
*/
|
*/
|
||||||
public double sumThenReset() {
|
public double sumThenReset() {
|
||||||
Cell[] as = cells;
|
Cell[] cs = cells;
|
||||||
double sum = Double.longBitsToDouble(base);
|
double sum = Double.longBitsToDouble(getAndSetBase(0L));
|
||||||
base = 0L;
|
if (cs != null) {
|
||||||
if (as != null) {
|
for (Cell c : cs) {
|
||||||
for (Cell a : as) {
|
if (c != null)
|
||||||
if (a != null) {
|
sum += Double.longBitsToDouble(c.getAndSet(0L));
|
||||||
long v = a.value;
|
|
||||||
a.reset();
|
|
||||||
sum += Double.longBitsToDouble(v);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sum;
|
return sum;
|
||||||
|
|
|
@ -103,17 +103,17 @@ public class LongAccumulator extends Striped64 implements Serializable {
|
||||||
* @param x the value
|
* @param x the value
|
||||||
*/
|
*/
|
||||||
public void accumulate(long x) {
|
public void accumulate(long x) {
|
||||||
Cell[] as; long b, v, r; int m; Cell a;
|
Cell[] cs; long b, v, r; int m; Cell c;
|
||||||
if ((as = cells) != null
|
if ((cs = cells) != null
|
||||||
|| ((r = function.applyAsLong(b = base, x)) != b
|
|| ((r = function.applyAsLong(b = base, x)) != b
|
||||||
&& !casBase(b, r))) {
|
&& !casBase(b, r))) {
|
||||||
boolean uncontended = true;
|
boolean uncontended = true;
|
||||||
if (as == null
|
if (cs == null
|
||||||
|| (m = as.length - 1) < 0
|
|| (m = cs.length - 1) < 0
|
||||||
|| (a = as[getProbe() & m]) == null
|
|| (c = cs[getProbe() & m]) == null
|
||||||
|| !(uncontended =
|
|| !(uncontended =
|
||||||
(r = function.applyAsLong(v = a.value, x)) == v
|
(r = function.applyAsLong(v = c.value, x)) == v
|
||||||
|| a.cas(v, r)))
|
|| c.cas(v, r)))
|
||||||
longAccumulate(x, function, uncontended);
|
longAccumulate(x, function, uncontended);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,12 +128,12 @@ public class LongAccumulator extends Striped64 implements Serializable {
|
||||||
* @return the current value
|
* @return the current value
|
||||||
*/
|
*/
|
||||||
public long get() {
|
public long get() {
|
||||||
Cell[] as = cells;
|
Cell[] cs = cells;
|
||||||
long result = base;
|
long result = base;
|
||||||
if (as != null) {
|
if (cs != null) {
|
||||||
for (Cell a : as)
|
for (Cell c : cs)
|
||||||
if (a != null)
|
if (c != null)
|
||||||
result = function.applyAsLong(result, a.value);
|
result = function.applyAsLong(result, c.value);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -147,12 +147,12 @@ public class LongAccumulator extends Striped64 implements Serializable {
|
||||||
* updating.
|
* updating.
|
||||||
*/
|
*/
|
||||||
public void reset() {
|
public void reset() {
|
||||||
Cell[] as = cells;
|
Cell[] cs = cells;
|
||||||
base = identity;
|
base = identity;
|
||||||
if (as != null) {
|
if (cs != null) {
|
||||||
for (Cell a : as)
|
for (Cell c : cs)
|
||||||
if (a != null)
|
if (c != null)
|
||||||
a.reset(identity);
|
c.reset(identity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,14 +167,12 @@ public class LongAccumulator extends Striped64 implements Serializable {
|
||||||
* @return the value before reset
|
* @return the value before reset
|
||||||
*/
|
*/
|
||||||
public long getThenReset() {
|
public long getThenReset() {
|
||||||
Cell[] as = cells;
|
Cell[] cs = cells;
|
||||||
long result = base;
|
long result = getAndSetBase(identity);
|
||||||
base = identity;
|
if (cs != null) {
|
||||||
if (as != null) {
|
for (Cell c : cs) {
|
||||||
for (Cell a : as) {
|
if (c != null) {
|
||||||
if (a != null) {
|
long v = c.getAndSet(identity);
|
||||||
long v = a.value;
|
|
||||||
a.reset(identity);
|
|
||||||
result = function.applyAsLong(result, v);
|
result = function.applyAsLong(result, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,12 +83,12 @@ public class LongAdder extends Striped64 implements Serializable {
|
||||||
* @param x the value to add
|
* @param x the value to add
|
||||||
*/
|
*/
|
||||||
public void add(long x) {
|
public void add(long x) {
|
||||||
Cell[] as; long b, v; int m; Cell a;
|
Cell[] cs; long b, v; int m; Cell c;
|
||||||
if ((as = cells) != null || !casBase(b = base, b + x)) {
|
if ((cs = cells) != null || !casBase(b = base, b + x)) {
|
||||||
boolean uncontended = true;
|
boolean uncontended = true;
|
||||||
if (as == null || (m = as.length - 1) < 0 ||
|
if (cs == null || (m = cs.length - 1) < 0 ||
|
||||||
(a = as[getProbe() & m]) == null ||
|
(c = cs[getProbe() & m]) == null ||
|
||||||
!(uncontended = a.cas(v = a.value, v + x)))
|
!(uncontended = c.cas(v = c.value, v + x)))
|
||||||
longAccumulate(x, null, uncontended);
|
longAccumulate(x, null, uncontended);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,12 +117,12 @@ public class LongAdder extends Striped64 implements Serializable {
|
||||||
* @return the sum
|
* @return the sum
|
||||||
*/
|
*/
|
||||||
public long sum() {
|
public long sum() {
|
||||||
Cell[] as = cells;
|
Cell[] cs = cells;
|
||||||
long sum = base;
|
long sum = base;
|
||||||
if (as != null) {
|
if (cs != null) {
|
||||||
for (Cell a : as)
|
for (Cell c : cs)
|
||||||
if (a != null)
|
if (c != null)
|
||||||
sum += a.value;
|
sum += c.value;
|
||||||
}
|
}
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
@ -135,12 +135,12 @@ public class LongAdder extends Striped64 implements Serializable {
|
||||||
* known that no threads are concurrently updating.
|
* known that no threads are concurrently updating.
|
||||||
*/
|
*/
|
||||||
public void reset() {
|
public void reset() {
|
||||||
Cell[] as = cells;
|
Cell[] cs = cells;
|
||||||
base = 0L;
|
base = 0L;
|
||||||
if (as != null) {
|
if (cs != null) {
|
||||||
for (Cell a : as)
|
for (Cell c : cs)
|
||||||
if (a != null)
|
if (c != null)
|
||||||
a.reset();
|
c.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,15 +155,12 @@ public class LongAdder extends Striped64 implements Serializable {
|
||||||
* @return the sum
|
* @return the sum
|
||||||
*/
|
*/
|
||||||
public long sumThenReset() {
|
public long sumThenReset() {
|
||||||
Cell[] as = cells;
|
Cell[] cs = cells;
|
||||||
long sum = base;
|
long sum = getAndSetBase(0L);
|
||||||
base = 0L;
|
if (cs != null) {
|
||||||
if (as != null) {
|
for (Cell c : cs) {
|
||||||
for (Cell a : as) {
|
if (c != null)
|
||||||
if (a != null) {
|
sum += c.getAndSet(0L);
|
||||||
sum += a.value;
|
|
||||||
a.reset();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sum;
|
return sum;
|
||||||
|
|
|
@ -133,6 +133,9 @@ abstract class Striped64 extends Number {
|
||||||
final void reset(long identity) {
|
final void reset(long identity) {
|
||||||
VALUE.setVolatile(this, identity);
|
VALUE.setVolatile(this, identity);
|
||||||
}
|
}
|
||||||
|
final long getAndSet(long val) {
|
||||||
|
return (long)VALUE.getAndSet(this, val);
|
||||||
|
}
|
||||||
|
|
||||||
// VarHandle mechanics
|
// VarHandle mechanics
|
||||||
private static final VarHandle VALUE;
|
private static final VarHandle VALUE;
|
||||||
|
@ -178,6 +181,10 @@ abstract class Striped64 extends Number {
|
||||||
return BASE.compareAndSet(this, cmp, val);
|
return BASE.compareAndSet(this, cmp, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final long getAndSetBase(long val) {
|
||||||
|
return (long)BASE.getAndSet(this, val);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CASes the cellsBusy field from 0 to 1 to acquire lock.
|
* CASes the cellsBusy field from 0 to 1 to acquire lock.
|
||||||
*/
|
*/
|
||||||
|
@ -228,9 +235,9 @@ abstract class Striped64 extends Number {
|
||||||
}
|
}
|
||||||
boolean collide = false; // True if last slot nonempty
|
boolean collide = false; // True if last slot nonempty
|
||||||
done: for (;;) {
|
done: for (;;) {
|
||||||
Cell[] as; Cell a; int n; long v;
|
Cell[] cs; Cell c; int n; long v;
|
||||||
if ((as = cells) != null && (n = as.length) > 0) {
|
if ((cs = cells) != null && (n = cs.length) > 0) {
|
||||||
if ((a = as[(n - 1) & h]) == null) {
|
if ((c = cs[(n - 1) & h]) == null) {
|
||||||
if (cellsBusy == 0) { // Try to attach new Cell
|
if (cellsBusy == 0) { // Try to attach new Cell
|
||||||
Cell r = new Cell(x); // Optimistically create
|
Cell r = new Cell(x); // Optimistically create
|
||||||
if (cellsBusy == 0 && casCellsBusy()) {
|
if (cellsBusy == 0 && casCellsBusy()) {
|
||||||
|
@ -252,17 +259,17 @@ abstract class Striped64 extends Number {
|
||||||
}
|
}
|
||||||
else if (!wasUncontended) // CAS already known to fail
|
else if (!wasUncontended) // CAS already known to fail
|
||||||
wasUncontended = true; // Continue after rehash
|
wasUncontended = true; // Continue after rehash
|
||||||
else if (a.cas(v = a.value,
|
else if (c.cas(v = c.value,
|
||||||
(fn == null) ? v + x : fn.applyAsLong(v, x)))
|
(fn == null) ? v + x : fn.applyAsLong(v, x)))
|
||||||
break;
|
break;
|
||||||
else if (n >= NCPU || cells != as)
|
else if (n >= NCPU || cells != cs)
|
||||||
collide = false; // At max size or stale
|
collide = false; // At max size or stale
|
||||||
else if (!collide)
|
else if (!collide)
|
||||||
collide = true;
|
collide = true;
|
||||||
else if (cellsBusy == 0 && casCellsBusy()) {
|
else if (cellsBusy == 0 && casCellsBusy()) {
|
||||||
try {
|
try {
|
||||||
if (cells == as) // Expand table unless stale
|
if (cells == cs) // Expand table unless stale
|
||||||
cells = Arrays.copyOf(as, n << 1);
|
cells = Arrays.copyOf(cs, n << 1);
|
||||||
} finally {
|
} finally {
|
||||||
cellsBusy = 0;
|
cellsBusy = 0;
|
||||||
}
|
}
|
||||||
|
@ -271,9 +278,9 @@ abstract class Striped64 extends Number {
|
||||||
}
|
}
|
||||||
h = advanceProbe(h);
|
h = advanceProbe(h);
|
||||||
}
|
}
|
||||||
else if (cellsBusy == 0 && cells == as && casCellsBusy()) {
|
else if (cellsBusy == 0 && cells == cs && casCellsBusy()) {
|
||||||
try { // Initialize table
|
try { // Initialize table
|
||||||
if (cells == as) {
|
if (cells == cs) {
|
||||||
Cell[] rs = new Cell[2];
|
Cell[] rs = new Cell[2];
|
||||||
rs[h & 1] = new Cell(x);
|
rs[h & 1] = new Cell(x);
|
||||||
cells = rs;
|
cells = rs;
|
||||||
|
@ -312,9 +319,9 @@ abstract class Striped64 extends Number {
|
||||||
}
|
}
|
||||||
boolean collide = false; // True if last slot nonempty
|
boolean collide = false; // True if last slot nonempty
|
||||||
done: for (;;) {
|
done: for (;;) {
|
||||||
Cell[] as; Cell a; int n; long v;
|
Cell[] cs; Cell c; int n; long v;
|
||||||
if ((as = cells) != null && (n = as.length) > 0) {
|
if ((cs = cells) != null && (n = cs.length) > 0) {
|
||||||
if ((a = as[(n - 1) & h]) == null) {
|
if ((c = cs[(n - 1) & h]) == null) {
|
||||||
if (cellsBusy == 0) { // Try to attach new Cell
|
if (cellsBusy == 0) { // Try to attach new Cell
|
||||||
Cell r = new Cell(Double.doubleToRawLongBits(x));
|
Cell r = new Cell(Double.doubleToRawLongBits(x));
|
||||||
if (cellsBusy == 0 && casCellsBusy()) {
|
if (cellsBusy == 0 && casCellsBusy()) {
|
||||||
|
@ -336,16 +343,16 @@ abstract class Striped64 extends Number {
|
||||||
}
|
}
|
||||||
else if (!wasUncontended) // CAS already known to fail
|
else if (!wasUncontended) // CAS already known to fail
|
||||||
wasUncontended = true; // Continue after rehash
|
wasUncontended = true; // Continue after rehash
|
||||||
else if (a.cas(v = a.value, apply(fn, v, x)))
|
else if (c.cas(v = c.value, apply(fn, v, x)))
|
||||||
break;
|
break;
|
||||||
else if (n >= NCPU || cells != as)
|
else if (n >= NCPU || cells != cs)
|
||||||
collide = false; // At max size or stale
|
collide = false; // At max size or stale
|
||||||
else if (!collide)
|
else if (!collide)
|
||||||
collide = true;
|
collide = true;
|
||||||
else if (cellsBusy == 0 && casCellsBusy()) {
|
else if (cellsBusy == 0 && casCellsBusy()) {
|
||||||
try {
|
try {
|
||||||
if (cells == as) // Expand table unless stale
|
if (cells == cs) // Expand table unless stale
|
||||||
cells = Arrays.copyOf(as, n << 1);
|
cells = Arrays.copyOf(cs, n << 1);
|
||||||
} finally {
|
} finally {
|
||||||
cellsBusy = 0;
|
cellsBusy = 0;
|
||||||
}
|
}
|
||||||
|
@ -354,9 +361,9 @@ abstract class Striped64 extends Number {
|
||||||
}
|
}
|
||||||
h = advanceProbe(h);
|
h = advanceProbe(h);
|
||||||
}
|
}
|
||||||
else if (cellsBusy == 0 && cells == as && casCellsBusy()) {
|
else if (cellsBusy == 0 && cells == cs && casCellsBusy()) {
|
||||||
try { // Initialize table
|
try { // Initialize table
|
||||||
if (cells == as) {
|
if (cells == cs) {
|
||||||
Cell[] rs = new Cell[2];
|
Cell[] rs = new Cell[2];
|
||||||
rs[h & 1] = new Cell(Double.doubleToRawLongBits(x));
|
rs[h & 1] = new Cell(Double.doubleToRawLongBits(x));
|
||||||
cells = rs;
|
cells = rs;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue