Skip to content

Commit 8cf9df4

Browse files
committed
feat: scatter streams to different cpu cores
Signed-off-by: Changliang Wu <changliang.wu@smartx.com>
1 parent 84c49f2 commit 8cf9df4

5 files changed

Lines changed: 112 additions & 3 deletions

File tree

src/iperf.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ struct iperf_stream
202202
pthread_t thr;
203203
int thread_created;
204204
int done;
205+
int affinity;
205206

206207
/* configurable members */
207208
int local_port;
@@ -293,6 +294,7 @@ enum debug_level {
293294
};
294295

295296

297+
#define MAX_STREAMS 128
296298
struct iperf_test
297299
{
298300
pthread_mutex_t print_mutex;
@@ -314,6 +316,9 @@ struct iperf_test
314316
int duration; /* total duration of test (-t flag) */
315317
char *diskfile_name; /* -F option */
316318
int affinity, server_affinity; /* -A option */
319+
#if defined(HAVE_SCHED_SETAFFINITY)
320+
cpu_set_t cpumask;
321+
#endif /* HAVE_CPUSET_SETAFFINITY */
317322
#if defined(HAVE_CPUSET_SETAFFINITY)
318323
cpuset_t cpumask;
319324
#endif /* HAVE_CPUSET_SETAFFINITY */
@@ -385,7 +390,8 @@ struct iperf_test
385390
double cpu_util[3]; /* cpu utilization of the test - total, user, system */
386391
double remote_cpu_util[3]; /* cpu utilization for the remote host/client - total, user, system */
387392

388-
int num_streams; /* total streams in the test (-P) */
393+
int num_streams; /* total streams in the test (-P) */
394+
int streams_affinity[MAX_STREAMS];
389395

390396
atomic_iperf_size_t bytes_sent;
391397
atomic_iperf_size_t blocks_sent;
@@ -463,7 +469,6 @@ struct iperf_test
463469
#define MAX_OMIT_TIME 600
464470
#define MAX_BURST 1000
465471
#define MAX_MSS (9 * 1024)
466-
#define MAX_STREAMS 128
467472

468473
#define TIMESTAMP_FORMAT "%c "
469474

src/iperf_api.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4635,6 +4635,7 @@ iperf_new_stream(struct iperf_test *test, int s, int sender)
46354635

46364636
memset(sp, 0, sizeof(struct iperf_stream));
46374637

4638+
sp->affinity = -1;
46384639
sp->sender = sender;
46394640
sp->test = test;
46404641
sp->settings = test->settings;
@@ -5169,6 +5170,85 @@ iperf_json_finish(struct iperf_test *test)
51695170

51705171

51715172
/* CPU affinity stuff - Linux, FreeBSD, and Windows only. */
5173+
/* init streams cpu map
5174+
If the number of CPUs >= streams (-P), map each stream to a specific CPU core.
5175+
*/
5176+
void
5177+
iperf_affinity_streams_init(struct iperf_test *test)
5178+
{
5179+
#if defined(HAVE_SCHED_SETAFFINITY)
5180+
if (sched_getaffinity(0, sizeof(cpu_set_t), &test->cpumask) != 0) {
5181+
return;
5182+
}
5183+
5184+
/* Assign bindings according to main process affinity */
5185+
int available_cpu_num = CPU_COUNT(&test->cpumask);
5186+
int affinity_stream_cnt = 0;
5187+
if (available_cpu_num > 0) {
5188+
affinity_stream_cnt = (test->num_streams / available_cpu_num) * available_cpu_num;
5189+
}
5190+
5191+
for (int i = 0; i < test->num_streams; i++) {
5192+
if (affinity_stream_cnt > 0) {
5193+
int offset = i % available_cpu_num;
5194+
int j = 0;
5195+
for (; j < CPU_SETSIZE; j++) {
5196+
if (CPU_ISSET(j, &test->cpumask)) {
5197+
if (offset == 0) {
5198+
break;
5199+
}
5200+
offset--;
5201+
}
5202+
}
5203+
test->streams_affinity[i] = j;
5204+
affinity_stream_cnt--;
5205+
} else {
5206+
test->streams_affinity[i] = -1;
5207+
}
5208+
}
5209+
#else
5210+
for (int i = 0; i < test->num_streams; i++) {
5211+
test->streams_affinity[i] = -1;
5212+
}
5213+
#endif
5214+
}
5215+
5216+
void
5217+
iperf_setaffinity_streams_raw(int affinity)
5218+
{
5219+
#if defined(HAVE_SCHED_SETAFFINITY)
5220+
cpu_set_t cpu_set;
5221+
CPU_ZERO(&cpu_set);
5222+
CPU_SET(affinity, &cpu_set);
5223+
if (sched_setaffinity(0, sizeof(cpu_set_t), &cpu_set) != 0) {
5224+
return;
5225+
}
5226+
#endif
5227+
}
5228+
5229+
void
5230+
iperf_setaffinity_streams(struct iperf_test *test, int index)
5231+
{
5232+
#if defined(HAVE_SCHED_SETAFFINITY)
5233+
iperf_setaffinity_streams_raw(test->streams_affinity[index]);
5234+
#endif
5235+
}
5236+
5237+
void
5238+
iperf_setaffinity_streams_post(struct iperf_test *test)
5239+
{
5240+
#if defined(HAVE_SCHED_SETAFFINITY)
5241+
if (sched_setaffinity(0, sizeof(cpu_set_t), &test->cpumask) != 0) {
5242+
return;
5243+
}
5244+
5245+
struct iperf_stream *sp;
5246+
int index = 0;
5247+
SLIST_FOREACH(sp, &test->streams, streams){
5248+
sp->affinity = test->streams_affinity[index++ % test->num_streams];
5249+
}
5250+
#endif
5251+
}
51725252

51735253
int
51745254
iperf_setaffinity(struct iperf_test *test, int affinity)

src/iperf_api.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,10 @@ int iperf_json_finish(struct iperf_test *);
385385
/* CPU affinity routines */
386386
int iperf_setaffinity(struct iperf_test *, int affinity);
387387
int iperf_clearaffinity(struct iperf_test *);
388+
void iperf_affinity_streams_init(struct iperf_test *test);
389+
void iperf_setaffinity_streams(struct iperf_test *test, int index);
390+
void iperf_setaffinity_streams_raw(int affinity);
391+
void iperf_setaffinity_streams_post(struct iperf_test *test);
388392

389393
/* Custom printf routine. */
390394
int iperf_printf(struct iperf_test *test, const char *format, ...) __attribute__ ((format(printf,2,3)));

src/iperf_client_api.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ iperf_client_worker_run(void *s) {
5757
struct iperf_stream *sp = (struct iperf_stream *) s;
5858
struct iperf_test *test = sp->test;
5959

60+
if (sp->affinity >= 0) {
61+
iperf_setaffinity_streams_raw(sp->affinity);
62+
}
63+
6064
/* Blocking signal to make sure that signal will be handled by main thread */
6165
sigset_t set;
6266
sigemptyset(&set);
@@ -112,6 +116,13 @@ iperf_create_streams(struct iperf_test *test, int sender)
112116

113117
int orig_bind_port = test->bind_port;
114118
for (i = 0; i < test->num_streams; ++i) {
119+
/* -> Create streams on different cpus
120+
The network protocol stack will save the cpu core when creating the socket.
121+
With a multi-queue NIC, the queue selection may relate to the cpu core num
122+
(XPS, RPS, sk_*_queue_mapping...),
123+
which helps improve the performance of multi-queue physical network cards.
124+
*/
125+
iperf_setaffinity_streams(test,i);
115126

116127
test->bind_port = orig_bind_port;
117128
if (orig_bind_port) {
@@ -339,6 +350,7 @@ iperf_handle_message_client(struct iperf_test *test)
339350
test->on_connect(test);
340351
break;
341352
case CREATE_STREAMS:
353+
iperf_affinity_streams_init(test);
342354
if (test->mode == BIDIRECTIONAL)
343355
{
344356
if (iperf_create_streams(test, 1) < 0)
@@ -348,6 +360,7 @@ iperf_handle_message_client(struct iperf_test *test)
348360
}
349361
else if (iperf_create_streams(test, test->mode) < 0)
350362
return -1;
363+
iperf_setaffinity_streams_post(test);
351364
break;
352365
case TEST_START:
353366
if (iperf_init_test(test) < 0)

src/iperf_server_api.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ iperf_server_worker_run(void *s) {
7070
struct iperf_stream *sp = (struct iperf_stream *) s;
7171
struct iperf_test *test = sp->test;
7272

73+
if (sp->affinity >= 0) {
74+
iperf_setaffinity_streams_raw(sp->affinity);
75+
}
76+
7377
/* Blocking signal to make sure that signal will be handled by main thread */
7478
sigset_t set;
7579
sigemptyset(&set);
@@ -713,6 +717,7 @@ iperf_run_server(struct iperf_test *test)
713717
streams_to_send = test->num_streams;
714718
streams_to_rec = 0;
715719
}
720+
iperf_affinity_streams_init(test);
716721
}
717722
}
718723
if (FD_ISSET(test->ctrl_sck, &read_set)) {
@@ -725,7 +730,7 @@ iperf_run_server(struct iperf_test *test)
725730

726731
if (test->state == CREATE_STREAMS) {
727732
if (FD_ISSET(test->prot_listener, &read_set)) {
728-
733+
iperf_setaffinity_streams(test,rec_streams_accepted);
729734
if ((s = test->protocol->accept(test)) < 0) {
730735
cleanup_server(test);
731736
return -1;
@@ -844,6 +849,8 @@ iperf_run_server(struct iperf_test *test)
844849

845850

846851
if (rec_streams_accepted == streams_to_rec && send_streams_accepted == streams_to_send) {
852+
iperf_setaffinity_streams_post(test);
853+
847854
if (test->protocol->id != Ptcp) {
848855
FD_CLR(test->prot_listener, &test->read_set);
849856
close(test->prot_listener);

0 commit comments

Comments
 (0)