]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
OPTIM: connection: progressive hash for conn_calculate_hash()
authorAurelien DARRAGON <adarragon@haproxy.com>
Thu, 25 Jan 2024 09:35:39 +0000 (10:35 +0100)
committerAurelien DARRAGON <adarragon@haproxy.com>
Thu, 1 Feb 2024 09:58:30 +0000 (10:58 +0100)
Some CPU time is needlessly wasted in conn_calculate_hash(), because all
params are first copied into a temporary buffer before computing the
hash on the whole buffer. Instead, let's leverage the XXH progressive
hash update functions to avoid expensive memcpys.

include/haproxy/connection.h
src/connection.c

index c7d98834ac7d02e7f988ee771367a9e2c6774270..2a7683d9a7ec9a002d7bccd9cdc69eac78f115c4 100644 (file)
@@ -96,12 +96,6 @@ void sockaddr_free(struct sockaddr_storage **sap);
 /* connection hash stuff */
 uint64_t conn_calculate_hash(const struct conn_hash_params *params);
 uint64_t conn_hash_prehash(char *buf, size_t size);
-void conn_hash_update(char *buf, size_t *idx,
-                      const void *data, size_t size,
-                      enum conn_hash_params_t *flags,
-                      enum conn_hash_params_t type);
-uint64_t conn_hash_digest(char *buf, size_t bufsize,
-                          enum conn_hash_params_t flags);
 
 int conn_reverse(struct connection *conn);
 
index ed6beb77cd076801c0a60548fd4b4cc68e91c7ab..99f7612d0cb46c1396c0df5f2dd2ec947d77b279 100644 (file)
@@ -2544,9 +2544,38 @@ static struct cfg_kw_list cfg_kws = {ILH, {
 
 INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
 
+/* Generate the hash of a connection with params as input
+ * Each non-null field of params is taken into account for the hash calcul.
+ */
+uint64_t conn_hash_prehash(char *buf, size_t size)
+{
+       return XXH64(buf, size, 0);
+}
+
+/* Computes <data> hash into <hash>. In the same time, <flags>
+ * are updated with <type> for the hash header.
+ */
+static void conn_hash_update(XXH64_state_t *hash,
+                             const void *data, size_t size,
+                             enum conn_hash_params_t *flags,
+                             enum conn_hash_params_t type)
+{
+       XXH64_update(hash, data, size);
+       *flags |= type;
+}
+
+static uint64_t conn_hash_digest(XXH64_state_t *hash,
+                                 enum conn_hash_params_t flags)
+{
+       const uint64_t flags_u64 = (uint64_t)flags;
+       const uint64_t f_hash = XXH64_digest(hash);
+
+       return (flags_u64 << CONN_HASH_PAYLOAD_LEN) | CONN_HASH_GET_PAYLOAD(f_hash);
+}
+
 /* private function to handle sockaddr as input for connection hash */
 static void conn_calculate_hash_sockaddr(const struct sockaddr_storage *ss,
-                                         char *buf, size_t *idx,
+                                         XXH64_state_t *hash,
                                          enum conn_hash_params_t *hash_flags,
                                          enum conn_hash_params_t param_type_addr,
                                          enum conn_hash_params_t param_type_port)
@@ -2558,12 +2587,12 @@ static void conn_calculate_hash_sockaddr(const struct sockaddr_storage *ss,
        case AF_INET:
                addr = (struct sockaddr_in *)ss;
 
-               conn_hash_update(buf, idx,
+               conn_hash_update(hash,
                                 &addr->sin_addr, sizeof(addr->sin_addr),
                                 hash_flags, param_type_addr);
 
                if (addr->sin_port) {
-                       conn_hash_update(buf, idx,
+                       conn_hash_update(hash,
                                         &addr->sin_port, sizeof(addr->sin_port),
                                         hash_flags, param_type_port);
                }
@@ -2573,12 +2602,12 @@ static void conn_calculate_hash_sockaddr(const struct sockaddr_storage *ss,
        case AF_INET6:
                addr6 = (struct sockaddr_in6 *)ss;
 
-               conn_hash_update(buf, idx,
+               conn_hash_update(hash,
                                 &addr6->sin6_addr, sizeof(addr6->sin6_addr),
                                 hash_flags, param_type_addr);
 
                if (addr6->sin6_port) {
-                       conn_hash_update(buf, idx,
+                       conn_hash_update(hash,
                                         &addr6->sin6_port, sizeof(addr6->sin6_port),
                                         hash_flags, param_type_port);
                }
@@ -2587,76 +2616,42 @@ static void conn_calculate_hash_sockaddr(const struct sockaddr_storage *ss,
        }
 }
 
-/* Generate the hash of a connection with params as input
- * Each non-null field of params is taken into account for the hash calcul.
- */
-uint64_t conn_hash_prehash(char *buf, size_t size)
-{
-       return XXH64(buf, size, 0);
-}
-
-/* Append <data> into <buf> at <idx> offset in preparation for connection hash
- * calcul. <idx> is incremented beyond data <size>. In the same time, <flags>
- * are updated with <type> for the hash header.
- */
-void conn_hash_update(char *buf, size_t *idx,
-                      const void *data, size_t size,
-                      enum conn_hash_params_t *flags,
-                      enum conn_hash_params_t type)
-{
-       memcpy(&buf[*idx], data, size);
-       *idx += size;
-       *flags |= type;
-}
-
-uint64_t conn_hash_digest(char *buf, size_t bufsize,
-                          enum conn_hash_params_t flags)
-{
-       const uint64_t flags_u64 = (uint64_t)flags;
-       const uint64_t hash = XXH64(buf, bufsize, 0);
-
-       return (flags_u64 << CONN_HASH_PAYLOAD_LEN) | CONN_HASH_GET_PAYLOAD(hash);
-}
-
 uint64_t conn_calculate_hash(const struct conn_hash_params *params)
 {
-       char *buf;
-       size_t idx = 0;
-       uint64_t hash = 0;
        enum conn_hash_params_t hash_flags = 0;
+       XXH64_state_t hash;
 
-       buf = trash.area;
+       XXH64_reset(&hash, 0);
 
-       conn_hash_update(buf, &idx, &params->target, sizeof(params->target), &hash_flags, 0);
+       conn_hash_update(&hash, &params->target, sizeof(params->target), &hash_flags, 0);
 
        if (params->sni_prehash) {
-               conn_hash_update(buf, &idx,
+               conn_hash_update(&hash,
                                 &params->sni_prehash, sizeof(params->sni_prehash),
                                 &hash_flags, CONN_HASH_PARAMS_TYPE_SNI);
        }
 
        if (params->dst_addr) {
                conn_calculate_hash_sockaddr(params->dst_addr,
-                                            buf, &idx, &hash_flags,
+                                            &hash, &hash_flags,
                                             CONN_HASH_PARAMS_TYPE_DST_ADDR,
                                             CONN_HASH_PARAMS_TYPE_DST_PORT);
        }
 
        if (params->src_addr) {
                conn_calculate_hash_sockaddr(params->src_addr,
-                                            buf, &idx, &hash_flags,
+                                            &hash, &hash_flags,
                                             CONN_HASH_PARAMS_TYPE_SRC_ADDR,
                                             CONN_HASH_PARAMS_TYPE_SRC_PORT);
        }
 
        if (params->proxy_prehash) {
-               conn_hash_update(buf, &idx,
+               conn_hash_update(&hash,
                                 &params->proxy_prehash, sizeof(params->proxy_prehash),
                                 &hash_flags, CONN_HASH_PARAMS_TYPE_PROXY);
        }
 
-       hash = conn_hash_digest(buf, idx, hash_flags);
-       return hash;
+       return conn_hash_digest(&hash, hash_flags);
 }
 
 /* Reverse a <conn> connection instance. This effectively moves the connection