diff options
author | Eric Dumazet <edumazet@google.com> | 2012-08-06 22:19:56 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-08-07 19:24:55 -0400 |
commit | 425f09ab7d1c9da6ca4137dd639cb6fe3f8a88f3 (patch) | |
tree | 49c586d8025f671a8e47415f4364bfb818534569 | |
parent | e07b94f1352723994d8b588ac5ed8af91bcc9fb6 (diff) |
net: output path optimizations
1) Avoid dirtying neighbour's confirmed field.
TCP workloads hits this cache line for each incoming ACK.
Lets write n->confirmed only if there is a jiffie change.
2) Optimize neigh_hh_output() for the common Ethernet case, were
hh_len is less than 16 bytes. Replace the memcpy() call
by two inlined 64bit load/stores on x86_64.
Bench results using udpflood test, with -C option (MSG_CONFIRM flag
added to sendto(), to reproduce the n->confirmed dirtying on UDP)
24 threads doing 1.000.000 UDP sendto() on dummy device, 4 runs.
before : 2.247s, 2.235s, 2.247s, 2.318s
after : 1.884s, 1.905s, 1.891s, 1.895s
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/dst.h | 10 | ||||
-rw-r--r-- | include/net/neighbour.h | 14 |
2 files changed, 16 insertions, 8 deletions
diff --git a/include/net/dst.h b/include/net/dst.h index baf597890064..77f52f7dc823 100644 --- a/include/net/dst.h +++ b/include/net/dst.h | |||
@@ -396,11 +396,15 @@ static inline void dst_confirm(struct dst_entry *dst) | |||
396 | static inline int dst_neigh_output(struct dst_entry *dst, struct neighbour *n, | 396 | static inline int dst_neigh_output(struct dst_entry *dst, struct neighbour *n, |
397 | struct sk_buff *skb) | 397 | struct sk_buff *skb) |
398 | { | 398 | { |
399 | struct hh_cache *hh; | 399 | const struct hh_cache *hh; |
400 | |||
401 | if (dst->pending_confirm) { | ||
402 | unsigned long now = jiffies; | ||
400 | 403 | ||
401 | if (unlikely(dst->pending_confirm)) { | ||
402 | n->confirmed = jiffies; | ||
403 | dst->pending_confirm = 0; | 404 | dst->pending_confirm = 0; |
405 | /* avoid dirtying neighbour */ | ||
406 | if (n->confirmed != now) | ||
407 | n->confirmed = now; | ||
404 | } | 408 | } |
405 | 409 | ||
406 | hh = &n->hh; | 410 | hh = &n->hh; |
diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 344d8988842a..0dab173e27da 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h | |||
@@ -334,18 +334,22 @@ static inline int neigh_hh_bridge(struct hh_cache *hh, struct sk_buff *skb) | |||
334 | } | 334 | } |
335 | #endif | 335 | #endif |
336 | 336 | ||
337 | static inline int neigh_hh_output(struct hh_cache *hh, struct sk_buff *skb) | 337 | static inline int neigh_hh_output(const struct hh_cache *hh, struct sk_buff *skb) |
338 | { | 338 | { |
339 | unsigned int seq; | 339 | unsigned int seq; |
340 | int hh_len; | 340 | int hh_len; |
341 | 341 | ||
342 | do { | 342 | do { |
343 | int hh_alen; | ||
344 | |||
345 | seq = read_seqbegin(&hh->hh_lock); | 343 | seq = read_seqbegin(&hh->hh_lock); |
346 | hh_len = hh->hh_len; | 344 | hh_len = hh->hh_len; |
347 | hh_alen = HH_DATA_ALIGN(hh_len); | 345 | if (likely(hh_len <= HH_DATA_MOD)) { |
348 | memcpy(skb->data - hh_alen, hh->hh_data, hh_alen); | 346 | /* this is inlined by gcc */ |
347 | memcpy(skb->data - HH_DATA_MOD, hh->hh_data, HH_DATA_MOD); | ||
348 | } else { | ||
349 | int hh_alen = HH_DATA_ALIGN(hh_len); | ||
350 | |||
351 | memcpy(skb->data - hh_alen, hh->hh_data, hh_alen); | ||
352 | } | ||
349 | } while (read_seqretry(&hh->hh_lock, seq)); | 353 | } while (read_seqretry(&hh->hh_lock, seq)); |
350 | 354 | ||
351 | skb_push(skb, hh_len); | 355 | skb_push(skb, hh_len); |