File size: 11,257 Bytes
f86fb3b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <chrono>
#include <iomanip>
#include <thread>
#include "../include/core/types.hpp"
#include "../include/core/time_utils.hpp"
#include "../include/core/spsc_queue.hpp"
#include "../include/core/mpsc_queue.hpp"
#include "../include/core/object_pool.hpp"
#include "../include/protocol/binary_protocol.hpp"
#include "../include/order_book/matching_engine.hpp"
#include "../include/risk/risk_engine.hpp"
#include "../include/engine/trading_engine.hpp"

struct LatencyStats {
    double min_ns{0};
    double p50_ns{0};
    double p90_ns{0};
    double p95_ns{0};
    double p99_ns{0};
    double p99_9_ns{0};
    double max_ns{0};
    double avg_ns{0};
    double throughput_mps{0}; // Million packets per second
};

LatencyStats compute_stats(std::vector<uint64_t>& latencies, double total_time_sec) {
    LatencyStats stats;
    if (latencies.empty()) return stats;

    std::sort(latencies.begin(), latencies.end());
    size_t n = latencies.size();

    stats.min_ns = latencies.front();
    stats.p50_ns = latencies[n * 50 / 100];
    stats.p90_ns = latencies[n * 90 / 100];
    stats.p95_ns = latencies[n * 95 / 100];
    stats.p99_ns = latencies[n * 99 / 100];
    stats.p99_9_ns = latencies[n * 999 / 1000];
    stats.max_ns = latencies.back();

    uint64_t sum = std::accumulate(latencies.begin(), latencies.end(), 0ULL);
    stats.avg_ns = static_cast<double>(sum) / n;
    stats.throughput_mps = (static_cast<double>(n) / 1'000'000.0) / total_time_sec;
    return stats;
}

void print_stats_row(const std::string& name, const LatencyStats& s) {
    std::cout << "| " << std::left << std::setw(32) << name
              << " | " << std::right << std::setw(8) << std::fixed << std::setprecision(2) << s.throughput_mps << " M/s"
              << " | " << std::setw(7) << std::setprecision(1) << s.p50_ns << " ns"
              << " | " << std::setw(7) << std::setprecision(1) << s.p95_ns << " ns"
              << " | " << std::setw(7) << std::setprecision(1) << s.p99_ns << " ns"
              << " | " << std::setw(7) << std::setprecision(1) << s.p99_9_ns << " ns"
              << " |\n";
}

// 1. SPSC Ring Buffer Queue Benchmark across depths
template <size_t Depth>
LatencyStats benchmark_spsc_queue(const std::string& label, size_t iterations) {
    (void)label;
    quant::core::LockFreeSPSCQueue<uint64_t, Depth> queue;
    std::vector<uint64_t> latencies;
    latencies.reserve(iterations);

    std::atomic<bool> start_flag{false};
    std::atomic<bool> done_flag{false};

    std::thread consumer([&]() {
        while (!start_flag.load(std::memory_order_acquire)) {}
        size_t received = 0;
        while (received < iterations) {
            uint64_t val;
            if (queue.pop(val)) {
                uint64_t now = quant::core::TimeUtils::now_ns();
                if (now >= val) {
                    latencies.push_back(now - val);
                }
                ++received;
            } else {
                quant::core::ThreadUtils::cpu_pause();
            }
        }
        done_flag.store(true, std::memory_order_release);
    });

    start_flag.store(true, std::memory_order_release);
    auto t0 = std::chrono::high_resolution_clock::now();

    for (size_t i = 0; i < iterations; ++i) {
        uint64_t ts = quant::core::TimeUtils::now_ns();
        while (!queue.push(ts)) {
            quant::core::ThreadUtils::cpu_pause();
        }
    }

    consumer.join();
    auto t1 = std::chrono::high_resolution_clock::now();
    double sec = std::chrono::duration<double>(t1 - t0).count();
    return compute_stats(latencies, sec);
}

// 2. MPSC Queue Concurrent Producer Benchmark (1, 2, 4 threads)
LatencyStats benchmark_mpsc_queue(size_t num_producers, size_t total_iterations) {
    quant::core::LockFreeMPSCQueue<uint64_t, 65536> queue;
    std::vector<uint64_t> latencies;
    latencies.reserve(total_iterations);

    size_t iters_per_prod = total_iterations / num_producers;
    std::atomic<bool> start_flag{false};

    std::thread consumer([&]() {
        while (!start_flag.load(std::memory_order_acquire)) {}
        size_t received = 0;
        while (received < total_iterations) {
            uint64_t val;
            if (queue.pop(val)) {
                uint64_t now = quant::core::TimeUtils::now_ns();
                if (now >= val) {
                    latencies.push_back(now - val);
                }
                ++received;
            } else {
                quant::core::ThreadUtils::cpu_pause();
            }
        }
    });

    std::vector<std::thread> producers;
    producers.reserve(num_producers);
    for (size_t p = 0; p < num_producers; ++p) {
        producers.emplace_back([&]() {
            while (!start_flag.load(std::memory_order_acquire)) {}
            for (size_t i = 0; i < iters_per_prod; ++i) {
                uint64_t ts = quant::core::TimeUtils::now_ns();
                while (!queue.push(ts)) {
                    quant::core::ThreadUtils::cpu_pause();
                }
            }
        });
    }

    auto t0 = std::chrono::high_resolution_clock::now();
    start_flag.store(true, std::memory_order_release);

    for (auto& th : producers) th.join();
    consumer.join();

    auto t1 = std::chrono::high_resolution_clock::now();
    double sec = std::chrono::duration<double>(t1 - t0).count();
    return compute_stats(latencies, sec);
}

// 3. Binary Protocol Serialization/Deserialization Benchmark
LatencyStats benchmark_binary_protocol(size_t iterations) {
    std::vector<uint64_t> latencies;
    latencies.reserve(iterations);

    std::array<uint8_t, quant::protocol::MAX_FRAME_SIZE> buffer;
    quant::protocol::NewOrderSinglePayload order{
        1, 1001, quant::core::Symbol("TSLA"),
        static_cast<uint8_t>(quant::core::Side::BUY),
        static_cast<uint8_t>(quant::core::OrderType::LIMIT),
        2500000, 100
    };

    auto t0 = std::chrono::high_resolution_clock::now();
    for (size_t i = 0; i < iterations; ++i) {
        uint64_t s = quant::core::TimeUtils::now_ns();
        size_t len = quant::protocol::BinaryProtocol::serialize_message(
            std::span<uint8_t>(buffer),
            quant::protocol::MessageType::NEW_ORDER_SINGLE,
            i + 1,
            s,
            order
        );
        auto* parsed = quant::protocol::BinaryProtocol::parse_payload<quant::protocol::NewOrderSinglePayload>(
            std::span<const uint8_t>(buffer.data(), len)
        );
        (void)parsed;
        uint64_t e = quant::core::TimeUtils::now_ns();
        latencies.push_back(e - s);
    }
    auto t1 = std::chrono::high_resolution_clock::now();
    double sec = std::chrono::duration<double>(t1 - t0).count();
    return compute_stats(latencies, sec);
}

// 4. Order Book & Matching Engine Core Benchmark
LatencyStats benchmark_matching_engine(size_t iterations) {
    quant::order_book::MatchingEngine engine(quant::core::Symbol("AAPL"));
    std::vector<uint64_t> latencies;
    latencies.reserve(iterations);

    // Pre-populate resting asks
    for (size_t i = 0; i < 50; ++i) {
        engine.process_new_order(
            1, i + 1, quant::core::Side::SELL, quant::core::OrderType::LIMIT,
            quant::core::Price::from_raw(1500000 + i * 100), 1000,
            quant::core::TimeUtils::now_ns()
        );
    }

    auto t0 = std::chrono::high_resolution_clock::now();
    for (size_t i = 0; i < iterations; ++i) {
        uint64_t s = quant::core::TimeUtils::now_ns();
        // Alternating matching buy orders
        engine.process_new_order(
            2, 100000 + i, quant::core::Side::BUY, quant::core::OrderType::LIMIT,
            quant::core::Price::from_raw(1500000 + (i % 50) * 100), 10, s
        );
        uint64_t e = quant::core::TimeUtils::now_ns();
        latencies.push_back(e - s);
    }
    auto t1 = std::chrono::high_resolution_clock::now();
    double sec = std::chrono::duration<double>(t1 - t0).count();
    return compute_stats(latencies, sec);
}

// 5. Burst Order Traffic Benchmark (100,000 orders in tight loop)
LatencyStats benchmark_burst_traffic(size_t iterations) {
    quant::order_book::MatchingEngine engine(quant::core::Symbol("NVDA"));
    std::vector<uint64_t> latencies;
    latencies.reserve(iterations);

    auto t0 = std::chrono::high_resolution_clock::now();
    for (size_t i = 0; i < iterations; ++i) {
        uint64_t s = quant::core::TimeUtils::now_ns();
        engine.process_new_order(
            1, i + 1,
            (i % 2 == 0) ? quant::core::Side::BUY : quant::core::Side::SELL,
            quant::core::OrderType::LIMIT,
            quant::core::Price::from_raw(1000000 + (i % 20) * 100),
            100,
            s
        );
        uint64_t e = quant::core::TimeUtils::now_ns();
        latencies.push_back(e - s);
    }
    auto t1 = std::chrono::high_resolution_clock::now();
    double sec = std::chrono::duration<double>(t1 - t0).count();
    return compute_stats(latencies, sec);
}

int main() {
    std::cout << "========================================================================================================\n";
    std::cout << "⚡ QUANT.AI MODERN C++20 PRODUCTION TRADING ENGINE BENCHMARK SUITE\n";
    std::cout << "========================================================================================================\n";
    std::cout << "| Benchmark Scenario               | Throughput |    p50    |    p95    |    p99    |   p99.9   |\n";
    std::cout << "|----------------------------------|------------|-----------|-----------|-----------|-----------|\n";

    constexpr size_t OPS = 500000;

    // SPSC Queue across depths
    auto spsc_256 = benchmark_spsc_queue<256>("Lock-Free SPSC (Depth 256)", OPS);
    print_stats_row("Lock-Free SPSC (Depth 256)", spsc_256);

    auto spsc_1024 = benchmark_spsc_queue<1024>("Lock-Free SPSC (Depth 1024)", OPS);
    print_stats_row("Lock-Free SPSC (Depth 1024)", spsc_1024);

    auto spsc_64k = benchmark_spsc_queue<65536>("Lock-Free SPSC (Depth 65536)", OPS);
    print_stats_row("Lock-Free SPSC (Depth 65536)", spsc_64k);

    // MPSC Queue concurrency: 1, 2, 4 threads
    auto mpsc_1 = benchmark_mpsc_queue(1, OPS);
    print_stats_row("Lock-Free MPSC (1 Thread)", mpsc_1);

    auto mpsc_2 = benchmark_mpsc_queue(2, OPS);
    print_stats_row("Lock-Free MPSC (2 Threads)", mpsc_2);

    auto mpsc_4 = benchmark_mpsc_queue(4, OPS);
    print_stats_row("Lock-Free MPSC (4 Threads)", mpsc_4);

    // Binary protocol zero-copy framing
    auto bin_stat = benchmark_binary_protocol(OPS);
    print_stats_row("Binary Protocol (Zero-Copy)", bin_stat);

    // Matching Engine price-time priority matching
    auto match_stat = benchmark_matching_engine(OPS);
    print_stats_row("Matching Engine (Order Match)", match_stat);

    // Burst traffic (100k+ orders)
    auto burst_stat = benchmark_burst_traffic(100000);
    print_stats_row("Burst Traffic (100k Orders)", burst_stat);

    std::cout << "========================================================================================================\n";
    std::cout << "✅ Benchmark completed. Sustained throughput & low latency confirmed across all concurrency pipelines.\n";
    return 0;
}