#include <stdio.h>
#include <string.h>
#include <unistd.h>
+#include <getopt.h>
#include <time.h>
#include <math.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <linux/can.h>
#include <pthread.h>
+#include "cegwerr.h"
+#include "readif.h"
/**
* ToDo:
* [ ] consider can timestamp
*/
+//#define BENCH_DEBUG
+#ifdef BENCH_DEBUG
+#define printdbg(...) printf( __VA_ARGS__ )
+#else
+#define printdbg(...)
+#endif
+
+#define BENCH_FLAG_N 1
+#define BENCH_FLAG_SRC 2
+#define BENCH_FLAG_DST 4
+
+enum {
+ BENCH_MODE_UNDEF,
+ BENCH_MODE_ASAP,
+ BENCH_MODE_ONEATTIME,
+ BENCH_MODE_PERIOD
+};
+
+int can_sock_create( int ifindex );
+int udp_sock_create( struct in_addr ip, unsigned int port );
+
struct optdata
{
+ int optflag;
+ int mode;
int n;
+ struct cegw_if ceif[2]; /* 0 -> src, 1 -> dst */
};
struct optdata d;
pthread_barrier_t barrier;
struct timespec* tx_time, * rx_time;
-void* udp_recv( void* arg )
+void* thr_recv( void* arg )
{
- struct sockaddr_in sa_udp;
- int udp_sock;
+ int sock;
struct can_frame cf;
int i;
+ int seq;
- sa_udp.sin_family = AF_INET;
- sa_udp.sin_port = htons( 10502 );
- inet_aton( "127.0.0.1", &sa_udp.sin_addr );
-
- udp_sock = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
- if( udp_sock < 0 )
+ if( d.ceif[1].type == IF_CAN )
+ sock = can_sock_create( d.ceif[1].can.ifindex );
+ else
+ sock = udp_sock_create( d.ceif[1].eth.ip, d.ceif[1].eth.port );
+ if( sock == -1 )
{
- fprintf( stderr, "error: udp socket creation failed\n" );
- return NULL;
- }
-
- if( bind(udp_sock, (struct sockaddr*)&sa_udp, sizeof(sa_udp)) != 0 )
- {
- fprintf( stderr, "error: udp socket binding failed\n" );
+ /* ToDo: handle */
return NULL;
}
/* recv */
for( i=0; i<d.n; i++ )
{
- recvfrom( udp_sock, &cf, sizeof(cf), 0, NULL, 0 );
- clock_gettime( CLOCK_REALTIME, &rx_time[cf.data[0]] );
- printf( "recv: (id=%d)%u\n", cf.can_id, cf.data[0] );
+ recvfrom( sock, &cf, sizeof(cf), 0, NULL, 0 );
+ seq = *((int*)cf.data);
+ clock_gettime( CLOCK_REALTIME, &rx_time[ seq ] );
+ printdbg( "recv: (id=%d)%d\n", cf.can_id, seq );
+ if( d.mode == BENCH_MODE_ONEATTIME )
+ {
+ pthread_barrier_wait( &barrier );
+ }
}
- close( udp_sock );
+ close( sock );
return NULL;
}
int timespec_subtract( struct timespec *result, struct timespec *x, struct timespec *yy )
{
struct timespec ylocal = *yy, *y = &ylocal;
- /* Perform the carry for the later subtraction by updating Y. */
+/* Perform the carry for the later subtraction by updating Y. */
if( x->tv_nsec < y->tv_nsec )
{
int nsec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1;
y->tv_nsec -= 1000000000 * nsec;
y->tv_sec += nsec;
- }
- if (x->tv_nsec - y->tv_nsec > 1000000000) {
+ }
+ if (x->tv_nsec - y->tv_nsec > 1000000000)
+ {
int nsec = (x->tv_nsec - y->tv_nsec) / 1000000000;
y->tv_nsec += 1000000000 * nsec;
y->tv_sec -= nsec;
return x->tv_sec < y->tv_sec;
}
+int udp_sock_create( struct in_addr ip, unsigned int port )
+{
+ struct sockaddr_in addr_udp;
+ int udp_sock;
+
+ addr_udp.sin_family = AF_INET;
+ addr_udp.sin_port = htons( port );
+ addr_udp.sin_addr.s_addr = INADDR_ANY;
+
+ udp_sock = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
+ if( udp_sock < 0 )
+ {
+ fprintf( stderr, "error: udp socket creation failed\n" );
+ return -1;
+ }
+
+ if( bind(udp_sock, (struct sockaddr*)&addr_udp, sizeof(addr_udp)) != 0 )
+ {
+ fprintf( stderr, "error: udp socket binding failed\n" );
+ return -1;
+ }
+
+ return udp_sock;
+}
+
+/**
+ * can_sock_create()
+ * @return can socket fd, or -1 on failure
+ */
+int can_sock_create( int ifindex )
+{
+ int can_sock;
+ struct sockaddr_can addr_can;
+
+ addr_can.can_family = AF_CAN;
+ addr_can.can_ifindex = ifindex;
+
+ can_sock = socket( PF_CAN, SOCK_RAW, CAN_RAW );
+ if( can_sock < 0 )
+ {
+ fprintf( stderr, "error: can socket creation failed\n" );
+ return -1;
+ }
+
+ if( bind(can_sock, (struct sockaddr*)&addr_can, sizeof(addr_can)) != 0 )
+ {
+ fprintf( stderr, "error: can socket binding failed\n" );
+ return -1;
+ }
+
+ return can_sock;
+}
+
+void dump_arg( int argc, char* argv[] )
+{
+ int i;
+
+ putchar( '#' );
+ for( i=0; i<argc; i++ )
+ {
+ printf( "%s ", argv[i] );
+ }
+ putchar( '\n' );
+}
+
+int read_mode( char* in )
+{
+ if( strcmp( in, "asap" ) == 0 )
+ return BENCH_MODE_ASAP;
+ if( strcmp( in, "oneattime") == 0 )
+ return BENCH_MODE_ONEATTIME;
+ if( strcmp( in, "period" ) == 0 )
+ return BENCH_MODE_PERIOD;
+
+ return BENCH_MODE_UNDEF;
+}
+
int main( int argc, char* argv[] )
{
char opt;
- struct sockaddr_can sa_can;
struct can_frame cf;
- int can_sock;
+ int sock;
pthread_t thr;
- float mean = 0;
float time;
+ int ret;
struct timespec res;
- int i;
+ int i, tmp;
+
+ d.optflag = 0;
+ d.mode = BENCH_MODE_ASAP;
+
+ struct option longopt[] =
+ {
+ { "mode", 0, NULL, 'm' },
+ { 0, 0, 0, 0 }
+ };
while( 1 )
{
- opt = getopt( argc, argv, "n:" );
+ opt = getopt( argc, argv, "s:d:m:n:" );
if( opt == -1 )
break;
switch( opt )
{
+ case 's':
+ d.optflag |= BENCH_FLAG_SRC;
+ if( read_if( optarg, &d.ceif[0] ) != 0 )
+ {
+ perr( "'-s'" );
+ return -1;
+ }
+ break;
+ case 'd':
+ d.optflag |= BENCH_FLAG_DST;
+ if( read_if( optarg, &d.ceif[1] ) )
+ {
+ perr( "-d" );
+ return -1;
+ }
+ break;
+ case 'm':
+ tmp = read_mode( optarg );
+ if( tmp == BENCH_MODE_UNDEF )
+ {
+ perr( "benchmarking mode unknown" );
+ return -1;
+ }
+ d.mode = tmp;
+ break;
case 'n':
+ d.optflag |= BENCH_FLAG_N;
d.n = atoi( optarg );
break;
case '?':
}
}
+ /* check opt */
+ /* '-n' option is mandatory and its value is >0 */
+ if( d.optflag & BENCH_FLAG_N )
+ {
+ if( d.n < 1 )
+ {
+ perr( "'-n' should be at least 1." );
+ }
+ } else
+ {
+ perr( "'-n' is mandatory." );
+ return -1;
+ }
+
+ /* '-s' and '-d' should be defined and different iftype */
+ if( (d.optflag & BENCH_FLAG_SRC) && (d.optflag & BENCH_FLAG_DST) )
+ {
+ if( !(d.ceif[0].type == IF_CAN && d.ceif[1].type == IF_ETH_UDP) &&
+ !(d.ceif[0].type == IF_ETH_UDP && d.ceif[1].type == IF_CAN ) )
+ {
+ perr( "'-s' and '-d' should be different interface type." );
+ return -1;
+ }
+ } else
+ {
+ perr( "'-s' and '-d' should be defined." );
+ return -1;
+ }
+
tx_time = malloc( d.n*sizeof(struct timespec) );
rx_time = malloc( d.n*sizeof(struct timespec) );
pthread_barrier_init( &barrier, NULL, 2 );
- pthread_create( &thr, NULL, udp_recv, NULL );
+ pthread_create( &thr, NULL, thr_recv, NULL );
- sa_can.can_family = AF_CAN;
- sa_can.can_ifindex = if_nametoindex( "vcan0" );
-
- can_sock = socket( PF_CAN, SOCK_RAW, CAN_RAW );
- if( can_sock < 0 )
+ /**/
+ struct sockaddr* addr;
+ struct sockaddr_can addr_can;
+ struct sockaddr_in addr_udp;
+ int addr_size;
+
+ if( d.ceif[0].type == IF_CAN )
{
- fprintf( stderr, "error: can socket creation failed\n" );
- return -1;
+ sock = socket( PF_CAN, SOCK_RAW, CAN_RAW );
+ addr_can.can_family = AF_CAN;
+ addr_can.can_ifindex = d.ceif[0].can.ifindex;
+ addr = (struct sockaddr*)&addr_can;
+ addr_size = sizeof( addr_can );
}
-
- if( bind(can_sock, (struct sockaddr*)&sa_can, sizeof(sa_can)) != 0 )
+ else
{
- fprintf( stderr, "error: can socket binding failed\n" );
- return -1;
+ sock = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
+ addr_udp.sin_family = AF_INET;
+ addr_udp.sin_addr = d.ceif[0].eth.ip;
+ addr_udp.sin_port = htons( d.ceif[0].eth.port );
+ addr = (struct sockaddr*)&addr_udp;
+ addr_size = sizeof( addr_udp );
}
+ if( sock < 0 ) /* ToDo: ? */
+ return -1;
pthread_barrier_wait( &barrier );
/* send */
for( i=0; i<d.n; i++ )
{
- //memset( &cf, 0, sizeof(cf) );
cf.can_id = i;
cf.can_dlc = 8;
- cf.data[0] = i;
- int ret = sendto( can_sock, &cf, sizeof(cf), 0, (struct sockaddr*)&sa_can, sizeof(sa_can) );
+ memcpy( cf.data, &i, sizeof(i) );
+
clock_gettime( CLOCK_REALTIME, &tx_time[cf.data[0]] );
- printf( "sending(%d)\n", ret );
+ ret = sendto( sock, &cf, sizeof(cf), 0, addr, addr_size ); /* ToDo: check ret */
+ printdbg( "sending(%d)\n", ret );
+ if( d.mode == BENCH_MODE_ONEATTIME )
+ {
+ pthread_barrier_wait( &barrier );
+ }
}
- close( can_sock ); /* shutdown? */
+ close( sock ); /* ToDo: shutdown? */
pthread_join( thr, NULL );
/* results */
+ dump_arg( argc, argv );
for( i=0; i<d.n; i++ )
{
- if( timespec_subtract( &res, &rx_time[i], &tx_time[i] ) == 0 )
- {
- time = res.tv_sec*1000000000.0f + (float)res.tv_nsec;
- mean += time;
- printf( "transfer time:%fns\n", time );
- } else
- {
- printf( "transfer time: irrelevant\n" );
- }
+ timespec_subtract( &res, &rx_time[i], &tx_time[i] );
+
+ time = res.tv_sec*1000000000.0f + (float)res.tv_nsec;
+ printf( "%f\t", time );
}
- mean /= ++i;
- printf( "average: %fns\n", mean );
+ putchar( '\n' );
+ pthread_barrier_destroy( &barrier );
free( tx_time );
free( rx_time );
-// clock_gettime( CLOCK_REALTIME, &tx_time );
return 0;
}