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