This is an automated email from the ASF dual-hosted git repository. cmcfarlen pushed a commit to branch 10.0.x in repository https://gitbox.apache.org/repos/asf/trafficserver.git
commit 8e3cc5c9c1ecd76c5d23ab01ce969dd8dd38578d Author: Chris McFarlen <[email protected]> AuthorDate: Mon Jun 10 10:09:16 2024 -0500 Add metrics to memory Allocators (#11413) * Add metrics to memory Allocators * Add build option to enable allocator metrics --------- Co-authored-by: Chris McFarlen <[email protected]> (cherry picked from commit 17ab9a9764671927c6346f1764eedcdf6d9f6bce) --- CMakeLists.txt | 2 + include/iocore/eventsystem/IOBuffer.h | 4 ++ include/tscore/Allocator.h | 90 +++++++++++++++++++++++++++++++++-- include/tscore/ink_config.h.cmake.in | 1 + include/tsutil/Metrics.h | 18 +++++++ src/iocore/eventsystem/IOBuffer.cc | 7 ++- 6 files changed, 117 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0916dab4bf..5433cf6978 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -122,6 +122,7 @@ set(DEFAULT_STACK_SIZE ) option(ENABLE_FAST_SDK "Use fast SDK APIs (default OFF)") option(ENABLE_MALLOC_ALLOCATOR "Use direct malloc allocator over freelist allocator (default OFF)") +option(ENABLE_ALLOCATOR_METRICS "Enable metrics for Allocators (default OFF)") option(ENABLE_DOCS "Build docs (default OFF)") option(ENABLE_DISK_FAILURE_TESTS "Build disk failure tests (enables AIO fault injection, default OFF)" OFF) if(ENABLE_DISK_FAILURE_TESTS) @@ -329,6 +330,7 @@ if(ENABLE_PROBES) endif() set(TS_USE_MALLOC_ALLOCATOR ${ENABLE_MALLOC_ALLOCATOR}) +set(TS_USE_ALLOCATOR_METRICS ${ENABLE_ALLOCATOR_METRICS}) find_package(ZLIB REQUIRED) # ncurses is used in traffic_top diff --git a/include/iocore/eventsystem/IOBuffer.h b/include/iocore/eventsystem/IOBuffer.h index 3487b2a880..c0d38d325d 100644 --- a/include/iocore/eventsystem/IOBuffer.h +++ b/include/iocore/eventsystem/IOBuffer.h @@ -110,7 +110,11 @@ enum AllocType { #define BUFFER_SIZE_FOR_CONSTANT(_size) (_size - DEFAULT_BUFFER_SIZES) #define BUFFER_SIZE_INDEX_FOR_CONSTANT_SIZE(_size) (_size + DEFAULT_BUFFER_SIZES) +#if TS_USE_ALLOCATOR_METRICS +extern MeteredAllocator<FreelistAllocator> ioBufAllocator[DEFAULT_BUFFER_SIZES]; +#else extern FreelistAllocator ioBufAllocator[DEFAULT_BUFFER_SIZES]; +#endif void init_buffer_allocators(int iobuffer_advice, int chunk_sizes[DEFAULT_BUFFER_SIZES], bool use_hugepages); void init_buffer_allocators(int iobuffer_advice); diff --git a/include/tscore/Allocator.h b/include/tscore/Allocator.h index d1a6cbdb2b..785dbae28a 100644 --- a/include/tscore/Allocator.h +++ b/include/tscore/Allocator.h @@ -39,12 +39,11 @@ #pragma once -#include <new> #include <cstdlib> #include <utility> #include "tscore/ink_queue.h" -#include "tscore/ink_defs.h" #include "tscore/ink_resource.h" +#include "tsutil/Metrics.h" #include <execinfo.h> #define RND16(_x) (((_x) + 15) & ~15) @@ -156,7 +155,7 @@ public: void free_void(void *ptr) { - free(ptr); + ::free(ptr); } /** @@ -221,11 +220,94 @@ private: int advice; }; +#if TS_USE_ALLOCATOR_METRICS +template <typename WrappedAllocator> class MeteredAllocator : public WrappedAllocator +{ +public: + void * + alloc_void() + { + inuse_metric->increment(1); + alloc_metric->increment(1); + return WrappedAllocator::alloc_void(); + } + + void + free_void(void *ptr) + { + inuse_metric->decrement(1); + free_metric->increment(1); + WrappedAllocator::free_void(ptr); + } + + void + free_void_bulk(void *head, void *tail, size_t num_item) + { + inuse_metric->decrement(num_item); + free_metric->increment(num_item); + WrappedAllocator::free_void_bulk(head, tail, num_item); + } + + MeteredAllocator() {} + + MeteredAllocator(const char *name, unsigned int element_size, unsigned int chunk_size = 128, unsigned int alignment = 8, + bool use_hugepages = false) + : WrappedAllocator(name, element_size, chunk_size, alignment, use_hugepages), + inuse_metric{ts::Metrics::Gauge::createPtr("proxy.process.allocator.inuse.", name)}, + alloc_metric{ts::Metrics::Counter::createPtr("proxy.process.allocator.alloc.", name)}, + free_metric{ts::Metrics::Counter::createPtr("proxy.process.allocator.free.", name)}, + size_metric{ts::Metrics::Gauge::createPtr("proxy.process.allocator.size.", name)} + { + size_metric->store(element_size); + } + + void + re_init(const char *name, unsigned int element_size, unsigned int chunk_size, unsigned int alignment, bool use_hugepages, + int advice) + { + if (inuse_metric == nullptr) { + inuse_metric = ts::Metrics::Gauge::createPtr("proxy.process.allocator.inuse.", name); + alloc_metric = ts::Metrics::Counter::createPtr("proxy.process.allocator.alloc.", name); + free_metric = ts::Metrics::Counter::createPtr("proxy.process.allocator.free.", name); + size_metric = ts::Metrics::Gauge::createPtr("proxy.process.allocator.size.", name); + } + size_metric->store(element_size); + + WrappedAllocator::re_init(name, element_size, chunk_size, alignment, use_hugepages, advice); + } + + void + destroy_if_enabled(void *p) + { + WrappedAllocator::destroy_if_enabled(p); + } + + // for metered allocator we don't want to return superclass or we'll skip metrics (see THREAD_FREE macro) + MeteredAllocator<WrappedAllocator> & + raw() + { + return *this; + } + +private: + ts::Metrics::AtomicType *inuse_metric = nullptr; + ts::Metrics::AtomicType *alloc_metric = nullptr; + ts::Metrics::AtomicType *free_metric = nullptr; + ts::Metrics::AtomicType *size_metric = nullptr; +}; + +#if TS_USE_MALLOC_ALLOCATOR +using Allocator = MeteredAllocator<MallocAllocator>; +#else +using Allocator = MeteredAllocator<FreelistAllocator>; +#endif +#else #if TS_USE_MALLOC_ALLOCATOR using Allocator = MallocAllocator; #else using Allocator = FreelistAllocator; #endif +#endif // TS_USE_ALLOCATOR_METRICS /** Allocator for Class objects. @@ -273,7 +355,7 @@ public: { } - Allocator & + BaseAllocator & raw() { return *this; diff --git a/include/tscore/ink_config.h.cmake.in b/include/tscore/ink_config.h.cmake.in index 554d19d630..c9ac033886 100644 --- a/include/tscore/ink_config.h.cmake.in +++ b/include/tscore/ink_config.h.cmake.in @@ -149,6 +149,7 @@ const int DEFAULT_STACKSIZE = @DEFAULT_STACK_SIZE@; #cmakedefine01 TS_USE_KQUEUE #cmakedefine01 TS_USE_LINUX_IO_URING #cmakedefine01 TS_USE_MALLOC_ALLOCATOR +#cmakedefine01 TS_USE_ALLOCATOR_METRICS #cmakedefine01 TS_USE_POSIX_CAP #cmakedefine01 TS_USE_QUIC #cmakedefine01 TS_USE_REMOTE_UNWINDING diff --git a/include/tsutil/Metrics.h b/include/tsutil/Metrics.h index 80da30fd71..cc309a5b60 100644 --- a/include/tsutil/Metrics.h +++ b/include/tsutil/Metrics.h @@ -395,6 +395,15 @@ public: return reinterpret_cast<AtomicType *>(instance.lookup(instance._create(name))); } + static AtomicType * + createPtr(const std::string_view prefix, const std::string_view name) + { + auto &instance = Metrics::instance(); + std::string tmpname = std::string(prefix) + std::string(name); + + return reinterpret_cast<AtomicType *>(instance.lookup(instance._create(tmpname))); + } + static Metrics::Gauge::SpanType createSpan(size_t size, IdType *id = nullptr) { @@ -483,6 +492,15 @@ public: return reinterpret_cast<AtomicType *>(instance.lookup(instance._create(name))); } + static AtomicType * + createPtr(const std::string_view prefix, const std::string_view name) + { + auto &instance = Metrics::instance(); + std::string tmpname = std::string(prefix) + std::string(name); + + return reinterpret_cast<AtomicType *>(instance.lookup(instance._create(tmpname))); + } + static Metrics::Counter::SpanType createSpan(size_t size, IdType *id = nullptr) { diff --git a/src/iocore/eventsystem/IOBuffer.cc b/src/iocore/eventsystem/IOBuffer.cc index fb82b40776..66decc4bac 100644 --- a/src/iocore/eventsystem/IOBuffer.cc +++ b/src/iocore/eventsystem/IOBuffer.cc @@ -25,6 +25,7 @@ UIOBuffer.cc **************************************************************************/ +#include "tscore/Allocator.h" #include "tscore/ink_defs.h" #include "P_EventSystem.h" #include "swoc/Lexicon.h" @@ -34,7 +35,11 @@ // // General Buffer Allocator // -FreelistAllocator ioBufAllocator[DEFAULT_BUFFER_SIZES]; +#if TS_USE_ALLOCATOR_METRICS +MeteredAllocator<FreelistAllocator> ioBufAllocator[DEFAULT_BUFFER_SIZES]; +#else +FreelistAllocator ioBufAllocator[DEFAULT_BUFFER_SIZES]; +#endif ClassAllocator<MIOBuffer> ioAllocator("ioAllocator", DEFAULT_BUFFER_NUMBER); ClassAllocator<IOBufferData> ioDataAllocator("ioDataAllocator", DEFAULT_BUFFER_NUMBER); ClassAllocator<IOBufferBlock> ioBlockAllocator("ioBlockAllocator", DEFAULT_BUFFER_NUMBER);
