Skip to content

Commit dde0a64

Browse files
edumazetdavem330
authored andcommitted
net_sched: sch_fq: avoid touching f->next from fq_gc()
A significant amount of cpu cycles is spent in fq_gc() When fq_gc() does its lookup in the rb-tree, it needs the following fields from struct fq_flow : f->sk (lookup key in the rb-tree) f->fq_node (anchor in the rb-tree) f->next (used to determine if the flow is detached) f->age (used to determine if the flow is candidate for gc) This unfortunately spans two cache lines (assuming 64 bytes cache lines) We can avoid using f->next, if we use the low order bit of f->{age|tail} This low order bit is 0, if f->tail points to an sk_buff. We set the low order bit to 1, if the union contains a jiffies value. Combined with the following patch, this makes sure we only need to bring into cpu caches one cache line per flow. Signed-off-by: Eric Dumazet <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent ee1bd48 commit dde0a64

File tree

1 file changed

+13
-8
lines changed

1 file changed

+13
-8
lines changed

net/sched/sch_fq.c

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,14 @@ struct fq_flow {
7070
struct sk_buff *head; /* list of skbs for this flow : first skb */
7171
union {
7272
struct sk_buff *tail; /* last skb in the list */
73-
unsigned long age; /* jiffies when flow was emptied, for gc */
73+
unsigned long age; /* (jiffies | 1UL) when flow was emptied, for gc */
7474
};
7575
struct rb_node fq_node; /* anchor in fq_root[] trees */
7676
struct sock *sk;
7777
int qlen; /* number of packets in flow queue */
7878
int credit;
7979
u32 socket_hash; /* sk_hash */
80-
struct fq_flow *next; /* next pointer in RR lists, or &detached */
80+
struct fq_flow *next; /* next pointer in RR lists */
8181

8282
struct rb_node rate_node; /* anchor in q->delayed tree */
8383
u64 time_next_packet;
@@ -126,20 +126,25 @@ struct fq_sched_data {
126126
struct qdisc_watchdog watchdog;
127127
};
128128

129-
/* special value to mark a detached flow (not on old/new list) */
130-
static struct fq_flow detached, throttled;
131-
129+
/*
130+
* f->tail and f->age share the same location.
131+
* We can use the low order bit to differentiate if this location points
132+
* to a sk_buff or contains a jiffies value, if we force this value to be odd.
133+
* This assumes f->tail low order bit must be 0 since alignof(struct sk_buff) >= 2
134+
*/
132135
static void fq_flow_set_detached(struct fq_flow *f)
133136
{
134-
f->next = &detached;
135-
f->age = jiffies;
137+
f->age = jiffies | 1UL;
136138
}
137139

138140
static bool fq_flow_is_detached(const struct fq_flow *f)
139141
{
140-
return f->next == &detached;
142+
return !!(f->age & 1UL);
141143
}
142144

145+
/* special value to mark a throttled flow (not on old/new list) */
146+
static struct fq_flow throttled;
147+
143148
static bool fq_flow_is_throttled(const struct fq_flow *f)
144149
{
145150
return f->next == &throttled;

0 commit comments

Comments
 (0)