RFR (S) : JDK-8245043 : Simplified contention benchmark

Aleksey Shipilev shade at redhat.com
Wed May 20 19:45:42 UTC 2020


On 5/18/20 10:33 PM, eric.caspole at oracle.com wrote:
> Webrev:
> http://cr.openjdk.java.net/~ecaspole/JDK-8245043/01/webrev/

I firmly believe the goal for microbenchmarks is to avoid accidental complexity.

Minimize the whole thing:
  *) No need for two @State-s, to have one carry @Param-s only -- you might as well use a single
state, and initialize @Param-s there. For this workload, it would mean you can just mark the entire
class the single state, and that simplifies the code;
  *) update(...), update1(...), update2(...) have single calls, you can inline them?
  *) refreshArray(...) is only used from setup(), you can inline it?
  *) Session/Table are probably redundant; I guess the only way it might matter is bulk rebias;
  *) sharedLocks need not be volatile, @Setup does all we want already.
  *) I cannot see why "while (waiter == null)" is needed; we always get the lock?

Other issues:
  *) static "random" is probably a scalability bottleneck that hides some locking behavior;
  *) Not sure if recurrent locking in update -> update1 -> update2 is meaningful;

Seems to me, this whole thing boils down to much more understandable (untested!):

@State(Scope.Thread)
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Threads(Threads.MAX)
public class MonitorBench {

    @Param({"20", "100", "250"})
    int consumeUnlocked;

    @Param({"20", "100", "250"})
    int consumeLocked;

    @Param({"1", "2", "4"})
    int throwThreshold;

    @Param({"10000"})
    int range;

    @Param({"1"})
    int locksSize;

    static final Random R = new Random(115655);

    Object perThreadLock;
    Object[] sharedLocks;

    int threadCompute;
    int sharedLockIndex;

    @Setup
    public void setup() {
        threadCompute = R.nextInt(Runtime.getRuntime().availableProcessors());
        sharedLockIndex = R.nextInt(locksSize);
        perThreadLock = new Object();

        sharedLocks = new Object[locksSize];
        for (int i = 0; i < locksSize; i++) {
            sharedLocks[i] = new Object();
        }
    }

    @Benchmark
    public int action() throws InterruptedException {
        synchronized (perThreadLock) {
            Blackhole.consumeCPU(consumeUnlocked + threadCompute);

            Object waiter = sharedLocks[sharedLockIndex];
            synchronized (waiter) {
                while (true) {
                    Blackhole.consumeCPU(consumeLocked);
                    if (R.nextInt(range) < throwThreshold) {
                        waiter.wait(100);
                    } else {
                        Blackhole.consumeCPU(consumeLocked);
                        return 0;
                    }
                }
            }
        }
    }
}


-- 
Thanks,
-Aleksey



More information about the hotspot-runtime-dev mailing list