|
| 1 | + |
| 2 | +#include "quanux/MarketTick.hpp" |
| 3 | +#include "quanux/SPSCQueue.hpp" |
| 4 | +#include <atomic> |
| 5 | +#include <chrono> |
| 6 | +#include <iostream> |
| 7 | +#include <thread> |
| 8 | +#include <vector> |
| 9 | + |
| 10 | +using namespace quanux; |
| 11 | + |
| 12 | +// Signal simplified for benchmark |
| 13 | +struct Signal { |
| 14 | + uint64_t tick_ts; |
| 15 | + uint32_t instrument_id; |
| 16 | + double z_score; |
| 17 | + double volatility; |
| 18 | +}; |
| 19 | + |
| 20 | +int main() { |
| 21 | + SPSCQueue<Signal> queue(4096); |
| 22 | + std::atomic<bool> running{true}; |
| 23 | + std::vector<uint64_t> latencies; |
| 24 | + latencies.reserve(1000000); |
| 25 | + |
| 26 | + // Consumer Thread (Execution) |
| 27 | + std::thread consumer([&]() { |
| 28 | + Signal sig; |
| 29 | + while (running) { |
| 30 | + if (queue.pop(sig)) { |
| 31 | + auto now = std::chrono::steady_clock::now(); |
| 32 | + auto tick_time = std::chrono::steady_clock::time_point( |
| 33 | + std::chrono::nanoseconds(sig.tick_ts)); |
| 34 | + auto latency = std::chrono::duration_cast<std::chrono::nanoseconds>( |
| 35 | + now - tick_time) |
| 36 | + .count(); |
| 37 | + latencies.push_back(latency); |
| 38 | + } |
| 39 | + } |
| 40 | + }); |
| 41 | + |
| 42 | + // Producer Loop (Simulation) |
| 43 | + std::cout << "Running Micro-Benchmark (1M messages)..." << std::endl; |
| 44 | + auto start = std::chrono::steady_clock::now(); |
| 45 | + |
| 46 | + for (int i = 0; i < 1000000; ++i) { |
| 47 | + auto now = std::chrono::steady_clock::now(); |
| 48 | + uint64_t ts = std::chrono::duration_cast<std::chrono::nanoseconds>( |
| 49 | + now.time_since_epoch()) |
| 50 | + .count(); |
| 51 | + Signal sig{ts, 1, 3.0, 0.5}; // Always trigger |
| 52 | + while (!queue.push(sig)) { |
| 53 | + // spin |
| 54 | + } |
| 55 | + } |
| 56 | + |
| 57 | + // Wait for drain |
| 58 | + std::this_thread::sleep_for(std::chrono::milliseconds(200)); |
| 59 | + running = false; |
| 60 | + consumer.join(); |
| 61 | + auto end = std::chrono::steady_clock::now(); |
| 62 | + |
| 63 | + std::cout << "Done." << std::endl; |
| 64 | + |
| 65 | + // Calculate Stats |
| 66 | + uint64_t sum = 0; |
| 67 | + uint64_t min_lat = -1; |
| 68 | + uint64_t max_lat = 0; |
| 69 | + for (auto lat : latencies) { |
| 70 | + sum += lat; |
| 71 | + if (lat < min_lat) |
| 72 | + min_lat = lat; |
| 73 | + if (lat > max_lat) |
| 74 | + max_lat = lat; |
| 75 | + } |
| 76 | + |
| 77 | + if (!latencies.empty()) { |
| 78 | + std::cout << "Avg Latency: " << (sum / latencies.size()) << " ns" |
| 79 | + << std::endl; |
| 80 | + std::cout << "Min Latency: " << min_lat << " ns" << std::endl; |
| 81 | + std::cout << "Max Latency: " << max_lat << " ns" << std::endl; |
| 82 | + std::cout << "Throughput: " |
| 83 | + << (1000000.0 / |
| 84 | + std::chrono::duration_cast<std::chrono::milliseconds>(end - |
| 85 | + start) |
| 86 | + .count() * |
| 87 | + 1000) |
| 88 | + << " msg/sec" << std::endl; |
| 89 | + } |
| 90 | + |
| 91 | + return 0; |
| 92 | +} |
0 commit comments