Skip to content

Commit 08643b1

Browse files
committed
Load shared libs impls
1 parent 2a45954 commit 08643b1

9 files changed

Lines changed: 156 additions & 29 deletions

File tree

benchmark/Makefile

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,26 @@ $(BUILD_DIR):
2222
mkdir -p $@
2323
echo "" > $(IMPLEMENTATIONS_INC)
2424

25-
$(GO_LIB): $(BUILD_DIR)
25+
$(GO_LIB): | $(BUILD_DIR)
2626
cd ./aws-sdk-go-v2 && go build -buildmode=c-shared -o ../$(BUILD_DIR)/libgo$(so_ext) .
2727

28-
$(CPP_LIB): $(BUILD_DIR)
29-
c++ -std=c++23 -shared -fPIC s3cpp/task.cpp -o $(BUILD_DIR)/libs3cpp$(so_ext)
28+
$(CPP_LIB): | $(BUILD_DIR)
29+
c++ -std=c++26 -shared -fPIC s3cpp/task.cpp -o $(BUILD_DIR)/libs3cpp$(so_ext)
3030

31-
$(RUST_LIB): $(BUILD_DIR)
31+
$(RUST_LIB): | $(BUILD_DIR)
3232
cargo build --release --manifest-path ./aws-sdk-rust/Cargo.toml
3333
mv ./aws-sdk-rust/target/release/librust$(so_ext) $(BUILD_DIR)/.
3434

35-
$(IMPLEMENTATIONS_INC): $(GO_LIB) $(CPP_LIB) $(RUST_LIB) $(BUILD_DIR)
35+
$(IMPLEMENTATIONS_INC): $(GO_LIB) $(CPP_LIB) $(RUST_LIB) | $(BUILD_DIR)
3636
printf '"./%s",\n' $(GO_LIB) $(CPP_LIB) $(RUST_LIB) > $@
3737

38+
bench: $(IMPLEMENTATIONS_INC) $(GO_LIB) $(CPP_LIB) $(RUST_LIB) | $(BUILD_DIR)
39+
c++ -std=c++26 main.cpp -o $(BUILD_DIR)/bench
40+
41+
test: $(IMPLEMENTATIONS_INC) $(GO_LIB) $(CPP_LIB) $(RUST_LIB) | $(BUILD_DIR)
42+
c++ -std=c++26 test.cpp -o $(BUILD_DIR)/test
43+
44+
3845
.PHONY: all clean
3946
clean:
4047
rm -rf $(BUILD_DIR)

benchmark/aws-sdk-go-v2/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ package main
66
import "C"
77
import "unsafe"
88

9-
// export get_object
9+
//export get_object
1010
func get_object(key *C.char) *C.char {
1111
k := C.GoString(key)
12-
s := "Hello from Go! Key: " + k
12+
s := "go: Key: " + k
1313
return C.CString(s)
1414
}
1515

benchmark/aws-sdk-rust/src/lib.rs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,23 @@
1-
use std::ffi::CString;
1+
use std::ffi::{CStr, CString};
2+
use std::os::raw::c_char;
23

34
#[unsafe(no_mangle)]
4-
pub unsafe extern "C" fn get_object(key: *const std::ffi::c_char) -> *const std::ffi::c_char {
5-
let result = format!("Hello from Rust! Key: {:?}", key).to_string();
6-
let c_result = CString::new(result).expect("CString::new failed");
7-
c_result.as_ptr()
5+
pub unsafe extern "C" fn get_object(key: *const c_char) -> *mut c_char {
6+
let key_str = if key.is_null() {
7+
"<null>".to_string()
8+
} else {
9+
unsafe { CStr::from_ptr(key) }.to_string_lossy().into_owned()
10+
};
11+
12+
let result = format!("rust: Key: {}", key_str);
13+
CString::new(result).unwrap().into_raw()
14+
}
15+
16+
#[unsafe(no_mangle)]
17+
pub unsafe extern "C" fn free_object(ptr: *mut c_char) {
18+
if !ptr.is_null() {
19+
unsafe {
20+
drop(CString::from_raw(ptr));
21+
}
22+
}
823
}

benchmark/implementations.h

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#ifndef S3CPP_BENCHMARK_IMPLEMENTATIONS_H
2+
#define S3CPP_BENCHMARK_IMPLEMENTATIONS_H
3+
4+
#include "tasks.h"
5+
#include <cstddef>
6+
#include <cstdio>
7+
#include <dlfcn.h>
8+
#include <iterator>
9+
#include <print>
10+
#include <vector>
11+
12+
namespace s3b {
13+
14+
#define SO_SYMBOLS "init", "get_object"
15+
16+
constexpr const char *implementations_so[] = {
17+
#include "build/implementations.inc"
18+
};
19+
20+
constexpr std::size_t implementations_count = std::size(implementations_so);
21+
22+
struct implementation {
23+
const char *name;
24+
init_f *init;
25+
get_object_f *get_object;
26+
};
27+
28+
inline implementation parse_implementation(const char *so_path) {
29+
void *so_handle = dlopen(so_path, RTLD_LAZY);
30+
if (so_handle == NULL) {
31+
std::println(stderr, "fatal: unable to get handle {}", so_path);
32+
std::exit(1);
33+
}
34+
35+
std::string symbol_name = "init";
36+
init_f *init = reinterpret_cast<init_f *>(dlsym(so_handle, symbol_name.c_str()));
37+
if (init == NULL) {
38+
std::println(stderr, "fatal: {} for {}", ::dlerror(), so_path);
39+
std::exit(1);
40+
}
41+
42+
symbol_name = "get_object";
43+
get_object_f *get_object =
44+
reinterpret_cast<get_object_f *>(dlsym(so_handle, symbol_name.c_str()));
45+
if (get_object == NULL) {
46+
std::println(stderr, "fatal: {} for {}", ::dlerror(), so_path);
47+
std::exit(1);
48+
}
49+
return implementation{so_path, init, get_object};
50+
}
51+
52+
inline std::array<implementation, implementations_count>
53+
parse_implementations() {
54+
std::array<implementation, implementations_count> implementations{};
55+
for (size_t i = 0; i < implementations_count; i++) {
56+
implementations[i] = parse_implementation(implementations_so[i]);
57+
}
58+
return implementations;
59+
}
60+
61+
} // namespace s3b
62+
63+
#endif

benchmark/main.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include "implementations.h"
2+
#include "tasks.h"
3+
#include <print>
4+
5+
using namespace s3b;
6+
7+
int main(int argc, char *argv[]) {
8+
std::array<implementation, implementations_count> implementations =
9+
parse_implementations();
10+
return 0;
11+
}

benchmark/s3cpp/task.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
1-
#include "task.h"
21
#include <format>
32
#include <string>
43

5-
const char *s3bench::get_object(const char *key) noexcept {
4+
extern "C" {
5+
6+
const char *init(const char *access, const char *secret,
7+
const char *endpoint) noexcept {
8+
static std::string result;
9+
result = std::format("c++: access: {}", access);
10+
return result.c_str();
11+
}
12+
13+
const char *get_object(const char *key) noexcept {
614
static std::string result;
7-
result = std::format("Hello from C++!\nKey: {}", key);
15+
result = std::format("c++: Key: {}", key);
816
return result.c_str();
917
}
18+
}

benchmark/s3cpp/task.h

Lines changed: 0 additions & 14 deletions
This file was deleted.

benchmark/tasks.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#ifndef S3CPP_BENCHMARK_TASKS_H
2+
#define S3CPP_BENCHMARK_TASKS_H
3+
4+
namespace s3b {
5+
6+
typedef const char* init_f(const char* access, const char* secret, const char* endpoint) noexcept;
7+
typedef const char* get_object_f(const char* key) noexcept;
8+
9+
extern "C" {
10+
__attribute__((visibility("default"))) init_f init;
11+
__attribute__((visibility("default"))) get_object_f get_object;
12+
}
13+
14+
} // namespace s3bench
15+
16+
#endif

benchmark/test.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include "implementations.h"
2+
#include "tasks.h"
3+
4+
namespace s3b {
5+
6+
void test_get_object(const char *name, get_object_f *get_object) {
7+
for (const auto key : {"one", "two", "three"}) {
8+
std::println("{}", get_object(key));
9+
}
10+
}
11+
12+
} // namespace s3b
13+
14+
int main() {
15+
std::array<s3b::implementation, s3b::implementations_count> implementations =
16+
s3b::parse_implementations();
17+
for (const auto &implementation : implementations) {
18+
s3b::test_get_object(implementation.name, implementation.get_object);
19+
}
20+
}

0 commit comments

Comments
 (0)