git.iko.soy/distributed-process
on 478d769 help sign in
183 lines 4.6 kB history raw
1/**
2 * Compute baseline average and standard deviancy ping latency
3 *
4 * Compile using
5 *
6 * gcc -o pingtest -O2 -std=c99 pingtest.c
7 *
8 * Then start server
9 *
10 * ./pingtest server &
11 *
12 * And finally start the client
13 *
14 * ./pingtest client <number of pings; for instance, 10000>
15 *
16 * The server will terminate when the client does.
17 *
18 * Edsko de Vries <edsko@well-typed.com>
19 */
21#include <stdio.h>
22#include <stdlib.h>
23#include <sys/types.h>
24#include <sys/socket.h>
25#include <netdb.h>
26#include <string.h>
27#include <unistd.h>
28#include <signal.h>
29#include <errno.h>
30#include <time.h>
31#include <sys/time.h>
32#include <math.h>
34// Note: this is not consistent across CPUs (and hence across threads on multicore machines)
35double timestamp() {
36 struct timeval tp;
37 gettimeofday(&tp, NULL);
38 return ((double) tp.tv_sec) * 1e6 + (double) tp.tv_usec;
41int server() {
42 printf("starting server\n");
44 struct addrinfo hints, *res;
45 int error, server_socket;
47 memset(&hints, 0, sizeof(hints));
48 hints.ai_family = PF_INET;
49 hints.ai_socktype = SOCK_STREAM;
50 hints.ai_flags = AI_PASSIVE;
52 error = getaddrinfo(NULL, "8080", &hints, &res);
53 if(error) {
54 printf("server error: %s\n", gai_strerror(error));
55 return -1;
56 }
58 server_socket = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
59 if(server_socket < 0) {
60 printf("server error: could not create socket\n");
61 return -1;
62 }
64 int yes = 1;
65 if(setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) < 0) {
66 printf("server error: could not set socket options\n");
67 return -1;
68 }
70 if(bind(server_socket, res->ai_addr, res->ai_addrlen) < 0) {
71 printf("server error: could not bind to socket\n");
72 return -1;
73 }
75 listen(server_socket, 5);
77 int client_socket;
78 struct sockaddr_storage client_addr;
79 socklen_t addr_size;
80 client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &addr_size);
82 for(;;) {
83 char buf[8];
84 ssize_t read = recv(client_socket, &buf, 8, 0);
85 // printf("server received '%s'\n", buf);
86 send(client_socket, buf, 8, 0);
87 }
89 freeaddrinfo(res);
90 return 0;
93int client(int pings) {
94 printf("starting client\n");
96 struct addrinfo hints, *res;
97 int error, client_socket;
99 memset(&hints, 0, sizeof(hints));
100 hints.ai_family = PF_INET;
101 hints.ai_socktype = SOCK_STREAM;
103 error = getaddrinfo("127.0.0.1", "8080", &hints, &res);
104 if(error) {
105 printf("client error: %s\n", gai_strerror(error));
106 return -1;
107 }
109 client_socket = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
110 if(client_socket < 0) {
111 printf("client error: could not create socket\n");
112 return -1;
113 }
115 if(connect(client_socket, res->ai_addr, res->ai_addrlen) < 0) {
116 printf("client error: could not connect: %s\n", strerror(errno));
117 return -1;
118 }
120 double* round_trip_latency = (double*) calloc(pings, sizeof(double));
122 for(int i = 0; i < pings; i++) {
123 double timestamp_before = timestamp();
125 send(client_socket, "ping123", 8, 0);
127 char buf[8];
128 ssize_t read = recv(client_socket, &buf, 8, 0);
129 // printf("client received '%s'\n", buf);
131 double timestamp_after = timestamp();
132 round_trip_latency[i] = timestamp_after - timestamp_before;
133 }
135 printf("client did %d pings\n", pings);
137 // Write data to a file for plotting
138 FILE* data = fopen("round-trip-latency-c.data", "wt");
139 for(int i = 0; i < pings; i++) {
140 fprintf(data, "%i %lf\n", i, round_trip_latency[i]);
141 }
142 fclose(data);
144 // compute average
145 double round_trip_latency_average = 0;
146 for(int i = 0; i < pings; i++) {
147 round_trip_latency_average += round_trip_latency[i];
148 };
149 round_trip_latency_average /= (double) pings;
152 // compute standard deviation
153 double round_trip_latency_stddev = 0;
154 for(int i = 0; i < pings; i++) {
155 round_trip_latency_stddev += pow(round_trip_latency[i] - round_trip_latency_average, 2);
156 }
157 round_trip_latency_stddev = sqrt(round_trip_latency_stddev / (double) (pings - 1));
159 printf("average round-trip latency: %lf us (standard devitation %lf us)\n", round_trip_latency_average, round_trip_latency_stddev);
161 freeaddrinfo(res);
162 return 0;
165int usage(int argc, char** argv) {
166 printf("usage: %s <number of pings>\n", argv[0]);
167 return -1;
170int main(int argc, char** argv) {
171 if(argc != 2) {
172 return usage(argc, argv);
173 }
175 if(fork() == 0) {
176 // TODO: we should wait until we know the server is ready
177 int pings = 0;
178 sscanf(argv[1], "%d", &pings);
179 return client(pings);
180 } else {
181 return server();
182 }