]> rtime.felk.cvut.cz Git - can-eth-gw.git/blob - utils/cegwbench/cegwbench.c
kernel/canethgw mutex_unlock bug fix
[can-eth-gw.git] / utils / cegwbench / cegwbench.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <getopt.h>
6 #include <time.h>
7 #include <math.h>
8 #include <sys/socket.h>
9 #include <netinet/in.h>
10 #include <net/if.h>
11 #include <arpa/inet.h>
12 #include <linux/can.h>
13 #include <pthread.h>
14 #include "cegwerr.h"
15 #include "readif.h"
16
17 //#define BENCH_DEBUG
18 #ifdef BENCH_DEBUG
19 #define printdbg(...) printf( __VA_ARGS__ )
20 #else
21 #define printdbg(...)
22 #endif
23
24 #define BENCH_FLAG_N 1
25 #define BENCH_FLAG_SRC 2
26 #define BENCH_FLAG_DST 4
27 #define BENCH_FLAG_TIMEO 8
28
29 enum {
30         BENCH_MODE_UNDEF,
31         BENCH_MODE_ASAP,
32         BENCH_MODE_ONEATTIME,
33         BENCH_MODE_PERIOD
34 };
35
36 int can_sock_create( int ifindex );
37 int udp_sock_create( struct in_addr ip, unsigned int port );
38
39 struct optdata
40 {
41         int optflag;
42         int mode;
43         int n;
44         struct timeval timeo;
45         struct cegw_if ceif[2]; /* 0 -> src, 1 -> dst */
46 };
47
48 struct optdata d;
49 pthread_barrier_t barrier;
50 struct timespec* tx_time, * rx_time;
51
52 void* thr_recv( void* arg )
53 {
54         int sock;
55         struct can_frame cf;
56         int i;
57         int seq;
58         int ret;
59
60         if( d.ceif[1].type == IF_CAN )
61                 sock = can_sock_create( d.ceif[1].can.ifindex );
62         else
63                 sock = udp_sock_create( d.ceif[1].eth.ip, d.ceif[1].eth.port );
64         if( sock == -1 )
65         {
66                 /* ToDo: handle */
67                 return (void*)1;
68         }
69
70         ret = setsockopt( sock, SOL_SOCKET, SO_RCVTIMEO, &d.timeo, sizeof(d.timeo) );
71         if( ret != 0 )
72                 return (void*)1;
73
74         pthread_barrier_wait( &barrier );
75
76         /* recv */
77         for( i=0; i<d.n; i++ )
78         {
79                 ret = recvfrom( sock, &cf, sizeof(cf), 0, NULL, 0 );
80                 printdbg( "ret=%d\n", ret );
81                 /* ToDo: rework */
82                 if( ret == -1 )
83                 {
84                         puts( "cegwbench: recv timed out\n" );
85                         return (void*)1;
86                 }
87                 seq = *((int*)cf.data);
88                 clock_gettime( CLOCK_REALTIME, &rx_time[ seq ] );
89                 printdbg( "recv: cf.data=%d\n", seq );
90                 if( d.mode == BENCH_MODE_ONEATTIME )
91                 {
92                         pthread_barrier_wait( &barrier );
93                 }
94         }
95
96         close( sock );
97         return (void*)0;
98 }
99
100 int timespec_subtract( struct timespec *result, struct timespec *x, struct timespec *yy )
101 {
102         struct timespec ylocal = *yy, *y = &ylocal;
103 /* Perform the carry for the later subtraction by updating Y. */
104         if( x->tv_nsec < y->tv_nsec )
105         {
106                 int nsec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1;
107                 y->tv_nsec -= 1000000000 * nsec;
108                 y->tv_sec += nsec;
109         }
110         if (x->tv_nsec - y->tv_nsec > 1000000000)
111         {
112                 int nsec = (x->tv_nsec - y->tv_nsec) / 1000000000;
113                 y->tv_nsec += 1000000000 * nsec;
114                 y->tv_sec -= nsec;
115         }
116
117         /* Compute the time remaining to wait.
118          *         `tv_nsec' is certainly positive. */
119         result->tv_sec = x->tv_sec - y->tv_sec;
120         result->tv_nsec = x->tv_nsec - y->tv_nsec;
121         /* Return 1 if result is negative. */
122         return x->tv_sec < y->tv_sec;
123 }
124
125 int udp_sock_create( struct in_addr ip, unsigned int port  )
126 {
127         struct sockaddr_in addr_udp;
128         int udp_sock;
129
130         addr_udp.sin_family = AF_INET;
131         addr_udp.sin_port = htons( port );
132         addr_udp.sin_addr.s_addr = INADDR_ANY;
133
134         udp_sock = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
135         if( udp_sock < 0 )
136         {
137                 fprintf( stderr, "error: udp socket creation failed\n" );
138                 return -1;
139         }
140
141         if( bind(udp_sock, (struct sockaddr*)&addr_udp, sizeof(addr_udp)) != 0 )
142         {
143                 fprintf( stderr, "error: udp socket binding failed\n" );
144                 return -1;
145         }
146
147         return udp_sock;
148 }
149
150 /**
151  * can_sock_create
152  * @return can socket fd, or -1 on failure
153  */
154 int can_sock_create( int ifindex )
155 {
156         int can_sock;
157         struct sockaddr_can addr_can;
158
159         addr_can.can_family = AF_CAN;
160         addr_can.can_ifindex = ifindex;
161         
162         can_sock = socket( PF_CAN, SOCK_RAW, CAN_RAW );
163         if( can_sock < 0 )
164         {
165                 fprintf( stderr, "error: can socket creation failed\n" );
166                 return -1;
167         }
168
169         if( bind(can_sock, (struct sockaddr*)&addr_can, sizeof(addr_can)) != 0 )
170         {
171                 fprintf( stderr, "error: can socket binding failed\n" );
172                 return -1;
173         }
174
175         return can_sock;
176 }
177
178 void dump_arg( int argc, char* argv[] )
179 {
180         int i;
181
182         putchar( '#' );
183         for( i=0; i<argc; i++ )
184         {
185                 printf( "%s ", argv[i] );
186         }
187         putchar( '\n' );        
188 }
189
190 int read_mode( char* in )
191 {
192         if( strcmp( in, "asap" ) == 0 )
193                 return BENCH_MODE_ASAP;
194         if( strcmp( in, "oneattime") == 0 )
195                 return BENCH_MODE_ONEATTIME;
196         if( strcmp( in, "period" ) == 0 )
197                 return BENCH_MODE_PERIOD;
198
199         return BENCH_MODE_UNDEF;
200 }
201
202 int main( int argc, char* argv[] )
203 {
204         char opt;
205         struct can_frame cf;
206         int sock;
207         pthread_t thr;
208         float time;
209         void* thr_ret;
210         int ret;
211         struct timespec res;
212         int i, tmp;
213
214         d.optflag = 0;
215         d.mode = BENCH_MODE_ASAP;
216         d.timeo.tv_sec = 0;
217         d.timeo.tv_usec = 0;
218
219         struct option longopt[] =
220         {
221                 { "mode", 0, NULL, 'm' },
222                 { 0, 0, 0, 0 }
223         };
224
225         while( 1 )
226         {
227                 opt = getopt( argc, argv, "s:d:m:n:t:" );
228                 if( opt == -1 )
229                         break;
230                 switch( opt )
231                 {
232                         case 's':
233                                 d.optflag |= BENCH_FLAG_SRC;
234                                 if( read_if( optarg, &d.ceif[0] ) != 0 )
235                                 {
236                                         perr( "'-s'" );
237                                         return -1;
238                                 }
239                                 break;
240                         case 'd':
241                                 d.optflag |= BENCH_FLAG_DST;
242                                 if( read_if( optarg, &d.ceif[1] ) )
243                                 {
244                                         perr( "-d" );
245                                         return -1;
246                                 }
247                                 break;
248                         case 'm':
249                                 tmp = read_mode( optarg );
250                                 if( tmp == BENCH_MODE_UNDEF )
251                                 {
252                                         perr( "benchmarking mode unknown" );
253                                         return -1;
254                                 }
255                                 d.mode = tmp;
256                                 break;
257                         case 'n':
258                                 d.optflag |= BENCH_FLAG_N;
259                                 d.n = atoi( optarg );
260                                 break;
261                         case 't':
262                                 d.optflag |= BENCH_FLAG_TIMEO;
263                                 if( sscanf( optarg, "%ld", &d.timeo.tv_sec ) != 1 )
264                                 {
265                                         perr( "timeout mismatch" );
266                                         return -1;
267                                 }
268                                 d.timeo.tv_usec = 0;
269                                 break;
270                         case '?':
271                                 return -1;
272                                 break;
273                 }
274         }
275
276         /* check opt */
277         /* '-n' option is mandatory and its value is >0 */
278         if( d.optflag & BENCH_FLAG_N )
279         {
280                 if( d.n < 1 )
281                 {
282                         perr( "'-n' should be at least 1." );
283                 }
284         } else 
285         {
286                 perr( "'-n' is mandatory." );
287                 return -1;
288         }
289
290         /* '-s' and '-d' should be defined and different iftype */
291         if( (d.optflag & BENCH_FLAG_SRC) && (d.optflag & BENCH_FLAG_DST) )
292         {
293                 if( !(d.ceif[0].type == IF_CAN     && d.ceif[1].type == IF_ETH_UDP) &&
294                     !(d.ceif[0].type == IF_ETH_UDP && d.ceif[1].type == IF_CAN    )    )
295                 {
296                         perr( "'-s' and '-d' should be different interface type." );
297                         return -1;
298                 }
299         } else
300         {
301                 perr( "'-s' and '-d' should be defined." );
302                 return -1;
303         }
304
305         tx_time = malloc( d.n*sizeof(struct timespec) );
306         rx_time = malloc( d.n*sizeof(struct timespec) );
307
308         pthread_barrier_init( &barrier, NULL, 2 );
309         pthread_create( &thr, NULL, thr_recv, &d  );
310
311         /**/
312         struct sockaddr* addr;
313         struct sockaddr_can addr_can;
314         struct sockaddr_in addr_udp;
315         int addr_size;
316
317         if( d.ceif[0].type == IF_CAN )
318         {
319                 sock = socket( PF_CAN, SOCK_RAW, CAN_RAW );
320                 addr_can.can_family = AF_CAN;
321                 addr_can.can_ifindex = d.ceif[0].can.ifindex;
322                 addr = (struct sockaddr*)&addr_can;
323                 addr_size = sizeof( addr_can );
324         }
325         else
326         {
327                 sock = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
328                 addr_udp.sin_family = AF_INET;
329                 addr_udp.sin_addr = d.ceif[0].eth.ip;
330                 addr_udp.sin_port = htons( d.ceif[0].eth.port );
331                 addr = (struct sockaddr*)&addr_udp;
332                 addr_size = sizeof( addr_udp );
333         }
334         if( sock < 0 ) /* ToDo: ? */
335                 return -1;
336
337         pthread_barrier_wait( &barrier );
338
339         /* send  */
340         for( i=0; i<d.n; i++ )
341         {
342                 cf.can_id = i;
343                 cf.can_dlc = 8;
344                 memcpy( cf.data, &i, sizeof(i) );
345
346                 clock_gettime( CLOCK_REALTIME, &tx_time[i] );
347                 ret = sendto( sock, &cf, sizeof(cf), 0, addr, addr_size ); /* ToDo: check ret */
348                 printdbg( "sending(%d)\n", ret );
349                 if( d.mode == BENCH_MODE_ONEATTIME )
350                 {
351                         pthread_barrier_wait( &barrier );
352                 }
353         }
354
355         close( sock ); /* ToDo: shutdown? */
356         pthread_join( thr, &thr_ret );
357
358         if( thr_ret != NULL )
359         {
360                 return 1;
361         }
362
363         /* results */
364         dump_arg( argc, argv );
365         for( i=0; i<d.n; i++ )
366         {
367                 timespec_subtract( &res, &rx_time[i], &tx_time[i] );
368
369                 time = res.tv_sec*1000000000.0f + (float)res.tv_nsec;
370                 printf( "%f\t", time );
371         }
372         putchar( '\n' );
373
374         pthread_barrier_destroy( &barrier );
375         free( tx_time );
376         free( rx_time );
377
378         return 0;
379 }
380