From: Aurelien DARRAGON Date: Thu, 25 Jan 2024 09:35:39 +0000 (+0100) Subject: OPTIM: connection: progressive hash for conn_calculate_hash() X-Git-Tag: v3.0-dev3~120 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ea09075f59d2ad0f218687e9ac3fda8d42eff3ed;p=thirdparty%2Fhaproxy.git OPTIM: connection: progressive hash for conn_calculate_hash() 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. --- diff --git a/include/haproxy/connection.h b/include/haproxy/connection.h index c7d98834ac..2a7683d9a7 100644 --- a/include/haproxy/connection.h +++ b/include/haproxy/connection.h @@ -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); diff --git a/src/connection.c b/src/connection.c index ed6beb77cd..99f7612d0c 100644 --- a/src/connection.c +++ b/src/connection.c @@ -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 hash into . In the same time, + * are updated with 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 into at offset in preparation for connection hash - * calcul. is incremented beyond data . In the same time, - * are updated with 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, ¶ms->target, sizeof(params->target), &hash_flags, 0); + conn_hash_update(&hash, ¶ms->target, sizeof(params->target), &hash_flags, 0); if (params->sni_prehash) { - conn_hash_update(buf, &idx, + conn_hash_update(&hash, ¶ms->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, ¶ms->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 connection instance. This effectively moves the connection