2014-05-03 22:57:43 +00:00
|
|
|
|
#pragma once
|
|
|
|
|
|
2016-07-31 03:53:16 +00:00
|
|
|
|
#include <atomic>
|
2015-09-29 19:19:54 +00:00
|
|
|
|
#include <common/Common.h>
|
2016-12-20 02:29:35 +00:00
|
|
|
|
#include <DB/Common/CurrentMetrics.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace CurrentMetrics
|
|
|
|
|
{
|
|
|
|
|
extern const Metric MemoryTracking;
|
|
|
|
|
}
|
2014-05-03 22:57:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Отслеживает потребление памяти.
|
|
|
|
|
* Кидает исключение, если оно стало бы больше некоторого предельного значения.
|
|
|
|
|
* Один объект может использоваться одновременно в разных потоках.
|
|
|
|
|
*/
|
|
|
|
|
class MemoryTracker
|
|
|
|
|
{
|
2016-07-31 03:53:16 +00:00
|
|
|
|
std::atomic<Int64> amount {0};
|
|
|
|
|
std::atomic<Int64> peak {0};
|
|
|
|
|
Int64 limit {0};
|
2014-05-03 22:57:43 +00:00
|
|
|
|
|
2015-12-23 07:39:28 +00:00
|
|
|
|
/// В целях тестирования exception safety - кидать исключение при каждом выделении памяти с указанной вероятностью.
|
|
|
|
|
double fault_probability = 0;
|
|
|
|
|
|
2016-01-13 03:59:24 +00:00
|
|
|
|
/// Односвязный список. Вся информация будет передаваться в следующие MemoryTracker-ы тоже. Они должны жить во время жизни данного MemoryTracker.
|
2015-12-30 15:39:11 +00:00
|
|
|
|
MemoryTracker * next = nullptr;
|
|
|
|
|
|
2016-12-20 02:29:35 +00:00
|
|
|
|
/// You could specify custom metric to track memory usage.
|
|
|
|
|
CurrentMetrics::Metric metric = CurrentMetrics::MemoryTracking;
|
|
|
|
|
|
2015-12-30 15:39:11 +00:00
|
|
|
|
/// Если задано (например, "for user") - в сообщениях в логе будет указываться это описание.
|
|
|
|
|
const char * description = nullptr;
|
|
|
|
|
|
2014-05-03 22:57:43 +00:00
|
|
|
|
public:
|
2016-01-13 02:38:30 +00:00
|
|
|
|
MemoryTracker() {}
|
2014-05-08 15:54:51 +00:00
|
|
|
|
MemoryTracker(Int64 limit_) : limit(limit_) {}
|
2014-05-03 22:57:43 +00:00
|
|
|
|
|
|
|
|
|
~MemoryTracker();
|
|
|
|
|
|
|
|
|
|
/** Вызывайте эти функции перед соответствующими операциями с памятью.
|
|
|
|
|
*/
|
2014-05-08 15:54:51 +00:00
|
|
|
|
void alloc(Int64 size);
|
2014-05-03 22:57:43 +00:00
|
|
|
|
|
2014-05-08 15:54:51 +00:00
|
|
|
|
void realloc(Int64 old_size, Int64 new_size)
|
2014-05-03 22:57:43 +00:00
|
|
|
|
{
|
|
|
|
|
alloc(new_size - old_size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** А эту функцию имеет смысл вызывать после освобождения памяти.
|
|
|
|
|
*/
|
2015-12-30 15:39:11 +00:00
|
|
|
|
void free(Int64 size);
|
2014-05-03 22:57:43 +00:00
|
|
|
|
|
2014-05-08 15:54:51 +00:00
|
|
|
|
Int64 get() const
|
2014-05-03 22:57:43 +00:00
|
|
|
|
{
|
2016-07-31 03:53:16 +00:00
|
|
|
|
return amount.load(std::memory_order_relaxed);
|
2014-05-03 22:57:43 +00:00
|
|
|
|
}
|
2015-07-01 05:31:27 +00:00
|
|
|
|
|
|
|
|
|
Int64 getPeak() const
|
|
|
|
|
{
|
2016-07-31 03:53:16 +00:00
|
|
|
|
return peak.load(std::memory_order_relaxed);
|
2015-07-01 05:31:27 +00:00
|
|
|
|
}
|
2015-12-23 07:39:28 +00:00
|
|
|
|
|
2016-01-13 02:38:30 +00:00
|
|
|
|
void setLimit(Int64 limit_)
|
|
|
|
|
{
|
|
|
|
|
limit = limit_;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-23 07:39:28 +00:00
|
|
|
|
void setFaultProbability(double value)
|
|
|
|
|
{
|
|
|
|
|
fault_probability = value;
|
|
|
|
|
}
|
2015-12-30 15:39:11 +00:00
|
|
|
|
|
2016-01-13 03:59:24 +00:00
|
|
|
|
void setNext(MemoryTracker * elem)
|
2015-12-30 15:39:11 +00:00
|
|
|
|
{
|
2016-01-13 03:59:24 +00:00
|
|
|
|
next = elem;
|
2015-12-30 15:39:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-12-20 02:29:35 +00:00
|
|
|
|
void setMetric(CurrentMetrics::Metric metric_)
|
|
|
|
|
{
|
|
|
|
|
metric = metric_;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-30 15:39:11 +00:00
|
|
|
|
void setDescription(const char * description_)
|
|
|
|
|
{
|
|
|
|
|
description = description_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Обнулить накопленные данные.
|
|
|
|
|
void reset();
|
|
|
|
|
|
|
|
|
|
/// Вывести в лог информацию о пиковом потреблении памяти.
|
|
|
|
|
void logPeakMemoryUsage() const;
|
2014-05-03 22:57:43 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Объект MemoryTracker довольно трудно протащить во все места, где выделяются существенные объёмы памяти.
|
|
|
|
|
* Поэтому, используется thread-local указатель на используемый MemoryTracker или nullptr, если его не нужно использовать.
|
|
|
|
|
* Этот указатель выставляется, когда в данном потоке следует отслеживать потребление памяти.
|
|
|
|
|
* Таким образом, его нужно всего-лишь протащить во все потоки, в которых обрабатывается один запрос.
|
|
|
|
|
*/
|
|
|
|
|
extern __thread MemoryTracker * current_memory_tracker;
|
2016-10-25 14:22:10 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <boost/noncopyable.hpp>
|
|
|
|
|
|
|
|
|
|
struct TemporarilyDisableMemoryTracker : private boost::noncopyable
|
|
|
|
|
{
|
|
|
|
|
MemoryTracker * memory_tracker;
|
|
|
|
|
|
|
|
|
|
TemporarilyDisableMemoryTracker()
|
|
|
|
|
{
|
|
|
|
|
memory_tracker = current_memory_tracker;
|
|
|
|
|
current_memory_tracker = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~TemporarilyDisableMemoryTracker()
|
|
|
|
|
{
|
|
|
|
|
current_memory_tracker = memory_tracker;
|
|
|
|
|
}
|
|
|
|
|
};
|