2014-05-03 22:57:43 +00:00
|
|
|
#pragma once
|
|
|
|
|
2016-07-31 03:53:16 +00:00
|
|
|
#include <atomic>
|
2020-03-19 10:38:34 +00:00
|
|
|
#include <common/types.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Common/CurrentMetrics.h>
|
2018-05-31 15:54:08 +00:00
|
|
|
#include <Common/SimpleActionBlocker.h>
|
2018-06-20 17:49:52 +00:00
|
|
|
#include <Common/VariableContext.h>
|
2016-12-20 02:29:35 +00:00
|
|
|
|
|
|
|
|
2016-12-23 20:23:46 +00:00
|
|
|
/** Tracks memory consumption.
|
|
|
|
* It throws an exception if amount of consumed memory become greater than certain limit.
|
|
|
|
* The same memory tracker could be simultaneously used in different threads.
|
2014-05-03 22:57:43 +00:00
|
|
|
*/
|
|
|
|
class MemoryTracker
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
std::atomic<Int64> amount {0};
|
|
|
|
std::atomic<Int64> peak {0};
|
2020-01-21 13:53:30 +00:00
|
|
|
std::atomic<Int64> hard_limit {0};
|
2020-01-22 15:20:19 +00:00
|
|
|
std::atomic<Int64> profiler_limit {0};
|
2020-01-21 13:53:30 +00:00
|
|
|
|
2020-01-22 15:20:19 +00:00
|
|
|
Int64 profiler_step = 0;
|
2014-05-03 22:57:43 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
/// To test exception safety of calling code, memory tracker throws an exception on each memory allocation with specified probability.
|
|
|
|
double fault_probability = 0;
|
2015-12-23 07:39:28 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
/// Singly-linked list. All information will be passed to subsequent memory trackers also (it allows to implement trackers hierarchy).
|
|
|
|
/// In terms of tree nodes it is the list of parents. Lifetime of these trackers should "include" lifetime of current tracker.
|
2018-02-01 17:55:08 +00:00
|
|
|
std::atomic<MemoryTracker *> parent {};
|
2015-12-30 15:39:11 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
/// You could specify custom metric to track memory usage.
|
2018-10-08 05:30:03 +00:00
|
|
|
CurrentMetrics::Metric metric = CurrentMetrics::end();
|
2016-12-20 02:29:35 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
/// This description will be used as prefix into log messages (if isn't nullptr)
|
|
|
|
const char * description = nullptr;
|
2015-12-30 15:39:11 +00:00
|
|
|
|
2014-05-03 22:57:43 +00:00
|
|
|
public:
|
2019-08-03 11:02:40 +00:00
|
|
|
MemoryTracker(VariableContext level_ = VariableContext::Thread) : level(level_) {}
|
|
|
|
MemoryTracker(MemoryTracker * parent_, VariableContext level_ = VariableContext::Thread) : parent(parent_), level(level_) {}
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
~MemoryTracker();
|
|
|
|
|
2018-06-09 15:29:08 +00:00
|
|
|
VariableContext level;
|
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
/** Call the following functions before calling of corresponding operations with memory allocators.
|
|
|
|
*/
|
|
|
|
void alloc(Int64 size);
|
|
|
|
|
|
|
|
void realloc(Int64 old_size, Int64 new_size)
|
|
|
|
{
|
2019-07-10 18:12:50 +00:00
|
|
|
Int64 addition = new_size - old_size;
|
|
|
|
if (addition > 0)
|
|
|
|
alloc(addition);
|
|
|
|
else
|
|
|
|
free(-addition);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/** This function should be called after memory deallocation.
|
|
|
|
*/
|
|
|
|
void free(Int64 size);
|
|
|
|
|
|
|
|
Int64 get() const
|
|
|
|
{
|
|
|
|
return amount.load(std::memory_order_relaxed);
|
|
|
|
}
|
|
|
|
|
|
|
|
Int64 getPeak() const
|
|
|
|
{
|
|
|
|
return peak.load(std::memory_order_relaxed);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Set limit if it was not set.
|
|
|
|
* Otherwise, set limit to new value, if new value is greater than previous limit.
|
|
|
|
*/
|
2020-01-21 13:53:30 +00:00
|
|
|
void setOrRaiseHardLimit(Int64 value);
|
2020-01-22 15:20:19 +00:00
|
|
|
void setOrRaiseProfilerLimit(Int64 value);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
void setFaultProbability(double value)
|
|
|
|
{
|
|
|
|
fault_probability = value;
|
|
|
|
}
|
|
|
|
|
2020-01-22 15:20:19 +00:00
|
|
|
void setProfilerStep(Int64 value)
|
2020-01-21 13:53:30 +00:00
|
|
|
{
|
2020-01-22 15:20:19 +00:00
|
|
|
profiler_step = value;
|
2020-01-21 13:53:30 +00:00
|
|
|
}
|
|
|
|
|
2017-09-09 04:06:54 +00:00
|
|
|
/// next should be changed only once: from nullptr to some value.
|
2018-02-01 17:55:08 +00:00
|
|
|
/// NOTE: It is not true in MergeListElement
|
|
|
|
void setParent(MemoryTracker * elem)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2018-02-01 17:55:08 +00:00
|
|
|
parent.store(elem, std::memory_order_relaxed);
|
|
|
|
}
|
|
|
|
|
|
|
|
MemoryTracker * getParent()
|
|
|
|
{
|
|
|
|
return parent.load(std::memory_order_relaxed);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// The memory consumption could be shown in realtime via CurrentMetrics counter
|
|
|
|
void setMetric(CurrentMetrics::Metric metric_)
|
|
|
|
{
|
|
|
|
metric = metric_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setDescription(const char * description_)
|
|
|
|
{
|
|
|
|
description = description_;
|
|
|
|
}
|
|
|
|
|
2018-06-09 15:29:08 +00:00
|
|
|
/// Reset the accumulated data
|
|
|
|
void resetCounters();
|
|
|
|
|
|
|
|
/// Reset the accumulated data and the parent.
|
2017-04-01 07:20:54 +00:00
|
|
|
void reset();
|
|
|
|
|
|
|
|
/// Prints info about peak memory consumption into log.
|
|
|
|
void logPeakMemoryUsage() const;
|
2014-05-03 22:57:43 +00:00
|
|
|
|
2018-02-01 17:55:08 +00:00
|
|
|
/// To be able to temporarily stop memory tracker
|
2018-05-31 15:54:08 +00:00
|
|
|
DB::SimpleActionBlocker blocker;
|
2018-02-01 17:55:08 +00:00
|
|
|
};
|
2014-05-03 22:57:43 +00:00
|
|
|
|
2016-10-25 14:22:10 +00:00
|
|
|
|
2018-02-01 17:55:08 +00:00
|
|
|
/// Convenience methods, that use current thread's memory_tracker if it is available.
|
2017-04-10 21:40:38 +00:00
|
|
|
namespace CurrentMemoryTracker
|
|
|
|
{
|
|
|
|
void alloc(Int64 size);
|
|
|
|
void realloc(Int64 old_size, Int64 new_size);
|
|
|
|
void free(Int64 size);
|
|
|
|
}
|
|
|
|
|
2016-10-25 14:22:10 +00:00
|
|
|
|
2020-03-15 00:22:06 +00:00
|
|
|
/// Holding this object will temporarily disable memory tracking.
|
2018-05-31 15:54:08 +00:00
|
|
|
DB::SimpleActionLock getCurrentMemoryTrackerActionLock();
|