From deefb95feab82b63d1a11953c56c5294c22173a8 Mon Sep 17 00:00:00 2001 From: "Bruce A. Mah" Date: Mon, 13 Jan 2014 10:58:47 -0800 Subject: [PATCH] Add FreeBSD support for -A (set CPU affinity). Mostly this change consists of adding FreeBSD-specific code to handle this feature. The concepts and system calls are very similar to what's already done for Linux. One difference is that on FreeBSD, the CPU affinity mask is saved before -A processing and restored afterwards. This causes a slight change to the function signatures for iperf_setaffinity() and iperf_clearaffinity() (these functions however are not documented as a part of the libiperf3 API). Slightly improve some of the documentation for the -A command line option, to hopefully stave off some of the questions about this feature. Mostly based on a submitted patch. Issue: 128 (better error message for CPU affinity failure) Submitted by: Susant Sahani --- README | 2 +- RELEASE_NOTES | 3 +++ src/iperf.h | 9 +++++++ src/iperf3.1 | 13 +++++++--- src/iperf_api.c | 57 ++++++++++++++++++++++++++++++++++++------ src/iperf_api.h | 4 +-- src/iperf_client_api.c | 2 +- src/iperf_server_api.c | 6 ++--- src/locale.c | 2 ++ 9 files changed, 80 insertions(+), 18 deletions(-) diff --git a/README b/README index c00f47c..c0ce188 100644 --- a/README +++ b/README @@ -44,7 +44,7 @@ New options: -O, --omit N omit the first n seconds (to ignore slowstart) -T, --title str prefix every output line with this string -F, --file name xmit/recv the specified file - -A, --affinity n/n,m set CPU affinity + -A, --affinity n/n,m set CPU affinity (Linux and FreeBSD only) -k, --blockcount #[KMG] number of blocks (packets) to transmit (instead of -t or -n) -L, --flowlabel set IPv6 flow label (Linux only) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 00cc8ca..954529e 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,3 +1,6 @@ +== iperf 3.?.? ????-??-?? == + * Setting CPU affinity now works on FreeBSD. + == iperf 3.0.1 2014-01-10 == * Added the following new flags -D, --daemon run server as a daemon diff --git a/src/iperf.h b/src/iperf.h index 43c88b9..41170ec 100644 --- a/src/iperf.h +++ b/src/iperf.h @@ -15,6 +15,12 @@ #include #include #include + +#if defined(__FreeBSD__) +#include +#include +#endif + #include "timer.h" #include "queue.h" #include "cjson.h" @@ -161,6 +167,9 @@ struct iperf_test int duration; /* total duration of test (-t flag) */ char *diskfile_name; /* -F option */ int affinity, server_affinity; /* -A option */ +#if (__FreeBSD__) + cpuset_t cpumask; +#endif char *title; /* -T option */ char *congestion; /* -C option */ diff --git a/src/iperf3.1 b/src/iperf3.1 index 013da9a..9cb2b35 100644 --- a/src/iperf3.1 +++ b/src/iperf3.1 @@ -36,10 +36,15 @@ server-side: read from the network and write to the file, instead of throwing the data away .TP .BR -A ", " --affinity " \fIn/n,m\fR" -Set the CPU affinity, if possible (linux only). -On both the client and server you can set the local affinity; -in addition, on the client side you can override the server's -affinity for just that one test, using the n,m form. +Set the CPU affinity, if possible (Linux and FreeBSD only). +On both the client and server you can set the local affinity by using +the \fIn\fR form of this argument (where \fIn\fR is a CPU number). +In addition, on the client side you can override the server's +affinity for just that one test, using the \fIn,m\fR form of +argument. +Note that when using this feature, a process will only be bound +to a single CPU (as opposed to a set containing potentialy multiple +CPUs). .TP .BR -V ", " --verbose " " give more detailed output diff --git a/src/iperf_api.c b/src/iperf_api.c index 091646f..f288011 100644 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -35,6 +35,11 @@ #include #include +#if defined(__FreeBSD__) +#include +#include +#endif + #include "net.h" #include "iperf.h" #include "iperf_api.h" @@ -531,7 +536,9 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) {"zerocopy", no_argument, NULL, 'Z'}, {"omit", required_argument, NULL, 'O'}, {"file", required_argument, NULL, 'F'}, +#if defined(linux) || defined(__FreeBSD__) {"affinity", required_argument, NULL, 'A'}, +#endif {"title", required_argument, NULL, 'T'}, #if defined(linux) {"linux-congestion", required_argument, NULL, 'C'}, @@ -713,6 +720,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) test->diskfile_name = optarg; break; case 'A': +#if defined(linux) || defined(__FreeBSD__) test->affinity = atoi(optarg); if (test->affinity < 0 || test->affinity > 1024) { i_errno = IEAFFINITY; @@ -727,6 +735,10 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) } client_flag = 1; } +#else + i_errno = IEUNIMP; + return -1; +#endif break; case 'T': test->title = malloc(strlen(optarg) + 4); @@ -1457,6 +1469,9 @@ iperf_defaults(struct iperf_test *testp) testp->diskfile_name = (char*) 0; testp->affinity = -1; testp->server_affinity = -1; +#if defined(__FreeBSD__) + CPU_ZERO(&testp->cpumask); +#endif testp->title = NULL; testp->congestion = NULL; testp->server_port = PORT; @@ -1614,6 +1629,9 @@ iperf_reset_test(struct iperf_test *test) test->omit = OMIT; test->duration = DURATION; test->server_affinity = -1; +#if defined(__FreeBSD__) + CPU_ZERO(&test->cpumask); +#endif test->state = 0; if(test->title) { @@ -2399,10 +2417,10 @@ iperf_json_finish(struct iperf_test *test) } -/* CPU affinity stuff - linux only. */ +/* CPU affinity stuff - Linux and FreeBSD only. */ int -iperf_setaffinity(int affinity) +iperf_setaffinity(struct iperf_test *test, int affinity) { #ifdef linux cpu_set_t cpu_set; @@ -2414,14 +2432,32 @@ iperf_setaffinity(int affinity) return -1; } return 0; -#else /*linux*/ +#elif (__FreeBSD__) + cpuset_t cpumask; + + if(cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, + sizeof(cpuset_t), &test->cpumask) != 0) { + i_errno = IEAFFINITY; + return -1; + } + + CPU_ZERO(&cpumask); + CPU_SET(affinity, &cpumask); + + if(cpuset_setaffinity(CPU_LEVEL_WHICH,CPU_WHICH_PID, -1, + sizeof(cpuset_t), &cpumask) != 0) { + i_errno = IEAFFINITY; + return -1; + } + return 0; +#else /* Linux or FreeBSD */ i_errno = IEAFFINITY; return -1; -#endif /*linux*/ +#endif /* Linux or FreeBSD*/ } int -iperf_clearaffinity(void) +iperf_clearaffinity(struct iperf_test *test) { #ifdef linux cpu_set_t cpu_set; @@ -2435,10 +2471,17 @@ iperf_clearaffinity(void) return -1; } return 0; -#else /*linux*/ +#elif (__FreeBSD__) + if(cpuset_setaffinity(CPU_LEVEL_WHICH,CPU_WHICH_PID, -1, + sizeof(cpuset_t), &test->cpumask) != 0) { + i_errno = IEAFFINITY; + return -1; + } + return 0; +#else /* Linux or FreeBSD */ i_errno = IEAFFINITY; return -1; -#endif /*linux*/ +#endif /* Linux or FreeBSD */ } int diff --git a/src/iperf_api.h b/src/iperf_api.h index c082448..1982836 100644 --- a/src/iperf_api.h +++ b/src/iperf_api.h @@ -213,8 +213,8 @@ int iperf_json_start(struct iperf_test *); int iperf_json_finish(struct iperf_test *); /* CPU affinity routines */ -int iperf_setaffinity(int affinity); -int iperf_clearaffinity(void); +int iperf_setaffinity(struct iperf_test *, int affinity); +int iperf_clearaffinity(struct iperf_test *); /* Custom printf routine. */ int iprintf(struct iperf_test *test, const char *format, ...) __attribute__ ((format(printf,2,3))); diff --git a/src/iperf_client_api.c b/src/iperf_client_api.c index 8846247..1e72c42 100644 --- a/src/iperf_client_api.c +++ b/src/iperf_client_api.c @@ -342,7 +342,7 @@ iperf_run_client(struct iperf_test * test) iperf_got_sigend(test); if (test->affinity != -1) - if (iperf_setaffinity(test->affinity) != 0) + if (iperf_setaffinity(test, test->affinity) != 0) return -1; if (test->json_output) diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index f490fc4..d52efce 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -136,7 +136,7 @@ iperf_accept(struct iperf_test *test) if (iperf_exchange_parameters(test) < 0) return -1; if (test->server_affinity != -1) - if (iperf_setaffinity(test->server_affinity) != 0) + if (iperf_setaffinity(test, test->server_affinity) != 0) return -1; if (test->on_connect) test->on_connect(test); @@ -436,7 +436,7 @@ iperf_run_server(struct iperf_test *test) iperf_got_sigend(test); if (test->affinity != -1) - if (iperf_setaffinity(test->affinity) != 0) + if (iperf_setaffinity(test, test->affinity) != 0) return -1; if (test->json_output) @@ -603,7 +603,7 @@ iperf_run_server(struct iperf_test *test) } if (test->server_affinity != -1) - if (iperf_clearaffinity() != 0) + if (iperf_clearaffinity(test) != 0) return -1; return 0; diff --git a/src/locale.c b/src/locale.c index 10c93cd..e213285 100644 --- a/src/locale.c +++ b/src/locale.c @@ -73,7 +73,9 @@ const char usage_longstr[] = "Usage: iperf [-s|-c host] [options]\n" " -f, --format [kmgKMG] format to report: Kbits, Mbits, KBytes, MBytes\n" " -i, --interval # seconds between periodic bandwidth reports\n" " -F, --file name xmit/recv the specified file\n" +#if defined(linux) || defined(__FreeBSD__) " -A, --affinity n/n,m set CPU affinity\n" +#endif " -V, --verbose more detailed output\n" " -J, --json output in JSON format\n" " -v, --version show version information and quit\n"