Skip to content

Commit

Permalink
Performance: use parallel accumulators to speed up PanamaFloatVectorO…
Browse files Browse the repository at this point in the history
…ps dotProduct and l2Distance (96% recall at 204 qps) (#620)
  • Loading branch information
alexklibisz authored Dec 3, 2023
1 parent 49baf24 commit ac3fed8
Show file tree
Hide file tree
Showing 9 changed files with 241 additions and 99 deletions.
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

0 comments on commit ac3fed8

Please sign in to comment.