From d79422a0ffa8ed926326496f45105e4132ebf5f0 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 28 Jun 2020 10:31:15 +0200 Subject: [PATCH] BUG/MEDIUM: buffers: always allocate from the local cache first It looked strange to see pool_evict_from_cache() always very present on "perf top", but there was actually a reason to this: while b_free() uses pool_free() which properly disposes the buffer into the local cache and b_alloc_fast() allocates using pool_get_first() which considers the local cache, b_alloc_margin() does not consider the local cache as it only uses __pool_get_first() which only allocates from the shared pools. The impact is that basically everywhere a buffer is allocated (muxes, streams, applets), it's always picked from the shared pool (hence involves locking) and is released to the local one and makes it grow until it's required to trigger a flush using pool_evict_from_cache(). Buffers usage are thus not thread-local at all, and cause eviction of a lot of possibly useful objects from the local caches. Just fixing this results in a 10% request rate increase in an HTTP/1 test on a 16-thread machine. This bug was caused by recent commit ed891fd ("MEDIUM: memory: make local pools independent on lockless pools") merged into 2.2-dev9, so not backport is needed. --- include/haproxy/dynbuf.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/haproxy/dynbuf.h b/include/haproxy/dynbuf.h index 79e64453e..2a7aa4768 100644 --- a/include/haproxy/dynbuf.h +++ b/include/haproxy/dynbuf.h @@ -143,6 +143,9 @@ static inline struct buffer *b_alloc_margin(struct buffer *buf, int margin) cached = 0; #ifdef CONFIG_HAP_LOCAL_POOLS + if (likely(area = __pool_get_from_cache(pool_head_buffer))) + goto done; + idx = pool_get_index(pool_head_buffer); if (idx >= 0) cached = pool_cache[tid][idx].count;