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