java - Is using own int capacity faster than using .length field of an array? -


in "95% of performance clean representative models" talk martin thompson, between 17 , 21 minute, such code presented:

public class queue {     private final object[] buffer;     private final int capacity;      // rest of code  } 

in 20:16 says:

you can better performance, leaving things capacity in there right thing do.

i tried come code example in capacity faster buffer.length, failed.

martin saying problems arise in 2 scenerios:

  1. in concurrent world. but, length field final, jls 10.7. so, don't see how problem.
  2. when cache misses. tried calling capacity vs buffer.length 1 million times (with queue having 1 million of elements), there no significant difference. used jmh benchmarking.

could please provide code example, demonstrates case in capacity superior buffer.length in terms of performance?

the more common case (frequently spotted in real code), better.

please note, i'm totally taking away aspect of aesthetics, clean code, potential code re-factoring etc. i'm asking performance.

when access array normally, jvm uses length anyway perform bounds check. when access array via sun.misc.unsafe (like martin does), don't have pay implicit penalty.

array's length field lies in same cache line first elements, have false sharing when multiple threads write first indices concurrently. using separate field buffer capacity break false sharing.

here benchmark shows how capacity field makes array access substantially faster:

package bench;  import org.openjdk.jmh.annotations.benchmark; import org.openjdk.jmh.annotations.param; import org.openjdk.jmh.annotations.scope; import org.openjdk.jmh.annotations.setup; import org.openjdk.jmh.annotations.state; import org.openjdk.jmh.annotations.threads; import sun.misc.unsafe;  import java.lang.reflect.field; import java.util.concurrent.atomic.atomicreferencearray;  @state(scope.benchmark) @threads(4) public class queue {     private static final unsafe unsafe = getunsafe();     private static final long base = unsafe.arraybaseoffset(object[].class);     private static final int scale = unsafe.arrayindexscale(object[].class);      private atomicreferencearray<object> atomic;     private object[] buffer;     private int capacity;      @param({"0", "25"})     private volatile int index;      @setup     public void setup() {         capacity = 32;         buffer = new object[capacity];         atomic = new atomicreferencearray<>(capacity);     }      @benchmark     public void atomicarray() {         atomic.set(index, "payload");     }      @benchmark     public void unsafearraylength() {         int index = this.index;         if (index < 0 || index >= buffer.length) {             throw new arrayindexoutofboundsexception();         }         unsafe.putobjectvolatile(buffer, base + index * scale, "payload");     }      @benchmark     public void unsafecapacityfield() {         int index = this.index;         if (index < 0 || index >= capacity) {             throw new arrayindexoutofboundsexception();         }         unsafe.putobjectvolatile(buffer, base + index * scale, "payload");     }      private static unsafe getunsafe() {         try {             field f = unsafe.class.getdeclaredfield("theunsafe");             f.setaccessible(true);             return (unsafe) f.get(null);         } catch (illegalaccessexception | nosuchfieldexception e) {             throw new assertionerror("should not happen");         }     } } 

results:

benchmark                  (index)   mode  cnt      score      error   units queue.atomicarray                0  thrpt    5  41804,825 ±  928,882  ops/ms queue.atomicarray               25  thrpt    5  84713,201 ± 1067,911  ops/ms queue.unsafearraylength          0  thrpt    5  48656,296 ±  676,166  ops/ms queue.unsafearraylength         25  thrpt    5  88812,863 ± 1089,380  ops/ms queue.unsafecapacityfield        0  thrpt    5  88904,433 ±  360,936  ops/ms queue.unsafecapacityfield       25  thrpt    5  88633,490 ± 1426,329  ops/ms 

Comments

Popular posts from this blog

angularjs - ADAL JS Angular- WebAPI add a new role claim to the token -

php - CakePHP HttpSockets send array of paramms -

node.js - Using Node without global install -