Skip to content

Commit 6d7b857

Browse files
netoptimizerdavem330
authored andcommitted
net: use lib/percpu_counter API for fragmentation mem accounting
Replace the per network namespace shared atomic "mem" accounting variable, in the fragmentation code, with a lib/percpu_counter. Getting percpu_counter to scale to the fragmentation code usage requires some tweaks. At first view, percpu_counter looks superfast, but it does not scale on multi-CPU/NUMA machines, because the default batch size is too small, for frag code usage. Thus, I have adjusted the batch size by using __percpu_counter_add() directly, instead of percpu_counter_sub() and percpu_counter_add(). The batch size is increased to 130.000, based on the largest 64K fragment memory usage. This does introduce some imprecise memory accounting, but its does not need to be strict for this use-case. It is also essential, that the percpu_counter, does not share cacheline with other writers, to make this scale. Signed-off-by: Jesper Dangaard Brouer <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent d433673 commit 6d7b857

File tree

2 files changed

+20
-8
lines changed

2 files changed

+20
-8
lines changed

include/net/inet_frag.h

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
#ifndef __NET_FRAG_H__
22
#define __NET_FRAG_H__
33

4+
#include <linux/percpu_counter.h>
5+
46
struct netns_frags {
57
int nqueues;
68
struct list_head lru_list;
79

8-
/* Its important for performance to keep lru_list and mem on
9-
* separate cachelines
10+
/* The percpu_counter "mem" need to be cacheline aligned.
11+
* mem.count must not share cacheline with other writers
1012
*/
11-
atomic_t mem ____cacheline_aligned_in_smp;
13+
struct percpu_counter mem ____cacheline_aligned_in_smp;
14+
1215
/* sysctls */
1316
int timeout;
1417
int high_thresh;
@@ -81,29 +84,36 @@ static inline void inet_frag_put(struct inet_frag_queue *q, struct inet_frags *f
8184

8285
/* Memory Tracking Functions. */
8386

87+
/* The default percpu_counter batch size is not big enough to scale to
88+
* fragmentation mem acct sizes.
89+
* The mem size of a 64K fragment is approx:
90+
* (44 fragments * 2944 truesize) + frag_queue struct(200) = 129736 bytes
91+
*/
92+
static unsigned int frag_percpu_counter_batch = 130000;
93+
8494
static inline int frag_mem_limit(struct netns_frags *nf)
8595
{
86-
return atomic_read(&nf->mem);
96+
return percpu_counter_read(&nf->mem);
8797
}
8898

8999
static inline void sub_frag_mem_limit(struct inet_frag_queue *q, int i)
90100
{
91-
atomic_sub(i, &q->net->mem);
101+
__percpu_counter_add(&q->net->mem, -i, frag_percpu_counter_batch);
92102
}
93103

94104
static inline void add_frag_mem_limit(struct inet_frag_queue *q, int i)
95105
{
96-
atomic_add(i, &q->net->mem);
106+
__percpu_counter_add(&q->net->mem, i, frag_percpu_counter_batch);
97107
}
98108

99109
static inline void init_frag_mem_limit(struct netns_frags *nf)
100110
{
101-
atomic_set(&nf->mem, 0);
111+
percpu_counter_init(&nf->mem, 0);
102112
}
103113

104114
static inline int sum_frag_mem_limit(struct netns_frags *nf)
105115
{
106-
return atomic_read(&nf->mem);
116+
return percpu_counter_sum_positive(&nf->mem);
107117
}
108118

109119
#endif

net/ipv4/inet_fragment.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f)
9191
local_bh_disable();
9292
inet_frag_evictor(nf, f, true);
9393
local_bh_enable();
94+
95+
percpu_counter_destroy(&nf->mem);
9496
}
9597
EXPORT_SYMBOL(inet_frags_exit_net);
9698

0 commit comments

Comments
 (0)