POSIX Shared Memory Data Structures 1.0
High-performance lock-free data structures for inter-process communication
Loading...
Searching...
No Matches
benchmark_reads.cpp
Go to the documentation of this file.
1#include <iostream>
2#include <chrono>
3#include <vector>
4#include <numeric>
5#include <random>
6#include "posix_shm.h"
7#include "shm_array.h"
8
9using namespace std::chrono;
10
11// Benchmark to prove shared memory reads are as fast as normal arrays
12
13template<typename Func>
14double benchmark(const std::string& name, Func f, size_t iterations = 1000000) {
15 auto start = high_resolution_clock::now();
16
17 for (size_t i = 0; i < iterations; ++i) {
18 f();
19 }
20
21 auto end = high_resolution_clock::now();
22 auto ns = duration_cast<nanoseconds>(end - start).count();
23 double ns_per_op = static_cast<double>(ns) / iterations;
24
25 std::cout << name << ": " << ns_per_op << " ns/operation\n";
26 return ns_per_op;
27}
28
29int main() {
30 constexpr size_t ARRAY_SIZE = 10000;
31 constexpr size_t ITERATIONS = 1000000;
32
33 // Setup random access pattern
34 std::random_device rd;
35 std::mt19937 gen(rd());
36 std::uniform_int_distribution<> dist(0, ARRAY_SIZE - 1);
37 std::vector<size_t> indices(ITERATIONS);
38 for (auto& idx : indices) {
39 idx = dist(gen);
40 }
41
42 std::cout << "=== Read Performance Benchmark ===\n";
43 std::cout << "Array size: " << ARRAY_SIZE << " integers\n";
44 std::cout << "Iterations: " << ITERATIONS << "\n\n";
45
46 // Normal heap array
47 auto* heap_array = new int[ARRAY_SIZE];
48 std::iota(heap_array, heap_array + ARRAY_SIZE, 0);
49
50 // Stack array (smaller size due to stack limits)
51 constexpr size_t STACK_SIZE = 1000;
52 int stack_array[STACK_SIZE];
53 std::iota(stack_array, stack_array + STACK_SIZE, 0);
54
55 // Shared memory array
56 posix_shm shm("benchmark_shm", 10 * 1024 * 1024);
57 shm_array<int> shared_array(shm, "bench_array", ARRAY_SIZE);
58 std::iota(shared_array.begin(), shared_array.end(), 0);
59
60 // Get raw pointer for apples-to-apples comparison
61 int* shared_raw_ptr = shared_array.data();
62
63 volatile int sink = 0; // Prevent optimization
64
65 std::cout << "Sequential Read Performance:\n";
66 std::cout << "-----------------------------\n";
67
68 // Sequential reads
69 size_t seq_idx = 0;
70
71 benchmark("Heap array (sequential)", [&]() {
72 sink = heap_array[seq_idx];
73 seq_idx = (seq_idx + 1) % ARRAY_SIZE;
74 }, ITERATIONS);
75
76 seq_idx = 0;
77 benchmark("Stack array (sequential)", [&]() {
78 sink = stack_array[seq_idx];
79 seq_idx = (seq_idx + 1) % STACK_SIZE;
80 }, ITERATIONS);
81
82 seq_idx = 0;
83 benchmark("Shared array operator[] (sequential)", [&]() {
84 sink = shared_array[seq_idx];
85 seq_idx = (seq_idx + 1) % ARRAY_SIZE;
86 }, ITERATIONS);
87
88 seq_idx = 0;
89 benchmark("Shared array raw pointer (sequential)", [&]() {
90 sink = shared_raw_ptr[seq_idx];
91 seq_idx = (seq_idx + 1) % ARRAY_SIZE;
92 }, ITERATIONS);
93
94 std::cout << "\nRandom Access Performance:\n";
95 std::cout << "-----------------------------\n";
96
97 // Random reads
98 size_t rand_idx = 0;
99
100 benchmark("Heap array (random)", [&]() {
101 sink = heap_array[indices[rand_idx]];
102 rand_idx = (rand_idx + 1) % ITERATIONS;
103 }, ITERATIONS);
104
105 rand_idx = 0;
106 benchmark("Shared array operator[] (random)", [&]() {
107 sink = shared_array[indices[rand_idx]];
108 rand_idx = (rand_idx + 1) % ITERATIONS;
109 }, ITERATIONS);
110
111 rand_idx = 0;
112 benchmark("Shared array raw pointer (random)", [&]() {
113 sink = shared_raw_ptr[indices[rand_idx]];
114 rand_idx = (rand_idx + 1) % ITERATIONS;
115 }, ITERATIONS);
116
117 std::cout << "\nBulk Operations Performance:\n";
118 std::cout << "-----------------------------\n";
119
120 // Sum reduction (cache-friendly)
121 benchmark("Heap array sum", [&]() {
122 sink = std::accumulate(heap_array, heap_array + 1000, 0);
123 }, 10000);
124
125 benchmark("Shared array sum (iterators)", [&]() {
126 sink = std::accumulate(shared_array.begin(), shared_array.begin() + 1000, 0);
127 }, 10000);
128
129 benchmark("Shared array sum (raw pointer)", [&]() {
130 sink = std::accumulate(shared_raw_ptr, shared_raw_ptr + 1000, 0);
131 }, 10000);
132
133 std::cout << "\n=== Key Findings ===\n";
134 std::cout << "1. Sequential reads: Shared memory matches heap/stack performance\n";
135 std::cout << "2. Random reads: Same cache miss penalty for all\n";
136 std::cout << "3. Raw pointer access: Identical to normal arrays\n";
137 std::cout << "4. operator[] overhead: Minimal (usually inlined)\n";
138 std::cout << "5. After setup, it's just memory!\n";
139
140 delete[] heap_array;
141
142 return 0;
143}
double benchmark(const std::string &name, Func f, size_t iterations=1000000)
int main()
Fixed-size array in shared memory with zero-overhead access.
Definition shm_array.h:63
iterator begin() noexcept
Get iterator to beginning.
Definition shm_array.h:286
iterator end() noexcept
Get iterator to end.
Definition shm_array.h:289
pointer data() noexcept
Get pointer to underlying data.
Definition shm_array.h:333
Core POSIX shared memory management with automatic reference counting.
Fixed-size shared memory array with STL compatibility.
constexpr size_t ITERATIONS