Skip to content

Commit

Permalink
add benchmark
Browse files Browse the repository at this point in the history
  • Loading branch information
vendelieu committed Oct 6, 2024
1 parent 2edc217 commit 8a7486c
Show file tree
Hide file tree
Showing 12 changed files with 232 additions and 73 deletions.
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,19 @@ dependencies {
}
```

# Comparison

```toml
main summary:
Benchmark Mode Cnt Score Error Units
JedisBenchmark.jedisGet thrpt 5 61059.312 ± 12766.457 ops/s
JedisBenchmark.jedisSet thrpt 5 63010.876 ± 3385.390 ops/s
KredsBenchmark.kredsGet thrpt 4 827647.673 ± 216763.090 ops/s
KredsBenchmark.kredsSet thrpt 4 843548.354 ± 163456.680 ops/s
RethisBenchmark.rethisGet thrpt 5 1186328.857 ± 717051.132 ops/s
RethisBenchmark.rethisSet thrpt 5 1176619.151 ± 1747469.858 ops/s
```

# Usage

### Connecting to Redis
Expand Down Expand Up @@ -97,7 +110,7 @@ transaction functionality also takes into account fail-state cases and gracefull
Also you can execute Redis commands using the execute method:

```kotlin
val result = client.execute(listOf("SET", "key", "value"))
val result = client.execute(listOf("SET".toArg(), "key".toArg(), "value".toArg()))
```

# Documentation
Expand Down
23 changes: 23 additions & 0 deletions benchmarks/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
plugins {
kotlin("jvm")
kotlin("plugin.allopen") version "2.0.20"
id("org.jetbrains.kotlinx.benchmark") version "0.4.11"
}

repositories {
mavenCentral()
}

dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:0.4.11")
implementation(project(":"))
implementation(libs.testcontainer.redis)
implementation("redis.clients:jedis:5.2.0")
implementation("io.github.crackthecodeabhi:kreds:0.9.1")
}

allOpen.annotation("org.openjdk.jmh.annotations.State")

benchmark {
targets.register("main")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package eu.vendeli.rethis.benchmarks

import kotlinx.benchmark.*
import org.openjdk.jmh.annotations.Timeout
import redis.clients.jedis.JedisPooled
import java.util.concurrent.TimeUnit

@BenchmarkMode(Mode.Throughput)
@State(Scope.Benchmark)
@Warmup(iterations = 2, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 5, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
@Timeout(time = 10, timeUnit = TimeUnit.SECONDS)
class JedisBenchmark {
private lateinit var jedis: JedisPooled

@Setup
fun setup() {
jedis = JedisPooled("localhost", 6379)
jedis.ping()
}

@TearDown
fun tearDown() {
jedis.close()
}

@Benchmark
fun jedisSet(bh: Blackhole) {

bh.consume(jedis.set("key", "value"))
}

@Benchmark
fun jedisGet(bh: Blackhole) {
bh.consume(jedis.get("key"))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package eu.vendeli.rethis.benchmarks

import io.github.crackthecodeabhi.kreds.connection.Endpoint
import io.github.crackthecodeabhi.kreds.connection.KredsClient
import io.github.crackthecodeabhi.kreds.connection.newClient
import kotlinx.benchmark.Benchmark
import kotlinx.benchmark.Blackhole
import kotlinx.benchmark.Setup
import kotlinx.benchmark.TearDown
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.openjdk.jmh.annotations.*
import java.util.concurrent.TimeUnit

@DelicateCoroutinesApi
@BenchmarkMode(Mode.Throughput)
@State(Scope.Benchmark)
@Warmup(iterations = 2, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 5, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
@Timeout(time = 10, timeUnit = TimeUnit.SECONDS)
class KredsBenchmark {
private lateinit var kreds: KredsClient

@Setup
fun setup() {
kreds = newClient(Endpoint("localhost", 6379))
GlobalScope.launch {
// kreds.use { it.ping("test") }
kreds.ping("test")
}
}

@TearDown
fun tearDown() {
kreds.close()
}

@Benchmark
fun kredsSet(bh: Blackhole) {
GlobalScope.launch {
bh.consume(
kreds.set("key", "value"),
// kreds.use { it.set("key", "value") },
)
}
}

@Benchmark
fun kredsGet(bh: Blackhole) {
GlobalScope.launch {
bh.consume(
// kreds.use { it.get("key") }
kreds.get("key"),
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package eu.vendeli.rethis.benchmarks

import eu.vendeli.rethis.ReThis
import eu.vendeli.rethis.commands.get
import eu.vendeli.rethis.commands.ping
import eu.vendeli.rethis.commands.set
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.openjdk.jmh.annotations.*
import org.openjdk.jmh.infra.Blackhole
import java.util.concurrent.TimeUnit

@DelicateCoroutinesApi
@BenchmarkMode(Mode.Throughput)
@State(Scope.Benchmark)
@Warmup(iterations = 2, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 5, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
@Timeout(time = 10, timeUnit = TimeUnit.SECONDS)
class RethisBenchmark {
private lateinit var rethis: ReThis

@Setup
fun setup() {
rethis = ReThis("localhost", 6379)
GlobalScope.launch { rethis.ping("test") }
}

@TearDown
fun tearDown() {
rethis.disconnect()
}

@Benchmark
fun rethisSet(bh: Blackhole) {
GlobalScope.launch {
bh.consume(rethis.runCatching { set("key", "value") })
}
}

@Benchmark
fun rethisGet(bh: Blackhole) {
GlobalScope.launch {
bh.consume(rethis.runCatching { get("key") })
}
}
}
8 changes: 8 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,2 +1,10 @@
rootProject.name = "re.this"

include("benchmarks")

pluginManagement {
repositories {
gradlePluginPortal()
mavenCentral()
}
}
12 changes: 6 additions & 6 deletions src/commonMain/kotlin/eu/vendeli/rethis/ReThis.kt
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,12 @@ class ReThis(
if (ctxConn != null) {
ctxConn!!.output.writeBuffer(pipelinedPayload)
ctxConn!!.output.flush()
requests.forEach { _ -> responses.add(ctxConn!!.input.readRedisMessage()) }
requests.forEach { _ -> responses.add(ctxConn!!.input.readRedisMessage(cfg.charset)) }
} else {
connectionPool.use { connection ->
connection.output.writeBuffer(pipelinedPayload)
connection.output.flush()
requests.forEach { _ -> responses.add(connection.input.readRedisMessage()) }
requests.forEach { _ -> responses.add(connection.input.readRedisMessage(cfg.charset)) }
}
}
requests.clear()
Expand All @@ -89,7 +89,7 @@ class ReThis(
logger.debug("Started transaction")
conn.output.writeBuffer(bufferValues(listOf("MULTI".toArg()), cfg.charset))
conn.output.flush()
require(conn.input.readRedisMessage().value == "OK")
require(conn.input.readRedisMessage(cfg.charset).value == "OK")

var e: Throwable? = null
coLaunch(currentCoroutineContext() + CoLocalConn(conn)) {
Expand All @@ -98,15 +98,15 @@ class ReThis(
e?.also {
conn.output.writeBuffer(bufferValues(listOf("DISCARD".toArg()), cfg.charset))
conn.output.flush()
require(conn.input.readRedisMessage().value == "OK")
require(conn.input.readRedisMessage(cfg.charset).value == "OK")
logger.error("Transaction canceled", it)
return@use emptyList()
}

logger.debug("Transaction completed")
conn.output.writeBuffer(bufferValues(listOf("EXEC".toArg()), cfg.charset))
conn.output.flush()
conn.input.readRedisMessage().unwrapList()
conn.input.readRedisMessage(cfg.charset).unwrapList()
}

@ReThisInternal
Expand Down Expand Up @@ -137,6 +137,6 @@ class ReThis(
logger.trace("Executing request with such payload $payload")
output.writeBuffer(bufferValues(payload, cfg.charset))
output.flush()
return input.readRedisMessage(raw)
return input.readRedisMessage(cfg.charset, raw)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import kotlin.contracts.InvocationKind
import kotlin.contracts.contract

internal class ConnectionPool(
private val client: ReThis,
internal val client: ReThis,
private val address: SocketAddress,
) {
internal val logger = KtorSimpleLogger("eu.vendeli.rethis.ConnectionPool")
Expand Down Expand Up @@ -55,7 +55,7 @@ internal class ConnectionPool(
conn.output.writeBuffer(reqBuffer)
conn.output.flush()
repeat(requests) {
logger.trace("Connection establishment response: " + conn.input.readRedisMessage())
logger.trace("Connection establishment response: " + conn.input.readRedisMessage(client.cfg.charset))
}

return conn
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ internal suspend inline fun ReThis.registerSubscription(

while (isActive) {
conn.input.awaitContent()
val msg = conn.input.readRedisMessage()
val msg = conn.input.readRedisMessage(cfg.charset)
val input = if (msg is Push) msg.value else msg.safeCast<RArray>()?.value
logger.debug("Handling event in $target channel subscription")

Expand Down
4 changes: 2 additions & 2 deletions src/commonMain/kotlin/eu/vendeli/rethis/utils/RequestUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ internal fun Sink.writeRedisValue(
is Array<*> -> writeArrayValue(data, charset)

is StringArg -> writeByteArray(data.value.toByteArray(charset))
is LongArg -> writeByteArray(data.value.toString(10).toByteArray(charset))
is IntArg -> writeByteArray(data.value.toString(10).toByteArray(charset))
is LongArg -> writeByteArray(data.value.toString().toByteArray(charset))
is IntArg -> writeByteArray(data.value.toString().toByteArray(charset))
is DoubleArg -> writeByteArray(data.value.toString().toByteArray(charset))
is BaArg -> writeByteArray(data.value)
}
Expand Down
Loading

0 comments on commit 8a7486c

Please sign in to comment.