diff options
Diffstat (limited to 'src/main.c')
-rw-r--r-- | src/main.c | 287 |
1 files changed, 101 insertions, 186 deletions
@@ -16,162 +16,119 @@ // #include <stdlib.h> #include <stdio.h> -#include <sys/socket.h> -#include <arpa/inet.h> -#include <netinet/in.h> -#include <strings.h> -#include <unistd.h> -#include <sys/time.h> -#include <wait.h> +#include <string.h> + +#include "common.h" +#include "test.h" + + +void get_help() { + printf( + "\n" + "Cnetbench is a simple protocol-agnostic network benchmarking program.\n" + "Simply put, it is a fire-hydrant of data and sends as much data as is\n" + "allowed, and reports what those numbers are. This can be single stream\n" + "or multiple concurrent data streams.\n" + "\n" + "Usage:\n\n" + " cnetbench -d <destination> -p <port> [-m <megabytes>] [-c <stream_count>]" + "\n\n"); +} // -// Watches an array of pids for their exit, and updates the output array -// exit_times with each pid's exit timeval struct timestamp (epoch with -// microseconds). -// -// Note that this function does not start the pids, but only watches them. To -// calculate runtime, external code needs to track when the pids were created. -// -// @param pids Array of pid_t pids to be watched -// @param count Number of pids in the pids array -// @param exit_times Array of timeval structs that will contain exit times for -// all of the pids in the array. Must be at least the size of -// the pids array or unpredictable behavior may result. +// Prints test results in a friendly, human-readable format. // -// @return int Overall status of all exited pids (if any fail exit, returns 1) +// @param t_test* Test type containing test parameters +// @param start_times Array of child start times, ordered by child process index +// @param exit_times Array of child exit times, ordered by child process index // -int time_pids(pid_t* pids, int count, struct timeval *exit_times) { - int i; - int waiting = 1; - - while(waiting != 0) { - waiting = 0; - for(i = 0; i < count; i++) { - // Pid with this index has exited, skip it. - if(pids[i] == 0) - continue; - - // 0 = state change (exit) - if(waitpid(pids[i], NULL, WNOHANG) != 0) { - // Child has exited - pids[i] = 0; - // Write the exit time - gettimeofday(&exit_times[i], NULL); - } else { - waiting = 1; - } - } - sleep(1); - } - return 0; -} +void print_results(t_test *t, + struct timeval *start_times, + struct timeval *exit_times) { + // Clear a little space + printf("\n\n"); + long total_amount = t->amount * t->streams; + double total_time = 0; -// -// Performs a benchmark test on the specified destination/port, sending the -// specified amount of data. -// -// @param amount Megabytes to send -// @param dest Destination host to send data to -// @param port Destination port to send the data on -// -// @return int Succcess (0) or failure (1) of data send -// -int test(int amount, char *dest, int port) { - int socket_desc; - // This is 1 megabyte - long size = 1048576; - char *message = calloc(size, 1); - - // AF_INET: ipv4 (AF_INET6 would be ipv6) - // SOCK_STREAM: TCP - // 0: Protocol 0 (IP) - socket_desc = socket(AF_INET, SOCK_STREAM, 0); - - if(socket_desc == -1) { - printf("Error creating socket\n"); - return 1; - } + for(int i = 0; i < t->streams; i++) { + // calculate average transfer rate for this thread - // Set socket values - struct sockaddr_in server; - server.sin_addr.s_addr = inet_addr(dest); - server.sin_family = AF_INET; - server.sin_port = htons(port); + // Second difference, multiplied by 1000 to make room for microseconds + double time_s = 1000 * (exit_times[i].tv_sec - start_times[i].tv_sec); + // Microsecond difference + double time_ms = exit_times[i].tv_usec - start_times[i].tv_usec; + // Sum of microsecond and second differences + double time = (time_s + time_ms) / 1000; - if(connect(socket_desc , (struct sockaddr *)&server , sizeof(server)) < 0) { - printf("Connection error\n"); - return -1; - } - printf("Connected\n"); + // Append duration to the total duration of transfers. + total_time += time; - // Send some data - long i = 0; - while(i < amount) { - if(send(socket_desc, message, size, 0) < 0) { - return -1; - } - i++; + double avg = t->amount / time; + + printf("Fork %d/%d transferred %d MB in %.4f seconds, averaging %.2f MB/s\n", + i + 1, + t->streams, + t->amount, + time, + avg + ); } - free(message); - return 0; + printf("\n%d forks transferred a total of %ld MBs in %.2f parallel seconds\n", + t->streams, + total_amount, + total_time + ); } // -// Forks sub-processes off stream_count times, to test bandwidth to the -// specified destination host/port, sending the specified amount of data. -// -// Note that start_times and exit_times are two arrays that will receive start -// and exit timestamps for each pid for timing purposes. -// -// @param amount Amount of data in megabytes to send -// @param stream_count Number of data streams to test concurrently -// @param dest Destination host to send data to -// @param port Destination port to send data over -// @param start_times Output array of timeval start time timestamps -// @param exit_times Output array of timeval exit time timestamps -// -// @return int Success (0) or failure(1) -// -int spawn_tests(int amount, - int stream_count, - char* dest, - int port, - struct timeval *start_times, - struct timeval *exit_times) { - pid_t pids[stream_count]; - - pid_t pid; - int i = 0; - while(i < stream_count) { - // Fork - pid = fork(); - - if(pid == 0) { - // Execute the test - printf("Fork %d starting\n", i); - test(amount, dest, port); - exit(0); - } else if(pid > 0) { - // parent - pids[i] = pid; - // Set start time - gettimeofday(&start_times[i], NULL); - i++; +// Parses the program arguments and populates a t_test type with the values +// specified by the user. +// +// @param argc Number of arguments passed to the program (the main argc) +// @param argv Arguments passed to the program (the main argv) +// @param test T_test object to be populated +// +int parse_args(int argc, char *argv[], t_test *test) { + int i = 1; + + char server = 0; + char port = 0; + + while(i < argc) { + if(strcmp(argv[i], "-m") == 0 || strcmp(argv[i], "--megabytes") == 0) { + ++i; + test->amount = atoi(argv[i]); + } else if(strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--count") == 0) { + ++i; + test->streams = atoi(argv[i]); + } else if(strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--dest") == 0) { + ++i; + strcpy(test->server, argv[i]); + server = 1; + } else if(strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "--port") == 0) { + ++i; + test->port = atoi(argv[i]); + port = 1; } else { - // failure - printf("%d: Failure\n", i); + get_help(); return 1; } + ++i; } - // Wait for all children to exit, and clock their exit time - time_pids(pids, stream_count, exit_times); + if(server == 0) { + printf("Please specify a destination server (-d,--dest) to test with.\n"); + return 1; + } + if(port == 0) { + printf("Please specify a port (-p,--port) to run tests over.\n"); + return 1; + } - printf("Fin!\n"); return 0; } @@ -180,63 +137,21 @@ int spawn_tests(int amount, // Ye olde main // int main(int argc, char *argv[]) { - int amount; - int stream_count; - char *server; - int port; - - if(argc != 5) { - printf("\nUsage:\n"); - printf(" %s <megabytes> <stream_count> <server-ip> <port>\n\n", argv[0]); - return 1; - } + t_test test; + // Initialize the test object with defaults + new_test(&test); // Parse program arguments - amount = atoi(argv[1]); - stream_count = atoi(argv[2]); - server = argv[3]; - port = atoi(argv[4]); + int arg_status = parse_args(argc, argv, &test); - struct timeval start_times[stream_count]; - struct timeval exit_times[stream_count]; - - spawn_tests(amount, stream_count, server, port, start_times, exit_times); - - // Clear a little space - printf("\n\n"); - - long total_amount = amount * stream_count; - double total_time = 0; - - for(int i = 0; i < stream_count; i++) { - // calculate average transfer rate for this thread - - // Second difference, multiplied by 1000 to make room for microseconds - double time_s = 1000 * (exit_times[i].tv_sec - start_times[i].tv_sec); - // Microsecond difference - double time_ms = exit_times[i].tv_usec - start_times[i].tv_usec; - // Sum of microsecond and second differences - double time = (time_s + time_ms) / 1000; + if(arg_status > 0) + return 1; - // Append duration to the total duration of transfers. - total_time += time; + struct timeval start_times[test.streams]; + struct timeval exit_times[test.streams]; - double avg = amount / time; + test_start_all(&test, start_times, exit_times); + print_results(&test, start_times, exit_times); - printf("Fork %d/%d transferred %d MB in %.4f seconds, averaging %.2f MB/s\n", - i + 1, - stream_count, - amount, - time, - avg - ); - } - - printf("\n%d forks transferred a total of %ld MBs in %.2f parallel seconds\n", - stream_count, - total_amount, - total_time - ); - return 0; } |