Skip to content

Commit e304390

Browse files
dfa1claude
andcommitted
bench: add jniReadClose/javaReadClose benchmarks for ALP-encoded F64
ALP result: JNI 57.3 ops/s vs Java 44.3 ops/s — Rust ALP decode currently faster; per-element float multiply loop is next target. Update README with full comparison table (volume + close). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 00fde52 commit e304390

2 files changed

Lines changed: 57 additions & 9 deletions

File tree

README.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,19 @@ Pure-Java reader/writer for the [Vortex](https://github.com/spiraldb/vortex) col
66

77
## Performance
88

9-
`RustVsJavaReadBenchmark` — 10M OHLC rows, project + sum `volume` (I64) column,
10-
JMH throughput (higher = better), Apple M-series, Java 25:
9+
`RustVsJavaReadBenchmark` — 10M OHLC rows, JMH throughput (higher = better), Apple M-series, Java 25:
1110

12-
| Reader | Throughput | vs JNI |
13-
|---------------|-------------|---------|
14-
| vortex-jni | 51.9 ops/s | |
15-
| vortex-java | 120.7 ops/s | **2.3×** |
11+
| Column | Encoding | vortex-jni | vortex-java | ratio |
12+
|-----------------|---------------|-------------|--------------|--------------|
13+
| `volume` (I64) | primitive | 51.9 ops/s | 120.7 ops/s | **Java 2.3×** |
14+
| `close` (F64) | ALP | 57.3 ops/s | 44.3 ops/s | JNI 1.3× |
1615

17-
JNI overhead: Arrow C Data Interface handshake + JNI boundary crossing + `VectorSchemaRoot`
18-
materialisation per batch. vortex-java reads directly from the mmap region via `MemorySegment`
19-
with zero copies and no intermediate format.
16+
`volume` (I64, primitive encoding): vortex-java wins decisively — no JNI boundary, no Arrow
17+
materialisation, direct `MemorySegment` read from the mmap region.
18+
19+
`close` (F64, ALP-encoded): JNI currently wins — the Rust ALP inverse transform is more
20+
optimised than the Java implementation. The per-element float multiply loop is the next
21+
target for improvement.
2022

2123
## Motivation
2224

performance/src/main/java/io/github/dfa1/vortex/performance/RustVsJavaReadBenchmark.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,32 @@ public long jniReadVolume() throws IOException {
157157
return sum;
158158
}
159159

160+
/// JNI read: project on "close" (F64, ALP-encoded), sum all values.
161+
@Benchmark
162+
public double jniReadClose() throws IOException {
163+
String uri = benchFile.toAbsolutePath().toUri().toString();
164+
var opts = ScanOptions.builder()
165+
.projection(Expression.select(new String[]{"close"}, Expression.root()))
166+
.build();
167+
168+
double sum = 0.0;
169+
DataSource ds = DataSource.open(SESSION, uri);
170+
Scan scan = ds.scan(opts);
171+
while (scan.hasNext()) {
172+
Partition partition = scan.next();
173+
try (ArrowReader reader = partition.scanArrow(allocator)) {
174+
while (reader.loadNextBatch()) {
175+
VectorSchemaRoot root = reader.getVectorSchemaRoot();
176+
Float8Vector closeVec = (Float8Vector) root.getVector("close");
177+
for (int i = 0; i < root.getRowCount(); i++) {
178+
sum += closeVec.get(i);
179+
}
180+
}
181+
}
182+
}
183+
return sum;
184+
}
185+
160186
// ── JNI file generation ───────────────────────────────────────────────────
161187

162188
/// Java read: project on "volume", sum all values.
@@ -179,6 +205,26 @@ public long javaReadVolume() throws IOException {
179205
return sum;
180206
}
181207

208+
/// Java read: project on "close" (F64, ALP-encoded), sum all values.
209+
@Benchmark
210+
public double javaReadClose() throws IOException {
211+
double sum = 0.0;
212+
try (VortexReader vf = VortexReader.open(benchFile, registry)) {
213+
var iter = vf.scan(io.github.dfa1.vortex.scan.ScanOptions.columns("close"));
214+
while (iter.hasNext()) {
215+
ScanResult r = iter.next();
216+
Array arr = r.columns().get("close");
217+
var layout = ValueLayout.JAVA_DOUBLE_UNALIGNED;
218+
MemorySegment buffer = arr.buffer(0);
219+
long count = buffer.byteSize() / layout.byteSize();
220+
for (long i = 0; i < count; i++) {
221+
sum += buffer.getAtIndex(layout, i);
222+
}
223+
}
224+
}
225+
return sum;
226+
}
227+
182228
private void writeJni(Path path) throws IOException {
183229
String uri = path.toAbsolutePath().toUri().toString();
184230
try (dev.vortex.api.VortexWriter writer = dev.vortex.api.VortexWriter.create(

0 commit comments

Comments
 (0)