Skip to content

Commit bcdc762

Browse files
jukkargalak
authored andcommitted
net: Use k_fifo instead of k_work in RX and TX processing
The k_work handler cannot manipulate the used k_work. This means that it is not easy to cleanup the net_pkt because it contains k_work in it. Because of this, use k_fifo instead between RX thread and network driver, and between application and TX thread. A echo-server/client run with IPv4 and UDP gave following results: Using k_work ------------ TX traffic class statistics: TC Priority Sent pkts bytes time [0] BK (1) 21922 5543071 103 us [0->41->26->34=101 us] [1] BE (0) 0 0 - RX traffic class statistics: TC Priority Recv pkts bytes time [0] BK (0) 0 0 - [1] BE (0) 21925 6039151 97 us [0->21->16->37->20=94 us] Using k_fifo ------------ TX traffic class statistics: TC Priority Sent pkts bytes time [0] BK (1) 15079 3811118 94 us [0->36->23->32=91 us] [1] BE (0) 0 0 - RX traffic class statistics: TC Priority Recv pkts bytes time [0] BK (1) 0 0 - [1] BE (0) 15073 4150947 79 us [0->17->12->32->14=75 us] So using k_fifo gives about 10% better performance with same workload. Fixes #34690 Signed-off-by: Jukka Rissanen <[email protected]>
1 parent 2697275 commit bcdc762

File tree

6 files changed

+96
-54
lines changed

6 files changed

+96
-54
lines changed

include/net/net_if.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -396,15 +396,18 @@ struct net_if_config {
396396
*
397397
* Traffic classes are used when sending or receiving data that is classified
398398
* with different priorities. So some traffic can be marked as high priority
399-
* and it will be sent or received first. There is always at least one work
400-
* queue in the system for Rx and Tx. Each network packet that is transmitted
401-
* or received goes through a work queue thread that will transmit it.
399+
* and it will be sent or received first. Each network packet that is
400+
* transmitted or received goes through a fifo to a thread that will transmit
401+
* it.
402402
*/
403403
struct net_traffic_class {
404-
/** Work queue for handling this Tx or Rx packet */
405-
struct k_work_q work_q;
404+
/** Fifo for handling this Tx or Rx packet */
405+
struct k_fifo fifo;
406406

407-
/** Stack for this work queue */
407+
/** Traffic class handler thread */
408+
struct k_thread handler;
409+
410+
/** Stack for this handler */
408411
k_thread_stack_t *stack;
409412
};
410413

include/net/net_pkt.h

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -60,18 +60,11 @@ struct net_pkt_cursor {
6060
* net_pkt_clone() function.
6161
*/
6262
struct net_pkt {
63-
union {
64-
/** Internal variable that is used when packet is sent
65-
* or received.
66-
*/
67-
struct k_work work;
68-
/** Socket layer will queue received net_pkt into a k_fifo.
69-
* Since this happens after consuming net_pkt's k_work on
70-
* RX path, it is then fine to have both attributes sharing
71-
* the same memory area.
72-
*/
73-
intptr_t sock_recv_fifo;
74-
};
63+
/**
64+
* The fifo is used by RX/TX threads and by socket layer. The net_pkt
65+
* is queued via fifo to the processing thread.
66+
*/
67+
intptr_t fifo;
7568

7669
/** Slab pointer from where it belongs to */
7770
struct k_mem_slab *slab;
@@ -264,11 +257,6 @@ struct net_pkt {
264257

265258
/** @cond ignore */
266259

267-
static inline struct k_work *net_pkt_work(struct net_pkt *pkt)
268-
{
269-
return &pkt->work;
270-
}
271-
272260
/* The interface real ll address */
273261
static inline struct net_linkaddr *net_pkt_lladdr_if(struct net_pkt *pkt)
274262
{

subsys/net/ip/net_core.c

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -364,12 +364,8 @@ static void net_rx(struct net_if *iface, struct net_pkt *pkt)
364364
net_pkt_print();
365365
}
366366

367-
static void process_rx_packet(struct k_work *work)
367+
void net_process_rx_packet(struct net_pkt *pkt)
368368
{
369-
struct net_pkt *pkt;
370-
371-
pkt = CONTAINER_OF(work, struct net_pkt, work);
372-
373369
net_pkt_set_rx_stats_tick(pkt, k_cycle_get_32());
374370

375371
net_capture_pkt(net_pkt_iface(pkt), pkt);
@@ -382,8 +378,6 @@ static void net_queue_rx(struct net_if *iface, struct net_pkt *pkt)
382378
uint8_t prio = net_pkt_priority(pkt);
383379
uint8_t tc = net_rx_priority2tc(prio);
384380

385-
k_work_init(net_pkt_work(pkt), process_rx_packet);
386-
387381
#if defined(CONFIG_NET_STATISTICS)
388382
net_stats_update_tc_recv_pkt(iface, tc);
389383
net_stats_update_tc_recv_bytes(iface, tc, net_pkt_get_len(pkt));
@@ -395,7 +389,7 @@ static void net_queue_rx(struct net_if *iface, struct net_pkt *pkt)
395389
#endif
396390

397391
if (NET_TC_RX_COUNT == 0) {
398-
process_rx_packet(net_pkt_work(pkt));
392+
net_process_rx_packet(pkt);
399393
} else {
400394
net_tc_submit_to_rx_queue(tc, pkt);
401395
}

subsys/net/ip/net_if.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -316,12 +316,9 @@ static bool net_if_tx(struct net_if *iface, struct net_pkt *pkt)
316316
return true;
317317
}
318318

319-
static void process_tx_packet(struct k_work *work)
319+
void net_process_tx_packet(struct net_pkt *pkt)
320320
{
321321
struct net_if *iface;
322-
struct net_pkt *pkt;
323-
324-
pkt = CONTAINER_OF(work, struct net_pkt, work);
325322

326323
net_pkt_set_tx_stats_tick(pkt, k_cycle_get_32());
327324

@@ -355,8 +352,6 @@ void net_if_queue_tx(struct net_if *iface, struct net_pkt *pkt)
355352
return;
356353
}
357354

358-
k_work_init(net_pkt_work(pkt), process_tx_packet);
359-
360355
#if NET_TC_TX_COUNT > 1
361356
NET_DBG("TC %d with prio %d pkt %p", tc, prio, pkt);
362357
#endif

subsys/net/ip/net_private.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ extern void net_if_post_init(void);
4747
extern void net_if_carrier_down(struct net_if *iface);
4848
extern void net_if_stats_reset(struct net_if *iface);
4949
extern void net_if_stats_reset_all(void);
50+
extern void net_process_rx_packet(struct net_pkt *pkt);
51+
extern void net_process_tx_packet(struct net_pkt *pkt);
5052

5153
#if defined(CONFIG_NET_NATIVE) || defined(CONFIG_NET_OFFLOAD)
5254
extern void net_context_init(void);

subsys/net/ip/net_tc.c

Lines changed: 77 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,19 @@ static struct net_traffic_class tx_classes[NET_TC_TX_COUNT];
4040
static struct net_traffic_class rx_classes[NET_TC_RX_COUNT];
4141
#endif
4242

43+
#if NET_TC_RX_COUNT > 0 || NET_TC_TX_COUNT > 0
44+
static void submit_to_queue(struct k_fifo *queue, struct net_pkt *pkt)
45+
{
46+
k_fifo_put(queue, pkt);
47+
}
48+
#endif
49+
4350
bool net_tc_submit_to_tx_queue(uint8_t tc, struct net_pkt *pkt)
4451
{
4552
#if NET_TC_TX_COUNT > 0
4653
net_pkt_set_tx_stats_tick(pkt, k_cycle_get_32());
4754

48-
k_work_submit_to_queue(&tx_classes[tc].work_q, net_pkt_work(pkt));
55+
submit_to_queue(&tx_classes[tc].fifo, pkt);
4956
#else
5057
ARG_UNUSED(tc);
5158
ARG_UNUSED(pkt);
@@ -58,7 +65,7 @@ void net_tc_submit_to_rx_queue(uint8_t tc, struct net_pkt *pkt)
5865
#if NET_TC_RX_COUNT > 0
5966
net_pkt_set_rx_stats_tick(pkt, k_cycle_get_32());
6067

61-
k_work_submit_to_queue(&rx_classes[tc].work_q, net_pkt_work(pkt));
68+
submit_to_queue(&rx_classes[tc].fifo, pkt);
6269
#else
6370
ARG_UNUSED(tc);
6471
ARG_UNUSED(pkt);
@@ -229,9 +236,40 @@ static void net_tc_rx_stats_priority_setup(struct net_if *iface,
229236
#endif
230237
#endif
231238

232-
/* Create workqueue for each traffic class we are using. All the network
233-
* traffic goes through these classes. There needs to be at least one traffic
234-
* class in the system.
239+
#if NET_TC_RX_COUNT > 0
240+
static void tc_rx_handler(struct k_fifo *fifo)
241+
{
242+
struct net_pkt *pkt;
243+
244+
while (1) {
245+
pkt = k_fifo_get(fifo, K_FOREVER);
246+
if (pkt == NULL) {
247+
continue;
248+
}
249+
250+
net_process_rx_packet(pkt);
251+
}
252+
}
253+
#endif
254+
255+
#if NET_TC_TX_COUNT > 0
256+
static void tc_tx_handler(struct k_fifo *fifo)
257+
{
258+
struct net_pkt *pkt;
259+
260+
while (1) {
261+
pkt = k_fifo_get(fifo, K_FOREVER);
262+
if (pkt == NULL) {
263+
continue;
264+
}
265+
266+
net_process_tx_packet(pkt);
267+
}
268+
}
269+
#endif
270+
271+
/* Create a fifo for each traffic class we are using. All the network
272+
* traffic goes through these classes.
235273
*/
236274
void net_tc_tx_init(void)
237275
{
@@ -250,32 +288,43 @@ void net_tc_tx_init(void)
250288
for (i = 0; i < NET_TC_TX_COUNT; i++) {
251289
uint8_t thread_priority;
252290
int priority;
291+
k_tid_t tid;
253292

254293
thread_priority = tx_tc2thread(i);
255294

256295
priority = IS_ENABLED(CONFIG_NET_TC_THREAD_COOPERATIVE) ?
257296
K_PRIO_COOP(thread_priority) :
258297
K_PRIO_PREEMPT(thread_priority);
259298

260-
NET_DBG("[%d] Starting TX queue %p stack size %zd "
299+
NET_DBG("[%d] Starting TX handler %p stack size %zd "
261300
"prio %d %s(%d)", i,
262-
&tx_classes[i].work_q,
301+
&tx_classes[i].handler,
263302
K_KERNEL_STACK_SIZEOF(tx_stack[i]),
264303
thread_priority,
265304
IS_ENABLED(CONFIG_NET_TC_THREAD_COOPERATIVE) ?
266305
"coop" : "preempt",
267306
priority);
268307

269-
k_work_queue_start(&tx_classes[i].work_q, tx_stack[i],
270-
K_KERNEL_STACK_SIZEOF(tx_stack[i]), priority,
271-
NULL);
308+
k_fifo_init(&tx_classes[i].fifo);
309+
310+
tid = k_thread_create(&tx_classes[i].handler, tx_stack[i],
311+
K_KERNEL_STACK_SIZEOF(tx_stack[i]),
312+
(k_thread_entry_t)tc_tx_handler,
313+
&tx_classes[i].fifo, NULL, NULL,
314+
priority, 0, K_FOREVER);
315+
if (!tid) {
316+
NET_ERR("Cannot create TC handler thread %d", i);
317+
continue;
318+
}
272319

273320
if (IS_ENABLED(CONFIG_THREAD_NAME)) {
274321
char name[MAX_NAME_LEN];
275322

276323
snprintk(name, sizeof(name), "tx_q[%d]", i);
277-
k_thread_name_set(&tx_classes[i].work_q.thread, name);
324+
k_thread_name_set(tid, name);
278325
}
326+
327+
k_thread_start(tid);
279328
}
280329
#endif
281330
}
@@ -297,32 +346,43 @@ void net_tc_rx_init(void)
297346
for (i = 0; i < NET_TC_RX_COUNT; i++) {
298347
uint8_t thread_priority;
299348
int priority;
349+
k_tid_t tid;
300350

301351
thread_priority = rx_tc2thread(i);
302352

303353
priority = IS_ENABLED(CONFIG_NET_TC_THREAD_COOPERATIVE) ?
304354
K_PRIO_COOP(thread_priority) :
305355
K_PRIO_PREEMPT(thread_priority);
306356

307-
NET_DBG("[%d] Starting RX queue %p stack size %zd "
357+
NET_DBG("[%d] Starting RX handler %p stack size %zd "
308358
"prio %d %s(%d)", i,
309-
&rx_classes[i].work_q,
359+
&rx_classes[i].handler,
310360
K_KERNEL_STACK_SIZEOF(rx_stack[i]),
311361
thread_priority,
312362
IS_ENABLED(CONFIG_NET_TC_THREAD_COOPERATIVE) ?
313363
"coop" : "preempt",
314364
priority);
315365

316-
k_work_queue_start(&rx_classes[i].work_q, rx_stack[i],
317-
K_KERNEL_STACK_SIZEOF(rx_stack[i]), priority,
318-
NULL);
366+
k_fifo_init(&rx_classes[i].fifo);
367+
368+
tid = k_thread_create(&rx_classes[i].handler, rx_stack[i],
369+
K_KERNEL_STACK_SIZEOF(rx_stack[i]),
370+
(k_thread_entry_t)tc_rx_handler,
371+
&rx_classes[i].fifo, NULL, NULL,
372+
priority, 0, K_FOREVER);
373+
if (!tid) {
374+
NET_ERR("Cannot create TC handler thread %d", i);
375+
continue;
376+
}
319377

320378
if (IS_ENABLED(CONFIG_THREAD_NAME)) {
321379
char name[MAX_NAME_LEN];
322380

323381
snprintk(name, sizeof(name), "rx_q[%d]", i);
324-
k_thread_name_set(&rx_classes[i].work_q.thread, name);
382+
k_thread_name_set(tid, name);
325383
}
384+
385+
k_thread_start(tid);
326386
}
327387
#endif
328388
}

0 commit comments

Comments
 (0)