diff --git a/bench/simple_bench.cpp b/bench/simple_bench.cpp new file mode 100644 index 0000000..f49eced --- /dev/null +++ b/bench/simple_bench.cpp @@ -0,0 +1,131 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.hpp" +#include "mpsc.hpp" +#include "spsc.hpp" + +using namespace fastchan; + +constexpr int num_iterations = 100'000'000; + +template +void producer(Chan &chan, int num_producers, int producer_id) { + for (int i = producer_id; i <= num_iterations; i += num_producers) { + chan.put(i); + } +} + +template +void consumer(Chan &chan) { + int consumed = 0; + while (consumed < num_iterations) { + auto item = chan.get(); + consumed++; + } +} + +void set_affinity(std::thread &t, int core_id) { + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + CPU_SET(core_id, &cpuset); + + auto native_handle = t.native_handle(); + int result = pthread_setaffinity_np(native_handle, sizeof(cpu_set_t), &cpuset); + if (result != 0) { + std::cerr << "Error setting thread affinity: " << result << std::endl; + } +} + +template +void run_benchmark(const std::string &name, int num_producers, bool pin_threads) { + Chan chan; + + auto start = std::chrono::steady_clock::now(); + + std::vector producers; + for (int i = 0; i < num_producers; i++) { + producers.emplace_back(producer, std::ref(chan), num_producers, i); + if (pin_threads) { + set_affinity(producers.back(), i % std::thread::hardware_concurrency()); + } + } + std::thread consumer_thread(consumer, std::ref(chan)); + if (pin_threads) { + set_affinity(consumer_thread, num_producers % std::thread::hardware_concurrency()); + } + + for (auto &t : producers) { + t.join(); + } + consumer_thread.join(); + + auto end = std::chrono::steady_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start).count(); + std::cout << name << "\t" << num_producers << " Producers" + << "\t" << (pin_threads ? " Pinned" : "UnPinned") << "\t" << num_iterations << "\t" << std::setfill(' ') << std::setw(3) + << (elapsed / num_iterations) << " ns/op" + << "\t" << elapsed / 1'000'000 << " ms" << std::endl; +} + +int main() { +#if defined(__linux__) + run_benchmark>("SPSC_Yield", 1, true); + run_benchmark>("SPSC_Yield", 1, false); + run_benchmark>("SPSC_Spin", 1, true); + run_benchmark>("SPSC_Spin", 1, false); + run_benchmark>("SPSC_Cond", 1, true); + run_benchmark>("SPSC_Cond", 1, false); + + std::cout << "============================" << std::endl; + + run_benchmark>("MPSC_Yield", 1, true); + run_benchmark>("MPSC_Yield", 1, false); + run_benchmark>("MPSC_Spin", 1, true); + run_benchmark>("MPSC_Spin", 1, false); + run_benchmark>("MPSC_Cond", 1, true); + run_benchmark>("MPSC_Cond", 1, false); + + std::cout << "============================" << std::endl; + + run_benchmark>("MPSC_Yield", 3, true); + run_benchmark>("MPSC_Yield", 3, false); + run_benchmark>("MPSC_Spin", 3, true); + run_benchmark>("MPSC_Spin", 3, false); + run_benchmark>("MPSC_Cond", 3, true); + run_benchmark>("MPSC_Cond", 3, false); + + std::cout << "============================" << std::endl; + + run_benchmark>("MPSC_Yield", 5, true); + run_benchmark>("MPSC_Yield", 5, false); + run_benchmark>("MPSC_Spin", 5, true); + run_benchmark>("MPSC_Spin", 5, false); + run_benchmark>("MPSC_Cond", 5, true); + run_benchmark>("MPSC_Cond", 5, false); + + std::cout << "============================" << std::endl; + + run_benchmark>("MPSC_Yield", 7, true); + run_benchmark>("MPSC_Yield", 7, false); + run_benchmark>("MPSC_Spin", 7, true); + run_benchmark>("MPSC_Spin", 7, false); + run_benchmark>("MPSC_Cond", 7, true); + run_benchmark>("MPSC_Cond", 7, false); + +#else + std::cout << "This benchmark requires a Linux platform to run. Exiting." << std::endl; +#endif + return 0; +}