Skip to content

Commit 4b27275

Browse files
Eric Dumazetdavem330
authored andcommitted
udp: add busylocks in RX path
Idea of busylocks is to let producers grab an extra spinlock to relieve pressure on the receive_queue spinlock shared by consumer. This behavior is requested only once socket receive queue is above half occupancy. Under flood, this means that only one producer can be in line trying to acquire the receive_queue spinlock. These busylock can be allocated on a per cpu manner, instead of a per socket one (that would consume a cache line per socket) This patch considerably improves UDP behavior under stress, depending on number of NIC RX queues and/or RPS spread. Signed-off-by: Eric Dumazet <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent d96dac1 commit 4b27275

File tree

1 file changed

+42
-1
lines changed

1 file changed

+42
-1
lines changed

net/ipv4/udp.c

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1195,10 +1195,36 @@ void udp_skb_destructor(struct sock *sk, struct sk_buff *skb)
11951195
}
11961196
EXPORT_SYMBOL(udp_skb_destructor);
11971197

1198+
/* Idea of busylocks is to let producers grab an extra spinlock
1199+
* to relieve pressure on the receive_queue spinlock shared by consumer.
1200+
* Under flood, this means that only one producer can be in line
1201+
* trying to acquire the receive_queue spinlock.
1202+
* These busylock can be allocated on a per cpu manner, instead of a
1203+
* per socket one (that would consume a cache line per socket)
1204+
*/
1205+
static int udp_busylocks_log __read_mostly;
1206+
static spinlock_t *udp_busylocks __read_mostly;
1207+
1208+
static spinlock_t *busylock_acquire(void *ptr)
1209+
{
1210+
spinlock_t *busy;
1211+
1212+
busy = udp_busylocks + hash_ptr(ptr, udp_busylocks_log);
1213+
spin_lock(busy);
1214+
return busy;
1215+
}
1216+
1217+
static void busylock_release(spinlock_t *busy)
1218+
{
1219+
if (busy)
1220+
spin_unlock(busy);
1221+
}
1222+
11981223
int __udp_enqueue_schedule_skb(struct sock *sk, struct sk_buff *skb)
11991224
{
12001225
struct sk_buff_head *list = &sk->sk_receive_queue;
12011226
int rmem, delta, amt, err = -ENOMEM;
1227+
spinlock_t *busy = NULL;
12021228
int size;
12031229

12041230
/* try to avoid the costly atomic add/sub pair when the receive
@@ -1214,8 +1240,11 @@ int __udp_enqueue_schedule_skb(struct sock *sk, struct sk_buff *skb)
12141240
* - Less cache line misses at copyout() time
12151241
* - Less work at consume_skb() (less alien page frag freeing)
12161242
*/
1217-
if (rmem > (sk->sk_rcvbuf >> 1))
1243+
if (rmem > (sk->sk_rcvbuf >> 1)) {
12181244
skb_condense(skb);
1245+
1246+
busy = busylock_acquire(sk);
1247+
}
12191248
size = skb->truesize;
12201249

12211250
/* we drop only if the receive buf is full and the receive
@@ -1252,13 +1281,15 @@ int __udp_enqueue_schedule_skb(struct sock *sk, struct sk_buff *skb)
12521281
if (!sock_flag(sk, SOCK_DEAD))
12531282
sk->sk_data_ready(sk);
12541283

1284+
busylock_release(busy);
12551285
return 0;
12561286

12571287
uncharge_drop:
12581288
atomic_sub(skb->truesize, &sk->sk_rmem_alloc);
12591289

12601290
drop:
12611291
atomic_inc(&sk->sk_drops);
1292+
busylock_release(busy);
12621293
return err;
12631294
}
12641295
EXPORT_SYMBOL_GPL(__udp_enqueue_schedule_skb);
@@ -2613,6 +2644,7 @@ EXPORT_SYMBOL(udp_flow_hashrnd);
26132644
void __init udp_init(void)
26142645
{
26152646
unsigned long limit;
2647+
unsigned int i;
26162648

26172649
udp_table_init(&udp_table, "UDP");
26182650
limit = nr_free_buffer_pages() / 8;
@@ -2623,4 +2655,13 @@ void __init udp_init(void)
26232655

26242656
sysctl_udp_rmem_min = SK_MEM_QUANTUM;
26252657
sysctl_udp_wmem_min = SK_MEM_QUANTUM;
2658+
2659+
/* 16 spinlocks per cpu */
2660+
udp_busylocks_log = ilog2(nr_cpu_ids) + 4;
2661+
udp_busylocks = kmalloc(sizeof(spinlock_t) << udp_busylocks_log,
2662+
GFP_KERNEL);
2663+
if (!udp_busylocks)
2664+
panic("UDP: failed to alloc udp_busylocks\n");
2665+
for (i = 0; i < (1U << udp_busylocks_log); i++)
2666+
spin_lock_init(udp_busylocks + i);
26262667
}

0 commit comments

Comments
 (0)