Updated the test to handle multiple sinks. The sinks cut their

transmissions by the number of them running so that they do not
overwhelm the source.

Added a simple shell script to kick off sinks on multiple hosts as
well as a source on the host where the shell script is run.  The script
also collects the output of all the sinks and the source into files named
for the host on which the tests are run.  A date is appended to each output
file to make it unique per run.
This commit is contained in:
George V. Neville-Neil 2008-04-24 06:56:45 +00:00
parent a975973d8b
commit 22dd049f7b
3 changed files with 147 additions and 39 deletions

View File

@ -36,7 +36,9 @@
.Op Fl n Ar number
.Op Fl s Ar size
.Op Fl t Ar inter-packet gap
.Op Fl r
.Op Fl M Ar number of clients (source only)
.Op Fl m Ar my client number (sink only)
.Op Fl r
.Sh DESCRIPTION
The
.Nm
@ -48,7 +50,8 @@ the time at which they're received and then reflects them back
over unicast to the source. When the source has captured all
the reflected packets it prints out the round trip time of each.
.Pp
The sink prints out the time between the packets received.
The source prints out the round trip time of packets sent to the
sinks. The sink prints out the time between the packets received.
.Pp
The options are as follows:
.Bl -tag -width ".Fl d Ar argument"
@ -60,6 +63,10 @@ Packet size in bytes.
Number of packets.
.It Fl t Ar gap
Inter-packet gap in nanoseconds.
.It Fl M Ar clients
The number of clients that are listening
.It Fl m Ar my number
The client's number 0, 1, etc.
.It Fl r
This version of
.Nm
@ -73,9 +80,9 @@ of the
command:
.Pp
Source
.Dl "mctest -i em0 -s 1024 -n 100 -t 1"
.Dl "mctest -i em0 -M 1 -s 1024 -n 100 -t 1"
Sink
.Dl "mctest -i em0 -s 1024 -n 100 -r"
.Dl "mctest -i em0 -m 0 -s 1024 -n 100 -r"
.Pp
Send 100 packets of 1024 bytes, with an inter-packet gap of 1 nanosecond.
.Pp

View File

@ -61,7 +61,7 @@ using namespace std;
//
void usage()
{
cout << "mctest -i interface -g multicast group -s packet size -n number -t inter-packet gap\n";
cout << "mctest [-r] -M clients -m client number -i interface -g multicast group -s packet size -n number -t inter-packet gap\n";
exit(-1);
}
@ -86,10 +86,13 @@ void usage(string message)
// @param group ///< multicast group
// @param pkt_size ///< packet Size
// @param number ///< number of packets we're expecting
// @param clients ///< total number of clients (N)
// @param client ///< our client number (0..N)
//
// @return 0 for 0K, -1 for error, sets errno
//
int sink(char *interface, struct in_addr *group, int pkt_size, int number) {
int sink(char *interface, struct in_addr *group, int pkt_size, int number,
int clients, int client) {
int sock, backchan;
@ -172,11 +175,18 @@ int sink(char *interface, struct in_addr *group, int pkt_size, int number) {
perror("recvfrom failed");
return -1;
}
recvd.sin_port = htons(SERVER_PORT);
if (sendto(backchan, packet, pkt_size, 0,
(struct sockaddr *)&recvd, sizeof(recvd)) < 0) {
perror("sendto failed");
return -1;
/*
* Bandwidth limiting. If there are N clients then we want
* 1/N packets from each, otherwise the clients will overwhelm
* the sender.
*/
if (n % clients == client) {
recvd.sin_port = htons(SERVER_PORT + client);
if (sendto(backchan, packet, pkt_size, 0,
(struct sockaddr *)&recvd, sizeof(recvd)) < 0) {
perror("sendto failed");
return -1;
}
}
gettimeofday(&packets[ntohl(*(int *)packet)], 0);
n++;
@ -208,10 +218,11 @@ int sink(char *interface, struct in_addr *group, int pkt_size, int number) {
//
// Structure to hold thread arguments
//
typedef struct server_args {
struct server_args {
struct timeval *packets; ///< The timestamps of returning packets
int number; ///< Number of packets to expect.
int pkt_size; ///< Size of the packets
int client; ///< Which client we listen for
};
//
@ -238,7 +249,7 @@ void* server(void *passed) {
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(SERVER_PORT);
addr.sin_port = htons(SERVER_PORT + args->client);
addr.sin_len = sizeof(addr);
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
@ -279,11 +290,12 @@ void* server(void *passed) {
// @param pkt_size ///< packet size
// @param number ///< number of packets
// @param gap ///< inter packet gap in nano-seconds
// @param clients ///< number of clients we intend to run
//
// @return 0 for OK, -1 for error, sets errno
//
int source(char *interface, struct in_addr *group, int pkt_size,
int number, int gap) {
int number, int gap, int clients) {
int sock;
struct sockaddr_in addr;
@ -346,18 +358,21 @@ int source(char *interface, struct in_addr *group, int pkt_size,
*(int *)packets[i] = htonl(i);
}
struct timeval received[number];
struct timeval sent[number];
server_args args;
pthread_t thread;
args.packets = received;
args.number = number;
args.pkt_size = pkt_size;
struct timeval received[clients][number];
server_args args[clients];
pthread_t thread[clients];
if (pthread_create(&thread, NULL, server, &args) < 0) {
perror("failed to create server thread");
return -1;
}
for (int i = 0;i < clients; i++) {
args[i].pkt_size = pkt_size;
args[i].packets = received[i];
args[i].number = number / clients;
args[i].client = i;
if (pthread_create(&thread[i], NULL, server, &args[i]) < 0) {
perror("failed to create server thread");
return -1;
}
}
struct timespec sleeptime;
sleeptime.tv_sec = 0;
@ -377,16 +392,23 @@ int source(char *interface, struct in_addr *group, int pkt_size,
}
}
if (pthread_join(thread, NULL) < 0) {
perror("failed to join thread");
return -1;
}
for (int i = 0; i < clients; i++) {
if (pthread_join(thread[i], NULL) < 0) {
perror("failed to join thread");
return -1;
}
}
timeval result;
for (int i = 0; i < number; i++) {
timersub(&args.packets[i], &sent[i], &result);
cout << "sec: " << result.tv_sec;
cout << " usecs: " << result.tv_usec << endl;
for (int client = 0;client < clients; client++) {
cout << "Results from client #" << client << endl;
for (int i = 0; i < number; i++) {
if (i % clients != client)
continue;
timersub(&args[client].packets[i], &sent[i], &result);
cout << "sec: " << result.tv_sec;
cout << " usecs: " << result.tv_usec << endl;
}
}
return 0;
@ -415,12 +437,14 @@ int main(int argc, char**argv)
int pkt_size = 0; ///< packet size
int gap = 0; ///< inter packet gap (in nanoseconds)
int number = 0; ///< number of packets to transmit
bool server = false;
bool server = false; ///< are we on he receiving end of multicast
int client = 0; ///< for receivers which client are we
int clients = 1; ///< for senders how many clients are there
if (argc < 2 || argc > 11)
if (argc < 2 || argc > 14)
usage();
while ((ch = getopt(argc, argv, "g:i:n:s:t:rh")) != -1) {
while ((ch = getopt(argc, argv, "M:m:g:i:n:s:t:rh")) != -1) {
switch (ch) {
case 'g':
group = new (struct in_addr );
@ -433,7 +457,7 @@ int main(int argc, char**argv)
break;
case 'n':
number = atoi(optarg);
if (number < 0 || number > 10000)
if (number < 0 || number > INT_MAX)
usage(argv[0] + string(" Error: ") + optarg +
string(" number of packets out of range"));
break;
@ -452,6 +476,12 @@ int main(int argc, char**argv)
case 'r':
server = true;
break;
case 'm':
client = atoi(optarg);
break;
case 'M':
clients = atoi(optarg);
break;
case 'h':
usage(string("Help\n"));
break;
@ -459,9 +489,13 @@ int main(int argc, char**argv)
}
if (server) {
sink(interface, group, pkt_size, number);
if (clients <= 0 || client < 0)
usage("must specify client (-m) and number of clients (-M)");
sink(interface, group, pkt_size, number, clients, client);
} else {
source(interface, group, pkt_size, number, gap);
if (clients <= 0)
usage("must specify number of clients (-M)");
source(interface, group, pkt_size, number, gap, clients);
}
}

View File

@ -0,0 +1,67 @@
#!/bin/sh
#
# A program to act as a test harness for the mctest program
#
# $FreeBSD$
#
# Defaults
size=1024
number=100
group=""
interface="cxgb0"
remote="ssh"
command="/sources/FreeBSD.CURRENT/src/tools/tools/mctest/mctest"
gap=1000
# Arguments are s (size), g (group), n (number), and c (command) followed
# by a set of hostnames.
args=`getopt s:g:n:c:i: $*`
if [ $? != 0 ]
then
echo 'Usage: mctest_run -s size -g group -n number -c remote command host1 host2 hostN'
exit 2
fi
set == $args
count=0
for i
do
case "$i"
in
-s)
size=$3;
shift 2;;
-n)
number=$3;
shift 2;;
-g)
group=$3;
shift 2;;
-c)
command=$3;
shift 2;;
-i)
interface=$3;
shift 2;;
--)
shift; break;;
esac
done
#
# Start our remote sink/reflectors
#
shift;
current=0
now=`date "+%Y%m%d%H%M"`
for host in $*
do
output=$host\_$interface\_$size\_$number\.$now
$remote $host $command -r -M $# -m $current -n $number -s $size -i $interface > $output &
sleep 1
current=`expr $current + 1 `;
done
#
# Start the source/collector on this machine
#
$command -M $# -n $number -s $size -i le1 -t $gap > `uname -n`\_$size\_$number\.$now