LCOV - code coverage report
Current view: top level - wirestead/memory - memory_tracker.cc (source / functions) Coverage Total Hit
Test: Wirestead Coverage Report Lines: 96.6 % 147 142
Test Date: 2026-08-30 10:35:09 Functions: 100.0 % 18 18
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 75.0 % 32 24

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * Copyright 2025 Jinwoo Sung
       3                 :             :  *
       4                 :             :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :             :  * you may not use this file except in compliance with the License.
       6                 :             :  * You may obtain a copy of the License at
       7                 :             :  *
       8                 :             :  *     http://www.apache.org/licenses/LICENSE-2.0
       9                 :             :  *
      10                 :             :  * Unless required by applicable law or agreed to in writing, software
      11                 :             :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :             :  * See the License for the specific language governing permissions and
      14                 :             :  * limitations under the License.
      15                 :             :  */
      16                 :             : 
      17                 :             : #include "wirestead/memory/memory_tracker.hpp"
      18                 :             : 
      19                 :             : #include <iomanip>
      20                 :             : #include <iostream>
      21                 :             : #include <sstream>
      22                 :             : 
      23                 :             : #include "wirestead/diagnostics/logger.hpp"
      24                 :             : 
      25                 :             : namespace wirestead {
      26                 :             : namespace memory {
      27                 :             : 
      28                 :          31 : MemoryTracker& MemoryTracker::instance() {
      29                 :          31 :   static MemoryTracker instance;
      30                 :          31 :   return instance;
      31                 :             : }
      32                 :             : 
      33                 :           7 : void MemoryTracker::track_allocation(void* ptr, size_t size, const char* file, int line, const char* function) {
      34         [ +  + ]:           7 :   if (!tracking_enabled_.load()) {
      35                 :           1 :     return;
      36                 :             :   }
      37                 :             : 
      38                 :           6 :   std::lock_guard<std::mutex> lock(allocations_mutex_);
      39                 :             : 
      40                 :           6 :   AllocationInfo info;
      41                 :           6 :   info.ptr = ptr;
      42                 :           6 :   info.size = size;
      43         [ +  + ]:           6 :   info.file = file ? file : "unknown";
      44                 :           6 :   info.line = line;
      45         [ +  + ]:           6 :   info.function = function ? function : "unknown";
      46                 :           6 :   info.timestamp = std::chrono::steady_clock::now();
      47                 :             : 
      48                 :           6 :   allocations_[ptr] = info;
      49                 :             : 
      50                 :             :   // Update statistics
      51                 :           6 :   stats_.total_allocations++;
      52                 :           6 :   stats_.current_allocations++;
      53                 :           6 :   stats_.total_bytes_allocated += size;
      54                 :           6 :   stats_.current_bytes_allocated += size;
      55                 :             : 
      56                 :             :   // Update peak values
      57         [ +  - ]:           6 :   if (stats_.current_allocations > stats_.peak_allocations) {
      58                 :           6 :     stats_.peak_allocations = stats_.current_allocations;
      59                 :             :   }
      60         [ +  - ]:           6 :   if (stats_.current_bytes_allocated > stats_.peak_bytes_allocated) {
      61                 :           6 :     stats_.peak_bytes_allocated = stats_.current_bytes_allocated;
      62                 :             :   }
      63                 :           6 : }
      64                 :             : 
      65                 :           2 : void MemoryTracker::track_deallocation(void* ptr) {
      66         [ -  + ]:           2 :   if (!tracking_enabled_.load()) {
      67                 :           0 :     return;
      68                 :             :   }
      69                 :             : 
      70                 :           2 :   std::lock_guard<std::mutex> lock(allocations_mutex_);
      71                 :             : 
      72                 :           2 :   auto it = allocations_.find(ptr);
      73         [ +  - ]:           2 :   if (it != allocations_.end()) {
      74                 :           2 :     size_t size = it->second.size;
      75                 :           2 :     allocations_.erase(it);
      76                 :             : 
      77                 :             :     // Update statistics
      78                 :           2 :     stats_.total_deallocations++;
      79                 :           2 :     stats_.current_allocations--;
      80                 :           2 :     stats_.total_bytes_deallocated += size;
      81                 :           2 :     stats_.current_bytes_allocated -= size;
      82                 :             :   }
      83                 :           2 : }
      84                 :             : 
      85                 :           8 : MemoryTracker::MemoryStats MemoryTracker::stats() const {
      86                 :           8 :   std::lock_guard<std::mutex> lock(allocations_mutex_);
      87                 :           8 :   return stats_;
      88                 :           8 : }
      89                 :             : 
      90                 :           5 : std::vector<MemoryTracker::AllocationInfo> MemoryTracker::current_allocations() const {
      91                 :           5 :   std::lock_guard<std::mutex> lock(allocations_mutex_);
      92                 :             : 
      93                 :           5 :   std::vector<AllocationInfo> result;
      94                 :           5 :   result.reserve(allocations_.size());
      95                 :             : 
      96         [ +  + ]:          10 :   for (const auto& pair : allocations_) {
      97                 :           5 :     result.push_back(pair.second);
      98                 :             :   }
      99                 :             : 
     100                 :          10 :   return result;
     101                 :           5 : }
     102                 :             : 
     103                 :           3 : std::vector<MemoryTracker::AllocationInfo> MemoryTracker::leaked_allocations() const {
     104                 :           3 :   return current_allocations();  // Current allocations are potential leaks
     105                 :             : }
     106                 :             : 
     107                 :           9 : void MemoryTracker::enable_tracking(bool enable) { tracking_enabled_.store(enable); }
     108                 :             : 
     109                 :           1 : void MemoryTracker::disable_tracking() { tracking_enabled_.store(false); }
     110                 :             : 
     111                 :           1 : bool MemoryTracker::tracking_enabled() const { return tracking_enabled_.load(); }
     112                 :             : 
     113                 :          16 : void MemoryTracker::clear_tracking_data() {
     114                 :          16 :   std::lock_guard<std::mutex> lock(allocations_mutex_);
     115                 :          16 :   allocations_.clear();
     116                 :             : 
     117                 :             :   // Reset statistics
     118                 :          16 :   stats_.total_allocations = 0;
     119                 :          16 :   stats_.total_deallocations = 0;
     120                 :          16 :   stats_.current_allocations = 0;
     121                 :          16 :   stats_.peak_allocations = 0;
     122                 :          16 :   stats_.total_bytes_allocated = 0;
     123                 :          16 :   stats_.total_bytes_deallocated = 0;
     124                 :          16 :   stats_.current_bytes_allocated = 0;
     125                 :          16 :   stats_.peak_bytes_allocated = 0;
     126                 :          16 : }
     127                 :             : 
     128                 :           1 : void MemoryTracker::print_memory_report() const {
     129                 :           1 :   auto mem_stats = stats();
     130                 :           1 :   auto allocs = current_allocations();
     131                 :             : 
     132                 :           1 :   std::cout << "\n=== Memory Tracker Report ===" << std::endl;
     133                 :           1 :   std::cout << "Total allocations: " << mem_stats.total_allocations << std::endl;
     134                 :           1 :   std::cout << "Total deallocations: " << mem_stats.total_deallocations << std::endl;
     135                 :           1 :   std::cout << "Current allocations: " << mem_stats.current_allocations << std::endl;
     136                 :           1 :   std::cout << "Peak allocations: " << mem_stats.peak_allocations << std::endl;
     137                 :           1 :   std::cout << "Total bytes allocated: " << mem_stats.total_bytes_allocated << std::endl;
     138                 :           1 :   std::cout << "Total bytes deallocated: " << mem_stats.total_bytes_deallocated << std::endl;
     139                 :           1 :   std::cout << "Current bytes allocated: " << mem_stats.current_bytes_allocated << std::endl;
     140                 :           1 :   std::cout << "Peak bytes allocated: " << mem_stats.peak_bytes_allocated << std::endl;
     141                 :           1 :   std::cout << "Current active allocations: " << allocs.size() << std::endl;
     142                 :             : 
     143         [ +  - ]:           1 :   if (!allocs.empty()) {
     144                 :           1 :     std::cout << "\n=== Current Allocations ===" << std::endl;
     145         [ +  + ]:           2 :     for (const auto& alloc : allocs) {
     146                 :           1 :       std::cout << "Ptr: " << alloc.ptr << ", Size: " << alloc.size << ", File: " << alloc.file << ":" << alloc.line
     147                 :           1 :                 << ", Function: " << alloc.function << std::endl;
     148                 :             :     }
     149                 :             :   }
     150                 :           1 : }
     151                 :             : 
     152                 :           1 : void MemoryTracker::print_leak_report() const {
     153                 :           1 :   auto leaks = leaked_allocations();
     154                 :             : 
     155         [ -  + ]:           1 :   if (leaks.empty()) {
     156                 :           0 :     std::cout << "\n=== No Memory Leaks Detected ===" << std::endl;
     157                 :           0 :     return;
     158                 :             :   }
     159                 :             : 
     160                 :           1 :   std::cout << "\n=== Memory Leak Report ===" << std::endl;
     161                 :           1 :   std::cout << "Found " << leaks.size() << " potential memory leaks:" << std::endl;
     162                 :             : 
     163                 :           1 :   size_t total_leaked_bytes = 0;
     164         [ +  + ]:           2 :   for (const auto& alloc : leaks) {
     165                 :           1 :     std::cout << "Leaked: " << alloc.size << " bytes at " << alloc.ptr << " allocated in " << alloc.file << ":"
     166                 :           1 :               << alloc.line << " (" << alloc.function << ")" << std::endl;
     167                 :           1 :     total_leaked_bytes += alloc.size;
     168                 :             :   }
     169                 :             : 
     170                 :           1 :   std::cout << "Total leaked bytes: " << total_leaked_bytes << std::endl;
     171                 :           1 : }
     172                 :             : 
     173                 :           1 : void MemoryTracker::log_memory_report() const {
     174                 :           1 :   auto mem_stats = stats();
     175                 :           1 :   auto allocs = current_allocations();
     176                 :             : 
     177                 :           1 :   std::ostringstream oss;
     178                 :           1 :   oss << "\n=== Memory Tracker Report ===\n";
     179                 :           1 :   oss << "Total allocations: " << mem_stats.total_allocations << "\n";
     180                 :           1 :   oss << "Total deallocations: " << mem_stats.total_deallocations << "\n";
     181                 :           1 :   oss << "Current allocations: " << mem_stats.current_allocations << "\n";
     182                 :           1 :   oss << "Peak allocations: " << mem_stats.peak_allocations << "\n";
     183                 :           1 :   oss << "Total bytes allocated: " << mem_stats.total_bytes_allocated << "\n";
     184                 :           1 :   oss << "Total bytes deallocated: " << mem_stats.total_bytes_deallocated << "\n";
     185                 :           1 :   oss << "Current bytes allocated: " << mem_stats.current_bytes_allocated << "\n";
     186                 :           1 :   oss << "Peak bytes allocated: " << mem_stats.peak_bytes_allocated << "\n";
     187                 :           1 :   oss << "Current active allocations: " << allocs.size();
     188                 :             : 
     189                 :           1 :   WIRESTEAD_LOG_INFO("memory_tracker", "report", oss.str());
     190                 :             : 
     191         [ +  - ]:           1 :   if (!allocs.empty()) {
     192                 :           1 :     std::ostringstream alloc_oss;
     193                 :           1 :     alloc_oss << "\n=== Current Allocations ===\n";
     194         [ +  + ]:           2 :     for (const auto& alloc : allocs) {
     195                 :           1 :       alloc_oss << "Ptr: " << alloc.ptr << ", Size: " << alloc.size << ", File: " << alloc.file << ":" << alloc.line
     196                 :           1 :                 << ", Function: " << alloc.function << "\n";
     197                 :             :     }
     198                 :           1 :     WIRESTEAD_LOG_INFO("memory_tracker", "allocations", alloc_oss.str());
     199                 :           1 :   }
     200                 :           1 : }
     201                 :             : 
     202                 :           1 : void MemoryTracker::log_leak_report() const {
     203                 :           1 :   auto leaks = leaked_allocations();
     204                 :             : 
     205         [ -  + ]:           1 :   if (leaks.empty()) {
     206                 :           0 :     WIRESTEAD_LOG_INFO("memory_tracker", "leak_check", "No Memory Leaks Detected");
     207                 :           0 :     return;
     208                 :             :   }
     209                 :             : 
     210                 :           1 :   std::ostringstream oss;
     211                 :           1 :   oss << "\n=== Memory Leak Report ===\n";
     212                 :           1 :   oss << "Found " << leaks.size() << " potential memory leaks:\n";
     213                 :             : 
     214                 :           1 :   size_t total_leaked_bytes = 0;
     215         [ +  + ]:           2 :   for (const auto& alloc : leaks) {
     216                 :           1 :     oss << "Leaked: " << alloc.size << " bytes at " << alloc.ptr << " allocated in " << alloc.file << ":" << alloc.line
     217                 :           1 :         << " (" << alloc.function << ")\n";
     218                 :           1 :     total_leaked_bytes += alloc.size;
     219                 :             :   }
     220                 :             : 
     221                 :           1 :   oss << "Total leaked bytes: " << total_leaked_bytes;
     222                 :           1 :   WIRESTEAD_LOG_ERROR("memory_tracker", "leak_check", oss.str());
     223                 :           1 : }
     224                 :             : 
     225                 :             : // ScopedMemoryTracker implementation
     226                 :           1 : ScopedMemoryTracker::ScopedMemoryTracker(const char* file, int line, const char* function)
     227                 :           1 :     : file_(file), line_(line), function_(function) {}
     228                 :             : 
     229                 :           1 : ScopedMemoryTracker::~ScopedMemoryTracker() {
     230                 :             :   // Destructor can be used for cleanup if needed
     231                 :           1 : }
     232                 :             : 
     233                 :           1 : void ScopedMemoryTracker::track_allocation(void* ptr, size_t size) {
     234                 :           1 :   MemoryTracker::instance().track_allocation(ptr, size, file_, line_, function_);
     235                 :           1 : }
     236                 :             : 
     237                 :           1 : void ScopedMemoryTracker::track_deallocation(void* ptr) { MemoryTracker::instance().track_deallocation(ptr); }
     238                 :             : 
     239                 :             : }  // namespace memory
     240                 :             : }  // namespace wirestead
        

Generated by: LCOV version 2.0-1