1 //
2 // Copyright (C) 2015 Aaron Ball <nullspoon@iohq.net>
3 //
4 // Cnetbench is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Cnetbench is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with cnetbench. If not, see <http://www.gnu.org/licenses/>.
16 //
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20
21 #include "common.h"
22 #include "test.h"
23
24
25 void get_help() {
26 printf(
27 "\n"
28 "Cnetbench is a simple protocol-agnostic network benchmarking program.\n"
29 "Simply put, it is a fire-hydrant of data and sends as much data as is\n"
30 "allowed, and reports what those numbers are. This can be single stream\n"
31 "or multiple concurrent data streams.\n"
32 "\n"
33 "Usage:\n\n"
34 " cnetbench -d <destination> -p <port> [-m <megabytes>] [-c <stream_count>]"
35 "\n\n");
36 }
37
38
39 //
40 // Prints test results in a friendly, human-readable format.
41 //
42 // @param t_test* Test type containing test parameters
43 // @param start_times Array of child start times, ordered by child process index
44 // @param exit_times Array of child exit times, ordered by child process index
45 //
46 void print_results(t_test *t,
47 struct timeval *start_times,
48 struct timeval *exit_times) {
49 // Clear a little space
50 printf("\n\n");
51
52 long total_amount = t->amount * t->streams;
53 double total_time = 0;
54
55 for(int i = 0; i < t->streams; i++) {
56 // calculate average transfer rate for this thread
57
58 // Second difference, multiplied by 1000 to make room for microseconds
59 double time_s = 1000 * (exit_times[i].tv_sec - start_times[i].tv_sec);
60 // Microsecond difference
61 double time_ms = exit_times[i].tv_usec - start_times[i].tv_usec;
62 // Sum of microsecond and second differences
63 double time = (time_s + time_ms) / 1000;
64
65 // Append duration to the total duration of transfers.
66 total_time += time;
67
68 double avg = t->amount / time;
69
70 printf("Fork %d/%d transferred %d MB in %.4f seconds, averaging %.2f MB/s\n",
71 i + 1,
72 t->streams,
73 t->amount,
74 time,
75 avg
76 );
77 }
78
79 printf("\n%d forks transferred a total of %ld MBs in %.2f parallel seconds\n",
80 t->streams,
81 total_amount,
82 total_time
83 );
84 }
85
86
87 //
88 // Parses the program arguments and populates a t_test type with the values
89 // specified by the user.
90 //
91 // @param argc Number of arguments passed to the program (the main argc)
92 // @param argv Arguments passed to the program (the main argv)
93 // @param test T_test object to be populated
94 //
95 int parse_args(int argc, char *argv[], t_test *test) {
96 int i = 1;
97
98 char server = 0;
99 char port = 0;
100
101 while(i < argc) {
102 if(strcmp(argv[i], "-m") == 0 || strcmp(argv[i], "--megabytes") == 0) {
103 ++i;
104 test->amount = atoi(argv[i]);
105 } else if(strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--count") == 0) {
106 ++i;
107 test->streams = atoi(argv[i]);
108 } else if(strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--dest") == 0) {
109 ++i;
110 strcpy(test->server, argv[i]);
111 server = 1;
112 } else if(strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "--port") == 0) {
113 ++i;
114 test->port = atoi(argv[i]);
115 port = 1;
116 } else {
117 get_help();
118 return 1;
119 }
120 ++i;
121 }
122
123 if(server == 0) {
124 printf("Please specify a destination server (-d,--dest) to test with.\n");
125 return 1;
126 }
127 if(port == 0) {
128 printf("Please specify a port (-p,--port) to run tests over.\n");
129 return 1;
130 }
131
132 return 0;
133 }
134
135
136 //
137 // Ye olde main
138 //
139 int main(int argc, char *argv[]) {
140 t_test test;
141
142 // Initialize the test object with defaults
143 new_test(&test);
144 // Parse program arguments
145 int arg_status = parse_args(argc, argv, &test);
146
147 if(arg_status > 0)
148 return 1;
149
150 struct timeval start_times[test.streams];
151 struct timeval exit_times[test.streams];
152
153 test_start_all(&test, start_times, exit_times);
154 print_results(&test, start_times, exit_times);
155
156 return 0;
157 }
|