booblik
Wiki

booblik-benchmark

Generated page

Model gemma-mtp, commit ef58254ca7be, 2026-08-16, sources: 6. Edit the code or the hand-written documentation instead.

What this module is responsible for

The booblik-benchmark module provides a comprehensive suite of performance measurements for the booblik project. It includes JMH-based benchmarks to measure throughput and latency of core components, as well as specialized "probes" designed to answer specific architectural questions regarding durability, recovery, and abstraction overhead.

Diagram

MeasurementDir and volatile filesystems

To prevent misleading results where fsync operations return instantly because they are running on RAM-backed filesystems like tmpfs, the MeasurementDir object enforces that all measurements occur on real physical storage. As defined in MeasurementDir.kt:32-47, the system explicitly refuses to create a directory if the underlying FileStore type is identified as tmpfs or ramfs.

More: MeasurementDir and volatile filesystems

FetchDecodeBenchmark and the JVM reader cost

This benchmark addresses M-140 by comparing the performance of the legacy ResponseReader (which uses ByteBuffer) against the new ResponseDecoder (which uses ByteArray and index arithmetic). As detailed in FetchDecodeBenchmark.kt:37-40, the goal is to determine if merging these two decoders imposes a measurable cost on the platform where reading occurs, with the test varying recordSize from 64 B to 8 KiB.

More: FetchDecodeBenchmark and the JVM reader cost

FlowOverheadBenchmark and the cost of abstraction

This benchmark isolates the cost of the Kotlin Flow machinery by removing the network component and comparing three distinct execution shapes: a standard loop, a coldFlow, and a bufferedFlow. According to FlowOverheadBenchmark.kt:24-35, this allows the developer to distinguish between the inherent cost of the Flow abstraction and the decoupling cost introduced by a channel/buffer.

PartitionWriterBenchmark and batching efficiency

This benchmark measures the overhead of the write actor and the efficiency gains provided by batching. As described in PartitionWriterBenchmark.kt:28-43, it compares a single-record unit against various batchSize settings and AckPolicy configurations to determine the "actor's price" in terms of records per second.

GroupCommitBenchmark and the durability barrier

This benchmark analyzes how throughput scales as the number of concurrent producers increases and how the groupWindowMillis affects the durability barrier. As noted in GroupCommitBenchmark.kt:34-43, it tests the hypothesis that a writer collecting multiple producers into a single group can increase throughput without significantly increasing the latency of the individual producers.

Benchmark configuration and task registration

The module uses a custom Gradle configuration to manage JMH targets and specialized probes. The build.gradle.kts file defines several benchmark configurations:

ConfigurationDescription
mainFull run with 5 warmups and 10 iterations
writerFocuses on PartitionWriterBenchmark
flowFocuses on FlowOverheadBenchmark
decodeFocuses on FetchDecodeBenchmark
ciExcludes GroupCommitBenchmark and uses flushEveryAppend = false
quickShort run for rapid feedback (2 warmups, 3 iterations)

The build.gradle.kts:132-140 also registers several probes as JavaExec tasks, which are ordinary programs used to answer specific architectural questions rather than providing average throughput.

Key files

FileLinesWhat is there
…/benchmark/MeasurementDir.kt27-49Logic for creating measurement directories and preventing volatile filesystems.
booblik-benchmark/build.gradle.kts57-125JMH target registrations and benchmark configurations.
…/benchmark/FetchDecodeBenchmark.kt37-40Benchmark class for comparing JVM reader and decoder.
…/benchmark/FlowOverheadBenchmark.kt18-35Benchmark class for measuring Flow abstraction overhead.
…/benchmark/GroupCommitBenchmark.kt29-43Benchmark class for measuring group commit scaling.
…/benchmark/PartitionWriterBenchmark.kt28-43Benchmark class for measuring batching and acknowledgement costs.

Behaviour that surprising

  • The MeasurementDir object treats a volatile filesystem as a refusal rather than a warning, throwing an IllegalStateException to prevent users from believing "fast" but false results (MeasurementDir.kt:37-47).
  • Benchmarks are placed in the main source set rather than a dedicated benchmark source set so that any refactoring that breaks a benchmark immediately breaks the build (build.gradle.kts:54-56).
  • In GroupCommitBenchmark, the score is reported as invocations per second, meaning the actual records per second must be calculated by multiplying the score by the number of producers (GroupCommitBenchmark.kt:41-43).

On this page