Skip to content

Commit 3e09a40

Browse files
jukkarfabiobaltieri
authored andcommitted
net: zperf: Add -w option to delay upload jobs
Use -w option to delay the startup of the upload job. Then when ready, do "zperf jobs start" to launch all upload sessions at the same time. Signed-off-by: Jukka Rissanen <[email protected]>
1 parent 7595a4b commit 3e09a40

File tree

9 files changed

+159
-12
lines changed

9 files changed

+159
-12
lines changed

doc/connectivity/networking/api/zperf.rst

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,12 @@ If :kconfig:option:`CONFIG_ZPERF_SESSION_PER_THREAD` option is set, then
104104
multiple upload sessions can be done at the same time if user supplies ``-a``
105105
option when starting the upload. Each session will have their own work queue
106106
to run the test. The session test results can be viewed also after the tests
107-
have finished.
107+
have finished. The sessions can be started with ``-w`` option which then
108+
lets the worker threads to wait a start signal so that all the threads can
109+
be started at the same time. This will prevent the case where the zperf shell
110+
cannot run because it is running in lower priority than the already started
111+
session thread. If you have only one upload session, then the ``-w`` is not
112+
really needed.
108113

109114
Following zperf shell commands are available for session management:
110115

@@ -115,6 +120,7 @@ Following zperf shell commands are available for session management:
115120
"``jobs``", "Show currently active or finished sessions"
116121
"``jobs all``", "Show statistics of finished sessions"
117122
"``jobs clear``", "Clear finished session statistics"
123+
"``jobs start``", "Start all the waiting sessions"
118124

119125
Example:
120126

@@ -172,3 +178,61 @@ Example:
172178
uart:~$ zperf jobs
173179
No active upload sessions
174180
No finished sessions found
181+
182+
The ``-w`` option can be used like this to delay the startup of the jobs.
183+
184+
.. code-block:: console
185+
186+
uart:~$ zperf tcp upload -a -t 6 -w 192.0.2.2 5001 10 1K
187+
Remote port is 5001
188+
Connecting to 192.0.2.2
189+
Duration: 10.00 s
190+
Packet size: 1000 bytes
191+
Rate: 10 kbps
192+
Waiting "zperf jobs start" command.
193+
[01:06:51.392,288] <inf> net_zperf: [0] TCP waiting for start
194+
195+
uart:~$ zperf udp upload -a -t 6 -w 192.0.2.2 5001 10 1K 10M
196+
Remote port is 5001
197+
Connecting to 192.0.2.2
198+
Duration: 10.00 s
199+
Packet size: 1000 bytes
200+
Rate: 10000 kbps
201+
Waiting "zperf jobs start" command.
202+
Rate: 10.00 Mbps
203+
Packet duration 781 us
204+
[01:06:58.064,552] <inf> net_zperf: [0] UDP waiting for start
205+
206+
uart:~$ zperf jobs start
207+
-
208+
Upload completed!
209+
-
210+
Upload completed!
211+
212+
# Note that the output may be garbled as two threads printed
213+
# output at the same time. Just print out the fresh listing
214+
# like this.
215+
216+
uart:~$ zperf jobs all
217+
-
218+
Upload completed!
219+
Statistics: server (client)
220+
Duration: 9.99 s (10.00 s)
221+
Num packets: 11429 (11429)
222+
Num packets out order: 0
223+
Num packets lost: 0
224+
Jitter: 164 us
225+
Rate: 9.14 Mbps (9.14 Mbps)
226+
Thread priority: 6
227+
Protocol: UDP
228+
Session id: 0
229+
-
230+
Upload completed!
231+
Duration: 10.00 s
232+
Num packets: 15487
233+
Num errors: 0 (retry or fail)
234+
Rate: 12.38 Mbps
235+
Thread priority: 6
236+
Protocol: TCP
237+
Session id: 0
238+
Total 2 sessions done

include/zephyr/net/zperf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ struct zperf_upload_params {
4747
int priority;
4848
#ifdef CONFIG_ZPERF_SESSION_PER_THREAD
4949
int thread_priority;
50+
bool wait_for_start;
5051
#endif
5152
uint32_t report_interval_ms;
5253
} options;

subsys/net/lib/zperf/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ config NET_ZPERF_LEGACY_HEADER_COMPAT
2424

2525
config ZPERF_SESSION_PER_THREAD
2626
bool "Run each session in a separate thread"
27+
select EVENTS
2728
help
2829
Each session is started in its own thread. This means
2930
that the system will use more memory because multiple

subsys/net/lib/zperf/zperf_common.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,7 @@ struct sockaddr_in *zperf_get_sin(void)
4747
K_LOWEST_APPLICATION_THREAD_PRIO)
4848

4949
#if defined(CONFIG_ZPERF_SESSION_PER_THREAD)
50-
struct zperf_work {
51-
struct k_work_q *queue;
52-
struct z_thread_stack_element *stack;
53-
size_t stack_size;
54-
};
50+
static K_EVENT_DEFINE(start_event);
5551

5652
#define CREATE_WORK_Q(i, _) \
5753
static struct k_work_q zperf_work_q_##i; \
@@ -80,7 +76,7 @@ static struct zperf_work zperf_work_q[] = {
8076
LISTIFY(MAX_SESSION_COUNT, SET_WORK_Q, (,), _)
8177
};
8278

83-
struct k_work_q *get_queue(enum session_proto proto, int session_id)
79+
struct zperf_work *get_queue(enum session_proto proto, int session_id)
8480
{
8581
if (session_id < 0 || session_id >= CONFIG_NET_ZPERF_MAX_SESSIONS) {
8682
return NULL;
@@ -95,9 +91,14 @@ struct k_work_q *get_queue(enum session_proto proto, int session_id)
9591
proto * SESSION_INDEX + session_id,
9692
session_id);
9793

98-
return zperf_work_q[proto * SESSION_INDEX + session_id].queue;
94+
95+
return &zperf_work_q[proto * SESSION_INDEX + session_id];
9996
}
10097

98+
void start_jobs(void)
99+
{
100+
k_event_set(&start_event, START_EVENT);
101+
}
101102
#else /* CONFIG_ZPERF_SESSION_PER_THREAD */
102103

103104
K_THREAD_STACK_DEFINE(zperf_work_q_stack, CONFIG_ZPERF_WORK_Q_STACK_SIZE);
@@ -298,6 +299,8 @@ static int zperf_init(void)
298299
.no_yield = false,
299300
};
300301

302+
zperf_work_q[i].start_event = &start_event;
303+
301304
#define MAX_NAME_LEN sizeof("zperf_work_q[xxx]")
302305
char name[MAX_NAME_LEN];
303306

subsys/net/lib/zperf/zperf_internal.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,17 @@ int zperf_get_ipv4_addr(char *host, struct in_addr *addr);
116116
struct sockaddr_in *zperf_get_sin(void);
117117

118118
extern void connect_ap(char *ssid);
119-
extern struct k_work_q *get_queue(enum session_proto proto, int session_id);
119+
120+
struct zperf_work {
121+
struct k_work_q *queue;
122+
struct z_thread_stack_element *stack;
123+
struct k_event *start_event;
124+
size_t stack_size;
125+
};
126+
127+
#define START_EVENT 0x0001
128+
extern void start_jobs(void);
129+
extern struct zperf_work *get_queue(enum session_proto proto, int session_id);
120130

121131
int zperf_prepare_upload_sock(const struct sockaddr *peer_addr, uint8_t tos,
122132
int priority, int tcp_nodelay, int proto);

subsys/net/lib/zperf/zperf_session.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ struct session {
5454
#ifdef CONFIG_ZPERF_SESSION_PER_THREAD
5555
struct zperf_results result;
5656
struct zperf_async_upload_context async_upload_ctx;
57+
struct zperf_work *zperf;
5758
bool in_progress; /* is this session finished or not */
59+
bool wait_for_start; /* wait until the user starts the sessions */
5860
#endif /* CONFIG_ZPERF_SESSION_PER_THREAD */
5961
};
6062

subsys/net/lib/zperf/zperf_shell.c

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -806,7 +806,14 @@ static int execute_upload(const struct shell *sh,
806806
param->packet_size);
807807
shell_fprintf(sh, SHELL_NORMAL, "Rate:\t\t%u kbps\n",
808808
param->rate_kbps);
809-
shell_fprintf(sh, SHELL_NORMAL, "Starting...\n");
809+
810+
if (IS_ENABLED(CONFIG_ZPERF_SESSION_PER_THREAD) &&
811+
COND_CODE_1(CONFIG_ZPERF_SESSION_PER_THREAD,
812+
(param->options.wait_for_start), (0))) {
813+
shell_fprintf(sh, SHELL_NORMAL, "Waiting \"zperf jobs start\" command.\n");
814+
} else {
815+
shell_fprintf(sh, SHELL_NORMAL, "Starting...\n");
816+
}
810817

811818
if (IS_ENABLED(CONFIG_NET_IPV6) && param->peer_addr.sa_family == AF_INET6) {
812819
struct sockaddr_in6 *ipv6 =
@@ -1000,6 +1007,11 @@ static int shell_cmd_upload(const struct shell *sh, size_t argc,
10001007
opt_cnt += 2;
10011008
async = true;
10021009
break;
1010+
1011+
case 'w':
1012+
param.options.wait_for_start = true;
1013+
opt_cnt += 1;
1014+
break;
10031015
#endif /* CONFIG_ZPERF_SESSION_PER_THREAD */
10041016

10051017
#ifdef CONFIG_NET_CONTEXT_PRIORITY
@@ -1247,6 +1259,11 @@ static int shell_cmd_upload2(const struct shell *sh, size_t argc,
12471259
opt_cnt += 2;
12481260
async = true;
12491261
break;
1262+
1263+
case 'w':
1264+
param.options.wait_for_start = true;
1265+
opt_cnt += 1;
1266+
break;
12501267
#endif /* CONFIG_ZPERF_SESSION_PER_THREAD */
12511268

12521269
#ifdef CONFIG_NET_CONTEXT_PRIORITY
@@ -1784,6 +1801,22 @@ static int cmd_jobs_clear(const struct shell *sh, size_t argc, char *argv[])
17841801
return 0;
17851802
}
17861803

1804+
static int cmd_jobs_start(const struct shell *sh, size_t argc, char *argv[])
1805+
{
1806+
#ifdef CONFIG_ZPERF_SESSION_PER_THREAD
1807+
ARG_UNUSED(argc);
1808+
ARG_UNUSED(argv);
1809+
ARG_UNUSED(sh);
1810+
1811+
start_jobs();
1812+
#else
1813+
shell_fprintf(sh, SHELL_INFO,
1814+
"Zephyr has not been built with %s support.\n",
1815+
"CONFIG_ZPERF_SESSION_PER_THREAD");
1816+
#endif
1817+
return 0;
1818+
}
1819+
17871820
void zperf_shell_init(void)
17881821
{
17891822
int ret;
@@ -1862,6 +1895,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(zperf_cmd_tcp,
18621895
"-n: Disable Nagle's algorithm\n"
18631896
#ifdef CONFIG_ZPERF_SESSION_PER_THREAD
18641897
"-t: Specify custom thread priority\n"
1898+
"-w: Wait for start signal before starting the tests\n"
18651899
#endif /* CONFIG_ZPERF_SESSION_PER_THREAD */
18661900
#ifdef CONFIG_NET_CONTEXT_PRIORITY
18671901
"-p: Specify custom packet priority\n"
@@ -1885,6 +1919,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(zperf_cmd_tcp,
18851919
"-n: Disable Nagle's algorithm\n"
18861920
#ifdef CONFIG_ZPERF_SESSION_PER_THREAD
18871921
"-t: Specify custom thread priority\n"
1922+
"-w: Wait for start signal before starting the tests\n"
18881923
#endif /* CONFIG_ZPERF_SESSION_PER_THREAD */
18891924
#ifdef CONFIG_NET_CONTEXT_PRIORITY
18901925
"-p: Specify custom packet priority\n"
@@ -1937,6 +1972,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(zperf_cmd_udp,
19371972
"-a: Asynchronous call (shell will not block for the upload)\n"
19381973
#ifdef CONFIG_ZPERF_SESSION_PER_THREAD
19391974
"-t: Specify custom thread priority\n"
1975+
"-w: Wait for start signal before starting the tests\n"
19401976
#endif /* CONFIG_ZPERF_SESSION_PER_THREAD */
19411977
#ifdef CONFIG_NET_CONTEXT_PRIORITY
19421978
"-p: Specify custom packet priority\n"
@@ -1961,6 +1997,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(zperf_cmd_udp,
19611997
"-a: Asynchronous call (shell will not block for the upload)\n"
19621998
#ifdef CONFIG_ZPERF_SESSION_PER_THREAD
19631999
"-t: Specify custom thread priority\n"
2000+
"-w: Wait for start signal before starting the tests\n"
19642001
#endif /* CONFIG_ZPERF_SESSION_PER_THREAD */
19652002
#ifdef CONFIG_NET_CONTEXT_PRIORITY
19662003
"-p: Specify custom packet priority\n"
@@ -1994,6 +2031,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(zperf_cmd_udp,
19942031
SHELL_STATIC_SUBCMD_SET_CREATE(zperf_cmd_jobs,
19952032
SHELL_CMD(all, NULL, "Show all statistics", cmd_jobs_all),
19962033
SHELL_CMD(clear, NULL, "Clear all statistics", cmd_jobs_clear),
2034+
SHELL_CMD(start, NULL, "Start waiting jobs", cmd_jobs_start),
19972035
);
19982036

19992037
SHELL_STATIC_SUBCMD_SET_CREATE(zperf_commands,

subsys/net/lib/zperf/zperf_tcp_uploader.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,15 @@ static void tcp_upload_async_work(struct k_work *work)
160160
ses = CONTAINER_OF(work, struct session, async_upload_ctx.work);
161161
upload_ctx = &ses->async_upload_ctx;
162162

163+
if (ses->wait_for_start) {
164+
NET_INFO("[%d] %s waiting for start", ses->id, "TCP");
165+
166+
/* Wait for the start event to be set */
167+
k_event_wait(ses->zperf->start_event, START_EVENT, true, K_FOREVER);
168+
169+
NET_INFO("[%d] %s starting", ses->id, "TCP");
170+
}
171+
163172
NET_DBG("[%d] thread %p priority %d name %s", ses->id, k_current_get(),
164173
k_thread_priority_get(k_current_get()),
165174
k_thread_name_get(k_current_get()));
@@ -250,6 +259,7 @@ int zperf_tcp_upload_async(const struct zperf_upload_params *param,
250259

251260
#ifdef CONFIG_ZPERF_SESSION_PER_THREAD
252261
struct k_work_q *queue;
262+
struct zperf_work *zperf;
253263
struct session *ses;
254264
k_tid_t tid;
255265

@@ -270,7 +280,9 @@ int zperf_tcp_upload_async(const struct zperf_upload_params *param,
270280
ses->async_upload_ctx.callback = callback;
271281
ses->async_upload_ctx.user_data = user_data;
272282

273-
queue = get_queue(SESSION_TCP, ses->id);
283+
zperf = get_queue(SESSION_TCP, ses->id);
284+
285+
queue = zperf->queue;
274286
if (queue == NULL) {
275287
NET_ERR("Cannot get a work queue!");
276288
return -ENOENT;
@@ -282,6 +294,8 @@ int zperf_tcp_upload_async(const struct zperf_upload_params *param,
282294
k_work_init(&ses->async_upload_ctx.work, tcp_upload_async_work);
283295

284296
ses->start_time = k_uptime_ticks();
297+
ses->zperf = zperf;
298+
ses->wait_for_start = param->options.wait_for_start;
285299

286300
zperf_async_work_submit(SESSION_TCP, ses->id, &ses->async_upload_ctx.work);
287301

subsys/net/lib/zperf/zperf_udp_uploader.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,15 @@ static void udp_upload_async_work(struct k_work *work)
346346
ses = CONTAINER_OF(work, struct session, async_upload_ctx.work);
347347
upload_ctx = &ses->async_upload_ctx;
348348

349+
if (ses->wait_for_start) {
350+
NET_INFO("[%d] %s waiting for start", ses->id, "UDP");
351+
352+
/* Wait for the start event to be set */
353+
k_event_wait(ses->zperf->start_event, START_EVENT, true, K_FOREVER);
354+
355+
NET_INFO("[%d] %s starting", ses->id, "UDP");
356+
}
357+
349358
NET_DBG("[%d] thread %p priority %d name %s", ses->id, k_current_get(),
350359
k_thread_priority_get(k_current_get()),
351360
k_thread_name_get(k_current_get()));
@@ -383,6 +392,7 @@ int zperf_udp_upload_async(const struct zperf_upload_params *param,
383392

384393
#ifdef CONFIG_ZPERF_SESSION_PER_THREAD
385394
struct k_work_q *queue;
395+
struct zperf_work *zperf;
386396
struct session *ses;
387397
k_tid_t tid;
388398

@@ -403,7 +413,9 @@ int zperf_udp_upload_async(const struct zperf_upload_params *param,
403413
ses->async_upload_ctx.callback = callback;
404414
ses->async_upload_ctx.user_data = user_data;
405415

406-
queue = get_queue(SESSION_UDP, ses->id);
416+
zperf = get_queue(SESSION_UDP, ses->id);
417+
418+
queue = zperf->queue;
407419
if (queue == NULL) {
408420
NET_ERR("Cannot get a work queue!");
409421
return -ENOENT;
@@ -415,6 +427,8 @@ int zperf_udp_upload_async(const struct zperf_upload_params *param,
415427
k_work_init(&ses->async_upload_ctx.work, udp_upload_async_work);
416428

417429
ses->start_time = k_uptime_ticks();
430+
ses->zperf = zperf;
431+
ses->wait_for_start = param->options.wait_for_start;
418432

419433
zperf_async_work_submit(SESSION_UDP, ses->id, &ses->async_upload_ctx.work);
420434

0 commit comments

Comments
 (0)