diff --git a/src/yb/tserver/tablet_server.cc b/src/yb/tserver/tablet_server.cc index 6a7e978b1734..9d62d3d1591a 100644 --- a/src/yb/tserver/tablet_server.cc +++ b/src/yb/tserver/tablet_server.cc @@ -487,6 +487,8 @@ Status TabletServer::Init() { RETURN_NOT_OK(DbServerBase::Init()); + MemTracker::InitializeGcMetrics(metric_entity()); + RETURN_NOT_OK(path_handlers_->Register(web_server_.get())); log_prefix_ = Format("P $0: ", permanent_uuid()); diff --git a/src/yb/util/mem_tracker.cc b/src/yb/util/mem_tracker.cc index 95f900532481..b4edfe1a4efa 100644 --- a/src/yb/util/mem_tracker.cc +++ b/src/yb/util/mem_tracker.cc @@ -119,6 +119,20 @@ DEFINE_RUNTIME_int64(mem_tracker_tcmalloc_gc_release_bytes, -1, DECLARE_int64(server_tcmalloc_max_total_thread_cache_bytes); +METRIC_DEFINE_counter(server, mem_tracker_gc_tcmalloc_calls, + "MemTracker GC TCMalloc Calls", + yb::MetricUnit::kOperations, + "Number of times MemTracker::GcTcmallocIfNeeded() has been called"); + +METRIC_DEFINE_histogram(server, mem_tracker_gc_tcmalloc_bytes_per_gc, + "MemTracker GC TCMalloc Bytes Per GC", + yb::MetricUnit::kBytes, + "Histogram of bytes released per garbage collection event in " + "MemTracker::GcTcmallocIfNeeded(). Only records when GC actually occurs. " + "Concurrent allocations during GC may cause negative apparent releases " + "which are not recorded.", + 60000000LU /* 60MB as max value */, 2 /* 2 digits precision */); + namespace yb { // NOTE: this class has been adapted from Impala, so the code style varies @@ -739,6 +753,10 @@ bool MemTracker::GcMemory(int64_t max_consumption) { void MemTracker::GcTcmallocIfNeeded() { #ifdef YB_TCMALLOC_ENABLED + if (gc_tcmalloc_calls_metric_) { + gc_tcmalloc_calls_metric_->Increment(); + } + released_memory_since_gc = 0; TRACE_EVENT0("process", "MemTracker::GcTcmallocIfNeeded"); @@ -748,7 +766,9 @@ void MemTracker::GcTcmallocIfNeeded() { // Bytes allocated by the application. int64_t bytes_used = GetTCMallocCurrentAllocatedBytes(); + int64_t initial_overhead = bytes_overhead; int64_t max_overhead = bytes_used * FLAGS_tcmalloc_max_free_bytes_percentage / 100.0; + if (bytes_overhead > max_overhead) { int64_t extra = bytes_overhead - max_overhead; while (extra > 0) { @@ -762,6 +782,15 @@ void MemTracker::GcTcmallocIfNeeded() { #endif // YB_GOOGLE_TCMALLOC extra -= 1024 * 1024; } + + int64_t final_overhead = GetTCMallocPageHeapFreeBytes(); + // bytes_released could theoretically be negative if memory increased during GC + // due to concurrent allocations. The > 0 check prevents recording negative values + // in the metrics, which could skew the statistics. + int64_t bytes_released = initial_overhead - final_overhead; + if (gc_tcmalloc_bytes_per_gc_metric_ && bytes_released > 0) { + gc_tcmalloc_bytes_per_gc_metric_->Increment(bytes_released); + } } #endif // YB_TCMALLOC_ENABLED } @@ -848,6 +877,15 @@ void MemTracker::TEST_SetReleasedMemorySinceGC(int64_t value) { released_memory_since_gc = value; } +scoped_refptr MemTracker::gc_tcmalloc_calls_metric_; +scoped_refptr MemTracker::gc_tcmalloc_bytes_per_gc_metric_; + +void MemTracker::InitializeGcMetrics(const scoped_refptr& metric_entity) { + gc_tcmalloc_calls_metric_ = METRIC_mem_tracker_gc_tcmalloc_calls.Instantiate(metric_entity); + gc_tcmalloc_bytes_per_gc_metric_ = + METRIC_mem_tracker_gc_tcmalloc_bytes_per_gc.Instantiate(metric_entity); +} + scoped_refptr MemTracker::metric_entity() const { return metrics_ ? metrics_->metric_entity_ : nullptr; } diff --git a/src/yb/util/mem_tracker.h b/src/yb/util/mem_tracker.h index 24f5dbb7fd5f..10544e741d51 100644 --- a/src/yb/util/mem_tracker.h +++ b/src/yb/util/mem_tracker.h @@ -55,6 +55,8 @@ namespace yb { class MemTracker; class MetricEntity; +class Counter; +class Histogram; using MemTrackerPtr = std::shared_ptr; static const std::string kTCMallocTrackerNamePrefix = "TCMalloc "; @@ -430,11 +432,16 @@ class MemTracker : public std::enable_shared_from_this { // This is needed in some tests to create deterministic GC behavior. static void TEST_SetReleasedMemorySinceGC(int64_t bytes); + static void InitializeGcMetrics(const scoped_refptr& metric_entity); + bool IsRoot() { return is_root_tracker_; } private: + static scoped_refptr gc_tcmalloc_calls_metric_; + static scoped_refptr gc_tcmalloc_bytes_per_gc_metric_; + template using GarbageCollectorsContainer = boost::container::small_vector; diff --git a/src/yb/yql/pggate/pggate.cc b/src/yb/yql/pggate/pggate.cc index 5a6325c52854..55b5919d4623 100644 --- a/src/yb/yql/pggate/pggate.cc +++ b/src/yb/yql/pggate/pggate.cc @@ -674,6 +674,8 @@ PgApiImpl::PgApiImpl( ybctid_reader_provider_(pg_session_), fk_reference_cache_(ybctid_reader_provider_, buffering_settings_, tablespace_map_), explicit_row_lock_buffer_(ybctid_reader_provider_, tablespace_map_) { + MemTracker::InitializeGcMetrics(metric_entity_); + PgBackendSetupSharedMemory(); // This is an RCU object, but there are no concurrent updates on PG side, only on tserver, so // it's safe to just save the pointer.