Skip to content

Commit

Permalink
af_unix: Optimise hash table layout.
Browse files Browse the repository at this point in the history
Commit 6dd4142 ("Merge branch 'af_unix-per-netns-socket-hash'") and
commit 51bae88 ("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>
  • Loading branch information
Kuniyuki Iwashima authored and Paolo Abeni committed Jul 7, 2022
1 parent 7ed5f24 commit cf21b35
Showing 1 changed file with 12 additions and 6 deletions.
18 changes: 12 additions & 6 deletions net/unix/af_unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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);

Expand All @@ -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]);
}
Expand Down

0 comments on commit cf21b35

Please sign in to comment.