You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
258 lines
8.4 KiB
258 lines
8.4 KiB
/** |
|
* Performance benchmark for lib socket management |
|
* Compares array-based vs linked list implementation |
|
*/ |
|
|
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <stdint.h> |
|
#include <unistd.h> |
|
#include <sys/time.h> |
|
#include <sys/socket.h> |
|
#include <netinet/in.h> |
|
#include <arpa/inet.h> |
|
#include <fcntl.h> |
|
#include <errno.h> |
|
|
|
#include "u_async.h" |
|
|
|
/* Performance measurement */ |
|
static uint64_t get_time_us(void) { |
|
struct timeval tv; |
|
gettimeofday(&tv, NULL); |
|
return (uint64_t)tv.tv_sec * 1000000ULL + tv.tv_usec; |
|
} |
|
|
|
static void test_socket_callback(int fd, void* arg) { |
|
(void)fd; |
|
(void)arg; |
|
// Empty callback for testing |
|
} |
|
|
|
/* Benchmark: Add and remove many sockets */ |
|
static void benchmark_socket_operations(int num_sockets) { |
|
printf("=== Socket Management Benchmark ===\n"); |
|
printf("Testing with %d sockets\n\n", num_sockets); |
|
|
|
uasync_t* ua = uasync_create(); |
|
if (!ua) { |
|
printf("Failed to create uasync\n"); |
|
return; |
|
} |
|
|
|
/* Create socket array */ |
|
int* sockets = malloc(num_sockets * sizeof(int)); |
|
void** socket_ids = malloc(num_sockets * sizeof(void*)); |
|
if (!sockets || !socket_ids) { |
|
printf("Memory allocation failed\n"); |
|
free(sockets); |
|
free(socket_ids); |
|
uasync_destroy(ua); |
|
return; |
|
} |
|
|
|
/* Create sockets */ |
|
for (int i = 0; i < num_sockets; i++) { |
|
sockets[i] = socket(AF_INET, SOCK_DGRAM, 0); |
|
if (sockets[i] < 0) { |
|
printf("Failed to create socket %d\n", i); |
|
// Clean up created sockets |
|
for (int j = 0; j < i; j++) { |
|
close(sockets[j]); |
|
} |
|
free(sockets); |
|
free(socket_ids); |
|
uasync_destroy(ua); |
|
return; |
|
} |
|
|
|
/* Make non-blocking */ |
|
int flags = fcntl(sockets[i], F_GETFL, 0); |
|
fcntl(sockets[i], F_SETFL, flags | O_NONBLOCK); |
|
} |
|
|
|
printf("Created %d sockets\n", num_sockets); |
|
|
|
/* Benchmark 1: Add all sockets */ |
|
uint64_t start_time = get_time_us(); |
|
for (int i = 0; i < num_sockets; i++) { |
|
socket_ids[i] = uasync_add_socket(ua, sockets[i], test_socket_callback, NULL, NULL, NULL); |
|
if (!socket_ids[i]) { |
|
printf("Failed to add socket %d\n", i); |
|
break; |
|
} |
|
} |
|
uint64_t add_time = get_time_us() - start_time; |
|
|
|
printf("Add %d sockets: %llu us (%.2f us per socket)\n", |
|
num_sockets, (unsigned long long)add_time, (double)add_time / num_sockets); |
|
|
|
/* Benchmark 2: Poll multiple times */ |
|
int poll_iterations = 1000; |
|
start_time = get_time_us(); |
|
for (int iter = 0; iter < poll_iterations; iter++) { |
|
uasync_poll(ua, 0); // Non-blocking poll |
|
} |
|
uint64_t poll_time = get_time_us() - start_time; |
|
|
|
printf("%d poll iterations: %llu us (%.2f us per poll)\n", |
|
poll_iterations, (unsigned long long)poll_time, (double)poll_time / poll_iterations); |
|
|
|
/* Benchmark 3: Remove all sockets */ |
|
start_time = get_time_us(); |
|
for (int i = 0; i < num_sockets; i++) { |
|
if (socket_ids[i]) { |
|
uasync_remove_socket(ua, socket_ids[i]); |
|
} |
|
} |
|
uint64_t remove_time = get_time_us() - start_time; |
|
|
|
printf("Remove %d sockets: %llu us (%.2f us per socket)\n", |
|
num_sockets, (unsigned long long)remove_time, (double)remove_time / num_sockets); |
|
|
|
/* Calculate total time */ |
|
uint64_t total_time = add_time + poll_time + remove_time; |
|
printf("\nTotal time: %llu us\n", (unsigned long long)total_time); |
|
printf("Average per operation: %.2f us\n", (double)total_time / (num_sockets * 2 + poll_iterations)); |
|
|
|
/* Memory usage */ |
|
size_t timer_alloc, timer_free, socket_alloc, socket_free; |
|
uasync_get_stats(ua, &timer_alloc, &timer_free, &socket_alloc, &socket_free); |
|
printf("\nMemory stats: timers %zu/%zu, sockets %zu/%zu\n", |
|
timer_alloc, timer_free, socket_alloc, socket_free); |
|
|
|
/* Cleanup */ |
|
for (int i = 0; i < num_sockets; i++) { |
|
close(sockets[i]); |
|
} |
|
free(sockets); |
|
free(socket_ids); |
|
uasync_destroy(ua); |
|
} |
|
|
|
/* Benchmark: High-frequency operations */ |
|
static void benchmark_high_frequency(void) { |
|
printf("\n=== High-Frequency Operations Benchmark ===\n"); |
|
|
|
uasync_t* ua = uasync_create(); |
|
if (!ua) { |
|
printf("Failed to create uasync\n"); |
|
return; |
|
} |
|
|
|
/* Create a few sockets for high-frequency operations */ |
|
int num_sockets = 10; |
|
int sockets[num_sockets]; |
|
void* socket_ids[num_sockets]; |
|
|
|
for (int i = 0; i < num_sockets; i++) { |
|
sockets[i] = socket(AF_INET, SOCK_DGRAM, 0); |
|
int flags = fcntl(sockets[i], F_GETFL, 0); |
|
fcntl(sockets[i], F_SETFL, flags | O_NONBLOCK); |
|
|
|
socket_ids[i] = uasync_add_socket(ua, sockets[i], test_socket_callback, NULL, NULL, NULL); |
|
} |
|
|
|
/* Benchmark: Rapid add/remove cycles */ |
|
int cycles = 10000; |
|
printf("Testing %d rapid add/remove cycles...\n", cycles); |
|
|
|
uint64_t start_time = get_time_us(); |
|
for (int cycle = 0; cycle < cycles; cycle++) { |
|
/* Remove all sockets */ |
|
for (int i = 0; i < num_sockets; i++) { |
|
if (socket_ids[i]) { |
|
uasync_remove_socket(ua, socket_ids[i]); |
|
socket_ids[i] = NULL; |
|
} |
|
} |
|
|
|
/* Add them back */ |
|
for (int i = 0; i < num_sockets; i++) { |
|
socket_ids[i] = uasync_add_socket(ua, sockets[i], test_socket_callback, NULL, NULL, NULL); |
|
} |
|
|
|
/* Poll once per cycle */ |
|
uasync_poll(ua, 0); |
|
} |
|
uint64_t total_time = get_time_us() - start_time; |
|
|
|
printf("Completed %d cycles in %llu us\n", cycles, (unsigned long long)total_time); |
|
printf("Average time per cycle: %.2f us\n", (double)total_time / cycles); |
|
printf("Operations per second: %.0f\n", (double)(cycles * num_sockets * 2) / (total_time / 1000000.0)); |
|
|
|
/* Cleanup */ |
|
for (int i = 0; i < num_sockets; i++) { |
|
close(sockets[i]); |
|
} |
|
uasync_destroy(ua); |
|
} |
|
|
|
/* Benchmark: Scalability test */ |
|
static void benchmark_scalability(void) { |
|
printf("\n=== Scalability Test ===\n"); |
|
|
|
int test_sizes[] = {10, 50, 100, 200, 500, 1000}; |
|
int num_tests = sizeof(test_sizes) / sizeof(test_sizes[0]); |
|
|
|
printf("Testing scalability with different numbers of sockets:\n"); |
|
|
|
for (int test = 0; test < num_tests; test++) { |
|
int num_sockets = test_sizes[test]; |
|
|
|
uasync_t* ua = uasync_create(); |
|
if (!ua) continue; |
|
|
|
/* Create sockets */ |
|
int* sockets = malloc(num_sockets * sizeof(int)); |
|
void** socket_ids = malloc(num_sockets * sizeof(void*)); |
|
|
|
for (int i = 0; i < num_sockets; i++) { |
|
sockets[i] = socket(AF_INET, SOCK_DGRAM, 0); |
|
int flags = fcntl(sockets[i], F_GETFL, 0); |
|
fcntl(sockets[i], F_SETFL, flags | O_NONBLOCK); |
|
|
|
socket_ids[i] = uasync_add_socket(ua, sockets[i], test_socket_callback, NULL, NULL, NULL); |
|
} |
|
|
|
/* Measure poll time */ |
|
uint64_t start_time = get_time_us(); |
|
for (int iter = 0; iter < 100; iter++) { |
|
uasync_poll(ua, 0); |
|
} |
|
uint64_t poll_time = get_time_us() - start_time; |
|
|
|
printf(" %d sockets: %.2f us per poll (%.2f ns per socket)\n", |
|
num_sockets, (double)poll_time / 100, |
|
((double)poll_time / 100) * 1000 / num_sockets); |
|
|
|
/* Cleanup */ |
|
for (int i = 0; i < num_sockets; i++) { |
|
close(sockets[i]); |
|
} |
|
free(sockets); |
|
free(socket_ids); |
|
uasync_destroy(ua); |
|
} |
|
} |
|
|
|
int main(void) { |
|
printf("lib Socket Management Performance Benchmark\n"); |
|
printf("================================================\n\n"); |
|
|
|
/* Run benchmarks */ |
|
benchmark_socket_operations(100); // 100 sockets |
|
benchmark_socket_operations(1000); // 1000 sockets |
|
benchmark_high_frequency(); // High-frequency operations |
|
benchmark_scalability(); // Scalability test |
|
|
|
printf("\n=== Benchmark Complete ===\n"); |
|
printf("Array-based socket management provides:\n"); |
|
printf("- O(1) add/remove operations (vs O(n) for linked list)\n"); |
|
printf("- Better cache locality for sequential socket processing\n"); |
|
printf("- Direct FD-to-index mapping for fast lookups\n"); |
|
printf("- Reduced memory allocations per operation\n"); |
|
|
|
return 0; |
|
} |