Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
memory_profile_demo.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2021-2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
17#include <iostream>
18#include <iomanip>
19#include <vector>
20#include <memory>
21#include <thread>
22#include <chrono>
23#include <string>
24#include <cstring>
25#include <map>
26#include <mutex>
27
28#if defined(__APPLE__)
29#include <mach/mach.h>
30#include <mach/task.h>
31#elif defined(__linux__)
32#include <fstream>
33#include <unistd.h>
34#endif
35
36using namespace kcenon::network;
37
42#if defined(__APPLE__)
43 mach_task_basic_info_data_t info;
44 mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT;
45 if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO,
46 reinterpret_cast<task_info_t>(&info), &count) == KERN_SUCCESS) {
47 return info.resident_size;
48 }
49 return 0;
50#elif defined(__linux__)
51 std::ifstream statm("/proc/self/statm");
52 size_t size, rss;
53 statm >> size >> rss;
54 return rss * static_cast<size_t>(sysconf(_SC_PAGESIZE));
55#else
56 return 0;
57#endif
58}
59
64#if defined(__APPLE__)
65 mach_task_basic_info_data_t info;
66 mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT;
67 if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO,
68 reinterpret_cast<task_info_t>(&info), &count) == KERN_SUCCESS) {
69 return info.virtual_size;
70 }
71 return 0;
72#elif defined(__linux__)
73 std::ifstream statm("/proc/self/statm");
74 size_t size;
75 statm >> size;
76 return size * static_cast<size_t>(sysconf(_SC_PAGESIZE));
77#else
78 return 0;
79#endif
80}
81
85void print_memory_stats(const std::string& label) {
86 size_t rss = get_current_rss();
87 size_t vms = get_virtual_memory();
88 std::cout << std::left << std::setw(40) << ("[" + label + "]")
89 << "RSS: " << std::setw(8) << (rss / (1024 * 1024)) << " MB"
90 << " VMS: " << std::setw(8) << (vms / (1024 * 1024)) << " MB"
91 << std::endl;
92}
93
97void profile_connections(int num_connections) {
98 std::cout << "\n========================================\n";
99 std::cout << " Profiling Connection Memory\n";
100 std::cout << " Target: " << num_connections << " connections\n";
101 std::cout << "========================================\n\n";
102
103 size_t baseline_rss = get_current_rss();
104 print_memory_stats("Before server start");
105
107 auto server = tcp.create_server({
108 .port = 5555,
109 .server_id = "profile-server"
110 });
111
112 auto start_result = server->start(5555);
113
114 if (start_result.is_err()) {
115 std::cerr << "Failed to start server: " << start_result.error().message << std::endl;
116 return;
117 }
118
119 print_memory_stats("After server start");
120 std::this_thread::sleep_for(std::chrono::milliseconds(100));
121
122 std::vector<std::shared_ptr<interfaces::i_protocol_client>> clients;
123 clients.reserve(static_cast<size_t>(num_connections));
124
125 size_t before_clients_rss = get_current_rss();
126
127 for (int i = 0; i < num_connections; ++i) {
128 auto client = tcp.create_client({
129 .client_id = "client-" + std::to_string(i)
130 });
131 auto result = client->start("localhost", 5555);
132
133 if (result.is_ok()) {
134 clients.push_back(std::move(client));
135 } else {
136 std::cerr << "Failed to connect client " << i << std::endl;
137 }
138
139 if ((i + 1) % 50 == 0) {
140 print_memory_stats("After " + std::to_string(i + 1) + " connections");
141 }
142 }
143
144 size_t after_clients_rss = get_current_rss();
145 size_t total_client_memory = after_clients_rss - before_clients_rss;
146
147 std::cout << "\n--- Connection Memory Summary ---\n";
148 std::cout << "Connections created: " << clients.size() << "\n";
149 std::cout << "Total memory for clients: " << (total_client_memory / 1024) << " KB\n";
150 if (!clients.empty()) {
151 std::cout << "Memory per connection: ~"
152 << (total_client_memory / clients.size() / 1024) << " KB\n";
153 }
154
155 // Cleanup
156 std::cout << "\n--- Cleanup ---\n";
157 for (auto& client : clients) {
158 (void)client->stop();
159 }
160 clients.clear();
161
162 std::this_thread::sleep_for(std::chrono::milliseconds(500));
163 print_memory_stats("After cleanup");
164
165 (void)server->stop();
166 std::this_thread::sleep_for(std::chrono::milliseconds(100));
167 print_memory_stats("After server stop");
168
169 size_t final_rss = get_current_rss();
170 std::cout << "\nMemory delta from baseline: "
171 << static_cast<long long>(final_rss - baseline_rss) / 1024 << " KB\n";
172}
173
177void profile_message_throughput(int num_messages) {
178 std::cout << "\n========================================\n";
179 std::cout << " Profiling Message Memory\n";
180 std::cout << " Target: " << num_messages << " messages\n";
181 std::cout << "========================================\n\n";
182
183 size_t baseline_rss = get_current_rss();
184 print_memory_stats("Before start");
185
187 auto server = tcp.create_server({
188 .port = 5556,
189 .server_id = "profile-server"
190 });
191
192 auto server_result = server->start(5556);
193
194 if (server_result.is_err()) {
195 std::cerr << "Failed to start server\n";
196 return;
197 }
198
199 std::this_thread::sleep_for(std::chrono::milliseconds(100));
200
201 auto client = tcp.create_client({
202 .client_id = "profile-client"
203 });
204 auto client_result = client->start("localhost", 5556);
205
206 if (client_result.is_err()) {
207 std::cerr << "Failed to connect client\n";
208 (void)server->stop();
209 return;
210 }
211
212 print_memory_stats("Before messages");
213
214 auto start_time = std::chrono::steady_clock::now();
215
216 for (int i = 0; i < num_messages; ++i) {
217 std::vector<uint8_t> msg(1024, static_cast<uint8_t>(i % 256));
218 (void)client->send(std::move(msg));
219
220 if ((i + 1) % 5000 == 0) {
221 print_memory_stats("After " + std::to_string(i + 1) + " messages");
222 }
223 }
224
225 auto end_time = std::chrono::steady_clock::now();
226 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
227
228 print_memory_stats("After all messages");
229
230 std::cout << "\n--- Message Throughput Summary ---\n";
231 std::cout << "Messages sent: " << num_messages << "\n";
232 std::cout << "Total time: " << duration.count() << " ms\n";
233 std::cout << "Throughput: " << (num_messages * 1000 / std::max(1LL, static_cast<long long>(duration.count())))
234 << " msg/s\n";
235
236 // Wait for processing
237 std::this_thread::sleep_for(std::chrono::seconds(1));
238 print_memory_stats("After processing");
239
240 // Cleanup
241 (void)client->stop();
242 (void)server->stop();
243
244 std::this_thread::sleep_for(std::chrono::milliseconds(200));
245 print_memory_stats("After cleanup");
246
247 size_t final_rss = get_current_rss();
248 std::cout << "\nMemory delta from baseline: "
249 << static_cast<long long>(final_rss - baseline_rss) / 1024 << " KB\n";
250}
251
255void profile_long_running(int duration_seconds) {
256 std::cout << "\n========================================\n";
257 std::cout << " Profiling Long-Running Stability\n";
258 std::cout << " Duration: " << duration_seconds << " seconds\n";
259 std::cout << "========================================\n\n";
260
261 size_t baseline_rss = get_current_rss();
262 size_t peak_rss = baseline_rss;
263 print_memory_stats("Baseline");
264
266 auto server = tcp.create_server({
267 .port = 5557,
268 .server_id = "profile-server"
269 });
270
271 auto server_result = server->start(5557);
272
273 if (server_result.is_err()) {
274 std::cerr << "Failed to start server\n";
275 return;
276 }
277
278 print_memory_stats("After server start");
279
280 auto start_time = std::chrono::steady_clock::now();
281 int iterations = 0;
282 int successful_cycles = 0;
283
284 while (std::chrono::steady_clock::now() - start_time <
285 std::chrono::seconds(duration_seconds)) {
286
287 // Create client, send message, disconnect
288 auto client = tcp.create_client({
289 .client_id = "temp-client"
290 });
291 auto result = client->start("localhost", 5557);
292
293 if (result.is_ok()) {
294 (void)client->send({'t', 'e', 's', 't'});
295 (void)client->stop();
296 successful_cycles++;
297 }
298
299 iterations++;
300
301 size_t current_rss = get_current_rss();
302 if (current_rss > peak_rss) {
303 peak_rss = current_rss;
304 }
305
306 if (iterations % 100 == 0) {
307 print_memory_stats("After " + std::to_string(iterations) + " cycles");
308 }
309
310 std::this_thread::sleep_for(std::chrono::milliseconds(10));
311 }
312
313 std::cout << "\n--- Long-Running Summary ---\n";
314 std::cout << "Total iterations: " << iterations << "\n";
315 std::cout << "Successful cycles: " << successful_cycles << "\n";
316 std::cout << "Peak RSS: " << (peak_rss / (1024 * 1024)) << " MB\n";
317
318 (void)server->stop();
319
320 std::this_thread::sleep_for(std::chrono::milliseconds(200));
321 print_memory_stats("Final");
322
323 size_t final_rss = get_current_rss();
324 std::cout << "\nMemory delta from baseline: "
325 << static_cast<long long>(final_rss - baseline_rss) / 1024 << " KB\n";
326 std::cout << "Memory leak indicator: "
327 << (final_rss > baseline_rss + 1024 * 1024 ? "POSSIBLE LEAK" : "OK")
328 << "\n";
329}
330
331void print_usage(const char* program_name) {
332 std::cout << "Usage: " << program_name << " [mode]\n\n";
333 std::cout << "Modes:\n";
334 std::cout << " connections - Profile connection memory overhead\n";
335 std::cout << " messages - Profile message throughput memory\n";
336 std::cout << " stability - Profile long-running stability\n";
337 std::cout << " all - Run all profiles (default)\n";
338 std::cout << "\nExamples:\n";
339 std::cout << " " << program_name << " connections\n";
340 std::cout << " " << program_name << " all\n";
341}
342
343int main(int argc, char* argv[]) {
344 std::cout << "========================================\n";
345 std::cout << " Network System Memory Profiling Demo\n";
346 std::cout << "========================================\n";
347
348 std::string mode = "all";
349 if (argc > 1) {
350 if (std::strcmp(argv[1], "-h") == 0 || std::strcmp(argv[1], "--help") == 0) {
351 print_usage(argv[0]);
352 return 0;
353 }
354 mode = argv[1];
355 }
356
357 print_memory_stats("Program start");
358
359 if (mode == "connections" || mode == "all") {
361 }
362
363 if (mode == "messages" || mode == "all") {
365 }
366
367 if (mode == "stability" || mode == "all") {
369 }
370
371 std::cout << "\n========================================\n";
372 std::cout << " Profiling Complete\n";
373 std::cout << "========================================\n";
374
375 return 0;
376}
int main()
Simplified facade for creating TCP clients and servers.
Definition tcp_facade.h:95
Session interface representing an active client-server connection.
size_t get_virtual_memory()
Get current virtual memory size in bytes.
void profile_connections(int num_connections)
Profile connection memory overhead.
size_t get_current_rss()
Get current RSS (Resident Set Size) in bytes.
void print_memory_stats(const std::string &label)
Print memory statistics with label.
void profile_message_throughput(int num_messages)
Profile message throughput memory.
void profile_long_running(int duration_seconds)
Profile long-running stability.
void print_usage(const char *program_name)
Main namespace for all Network System components.
Simplified facade for creating TCP clients and servers.