8#include <benchmark/benchmark.h>
18using namespace benchmark;
23void poseiden_hash_direct(State& state)
noexcept
27 for (
auto _ : state) {
33BENCHMARK(poseiden_hash_direct)->Unit(benchmark::kMicrosecond)->Iterations(10000);
36static pid_t spawn_bb_msgpack_server(
const std::string& path)
38 pid_t bb_pid = fork();
41 int devnull = open(
"/dev/null", O_WRONLY);
43 dup2(devnull, STDOUT_FILENO);
44 dup2(devnull, STDERR_FILENO);
54 for (
const char* bb_path : bb_paths) {
55 execl(bb_path, bb_path,
"msgpack",
"run",
"--input", path.c_str(),
nullptr);
63enum class TransportType { Socket, Shm };
69template <TransportType Transport,
size_t NumClients>
class Poseidon2BBMsgpack :
public Fixture {
71 static_assert(NumClients >= 1,
"Must have at least 1 client");
75 std::array<std::thread, (NumClients > 1 ? NumClients - 1 : 1)> background_threads{};
76 std::atomic<bool> stop_background{
false };
84 if constexpr (Transport == TransportType::Socket) {
85 ipc_path =
"/tmp/poseidon_bb_msgpack_bench.sock";
88 ipc_path =
"/p2_bench.shm";
93 bool socket_exists(
const char* path,
int max_attempts = 20)
95 for (
int i = 0; i < max_attempts; i++) {
97 if (stat(path, &st) == 0 && S_ISSOCK(st.st_mode)) {
100 std::this_thread::sleep_for(std::chrono::milliseconds(50));
105 void SetUp(const ::benchmark::State& )
override
110 bb_pid = spawn_bb_msgpack_server(ipc_path);
112 throw std::runtime_error(
"Failed to fork bb process");
116 if constexpr (Transport == TransportType::Socket) {
118 if (!socket_exists(ipc_path.c_str())) {
119 kill(bb_pid, SIGKILL);
120 waitpid(bb_pid,
nullptr, 0);
121 throw std::runtime_error(
"BB binary failed to create socket within timeout");
123 std::this_thread::sleep_for(std::chrono::milliseconds(50));
126 std::this_thread::sleep_for(std::chrono::milliseconds(500));
130 for (
size_t i = 0; i < NumClients; i++) {
131 if constexpr (Transport == TransportType::Socket) {
135 std::string base_name = ipc_path.substr(0, ipc_path.size() - 4);
139 bool connected =
false;
140 for (
int retry_count = 0; retry_count < 5; retry_count++) {
141 if (clients[i]->connect()) {
145 std::this_thread::sleep_for(std::chrono::milliseconds(50));
149 kill(bb_pid, SIGKILL);
150 waitpid(bb_pid,
nullptr, 0);
151 throw std::runtime_error(
"Failed to connect to BB IPC server after retries");
156 if constexpr (NumClients > 1) {
157 for (
size_t i = 1; i < NumClients; i++) {
158 background_threads[i - 1] = std::thread([
this, i]() {
169 msgpack::sbuffer cmd_buffer;
170 msgpack::pack(cmd_buffer, std::make_tuple(command));
173 constexpr uint64_t TIMEOUT_NS = 100000000;
174 while (!clients[i]->send(cmd_buffer.data(), cmd_buffer.size(), TIMEOUT_NS)) {
183 while ((response = clients[i]->receive(TIMEOUT_NS)).empty()) {
191 clients[i]->release(response.size());
202 void TearDown(const ::benchmark::State& )
override
205 if constexpr (NumClients > 1) {
207 for (
size_t i = 0; i < NumClients - 1; i++) {
208 if (background_threads[i].joinable()) {
209 background_threads[i].join();
221 msgpack::sbuffer cmd_buffer;
222 msgpack::pack(cmd_buffer, std::make_tuple(command));
225 constexpr uint64_t TIMEOUT_NS = 1000000000;
226 while (!clients[0]->send(cmd_buffer.data(), cmd_buffer.size(), TIMEOUT_NS)) {
231 while ((response = clients[0]->receive(TIMEOUT_NS)).empty()) {
235 clients[0]->release(response.size());
239 for (
auto& client : clients) {
248 pid_t result = waitpid(bb_pid, &status, 0);
251 kill(bb_pid, SIGKILL);
252 waitpid(bb_pid,
nullptr, 0);
258 void run_benchmark(benchmark::State& state)
260 constexpr uint64_t TIMEOUT_NS = 1000000000;
262 for (
auto _ : state) {
269 msgpack::sbuffer cmd_buffer;
270 msgpack::pack(cmd_buffer, std::make_tuple(command));
273 while (!clients[0]->send(cmd_buffer.data(), cmd_buffer.size(), TIMEOUT_NS)) {
279 while ((resp = clients[0]->receive(TIMEOUT_NS)).empty()) {
284 auto unpacked = msgpack::unpack(
reinterpret_cast<const char*
>(resp.data()), resp.size());
286 unpacked.
get().convert(response);
289 clients[0]->release(resp.size());
294 if (hash_response ==
nullptr) {
295 state.SkipWithError(
"Invalid response type");
299 DoNotOptimize(hash_response->hash);
306using Poseidon2BBSocketSPSC = Poseidon2BBMsgpack<TransportType::Socket, 1>;
307using Poseidon2BBShmSPSC = Poseidon2BBMsgpack<TransportType::Shm, 1>;
310using Poseidon2BBSocketMPSC = Poseidon2BBMsgpack<TransportType::Socket, 3>;
313#define REGISTER_BB_BENCHMARK(fixture_name) \
314 BENCHMARK_DEFINE_F(fixture_name, poseiden_hash_roundtrip)(benchmark::State & state) \
316 run_benchmark(state); \
318 BENCHMARK_REGISTER_F(fixture_name, poseiden_hash_roundtrip)->Unit(benchmark::kMicrosecond)->Iterations(10000)
A wrapper around std::variant that provides msgpack serialization based on type names.
std::variant< Types... > VariantType
static std::unique_ptr< IpcClient > create_socket(const std::string &socket_path)
static std::unique_ptr< IpcClient > create_shm(const std::string &base_name)
#define REGISTER_BB_BENCHMARK(fixture_name)
void hash(State &state) noexcept
Entry point for Barretenberg command-line interface.
BENCHMARK(bench_commit_structured_random_poly< curve::BN254 >) -> Unit(benchmark::kMillisecond)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Compute Poseidon2 hash of input field elements.
static field random_element(numeric::RNG *engine=nullptr) noexcept