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

Java benchmark JNA, JNI and uniffi FFI sync clients together #30

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions benchmarks/install_and_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ runNode=0
runCsharp=0
runJava=0
runRust=0
concurrentTasks="1 10 100 1000"
dataSize="100 4000"
clientCount="1"
concurrentTasks="10 100 1000"
dataSize="100"
clientCount="2"
chosenClients="all"
host="localhost"
port=6379
Expand Down Expand Up @@ -71,18 +71,20 @@ function runCSharpBenchmark(){
}

function runJavaBenchmark(){
cd ${BENCH_FOLDER}/../kotlin
./gradlew build
cd ${BENCH_FOLDER}/../java
echo "./gradlew run --args=\"--resultsFile=${BENCH_FOLDER}/$1 --clients $chosenClients --host $host --port $port\""
# ./gradlew run --args="--resultsFile=../$1 --dataSize $2 --concurrentTasks $concurrentTasks --clients $chosenClients --host $host --port $port --clientCount $clientCount $tlsFlag"
./gradlew run --args="--resultsFile=${BENCH_FOLDER}/$1 --clients $chosenClients --host $host --port $port"
cd ${BENCH_FOLDER}/java
cargo build
# ./gradlew build
# echo ./gradlew :benchmarks:run --args="-resultsFile ${BENCH_FOLDER}/$1 -dataSize \"$2\" -concurrentTasks \"$concurrentTasks\" -clients \"$chosenClients\" -host $host -port $port -clientCount \"$clientCount\" $tlsFlag"
./gradlew :benchmarks:run --args="-resultsFile ${BENCH_FOLDER}/$1 -dataSize \"$2\" -concurrentTasks \"$concurrentTasks\" -clients \"$chosenClients\" -host $host -port $port -clientCount \"$clientCount\" $tlsFlag"
}

function runRustBenchmark(){
rustConcurrentTasks=
for value in $concurrentTasks
do
rustConcurrentTasks=$rustConcurrentTasks" --concurrentTasks "$value
rustConcurrentTasks="$rustConcurrentTasks --concurrentTasks $value"
done
cd ${BENCH_FOLDER}/rust
cargo run --release -- --resultsFile=../$1 --dataSize $2 $rustConcurrentTasks --host $host --clientCount $clientCount $tlsFlag $clusterFlag $portFlag
Expand Down Expand Up @@ -198,7 +200,7 @@ do
-java)
runAllBenchmarks=0
runJava=1
chosenClients="Babushka"
chosenClients="Lettuce,JNI_FFI,JNA_FFI,Kotlin"
;;
-lettuce)
runAllBenchmarks=0
Expand Down
3 changes: 0 additions & 3 deletions benchmarks/utilities/csv_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,3 @@
json_object["language"] = language
values = [json_object[field] for field in base_fields]
writer.writerow(values)

for json_file_full_path in sys.argv[1:-1]:
os.remove(json_file_full_path)
8 changes: 8 additions & 0 deletions java/.gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
# Ignore Gradle project-specific cache directory
.gradle

# Ignore gradle wrapper files (they are managed by gradle)
gradlew
gradlew.bat
gradle

# Ignore Gradle build output directory
build

# IDE files
.idea

# Ignore generated files (e.g. protobuf)
generated
11 changes: 10 additions & 1 deletion java/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,18 @@ crate-type = ["cdylib"]
redis = { path = "../submodules/redis-rs/redis", features = ["aio", "tokio-comp", "connection-manager", "tls", "tokio-rustls-comp"] }
babushka = { path = "../babushka-core" }
tokio = { version = "^1", features = ["rt", "macros", "rt-multi-thread", "time"] }
logger_core = {path = "../logger_core"}
logger_core = { path = "../logger_core" }
tracing-subscriber = "0.3.16"
jni = "0.21.1"
env_logger = "0.10.0"
log = "0.4.20"
thiserror = "1.0.49"
num-derive = "0.4.1"
num-traits = "0.2.17"

[profile.release]
lto = true
debug = true

[build-dependencies]
cbindgen = "0.26.0"
7 changes: 7 additions & 0 deletions java/benchmarks/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ dependencies {

compileOnly 'org.projectlombok:lombok:1.18.30'
annotationProcessor 'org.projectlombok:lombok:1.18.30'

// Required for interop
implementation "net.java.dev.jna:jna:5.8.0"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.20"
implementation files("../../kotlin/client/build/libs/kotlinbabushka-0.0.1.jar")
}

// Apply a specific Java toolchain to ease working on different environments.
Expand All @@ -34,6 +39,8 @@ java {
application {
// Define the main class for the application.
mainClass = 'javababushka.benchmarks.BenchmarkingApp'
// mainClass = 'javababushka.benchmarks.babushka.Jni'
applicationDefaultJvmArgs += "-Djava.library.path=${projectDir}/../target/debug"
}

tasks.withType(Test) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Stream;
import javababushka.benchmarks.babushka.JnaFfi;
import javababushka.benchmarks.babushka.JniFfi;
import javababushka.benchmarks.babushka.KotlinClient;
import javababushka.benchmarks.jedis.JedisClient;
import javababushka.benchmarks.jedis.JedisPseudoAsyncClient;
import javababushka.benchmarks.lettuce.LettuceAsyncClient;
Expand Down Expand Up @@ -46,6 +49,9 @@ public static void main(String[] args) {

for (ClientName client : runConfiguration.clients) {
switch (client) {
case JNI_FFI:
testClientSetGet(JniFfi::new, runConfiguration, false);
break;
case JEDIS:
testClientSetGet(JedisClient::new, runConfiguration, false);
break;
Expand All @@ -58,6 +64,12 @@ public static void main(String[] args) {
case LETTUCE_ASYNC:
testClientSetGet(LettuceAsyncClient::new, runConfiguration, true);
break;
case JNA_FFI:
testClientSetGet(JnaFfi::new, runConfiguration, false);
break;
case KOTLIN:
testClientSetGet(KotlinClient::new, runConfiguration, false);
break;
case BABUSHKA:
System.out.println("Babushka not yet configured");
break;
Expand Down Expand Up @@ -137,7 +149,9 @@ private static RunConfiguration verifyOptions(CommandLine line) throws ParseExce
return Stream.of(
ClientName.JEDIS,
ClientName.JEDIS_ASYNC,
ClientName.BABUSHKA,
ClientName.JNA_FFI,
ClientName.JNI_FFI,
ClientName.KOTLIN,
// ClientName.BABUSHKA_ASYNC,
ClientName.LETTUCE,
ClientName.LETTUCE_ASYNC);
Expand All @@ -149,8 +163,9 @@ private static RunConfiguration verifyOptions(CommandLine line) throws ParseExce
case ALL_SYNC:
return Stream.of(
ClientName.JEDIS,
// ClientName.BABUSHKA,
ClientName.LETTUCE);
ClientName.JNA_FFI,
ClientName.LETTUCE,
ClientName.JNI_FFI);
default:
return Stream.of(e);
}
Expand Down Expand Up @@ -183,7 +198,7 @@ private static int[] parseIntListOption(String line) throws ParseException {
lineValue = lineValue.substring(1, lineValue.length() - 1);
}
// check if it's the correct format
if (!lineValue.matches("\\d+(\\s+\\d+)?")) {
if (!lineValue.matches("\\d+(\\s+\\d+)*")) {
throw new ParseException("Invalid option: " + line);
}
// split the string into a list of integers
Expand All @@ -195,8 +210,11 @@ public enum ClientName {
JEDIS_ASYNC("Jedis async"),
LETTUCE("Lettuce"),
LETTUCE_ASYNC("Lettuce async"),
BABUSHKA("Babushka"),
JNA_FFI("JNA FFI"),
BABUSHKA_ASYNC("Babushka async"),
JNI_FFI("JNI FFI"),
BABUSHKA("Babushka"),
KOTLIN("Kotlin"),
ALL("All"),
ALL_SYNC("All sync"),
ALL_ASYNC("All async");
Expand Down Expand Up @@ -232,12 +250,11 @@ public static class RunConfiguration {
public RunConfiguration() {
configuration = "Release";
resultsFile = Optional.empty();
dataSize = new int[] {100, 4000};
concurrentTasks = new int[] {100, 1000};
dataSize = new int[] {20};
concurrentTasks = new int[] {10, 100};
clients =
new ClientName[] {
// ClientName.BABUSHKA_ASYNC,
ClientName.JEDIS, ClientName.JEDIS_ASYNC, ClientName.LETTUCE, ClientName.LETTUCE_ASYNC
ClientName.LETTUCE, ClientName.JNI_FFI, ClientName.JNA_FFI, ClientName.KOTLIN
};
host = "localhost";
port = 6379;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package javababushka.benchmarks.babushka;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Structure;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import javababushka.benchmarks.SyncClient;
import javababushka.benchmarks.utils.ConnectionSettings;

public class JnaFfi implements SyncClient {

private final long ptr = lib.init_client0(42);

// = enum
public static enum ResultType {
Str(0),
Int(1),
Nil(2),
Data(3),
Bulk(4),
Ok(5),
Err(6),
Undef(-1);

private int id;

ResultType(int id) {
this.id = id;
}

public static ResultType of(int val) {
switch (val) {
case 0:
return ResultType.Str;
case 1:
return ResultType.Int;
case 2:
return ResultType.Nil;
case 3:
return ResultType.Data;
case 4:
return ResultType.Bulk;
case 5:
return ResultType.Ok;
case 6:
return ResultType.Err;
default:
return ResultType.Undef;
}
}
}

public interface RustLib extends Library {

@Structure.FieldOrder({"error", "value_type", "string", "num"})
public static class BabushkaResult extends Structure {
public BabushkaResult() {
error = null;
value_type = 0;
string = null;
num = 0;
}

public static class ByValue extends BabushkaResult implements Structure.ByValue {}

public String error = null;
public int value_type = 0;
public String string = null;
public long num = 0;
}
;

public long init_client0(int data);

public BabushkaResult.ByValue connect0(long client, String address);

public BabushkaResult.ByValue set0(long client, String key, String value);

public BabushkaResult.ByValue get0(long client, String key);
}

private static final RustLib lib;

static {
var is_win = System.getProperty("os.name").contains("Windows");
var targetDir =
Paths.get(
"jna-stuff", "build", "resources", "main", is_win ? "win32-x86-64" : "linux-x86-64")
.toAbsolutePath();

// System.setProperty("jna.debug_load", "true");
System.setProperty("jna.library.path", targetDir.toString());

var created = targetDir.toFile().mkdirs();
try {
if (is_win) {
Files.copy(
Paths.get(System.getProperty("user.dir"), "target", "debug", "javababushka.dll"),
Paths.get(targetDir.toString(), "javababushka.dll"),
StandardCopyOption.REPLACE_EXISTING);
} else {
Files.copy(
Paths.get(
System.getProperty("user.dir"), "..", "target", "debug", "libjavababushka.so"),
Paths.get(targetDir.toString(), "libjavababushka.so"),
StandardCopyOption.REPLACE_EXISTING);
}
} catch (IOException e) {
System.out.printf("Failed to copy lib: %s%n", e.getMessage());
e.printStackTrace();
}

lib = Native.load("javababushka", RustLib.class);
}

@Override
public void connectToRedis() {
connectToRedis(new ConnectionSettings("localhost", 6379, false));
}

@Override
public void connectToRedis(ConnectionSettings connectionSettings) {
var connStr =
String.format(
"%s://%s:%d",
connectionSettings.useSsl ? "rediss" : "redis",
connectionSettings.host,
connectionSettings.port);
lib.connect0(ptr, connStr);
}

@Override
public String getName() {
return "JNA babushka";
}

@Override
public void set(String key, String value) {
var res = lib.set0(ptr, key, value);
}

@Override
public String get(String key) {
var res = lib.get0(ptr, key);
if (res.value_type == ResultType.Str.id) {
return res.string;
}
return res.error;
}
}
Loading
Loading