This is an automated email from the ASF dual-hosted git repository.
cmcfarlen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new 17ab9a9764 Add metrics to memory Allocators (#11413)
17ab9a9764 is described below
commit 17ab9a9764671927c6346f1764eedcdf6d9f6bce
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]>
---
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 b9d24c5f26..b4f2e19523 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -123,6 +123,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)
@@ -330,6 +331,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);