| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| #ifndef IMPALA_UTIL_MEM_METRICS_H |
| #define IMPALA_UTIL_MEM_METRICS_H |
| |
| #include "util/metrics.h" |
| |
| #include <boost/bind.hpp> |
| #include <boost/thread/mutex.hpp> |
| #include <gperftools/malloc_extension.h> |
| #if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) |
| #include <sanitizer/allocator_interface.h> |
| #endif |
| |
| #include "gen-cpp/Frontend_types.h" |
| #include "util/debug-util.h" |
| |
| namespace impala { |
| |
| class BufferPool; |
| class MemTracker; |
| class ReservationTracker; |
| class Thread; |
| |
| /// Each names one of the fields in TJvmMemoryPool. |
| enum JvmMemoryMetricType { |
| MAX, |
| INIT, |
| COMMITTED, |
| CURRENT, |
| PEAK_MAX, |
| PEAK_INIT, |
| PEAK_COMMITTED, |
| PEAK_CURRENT |
| }; |
| |
| /// Memory metrics including TCMalloc and BufferPool memory. |
| class AggregateMemoryMetrics { |
| public: |
| /// The sum of Tcmalloc TOTAL_BYTES_RESERVED and BufferPool SYSTEM_ALLOCATED. |
| /// Approximates the total amount of physical memory consumed by the backend (i.e. not |
| /// including JVM memory), which is either in use by queries or cached by the BufferPool |
| /// or the malloc implementation. |
| /// TODO: IMPALA-691 - consider changing this to include JVM memory. |
| static SumGauge* TOTAL_USED; |
| |
| /// The total number of virtual memory regions for the process. |
| /// The value must be refreshed by calling Refresh(). |
| static IntGauge* NUM_MAPS; |
| |
| /// The total size of virtual memory regions for the process. |
| /// The value must be refreshed by calling Refresh(). |
| static IntGauge* MAPPED_BYTES; |
| |
| /// The total RSS of all virtual memory regions for the process. |
| /// The value must be refreshed by calling Refresh(). |
| static IntGauge* RSS; |
| |
| /// The total RSS of all virtual memory regions for the process. |
| /// The value must be refreshed by calling Refresh(). |
| static IntGauge* ANON_HUGE_PAGE_BYTES; |
| |
| /// The string reporting the /enabled setting for transparent huge pages. |
| /// The value must be refreshed by calling Refresh(). |
| static StringProperty* THP_ENABLED; |
| |
| /// The string reporting the /defrag setting for transparent huge pages. |
| /// The value must be refreshed by calling Refresh(). |
| static StringProperty* THP_DEFRAG; |
| |
| /// The string reporting the khugepaged/defrag setting for transparent huge pages. |
| /// The value must be refreshed by calling Refresh(). |
| static StringProperty* THP_KHUGEPAGED_DEFRAG; |
| |
| /// Refreshes values of any of the aggregate metrics that require refreshing. |
| static void Refresh(); |
| }; |
| |
| /// Specialised metric which exposes numeric properties from tcmalloc. |
| class TcmallocMetric : public IntGauge { |
| public: |
| /// Number of bytes allocated by tcmalloc, currently used by the application. |
| static TcmallocMetric* BYTES_IN_USE; |
| |
| /// Number of bytes of system memory reserved by tcmalloc, including that in use by the |
| /// application. Does not include what tcmalloc accounts for as 'malloc metadata' in |
| /// /memz. That is, this is memory reserved by tcmalloc that the application can use. |
| /// Includes unmapped virtual memory. |
| static TcmallocMetric* TOTAL_BYTES_RESERVED; |
| |
| /// Number of bytes reserved and still mapped by tcmalloc that are not allocated to the |
| /// application. |
| static TcmallocMetric* PAGEHEAP_FREE_BYTES; |
| |
| /// Number of bytes once reserved by tcmalloc, but released back to the operating system |
| /// so that their use incurs a pagefault. Contributes to the total amount of virtual |
| /// address space used, but not to the physical memory usage. |
| static TcmallocMetric* PAGEHEAP_UNMAPPED_BYTES; |
| |
| /// Derived metric computing the amount of physical memory (in bytes) used by the |
| /// process, including that actually in use and free bytes reserved by tcmalloc. Does not |
| /// include the tcmalloc metadata. |
| class PhysicalBytesMetric : public IntGauge { |
| public: |
| PhysicalBytesMetric(const TMetricDef& def) : IntGauge(def, 0) { } |
| |
| virtual int64_t GetValue() override { |
| return TOTAL_BYTES_RESERVED->GetValue() - PAGEHEAP_UNMAPPED_BYTES->GetValue(); |
| } |
| }; |
| |
| static PhysicalBytesMetric* PHYSICAL_BYTES_RESERVED; |
| |
| static TcmallocMetric* CreateAndRegister(MetricGroup* metrics, const std::string& key, |
| const std::string& tcmalloc_var); |
| |
| virtual int64_t GetValue() override { |
| int64_t retval = 0; |
| #if !defined(ADDRESS_SANITIZER) && !defined(THREAD_SANITIZER) |
| MallocExtension::instance()->GetNumericProperty(tcmalloc_var_.c_str(), |
| reinterpret_cast<size_t*>(&retval)); |
| #endif |
| return retval; |
| } |
| |
| private: |
| /// Name of the tcmalloc property this metric should fetch. |
| const std::string tcmalloc_var_; |
| |
| TcmallocMetric(const TMetricDef& def, const std::string& tcmalloc_var) |
| : IntGauge(def, 0), tcmalloc_var_(tcmalloc_var) { } |
| }; |
| |
| /// Alternative to TCMallocMetric if we're running under a sanitizer that replaces |
| /// malloc(), e.g. address or thread sanitizer. |
| class SanitizerMallocMetric : public IntGauge { |
| public: |
| SanitizerMallocMetric(const TMetricDef& def) : IntGauge(def, 0) {} |
| |
| static SanitizerMallocMetric* BYTES_ALLOCATED; |
| |
| virtual int64_t GetValue() override { |
| #if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) |
| return __sanitizer_get_current_allocated_bytes(); |
| #else |
| return 0; |
| #endif |
| |
| } |
| }; |
| |
| // A singleton for caching the gathering of JVM Metrics for 1 second, to amortize |
| // the cost of getting all the JVM metrics. |
| // |
| // Clients should get the singleton via GetInstance() and call the |
| // Get* methods. Internally, the Get* methods are synchronized with |
| // lock_. |
| class JvmMetricCache { |
| public: |
| /// Retrieves a metric for a given pool. |
| long GetPoolMetric(const std::string& mempool_name, JvmMemoryMetricType type); |
| /// Retrieves a single counter metric from the response. |
| long GetCounterMetric(int64_t(*accessor)(const TGetJvmMemoryMetricsResponse&)); |
| /// Returns all pool names. |
| vector<string> GetPoolNames(); |
| /// Returns singleton instance. |
| static JvmMetricCache* GetInstance(); |
| |
| private: |
| /// Updates metrics if over CACHE_PERIOD_MILLIS has elapsed. |
| void GrabMetricsIfNecessary(); |
| |
| boost::mutex lock_; |
| /// Time when metrics were last fetched, using MonotonicMillis(). |
| /// Protected by lock_. |
| int64_t last_fetch_ = 0; |
| /// Last available metrics. |
| /// Protected by lock_. |
| TGetJvmMemoryMetricsResponse last_response_; |
| |
| static const int64_t CACHE_PERIOD_MILLIS = 1000; |
| JvmMetricCache() { } |
| DISALLOW_COPY_AND_ASSIGN(JvmMetricCache); |
| }; |
| |
| /// A JvmMemoryMetric corresponds to one value drawn from one 'memory pool' in the JVM. A |
| /// memory pool is an area of memory assigned for one particular aspect of memory |
| /// management. For example Hotspot has pools for the permanent generation, the old |
| /// generation, survivor space, code cache and permanently tenured objects. |
| class JvmMemoryMetric : public IntGauge { |
| public: |
| /// Adds a "jvm" child group to 'parent' and registers many Jvm memory metrics: one |
| /// for every member of JvmMemoryMetricType for each pool (usually ~5 pools plus a |
| /// synthetic 'total' pool). |
| /// Idempotent but not thread-safe - can be safely called multiple times from the same |
| /// thread. |
| static void InitMetrics(MetricGroup* parent); |
| |
| /// Searches through jvm_metrics_response_ for a matching memory pool and pulls out the |
| /// right value from that structure according to metric_type_. |
| virtual int64_t GetValue() override; |
| |
| // Expose the total memory metrics that may be counted against process memory limit. |
| // Initialised by InitMetrics(). |
| |
| // The jvm.heap.max-usage-bytes metric. |
| static JvmMemoryMetric* HEAP_MAX_USAGE; |
| |
| // The jvm.non-heap.committed-usage-bytes metric. |
| static JvmMemoryMetric* NON_HEAP_COMMITTED; |
| |
| private: |
| static JvmMemoryMetric* CreateAndRegister(MetricGroup* metrics, const std::string& key, |
| const std::string& pool_name, JvmMemoryMetricType type); |
| |
| /// Private constructor to ensure only InitMetrics() can create JvmMemoryMetrics. |
| JvmMemoryMetric( |
| const TMetricDef& def, const std::string& mempool_name, JvmMemoryMetricType type); |
| |
| /// The name of the memory pool, defined by the Jvm. |
| std::string mempool_name_; |
| |
| /// Each metric corresponds to one value; this tells us which value from the memory pool |
| /// that is. |
| JvmMemoryMetricType metric_type_; |
| |
| /// Set the first time that InitMetrics() is called. |
| static bool initialized_; |
| }; |
| |
| // A counter that represents metrics about JVM Memory. It acesses the underlying |
| // data via JniUtil::GetJvmMemoryMetrics() via JvmMetricCache. |
| class JvmMemoryCounterMetric : public IntCounter { |
| virtual int64_t GetValue() override; |
| |
| private: |
| friend class JvmMemoryMetric; |
| static JvmMemoryCounterMetric* CreateAndRegister(MetricGroup* metrics, |
| const string& key, |
| int64_t(*accessor)(const TGetJvmMemoryMetricsResponse&)); |
| /// Private constructor; used via CreateAndRegister |
| JvmMemoryCounterMetric(const TMetricDef& def, |
| int64_t(*accessor)(const TGetJvmMemoryMetricsResponse&)); |
| |
| int64_t(*accessor_)(const TGetJvmMemoryMetricsResponse&); |
| }; |
| |
| /// Metric that reports information about the buffer pool. |
| class BufferPoolMetric : public IntGauge { |
| public: |
| static Status InitMetrics(MetricGroup* metrics, ReservationTracker* global_reservations, |
| BufferPool* buffer_pool) WARN_UNUSED_RESULT; |
| |
| /// Global metrics, initialized by InitMetrics(). |
| static BufferPoolMetric* LIMIT; |
| static BufferPoolMetric* SYSTEM_ALLOCATED; |
| static BufferPoolMetric* RESERVED; |
| static BufferPoolMetric* UNUSED_RESERVATION_BYTES; |
| static BufferPoolMetric* NUM_FREE_BUFFERS; |
| static BufferPoolMetric* FREE_BUFFER_BYTES; |
| static BufferPoolMetric* CLEAN_PAGES_LIMIT; |
| static BufferPoolMetric* NUM_CLEAN_PAGES; |
| static BufferPoolMetric* CLEAN_PAGE_BYTES; |
| |
| virtual int64_t GetValue() override; |
| |
| private: |
| friend class ReservationTrackerTest; |
| |
| enum class BufferPoolMetricType { |
| LIMIT, // Limit on memory allocated to buffers. |
| // Total amount of buffer memory allocated from the system. Always <= LIMIT. |
| SYSTEM_ALLOCATED, |
| // Total of all buffer reservations. May be < SYSTEM_ALLOCATED if not all reservations |
| // are fulfilled, or > SYSTEM_ALLOCATED because of additional memory cached by |
| // BufferPool. Always <= LIMIT. |
| RESERVED, |
| // Total bytes of reservations that have not been used to allocate buffers from the |
| // pool. |
| UNUSED_RESERVATION_BYTES, |
| NUM_FREE_BUFFERS, // Total number of free buffers in BufferPool. |
| FREE_BUFFER_BYTES, // Total bytes of free buffers in BufferPool. |
| CLEAN_PAGES_LIMIT, // Limit on number of clean pages in BufferPool. |
| NUM_CLEAN_PAGES, // Total number of clean pages in BufferPool. |
| CLEAN_PAGE_BYTES, // Total bytes of clean pages in BufferPool. |
| }; |
| |
| BufferPoolMetric(const TMetricDef& def, BufferPoolMetricType type, |
| ReservationTracker* global_reservations, BufferPool* buffer_pool); |
| |
| BufferPoolMetricType type_; |
| ReservationTracker* global_reservations_; |
| BufferPool* buffer_pool_; |
| }; |
| |
| /// Metric that reports information about a MemTracker. |
| class MemTrackerMetric : public IntGauge { |
| public: |
| // Creates two new metrics tracking the current and peak usages of 'mem_tracker' in |
| // the metrics group 'metrics'. The caller must make sure that 'mem_tracker' is not |
| // destructed before 'metrics'. |
| static void CreateMetrics(MetricGroup* metrics, MemTracker* mem_tracker, |
| const std::string& name); |
| |
| virtual int64_t GetValue() override; |
| |
| private: |
| enum class MemTrackerMetricType { |
| CURRENT, // Current usage of the MemTracker |
| PEAK, // Peak usage of the MemTracker |
| }; |
| |
| MemTrackerMetric(const TMetricDef& def, MemTrackerMetricType type, |
| MemTracker* mem_tracker); |
| |
| const MemTrackerMetricType type_; |
| const MemTracker* mem_tracker_; |
| }; |
| |
| /// Registers common tcmalloc memory metrics. If 'register_jvm_metrics' is true, the JVM |
| /// memory metrics are also registered. If 'global_reservations' and 'buffer_pool' are |
| /// not NULL, also register buffer pool metrics. |
| Status RegisterMemoryMetrics(MetricGroup* metrics, bool register_jvm_metrics, |
| ReservationTracker* global_reservations, BufferPool* buffer_pool); |
| } |
| |
| #endif |