From: Eduard Bagdasaryan Date: Fri, 13 Jul 2018 21:27:19 +0000 (+0000) Subject: Optimization: Fewer memory (re)allocations for HTTP headers (#239) X-Git-Tag: M-staged-PR239 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c3b51d64909335642672ca01dc6da9526187d36d;p=thirdparty%2Fsquid.git Optimization: Fewer memory (re)allocations for HTTP headers (#239) Tests revealed multiple fresh memory allocations/deallocations while storing small (few fields) HTTP headers. Many popular sites use larger headers (15-30 fields). To avoid expensive memory operations: 1. Pool all std::vector memory allocations. 2. Prevent reallocations (for HTTP headers with fewer than 32 fields). This optimization deals with storing the header index. It does not affect how individual header fields are stored. --- diff --git a/src/HttpHeader.cc b/src/HttpHeader.cc index a264c7c37f..185399fafc 100644 --- a/src/HttpHeader.cc +++ b/src/HttpHeader.cc @@ -145,6 +145,7 @@ httpHeaderInitModule(void) HttpHeader::HttpHeader() : owner (hoNone), len (0), conflictingContentLength_(false) { + entries.reserve(32); httpHeaderMaskInit(&mask, 0); } @@ -152,11 +153,13 @@ HttpHeader::HttpHeader(const http_hdr_owner_type anOwner): owner(anOwner), len(0 { assert(anOwner > hoNone && anOwner < hoEnd); debugs(55, 7, "init-ing hdr: " << this << " owner: " << owner); + entries.reserve(32); httpHeaderMaskInit(&mask, 0); } HttpHeader::HttpHeader(const HttpHeader &other): owner(other.owner), len(other.len), conflictingContentLength_(false) { + entries.reserve(other.entries.capacity()); httpHeaderMaskInit(&mask, 0); update(&other); // will update the mask as well } diff --git a/src/HttpHeader.h b/src/HttpHeader.h index 64b0651c5f..cc21d3e0c1 100644 --- a/src/HttpHeader.h +++ b/src/HttpHeader.h @@ -14,7 +14,7 @@ #include "http/RegisteredHeaders.h" /* because we pass a spec by value */ #include "HttpHeaderMask.h" -#include "mem/forward.h" +#include "mem/PoolingAllocator.h" #include "sbuf/forward.h" #include "SquidString.h" @@ -153,7 +153,7 @@ public: inline bool chunked() const; ///< whether message uses chunked Transfer-Encoding /* protected, do not use these, use interface functions instead */ - std::vector entries; /**< parsed fields in raw format */ + std::vector > entries; /**< parsed fields in raw format */ HttpHeaderMask mask; /**< bit set <=> entry present */ http_hdr_owner_type owner; /**< request or reply */ int len; /**< length when packed, not counting terminating null-byte */ diff --git a/src/mem/Makefile.am b/src/mem/Makefile.am index f940cf8fcd..4b4f7057b7 100644 --- a/src/mem/Makefile.am +++ b/src/mem/Makefile.am @@ -14,11 +14,12 @@ libmem_la_SOURCES = \ AllocatorProxy.cc \ AllocatorProxy.h \ forward.h \ - old_api.cc \ Meter.h \ + old_api.cc \ Pool.cc \ Pool.h \ PoolChunked.cc \ PoolChunked.h \ + PoolingAllocator.h \ PoolMalloc.cc \ PoolMalloc.h diff --git a/src/mem/PoolingAllocator.h b/src/mem/PoolingAllocator.h new file mode 100644 index 0000000000..c6ec0045e2 --- /dev/null +++ b/src/mem/PoolingAllocator.h @@ -0,0 +1,42 @@ +/* ++ * Copyright (C) 1996-2018 The Squid Software Foundation and contributors ++ * ++ * Squid software is distributed under GPLv2+ license and includes ++ * contributions from numerous individuals and organizations. ++ * Please see the COPYING and CONTRIBUTORS files for details. ++ */ + +#ifndef SQUID_MEM_POOLINGALLOCATOR_H +#define SQUID_MEM_POOLINGALLOCATOR_H + +#include "mem/forward.h" + +/// STL Allocator that uses Squid memory pools for memory management +template +class PoolingAllocator +{ +public: + /* STL Allocator API */ + using value_type = Value; + PoolingAllocator() noexcept {} + template PoolingAllocator(const PoolingAllocator &) noexcept {} + value_type *allocate(std::size_t n) { return static_cast(memAllocRigid(n*sizeof(value_type))); } + void deallocate(value_type *vp, std::size_t n) noexcept { memFreeRigid(vp, n*sizeof(value_type)); } +}; + +template +inline bool +operator ==(const PoolingAllocator&, const PoolingAllocator&) noexcept +{ + return true; +} + +template +inline bool +operator !=(const PoolingAllocator &l, const PoolingAllocator &r) noexcept +{ + return !(l == r); +} + +#endif /* SQUID_MEM_POOLINGALLOCATOR_H */ + diff --git a/src/mem/forward.h b/src/mem/forward.h index e1bd8fcd4f..96c14a4a66 100644 --- a/src/mem/forward.h +++ b/src/mem/forward.h @@ -59,11 +59,13 @@ void memConfigure(void); void *memAllocate(mem_type); void *memAllocString(size_t net_size, size_t * gross_size); void *memAllocBuf(size_t net_size, size_t * gross_size); +void *memAllocRigid(size_t net_size); void *memReallocBuf(void *buf, size_t net_size, size_t * gross_size); /// Free a element allocated by memAllocate() void memFree(void *, int type); void memFreeString(size_t size, void *); void memFreeBuf(size_t size, void *); +void memFreeRigid(void *, size_t net_size); FREE *memFreeBufFunc(size_t size); int memInUse(mem_type); void memDataInit(mem_type, const char *, size_t, int, bool doZero = true); diff --git a/src/mem/old_api.cc b/src/mem/old_api.cc index 5a260d6d9c..e360aa6e03 100644 --- a/src/mem/old_api.cc +++ b/src/mem/old_api.cc @@ -245,6 +245,22 @@ memAllocString(size_t net_size, size_t * gross_size) return xcalloc(1, net_size); } +void * +memAllocRigid(size_t net_size) +{ + // TODO: Use memAllocString() instead (after it stops zeroing memory). + + if (const auto pool = memFindStringPool(net_size, true)) { + ++StrCountMeter; + StrVolumeMeter += pool->objectSize(); + return pool->alloc(); + } + + ++StrCountMeter; + StrVolumeMeter += net_size; + return xmalloc(net_size); +} + size_t memStringCount() { @@ -271,6 +287,23 @@ memFreeString(size_t size, void *buf) StrVolumeMeter -= size; } +void +memFreeRigid(void *buf, size_t net_size) +{ + // TODO: Use memFreeString() instead (after removing fuzzy=false pool search). + + if (const auto pool = memFindStringPool(net_size, true)) { + pool->freeOne(buf); + StrVolumeMeter -= pool->objectSize(); + --StrCountMeter; + return; + } + + xfree(buf); + StrVolumeMeter -= net_size; + --StrCountMeter; +} + /* Find the best fit MEM_X_BUF type */ static mem_type memFindBufSizeType(size_t net_size, size_t * gross_size) diff --git a/src/tests/stub_libmem.cc b/src/tests/stub_libmem.cc index 474a4ae1d8..ac0b6186cf 100644 --- a/src/tests/stub_libmem.cc +++ b/src/tests/stub_libmem.cc @@ -40,6 +40,11 @@ void * memAllocate(mem_type) void *memAllocString(size_t net_size, size_t * gross_size) {return memAllocBuf(net_size, gross_size);} +void *memAllocRigid(size_t net_size) +{ + return xmalloc(net_size); +} + void * memAllocBuf(size_t net_size, size_t * gross_size) { @@ -62,6 +67,7 @@ memReallocBuf(void *oldbuf, size_t net_size, size_t * gross_size) void memFree(void *p, int) {xfree(p);} void memFreeString(size_t, void *buf) {xfree(buf);} +void memFreeRigid(void *buf, size_t) {xfree(buf);} void memFreeBuf(size_t, void *buf) {xfree(buf);} static void cxx_xfree(void * ptr) {xfree(ptr);} FREE *memFreeBufFunc(size_t) {return cxx_xfree;}