/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.airlift.stats.cardinality;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.options.VerboseMode;

import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

@State(Scope.Thread)
@OutputTimeUnit(TimeUnit.SECONDS)
@Fork(5)
@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
public class BenchmarkDenseHll
{
    @Benchmark
    public DenseHll benchmarkInsert(Data data)
    {
        for (long hash : data.hashes) {
            data.instance.insertHash(hash);
        }

        return data.instance;
    }

    @State(Scope.Thread)
    public static class Data
    {
        public final DenseHll instance = new DenseHll(11);
        public final long[] hashes = new long[500];

        @Setup(Level.Iteration)
        public void initialize()
        {
            for (int i = 0; i < hashes.length; i++) {
                hashes[i] = ThreadLocalRandom.current().nextLong();
            }
        }
    }

    public static void main(String[] args)
            throws RunnerException
    {
        Options options = new OptionsBuilder()
                .verbosity(VerboseMode.NORMAL)
                .include(".*" + BenchmarkDenseHll.class.getSimpleName() + ".*")
                .build();

        new Runner(options).run();
    }
}

@@ -636,24 +636,74 @@
 .Benchmark;%0A
+import org.openjdk.jmh.annotations.BenchmarkMode;%0A
 import org.o
@@ -821,16 +821,57 @@
 rement;%0A
+import org.openjdk.jmh.annotations.Mode;%0A
 import o
@@ -1452,16 +1452,21 @@
 imeUnit.
+MICRO
 SECONDS)
@@ -1466,16 +1466,49 @@
 ECONDS)%0A
+@BenchmarkMode(Mode.AverageTime)%0A
 @Fork(5)
@@ -1687,16 +1687,131 @@
 seHll%0A%7B%0A
+    private static final int LARGE_CARDINALITY = 1_000_000;%0A    private static final int SMALL_CARDINALITY = 100;%0A%0A
     @Ben
@@ -1853,16 +1853,22 @@
 kInsert(
+Insert
 Data dat
@@ -2004,24 +2004,153 @@
 nce;%0A    %7D%0A%0A
+    @Benchmark%0A    public DenseHll benchmarkMerge(MergeData data)%0A    %7B%0A        return data.base.mergeWith(data.toMerge);%0A    %7D%0A%0A
     @State(S
@@ -2186,16 +2186,22 @@
 c class 
+Insert
 Data%0A   
@@ -2539,24 +2539,808 @@
    %7D%0A    %7D%0A%0A
+    @State(Scope.Thread)%0A    public static class MergeData%0A    %7B%0A        public DenseHll base;%0A        public DenseHll toMerge;%0A%0A        @Setup(Level.Iteration)%0A        public void initialize()%0A        %7B%0A            base = new DenseHll(12);%0A            for (int i = 0; i %3C LARGE_CARDINALITY; i++) %7B%0A                base.insertHash(ThreadLocalRandom.current().nextLong());%0A            %7D%0A%0A            // Small cardinality so we can do an apples-to-apples comparison%0A            // between dense/dense vs dense/sparse merge. Sparse only supports%0A            // small cardinalities.%0A            toMerge = new DenseHll(12);%0A            for (int i = 0; i %3C SMALL_CARDINALITY; i++) %7B%0A                toMerge.insertHash(ThreadLocalRandom.current().nextLong());%0A            %7D%0A        %7D%0A    %7D%0A%0A
     public s

Add Dense HLL merge benchmark