package com.bellsw.simple;

import java.util.concurrent.TimeUnit;
import java.util.Arrays;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
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.Warmup;

@Warmup(iterations = 40)
@Measurement(iterations = 5)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Benchmark)
public class ArrayEqualsBench {
    static final int BATCH_DATA_SIZE = 17000000; // a bit more than 16mb(L2)
    @Param({"1", "256", "512", "1024", "1000000"})
    int size;
    int amountOfByteArrays;

    byte[][] byteArray1;
    byte[][] byteArray2;

    int array1Counter;
    int array2Counter;

    @Setup(Level.Trial)
    public void init() {
        amountOfByteArrays = BATCH_DATA_SIZE / size;
        byteArray1 = new byte[amountOfByteArrays][size];
        byteArray2 = new byte[amountOfByteArrays][size];

        for (int i = 0; i < amountOfByteArrays; i++) {
            for (int j = 0; j < size - 1; j++) {
                byteArray1[i][j] = (byte) j;
                byteArray2[i][j] = (byte) j;
            }
            // now, let last element different in each input
            byteArray1[i][size - 1] = (byte) 0;
            byteArray2[i][size - 1] = (byte) 1;
        }
        array1Counter = array2Counter = 0;
    }

    @Benchmark
    public boolean byteArrayEquals() {
        array1Counter = array1Counter % amountOfByteArrays;
        array2Counter = array2Counter % amountOfByteArrays;
        return Arrays.equals(byteArray1[array1Counter++], byteArray2[array2Counter++]);
    }
}
