mirror of https://github.com/apache/druid.git
Migrate bitmap benchmarks to JMH (#10936)
* Migrate bitmap benchmarks to JMH * add concise
This commit is contained in:
parent
1a15987432
commit
2c30f8b3b7
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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 org.apache.druid.benchmark.bitmap;
|
||||||
|
|
||||||
|
import org.apache.druid.collections.bitmap.ImmutableBitmap;
|
||||||
|
import org.apache.druid.collections.bitmap.WrappedImmutableConciseBitmap;
|
||||||
|
import org.apache.druid.collections.bitmap.WrappedImmutableRoaringBitmap;
|
||||||
|
import org.apache.druid.extendedset.intset.ImmutableConciseSet;
|
||||||
|
import org.apache.druid.java.util.common.IAE;
|
||||||
|
import org.apache.druid.java.util.common.StringUtils;
|
||||||
|
import org.apache.druid.java.util.common.logger.Logger;
|
||||||
|
import org.roaringbitmap.buffer.ImmutableRoaringBitmap;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public final class BitmapBenchmarkUtils
|
||||||
|
{
|
||||||
|
private static final Logger LOG = new Logger(BitmapBenchmarkUtils.class);
|
||||||
|
|
||||||
|
public static ImmutableBitmap toOffheap(ImmutableBitmap bitmap) throws IOException
|
||||||
|
{
|
||||||
|
if (bitmap instanceof WrappedImmutableConciseBitmap) {
|
||||||
|
final WrappedImmutableConciseBitmap conciseBitmap = (WrappedImmutableConciseBitmap) bitmap;
|
||||||
|
final byte[] bytes = conciseBitmap.getBitmap().toBytes();
|
||||||
|
final ByteBuffer buf = ByteBuffer.allocateDirect(bytes.length).put(bytes);
|
||||||
|
buf.rewind();
|
||||||
|
return new WrappedImmutableConciseBitmap(new ImmutableConciseSet(buf.asIntBuffer()));
|
||||||
|
} else if (bitmap instanceof WrappedImmutableRoaringBitmap) {
|
||||||
|
final WrappedImmutableRoaringBitmap roaringBitmap = (WrappedImmutableRoaringBitmap) bitmap;
|
||||||
|
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
roaringBitmap.getBitmap().serialize(new DataOutputStream(out));
|
||||||
|
final byte[] bytes = out.toByteArray();
|
||||||
|
final ByteBuffer buf = ByteBuffer.allocateDirect(bytes.length);
|
||||||
|
buf.put(bytes);
|
||||||
|
buf.rewind();
|
||||||
|
return new WrappedImmutableRoaringBitmap(new ImmutableRoaringBitmap(buf.asReadOnlyBuffer()));
|
||||||
|
} else {
|
||||||
|
throw new IAE("Unsupported bitmap type [%s]", bitmap.getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void printSizeStats(String type, double density, long count, long totalBytes)
|
||||||
|
{
|
||||||
|
LOG.info(
|
||||||
|
StringUtils.format(
|
||||||
|
" type = %s, density = %06.5f, count = %5d, average byte size = %5d",
|
||||||
|
type,
|
||||||
|
density,
|
||||||
|
count,
|
||||||
|
totalBytes / count
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BitmapBenchmarkUtils()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,152 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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 org.apache.druid.benchmark.bitmap;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||||
|
import org.apache.druid.collections.bitmap.BitmapFactory;
|
||||||
|
import org.apache.druid.collections.bitmap.ConciseBitmapFactory;
|
||||||
|
import org.apache.druid.collections.bitmap.ImmutableBitmap;
|
||||||
|
import org.apache.druid.collections.bitmap.MutableBitmap;
|
||||||
|
import org.apache.druid.collections.bitmap.RoaringBitmapFactory;
|
||||||
|
import org.apache.druid.common.config.NullHandling;
|
||||||
|
import org.apache.druid.java.util.common.IAE;
|
||||||
|
import org.openjdk.jmh.annotations.Benchmark;
|
||||||
|
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||||
|
import org.openjdk.jmh.annotations.Fork;
|
||||||
|
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;
|
||||||
|
import org.openjdk.jmh.infra.Blackhole;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.function.IntConsumer;
|
||||||
|
|
||||||
|
@State(Scope.Benchmark)
|
||||||
|
@Fork(value = 1, jvmArgsAppend = "-XX:+UseG1GC")
|
||||||
|
@Warmup(iterations = 10)
|
||||||
|
@Measurement(iterations = 10)
|
||||||
|
@BenchmarkMode(Mode.AverageTime)
|
||||||
|
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||||
|
public class BitmapBenchmarkWithVaryingOrder
|
||||||
|
{
|
||||||
|
private static final Random RANDOM = new Random(0);
|
||||||
|
|
||||||
|
@Param({"roaring", "concise"})
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
@Param("10000")
|
||||||
|
private int numBitmaps;
|
||||||
|
|
||||||
|
@Param("500000")
|
||||||
|
private int bitmapLength;
|
||||||
|
|
||||||
|
@Param("50")
|
||||||
|
private int minIntersect;
|
||||||
|
|
||||||
|
// sorted by an order of increasing density
|
||||||
|
private List<ImmutableBitmap> bitmaps;
|
||||||
|
// sorted by an order of decreasing density
|
||||||
|
private List<ImmutableBitmap> reverseBitmaps;
|
||||||
|
private BitmapFactory bitmapFactory;
|
||||||
|
|
||||||
|
static {
|
||||||
|
NullHandling.initializeForTests();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Setup(Level.Trial)
|
||||||
|
public void setup() throws IOException
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case "concise":
|
||||||
|
bitmapFactory = new ConciseBitmapFactory();
|
||||||
|
break;
|
||||||
|
case "roaring":
|
||||||
|
bitmapFactory = new RoaringBitmapFactory();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IAE("Unknown bitmap type[%s]", type);
|
||||||
|
}
|
||||||
|
bitmaps = new ArrayList<>(numBitmaps);
|
||||||
|
|
||||||
|
// Bitmaps usually have a short circuit to early return an empty bitmap if it finds no intersection
|
||||||
|
// during an AND operation. We want to let them iterate all bitmaps instead, so add some bits that
|
||||||
|
// will be set for all bitmaps we create.
|
||||||
|
final int[] knownTrue = new int[minIntersect];
|
||||||
|
for (int i = 0; i < knownTrue.length; ++i) {
|
||||||
|
knownTrue[i] = RANDOM.nextInt(bitmapLength);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < numBitmaps; ++i) {
|
||||||
|
final int bitCount = (int) (i * 0.1); // the later the bitmap is created, the higher its density is.
|
||||||
|
IntSet ints = new IntOpenHashSet(bitCount);
|
||||||
|
for (int j = 0; j < bitCount; j++) {
|
||||||
|
int offset;
|
||||||
|
do {
|
||||||
|
offset = RANDOM.nextInt(bitmapLength);
|
||||||
|
} while (ints.contains(offset));
|
||||||
|
ints.add(offset);
|
||||||
|
}
|
||||||
|
final MutableBitmap mutableBitmap = bitmapFactory.makeEmptyMutableBitmap();
|
||||||
|
ints.iterator().forEachRemaining((IntConsumer) mutableBitmap::add);
|
||||||
|
for (int k : knownTrue) {
|
||||||
|
mutableBitmap.add(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
bitmaps.add(BitmapBenchmarkUtils.toOffheap(bitmapFactory.makeImmutableBitmap(mutableBitmap)));
|
||||||
|
}
|
||||||
|
|
||||||
|
reverseBitmaps = Lists.reverse(bitmaps);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void union(Blackhole blackhole)
|
||||||
|
{
|
||||||
|
blackhole.consume(bitmapFactory.union(bitmaps));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void unionReverse(Blackhole blackhole)
|
||||||
|
{
|
||||||
|
blackhole.consume(bitmapFactory.union(reverseBitmaps));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void intersection(Blackhole blackhole)
|
||||||
|
{
|
||||||
|
blackhole.consume(bitmapFactory.intersection(bitmaps));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void intersectionReverse(Blackhole blackhole)
|
||||||
|
{
|
||||||
|
blackhole.consume(bitmapFactory.intersection(reverseBitmaps));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,132 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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 org.apache.druid.benchmark.bitmap;
|
||||||
|
|
||||||
|
import org.apache.druid.collections.bitmap.BitmapFactory;
|
||||||
|
import org.apache.druid.collections.bitmap.ConciseBitmapFactory;
|
||||||
|
import org.apache.druid.collections.bitmap.ImmutableBitmap;
|
||||||
|
import org.apache.druid.collections.bitmap.MutableBitmap;
|
||||||
|
import org.apache.druid.collections.bitmap.RoaringBitmapFactory;
|
||||||
|
import org.apache.druid.common.config.NullHandling;
|
||||||
|
import org.apache.druid.java.util.common.IAE;
|
||||||
|
import org.openjdk.jmh.annotations.Benchmark;
|
||||||
|
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||||
|
import org.openjdk.jmh.annotations.Fork;
|
||||||
|
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;
|
||||||
|
import org.openjdk.jmh.infra.Blackhole;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@State(Scope.Benchmark)
|
||||||
|
@Fork(value = 1, jvmArgsAppend = "-XX:+UseG1GC")
|
||||||
|
@Warmup(iterations = 10)
|
||||||
|
@Measurement(iterations = 10)
|
||||||
|
@BenchmarkMode(Mode.AverageTime)
|
||||||
|
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||||
|
public class RangeBitmapBenchmark
|
||||||
|
{
|
||||||
|
private static final Random RANDOM = new Random(0);
|
||||||
|
|
||||||
|
@Param({"concise", "roaring"})
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
@Param("10000")
|
||||||
|
private int numBitmaps;
|
||||||
|
|
||||||
|
@Param("500000")
|
||||||
|
private int bitmapLength;
|
||||||
|
|
||||||
|
@Param("0.001")
|
||||||
|
private double density;
|
||||||
|
|
||||||
|
@Param("50")
|
||||||
|
private int minIntersect;
|
||||||
|
|
||||||
|
private List<ImmutableBitmap> bitmaps;
|
||||||
|
private BitmapFactory bitmapFactory;
|
||||||
|
|
||||||
|
static {
|
||||||
|
NullHandling.initializeForTests();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Setup(Level.Trial)
|
||||||
|
public void setup() throws IOException
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case "concise":
|
||||||
|
bitmapFactory = new ConciseBitmapFactory();
|
||||||
|
break;
|
||||||
|
case "roaring":
|
||||||
|
bitmapFactory = new RoaringBitmapFactory();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IAE("Unknown bitmap type[%s]", type);
|
||||||
|
}
|
||||||
|
bitmaps = new ArrayList<>(numBitmaps);
|
||||||
|
|
||||||
|
for (int i = 0; i < numBitmaps; ++i) {
|
||||||
|
final MutableBitmap mutableBitmap = bitmapFactory.makeEmptyMutableBitmap();
|
||||||
|
|
||||||
|
int k = 0;
|
||||||
|
boolean fill = true;
|
||||||
|
while (k < bitmapLength) {
|
||||||
|
int runLength = (int) (bitmapLength * density) + RANDOM.nextInt((int) (bitmapLength * density));
|
||||||
|
for (int j = k; fill && j < bitmapLength && j < k + runLength; ++j) {
|
||||||
|
mutableBitmap.add(j);
|
||||||
|
}
|
||||||
|
k += runLength;
|
||||||
|
fill = !fill;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (k = bitmapLength / 2; k < bitmapLength / 2 + minIntersect; ++k) {
|
||||||
|
mutableBitmap.add(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
bitmaps.add(BitmapBenchmarkUtils.toOffheap(bitmapFactory.makeImmutableBitmap(mutableBitmap)));
|
||||||
|
}
|
||||||
|
|
||||||
|
final long totalSizeBytes = bitmaps.stream().mapToLong(bitmap -> bitmap.toBytes().length).sum();
|
||||||
|
BitmapBenchmarkUtils.printSizeStats(type, density, bitmaps.size(), totalSizeBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void union(Blackhole blackhole)
|
||||||
|
{
|
||||||
|
blackhole.consume(bitmapFactory.union(bitmaps));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void intersection(Blackhole blackhole)
|
||||||
|
{
|
||||||
|
blackhole.consume(bitmapFactory.intersection(bitmaps));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,129 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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 org.apache.druid.benchmark.bitmap;
|
||||||
|
|
||||||
|
import org.apache.druid.collections.bitmap.BitmapFactory;
|
||||||
|
import org.apache.druid.collections.bitmap.ConciseBitmapFactory;
|
||||||
|
import org.apache.druid.collections.bitmap.ImmutableBitmap;
|
||||||
|
import org.apache.druid.collections.bitmap.MutableBitmap;
|
||||||
|
import org.apache.druid.collections.bitmap.RoaringBitmapFactory;
|
||||||
|
import org.apache.druid.common.config.NullHandling;
|
||||||
|
import org.apache.druid.java.util.common.IAE;
|
||||||
|
import org.openjdk.jmh.annotations.Benchmark;
|
||||||
|
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||||
|
import org.openjdk.jmh.annotations.Fork;
|
||||||
|
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;
|
||||||
|
import org.openjdk.jmh.infra.Blackhole;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@State(Scope.Benchmark)
|
||||||
|
@Fork(value = 1, jvmArgsAppend = "-XX:+UseG1GC")
|
||||||
|
@Warmup(iterations = 10)
|
||||||
|
@Measurement(iterations = 10)
|
||||||
|
@BenchmarkMode(Mode.AverageTime)
|
||||||
|
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||||
|
public class UniformBitmapBenchmark
|
||||||
|
{
|
||||||
|
private static final Random RANDOM = new Random(0);
|
||||||
|
|
||||||
|
@Param({"concise", "roaring"})
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
@Param("10000")
|
||||||
|
private int numBitmaps;
|
||||||
|
|
||||||
|
@Param("500000")
|
||||||
|
private int bitmapLength;
|
||||||
|
|
||||||
|
@Param("0.01")
|
||||||
|
private double density;
|
||||||
|
|
||||||
|
@Param("50")
|
||||||
|
private int minIntersect;
|
||||||
|
|
||||||
|
private List<ImmutableBitmap> bitmaps;
|
||||||
|
private BitmapFactory bitmapFactory;
|
||||||
|
|
||||||
|
static {
|
||||||
|
NullHandling.initializeForTests();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Setup(Level.Trial)
|
||||||
|
public void setup() throws IOException
|
||||||
|
{
|
||||||
|
final int[] knownTrue = new int[minIntersect];
|
||||||
|
for (int i = 0; i < knownTrue.length; ++i) {
|
||||||
|
knownTrue[i] = RANDOM.nextInt(bitmapLength);
|
||||||
|
}
|
||||||
|
switch (type) {
|
||||||
|
case "concise":
|
||||||
|
bitmapFactory = new ConciseBitmapFactory();
|
||||||
|
break;
|
||||||
|
case "roaring":
|
||||||
|
bitmapFactory = new RoaringBitmapFactory();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IAE("Unknown bitmap type[%s]", type);
|
||||||
|
}
|
||||||
|
bitmaps = new ArrayList<>(numBitmaps);
|
||||||
|
|
||||||
|
for (int i = 0; i < numBitmaps; ++i) {
|
||||||
|
final MutableBitmap mutableBitmap = bitmapFactory.makeEmptyMutableBitmap();
|
||||||
|
for (int k = 0; k < bitmapLength; ++k) {
|
||||||
|
if (RANDOM.nextDouble() < density) {
|
||||||
|
mutableBitmap.add(k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int k : knownTrue) {
|
||||||
|
mutableBitmap.add(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
bitmaps.add(BitmapBenchmarkUtils.toOffheap(bitmapFactory.makeImmutableBitmap(mutableBitmap)));
|
||||||
|
}
|
||||||
|
|
||||||
|
final long totalSizeBytes = bitmaps.stream().mapToLong(bitmap -> bitmap.toBytes().length).sum();
|
||||||
|
BitmapBenchmarkUtils.printSizeStats(type, density, bitmaps.size(), totalSizeBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void union(Blackhole blackhole)
|
||||||
|
{
|
||||||
|
blackhole.consume(bitmapFactory.union(bitmaps));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void intersection(Blackhole blackhole)
|
||||||
|
{
|
||||||
|
blackhole.consume(bitmapFactory.intersection(bitmaps));
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,27 +19,14 @@
|
||||||
|
|
||||||
package org.apache.druid.collections.bitmap;
|
package org.apache.druid.collections.bitmap;
|
||||||
|
|
||||||
import com.carrotsearch.junitbenchmarks.annotation.BenchmarkHistoryChart;
|
|
||||||
import com.carrotsearch.junitbenchmarks.annotation.LabelType;
|
|
||||||
import org.apache.druid.collections.test.annotation.Benchmark;
|
|
||||||
import org.apache.druid.extendedset.intset.ConciseSet;
|
import org.apache.druid.extendedset.intset.ConciseSet;
|
||||||
import org.apache.druid.extendedset.intset.ImmutableConciseSet;
|
import org.apache.druid.extendedset.intset.ImmutableConciseSet;
|
||||||
import org.apache.druid.java.util.common.StringUtils;
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.experimental.categories.Category;
|
|
||||||
import org.roaringbitmap.buffer.MutableRoaringBitmap;
|
import org.roaringbitmap.buffer.MutableRoaringBitmap;
|
||||||
|
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
|
|
||||||
/**
|
public class BitmapOperationAgainstConsecutiveRunsTest extends BitmapOperationTest
|
||||||
* TODO rewrite this benchmark to JMH
|
|
||||||
* If you want to run locally, remove @Ignore on the class.
|
|
||||||
*/
|
|
||||||
@Category({Benchmark.class})
|
|
||||||
@BenchmarkHistoryChart(labelWith = LabelType.CUSTOM_KEY, maxRuns = 20)
|
|
||||||
@Ignore
|
|
||||||
public class RangeBitmapBenchmarkTest extends BitmapBenchmark
|
|
||||||
{
|
{
|
||||||
|
|
||||||
public static final double DENSITY = 0.001;
|
public static final double DENSITY = 0.001;
|
||||||
|
@ -48,19 +35,18 @@ public class RangeBitmapBenchmarkTest extends BitmapBenchmark
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void prepareRandomRanges() throws Exception
|
public static void prepareRandomRanges() throws Exception
|
||||||
{
|
{
|
||||||
System.setProperty("jub.customkey", StringUtils.format("%06.5f", DENSITY));
|
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
final BitSet expectedUnion = new BitSet();
|
final BitSet expectedUnion = new BitSet();
|
||||||
for (int i = 0; i < SIZE; ++i) {
|
for (int i = 0; i < NUM_BITMAPS; ++i) {
|
||||||
ConciseSet c = new ConciseSet();
|
ConciseSet c = new ConciseSet();
|
||||||
MutableRoaringBitmap r = new MutableRoaringBitmap();
|
MutableRoaringBitmap r = new MutableRoaringBitmap();
|
||||||
{
|
{
|
||||||
int k = 0;
|
int k = 0;
|
||||||
boolean fill = true;
|
boolean fill = true;
|
||||||
while (k < LENGTH) {
|
while (k < BITMAP_LENGTH) {
|
||||||
int runLength = (int) (LENGTH * DENSITY) + rand.nextInt((int) (LENGTH * DENSITY));
|
int runLength = (int) (BITMAP_LENGTH * DENSITY) + rand.nextInt((int) (BITMAP_LENGTH * DENSITY));
|
||||||
for (int j = k; fill && j < LENGTH && j < k + runLength; ++j) {
|
for (int j = k; fill && j < BITMAP_LENGTH && j < k + runLength; ++j) {
|
||||||
c.add(j);
|
c.add(j);
|
||||||
r.add(j);
|
r.add(j);
|
||||||
expectedUnion.set(j);
|
expectedUnion.set(j);
|
||||||
|
@ -70,7 +56,7 @@ public class RangeBitmapBenchmarkTest extends BitmapBenchmark
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
minIntersection = MIN_INTERSECT;
|
minIntersection = MIN_INTERSECT;
|
||||||
for (int k = LENGTH / 2; k < LENGTH / 2 + minIntersection; ++k) {
|
for (int k = BITMAP_LENGTH / 2; k < BITMAP_LENGTH / 2 + minIntersection; ++k) {
|
||||||
c.add(k);
|
c.add(k);
|
||||||
r.add(k);
|
r.add(k);
|
||||||
expectedUnion.set(k);
|
expectedUnion.set(k);
|
|
@ -19,47 +19,32 @@
|
||||||
|
|
||||||
package org.apache.druid.collections.bitmap;
|
package org.apache.druid.collections.bitmap;
|
||||||
|
|
||||||
import com.carrotsearch.junitbenchmarks.annotation.BenchmarkHistoryChart;
|
|
||||||
import com.carrotsearch.junitbenchmarks.annotation.LabelType;
|
|
||||||
import org.apache.druid.collections.test.annotation.Benchmark;
|
|
||||||
import org.apache.druid.extendedset.intset.ConciseSet;
|
import org.apache.druid.extendedset.intset.ConciseSet;
|
||||||
import org.apache.druid.extendedset.intset.ImmutableConciseSet;
|
import org.apache.druid.extendedset.intset.ImmutableConciseSet;
|
||||||
import org.apache.druid.java.util.common.StringUtils;
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.experimental.categories.Category;
|
|
||||||
import org.roaringbitmap.buffer.MutableRoaringBitmap;
|
import org.roaringbitmap.buffer.MutableRoaringBitmap;
|
||||||
|
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
|
|
||||||
/**
|
public class BitmapOperationAgainstUniformDistributionTest extends BitmapOperationTest
|
||||||
* TODO rewrite this benchmark to JMH.
|
|
||||||
* If you want to run locally, remove @Ignore on the class.
|
|
||||||
*/
|
|
||||||
@Category({Benchmark.class})
|
|
||||||
@BenchmarkHistoryChart(labelWith = LabelType.CUSTOM_KEY, maxRuns = 20)
|
|
||||||
@Ignore
|
|
||||||
public class UniformBitmapBenchmarkTest extends BitmapBenchmark
|
|
||||||
{
|
{
|
||||||
|
|
||||||
public static final double DENSITY = 0.01;
|
public static final double DENSITY = 0.01;
|
||||||
public static final int MIN_INTERSECT = 50;
|
public static final int MIN_INTERSECT = 50;
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void prepareMostlyUniform() throws Exception
|
public static void prepareMostlyUniform() throws Exception
|
||||||
{
|
{
|
||||||
System.setProperty("jub.customkey", StringUtils.format("%05.4f", DENSITY));
|
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
final BitSet expectedUnion = new BitSet();
|
final BitSet expectedUnion = new BitSet();
|
||||||
final int[] knownTrue = new int[MIN_INTERSECT];
|
final int[] knownTrue = new int[MIN_INTERSECT];
|
||||||
for (int i = 0; i < knownTrue.length; ++i) {
|
for (int i = 0; i < knownTrue.length; ++i) {
|
||||||
knownTrue[i] = rand.nextInt(LENGTH);
|
knownTrue[i] = rand.nextInt(BITMAP_LENGTH);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < SIZE; ++i) {
|
for (int i = 0; i < NUM_BITMAPS; ++i) {
|
||||||
ConciseSet c = new ConciseSet();
|
ConciseSet c = new ConciseSet();
|
||||||
MutableRoaringBitmap r = new MutableRoaringBitmap();
|
MutableRoaringBitmap r = new MutableRoaringBitmap();
|
||||||
for (int k = 0; k < LENGTH; ++k) {
|
for (int k = 0; k < BITMAP_LENGTH; ++k) {
|
||||||
if (rand.nextDouble() < DENSITY) {
|
if (rand.nextDouble() < DENSITY) {
|
||||||
c.add(k);
|
c.add(k);
|
||||||
r.add(k);
|
r.add(k);
|
|
@ -19,16 +19,10 @@
|
||||||
|
|
||||||
package org.apache.druid.collections.bitmap;
|
package org.apache.druid.collections.bitmap;
|
||||||
|
|
||||||
import com.carrotsearch.junitbenchmarks.BenchmarkOptions;
|
|
||||||
import com.carrotsearch.junitbenchmarks.BenchmarkRule;
|
|
||||||
import com.carrotsearch.junitbenchmarks.Clock;
|
|
||||||
import org.apache.druid.common.config.NullHandling;
|
import org.apache.druid.common.config.NullHandling;
|
||||||
import org.apache.druid.extendedset.intset.ImmutableConciseSet;
|
import org.apache.druid.extendedset.intset.ImmutableConciseSet;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.TestRule;
|
|
||||||
import org.roaringbitmap.buffer.BufferFastAggregation;
|
import org.roaringbitmap.buffer.BufferFastAggregation;
|
||||||
import org.roaringbitmap.buffer.ImmutableRoaringBitmap;
|
import org.roaringbitmap.buffer.ImmutableRoaringBitmap;
|
||||||
import org.roaringbitmap.buffer.MutableRoaringBitmap;
|
import org.roaringbitmap.buffer.MutableRoaringBitmap;
|
||||||
|
@ -41,23 +35,17 @@ import java.util.Arrays;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
/**
|
public class BitmapOperationTest
|
||||||
* TODO rewrite this benchmark to JMH
|
|
||||||
* If you want to run locally, remove @Ignore on the class.
|
|
||||||
*/
|
|
||||||
@BenchmarkOptions(clock = Clock.NANO_TIME, benchmarkRounds = 50)
|
|
||||||
@Ignore
|
|
||||||
public class BitmapBenchmark
|
|
||||||
{
|
{
|
||||||
public static final int LENGTH = 500_000;
|
public static final int BITMAP_LENGTH = 500_000;
|
||||||
public static final int SIZE = 10_000;
|
public static final int NUM_BITMAPS = 1000;
|
||||||
static final ImmutableConciseSet[] CONCISE = new ImmutableConciseSet[SIZE];
|
static final ImmutableConciseSet[] CONCISE = new ImmutableConciseSet[NUM_BITMAPS];
|
||||||
static final ImmutableConciseSet[] OFF_HEAP_CONCISE = new ImmutableConciseSet[SIZE];
|
static final ImmutableConciseSet[] OFF_HEAP_CONCISE = new ImmutableConciseSet[NUM_BITMAPS];
|
||||||
static final ImmutableRoaringBitmap[] ROARING = new ImmutableRoaringBitmap[SIZE];
|
static final ImmutableRoaringBitmap[] ROARING = new ImmutableRoaringBitmap[NUM_BITMAPS];
|
||||||
static final ImmutableRoaringBitmap[] IMMUTABLE_ROARING = new ImmutableRoaringBitmap[SIZE];
|
static final ImmutableRoaringBitmap[] IMMUTABLE_ROARING = new ImmutableRoaringBitmap[NUM_BITMAPS];
|
||||||
static final ImmutableRoaringBitmap[] OFF_HEAP_ROARING = new ImmutableRoaringBitmap[SIZE];
|
static final ImmutableRoaringBitmap[] OFF_HEAP_ROARING = new ImmutableRoaringBitmap[NUM_BITMAPS];
|
||||||
static final ImmutableBitmap[] GENERIC_CONCISE = new ImmutableBitmap[SIZE];
|
static final ImmutableBitmap[] GENERIC_CONCISE = new ImmutableBitmap[NUM_BITMAPS];
|
||||||
static final ImmutableBitmap[] GENERIC_ROARING = new ImmutableBitmap[SIZE];
|
static final ImmutableBitmap[] GENERIC_ROARING = new ImmutableBitmap[NUM_BITMAPS];
|
||||||
static final ConciseBitmapFactory CONCISE_FACTORY = new ConciseBitmapFactory();
|
static final ConciseBitmapFactory CONCISE_FACTORY = new ConciseBitmapFactory();
|
||||||
static final RoaringBitmapFactory ROARING_FACTORY = new RoaringBitmapFactory();
|
static final RoaringBitmapFactory ROARING_FACTORY = new RoaringBitmapFactory();
|
||||||
static Random rand = new Random(0);
|
static Random rand = new Random(0);
|
||||||
|
@ -67,8 +55,6 @@ public class BitmapBenchmark
|
||||||
static long roaringCount = 0;
|
static long roaringCount = 0;
|
||||||
static long unionCount = 0;
|
static long unionCount = 0;
|
||||||
static long minIntersection = 0;
|
static long minIntersection = 0;
|
||||||
@Rule
|
|
||||||
public TestRule benchmarkRun = new BenchmarkRule();
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
NullHandling.initializeForTests();
|
NullHandling.initializeForTests();
|
||||||
|
@ -141,67 +127,63 @@ public class BitmapBenchmark
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@BenchmarkOptions(warmupRounds = 1, benchmarkRounds = 2)
|
public void testConciseUnion()
|
||||||
public void timeConciseUnion()
|
|
||||||
{
|
{
|
||||||
ImmutableConciseSet union = ImmutableConciseSet.union(CONCISE);
|
ImmutableConciseSet union = ImmutableConciseSet.union(CONCISE);
|
||||||
Assert.assertEquals(unionCount, union.size());
|
Assert.assertEquals(unionCount, union.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@BenchmarkOptions(warmupRounds = 1, benchmarkRounds = 2)
|
public void testOffheapConciseUnion()
|
||||||
public void timeOffheapConciseUnion()
|
|
||||||
{
|
{
|
||||||
ImmutableConciseSet union = ImmutableConciseSet.union(OFF_HEAP_CONCISE);
|
ImmutableConciseSet union = ImmutableConciseSet.union(OFF_HEAP_CONCISE);
|
||||||
Assert.assertEquals(unionCount, union.size());
|
Assert.assertEquals(unionCount, union.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@BenchmarkOptions(warmupRounds = 1, benchmarkRounds = 2)
|
public void testGenericConciseUnion()
|
||||||
public void timeGenericConciseUnion()
|
|
||||||
{
|
{
|
||||||
ImmutableBitmap union = CONCISE_FACTORY.union(Arrays.asList(GENERIC_CONCISE));
|
ImmutableBitmap union = CONCISE_FACTORY.union(Arrays.asList(GENERIC_CONCISE));
|
||||||
Assert.assertEquals(unionCount, union.size());
|
Assert.assertEquals(unionCount, union.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@BenchmarkOptions(warmupRounds = 1, benchmarkRounds = 5)
|
public void testGenericConciseIntersection()
|
||||||
public void timeGenericConciseIntersection()
|
|
||||||
{
|
{
|
||||||
ImmutableBitmap intersection = CONCISE_FACTORY.intersection(Arrays.asList(GENERIC_CONCISE));
|
ImmutableBitmap intersection = CONCISE_FACTORY.intersection(Arrays.asList(GENERIC_CONCISE));
|
||||||
Assert.assertTrue(intersection.size() >= minIntersection);
|
Assert.assertTrue(intersection.size() >= minIntersection);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void timeRoaringUnion()
|
public void testRoaringUnion()
|
||||||
{
|
{
|
||||||
ImmutableRoaringBitmap union = BufferFastAggregation.horizontal_or(Arrays.asList(ROARING).iterator());
|
ImmutableRoaringBitmap union = BufferFastAggregation.horizontal_or(Arrays.asList(ROARING).iterator());
|
||||||
Assert.assertEquals(unionCount, union.getCardinality());
|
Assert.assertEquals(unionCount, union.getCardinality());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void timeImmutableRoaringUnion()
|
public void testImmutableRoaringUnion()
|
||||||
{
|
{
|
||||||
ImmutableRoaringBitmap union = BufferFastAggregation.horizontal_or(Arrays.asList(IMMUTABLE_ROARING).iterator());
|
ImmutableRoaringBitmap union = BufferFastAggregation.horizontal_or(Arrays.asList(IMMUTABLE_ROARING).iterator());
|
||||||
Assert.assertEquals(unionCount, union.getCardinality());
|
Assert.assertEquals(unionCount, union.getCardinality());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void timeOffheapRoaringUnion()
|
public void testOffheapRoaringUnion()
|
||||||
{
|
{
|
||||||
ImmutableRoaringBitmap union = BufferFastAggregation.horizontal_or(Arrays.asList(OFF_HEAP_ROARING).iterator());
|
ImmutableRoaringBitmap union = BufferFastAggregation.horizontal_or(Arrays.asList(OFF_HEAP_ROARING).iterator());
|
||||||
Assert.assertEquals(unionCount, union.getCardinality());
|
Assert.assertEquals(unionCount, union.getCardinality());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void timeGenericRoaringUnion()
|
public void testGenericRoaringUnion()
|
||||||
{
|
{
|
||||||
ImmutableBitmap union = ROARING_FACTORY.union(Arrays.asList(GENERIC_ROARING));
|
ImmutableBitmap union = ROARING_FACTORY.union(Arrays.asList(GENERIC_ROARING));
|
||||||
Assert.assertEquals(unionCount, union.size());
|
Assert.assertEquals(unionCount, union.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void timeGenericRoaringIntersection()
|
public void testGenericRoaringIntersection()
|
||||||
{
|
{
|
||||||
ImmutableBitmap intersection = ROARING_FACTORY.intersection(Arrays.asList(GENERIC_ROARING));
|
ImmutableBitmap intersection = ROARING_FACTORY.intersection(Arrays.asList(GENERIC_ROARING));
|
||||||
Assert.assertTrue(intersection.size() >= minIntersection);
|
Assert.assertTrue(intersection.size() >= minIntersection);
|
Loading…
Reference in New Issue