mkql_mem_info.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. #include "mkql_mem_info.h"
  2. #include <util/generic/yexception.h>
  3. namespace NKikimr {
  4. namespace NMiniKQL {
  5. TMemoryUsageInfo::TMemoryUsageInfo(const TStringBuf& title)
  6. : Title_(title)
  7. , Allocated_(0)
  8. , Freed_(0)
  9. , Peak_(0)
  10. , AllowMissing_(false)
  11. , CheckOnExit_(true)
  12. {
  13. }
  14. TMemoryUsageInfo::~TMemoryUsageInfo() {
  15. if (CheckOnExit_ && !UncaughtException()) {
  16. VerifyDebug();
  17. }
  18. }
  19. void TMemoryUsageInfo::AllowMissing() {
  20. AllowMissing_ = true;
  21. }
  22. void TMemoryUsageInfo::CheckOnExit(bool check) {
  23. CheckOnExit_ = check;
  24. }
  25. #ifndef NDEBUG
  26. void TMemoryUsageInfo::Take(const void* mem, ui64 size, TMkqlLocation location) {
  27. Allocated_ += size;
  28. Peak_ = Max(Peak_, Allocated_ - Freed_);
  29. if (size == 0) {
  30. return;
  31. }
  32. if (AllowMissing_) {
  33. auto it = AllocationsMap_.find(mem);
  34. if (it != AllocationsMap_.end() && it->second.IsDeleted) {
  35. AllocationsMap_.erase(it);
  36. }
  37. }
  38. auto res = AllocationsMap_.insert({mem, { size, std::move(location), false }});
  39. Y_DEBUG_ABORT_UNLESS(res.second, "Duplicate allocation at: %p, "
  40. "already allocated at: %s", mem, (TStringBuilder() << res.first->second.Location).c_str());
  41. //Clog << Title_ << " take: " << size << " -> " << mem << " " << AllocationsMap_.size() << Endl;
  42. }
  43. #endif
  44. #ifndef NDEBUG
  45. void TMemoryUsageInfo::Return(const void* mem, ui64 size) {
  46. Freed_ += size;
  47. if (size == 0) {
  48. return;
  49. }
  50. //Clog << Title_ << " free: " << size << " -> " << mem << " " << AllocationsMap_.size() << Endl;
  51. auto it = AllocationsMap_.find(mem);
  52. if (AllowMissing_ && it == AllocationsMap_.end()) {
  53. return;
  54. }
  55. if (AllowMissing_) {
  56. Y_DEBUG_ABORT_UNLESS(!it->second.IsDeleted, "Double free at: %p", mem);
  57. } else {
  58. Y_DEBUG_ABORT_UNLESS(it != AllocationsMap_.end(), "Double free at: %p", mem);
  59. }
  60. Y_DEBUG_ABORT_UNLESS(size == it->second.Size,
  61. "Deallocating wrong size at: %p, "
  62. "allocated at: %s", mem, (TStringBuilder() << it->second.Location).c_str());
  63. if (AllowMissing_) {
  64. it->second.IsDeleted = true;
  65. } else {
  66. AllocationsMap_.erase(it);
  67. }
  68. }
  69. #endif
  70. #ifndef NDEBUG
  71. void TMemoryUsageInfo::Return(const void* mem) {
  72. //Clog << Title_ << " free: " << size << " -> " << mem << " " << AllocationsMap_.size() << Endl;
  73. auto it = AllocationsMap_.find(mem);
  74. if (AllowMissing_ && it == AllocationsMap_.end()) {
  75. return;
  76. }
  77. if (AllowMissing_) {
  78. Y_DEBUG_ABORT_UNLESS(!it->second.IsDeleted, "Double free at: %p", mem);
  79. } else {
  80. Y_DEBUG_ABORT_UNLESS(it != AllocationsMap_.end(), "Double free at: %p", mem);
  81. }
  82. Freed_ += it->second.Size;
  83. if (AllowMissing_) {
  84. it->second.IsDeleted = true;
  85. } else {
  86. AllocationsMap_.erase(it);
  87. }
  88. }
  89. #endif
  90. i64 TMemoryUsageInfo::GetUsage() const {
  91. return static_cast<i64>(Allocated_) - static_cast<i64>(Freed_);
  92. }
  93. ui64 TMemoryUsageInfo::GetAllocated() const { return Allocated_; }
  94. ui64 TMemoryUsageInfo::GetFreed() const { return Freed_; }
  95. ui64 TMemoryUsageInfo::GetPeak() const { return Peak_; }
  96. void TMemoryUsageInfo::PrintTo(IOutputStream& out) const {
  97. out << Title_ << TStringBuf(": usage=") << GetUsage()
  98. << TStringBuf(" (allocated=") << GetAllocated()
  99. << TStringBuf(", freed=") << GetFreed()
  100. << TStringBuf(", peak=") << GetPeak()
  101. << ')';
  102. }
  103. void TMemoryUsageInfo::VerifyDebug() const {
  104. #ifndef NDEBUG
  105. size_t leakCount = 0;
  106. for (const auto& it: AllocationsMap_) {
  107. if (it.second.IsDeleted) {
  108. continue;
  109. }
  110. ++leakCount;
  111. Cerr << TStringBuf("Not freed ")
  112. << it.first << TStringBuf(" size: ") << it.second.Size
  113. << TStringBuf(", location: ") << it.second.Location
  114. << Endl;
  115. }
  116. if (!AllowMissing_) {
  117. Y_DEBUG_ABORT_UNLESS(GetUsage() == 0,
  118. "Allocated: %ld, Freed: %ld, Peak: %ld",
  119. GetAllocated(), GetFreed(), GetPeak());
  120. }
  121. Y_DEBUG_ABORT_UNLESS(!leakCount, "Has no freed memory");
  122. #endif
  123. }
  124. }
  125. }