This is an automated email from the ASF dual-hosted git repository.
xiangfu0 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git
The following commit(s) were added to refs/heads/master by this push:
new a6ea7b0debd Remove obsolete benchmarks and timing-only unit tests
(#19538)
a6ea7b0debd is described below
commit a6ea7b0debd74950a5fa97720eff5ef78e4cf1f2
Author: Xiang Fu <[email protected]>
AuthorDate: Sun Sep 13 23:55:01 2026 -0700
Remove obsolete benchmarks and timing-only unit tests (#19538)
* Remove ad hoc benchmarks from unit tests
Remove timing-only interner and retention tests and the disabled vector
benchmark class. Preserve functional assertions, remove the HDFS deletion
timing threshold, and give the ANY_VALUE test a correctness-focused name.
How to reproduce:
On the parent revision, run FALFInternerTest#benchmarkingTest through
./mvnw -pl pinot-common -am -Dsurefire.failIfNoSpecifiedTests=false test
with -Dtest=FALFInternerTest#benchmarkingTest. It runs about 737 million
interning calls and prints timings without checking correctness.
Validation: 136 focused tests passed on JDK 25. Spotless, Checkstyle, and
license checks passed. Isolated lint passed for all modified test classes.
* Remove obsolete and duplicate performance benchmarks
Drop ten retired experiments or invalid/duplicate harnesses, their obsolete
launchers, unused LazyDataList, and three unregistered off-heap map methods.
Keep current workload benchmarks and document their entry points.
The removed standalone runners include a dictionary test that reloads its
deleted segment, a memory test that never initializes its memory manager,
and index-size comparisons based on stale v1 file paths or empty offsets.
The removed SUM workload is covered by the retained SUM/SUMINT benchmark.
Validation: all four style/license checks passed for pinot-perf; the
64-module reactor package build passed. JMH discovers 302 retained methods,
all 16 launchers resolve, and forked SUM/dictionary lookup smoke runs pass.
---
.../pinot/common/utils/FALFInternerTest.java | 71 +---
.../helix/core/retention/RetentionManagerTest.java | 79 -----
.../function/AnyValueAggregationFunctionTest.java | 5 +-
pinot-perf/README.md | 19 +
pinot-perf/pom.xml | 20 --
.../perf/BenchmarkFixedIntArrayOffHeapIdMap.java | 59 ----
.../perf/BenchmarkGroovyExpressionEvaluation.java | 190 ----------
.../org/apache/pinot/perf/BenchmarkJsonKeyMap.java | 172 ---------
.../perf/BenchmarkOffHeapDictionaryMemory.java | 133 -------
.../apache/pinot/perf/BenchmarkQueryEngine.java | 152 --------
.../pinot/perf/BenchmarkRoaringBitmapCreation.java | 217 ------------
.../pinot/perf/BenchmarkRoaringBitmapMapping.java | 328 -----------------
.../pinot/perf/ForwardIndexWriterBenchmark.java | 120 -------
.../java/org/apache/pinot/perf/LazyDataList.java | 163 ---------
.../org/apache/pinot/perf/RawIndexBenchmark.java | 293 ----------------
.../pinot/perf/StringDictionaryPerfTest.java | 189 ----------
.../pinot/perf/aggregation/BenchmarkSumQuery.java | 121 -------
.../pinot/plugin/filesystem/HadoopPinotFSTest.java | 16 +-
.../index/vector/VectorSearchBenchmark.java | 389 ---------------------
19 files changed, 39 insertions(+), 2697 deletions(-)
diff --git
a/pinot-common/src/test/java/org/apache/pinot/common/utils/FALFInternerTest.java
b/pinot-common/src/test/java/org/apache/pinot/common/utils/FALFInternerTest.java
index 3916a3494f9..f333a8e3dd7 100644
---
a/pinot-common/src/test/java/org/apache/pinot/common/utils/FALFInternerTest.java
+++
b/pinot-common/src/test/java/org/apache/pinot/common/utils/FALFInternerTest.java
@@ -23,9 +23,11 @@ import com.google.common.collect.Interners;
import java.util.Objects;
import java.util.Random;
import org.apache.pinot.spi.utils.FALFInterner;
-import org.testng.Assert;
import org.testng.annotations.Test;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
public class FALFInternerTest {
@Test
@@ -49,78 +51,27 @@ public class FALFInternerTest {
new FALFInterner(nUniqueObjs, s -> FALFInterner.hashCode((String) s),
Objects::equals);
// Go over all objects and intern them using both exact and FALF interners
- int nHits1 = runInterning(allObjs, exactInterner, true);
- int nHits2 = runInterning(allObjs, falfInterner, true);
- int nHits3 = runInterning(allObjs, falfInternerCustomHash, true);
+ int nHits1 = runInterning(allObjs, exactInterner);
+ int nHits2 = runInterning(allObjs, falfInterner);
+ int nHits3 = runInterning(allObjs, falfInternerCustomHash);
// For the exact interner, we should get a hit for each object except the
// first nUniqueObjs.
- Assert.assertEquals(nHits1, nTotalObjs - nUniqueObjs);
+ assertEquals(nHits1, nTotalObjs - nUniqueObjs);
// For the FALF interner, due to its fixed size and thus almost inevitable
hash
// collisions, the number of hits is smaller. Let's verify that it's not
too small, though.
- Assert.assertTrue(nHits2 > (nTotalObjs - nUniqueObjs) * 0.4);
+ assertTrue(nHits2 > (nTotalObjs - nUniqueObjs) * 0.4);
// With the better hash function, FALF interner should have more hits
- Assert.assertTrue(nHits3 > (nTotalObjs - nUniqueObjs) * 0.6);
+ assertTrue(nHits3 > (nTotalObjs - nUniqueObjs) * 0.6);
}
- /// Ad hoc benchmarking code. In one run the MacBook laptop, FALFInterner
below performs nearly twice faster (1217 ms
- /// vs 2230 ms) With custom hash function, FALFInterner's speed is about the
same as the Guava interner.
- @Test
- public void benchmarkingTest() {
- Random random = new Random(1);
-
- int nUniqueObjs = 1024;
- int nTotalObjs = 8 * nUniqueObjs;
-
- String[] allObjs = new String[nTotalObjs];
-
- Interner<String> exactInterner = Interners.newStrongInterner();
- Interner<String> falfInterner = new FALFInterner(nUniqueObjs);
- Interner<String> falfInternerCustomHash =
- new FALFInterner(nUniqueObjs, s -> FALFInterner.hashCode((String) s),
Objects::equals);
-
- // Create an array of objects where each object should have ~8 copies
- for (int i = 0; i < nTotalObjs; i++) {
- int next = random.nextInt(nUniqueObjs);
- allObjs[i] = Integer.toString(next);
- }
-
- for (int j = 0; j < 3; j++) {
- long time0 = System.currentTimeMillis();
- long totNHits = 0;
- for (int i = 0; i < 10000; i++) {
- totNHits += runInterning(allObjs, exactInterner, false);
- }
- long time1 = System.currentTimeMillis();
- System.out.println("Guava interner. totNHits = " + totNHits + ", time =
" + (time1 - time0));
-
- time0 = System.currentTimeMillis();
- totNHits = 0;
- for (int i = 0; i < 10000; i++) {
- totNHits += runInterning(allObjs, falfInterner, false);
- }
- time1 = System.currentTimeMillis();
- System.out.println("FALF interner. totNHits = " + totNHits + ", time = "
+ (time1 - time0));
-
- time0 = System.currentTimeMillis();
- totNHits = 0;
- for (int i = 0; i < 10000; i++) {
- totNHits += runInterning(allObjs, falfInternerCustomHash, false);
- }
- time1 = System.currentTimeMillis();
- System.out.println("FALF interner Custom Hash. totNHits = " + totNHits +
", time = " + (time1 - time0));
- }
- }
-
- private int runInterning(String[] objs, Interner<String> interner, boolean
performAssert) {
+ private int runInterning(String[] objs, Interner<String> interner) {
int nHits = 0;
for (String origObj : objs) {
String internedObj = interner.intern(origObj);
- if (performAssert) {
- Assert.assertEquals(origObj, internedObj);
- }
+ assertEquals(origObj, internedObj);
if (origObj != internedObj) {
nHits++;
}
diff --git
a/pinot-controller/src/test/java/org/apache/pinot/controller/helix/core/retention/RetentionManagerTest.java
b/pinot-controller/src/test/java/org/apache/pinot/controller/helix/core/retention/RetentionManagerTest.java
index 7c1cf544a04..c0023bda878 100644
---
a/pinot-controller/src/test/java/org/apache/pinot/controller/helix/core/retention/RetentionManagerTest.java
+++
b/pinot-controller/src/test/java/org/apache/pinot/controller/helix/core/retention/RetentionManagerTest.java
@@ -20,14 +20,12 @@ package org.apache.pinot.controller.helix.core.retention;
import java.io.File;
import java.io.IOException;
-import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -58,9 +56,6 @@ import
org.apache.pinot.spi.config.table.ingestion.IngestionConfig;
import org.apache.pinot.spi.data.DateTimeFieldSpec;
import org.apache.pinot.spi.data.FieldSpec;
import org.apache.pinot.spi.data.Schema;
-import org.apache.pinot.spi.filesystem.FileMetadata;
-import org.apache.pinot.spi.filesystem.LocalPinotFS;
-import org.apache.pinot.spi.filesystem.PinotFSFactory;
import org.apache.pinot.spi.metrics.PinotMetricUtils;
import org.apache.pinot.spi.stream.LongMsgOffset;
import org.apache.pinot.spi.utils.CommonConstants;
@@ -84,7 +79,6 @@ public class RetentionManagerTest {
private static final String TEST_TABLE_NAME = "testTable";
private static final String OFFLINE_TABLE_NAME =
TableNameBuilder.OFFLINE.tableNameWithType(TEST_TABLE_NAME);
private static final String REALTIME_TABLE_NAME =
TableNameBuilder.REALTIME.tableNameWithType(TEST_TABLE_NAME);
- private static final int LARGE_SEGMENT_COUNT = 400_000;
// Variables for real file test
private Path _tempDir;
@@ -672,48 +666,6 @@ public class RetentionManagerTest {
verify(pinotHelixResourceManager, times(1)).deleteSegments(anyString(),
anyList());
}
- @Test
- public void testPerformanceWithLargeNumberOfSegments()
- throws Exception {
- // Test that the optimized Set-based lookup can handle 400,000 segments
within 30 seconds
- final long maxTestExecutionTimeMs = 30_000; // 30 seconds
-
- long startTime = System.currentTimeMillis();
-
- PinotFSFactory.register("fake",
RetentionManagerTest.FakePinotFs.class.getName(), null);
-
- Set<String> segmentsToExclude = new HashSet<>();
-
- for (int i = 0; i < LARGE_SEGMENT_COUNT; i++) {
- String segmentName = "segment" + i;
- segmentsToExclude.add(segmentName);
- }
-
- LeadControllerManager leadControllerManager =
mock(LeadControllerManager.class);
- when(leadControllerManager.isLeaderForTable(anyString())).thenReturn(true);
-
- PinotHelixResourceManager pinotHelixResourceManager =
mock(PinotHelixResourceManager.class);
-
when(pinotHelixResourceManager.getDataDir()).thenReturn("fake://bucket/sc/managed/pinot/");
-
- ControllerConf conf = new ControllerConf();
- ControllerMetrics controllerMetrics = new
ControllerMetrics(PinotMetricUtils.getPinotMetricsRegistry());
- conf.setRetentionControllerFrequencyInSeconds(0);
- conf.setDeletedSegmentsRetentionInDays(0);
- conf.setUntrackedSegmentDeletionEnabled(true);
- PinotHelixResourceManager mockResourceManager =
mock(PinotHelixResourceManager.class);
- BrokerServiceHelper brokerServiceHelper =
- new BrokerServiceHelper(mockResourceManager, conf, null, null);
- RetentionManager retentionManager =
- createRetentionManager(pinotHelixResourceManager,
leadControllerManager, conf, controllerMetrics,
- brokerServiceHelper);
-
-
retentionManager.findUntrackedSegmentsToDeleteFromDeepstore("table1_REALTIME",
null, segmentsToExclude, null);
-
- long executionTime = System.currentTimeMillis() - startTime;
- assertTrue(executionTime < maxTestExecutionTimeMs,
- "Test should complete within 30 seconds but took " + executionTime +
"ms");
- }
-
private PinotHelixResourceManager setupSegmentMetadata(TableConfig
tableConfig, final long now, final int nSegments,
List<String> segmentsToBeDeleted) {
final int replicaCount = tableConfig.getReplication();
@@ -963,35 +915,4 @@ public class RetentionManagerTest {
// already asserts the correct segments via TestNG assertions
verify(pinotHelixResourceManager,
times(1)).deleteSegments(eq(OFFLINE_TABLE_NAME), anyList());
}
-
- public static class FakePinotFs extends LocalPinotFS {
-
- @Override
- public boolean exists(URI fileUri) {
- // The fake deep store is not backed by a real directory, but always has
the segments listed below
- return true;
- }
-
- @Override
- public List<FileMetadata> listFilesWithMetadata(URI fileUri, boolean
recursive)
- throws IOException {
-
- URI tableUri1 = null;
- List<FileMetadata> fileMetadataList = new ArrayList<>();
- try {
- tableUri1 = new URI("fake://bucket/sc/managed/pinot/table1/");
-
- for (int i = 0; i < LARGE_SEGMENT_COUNT; i++) {
- String segmentName = "segment" + i;
- URI segmentURIForTable =
- new URI(tableUri1.getPath() + segmentName);
- fileMetadataList.add(
- new
FileMetadata.Builder().setFilePath(segmentURIForTable.getPath()).setIsDirectory(false).build());
- }
- return fileMetadataList;
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- }
}
diff --git
a/pinot-core/src/test/java/org/apache/pinot/core/query/aggregation/function/AnyValueAggregationFunctionTest.java
b/pinot-core/src/test/java/org/apache/pinot/core/query/aggregation/function/AnyValueAggregationFunctionTest.java
index 94b2d0f6e58..ffe3201d705 100644
---
a/pinot-core/src/test/java/org/apache/pinot/core/query/aggregation/function/AnyValueAggregationFunctionTest.java
+++
b/pinot-core/src/test/java/org/apache/pinot/core/query/aggregation/function/AnyValueAggregationFunctionTest.java
@@ -206,15 +206,14 @@ public class AnyValueAggregationFunctionTest extends
AbstractAggregationFunction
validateAnyValueBehavior(result, true); // Should return non-null
(multiple non-null values available)
}
- // Performance validation test - ensures ANY_VALUE doesn't require all
values to be processed
@Test
- void testPerformanceWithLargeDataset() {
+ void testGroupByWithMultipleStringValues() {
// ANY_VALUE can return any of the values in the dataset
// This test has mixed values, so ANY_VALUE could return any of them
DataTypeScenario scenario = new DataTypeScenario(DataType.STRING);
FluentQueryTest.DeclaringTable table = scenario.getDeclaringTable(true);
- // Create a large dataset where ANY_VALUE can return any value
+ // Each instance provides distinct string values that ANY_VALUE can return.
FluentQueryTest.QueryExecuted result =
table.onFirstInstance("myField", "first_value", "value_1", "value_2",
"value_3", "value_4")
.andOnSecondInstance("myField", "value_5", "value_6", "value_7",
"value_8", "value_9")
diff --git a/pinot-perf/README.md b/pinot-perf/README.md
index a4f4efa41c4..48ac08a78d3 100644
--- a/pinot-perf/README.md
+++ b/pinot-perf/README.md
@@ -25,6 +25,25 @@ Pinot perf package contains a set of performance benchmark
for Pinot components.
Note: this package will pull `org.openjdk.jmh:jmh-core`, which is based on
`GPL 2 license`.
+# Choosing a benchmark
+
+Prefer benchmarks that exercise current Pinot implementations with
reproducible inputs and consume their results.
+Keep an explicit comparison baseline when it answers a current engineering
question. Retired implementation copies,
+duplicate workloads, and unfinished local experiments belong in their original
change history.
+
+| Workload | Entry points |
+| --- | --- |
+| Single-stage and multi-stage queries | `BenchmarkQueriesSSQE`,
`BenchmarkQueriesMSQE` |
+| Integer SUM and null handling |
`aggregation.SumIntAggregationFunctionBenchmark` |
+| Immutable string dictionary lookup and reads | `BenchmarkDictionaryLookup`,
`BenchmarkStringVarLengthDictionary` |
+| Mutable dictionary capacity and overflow | `BenchmarkDictionary`,
`BenchmarkStringDictionary` |
+| Raw forward-index reads and writes | `BenchmarkRawForwardIndexReader`,
`BenchmarkRawForwardIndexWriter` |
+| JSON index queries and scalar extraction | `BenchmarkJsonIndexDistinct`,
`BenchmarkJsonExtractScalarQuery` |
+| Vector search | `BenchmarkVectorIndex` and the vector suite described below |
+
+For query workloads against supplied segments, use the configurable
`PerfBenchmarkDriver` in `pinot-tools` with
+`pinot-tools/src/main/resources/conf/sample_perf_benchmark.yaml` as a starting
point.
+
# Steps for running benchmark
1. Build the source
diff --git a/pinot-perf/pom.xml b/pinot-perf/pom.xml
index 4009800d0c2..220306d620b 100644
--- a/pinot-perf/pom.xml
+++ b/pinot-perf/pom.xml
@@ -166,10 +166,6 @@
<mainClass>org.apache.pinot.perf.BenchmarkFixedIntArrayOffHeapIdMap</mainClass>
<name>pinot-BenchmarkFixedIntArrayOffHeapIdMap</name>
</program>
- <program>
-
<mainClass>org.apache.pinot.perf.BenchmarkOffHeapDictionaryMemory</mainClass>
- <name>pinot-BenchmarkOffHeapDictionaryMemory</name>
- </program>
<program>
<mainClass>org.apache.pinot.perf.BenchmarkOfflineIndexReader</mainClass>
<name>pinot-BenchmarkOfflineIndexReader</name>
@@ -178,10 +174,6 @@
<mainClass>org.apache.pinot.perf.BenchmarkOrDocIdIterator</mainClass>
<name>pinot-BenchmarkOrDocIdIterator</name>
</program>
- <program>
- <mainClass>org.apache.pinot.perf.BenchmarkQueryEngine</mainClass>
- <name>pinot-BenchmarkQueryEngine</name>
- </program>
<program>
<mainClass>org.apache.pinot.perf.BenchmarkRealtimeConsumptionSpeed</mainClass>
<name>pinot-BenchmarkRealtimeConsumptionSpeed</name>
@@ -198,22 +190,10 @@
<mainClass>org.apache.pinot.perf.DictionaryDumper</mainClass>
<name>pinot-DictionaryDumper</name>
</program>
- <program>
-
<mainClass>org.apache.pinot.perf.ForwardIndexWriterBenchmark</mainClass>
- <name>pinot-ForwardIndexWriterBenchmark</name>
- </program>
<program>
<mainClass>org.apache.pinot.perf.BenchmarkPinotDataBitSet</mainClass>
<name>pinot-BenchmarkPinotDataBitSet</name>
</program>
- <program>
- <mainClass>org.apache.pinot.perf.RawIndexBenchmark</mainClass>
- <name>pinot-RawIndexBenchmark</name>
- </program>
- <program>
-
<mainClass>org.apache.pinot.perf.StringDictionaryPerfTest</mainClass>
- <name>pinot-StringDictionaryPerfTest</name>
- </program>
<program>
<mainClass>org.apache.pinot.perf.aggregation.SumIntAggregationFunctionBenchmark</mainClass>
<name>pinot-SumIntAggregationFunctionBenchmark</name>
diff --git
a/pinot-perf/src/main/java/org/apache/pinot/perf/BenchmarkFixedIntArrayOffHeapIdMap.java
b/pinot-perf/src/main/java/org/apache/pinot/perf/BenchmarkFixedIntArrayOffHeapIdMap.java
index 64f9f428f01..28c73ec1b5f 100644
---
a/pinot-perf/src/main/java/org/apache/pinot/perf/BenchmarkFixedIntArrayOffHeapIdMap.java
+++
b/pinot-perf/src/main/java/org/apache/pinot/perf/BenchmarkFixedIntArrayOffHeapIdMap.java
@@ -33,7 +33,6 @@ 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.TearDown;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.ChainedOptionsBuilder;
import org.openjdk.jmh.runner.options.OptionsBuilder;
@@ -66,11 +65,6 @@ public class BenchmarkFixedIntArrayOffHeapIdMap {
}
}
- @TearDown
- public void tearDown()
- throws Exception {
- }
-
// Start with mid size, with overflow
@Benchmark
@BenchmarkMode(Mode.SampleTime)
@@ -90,59 +84,6 @@ public class BenchmarkFixedIntArrayOffHeapIdMap {
return idMap;
}
- // Start with max size, no cache
- @BenchmarkMode(Mode.SampleTime)
- @OutputTimeUnit(TimeUnit.MILLISECONDS)
- public IdMap<FixedIntArray> benchmarkOffHeapWithReSizeWithoutCache()
- throws IOException {
- PinotDataBufferMemoryManager memoryManager = new
DirectMemoryManager("perfTest");
-
- IdMap<FixedIntArray> idMap =
- new FixedIntArrayOffHeapIdMap(CARDINALITY / 10, 0, NUM_COLUMNS,
memoryManager, "perfTestWithCache");
-
- for (FixedIntArray value : _values) {
- idMap.put(value);
- }
-
- memoryManager.close();
- return idMap;
- }
-
- @BenchmarkMode(Mode.SampleTime)
- @OutputTimeUnit(TimeUnit.MILLISECONDS)
- public IdMap<FixedIntArray> benchmarkOffHeapPreSizeWithCache()
- throws IOException {
- PinotDataBufferMemoryManager memoryManager = new
DirectMemoryManager("perfTest");
-
- IdMap<FixedIntArray> idMap =
- new FixedIntArrayOffHeapIdMap(CARDINALITY, 1000, NUM_COLUMNS,
memoryManager, "perfTestWithCache");
-
- for (FixedIntArray value : _values) {
- idMap.put(value);
- }
-
- memoryManager.close();
- return idMap;
- }
-
- // Start with max size, no cache
- @BenchmarkMode(Mode.SampleTime)
- @OutputTimeUnit(TimeUnit.MILLISECONDS)
- public IdMap<FixedIntArray> benchmarkOffHeapPreSizeWithoutCache()
- throws IOException {
- PinotDataBufferMemoryManager memoryManager = new
DirectMemoryManager("perfTest");
-
- IdMap<FixedIntArray> idMap =
- new FixedIntArrayOffHeapIdMap(CARDINALITY, 0, NUM_COLUMNS,
memoryManager, "perfTestWithCache");
-
- for (FixedIntArray value : _values) {
- idMap.put(value);
- }
-
- memoryManager.close();
- return idMap;
- }
-
public static void main(String[] args)
throws Exception {
ChainedOptionsBuilder opt = new
OptionsBuilder().include(BenchmarkFixedIntArrayOffHeapIdMap.class.getSimpleName())
diff --git
a/pinot-perf/src/main/java/org/apache/pinot/perf/BenchmarkGroovyExpressionEvaluation.java
b/pinot-perf/src/main/java/org/apache/pinot/perf/BenchmarkGroovyExpressionEvaluation.java
deleted file mode 100644
index 96f2782e6a8..00000000000
---
a/pinot-perf/src/main/java/org/apache/pinot/perf/BenchmarkGroovyExpressionEvaluation.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/**
- * 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.pinot.perf;
-
-import groovy.lang.Binding;
-import groovy.lang.GroovyClassLoader;
-import groovy.lang.GroovyCodeSource;
-import groovy.lang.GroovyShell;
-import groovy.lang.Script;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
-import java.util.concurrent.TimeUnit;
-import org.apache.commons.lang3.RandomStringUtils;
-import org.openjdk.jmh.annotations.Benchmark;
-import org.openjdk.jmh.annotations.BenchmarkMode;
-import org.openjdk.jmh.annotations.Fork;
-import org.openjdk.jmh.annotations.Mode;
-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.runner.Runner;
-import org.openjdk.jmh.runner.options.ChainedOptionsBuilder;
-import org.openjdk.jmh.runner.options.OptionsBuilder;
-import org.openjdk.jmh.runner.options.TimeValue;
-
-
-@State(Scope.Benchmark)
-@Fork(value = 1, jvmArgs = {"-server", "-Xmx8G",
"-XX:MaxDirectMemorySize=16G"})
-public class BenchmarkGroovyExpressionEvaluation {
-
- private final GroovyClassLoader _groovyClassLoader = new GroovyClassLoader();
- private final Random _random = new Random();
-
- private String _concatScriptText;
- private GroovyCodeSource _concatCodeSource;
- private String _maxScriptText;
- private GroovyCodeSource _maxCodeSource;
-
- private Binding _concatBinding;
- private Script _concatScript;
- private Script _concatGCLScript;
- private Binding _maxBinding;
- private Script _maxScript;
- private Script _maxGCLScript;
-
- @Setup
- public void setup()
- throws IllegalAccessException, InstantiationException {
- _concatScriptText = "firstName + ' ' + lastName";
- _concatBinding = new Binding();
- _concatScript = new GroovyShell(_concatBinding).parse(_concatScriptText);
- _concatCodeSource = new GroovyCodeSource(_concatScriptText,
Math.abs(_concatScriptText.hashCode()) + ".groovy",
- GroovyShell.DEFAULT_CODE_BASE);
- _concatGCLScript = (Script)
_groovyClassLoader.parseClass(_concatCodeSource).newInstance();
-
- _maxScriptText = "longList.max{ it.toBigDecimal() }";
- _maxBinding = new Binding();
- _maxScript = new GroovyShell(_maxBinding).parse(_maxScriptText);
- _maxCodeSource = new GroovyCodeSource(_maxScriptText,
Math.abs(_maxScriptText.hashCode()) + ".groovy",
- GroovyShell.DEFAULT_CODE_BASE);
- _maxGCLScript = (Script)
_groovyClassLoader.parseClass(_maxCodeSource).newInstance();
- }
-
- private String getFirstName() {
- return RandomStringUtils.secure().nextAlphabetic(10);
- }
-
- private String getLastName() {
- return RandomStringUtils.secure().nextAlphabetic(20);
- }
-
- private List<String> getLongList() {
- int listLength = _random.nextInt(100) + 10;
- List<String> longList = new ArrayList<>(listLength);
- for (int i = 0; i < listLength; i++) {
- longList.add(String.valueOf(_random.nextInt()));
- }
- return longList;
- }
-
- @Benchmark
- @BenchmarkMode(Mode.AverageTime)
- @OutputTimeUnit(TimeUnit.MICROSECONDS)
- public void javaConcat() {
- getFullNameJava(getFirstName(), getLastName());
- }
-
- @Benchmark
- @BenchmarkMode(Mode.AverageTime)
- @OutputTimeUnit(TimeUnit.MICROSECONDS)
- public void groovyShellConcat() {
- getFullNameGroovyShell(getFirstName(), getLastName());
- }
-
- @Benchmark
- @BenchmarkMode(Mode.AverageTime)
- @OutputTimeUnit(TimeUnit.MICROSECONDS)
- public void groovyCodeSourceConcat() {
- getFullNameGroovyCodeSource(getFirstName(), getLastName());
- }
-
- @Benchmark
- @BenchmarkMode(Mode.AverageTime)
- @OutputTimeUnit(TimeUnit.MICROSECONDS)
- public void javaMax() {
- List<String> longList = getLongList();
- getMaxJava(longList);
- }
-
- @Benchmark
- @BenchmarkMode(Mode.AverageTime)
- @OutputTimeUnit(TimeUnit.MICROSECONDS)
- public void groovyShellMax() {
- List<String> longList = getLongList();
- getMaxGroovyShell(longList);
- }
-
- @Benchmark
- @BenchmarkMode(Mode.AverageTime)
- @OutputTimeUnit(TimeUnit.MICROSECONDS)
- public void groovyCodeSourceMax() {
- List<String> longList = getLongList();
- getMaxGroovyCodeSource(longList);
- }
-
- private String getFullNameJava(String firstName, String lastName) {
- return String.join(" ", firstName, lastName);
- }
-
- private Object getFullNameGroovyShell(String firstName, String lastName) {
- _concatBinding.setVariable("firstName", firstName);
- _concatBinding.setVariable("lastName", lastName);
- return _concatScript.run();
- }
-
- private Object getFullNameGroovyCodeSource(String firstName, String
lastName) {
- _concatBinding.setVariable("firstName", firstName);
- _concatBinding.setVariable("lastName", lastName);
- _concatGCLScript.setBinding(_concatBinding);
- return _concatGCLScript.run();
- }
-
- private int getMaxJava(List<String> longList) {
- int maxInt = Integer.MIN_VALUE;
- for (String value : longList) {
- int number = Integer.parseInt(value);
- if (number > maxInt) {
- maxInt = number;
- }
- }
- return maxInt;
- }
-
- private Object getMaxGroovyShell(List<String> longList) {
- _maxBinding.setVariable("longList", longList);
- return _maxScript.run();
- }
-
- private Object getMaxGroovyCodeSource(List<String> longList) {
- _maxBinding.setVariable("longList", longList);
- _maxGCLScript.setBinding(_maxBinding);
- return _maxGCLScript.run();
- }
-
- public static void main(String[] args)
- throws Exception {
- ChainedOptionsBuilder opt = new
OptionsBuilder().include(BenchmarkGroovyExpressionEvaluation.class.getSimpleName())
-
.warmupTime(TimeValue.seconds(10)).warmupIterations(1).measurementTime(TimeValue.seconds(30))
- .measurementIterations(3).forks(1);
- new Runner(opt.build()).run();
- }
-}
diff --git
a/pinot-perf/src/main/java/org/apache/pinot/perf/BenchmarkJsonKeyMap.java
b/pinot-perf/src/main/java/org/apache/pinot/perf/BenchmarkJsonKeyMap.java
deleted file mode 100644
index 3d85f3dd3ed..00000000000
--- a/pinot-perf/src/main/java/org/apache/pinot/perf/BenchmarkJsonKeyMap.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/**
- * 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.pinot.perf;
-
-import java.util.Comparator;
-import java.util.Map;
-import java.util.Random;
-import java.util.TreeMap;
-import java.util.concurrent.TimeUnit;
-import org.apache.pinot.segment.spi.index.creator.JsonIndexCreator;
-import org.openjdk.jmh.annotations.Benchmark;
-import org.openjdk.jmh.annotations.BenchmarkMode;
-import org.openjdk.jmh.annotations.Fork;
-import org.openjdk.jmh.annotations.Measurement;
-import org.openjdk.jmh.annotations.Mode;
-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.options.ChainedOptionsBuilder;
-import org.openjdk.jmh.runner.options.OptionsBuilder;
-import org.roaringbitmap.Container;
-import org.roaringbitmap.RoaringBitmap;
-import org.roaringbitmap.RoaringBitmapWriter;
-
-
-// simple test checking if delaying key concatenation and checking map with
stringbuilder is any faster than always
-// concatenating
-@BenchmarkMode(Mode.AverageTime)
-@OutputTimeUnit(TimeUnit.MILLISECONDS)
-@Fork(0)
-@Warmup(iterations = 3, time = 1)
-@Measurement(iterations = 3, time = 1)
-@State(Scope.Benchmark)
-public class BenchmarkJsonKeyMap {
-
- public static void main(String[] args)
- throws Exception {
- ChainedOptionsBuilder opt = new
OptionsBuilder().include(BenchmarkJsonKeyMap.class.getSimpleName());
- new Runner(opt.build()).run();
- }
-
- private final Map<String, RoaringBitmapWriter<RoaringBitmap>>
_csPostingListMap = new TreeMap<>(
- (Comparator<CharSequence>) (o1, o2) -> CharSequence.compare(o1, o2));
-
- private final TreeMap<String, RoaringBitmapWriter<RoaringBitmap>>
_strPostingListMap = new TreeMap<>();
- private int _nextFlattenedDocId;
- final RoaringBitmapWriter.Wizard<Container, RoaringBitmap>
_bitmapWriterWizard = RoaringBitmapWriter.writer();
- final String[] _keys = new String[1000];
- final String[] _values = new String[100];
- final int _iterations = 1000_000;
-
- @Benchmark
- public Map withConcat() {
- final Random rnd = new Random(0L);
- for (int i = 0; i < _iterations; i++) {
- String key = _keys[rnd.nextInt(_keys.length)];
- String value = _values[rnd.nextInt(_values.length)];
- addToStrPostingList(key);
- String keyAndValue = key + JsonIndexCreator.KEY_VALUE_SEPARATOR + value;
- addToStrPostingList(keyAndValue);
- _nextFlattenedDocId++;
- }
- _strPostingListMap.clear();
- return _strPostingListMap;
- }
-
- @Benchmark
- public Map withConcatOnBuffer() {
- final Random rnd = new Random(0L);
- StringBuilder buffer = new StringBuilder();
-
- for (int i = 0; i < _iterations; i++) {
- String key = _keys[rnd.nextInt(_keys.length)];
- String value = _values[rnd.nextInt(_values.length)];
- addToStrPostingList(key);
- buffer.setLength(0);
- String keyAndValue =
buffer.append(key).append(JsonIndexCreator.KEY_VALUE_SEPARATOR).append(value).toString();
- addToStrPostingList(keyAndValue);
- _nextFlattenedDocId++;
- }
- _csPostingListMap.clear();
- return _csPostingListMap;
- }
-
- @Benchmark
- public Map withBuffer() {
- final Random rnd = new Random(0L);
- StringBuilder buffer = new StringBuilder();
-
- for (int i = 0; i < _iterations; i++) {
- String key = _keys[rnd.nextInt(_keys.length)];
- String value = _values[rnd.nextInt(_values.length)];
- addToCsPostingList(key);
- buffer.setLength(0);
-
buffer.append(key).append(JsonIndexCreator.KEY_VALUE_SEPARATOR).append(value);
- addToCsPostingList(buffer);
- _nextFlattenedDocId++;
- }
- _csPostingListMap.clear();
- return _csPostingListMap;
- }
-
- @Setup
- public void setUp()
- throws Exception {
- final Random rnd = new Random(0L);
- StringBuilder sb = new StringBuilder(30);
-
- for (int i = 0; i < _keys.length; i++) {
- int len = rnd.nextInt(20) + 10;
-
- sb.setLength(0);
- for (int j = 0; j < len; j++) {
- sb.append((char) (rnd.nextInt('Z' - 'A') + 'A'));
- }
-
- _keys[i] = sb.toString();
- }
-
- for (int i = 0; i < _values.length; i++) {
- int len = rnd.nextInt(5) + 10;
-
- sb.setLength(0);
- for (int j = 0; j < len; j++) {
- sb.append((char) (rnd.nextInt('Z' - 'A') + 'A'));
- }
-
- _values[i] = sb.toString();
- }
-
- _strPostingListMap.clear();
- _csPostingListMap.clear();
- _nextFlattenedDocId = 0;
- }
-
- void addToStrPostingList(String value) {
- RoaringBitmapWriter<RoaringBitmap> bitmapWriter =
_strPostingListMap.get(value);
- if (bitmapWriter == null) {
- bitmapWriter = _bitmapWriterWizard.get();
- _strPostingListMap.put(value, bitmapWriter);
- }
- bitmapWriter.add(_nextFlattenedDocId);
- }
-
- void addToCsPostingList(CharSequence value) {
- RoaringBitmapWriter<RoaringBitmap> bitmapWriter =
_csPostingListMap.get(value);
- if (bitmapWriter == null) {
- bitmapWriter = _bitmapWriterWizard.get();
- _csPostingListMap.put(value.toString(), bitmapWriter);
- }
- bitmapWriter.add(_nextFlattenedDocId);
- }
-}
diff --git
a/pinot-perf/src/main/java/org/apache/pinot/perf/BenchmarkOffHeapDictionaryMemory.java
b/pinot-perf/src/main/java/org/apache/pinot/perf/BenchmarkOffHeapDictionaryMemory.java
deleted file mode 100644
index 4cfbd23aaed..00000000000
---
a/pinot-perf/src/main/java/org/apache/pinot/perf/BenchmarkOffHeapDictionaryMemory.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/**
- * 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.pinot.perf;
-
-import org.apache.pinot.segment.local.io.writer.impl.DirectMemoryManager;
-import
org.apache.pinot.segment.local.realtime.impl.dictionary.BaseOffHeapMutableDictionary;
-import
org.apache.pinot.segment.local.realtime.impl.dictionary.LongOffHeapMutableDictionary;
-import org.apache.pinot.segment.spi.memory.PinotDataBufferMemoryManager;
-import org.openjdk.jmh.annotations.Setup;
-import org.openjdk.jmh.annotations.TearDown;
-
-
-// Test to get memory statistics for off-heap dictionary
-public class BenchmarkOffHeapDictionaryMemory {
- private Long[] _colValues;
- private final int _nRuns = 10;
- private final int _nDivs = 10;
- final int _cardinality = 1_000_000;
- final int _nRows = 2_500_000;
- private final long[] _totalMem = new long[_nDivs + 1];
- private final int[] _nBufs = new int[_nDivs + 1];
- private final int[] _overflowSize = new int[_nDivs + 1];
- private PinotDataBufferMemoryManager _memoryManager;
-
- @Setup
- public void setUp() {
- _memoryManager = new
DirectMemoryManager(BenchmarkOffHeapDictionaryMemory.class.getName());
- }
-
- @TearDown
- public void tearDown()
- throws Exception {
- _memoryManager.close();
- }
-
- private void setupValues(final int cardinality, final int nRows) {
- // Create a list of values to insert into the hash map
- long[] uniqueColValues = new long[cardinality];
- for (int i = 0; i < uniqueColValues.length; i++) {
- uniqueColValues[i] = (long) (Math.random() * Long.MAX_VALUE);
- }
- _colValues = new Long[nRows];
- for (int i = 0; i < _colValues.length; i++) {
- _colValues[i] = uniqueColValues[(int) (Math.random() * cardinality)];
- }
- }
-
- private BaseOffHeapMutableDictionary testMem(final int initialCardinality,
final int maxOverflowSize) {
- LongOffHeapMutableDictionary dictionary =
- new LongOffHeapMutableDictionary(initialCardinality, maxOverflowSize,
_memoryManager, "longColumn");
- for (Long colValue : _colValues) {
- dictionary.index(colValue);
- }
- return dictionary;
- }
-
- private void addStats(BaseOffHeapMutableDictionary dictionary, int div) {
- _totalMem[div] += dictionary.getTotalOffHeapMemUsed();
- _overflowSize[div] += dictionary.getNumberOfOveflowValues();
- _nBufs[div] += dictionary.getNumberOfHeapBuffersUsed();
-
- /*
- System.out.println("Cardinality:" + actualCardinality +
",initialCardinality:" + initialCardinality +
- ",OffHeapMem:" + dictionary.getTotalOffHeapMemUsed()/1024/1024 + "MB" +
- ",NumBuffers=" + dictionary.getNumberOfHeapBuffersUsed() +
- ",maxOverflowSize=" + maxOverflowSize +
- ",actualOverflowSize=" + dictionary.getNumberOfOveflowValues() +
- ",rowFills=" + Arrays.toString(dictionary.getRowFillCount())
- );
- */
- }
-
- private void printStats() {
- for (int div = 1; div < _nDivs; div++) {
- _totalMem[div] /= _nRuns;
- _nBufs[div] /= _nRuns;
- _overflowSize[div] /= _nRuns;
- System.out.println(
- "Div=" + div + ",TotalMem:" + _totalMem[div] / 1024 / 1024 +
"MB,_nBufs=" + _nBufs[div] + ",numOverflows="
- + _overflowSize[div]);
- }
- }
-
- private void clearStats() {
- for (int div = 1; div < _nDivs; div++) {
- _totalMem[div] = 0;
- _nBufs[div] = 0;
- _overflowSize[div] = 0;
- }
- }
-
- private void testMem(final int maxOverflowSize)
- throws Exception {
- clearStats();
-
- for (int div = 1; div <= _nDivs; div++) {
- setupValues(_cardinality, _nRows);
- for (int i = 0; i < _nRuns; i++) {
- int initialCardinality = _cardinality / div;
- try (BaseOffHeapMutableDictionary dictionary =
testMem(initialCardinality, maxOverflowSize)) {
- addStats(dictionary, div);
- }
- }
- }
-
- printStats();
- }
-
- public static void main(String[] args)
- throws Exception {
- BenchmarkOffHeapDictionaryMemory benchmark = new
BenchmarkOffHeapDictionaryMemory();
- System.out.println("Results with overflow:");
- benchmark.testMem(1000);
- System.out.println("Results without overflow:");
- benchmark.testMem(0);
- }
-}
diff --git
a/pinot-perf/src/main/java/org/apache/pinot/perf/BenchmarkQueryEngine.java
b/pinot-perf/src/main/java/org/apache/pinot/perf/BenchmarkQueryEngine.java
deleted file mode 100644
index c9b1f3f0877..00000000000
--- a/pinot-perf/src/main/java/org/apache/pinot/perf/BenchmarkQueryEngine.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/**
- * 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.pinot.perf;
-
-import com.google.common.util.concurrent.Uninterruptibles;
-import java.io.File;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-import org.apache.helix.zookeeper.datamodel.ZNRecord;
-import org.apache.helix.zookeeper.datamodel.serializer.ZNRecordSerializer;
-import org.apache.helix.zookeeper.impl.client.ZkClient;
-import org.apache.pinot.segment.spi.index.metadata.SegmentMetadataImpl;
-import org.apache.pinot.tools.perf.PerfBenchmarkDriver;
-import org.apache.pinot.tools.perf.PerfBenchmarkDriverConf;
-import org.openjdk.jmh.annotations.Benchmark;
-import org.openjdk.jmh.annotations.BenchmarkMode;
-import org.openjdk.jmh.annotations.Fork;
-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.profile.StackProfiler;
-import org.openjdk.jmh.runner.Runner;
-import org.openjdk.jmh.runner.options.ChainedOptionsBuilder;
-import org.openjdk.jmh.runner.options.OptionsBuilder;
-import org.openjdk.jmh.runner.options.TimeValue;
-
-
-@State(Scope.Benchmark)
-@Fork(value = 1, jvmArgs = {"-server", "-Xmx8G",
"-XX:MaxDirectMemorySize=16G"})
-public class BenchmarkQueryEngine {
- /// List of query patterns used in the benchmark
- private static final String[] QUERY_PATTERNS = new String[]{"SELECT count(*)
from myTable"};
-
- /// List of query patterns indices to run
- @Param({"0"})
- public int _queryPattern;
-
- /// The table name which contains the offline data, for example
"myTable_OFFLINE."
- private static final String TABLE_NAME = "myTable_OFFLINE";
-
- /// The directory that contains the unpacked data, for example "/data"
- ///
- /// In that directory, there should be a "myTable_OFFLINE" directory which
contains unpacked segments, so the
- /// directory for "/data" should look like
"/data/myTable_OFFLINE/mySegment_0/metadata.properties"
- private static final String DATA_DIRECTORY = "/home/someuser/data";
-
- /// Whether or not to enable profiling information
- private static final boolean ENABLE_PROFILING = false;
-
- PerfBenchmarkDriver _perfBenchmarkDriver;
- boolean _ranOnce = false;
-
- @Setup
- public void startPinot()
- throws Exception {
- System.out.println("Using table name " + TABLE_NAME);
- System.out.println("Using data directory " + DATA_DIRECTORY);
- System.out.println("Starting pinot");
-
- PerfBenchmarkDriverConf conf = new PerfBenchmarkDriverConf();
- conf.setStartBroker(true);
- conf.setStartController(true);
- conf.setStartServer(true);
- conf.setStartZookeeper(true);
- conf.setRunQueries(false);
- conf.setServerInstanceSegmentTarDir(null);
- conf.setServerInstanceDataDir(DATA_DIRECTORY);
- conf.setConfigureResources(false);
- _perfBenchmarkDriver = new PerfBenchmarkDriver(conf);
- _perfBenchmarkDriver.run();
-
- File[] segments = new File(DATA_DIRECTORY, TABLE_NAME).listFiles();
- for (File segmentDir : segments) {
- SegmentMetadataImpl segmentMetadata = new
SegmentMetadataImpl(segmentDir);
- _perfBenchmarkDriver.configureTable(TABLE_NAME);
- System.out.println("Adding segment " + segmentDir.getAbsolutePath());
- _perfBenchmarkDriver.addSegment(TABLE_NAME, segmentMetadata);
- }
-
- ZkClient client = new ZkClient("localhost:2191", 10000, 10000, new
ZNRecordSerializer());
-
- ZNRecord record = client.readData("/PinotPerfTestCluster/EXTERNALVIEW/" +
TABLE_NAME);
- while (true) {
- System.out.println("record = " + record);
- Uninterruptibles.sleepUninterruptibly(10, TimeUnit.SECONDS);
-
- int onlineSegmentCount = 0;
- for (Map<String, String> instancesAndStates :
record.getMapFields().values()) {
- for (String state : instancesAndStates.values()) {
- if (state.equals("ONLINE")) {
- onlineSegmentCount++;
- break;
- }
- }
- }
-
- System.out.println(onlineSegmentCount + " segments online out of " +
segments.length);
-
- if (onlineSegmentCount == segments.length) {
- break;
- }
-
- record = client.readData("/PinotPerfTestCluster/EXTERNALVIEW/" +
TABLE_NAME);
- }
-
- _ranOnce = false;
-
-
System.out.println(_perfBenchmarkDriver.postQuery(QUERY_PATTERNS[_queryPattern]).toString());
- }
-
- @Benchmark
- @BenchmarkMode({Mode.SampleTime})
- @OutputTimeUnit(TimeUnit.MILLISECONDS)
- public int sendQueryToPinot()
- throws Exception {
- return
_perfBenchmarkDriver.postQuery(QUERY_PATTERNS[_queryPattern]).get("totalDocs").asInt();
- }
-
- public static void main(String[] args)
- throws Exception {
- ChainedOptionsBuilder opt =
- new
OptionsBuilder().include(BenchmarkQueryEngine.class.getSimpleName()).warmupTime(TimeValue.seconds(30))
-
.warmupIterations(4).measurementTime(TimeValue.seconds(30)).measurementIterations(20);
-
- if (ENABLE_PROFILING) {
- opt = opt.addProfiler(StackProfiler.class,
-
"excludePackages=true;excludePackageNames=sun.,java.net.,io.netty.,org.apache.zookeeper.,org.eclipse.jetty"
- + ".;lines=5;period=1;top=20");
- }
-
- new Runner(opt.build()).run();
- }
-}
diff --git
a/pinot-perf/src/main/java/org/apache/pinot/perf/BenchmarkRoaringBitmapCreation.java
b/pinot-perf/src/main/java/org/apache/pinot/perf/BenchmarkRoaringBitmapCreation.java
deleted file mode 100644
index 7f64491377e..00000000000
---
a/pinot-perf/src/main/java/org/apache/pinot/perf/BenchmarkRoaringBitmapCreation.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/**
- * 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.pinot.perf;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.ref.SoftReference;
-import java.nio.ByteOrder;
-import java.util.Random;
-import java.util.concurrent.TimeUnit;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.lang3.tuple.Pair;
-import
org.apache.pinot.segment.local.segment.creator.impl.inv.BitmapInvertedIndexWriter;
-import org.apache.pinot.segment.spi.memory.PinotByteBuffer;
-import org.apache.pinot.segment.spi.memory.PinotDataBuffer;
-import org.openjdk.jmh.annotations.Benchmark;
-import org.openjdk.jmh.annotations.BenchmarkMode;
-import org.openjdk.jmh.annotations.Fork;
-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.TearDown;
-import org.openjdk.jmh.profile.GCProfiler;
-import org.openjdk.jmh.runner.Runner;
-import org.openjdk.jmh.runner.options.ChainedOptionsBuilder;
-import org.openjdk.jmh.runner.options.OptionsBuilder;
-import org.openjdk.jmh.runner.options.TimeValue;
-import org.roaringbitmap.RoaringBitmap;
-import org.roaringbitmap.buffer.ImmutableRoaringBitmap;
-
-
-/// Benchmark created to test the impact of removing the SoftReference array
cache for ImmutableRoaringBitmap
-@State(Scope.Benchmark)
-@Fork(1)
-public class BenchmarkRoaringBitmapCreation {
-
- private static final int NUM_DOCS = 1_000_000;
- private static final int CARDINALITY = 100_000;
- private static final File TEMP_DIR =
- new File(FileUtils.getTempDirectory(), "bitmap_creation_benchmark_" +
System.currentTimeMillis());
-
- @Param({"100", "10000", "99999"}) // higher this is, lesser the cache access
- public int _dictIdsToRead;
-
- private int _numBitmaps;
- private BitmapInvertedIndexWriter _bitmapInvertedIndexWriter;
- private SoftReference<SoftReference<ImmutableRoaringBitmap>[]>
_bitmapsArrayReference = null;
- private SoftReference<SoftReference<Pair<Integer, Integer>>[]>
_offsetLengthPairsArrayReference = null;
- private PinotDataBuffer _offsetLengthBuffer;
- private PinotDataBuffer _bitmapBuffer;
- private int _firstOffset;
-
- @Setup
- public void setup()
- throws IllegalAccessException, InstantiationException, IOException {
- _numBitmaps = CARDINALITY;
-
- File bufferDir = new File(TEMP_DIR, "cardinality_" + CARDINALITY);
- FileUtils.forceMkdir(bufferDir);
- File bufferFile = new File(bufferDir, "buffer");
- _bitmapInvertedIndexWriter = new BitmapInvertedIndexWriter(bufferFile,
_numBitmaps);
- Random random = new Random();
- // Insert between 10-1000 values per bitmap
- for (int i = 0; i < _numBitmaps; i++) {
- int size = 10 + random.nextInt(990);
- int[] data = new int[size];
- for (int j = 0; j < size; j++) {
- //docIds will repeat across bitmaps, but doesn't matter for purpose of
this benchmark
- data[j] = random.nextInt(NUM_DOCS);
- }
- RoaringBitmap bitmap = RoaringBitmap.bitmapOf(data);
- _bitmapInvertedIndexWriter.add(bitmap);
- }
-
- PinotDataBuffer dataBuffer =
PinotByteBuffer.mapReadOnlyBigEndianFile(bufferFile);
- long offsetBufferEndOffset = (long) (_numBitmaps + 1) * Integer.BYTES;
- _offsetLengthBuffer = dataBuffer.view(0, offsetBufferEndOffset,
ByteOrder.BIG_ENDIAN);
- _bitmapBuffer = dataBuffer.view(offsetBufferEndOffset, dataBuffer.size());
- _firstOffset = _offsetLengthBuffer.getInt(0);
- }
-
- @TearDown
- public void teardown()
- throws IOException {
- _bitmapInvertedIndexWriter.close();
- FileUtils.deleteQuietly(TEMP_DIR);
- }
-
- @Benchmark
- @BenchmarkMode(Mode.AverageTime)
- @OutputTimeUnit(TimeUnit.MICROSECONDS)
- public boolean cacheReferences() {
- Random random = new Random();
- int dictId = random.nextInt(_dictIdsToRead);
- ImmutableRoaringBitmap roaringBitmapFromCache =
getRoaringBitmapFromCache(dictId);
- return roaringBitmapFromCache.isEmpty();
- }
-
- @Benchmark
- @BenchmarkMode(Mode.AverageTime)
- @OutputTimeUnit(TimeUnit.MICROSECONDS)
- public boolean alwaysBuild() {
- Random random = new Random();
- int dictId = random.nextInt(_dictIdsToRead);
- ImmutableRoaringBitmap immutableRoaringBitmap = buildRoaringBitmap(dictId);
- return immutableRoaringBitmap.isEmpty();
- }
-
- @Benchmark
- @BenchmarkMode(Mode.AverageTime)
- @OutputTimeUnit(TimeUnit.MICROSECONDS)
- public boolean alwaysBuildCachedOffsetAndLength() {
- Random random = new Random();
- int dictId = random.nextInt(_dictIdsToRead);
- ImmutableRoaringBitmap immutableRoaringBitmap =
buildRoaringBitmapUsingOffsetPairFromCache(dictId);
- return immutableRoaringBitmap.isEmpty();
- }
-
- /// Code as of before this commit, using an array of SoftReference for the
ImmutableRoaringBitmap
- private ImmutableRoaringBitmap getRoaringBitmapFromCache(int dictId) {
- SoftReference<ImmutableRoaringBitmap>[] bitmapArrayReference =
- (_bitmapsArrayReference != null) ? _bitmapsArrayReference.get() : null;
- if (bitmapArrayReference != null) {
- SoftReference<ImmutableRoaringBitmap> bitmapReference =
bitmapArrayReference[dictId];
- ImmutableRoaringBitmap bitmap = (bitmapReference != null) ?
bitmapReference.get() : null;
- if (bitmap != null) {
- return bitmap;
- }
- } else {
- bitmapArrayReference = new SoftReference[_numBitmaps];
- _bitmapsArrayReference = new SoftReference<>(bitmapArrayReference);
- }
- synchronized (this) {
- SoftReference<ImmutableRoaringBitmap> bitmapReference =
bitmapArrayReference[dictId];
- ImmutableRoaringBitmap bitmap = (bitmapReference != null) ?
bitmapReference.get() : null;
- if (bitmap == null) {
- bitmap = buildRoaringBitmap(dictId);
- bitmapArrayReference[dictId] = new SoftReference<>(bitmap);
- }
- return bitmap;
- }
- }
-
- private ImmutableRoaringBitmap buildRoaringBitmap(int dictId) {
- Pair<Integer, Integer> offsetLengthPair = buildOffsetLengthPair(dictId);
- return buildRoaringBitmap(offsetLengthPair);
- }
-
- private Pair<Integer, Integer> buildOffsetLengthPair(int dictId) {
- int offset = _offsetLengthBuffer.getInt(dictId * Integer.BYTES);
- int length = _offsetLengthBuffer.getInt((dictId + 1) * Integer.BYTES) -
offset;
- return Pair.of(offset, length);
- }
-
- private ImmutableRoaringBitmap buildRoaringBitmap(Pair<Integer, Integer>
offsetLengthPair) {
- return new ImmutableRoaringBitmap(
- _bitmapBuffer.toDirectByteBuffer(offsetLengthPair.getLeft() -
_firstOffset, offsetLengthPair.getRight()));
- }
-
- private ImmutableRoaringBitmap
buildRoaringBitmapUsingOffsetPairFromCache(int dictId) {
- return buildRoaringBitmap(getOffsetLengthPairFromCache(dictId));
- }
-
- private Pair<Integer, Integer> getOffsetLengthPairFromCache(int dictId) {
-
- SoftReference<Pair<Integer, Integer>>[] offsetLengthPairArrayReference =
- (_offsetLengthPairsArrayReference != null) ?
_offsetLengthPairsArrayReference.get() : null;
- if (offsetLengthPairArrayReference != null) {
- SoftReference<Pair<Integer, Integer>> offsetLengthPairReference =
offsetLengthPairArrayReference[dictId];
- Pair<Integer, Integer> offsetLengthPair =
- (offsetLengthPairReference != null) ?
offsetLengthPairReference.get() : null;
- if (offsetLengthPair != null) {
- return offsetLengthPair;
- }
- } else {
- offsetLengthPairArrayReference = new SoftReference[_numBitmaps];
- _offsetLengthPairsArrayReference = new
SoftReference<>(offsetLengthPairArrayReference);
- }
- synchronized (this) {
- SoftReference<Pair<Integer, Integer>> offsetLengthPairReference =
offsetLengthPairArrayReference[dictId];
- Pair<Integer, Integer> offsetLengthPair =
- (offsetLengthPairReference != null) ?
offsetLengthPairReference.get() : null;
- if (offsetLengthPair == null) {
- offsetLengthPair = buildOffsetLengthPair(dictId);
- offsetLengthPairArrayReference[dictId] = new
SoftReference<>(offsetLengthPair);
- }
- return offsetLengthPair;
- }
- }
-
- public static void main(String[] args)
- throws Exception {
- ChainedOptionsBuilder opt = new
OptionsBuilder().include(BenchmarkRoaringBitmapCreation.class.getSimpleName())
-
.warmupTime(TimeValue.seconds(10)).warmupIterations(1).measurementTime(TimeValue.seconds(60))
- .measurementIterations(1).forks(1).addProfiler(GCProfiler.class);
- new Runner(opt.build()).run();
- }
-}
diff --git
a/pinot-perf/src/main/java/org/apache/pinot/perf/BenchmarkRoaringBitmapMapping.java
b/pinot-perf/src/main/java/org/apache/pinot/perf/BenchmarkRoaringBitmapMapping.java
deleted file mode 100644
index 5f4a2d731da..00000000000
---
a/pinot-perf/src/main/java/org/apache/pinot/perf/BenchmarkRoaringBitmapMapping.java
+++ /dev/null
@@ -1,328 +0,0 @@
-/**
- * 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.pinot.perf;
-
-import com.google.common.io.Resources;
-import java.io.File;
-import java.io.IOException;
-import java.net.URL;
-import java.util.Arrays;
-import java.util.concurrent.TimeUnit;
-import org.apache.pinot.segment.spi.memory.PinotByteBuffer;
-import org.apache.pinot.segment.spi.memory.PinotDataBuffer;
-import org.openjdk.jmh.annotations.Benchmark;
-import org.openjdk.jmh.annotations.BenchmarkMode;
-import org.openjdk.jmh.annotations.Fork;
-import org.openjdk.jmh.annotations.Measurement;
-import org.openjdk.jmh.annotations.Mode;
-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.TearDown;
-import org.openjdk.jmh.annotations.Warmup;
-import org.openjdk.jmh.profile.GCProfiler;
-import org.openjdk.jmh.runner.Runner;
-import org.openjdk.jmh.runner.options.ChainedOptionsBuilder;
-import org.openjdk.jmh.runner.options.OptionsBuilder;
-import org.roaringbitmap.IntConsumer;
-import org.roaringbitmap.RoaringBitmap;
-import org.roaringbitmap.RoaringBitmapWriter;
-import org.roaringbitmap.buffer.ImmutableRoaringBitmap;
-import org.roaringbitmap.buffer.MutableRoaringBitmap;
-
-
-/// Test optimal settings for transforming bitmap via mapping.
-/// Depends on following files:
-/// - docMapping.buffer (json flattened doc ids -> doc ids mapping)
-/// - test.bitmap (serialized mutable roaring bitmap)
-/// that have to be generated (copied from pinot instance) before benchmark
run.
-@BenchmarkMode(Mode.AverageTime)
-@OutputTimeUnit(TimeUnit.MILLISECONDS)
-@Fork(1)
-@Warmup(iterations = 3, time = 1)
-@Measurement(iterations = 5, time = 1)
-@State(Scope.Benchmark)
-public class BenchmarkRoaringBitmapMapping {
-
- public static void main(String[] args)
- throws Exception {
- ChainedOptionsBuilder opt = new OptionsBuilder()
- .shouldDoGC(true)
- .addProfiler(GCProfiler.class)
- //.addProfiler(JavaFlightRecorderProfiler.class)
- .include(BenchmarkRoaringBitmapMapping.class.getSimpleName());
- new Runner(opt.build()).run();
- }
-
- PinotDataBuffer _bitmapBuffer;
- ImmutableRoaringBitmap _docIds;
- PinotDataBuffer _docIdMapping;
-
- private int getDocId(int flattenedDocId) {
- return _docIdMapping.getInt((long) flattenedDocId << 2);
- }
-
- @Setup
- public void setUp()
- throws IOException {
- String fileName = "test.bitmap";
-
- _bitmapBuffer = getPinotDataBuffer(fileName);
- _docIds = new ImmutableRoaringBitmap(
- _bitmapBuffer.toDirectByteBuffer(0, (int) _bitmapBuffer.size()));
- _docIdMapping = getPinotDataBuffer("docMapping.buffer");
- }
-
- private static PinotDataBuffer getPinotDataBuffer(String fileName)
- throws IOException {
- URL bitmapUrl = Resources.getResource(fileName);
- File file = new File(bitmapUrl.getFile());
- if (!file.exists()) {
- throw new RuntimeException("File test.bitmap doesn't exist!");
- }
- return PinotByteBuffer.mapReadOnlyBigEndianFile(file);
- }
-
- @TearDown
- public void tearDown()
- throws IOException {
- if (_bitmapBuffer != null) {
- try {
- _bitmapBuffer.close();
- } catch (Exception e) {
- // Ignore
- }
- }
-
- if (_docIdMapping != null) {
- try {
- _docIdMapping.close();
- } catch (Exception e) {
- // Ignore
- }
- }
- }
-
- @Benchmark
- public MutableRoaringBitmap mapWithDefaults() {
- RoaringBitmapWriter<MutableRoaringBitmap> writer =
RoaringBitmapWriter.bufferWriter()
- .get();
- return map(writer);
- }
-
- @Benchmark
- public MutableRoaringBitmap mapWithInitCapacity() {
- RoaringBitmapWriter<MutableRoaringBitmap> writer =
RoaringBitmapWriter.bufferWriter()
- .initialCapacity((_docIds.getCardinality() >>> 16) + 1)
- .get();
- return map(writer);
- }
-
- @Benchmark
- public MutableRoaringBitmap mapWithMaxInitCapacity() {
- RoaringBitmapWriter<MutableRoaringBitmap> writer =
RoaringBitmapWriter.bufferWriter()
- .initialCapacity(65534)
- .get();
- return map(writer);
- }
-
- @Benchmark
- public MutableRoaringBitmap mapWithRunCompressDisabled() {
- RoaringBitmapWriter<MutableRoaringBitmap> writer =
RoaringBitmapWriter.bufferWriter()
- .runCompress(false)
- .get();
- return map(writer);
- }
-
- @Benchmark
- public MutableRoaringBitmap mapWithPartialRadixSort() {
- RoaringBitmapWriter<MutableRoaringBitmap> writer =
RoaringBitmapWriter.bufferWriter()
- .doPartialRadixSort()
- .get();
-
- int[] buffer = new int[1024];
-
- IntConsumer consumer = new IntConsumer() {
- int _idx = 0;
-
- @Override
- public void accept(int value) {
- buffer[_idx++] = getDocId(value);
- if (_idx == 1024) {
- writer.addMany(buffer);
- _idx = 0;
- }
- }
- };
- _docIds.forEach(consumer);
-
- // ignore small leftover
-
- return writer.get();
- }
-
- @Benchmark
- public MutableRoaringBitmap mapWithPartialRadixSortPrealloc() {
- RoaringBitmapWriter<MutableRoaringBitmap> writer =
RoaringBitmapWriter.bufferWriter()
- .get();
-
- final int[] buffer = new int[10 * 1024];
- final int bufLen = buffer.length;
-
- IntConsumer consumer = new IntConsumer() {
- int _idx = 0;
- final int[] _low = new int[257];
- final int[] _high = new int[257];
- int[] _copy = new int[buffer.length];
-
- @Override
- public void accept(int value) {
- buffer[_idx++] = getDocId(value);
- if (_idx == bufLen) {
- partialRadixSort(buffer, _low, _high, _copy);
- writer.addMany(buffer);
- _idx = 0;
- }
- }
- };
- _docIds.forEach(consumer);
-
- // ignore small leftover
-
- return writer.get();
- }
-
- @Benchmark
- public MutableRoaringBitmap mapWithOptimisedForRunsAppender() {
- RoaringBitmapWriter<MutableRoaringBitmap> writer =
RoaringBitmapWriter.bufferWriter()
- .optimiseForRuns()
- .get();
- return map(writer);
- }
-
- @Benchmark
- public MutableRoaringBitmap mapWithOptimisedForArraysAppender() {
- RoaringBitmapWriter<MutableRoaringBitmap> writer =
RoaringBitmapWriter.bufferWriter()
- .optimiseForArrays()
- .get();
- return map(writer);
- }
-
- @Benchmark
- public MutableRoaringBitmap mapSimple() {
- MutableRoaringBitmap target = new MutableRoaringBitmap();
- IntConsumer mapper = new IntConsumer() {
- int _previous = -1;
-
- @Override
- public void accept(int flattenedDocId) {
- int docId = getDocId(flattenedDocId);
- if (_previous != docId) {
- target.add(docId);
- _previous = docId;
- }
- }
- };
-
- _docIds.forEach(mapper);
- return target;
- }
-
- @Benchmark
- public RoaringBitmap mapRoaringSimple() {
- RoaringBitmap target = new RoaringBitmap();
- _docIds.forEach((IntConsumer) flattenedDocId ->
target.add(getDocId(flattenedDocId)));
- return target;
- }
-
- @Benchmark
- public RoaringBitmap mapRoaringAppender() {
- RoaringBitmapWriter<RoaringBitmap> writer = RoaringBitmapWriter.writer()
- .get();
- _docIds.forEach((IntConsumer) flattenedDocId ->
writer.add(getDocId(flattenedDocId)));
- RoaringBitmap result = writer.get();
- return result;
- }
-
- @Benchmark
- public RoaringBitmap mapRoaringAppenderConstantMem() {
- RoaringBitmapWriter<RoaringBitmap> writer = RoaringBitmapWriter.writer()
- .constantMemory()
- .get();
- _docIds.forEach((IntConsumer) flattenedDocId ->
writer.add(getDocId(flattenedDocId)));
- return writer.get();
- }
-
- @Benchmark
- public long iterateMapping() {
- long result = 0;
- for (int i = 0, n = (int) _docIdMapping.size() / 8; i < n; i++) {
- result += _docIdMapping.getLong(i);
- }
- return result;
- }
-
- private MutableRoaringBitmap map(RoaringBitmapWriter<MutableRoaringBitmap>
writer) {
- _docIds.forEach((IntConsumer) flattenedDocId ->
writer.add(getDocId(flattenedDocId)));
- return writer.get();
- }
-
- // same as partialRadixSort in RB, but with arrays pre-allocated
- private static void partialRadixSort(int[] data, int[] low, int[] high,
int[] copy) {
- Arrays.fill(low, 0);
- Arrays.fill(high, 0);
- for (int value : data) {
- ++low[((value >>> 16) & 0xFF) + 1];
- ++high[(value >>> 24) + 1];
- }
- // avoid passes over the data if it's not required
- boolean sortLow = low[1] < data.length;
- boolean sortHigh = high[1] < data.length;
- if (!sortLow && !sortHigh) {
- return;
- }
- Arrays.fill(copy, 0);
- if (sortLow) {
- for (int i = 1; i < low.length; i++) {
- low[i] += low[i - 1];
- }
- for (int value : data) {
- copy[low[(value >>> 16) & 0xFF]++] = value;
- }
- }
- if (sortHigh) {
- for (int i = 1; i < high.length; i++) {
- high[i] += high[i - 1];
- }
- if (sortLow) {
- for (int value : copy) {
- data[high[value >>> 24]++] = value;
- }
- } else {
- for (int value : data) {
- copy[high[value >>> 24]++] = value;
- }
- System.arraycopy(copy, 0, data, 0, data.length);
- }
- } else {
- System.arraycopy(copy, 0, data, 0, data.length);
- }
- }
-}
diff --git
a/pinot-perf/src/main/java/org/apache/pinot/perf/ForwardIndexWriterBenchmark.java
b/pinot-perf/src/main/java/org/apache/pinot/perf/ForwardIndexWriterBenchmark.java
deleted file mode 100644
index 8642cc28b64..00000000000
---
a/pinot-perf/src/main/java/org/apache/pinot/perf/ForwardIndexWriterBenchmark.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/**
- * 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.pinot.perf;
-
-import java.io.ByteArrayOutputStream;
-import java.io.DataOutputStream;
-import java.io.File;
-import java.io.FileReader;
-import java.util.Arrays;
-import java.util.List;
-import org.apache.commons.io.IOUtils;
-import
org.apache.pinot.segment.local.io.writer.impl.FixedBitMVForwardIndexWriter;
-import org.roaringbitmap.buffer.MutableRoaringBitmap;
-
-
-public class ForwardIndexWriterBenchmark {
- private ForwardIndexWriterBenchmark() {
- }
-
- public static void convertRawToForwardIndex(File rawFile)
- throws Exception {
- List<String> lines = IOUtils.readLines(new FileReader(rawFile));
- int totalDocs = lines.size();
- int max = Integer.MIN_VALUE;
- int maxNumberOfMultiValues = Integer.MIN_VALUE;
- int totalNumValues = 0;
- int[][] data = new int[totalDocs][];
- for (int i = 0; i < lines.size(); i++) {
- String line = lines.get(i);
- String[] split = line.split(",");
- totalNumValues = totalNumValues + split.length;
- if (split.length > maxNumberOfMultiValues) {
- maxNumberOfMultiValues = split.length;
- }
- data[i] = new int[split.length];
- for (int j = 0; j < split.length; j++) {
- String token = split[j];
- int val = Integer.parseInt(token);
- data[i][j] = val;
- if (val > max) {
- max = val;
- }
- }
- }
- int maxBitsNeeded = (int) Math.ceil(Math.log(max) / Math.log(2));
- int size = 2048;
- int[] offsets = new int[size];
- int bitMapSize = 0;
- File outputFile = new File("output.mv.fwd");
-
- FixedBitMVForwardIndexWriter fixedBitSkipListSCMVWriter =
- new FixedBitMVForwardIndexWriter(outputFile, totalDocs,
totalNumValues, maxBitsNeeded);
-
- for (int i = 0; i < totalDocs; i++) {
- fixedBitSkipListSCMVWriter.putDictIds(data[i]);
- if (i % size == size - 1) {
- MutableRoaringBitmap rr1 = MutableRoaringBitmap.bitmapOf(offsets);
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- DataOutputStream dos = new DataOutputStream(bos);
- rr1.serialize(dos);
- dos.close();
- // System.out.println("Chunk " + i / size + " bitmap size:" +
bos.size());
- bitMapSize += bos.size();
- } else if (i == totalDocs - 1) {
- MutableRoaringBitmap rr1 =
MutableRoaringBitmap.bitmapOf(Arrays.copyOf(offsets, i % size));
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- DataOutputStream dos = new DataOutputStream(bos);
- rr1.serialize(dos);
- dos.close();
- // System.out.println("Chunk " + i / size + " bitmap size:" +
bos.size());
- bitMapSize += bos.size();
- }
- }
- fixedBitSkipListSCMVWriter.close();
- System.out.println("Output file size:" + outputFile.length());
- System.out.println("totalNumberOfDoc\t\t\t:" + totalDocs);
- System.out.println("totalNumberOfValues\t\t\t:" + totalNumValues);
- System.out.println("chunk size\t\t\t\t:" + size);
- System.out.println("Num chunks\t\t\t\t:" + totalDocs / size);
- int numChunks = totalDocs / size + 1;
- int totalBits = (totalNumValues * maxBitsNeeded);
- int dataSizeinBytes = (totalBits + 7) / 8;
-
- System.out.println("Raw data size with fixed bit encoding\t:" +
dataSizeinBytes);
- System.out.println("\nPer encoding size");
- System.out.println();
- System.out.println("size (offset + length)\t\t\t:" + ((totalDocs * (4 +
4)) + dataSizeinBytes));
- System.out.println();
- System.out.println("size (offset only)\t\t\t:" + ((totalDocs * (4)) +
dataSizeinBytes));
- System.out.println();
- System.out.println("bitMapSize\t\t\t\t:" + bitMapSize);
- System.out.println("size (with bitmap)\t\t\t:" + (bitMapSize + (numChunks
* 4) + dataSizeinBytes));
-
- System.out.println();
- System.out.println("Custom Bitset\t\t\t\t:" + (totalNumValues + 7) / 8);
- System.out
- .println("size (with custom bitset)\t\t\t:" + (((totalNumValues + 7) /
8) + (numChunks * 4) + dataSizeinBytes));
- }
-
- public static void main(String[] args)
- throws Exception {
- convertRawToForwardIndex(new File("/tmp/output.mv.raw"));
- }
-}
diff --git a/pinot-perf/src/main/java/org/apache/pinot/perf/LazyDataList.java
b/pinot-perf/src/main/java/org/apache/pinot/perf/LazyDataList.java
deleted file mode 100644
index 066b6b05328..00000000000
--- a/pinot-perf/src/main/java/org/apache/pinot/perf/LazyDataList.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/**
- * 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.pinot.perf;
-
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-import org.apache.pinot.spi.data.readers.GenericRow;
-
-
-public class LazyDataList implements List<GenericRow> {
-
- private final GenericRow _row;
- private final int _size;
- private final RowGenerator _rowGenerator;
-
- public interface RowGenerator {
- void generateRow(GenericRow row, int index);
- }
-
- public LazyDataList(int size, RowGenerator rowGenerator) {
- _row = new GenericRow();
- _size = size;
- _rowGenerator = rowGenerator;
- }
-
- @Override
- public int size() {
- return _size;
- }
-
- @Override
- public boolean isEmpty() {
- return _size == 0;
- }
-
- @Override
- public boolean contains(Object o) {
- return false;
- }
-
- @Override
- public Iterator<GenericRow> iterator() {
- return null;
- }
-
- @Override
- public Object[] toArray() {
- return new Object[0];
- }
-
- @Override
- public <T> T[] toArray(T[] a) {
- return null;
- }
-
- @Override
- public boolean add(GenericRow genericRow) {
- return false;
- }
-
- @Override
- public boolean remove(Object o) {
- return false;
- }
-
- @Override
- public boolean containsAll(Collection<?> c) {
- return false;
- }
-
- @Override
- public boolean addAll(Collection<? extends GenericRow> c) {
- return false;
- }
-
- @Override
- public boolean addAll(int index, Collection<? extends GenericRow> c) {
- return false;
- }
-
- @Override
- public boolean removeAll(Collection<?> c) {
- return false;
- }
-
- @Override
- public boolean retainAll(Collection<?> c) {
- return false;
- }
-
- @Override
- public void clear() {
- // do nothing
- }
-
- @Override
- public GenericRow get(int index) {
- generateRow(index);
- return _row;
- }
-
- private void generateRow(int index) {
- _rowGenerator.generateRow(_row, index);
- }
-
- @Override
- public GenericRow set(int index, GenericRow element) {
- return null;
- }
-
- @Override
- public void add(int index, GenericRow element) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public GenericRow remove(int index) {
- return null;
- }
-
- @Override
- public int indexOf(Object o) {
- return 0;
- }
-
- @Override
- public int lastIndexOf(Object o) {
- return 0;
- }
-
- @Override
- public ListIterator<GenericRow> listIterator() {
- return null;
- }
-
- @Override
- public ListIterator<GenericRow> listIterator(int index) {
- return null;
- }
-
- @Override
- public List<GenericRow> subList(int fromIndex, int toIndex) {
- return List.of();
- }
-}
diff --git
a/pinot-perf/src/main/java/org/apache/pinot/perf/RawIndexBenchmark.java
b/pinot-perf/src/main/java/org/apache/pinot/perf/RawIndexBenchmark.java
deleted file mode 100644
index 845c0d62d2b..00000000000
--- a/pinot-perf/src/main/java/org/apache/pinot/perf/RawIndexBenchmark.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/**
- * 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.pinot.perf;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-import org.apache.commons.io.FileUtils;
-import org.apache.pinot.core.operator.DocIdSetOperator;
-import org.apache.pinot.core.operator.ProjectionOperator;
-import org.apache.pinot.core.operator.blocks.ProjectionBlock;
-import org.apache.pinot.core.operator.docvalsets.ProjectionBlockValSet;
-import org.apache.pinot.core.operator.filter.BaseFilterOperator;
-import org.apache.pinot.core.operator.filter.TestFilterOperator;
-import org.apache.pinot.core.plan.DocIdSetPlanNode;
-import org.apache.pinot.core.query.request.context.QueryContext;
-import
org.apache.pinot.segment.local.indexsegment.immutable.ImmutableSegmentLoader;
-import
org.apache.pinot.segment.local.segment.creator.impl.SegmentIndexCreationDriverImpl;
-import org.apache.pinot.segment.local.segment.readers.GenericRowRecordReader;
-import org.apache.pinot.segment.spi.IndexSegment;
-import org.apache.pinot.segment.spi.V1Constants;
-import org.apache.pinot.segment.spi.creator.SegmentGeneratorConfig;
-import org.apache.pinot.segment.spi.datasource.DataSource;
-import org.apache.pinot.spi.config.table.TableConfig;
-import org.apache.pinot.spi.config.table.TableType;
-import org.apache.pinot.spi.data.DimensionFieldSpec;
-import org.apache.pinot.spi.data.FieldSpec;
-import org.apache.pinot.spi.data.Schema;
-import org.apache.pinot.spi.data.readers.GenericRow;
-import org.apache.pinot.spi.utils.ReadMode;
-import org.apache.pinot.spi.utils.builder.TableConfigBuilder;
-import picocli.CommandLine;
-
-
-/// Class to perform benchmark on lookups for dictionary encoded fwd index
v.s. raw index without dictionary.
-/// It can take an existing segment with two columns to compare. It can also
create a segment on the fly with a
-/// given input file containing strings (one string per line).
-@SuppressWarnings({"FieldCanBeLocal", "unused"})
[email protected]
-public class RawIndexBenchmark {
- private static final String SEGMENT_DIR_NAME =
System.getProperty("java.io.tmpdir") + File.separator + "rawIndexPerf";
- private static final String SEGMENT_NAME = "perfTestSegment";
- private static final int NUM_COLUMNS = 2;
-
- private static final String DEFAULT_RAW_INDEX_COLUMN = "column_0";
- private static final String DEFAULT_FWD_INDEX_COLUMN = "column_1";
- private static final int DEFAULT_NUM_LOOKUP = 100_000;
- private static final int DEFAULT_NUM_CONSECUTIVE_LOOKUP = 50;
-
- @CommandLine.Option(names = {"-segmentDir"}, required = false, description =
"Untarred segment")
- private String _segmentDir = null;
-
- @CommandLine.Option(names = {"-fwdIndexColumn"}, required = false,
- description = "Name of column with dictionary encoded index")
- private String _fwdIndexColumn = DEFAULT_FWD_INDEX_COLUMN;
-
- @CommandLine.Option(names = {"-rawIndexColumn"}, required = false,
- description = "Name of column with raw index (no-dictionary")
- private String _rawIndexColumn = DEFAULT_RAW_INDEX_COLUMN;
-
- @CommandLine.Option(names = {"-dataFile"}, required = false,
- description = "File containing input data (one string per line)")
- private String _dataFile = null;
-
- @CommandLine.Option(names = {"-loadMode"}, required = false, description =
"Load mode for data (mmap|heap")
- private String _loadMode = "heap";
-
- @CommandLine.Option(names = {"-numLookups"}, required = false,
- description = "Number of lookups to be performed for benchmark")
- private int _numLookups = DEFAULT_NUM_LOOKUP;
-
- @CommandLine.Option(names = {"-numConsecutiveLookups"}, required = false,
- description = "Number of consecutive docIds to lookup")
- private int _numConsecutiveLookups = DEFAULT_NUM_CONSECUTIVE_LOOKUP;
-
- @CommandLine.Option(names = {"-help", "-h", "--h", "--help"}, required =
false, usageHelp = true,
- description = "print this message")
- private boolean _help = false;
-
- private int _numRows = 0;
-
- public void run()
- throws Exception {
- if (_segmentDir == null && _dataFile == null) {
- System.out.println("Error: One of 'segmentDir' or 'dataFile' must be
specified");
- return;
- }
-
- File segmentFile = (_segmentDir == null) ? buildSegment() : new
File(_segmentDir);
- IndexSegment segment = ImmutableSegmentLoader.load(segmentFile,
ReadMode.valueOf(_loadMode));
- compareIndexSizes(segment, segmentFile, _fwdIndexColumn, _rawIndexColumn);
- compareLookups(segment);
-
- // Cleanup the temporary directory
- if (_segmentDir != null) {
- FileUtils.deleteQuietly(new File(SEGMENT_DIR_NAME));
- }
- segment.destroy();
- }
-
- /// Helper method that builds a segment containing two columns both with
data from input file.
- /// The first column has raw indices (no dictionary), where as the second
column is dictionary encoded.
- ///
- /// @throws Exception
- private File buildSegment()
- throws Exception {
- Schema schema = new Schema();
-
- for (int i = 0; i < NUM_COLUMNS; i++) {
- String column = "column_" + i;
- DimensionFieldSpec dimensionFieldSpec = new DimensionFieldSpec(column,
FieldSpec.DataType.STRING, true);
- schema.addField(dimensionFieldSpec);
- }
- TableConfig tableConfig =
- new
TableConfigBuilder(TableType.OFFLINE).setTableName("test").setNoDictionaryColumns(List.of(_rawIndexColumn))
- .build();
- SegmentGeneratorConfig config = new SegmentGeneratorConfig(tableConfig,
schema);
-
- config.setOutDir(SEGMENT_DIR_NAME);
- config.setSegmentName(SEGMENT_NAME);
-
- BufferedReader reader = new BufferedReader(new FileReader(_dataFile));
- String value;
-
- final List<GenericRow> rows = new ArrayList<>();
-
- System.out.println("Reading data...");
- while ((value = reader.readLine()) != null) {
- GenericRow row = new GenericRow();
- for (FieldSpec fieldSpec : schema.getAllFieldSpecs()) {
- row.putValue(fieldSpec.getName(), value);
- }
- rows.add(row);
- _numRows++;
-
- if (_numRows % 1000000 == 0) {
- System.out.println("Read rows: " + _numRows);
- }
- }
-
- System.out.println("Generating segment...");
- SegmentIndexCreationDriverImpl driver = new
SegmentIndexCreationDriverImpl();
- driver.init(config, new GenericRowRecordReader(rows));
- driver.build();
-
- return new File(SEGMENT_DIR_NAME, SEGMENT_NAME);
- }
-
- /// Compares and prints the index size for the raw and dictionary encoded
columns.
- ///
- /// @param segment Segment to compare
- private void compareIndexSizes(IndexSegment segment, File segmentDir, String
fwdIndexColumn, String rawIndexColumn) {
- String filePrefix = segmentDir.getAbsolutePath() + File.separator;
- File rawIndexFile = new File(filePrefix + rawIndexColumn +
V1Constants.Indexes.RAW_SV_FORWARD_INDEX_FILE_EXTENSION);
-
- String extension =
(segment.getDataSource(_fwdIndexColumn).getDataSourceMetadata().isSorted())
- ? V1Constants.Indexes.SORTED_SV_FORWARD_INDEX_FILE_EXTENSION
- : V1Constants.Indexes.UNSORTED_SV_FORWARD_INDEX_FILE_EXTENSION;
-
- File fwdIndexFile = new File(filePrefix + _fwdIndexColumn + extension);
- File fwdIndexDictFile = new File(filePrefix + _fwdIndexColumn +
V1Constants.Dict.FILE_EXTENSION);
-
- long rawIndexSize = rawIndexFile.length();
- long fwdIndexSize = fwdIndexFile.length() + fwdIndexDictFile.length();
-
- System.out.println("Raw index size: " + toMegaBytes(rawIndexSize) + "
MB.");
- System.out.println("Fwd index size: " + toMegaBytes(fwdIndexSize) + "
MB.");
- System.out.println("Storage space saving: " + ((fwdIndexSize -
rawIndexSize) * 100.0 / fwdIndexSize) + " %");
- }
-
- /// Compares lookup times for the two columns.
- /// Performs [#_numConsecutiveLookups] on the two columns on randomly
generated docIds.
- ///
- /// @param segment Segment to compare the columns for
- private void compareLookups(IndexSegment segment) {
- int[] filteredDocIds = generateDocIds(segment);
- long rawIndexTime = profileLookups(segment, _rawIndexColumn,
filteredDocIds);
- long fwdIndexTime = profileLookups(segment, _fwdIndexColumn,
filteredDocIds);
-
- System.out.println("Raw index lookup time: " + rawIndexTime);
- System.out.println("Fwd index lookup time: " + fwdIndexTime);
- System.out.println("Percentage change: " + ((fwdIndexTime - rawIndexTime)
* 100.0 / rawIndexTime) + " %");
- }
-
- /// Profiles the lookup time for a given column, for the given docIds.
- ///
- /// @param segment Segment to profile
- /// @param column Column to profile
- /// @param docIds DocIds to lookup on the column
- /// @return Time take in millis for the lookups
- private long profileLookups(IndexSegment segment, String column, int[]
docIds) {
- BaseFilterOperator filterOperator =
- new TestFilterOperator(docIds,
segment.getDataSource(column).getDataSourceMetadata().getNumDocs());
- DocIdSetOperator docIdSetOperator = new DocIdSetOperator(filterOperator,
DocIdSetPlanNode.MAX_DOC_PER_CALL);
- ProjectionOperator projectionOperator =
- new ProjectionOperator(buildDataSourceMap(segment), docIdSetOperator,
new QueryContext.Builder().build());
-
- long start = System.currentTimeMillis();
- ProjectionBlock projectionBlock;
- while ((projectionBlock = projectionOperator.nextBlock()) != null) {
- ProjectionBlockValSet blockValueSet = (ProjectionBlockValSet)
projectionBlock.getBlockValueSet(column);
- blockValueSet.getDoubleValuesSV();
- }
- return (System.currentTimeMillis() - start);
- }
-
- /// Convert from bytes to mega-bytes.
- ///
- /// @param sizeInBytes Size to convert
- /// @return Size in MB's
- private double toMegaBytes(long sizeInBytes) {
- return sizeInBytes / (1024 * 1024);
- }
-
- /// Helper method to build map from column to data source
- ///
- /// @param segment Segment for which to build the map
- /// @return Column to data source map
- private Map<String, DataSource> buildDataSourceMap(IndexSegment segment) {
- Map<String, DataSource> dataSourceMap = new HashMap<>();
- for (String column : segment.getPhysicalColumnNames()) {
- dataSourceMap.put(column, segment.getDataSource(column));
- }
- return dataSourceMap;
- }
-
- /// Generate random docIds.
- ///
- /// - Total of [#_numLookups] docIds are generated.
- /// - DocId's are in clusters containing [#_numConsecutiveLookups] ids.
- ///
- /// @param segment
- /// @return
- private int[] generateDocIds(IndexSegment segment) {
- Random random = new Random();
- int numDocs = segment.getSegmentMetadata().getTotalDocs();
- int maxDocId = numDocs - _numConsecutiveLookups - 1;
-
- int[] docIdSet = new int[_numLookups];
- int j = 0;
- for (int i = 0; i < (_numLookups / _numConsecutiveLookups); i++) {
- int startDocId = random.nextInt(maxDocId);
- int endDocId = startDocId + _numConsecutiveLookups;
-
- for (int docId = startDocId; docId < endDocId; docId++) {
- docIdSet[j++] = docId;
- }
- }
-
- int docId = random.nextInt(maxDocId);
- for (; j < _numLookups; j++) {
- docIdSet[j] = docId++;
- }
- return docIdSet;
- }
-
- /// Main method for the class. Parses the command line arguments, and
invokes the benchmark.
- ///
- /// @param args Command line arguments.
- /// @throws Exception
- public static void main(String[] args)
- throws Exception {
- RawIndexBenchmark benchmark = new RawIndexBenchmark();
- CommandLine commandLine = new CommandLine(benchmark);
- CommandLine.ParseResult result = commandLine.parseArgs(args);
- if (commandLine.isUsageHelpRequested() || result.matchedArgs().size() ==
0) {
- commandLine.usage(System.out);
- return;
- }
- benchmark.run();
- }
-}
diff --git
a/pinot-perf/src/main/java/org/apache/pinot/perf/StringDictionaryPerfTest.java
b/pinot-perf/src/main/java/org/apache/pinot/perf/StringDictionaryPerfTest.java
deleted file mode 100644
index 806da4dde84..00000000000
---
a/pinot-perf/src/main/java/org/apache/pinot/perf/StringDictionaryPerfTest.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/**
- * 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.pinot.perf;
-
-import com.google.common.base.Joiner;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Random;
-import java.util.Set;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.lang3.RandomStringUtils;
-import org.apache.commons.math.stat.descriptive.DescriptiveStatistics;
-import
org.apache.pinot.segment.local.indexsegment.immutable.ImmutableSegmentLoader;
-import
org.apache.pinot.segment.local.segment.creator.impl.SegmentIndexCreationDriverImpl;
-import org.apache.pinot.segment.local.segment.index.loader.IndexLoadingConfig;
-import org.apache.pinot.segment.local.segment.readers.GenericRowRecordReader;
-import org.apache.pinot.segment.spi.ImmutableSegment;
-import org.apache.pinot.segment.spi.creator.SegmentGeneratorConfig;
-import org.apache.pinot.segment.spi.index.reader.Dictionary;
-import org.apache.pinot.spi.config.table.TableConfig;
-import org.apache.pinot.spi.config.table.TableType;
-import org.apache.pinot.spi.data.DimensionFieldSpec;
-import org.apache.pinot.spi.data.FieldSpec;
-import org.apache.pinot.spi.data.Schema;
-import org.apache.pinot.spi.data.readers.FileFormat;
-import org.apache.pinot.spi.data.readers.GenericRow;
-import org.apache.pinot.spi.utils.ReadMode;
-import org.apache.pinot.spi.utils.builder.TableConfigBuilder;
-
-
-/// Performance test for lookup in string dictionary.
-public class StringDictionaryPerfTest {
- private static final int MAX_STRING_LENGTH = 1000;
- private static final boolean USE_FIXED_SIZE_STRING = true;
- private static final String TMP_DIR = System.getProperty("java.io.tmpdir");
- private static final String COLUMN_NAME = "test";
- private static final String[] STATS_HEADERS = new String[]{
- "DictSize", "TimeTaken(ms)", "SegmentSize", "NumLookups", "Min", "Max",
"Mean", "StdDev", "Median", "Skewness",
- "Kurtosis", "Variance", "BufferSize"
- };
- private static final Joiner COMMA_JOINER = Joiner.on(",");
- private static final TableConfig TABLE_CONFIG =
- new
TableConfigBuilder(TableType.OFFLINE).setOnHeapDictionaryColumns(List.of(COLUMN_NAME)).setTableName("test")
- .build();
-
- private final DescriptiveStatistics _statistics = new
DescriptiveStatistics();
- private String[] _inputStrings;
- private File _indexDir;
- private int _dictLength;
- private Schema _schema;
-
- /// Helper method to build a segment:
- /// - Segment contains one string column
- /// - Row values for the column are randomly generated strings of length 1
to 100
- private void buildSegment(int dictLength)
- throws Exception {
- _schema = new Schema();
- String segmentName = "perfTestSegment" + System.currentTimeMillis();
- _indexDir = new File(TMP_DIR + File.separator + segmentName);
- _indexDir.deleteOnExit();
-
- FieldSpec fieldSpec = new DimensionFieldSpec(COLUMN_NAME,
FieldSpec.DataType.STRING, true);
- _schema.addField(fieldSpec);
-
- _dictLength = dictLength;
- _inputStrings = new String[dictLength];
-
- SegmentGeneratorConfig config = new SegmentGeneratorConfig(TABLE_CONFIG,
_schema);
- config.setOutDir(_indexDir.getParent());
- config.setFormat(FileFormat.AVRO);
- config.setSegmentName(segmentName);
-
- Random random = new Random(System.nanoTime());
- List<GenericRow> rows = new ArrayList<>(dictLength);
- Set<String> uniqueStrings = new HashSet<>(dictLength);
-
- int i = 0;
- while (i < dictLength) {
- String randomString = RandomStringUtils.secure().nextAlphanumeric(
- USE_FIXED_SIZE_STRING ? MAX_STRING_LENGTH : (1 +
random.nextInt(MAX_STRING_LENGTH)));
- if (!uniqueStrings.add(randomString)) {
- continue;
- }
- _inputStrings[i++] = randomString;
- _statistics.addValue(randomString.length());
- GenericRow row = new GenericRow();
- row.putValue(COLUMN_NAME, randomString);
- rows.add(row);
- }
-
- long start = System.currentTimeMillis();
- SegmentIndexCreationDriverImpl driver = new
SegmentIndexCreationDriverImpl();
- driver.init(config, new GenericRowRecordReader(rows));
- driver.build();
- System.out.println("Total time for building segment: " +
(System.currentTimeMillis() - start));
- }
-
- /// Measures the performance of string dictionary lookups by performing the
provided number of lookups to random
- /// value.
- public void perfTestLookups(int numLookups)
- throws Exception {
- ImmutableSegment immutableSegment = ImmutableSegmentLoader.load(_indexDir,
ReadMode.heap);
- Dictionary dictionary = immutableSegment.getDictionary(COLUMN_NAME);
-
- Random random = new Random(System.nanoTime());
- long start = System.currentTimeMillis();
-
- for (int i = 0; i < numLookups; i++) {
- dictionary.indexOf(_inputStrings[random.nextInt(_dictLength)]);
- }
-
- FileUtils.deleteQuietly(_indexDir);
- System.out.println("Total time for " + numLookups + " lookups: " +
(System.currentTimeMillis() - start) + "ms");
- }
-
- /// Measures the performance of string dictionary reads by performing the
provided number of reads for random index.
- private String[] perfTestGetValues(int numGetValues)
- throws Exception {
- Runtime r = Runtime.getRuntime();
- System.gc();
- long oldMemory = r.totalMemory() - r.freeMemory();
- IndexLoadingConfig defaultIndexLoadingConfig = new
IndexLoadingConfig(TABLE_CONFIG, _schema);
-
- ImmutableSegment immutableSegment = ImmutableSegmentLoader.load(_indexDir,
defaultIndexLoadingConfig);
- Dictionary dictionary = immutableSegment.getDictionary(COLUMN_NAME);
-
- Random random = new Random(System.nanoTime());
- long start = System.currentTimeMillis();
- for (int i = 0; i < numGetValues; i++) {
- dictionary.get(random.nextInt(_dictLength));
- }
- long time = System.currentTimeMillis() - start;
-
- System.gc();
- long newMemory = r.totalMemory() - r.freeMemory();
- long segmentSize = immutableSegment.getSegmentSizeBytes();
- FileUtils.deleteQuietly(_indexDir);
-
- System.out.println("Total time for " + numGetValues + " lookups: " + time
+ "ms");
- System.out.println("Memory usage: " + (newMemory - oldMemory));
- return new String[]{
- String.valueOf(_statistics.getN()), String.valueOf(time),
String.valueOf(segmentSize),
- String.valueOf(numGetValues), String.valueOf(_statistics.getMin()),
String.valueOf(_statistics.getMax()),
- String.valueOf(_statistics.getMean()),
String.valueOf(_statistics.getStandardDeviation()),
- String.valueOf(_statistics.getPercentile(50.0D)),
String.valueOf(_statistics.getSkewness()),
- String.valueOf(_statistics.getKurtosis()),
String.valueOf(_statistics.getVariance())
- };
- }
-
- public static void main(String[] args)
- throws Exception {
- if (args.length < 2) {
- System.out.println("Usage: StringDictionaryPerfTest <dictionary_length>
<dictionary_length> ... <num_lookups> ");
- }
-
- int numLookups = Integer.valueOf(args[args.length - 1]);
-
- String[][] stats = new String[args.length][];
- stats[0] = STATS_HEADERS;
- for (int i = 0; i < args.length - 1; i++) {
- int dictLength = Integer.valueOf(args[i]);
- StringDictionaryPerfTest test = new StringDictionaryPerfTest();
- test.buildSegment(dictLength);
- test.perfTestLookups(numLookups);
- stats[i + 1] = test.perfTestGetValues(numLookups);
- }
- for (String[] s : stats) {
- System.out.println(COMMA_JOINER.join(s));
- }
- }
-}
diff --git
a/pinot-perf/src/main/java/org/apache/pinot/perf/aggregation/BenchmarkSumQuery.java
b/pinot-perf/src/main/java/org/apache/pinot/perf/aggregation/BenchmarkSumQuery.java
deleted file mode 100644
index eb3e4fb7872..00000000000
---
a/pinot-perf/src/main/java/org/apache/pinot/perf/aggregation/BenchmarkSumQuery.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/**
- * 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.pinot.perf.aggregation;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
-import java.util.concurrent.TimeUnit;
-import org.apache.pinot.spi.config.table.TableConfig;
-import org.apache.pinot.spi.config.table.TableType;
-import org.apache.pinot.spi.data.FieldSpec;
-import org.apache.pinot.spi.data.Schema;
-import org.apache.pinot.spi.utils.builder.TableConfigBuilder;
-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 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;
-
-
-@Fork(1)
-@BenchmarkMode(Mode.AverageTime)
-@OutputTimeUnit(TimeUnit.MICROSECONDS)
-@Warmup(iterations = 10, time = 1)
-@Measurement(iterations = 10, time = 1)
-@State(Scope.Benchmark)
-public class BenchmarkSumQuery extends AbstractAggregationQueryBenchmark {
-
- @Param({"false", "true"})
- public boolean _nullHandling;
-
- @Param({"1", "2", "4", "8", "16", "32", "64", "128"})
- protected int _nullPeriod;
-
- public static void main(String[] args) throws RunnerException {
- Options opt = new OptionsBuilder()
- .include(BenchmarkSumQuery.class.getSimpleName())
- .build();
-
- new Runner(opt).run();
- }
-
- @Override
- protected Schema createSchema() {
- return new Schema.SchemaBuilder()
- .setSchemaName("benchmark")
- .addMetricField("col", FieldSpec.DataType.INT)
- .build();
- }
-
- @Override
- protected TableConfig createTableConfig() {
- return new TableConfigBuilder(TableType.OFFLINE)
- .setTableName("benchmark")
- .setNullHandlingEnabled(true)
- .build();
- }
-
- @Override
- protected List<List<Object[][]>> createSegmentsPerServer() {
- Random valueRandom = new Random(420);
- List<List<Object[][]>> segmentsPerServer = new ArrayList<>();
- segmentsPerServer.add(new ArrayList<>());
- segmentsPerServer.add(new ArrayList<>());
-
- // 2 servers
- for (int server = 0; server < 2; server++) {
- List<Object[][]> segments = segmentsPerServer.get(server);
- // 3 segments per server
- for (int seg = 0; seg < 3; seg++) {
- // 10000 single column rows per segment
- Object[][] segment = new Object[10000][1];
- for (int row = 0; row < 10000; row++) {
- segment[row][0] = (row % _nullPeriod) == 0 ? null :
valueRandom.nextInt();
- }
- segments.add(segment);
- }
- }
-
- return segmentsPerServer;
- }
-
- @Setup(Level.Trial)
- public void setup() throws IOException {
- init(_nullHandling);
- }
-
- @Benchmark
- public void test(Blackhole bh) {
- executeQuery("SELECT SUM(col) FROM mytable", bh);
- }
-}
diff --git
a/pinot-plugins/pinot-file-system/pinot-hdfs/src/test/java/org/apache/pinot/plugin/filesystem/HadoopPinotFSTest.java
b/pinot-plugins/pinot-file-system/pinot-hdfs/src/test/java/org/apache/pinot/plugin/filesystem/HadoopPinotFSTest.java
index b94afe63647..8eb6b312432 100644
---
a/pinot-plugins/pinot-file-system/pinot-hdfs/src/test/java/org/apache/pinot/plugin/filesystem/HadoopPinotFSTest.java
+++
b/pinot-plugins/pinot-file-system/pinot-hdfs/src/test/java/org/apache/pinot/plugin/filesystem/HadoopPinotFSTest.java
@@ -37,6 +37,9 @@ import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
public class HadoopPinotFSTest {
private static final String TMP_DIR = System.getProperty("java.io.tmpdir") +
"/HadoopPinotFSTest";
@@ -433,9 +436,9 @@ public class HadoopPinotFSTest {
}
@Test
- public void testDeleteBatchPerformanceWithManyFiles()
+ public void testDeleteBatchWithManyFiles()
throws IOException {
- URI baseURI = URI.create(TMP_DIR + "/testDeleteBatchPerformance");
+ URI baseURI = URI.create(TMP_DIR + "/testDeleteBatchWithManyFiles");
try (HadoopPinotFS hadoopFS = new HadoopPinotFS()) {
hadoopFS.init(new PinotConfiguration());
hadoopFS.mkdir(baseURI);
@@ -450,18 +453,13 @@ public class HadoopPinotFSTest {
}
// Delete all files using deleteBatch
- long startTime = System.currentTimeMillis();
- Assert.assertTrue(hadoopFS.deleteBatch(urisToDelete, false));
- long batchTime = System.currentTimeMillis() - startTime;
+ assertTrue(hadoopFS.deleteBatch(urisToDelete, false));
// Verify all files are deleted
for (URI uri : urisToDelete) {
- Assert.assertFalse(hadoopFS.exists(uri));
+ assertFalse(hadoopFS.exists(uri));
}
- // Log performance (batch deletion should be reasonably fast)
- Assert.assertTrue(batchTime < 10000, "Batch deletion took too long: " +
batchTime + "ms");
-
hadoopFS.delete(baseURI, true);
}
}
diff --git
a/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/segment/index/vector/VectorSearchBenchmark.java
b/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/segment/index/vector/VectorSearchBenchmark.java
deleted file mode 100644
index dc9c978f886..00000000000
---
a/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/segment/index/vector/VectorSearchBenchmark.java
+++ /dev/null
@@ -1,389 +0,0 @@
-/**
- * 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.pinot.segment.local.segment.index.vector;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Random;
-import
org.apache.pinot.segment.local.segment.index.readers.vector.IvfFlatVectorIndexReader;
-import org.apache.pinot.segment.spi.index.creator.VectorIndexConfig;
-import org.roaringbitmap.buffer.ImmutableRoaringBitmap;
-import org.roaringbitmap.buffer.MutableRoaringBitmap;
-import org.testng.annotations.AfterClass;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
-
-/// Manual benchmark for vector search operations across different backends
and configurations.
-/// All test methods are disabled by default so they do not run in CI. Enable
individually
-/// when running locally for performance evaluation.
-///
-/// This is a comparative micro-benchmark that measures:
-///
-/// - IVF_FLAT search latency with different nprobe values
-/// - SQ8 vs SQ4 vs FLAT quantizer encode/decode/distance performance
-/// - Pre-filter vs post-filter ANN with different selectivities
-/// - Recall quality across configurations
-///
-/// Run with: `mvn test -pl pinot-segment-local -Dtest=VectorSearchBenchmark
-Dcheckstyle.skip`
-public class VectorSearchBenchmark {
-
- private static final int DIMENSION = 128;
- private static final int NUM_VECTORS = 50000;
- private static final int NUM_QUERIES = 100;
- private static final int TOP_K = 10;
- private static final int NLIST = 128;
- private static final Random RANDOM = new Random(42);
-
- private float[][] _vectors;
- private float[][] _queries;
- private File _tempDir;
- private IvfFlatVectorIndexReader _ivfReader;
-
- @BeforeClass
- public void setUp() throws Exception {
- // Generate dataset
- _vectors = new float[NUM_VECTORS][DIMENSION];
- for (int i = 0; i < NUM_VECTORS; i++) {
- for (int d = 0; d < DIMENSION; d++) {
- _vectors[i][d] = RANDOM.nextFloat() * 2 - 1;
- }
- }
-
- _queries = new float[NUM_QUERIES][DIMENSION];
- for (int i = 0; i < NUM_QUERIES; i++) {
- for (int d = 0; d < DIMENSION; d++) {
- _queries[i][d] = RANDOM.nextFloat() * 2 - 1;
- }
- }
-
- // Build IVF_FLAT index
- _tempDir = Files.createTempDirectory("vector-bench").toFile();
- Map<String, String> props = new HashMap<>();
- props.put("vectorIndexType", "IVF_FLAT");
- props.put("vectorDimension", String.valueOf(DIMENSION));
- props.put("vectorDistanceFunction", "EUCLIDEAN");
- props.put("version", "1");
- props.put("nlist", String.valueOf(NLIST));
- props.put("trainingSeed", "42");
- VectorIndexConfig config = new VectorIndexConfig(false, "IVF_FLAT",
DIMENSION, 1,
- VectorIndexConfig.VectorDistanceFunction.EUCLIDEAN, props);
-
- try (IvfFlatVectorIndexCreator creator = new
IvfFlatVectorIndexCreator("embedding", _tempDir, config)) {
- for (float[] vector : _vectors) {
- creator.add(vector);
- }
- creator.seal();
- }
-
- _ivfReader = new IvfFlatVectorIndexReader("embedding",
- IvfCombinedBuffers.mapCombined(_tempDir, "embedding", config,
"test-vector"), config);
- }
-
- @AfterClass
- public void tearDown() throws IOException {
- if (_ivfReader != null) {
- _ivfReader.close();
- }
- if (_tempDir != null) {
- for (File f : _tempDir.listFiles()) {
- f.delete();
- }
- _tempDir.delete();
- }
- }
-
- // -----------------------------------------------------------------------
- // Benchmark 1: IVF_FLAT nprobe sweep
- // -----------------------------------------------------------------------
-
- @Test(enabled = false)
- public void benchmarkNprobeSweep() {
- System.out.println("\n=== IVF_FLAT nprobe Sweep (" + NUM_VECTORS + "
vectors, dim=" + DIMENSION + ") ===");
- System.out.printf("%-10s %-15s %-15s %-10s%n", "nprobe", "avg_latency_us",
"avg_recall@10", "candidates");
-
- int[] nprobeValues = {1, 2, 4, 8, 16, 32, 64, 128};
- for (int nprobe : nprobeValues) {
- _ivfReader.setNprobe(nprobe);
-
- long totalLatencyNs = 0;
- double totalRecall = 0;
- int totalCandidates = 0;
-
- for (int q = 0; q < NUM_QUERIES; q++) {
- long start = System.nanoTime();
- MutableRoaringBitmap result = _ivfReader.getDocIds(_queries[q], TOP_K);
- long elapsed = System.nanoTime() - start;
-
- totalLatencyNs += elapsed;
- totalCandidates += result.getCardinality();
-
- // Compute recall against brute-force
- int[] exactTopK = bruteForceTopK(_queries[q], TOP_K);
- int overlap = 0;
- for (int docId : exactTopK) {
- if (result.contains(docId)) {
- overlap++;
- }
- }
- totalRecall += (double) overlap / TOP_K;
- }
-
- _ivfReader.clearNprobe();
-
- System.out.printf("%-10d %-15.1f %-15.3f %-10.1f%n",
- nprobe,
- (double) totalLatencyNs / NUM_QUERIES / 1000,
- totalRecall / NUM_QUERIES,
- (double) totalCandidates / NUM_QUERIES);
- }
- }
-
- // -----------------------------------------------------------------------
- // Benchmark 2: SQ8 vs SQ4 vs FLAT quantizer
- // -----------------------------------------------------------------------
-
- @Test(enabled = false)
- public void benchmarkQuantizers() {
- System.out.println("\n=== Quantizer Comparison (dim=" + DIMENSION + ", " +
NUM_VECTORS + " vectors) ===");
- System.out.printf("%-8s %-15s %-15s %-15s %-12s %-10s%n",
- "Type", "encode_us/vec", "decode_us/vec", "dist_us/vec", "bytes/vec",
"recall@10");
-
- // Train quantizers
- float[][] trainSample = new float[Math.min(10000, NUM_VECTORS)][];
- System.arraycopy(_vectors, 0, trainSample, 0, trainSample.length);
-
- ScalarQuantizer sq8 = ScalarQuantizer.train(trainSample, DIMENSION,
ScalarQuantizer.BitWidth.SQ8);
- ScalarQuantizer sq4 = ScalarQuantizer.train(trainSample, DIMENSION,
ScalarQuantizer.BitWidth.SQ4);
-
- // Encode all vectors
- byte[][] encodedSq8 = new byte[NUM_VECTORS][];
- byte[][] encodedSq4 = new byte[NUM_VECTORS][];
-
- // Benchmark encode
- long sq8EncodeNs = benchmarkEncode(sq8, _vectors, encodedSq8);
- long sq4EncodeNs = benchmarkEncode(sq4, _vectors, encodedSq4);
-
- // Benchmark decode
- long sq8DecodeNs = benchmarkDecode(sq8, encodedSq8);
- long sq4DecodeNs = benchmarkDecode(sq4, encodedSq4);
-
- // Benchmark distance
- long flatDistNs = benchmarkFlatDistance(_queries, _vectors);
- long sq8DistNs = benchmarkQuantizedDistance(sq8, _queries, encodedSq8);
- long sq4DistNs = benchmarkQuantizedDistance(sq4, _queries, encodedSq4);
-
- // Benchmark recall
- double sq8Recall = benchmarkQuantizedRecall(sq8, _queries, encodedSq8,
TOP_K);
- double sq4Recall = benchmarkQuantizedRecall(sq4, _queries, encodedSq4,
TOP_K);
-
- int distIterCount = Math.min(1000, NUM_VECTORS);
- System.out.printf("%-8s %-15s %-15s %-15.1f %-12d %-10.3f%n",
- "FLAT", "N/A", "N/A",
- (double) flatDistNs / NUM_QUERIES / distIterCount * 1000,
- DIMENSION * 4, 1.0);
- System.out.printf("%-8s %-15.1f %-15.1f %-15.1f %-12d %-10.3f%n",
- "SQ8",
- (double) sq8EncodeNs / NUM_VECTORS / 1000,
- (double) sq8DecodeNs / NUM_VECTORS / 1000,
- (double) sq8DistNs / NUM_QUERIES / distIterCount * 1000,
- sq8.getEncodedBytesPerVector(), sq8Recall);
- System.out.printf("%-8s %-15.1f %-15.1f %-15.1f %-12d %-10.3f%n",
- "SQ4",
- (double) sq4EncodeNs / NUM_VECTORS / 1000,
- (double) sq4DecodeNs / NUM_VECTORS / 1000,
- (double) sq4DistNs / NUM_QUERIES / distIterCount * 1000,
- sq4.getEncodedBytesPerVector(), sq4Recall);
- }
-
- // -----------------------------------------------------------------------
- // Benchmark 3: Pre-filter vs post-filter selectivity sweep
- // -----------------------------------------------------------------------
-
- @Test(enabled = false)
- public void benchmarkFilterSelectivity() {
- System.out.println("\n=== Filter Selectivity Sweep (pre-filter vs
no-filter) ===");
- System.out.printf("%-15s %-15s %-15s %-15s %-10s%n",
- "selectivity", "nofilt_us", "prefilt_us", "speedup", "recall");
-
- double[] selectivities = {1.0, 0.5, 0.2, 0.1, 0.05, 0.01};
- for (double sel : selectivities) {
- int filteredCount = (int) (NUM_VECTORS * sel);
- MutableRoaringBitmap filterBitmap = new MutableRoaringBitmap();
- for (int i = 0; i < filteredCount; i++) {
- filterBitmap.add(RANDOM.nextInt(NUM_VECTORS));
- }
-
- _ivfReader.setNprobe(8);
-
- // Unfiltered
- long unfilteredNs = 0;
- for (int q = 0; q < NUM_QUERIES; q++) {
- long start = System.nanoTime();
- _ivfReader.getDocIds(_queries[q], TOP_K);
- unfilteredNs += System.nanoTime() - start;
- }
-
- // Pre-filtered
- long filteredNs = 0;
- double totalRecall = 0;
- for (int q = 0; q < NUM_QUERIES; q++) {
- long start = System.nanoTime();
- ImmutableRoaringBitmap result = _ivfReader.getDocIds(_queries[q],
TOP_K, filterBitmap);
- filteredNs += System.nanoTime() - start;
-
- // Check all results are in filter
- org.roaringbitmap.IntIterator it = result.getIntIterator();
- int inFilter = 0;
- while (it.hasNext()) {
- if (filterBitmap.contains(it.next())) {
- inFilter++;
- }
- }
- totalRecall += result.getCardinality() > 0 ? (double) inFilter /
result.getCardinality() : 1.0;
- }
-
- _ivfReader.clearNprobe();
-
- double avgUnfiltered = (double) unfilteredNs / NUM_QUERIES / 1000;
- double avgFiltered = (double) filteredNs / NUM_QUERIES / 1000;
- double speedup = avgUnfiltered / Math.max(avgFiltered, 1);
-
- System.out.printf("%-15.2f %-15.1f %-15.1f %-15.2fx %-10.3f%n",
- sel, avgUnfiltered, avgFiltered, speedup, totalRecall / NUM_QUERIES);
- }
- }
-
- // -----------------------------------------------------------------------
- // Helpers
- // -----------------------------------------------------------------------
-
- private int[] bruteForceTopK(float[] query, int k) {
- float[] distances = new float[NUM_VECTORS];
- int[] indices = new int[NUM_VECTORS];
- for (int i = 0; i < NUM_VECTORS; i++) {
- distances[i] = euclideanDistance(query, _vectors[i]);
- indices[i] = i;
- }
- // Partial sort for top-k
- for (int i = 0; i < k; i++) {
- for (int j = i + 1; j < NUM_VECTORS; j++) {
- if (distances[j] < distances[i]) {
- float tmpD = distances[i];
- distances[i] = distances[j];
- distances[j] = tmpD;
- int tmpI = indices[i];
- indices[i] = indices[j];
- indices[j] = tmpI;
- }
- }
- }
- int[] result = new int[k];
- System.arraycopy(indices, 0, result, 0, k);
- return result;
- }
-
- private static float euclideanDistance(float[] a, float[] b) {
- float sum = 0;
- for (int d = 0; d < a.length; d++) {
- float diff = a[d] - b[d];
- sum += diff * diff;
- }
- return (float) Math.sqrt(sum);
- }
-
- private long benchmarkEncode(ScalarQuantizer sq, float[][] vectors, byte[][]
output) {
- long start = System.nanoTime();
- for (int i = 0; i < vectors.length; i++) {
- output[i] = sq.encode(vectors[i]);
- }
- return System.nanoTime() - start;
- }
-
- private long benchmarkDecode(ScalarQuantizer sq, byte[][] encoded) {
- long start = System.nanoTime();
- for (byte[] e : encoded) {
- sq.decode(e);
- }
- return System.nanoTime() - start;
- }
-
- private long benchmarkFlatDistance(float[][] queries, float[][] vectors) {
- int iterCount = Math.min(1000, vectors.length);
- long start = System.nanoTime();
- for (float[] query : queries) {
- for (int i = 0; i < iterCount; i++) {
- euclideanDistance(query, vectors[i]);
- }
- }
- return System.nanoTime() - start;
- }
-
- private long benchmarkQuantizedDistance(ScalarQuantizer sq, float[][]
queries, byte[][] encoded) {
- int iterCount = Math.min(1000, encoded.length);
- long start = System.nanoTime();
- for (float[] query : queries) {
- for (int i = 0; i < iterCount; i++) {
- sq.computeDistance(query, encoded[i],
VectorIndexConfig.VectorDistanceFunction.EUCLIDEAN);
- }
- }
- return System.nanoTime() - start;
- }
-
- private double benchmarkQuantizedRecall(ScalarQuantizer sq, float[][]
queries, byte[][] encoded, int k) {
- double totalRecall = 0;
- for (int q = 0; q < queries.length; q++) {
- int[] exactTopK = bruteForceTopK(queries[q], k);
- // Find approximate top-k using quantized distances
- float[] approxDists = new float[encoded.length];
- int[] approxIndices = new int[encoded.length];
- for (int i = 0; i < encoded.length; i++) {
- approxDists[i] = sq.computeDistance(queries[q], encoded[i],
- VectorIndexConfig.VectorDistanceFunction.EUCLIDEAN);
- approxIndices[i] = i;
- }
- for (int i = 0; i < k; i++) {
- for (int j = i + 1; j < encoded.length; j++) {
- if (approxDists[j] < approxDists[i]) {
- float tmpD = approxDists[i];
- approxDists[i] = approxDists[j];
- approxDists[j] = tmpD;
- int tmpI = approxIndices[i];
- approxIndices[i] = approxIndices[j];
- approxIndices[j] = tmpI;
- }
- }
- }
- int overlap = 0;
- for (int i = 0; i < k; i++) {
- for (int exact : exactTopK) {
- if (approxIndices[i] == exact) {
- overlap++;
- break;
- }
- }
- }
- totalRecall += (double) overlap / k;
- }
- return totalRecall / queries.length;
- }
-}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]