Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Performance: use parallel accumulators to speed up PanamaFloatVectorOps dotProduct and l2Distance (96% recall at 204 qps) #620

Merged
merged 12 commits into from
Dec 3, 2023
Merged
6 changes: 3 additions & 3 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
timeout-minutes: 1
with:
distribution: 'adopt'
java-version: 19
java-version: 21
cache: 'sbt'
- uses: arduino/setup-task@v1
timeout-minutes: 1
Expand Down Expand Up @@ -78,7 +78,7 @@ jobs:
timeout-minutes: 1
with:
distribution: 'adopt'
java-version: 19
java-version: 21
cache: 'sbt'
- uses: actions/setup-python@v4
timeout-minutes: 1
Expand Down Expand Up @@ -122,7 +122,7 @@ jobs:
timeout-minutes: 1
with:
distribution: 'adopt'
java-version: 19
java-version: 21
cache: 'sbt'
- uses: arduino/setup-task@v1
timeout-minutes: 1
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
- uses: actions/setup-java@v3
with:
distribution: 'adopt'
java-version: 19
java-version: 21
cache: 'sbt'
- uses: arduino/setup-task@v1
with:
Expand Down
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
java oracle-19.0.2
java oracle-21.0.1
python 3.10.8
2 changes: 1 addition & 1 deletion docs/pages/performance/fashion-mnist/plot.b64

Large diffs are not rendered by default.

Binary file modified docs/pages/performance/fashion-mnist/plot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 8 additions & 8 deletions docs/pages/performance/fashion-mnist/results.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
|Model|Parameters|Recall|Queries per Second|
|---|---|---|---|
|eknn-l2lsh|L=100 k=4 w=1024 candidates=500 probes=0|0.378|349.851|
|eknn-l2lsh|L=100 k=4 w=1024 candidates=1000 probes=0|0.446|296.219|
|eknn-l2lsh|L=100 k=4 w=1024 candidates=500 probes=3|0.635|286.468|
|eknn-l2lsh|L=100 k=4 w=1024 candidates=1000 probes=3|0.716|244.536|
|eknn-l2lsh|L=100 k=4 w=2048 candidates=500 probes=0|0.767|315.023|
|eknn-l2lsh|L=100 k=4 w=2048 candidates=1000 probes=0|0.847|264.479|
|eknn-l2lsh|L=100 k=4 w=2048 candidates=500 probes=3|0.922|220.714|
|eknn-l2lsh|L=100 k=4 w=2048 candidates=1000 probes=3|0.960|193.597|
|eknn-l2lsh|L=100 k=4 w=1024 candidates=500 probes=0|0.378|377.213|
|eknn-l2lsh|L=100 k=4 w=1024 candidates=1000 probes=0|0.447|320.000|
|eknn-l2lsh|L=100 k=4 w=1024 candidates=500 probes=3|0.635|302.384|
|eknn-l2lsh|L=100 k=4 w=1024 candidates=1000 probes=3|0.717|259.201|
|eknn-l2lsh|L=100 k=4 w=2048 candidates=500 probes=0|0.767|335.978|
|eknn-l2lsh|L=100 k=4 w=2048 candidates=1000 probes=0|0.846|287.923|
|eknn-l2lsh|L=100 k=4 w=2048 candidates=500 probes=3|0.921|229.917|
|eknn-l2lsh|L=100 k=4 w=2048 candidates=1000 probes=3|0.960|204.375|
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package com.klibisz.elastiknn.jmhbenchmarks

import com.klibisz.elastiknn.api.Vec
import com.klibisz.elastiknn.vectors._
import org.apache.lucene.util.VectorUtil
import org.openjdk.jmh.annotations._

import scala.util.Random

@State(Scope.Benchmark)
class FloatVectorOpsBenchmarkState {
implicit private val rng: Random = new Random(0)
val v1 = Vec.DenseFloat.random(999).values
val v2 = Vec.DenseFloat.random(999).values
val panama = new PanamaFloatVectorOps
val default = new DefaultFloatVectorOps
}

class FloatVectorOpsBenchmark {

@Benchmark
@BenchmarkMode(Array(Mode.Throughput))
@Fork(value = 1)
@Warmup(time = 1, iterations = 5)
@Measurement(time = 1, iterations = 5)
def cosineSimilarityPanama(state: FloatVectorOpsBenchmarkState): Double =
state.panama.cosineSimilarity(state.v1, state.v2)

@Benchmark
@BenchmarkMode(Array(Mode.Throughput))
@Fork(value = 1)
@Warmup(time = 1, iterations = 5)
@Measurement(time = 1, iterations = 5)
def cosineSimilarityDefault(state: FloatVectorOpsBenchmarkState): Double =
state.default.cosineSimilarity(state.v1, state.v2)

@Benchmark
@BenchmarkMode(Array(Mode.Throughput))
@Fork(value = 1)
@Warmup(time = 1, iterations = 5)
@Measurement(time = 1, iterations = 5)
def dotProductDefault(state: FloatVectorOpsBenchmarkState): Double =
state.default.dotProduct(state.v1, state.v2)

@Benchmark
@BenchmarkMode(Array(Mode.Throughput))
@Fork(value = 1)
@Warmup(time = 1, iterations = 5)
@Measurement(time = 1, iterations = 5)
def dotProductPanama(state: FloatVectorOpsBenchmarkState): Double =
state.panama.dotProduct(state.v1, state.v2)

@Benchmark
@BenchmarkMode(Array(Mode.Throughput))
@Fork(value = 1)
@Warmup(time = 1, iterations = 5)
@Measurement(time = 1, iterations = 5)
def dotProductPanamaSimple(state: FloatVectorOpsBenchmarkState): Double =
state.panama.dotProductSimple(state.v1, state.v2)

@Benchmark
@BenchmarkMode(Array(Mode.Throughput))
@Fork(value = 1)
@Warmup(time = 1, iterations = 5)
@Measurement(time = 1, iterations = 5)
def dotProductLucene(state: FloatVectorOpsBenchmarkState): Float =
VectorUtil.dotProduct(state.v1, state.v2)

@Benchmark
@BenchmarkMode(Array(Mode.Throughput))
@Fork(value = 1)
@Warmup(time = 1, iterations = 5)
@Measurement(time = 1, iterations = 5)
def l1DistancePanama(state: FloatVectorOpsBenchmarkState): Double =
state.panama.l1Distance(state.v1, state.v2)

@Benchmark
@BenchmarkMode(Array(Mode.Throughput))
@Fork(value = 1)
@Warmup(time = 1, iterations = 5)
@Measurement(time = 1, iterations = 5)
def l1DistanceDefault(state: FloatVectorOpsBenchmarkState): Double =
state.default.l1Distance(state.v1, state.v2)

@Benchmark
@BenchmarkMode(Array(Mode.Throughput))
@Fork(value = 1)
@Warmup(time = 1, iterations = 5)
@Measurement(time = 1, iterations = 5)
def l2DistancePanama(state: FloatVectorOpsBenchmarkState): Double =
state.panama.l2Distance(state.v1, state.v2)

@Benchmark
@BenchmarkMode(Array(Mode.Throughput))
@Fork(value = 1)
@Warmup(time = 1, iterations = 5)
@Measurement(time = 1, iterations = 5)
def l2DistancePanamaSimple(state: FloatVectorOpsBenchmarkState): Double =
state.panama.l2DistanceSimple(state.v1, state.v2)

@Benchmark
@BenchmarkMode(Array(Mode.Throughput))
@Fork(value = 1)
@Warmup(time = 1, iterations = 5)
@Measurement(time = 1, iterations = 5)
def l2DistanceDefault(state: FloatVectorOpsBenchmarkState): Double =
state.default.l2Distance(state.v1, state.v2)

@Benchmark
@BenchmarkMode(Array(Mode.Throughput))
@Fork(value = 1)
@Warmup(time = 1, iterations = 5)
@Measurement(time = 1, iterations = 5)
def l2DistanceLucene(state: FloatVectorOpsBenchmarkState): Double =
Math.sqrt(VectorUtil.squareDistance(state.v1, state.v2) * 1d)
}

This file was deleted.

Loading