summaryrefslogtreecommitdiff
path: root/net/unix
diff options
context:
space:
mode:
authorKuniyuki Iwashima <kuniyu@amazon.com>2022-07-06 02:37:15 +0300
committerPaolo Abeni <pabeni@redhat.com>2022-07-07 14:19:01 +0300
commitcf21b355ccb39b0de0b6a7362532bb5584c84a80 (patch)
treecd09f66919c570be5fe870782f649c54b1293a3b /net/unix
parent7ed5f2454acf8ebc126ff4d541832e8d2c28c0a0 (diff)
downloadlinux-cf21b355ccb39b0de0b6a7362532bb5584c84a80.tar.xz
af_unix: Optimise hash table layout.
Commit 6dd4142fb5a9 ("Merge branch 'af_unix-per-netns-socket-hash'") and commit 51bae889fe11 ("af_unix: Put pathname sockets in the global hash table.") changed a hash table layout. Before: unix_socket_table [0 - 255] : abstract & pathname sockets [256 - 511] : unnamed sockets After: per-netns table [0 - 255] : abstract & pathname sockets [256 - 511] : unnamed sockets bsd_socket_table [0 - 255] : pathname sockets (sk_bind_node) Now, while looking up sockets, we traverse the global table for the pathname sockets and the first half of each per-netns hash table for abstract sockets, where pathname sockets are also linked. Thus, the more pathname sockets we have, the longer we take to look up abstract sockets. This characteristic has been there before the layout change, but we can improve it now. This patch changes the per-netns hash table's layout so that sockets not requiring lookup reside in the first half and do not impact the lookup of abstract sockets. per-netns table [0 - 255] : pathname & unnamed sockets [256 - 511] : abstract sockets bsd_socket_table [0 - 255] : pathname sockets (sk_bind_node) We have run a test that bind()s 100,000 abstract/pathname sockets for each, bind()s an abstract socket 100,000 times and measures the time on __unix_find_socket_byname(). The result shows that the patch makes each lookup faster. Without this patch: $ sudo ./funclatency -p 2278 --microseconds __unix_find_socket_byname.isra.44 usec : count distribution 0 -> 1 : 0 | | 2 -> 3 : 0 | | 4 -> 7 : 0 | | 8 -> 15 : 126 | | 16 -> 31 : 1438 |* | 32 -> 63 : 4150 |*** | 64 -> 127 : 9049 |******* | 128 -> 255 : 37704 |******************************* | 256 -> 511 : 47533 |****************************************| With this patch: $ sudo ./funclatency -p 3648 --microseconds __unix_find_socket_byname.isra.46 usec : count distribution 0 -> 1 : 109 | | 2 -> 3 : 318 | | 4 -> 7 : 725 | | 8 -> 15 : 2501 |* | 16 -> 31 : 3061 |** | 32 -> 63 : 4028 |*** | 64 -> 127 : 9312 |******* | 128 -> 255 : 51372 |****************************************| 256 -> 511 : 28574 |********************** | Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com> Link: https://lore.kernel.org/r/20220705233715.759-1-kuniyu@amazon.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Diffstat (limited to 'net/unix')
-rw-r--r--net/unix/af_unix.c18
1 files changed, 12 insertions, 6 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 526b872cc710..784b4b30ce9a 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -135,7 +135,7 @@ static unsigned int unix_unbound_hash(struct sock *sk)
hash ^= hash >> 8;
hash ^= sk->sk_type;
- return UNIX_HASH_MOD + 1 + (hash & UNIX_HASH_MOD);
+ return hash & UNIX_HASH_MOD;
}
static unsigned int unix_bsd_hash(struct inode *i)
@@ -153,16 +153,17 @@ static unsigned int unix_abstract_hash(struct sockaddr_un *sunaddr,
hash ^= hash >> 8;
hash ^= type;
- return hash & UNIX_HASH_MOD;
+ return UNIX_HASH_MOD + 1 + (hash & UNIX_HASH_MOD);
}
static void unix_table_double_lock(struct net *net,
unsigned int hash1, unsigned int hash2)
{
- /* hash1 and hash2 is never the same because
- * one is between 0 and UNIX_HASH_MOD, and
- * another is between UNIX_HASH_MOD + 1 and UNIX_HASH_SIZE - 1.
- */
+ if (hash1 == hash2) {
+ spin_lock(&net->unx.table.locks[hash1]);
+ return;
+ }
+
if (hash1 > hash2)
swap(hash1, hash2);
@@ -173,6 +174,11 @@ static void unix_table_double_lock(struct net *net,
static void unix_table_double_unlock(struct net *net,
unsigned int hash1, unsigned int hash2)
{
+ if (hash1 == hash2) {
+ spin_unlock(&net->unx.table.locks[hash1]);
+ return;
+ }
+
spin_unlock(&net->unx.table.locks[hash1]);
spin_unlock(&net->unx.table.locks[hash2]);
}