aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJef Poskanzer <jef@mail.acme.com>2013-04-09 11:42:30 -0700
committerJef Poskanzer <jef@mail.acme.com>2013-04-09 11:42:30 -0700
commita27f6534b56bbc6869a74e00bbfe945deb54e408 (patch)
tree79ccf5ae1b68460d20e9a98e160c09e82a432524
parenta6b3f26be128cbeaccb736151e2d864a1a63ee61 (diff)
downloadiperf3-a27f6534b56bbc6869a74e00bbfe945deb54e408.tar.gz
Added second concurrency model based on SIGALRM.
-rw-r--r--examples/mic.c4
-rw-r--r--src/iperf.h3
-rw-r--r--src/iperf_api.c29
-rw-r--r--src/iperf_api.h2
-rw-r--r--src/iperf_client_api.c138
-rw-r--r--src/main.c3
6 files changed, 127 insertions, 52 deletions
diff --git a/examples/mic.c b/examples/mic.c
index a1195d7..fb47459 100644
--- a/examples/mic.c
+++ b/examples/mic.c
@@ -34,6 +34,10 @@ main( int argc, char** argv )
exit( EXIT_FAILURE );
}
iperf_defaults( test );
+
+ /* This main program doesn't use SIGALRM, so the iperf API may use it. */
+ iperf_set_test_may_use_sigalrm(test, 1);
+
iperf_set_test_role( test, 'c' );
iperf_set_test_server_hostname( test, host );
iperf_set_test_server_port( test, port );
diff --git a/src/iperf.h b/src/iperf.h
index 5b0437d..1d82ba5 100644
--- a/src/iperf.h
+++ b/src/iperf.h
@@ -146,6 +146,9 @@ struct iperf_test
int json_output; /* -J option - JSON output */
int zerocopy; /* -Z option - use sendfile */
+ int multisend;
+ int may_use_sigalrm;
+
/* Select related parameters */
int max_fd;
fd_set read_set; /* set of read sockets */
diff --git a/src/iperf_api.c b/src/iperf_api.c
index 540b9fb..9815711 100644
--- a/src/iperf_api.c
+++ b/src/iperf_api.c
@@ -164,6 +164,12 @@ iperf_get_test_zerocopy(struct iperf_test *ipt)
return ipt->zerocopy;
}
+int
+iperf_get_test_may_use_sigalrm(struct iperf_test *ipt)
+{
+ return ipt->may_use_sigalrm;
+}
+
/************** Setter routines for some fields inside iperf_test *************/
void
@@ -256,6 +262,12 @@ iperf_set_test_zerocopy(struct iperf_test *ipt, int zerocopy)
ipt->zerocopy = zerocopy;
}
+void
+iperf_set_test_may_use_sigalrm(struct iperf_test *ipt, int may_use_sigalrm)
+{
+ ipt->may_use_sigalrm = may_use_sigalrm;
+}
+
/********************** Get/set test protocol structure ***********************/
struct protocol *
@@ -610,18 +622,18 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
int
iperf_send(struct iperf_test *test, fd_set *write_setP)
{
- int multisend, r;
+ register int multisend, r;
register struct iperf_stream *sp;
/* Can we do multisend mode? */
if (test->protocol->id == Pudp && test->settings->rate != 0)
multisend = 1; /* nope */
else
- multisend = 20; /* arbitrary */
+ multisend = test->multisend;
for (; multisend > 0; --multisend) {
SLIST_FOREACH(sp, &test->streams, streams) {
- if (FD_ISSET(sp->socket, write_setP)) {
+ if (write_setP == NULL || FD_ISSET(sp->socket, write_setP)) {
if ((r = sp->snd(sp)) < 0) {
if (r == NET_SOFTERROR)
break;
@@ -634,9 +646,10 @@ iperf_send(struct iperf_test *test, fd_set *write_setP)
}
}
}
- SLIST_FOREACH(sp, &test->streams, streams)
- if (FD_ISSET(sp->socket, write_setP))
- FD_CLR(sp->socket, write_setP);
+ if (write_setP != NULL)
+ SLIST_FOREACH(sp, &test->streams, streams)
+ if (FD_ISSET(sp->socket, write_setP))
+ FD_CLR(sp->socket, write_setP);
return 0;
}
@@ -1182,6 +1195,9 @@ iperf_defaults(struct iperf_test *testp)
testp->settings->bytes = 0;
memset(testp->cookie, 0, COOKIE_SIZE);
+ testp->multisend = 10; /* arbitrary */
+ testp->may_use_sigalrm = 0;
+
/* Set up protocol list */
SLIST_INIT(&testp->streams);
SLIST_INIT(&testp->protocols);
@@ -1315,6 +1331,7 @@ iperf_reset_test(struct iperf_test *test)
test->settings->rate = RATE; /* UDP only */
test->settings->mss = 0;
memset(test->cookie, 0, COOKIE_SIZE);
+ test->multisend = 10; /* arbitrary */
}
diff --git a/src/iperf_api.h b/src/iperf_api.h
index 5097124..bd83f04 100644
--- a/src/iperf_api.h
+++ b/src/iperf_api.h
@@ -58,6 +58,7 @@ char* iperf_get_test_server_hostname( struct iperf_test* ipt );
int iperf_get_test_protocol_id( struct iperf_test* ipt );
int iperf_get_test_json_output( struct iperf_test* ipt );
int iperf_get_test_zerocopy( struct iperf_test* ipt );
+int iperf_get_test_may_use_sigalrm( struct iperf_test* ipt );
/* Setter routines for some fields inside iperf_test. */
void iperf_set_control_socket( struct iperf_test* ipt, int ctrl_sck );
@@ -75,6 +76,7 @@ void iperf_set_test_server_hostname( struct iperf_test* ipt, char* server_hostna
void iperf_set_test_json_output( struct iperf_test* ipt, int json_output );
int iperf_has_zerocopy( void );
void iperf_set_test_zerocopy( struct iperf_test* ipt, int zerocopy );
+void iperf_set_test_may_use_sigalrm( struct iperf_test* ipt, int may_use_sigalrm );
/**
* exchange_parameters - handles the param_Exchange part for client
diff --git a/src/iperf_client_api.c b/src/iperf_client_api.c
index e60ac92..d33262f 100644
--- a/src/iperf_client_api.c
+++ b/src/iperf_client_api.c
@@ -13,6 +13,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <signal.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/uio.h>
@@ -181,9 +182,22 @@ iperf_client_end(struct iperf_test *test)
}
+static int sigalrm_triggered;
+
+static void
+sigalrm_handler(int sig)
+{
+ sigalrm_triggered = 1;
+}
+
+
int
iperf_run_client(struct iperf_test * test)
{
+ int concurrency_model;
+ int startup;
+#define CM_SELECT 1
+#define CM_SIGALRM 2
int result;
fd_set read_set, write_set;
struct timeval now;
@@ -205,63 +219,95 @@ iperf_run_client(struct iperf_test * test)
return -1;
}
- // Begin calculating CPU utilization
+ /* Begin calculating CPU utilization */
cpu_util(NULL);
+ startup = 1;
+ concurrency_model = CM_SELECT; /* always start in select mode */
(void) gettimeofday(&now, NULL);
while (test->state != IPERF_DONE) {
- memcpy(&read_set, &test->read_set, sizeof(fd_set));
- memcpy(&write_set, &test->write_set, sizeof(fd_set));
-
- result = select(test->max_fd + 1, &read_set, &write_set, NULL, tmr_timeout(&now));
- if (result < 0 && errno != EINTR) {
- i_errno = IESELECT;
- return -1;
- }
- if (result > 0) {
- if (FD_ISSET(test->ctrl_sck, &read_set)) {
- if (iperf_handle_message_client(test) < 0) {
- return -1;
+ if (concurrency_model == CM_SELECT) {
+ memcpy(&read_set, &test->read_set, sizeof(fd_set));
+ memcpy(&write_set, &test->write_set, sizeof(fd_set));
+ result = select(test->max_fd + 1, &read_set, &write_set, NULL, tmr_timeout(&now));
+ if (result < 0 && errno != EINTR) {
+ i_errno = IESELECT;
+ return -1;
+ }
+ if (result > 0) {
+ if (FD_ISSET(test->ctrl_sck, &read_set)) {
+ if (iperf_handle_message_client(test) < 0) {
+ return -1;
+ }
+ FD_CLR(test->ctrl_sck, &read_set);
}
- FD_CLR(test->ctrl_sck, &read_set);
- }
+ }
+ }
+
+ if (test->state == TEST_RUNNING) {
+
+ /* Is this our first time in TEST_RUNNING mode? */
+ if (startup) {
+ startup = 0;
+ /* Can we switch to SIGALRM mode? There are a bunch of
+ ** cases where either it won't work or it's ill-advised.
+ */
+ if (test->may_use_sigalrm &&
+ (test->protocol->id != Pudp || test->settings->rate == 0) &&
+ (test->stats_interval == 0 || test->stats_interval > 1) &&
+ (test->reporter_interval == 0 || test->reporter_interval > 1) &&
+ ! test->reverse) {
+ concurrency_model = CM_SIGALRM;
+ test->multisend = 1;
+ signal(SIGALRM, sigalrm_handler);
+ sigalrm_triggered = 0;
+ alarm(1);
+ }
+ }
- if (test->state == TEST_RUNNING) {
- if (test->reverse) {
- // Reverse mode. Client receives.
- if (iperf_recv(test, &read_set) < 0) {
- return -1;
- }
- } else {
- // Regular mode. Client sends.
- if (iperf_send(test, &write_set) < 0) {
- return -1;
- }
- }
+ if (test->reverse) {
+ // Reverse mode. Client receives.
+ if (iperf_recv(test, &read_set) < 0) {
+ return -1;
+ }
+ } else {
+ // Regular mode. Client sends.
+ if (iperf_send(test, concurrency_model == CM_SIGALRM ? NULL : &write_set) < 0) {
+ return -1;
+ }
+ }
- /* Run the timers. */
+ if (concurrency_model == CM_SELECT ||
+ (concurrency_model == CM_SIGALRM && sigalrm_triggered)) {
+ /* Run the timers. */
(void) gettimeofday(&now, NULL);
tmr_run(&now);
-
- /* Is the test done yet? */
- if (test->settings->bytes == 0) {
- if (!test->done)
- continue; /* not done */
- } else {
- if (test->bytes_sent < test->settings->bytes)
- continue; /* not done */
+ if (concurrency_model == CM_SIGALRM) {
+ sigalrm_triggered = 0;
+ alarm(1);
}
- /* Yes, done! Send TEST_END. */
- cpu_util(&test->cpu_util);
- test->stats_callback(test);
- test->state = TEST_END;
- if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
- i_errno = IESENDMESSAGE;
- return -1;
- }
- }
- }
+ }
+
+ /* Is the test done yet? */
+ if (test->settings->bytes == 0) {
+ if (!test->done)
+ continue; /* not done */
+ } else {
+ if (test->bytes_sent < test->settings->bytes)
+ continue; /* not done */
+ }
+ /* Yes, done! Send TEST_END. */
+ cpu_util(&test->cpu_util);
+ test->stats_callback(test);
+ test->state = TEST_END;
+ if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
+ i_errno = IESENDMESSAGE;
+ return -1;
+ }
+ /* And if we were doing SIGALRM, go back to select for the end. */
+ concurrency_model = CM_SELECT;
+ }
}
if (test->json_output) {
diff --git a/src/main.c b/src/main.c
index 786d7d7..dc3f26e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -78,6 +78,9 @@ main(int argc, char **argv)
iperf_errexit(NULL, "create new test error - %s", iperf_strerror(i_errno));
iperf_defaults(test); /* sets defaults */
+ /* This main program doesn't use SIGALRM, so the iperf API may use it. */
+ iperf_set_test_may_use_sigalrm(test, 1);
+
// XXX: Check signal for errors?
signal(SIGINT, sig_handler);
if (setjmp(env)) {