mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 19:51:31 -04:00
[INET]: speedup inet (tcp/dccp) lookups
Arnaldo and I agreed it could be applied now, because I have other
pending patches depending on this one (Thank you Arnaldo)
(The other important patch moves skc_refcnt in a separate cache line,
so that the SMP/NUMA performance doesnt suffer from cache line ping pongs)
1) First some performance data :
--------------------------------
tcp_v4_rcv() wastes a *lot* of time in __inet_lookup_established()
The most time critical code is :
sk_for_each(sk, node, &head->chain) {
if (INET_MATCH(sk, acookie, saddr, daddr, ports, dif))
goto hit; /* You sunk my battleship! */
}
The sk_for_each() does use prefetch() hints but only the begining of
"struct sock" is prefetched.
As INET_MATCH first comparison uses inet_sk(__sk)->daddr, wich is far
away from the begining of "struct sock", it has to bring into CPU
cache cold cache line. Each iteration has to use at least 2 cache
lines.
This can be problematic if some chains are very long.
2) The goal
-----------
The idea I had is to change things so that INET_MATCH() may return
FALSE in 99% of cases only using the data already in the CPU cache,
using one cache line per iteration.
3) Description of the patch
---------------------------
Adds a new 'unsigned int skc_hash' field in 'struct sock_common',
filling a 32 bits hole on 64 bits platform.
struct sock_common {
unsigned short skc_family;
volatile unsigned char skc_state;
unsigned char skc_reuse;
int skc_bound_dev_if;
struct hlist_node skc_node;
struct hlist_node skc_bind_node;
atomic_t skc_refcnt;
+ unsigned int skc_hash;
struct proto *skc_prot;
};
Store in this 32 bits field the full hash, not masked by (ehash_size -
1) Using this full hash as the first comparison done in INET_MATCH
permits us immediatly skip the element without touching a second cache
line in case of a miss.
Suppress the sk_hashent/tw_hashent fields since skc_hash (aliased to
sk_hash and tw_hash) already contains the slot number if we mask with
(ehash_size - 1)
File include/net/inet_hashtables.h
64 bits platforms :
#define INET_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\
(((__sk)->sk_hash == (__hash))
((*((__u64 *)&(inet_sk(__sk)->daddr)))== (__cookie)) && \
((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \
(!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
32bits platforms:
#define TCP_IPV4_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\
(((__sk)->sk_hash == (__hash)) && \
(inet_sk(__sk)->daddr == (__saddr)) && \
(inet_sk(__sk)->rcv_saddr == (__daddr)) && \
(!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
- Adds a prefetch(head->chain.first) in
__inet_lookup_established()/__tcp_v4_check_established() and
__inet6_lookup_established()/__tcp_v6_check_established() and
__dccp_v4_check_established() to bring into cache the first element of the
list, before the {read|write}_lock(&head->lock);
Signed-off-by: Eric Dumazet <[email protected]>
Acked-by: Arnaldo Carvalho de Melo <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
This commit is contained in:
parent
399de50bbb
commit
81c3d5470e
12 changed files with 85 additions and 69 deletions
|
|
@ -46,7 +46,7 @@ static void __vcc_insert_socket(struct sock *sk)
|
|||
struct atm_vcc *vcc = atm_sk(sk);
|
||||
struct hlist_head *head = &vcc_hash[vcc->vci &
|
||||
(VCC_HTABLE_SIZE - 1)];
|
||||
sk->sk_hashent = vcc->vci & (VCC_HTABLE_SIZE - 1);
|
||||
sk->sk_hash = vcc->vci & (VCC_HTABLE_SIZE - 1);
|
||||
sk_add_node(sk, head);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,27 +62,27 @@ static int __dccp_v4_check_established(struct sock *sk, const __u16 lport,
|
|||
const int dif = sk->sk_bound_dev_if;
|
||||
INET_ADDR_COOKIE(acookie, saddr, daddr)
|
||||
const __u32 ports = INET_COMBINED_PORTS(inet->dport, lport);
|
||||
const int hash = inet_ehashfn(daddr, lport, saddr, inet->dport,
|
||||
dccp_hashinfo.ehash_size);
|
||||
struct inet_ehash_bucket *head = &dccp_hashinfo.ehash[hash];
|
||||
unsigned int hash = inet_ehashfn(daddr, lport, saddr, inet->dport);
|
||||
struct inet_ehash_bucket *head = inet_ehash_bucket(&dccp_hashinfo, hash);
|
||||
const struct sock *sk2;
|
||||
const struct hlist_node *node;
|
||||
struct inet_timewait_sock *tw;
|
||||
|
||||
prefetch(head->chain.first);
|
||||
write_lock(&head->lock);
|
||||
|
||||
/* Check TIME-WAIT sockets first. */
|
||||
sk_for_each(sk2, node, &(head + dccp_hashinfo.ehash_size)->chain) {
|
||||
tw = inet_twsk(sk2);
|
||||
|
||||
if (INET_TW_MATCH(sk2, acookie, saddr, daddr, ports, dif))
|
||||
if (INET_TW_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif))
|
||||
goto not_unique;
|
||||
}
|
||||
tw = NULL;
|
||||
|
||||
/* And established part... */
|
||||
sk_for_each(sk2, node, &head->chain) {
|
||||
if (INET_MATCH(sk2, acookie, saddr, daddr, ports, dif))
|
||||
if (INET_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif))
|
||||
goto not_unique;
|
||||
}
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ static int __dccp_v4_check_established(struct sock *sk, const __u16 lport,
|
|||
* in hash table socket with a funny identity. */
|
||||
inet->num = lport;
|
||||
inet->sport = htons(lport);
|
||||
sk->sk_hashent = hash;
|
||||
sk->sk_hash = hash;
|
||||
BUG_TRAP(sk_unhashed(sk));
|
||||
__sk_add_node(sk, &head->chain);
|
||||
sock_prot_inc_use(sk->sk_prot);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ void __inet_twsk_kill(struct inet_timewait_sock *tw, struct inet_hashinfo *hashi
|
|||
struct inet_bind_hashbucket *bhead;
|
||||
struct inet_bind_bucket *tb;
|
||||
/* Unlink from established hashes. */
|
||||
struct inet_ehash_bucket *ehead = &hashinfo->ehash[tw->tw_hashent];
|
||||
struct inet_ehash_bucket *ehead = inet_ehash_bucket(hashinfo, tw->tw_hash);
|
||||
|
||||
write_lock(&ehead->lock);
|
||||
if (hlist_unhashed(&tw->tw_node)) {
|
||||
|
|
@ -60,7 +60,7 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk,
|
|||
{
|
||||
const struct inet_sock *inet = inet_sk(sk);
|
||||
const struct inet_connection_sock *icsk = inet_csk(sk);
|
||||
struct inet_ehash_bucket *ehead = &hashinfo->ehash[sk->sk_hashent];
|
||||
struct inet_ehash_bucket *ehead = inet_ehash_bucket(hashinfo, sk->sk_hash);
|
||||
struct inet_bind_hashbucket *bhead;
|
||||
/* Step 1: Put TW into bind hash. Original socket stays there too.
|
||||
Note, that any socket with inet->num != 0 MUST be bound in
|
||||
|
|
@ -106,7 +106,7 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int stat
|
|||
tw->tw_dport = inet->dport;
|
||||
tw->tw_family = sk->sk_family;
|
||||
tw->tw_reuse = sk->sk_reuse;
|
||||
tw->tw_hashent = sk->sk_hashent;
|
||||
tw->tw_hash = sk->sk_hash;
|
||||
tw->tw_ipv6only = 0;
|
||||
tw->tw_prot = sk->sk_prot_creator;
|
||||
atomic_set(&tw->tw_refcnt, 1);
|
||||
|
|
|
|||
|
|
@ -130,19 +130,20 @@ static int __tcp_v4_check_established(struct sock *sk, __u16 lport,
|
|||
int dif = sk->sk_bound_dev_if;
|
||||
INET_ADDR_COOKIE(acookie, saddr, daddr)
|
||||
const __u32 ports = INET_COMBINED_PORTS(inet->dport, lport);
|
||||
const int hash = inet_ehashfn(daddr, lport, saddr, inet->dport, tcp_hashinfo.ehash_size);
|
||||
struct inet_ehash_bucket *head = &tcp_hashinfo.ehash[hash];
|
||||
unsigned int hash = inet_ehashfn(daddr, lport, saddr, inet->dport);
|
||||
struct inet_ehash_bucket *head = inet_ehash_bucket(&tcp_hashinfo, hash);
|
||||
struct sock *sk2;
|
||||
const struct hlist_node *node;
|
||||
struct inet_timewait_sock *tw;
|
||||
|
||||
prefetch(head->chain.first);
|
||||
write_lock(&head->lock);
|
||||
|
||||
/* Check TIME-WAIT sockets first. */
|
||||
sk_for_each(sk2, node, &(head + tcp_hashinfo.ehash_size)->chain) {
|
||||
tw = inet_twsk(sk2);
|
||||
|
||||
if (INET_TW_MATCH(sk2, acookie, saddr, daddr, ports, dif)) {
|
||||
if (INET_TW_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif)) {
|
||||
const struct tcp_timewait_sock *tcptw = tcp_twsk(sk2);
|
||||
struct tcp_sock *tp = tcp_sk(sk);
|
||||
|
||||
|
|
@ -179,7 +180,7 @@ static int __tcp_v4_check_established(struct sock *sk, __u16 lport,
|
|||
|
||||
/* And established part... */
|
||||
sk_for_each(sk2, node, &head->chain) {
|
||||
if (INET_MATCH(sk2, acookie, saddr, daddr, ports, dif))
|
||||
if (INET_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif))
|
||||
goto not_unique;
|
||||
}
|
||||
|
||||
|
|
@ -188,7 +189,7 @@ unique:
|
|||
* in hash table socket with a funny identity. */
|
||||
inet->num = lport;
|
||||
inet->sport = htons(lport);
|
||||
sk->sk_hashent = hash;
|
||||
sk->sk_hash = hash;
|
||||
BUG_TRAP(sk_unhashed(sk));
|
||||
__sk_add_node(sk, &head->chain);
|
||||
sock_prot_inc_use(sk->sk_prot);
|
||||
|
|
|
|||
|
|
@ -209,9 +209,11 @@ static __inline__ void __tcp_v6_hash(struct sock *sk)
|
|||
lock = &tcp_hashinfo.lhash_lock;
|
||||
inet_listen_wlock(&tcp_hashinfo);
|
||||
} else {
|
||||
sk->sk_hashent = inet6_sk_ehashfn(sk, tcp_hashinfo.ehash_size);
|
||||
list = &tcp_hashinfo.ehash[sk->sk_hashent].chain;
|
||||
lock = &tcp_hashinfo.ehash[sk->sk_hashent].lock;
|
||||
unsigned int hash;
|
||||
sk->sk_hash = hash = inet6_sk_ehashfn(sk);
|
||||
hash &= (tcp_hashinfo.ehash_size - 1);
|
||||
list = &tcp_hashinfo.ehash[hash].chain;
|
||||
lock = &tcp_hashinfo.ehash[hash].lock;
|
||||
write_lock(lock);
|
||||
}
|
||||
|
||||
|
|
@ -322,13 +324,13 @@ static int __tcp_v6_check_established(struct sock *sk, const __u16 lport,
|
|||
const struct in6_addr *saddr = &np->daddr;
|
||||
const int dif = sk->sk_bound_dev_if;
|
||||
const u32 ports = INET_COMBINED_PORTS(inet->dport, lport);
|
||||
const int hash = inet6_ehashfn(daddr, inet->num, saddr, inet->dport,
|
||||
tcp_hashinfo.ehash_size);
|
||||
struct inet_ehash_bucket *head = &tcp_hashinfo.ehash[hash];
|
||||
unsigned int hash = inet6_ehashfn(daddr, inet->num, saddr, inet->dport);
|
||||
struct inet_ehash_bucket *head = inet_ehash_bucket(&tcp_hashinfo, hash);
|
||||
struct sock *sk2;
|
||||
const struct hlist_node *node;
|
||||
struct inet_timewait_sock *tw;
|
||||
|
||||
prefetch(head->chain.first);
|
||||
write_lock(&head->lock);
|
||||
|
||||
/* Check TIME-WAIT sockets first. */
|
||||
|
|
@ -365,14 +367,14 @@ static int __tcp_v6_check_established(struct sock *sk, const __u16 lport,
|
|||
|
||||
/* And established part... */
|
||||
sk_for_each(sk2, node, &head->chain) {
|
||||
if (INET6_MATCH(sk2, saddr, daddr, ports, dif))
|
||||
if (INET6_MATCH(sk2, hash, saddr, daddr, ports, dif))
|
||||
goto not_unique;
|
||||
}
|
||||
|
||||
unique:
|
||||
BUG_TRAP(sk_unhashed(sk));
|
||||
__sk_add_node(sk, &head->chain);
|
||||
sk->sk_hashent = hash;
|
||||
sk->sk_hash = hash;
|
||||
sock_prot_inc_use(sk->sk_prot);
|
||||
write_unlock(&head->lock);
|
||||
|
||||
|
|
|
|||
|
|
@ -393,10 +393,10 @@ META_COLLECTOR(int_sk_route_caps)
|
|||
dst->value = skb->sk->sk_route_caps;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_hashent)
|
||||
META_COLLECTOR(int_sk_hash)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_hashent;
|
||||
dst->value = skb->sk->sk_hash;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_lingertime)
|
||||
|
|
@ -515,7 +515,7 @@ static struct meta_ops __meta_ops[TCF_META_TYPE_MAX+1][TCF_META_ID_MAX+1] = {
|
|||
[META_ID(SK_FORWARD_ALLOCS)] = META_FUNC(int_sk_fwd_alloc),
|
||||
[META_ID(SK_ALLOCS)] = META_FUNC(int_sk_alloc),
|
||||
[META_ID(SK_ROUTE_CAPS)] = META_FUNC(int_sk_route_caps),
|
||||
[META_ID(SK_HASHENT)] = META_FUNC(int_sk_hashent),
|
||||
[META_ID(SK_HASH)] = META_FUNC(int_sk_hash),
|
||||
[META_ID(SK_LINGERTIME)] = META_FUNC(int_sk_lingertime),
|
||||
[META_ID(SK_ACK_BACKLOG)] = META_FUNC(int_sk_ack_bl),
|
||||
[META_ID(SK_MAX_ACK_BACKLOG)] = META_FUNC(int_sk_max_ack_bl),
|
||||
|
|
|
|||
Loading…
Reference in a new issue