LCOV - code coverage report
Current view: top level - core - memory_manager.cpp (source / functions) Coverage Total Hit
Test: hashbrowns Coverage Lines: 86.7 % 83 72
Test Date: 2026-04-10 19:00:18 Functions: 100.0 % 5 5
Legend: Lines: hit not hit

            Line data    Source code
       1              : #include "memory_manager.h"
       2              : 
       3              : #include <algorithm>
       4              : #include <iomanip>
       5              : #include <iostream>
       6              : 
       7              : namespace hashbrowns {
       8              : 
       9          777 : MemoryTracker& MemoryTracker::instance() {
      10          777 :     static MemoryTracker instance;
      11          777 :     return instance;
      12              : }
      13              : 
      14          309 : void MemoryTracker::record_allocation(void* ptr, size_t size, const char* file, int line) {
      15          309 :     if (!ptr)
      16            0 :         return;
      17              : 
      18          309 :     std::lock_guard<std::mutex> lock(mutex_);
      19              : 
      20              :     // Update statistics
      21          309 :     stats_.total_allocated += size;
      22          309 :     stats_.current_usage += size;
      23          309 :     stats_.allocation_count += 1;
      24              : 
      25              :     // Update peak usage
      26          309 :     if (stats_.current_usage > stats_.peak_usage) {
      27          219 :         stats_.peak_usage = stats_.current_usage;
      28              :     }
      29              : 
      30              :     // Always record ptr->size mapping so deallocation can reverse the stats.
      31              :     // Verbose logging is gated on detailed_tracking_.
      32          309 :     allocations_[ptr] = size;
      33              : 
      34          309 :     if (detailed_tracking_ && file && line > 0) {
      35            0 :         std::cout << "[ALLOC] " << size << " bytes at " << ptr << " (" << file << ":" << line << ")\n";
      36              :     }
      37          309 : }
      38              : 
      39          309 : void MemoryTracker::record_deallocation(void* ptr) {
      40          309 :     if (!ptr)
      41            0 :         return;
      42              : 
      43          309 :     std::lock_guard<std::mutex> lock(mutex_);
      44              : 
      45          309 :     size_t size = 0;
      46              : 
      47              :     // Always look up the size so stats stay correct regardless of tracking mode.
      48          309 :     auto it = allocations_.find(ptr);
      49          309 :     if (it != allocations_.end()) {
      50          284 :         size = it->second;
      51          284 :         allocations_.erase(it);
      52          284 :         if (detailed_tracking_) {
      53           82 :             std::cout << "[DEALLOC] " << size << " bytes at " << ptr << "\n";
      54              :         }
      55              :     } else {
      56           25 :         if (detailed_tracking_) {
      57            0 :             std::cout << "[DEALLOC] Unknown allocation at " << ptr << "\n";
      58              :         }
      59           25 :         stats_.deallocation_count += 1; // Still count the deallocation
      60           25 :         return;
      61              :     }
      62              : 
      63              :     // Update statistics
      64          284 :     if (size > 0) {
      65          284 :         stats_.total_deallocated += size;
      66          284 :         stats_.current_usage -= size;
      67              :     }
      68          284 :     stats_.deallocation_count += 1;
      69          309 : }
      70              : 
      71           41 : void MemoryTracker::reset() {
      72           41 :     std::lock_guard<std::mutex> lock(mutex_);
      73              : 
      74           41 :     stats_.total_allocated    = 0;
      75           41 :     stats_.total_deallocated  = 0;
      76           41 :     stats_.current_usage      = 0;
      77           41 :     stats_.peak_usage         = 0;
      78           41 :     stats_.allocation_count   = 0;
      79           41 :     stats_.deallocation_count = 0;
      80              : 
      81           41 :     allocations_.clear();
      82           82 : }
      83              : 
      84            2 : bool MemoryTracker::check_leaks() const {
      85            2 :     std::lock_guard<std::mutex> lock(mutex_);
      86              : 
      87            2 :     Stats current_stats = stats_;
      88              : 
      89            2 :     std::cout << "\n=== Memory Leak Report ===\n";
      90            2 :     std::cout << std::fixed << std::setprecision(2);
      91              : 
      92              :     // Summary statistics
      93            2 :     std::cout << "Total allocated:     " << current_stats.total_allocated << " bytes\n";
      94            2 :     std::cout << "Total deallocated:   " << current_stats.total_deallocated << " bytes\n";
      95            2 :     std::cout << "Current usage:       " << current_stats.current_usage << " bytes\n";
      96            2 :     std::cout << "Peak usage:          " << current_stats.peak_usage << " bytes\n";
      97            2 :     std::cout << "Allocation count:    " << current_stats.allocation_count << "\n";
      98            2 :     std::cout << "Deallocation count:  " << current_stats.deallocation_count << "\n";
      99              : 
     100              :     // Memory efficiency metrics
     101            2 :     if (current_stats.peak_usage > 0) {
     102            2 :         double efficiency = static_cast<double>(current_stats.total_allocated) / current_stats.peak_usage;
     103            2 :         std::cout << "Memory efficiency:   " << efficiency << "x (allocated/peak)\n";
     104              :     }
     105              : 
     106              :     // Leak detection
     107            2 :     size_t leaked_bytes       = current_stats.memory_leaked();
     108            2 :     size_t outstanding_allocs = current_stats.outstanding_allocations();
     109              : 
     110            2 :     std::cout << "\n--- Leak Analysis ---\n";
     111            2 :     std::cout << "Leaked bytes:        " << leaked_bytes << "\n";
     112            2 :     std::cout << "Outstanding allocs:  " << outstanding_allocs << "\n";
     113              : 
     114            2 :     bool has_leaks = false;
     115              : 
     116            2 :     if (detailed_tracking_ && !allocations_.empty()) {
     117            0 :         has_leaks = true;
     118            0 :         std::cout << "\n--- Unfreed Allocations ---\n";
     119              : 
     120            0 :         size_t total_unfreed = 0;
     121            0 :         for (const auto& [ptr, size] : allocations_) {
     122            0 :             std::cout << "  " << ptr << ": " << size << " bytes\n";
     123            0 :             total_unfreed += size;
     124              :         }
     125            0 :         std::cout << "Total unfreed: " << total_unfreed << " bytes\n";
     126            2 :     } else if (leaked_bytes > 0 || outstanding_allocs > 0) {
     127            1 :         has_leaks = true;
     128            1 :         std::cout << "WARNING: Potential memory leaks detected!\n";
     129            1 :         std::cout << "Enable detailed tracking for more information.\n";
     130              :     }
     131              : 
     132            2 :     if (!has_leaks) {
     133            1 :         std::cout << "✓ No memory leaks detected!\n";
     134              :     }
     135              : 
     136            2 :     std::cout << "=========================\n\n";
     137              : 
     138            2 :     return !has_leaks;
     139            2 : }
     140              : 
     141              : } // namespace hashbrowns
        

Generated by: LCOV version 2.0-1