blob: bdb083f0eccbb1bef2eec2f8ed4020655008ad30 [file] [log] [blame]
// 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