1 #ifndef NETGEN_CORE_MEMTRACER_HPP 2 #define NETGEN_CORE_MEMTRACER_HPP 3 4 #include <array> 5 #include <chrono> 6 #include <functional> 7 #include <string> 8 9 #include "array.hpp" 10 #include "logging.hpp" 11 #include "paje_trace.hpp" 12 #include "utils.hpp" 13 14 namespace ngcore 15 { 16 17 class MemoryTracer; 18 19 namespace detail 20 { 21 //Type trait to check if a class implements a 'void SetMemoryTacing(int)' function 22 template<typename T> 23 struct has_StartMemoryTracing 24 { 25 private: 26 template<typename T2> 27 static constexpr auto check(T2*) -> 28 typename std::is_same<decltype(std::declval<T2>().StartMemoryTracing()),void>::type; 29 template<typename> 30 static constexpr std::false_type check(...); 31 using type = decltype(check<T>(nullptr)); // NOLINT 32 public: 33 static constexpr bool value = type::value; 34 }; 35 } // namespace detail 36 37 class MemoryTracer 38 { 39 #ifdef NETGEN_TRACE_MEMORY 40 NGCORE_API static std::vector<std::string> names; 41 NGCORE_API static std::vector<int> parents; 42 CreateId(const std::string & name)43 static int CreateId(const std::string& name) 44 { 45 int id = names.size(); 46 names.push_back(name); 47 parents.push_back(0); 48 if(id==10*8*1024) 49 std::cerr << "Allocated " << id << " MemoryTracer objects" << std::endl; 50 return id; 51 } 52 int id; 53 54 public: 55 MemoryTracer(std::string name)56 MemoryTracer( std::string name ) 57 { 58 id = CreateId(name); 59 } 60 61 // not tracing MemoryTracer()62 MemoryTracer() : id(0) {} 63 64 template <typename... TRest> MemoryTracer(std::string name,TRest &...rest)65 MemoryTracer( std::string name, TRest & ... rest ) 66 { 67 id = CreateId(name); 68 Track(rest...); 69 } 70 Alloc(size_t size) const71 NETGEN_INLINE void Alloc(size_t size) const 72 { 73 if(id && trace) 74 trace->AllocMemory(id, size); 75 } 76 Free(size_t size) const77 void Free(size_t size) const 78 { 79 if(id && trace) 80 trace->FreeMemory(id, size); 81 } 82 Swap(size_t mysize,MemoryTracer & other,size_t other_size) const83 void Swap(size_t mysize, MemoryTracer& other, size_t other_size) const 84 { 85 if(!trace || (id == 0 && other.id == 0)) 86 return; 87 if(id == 0) 88 return trace->ChangeMemory(other.id, mysize - other_size); 89 if(other.id == 0) 90 return trace->ChangeMemory(id, other_size - mysize); 91 92 // first decrease memory, otherwise have artificial/wrong high peak memory usage 93 if(mysize<other_size) 94 { 95 trace->ChangeMemory(other.id, mysize-other_size); 96 trace->ChangeMemory(id, other_size-mysize); 97 } 98 else 99 { 100 trace->ChangeMemory(id, other_size-mysize); 101 trace->ChangeMemory(other.id, mysize-other_size); 102 } 103 } 104 GetId() const105 int GetId() const { return id; } 106 107 template <typename T1, typename... TRest> Track(T1 & obj,const std::string & name,TRest &...rest) const108 void Track( T1 & obj, const std::string& name, TRest & ... rest ) const 109 { 110 Track(obj, name); 111 Track(rest...); 112 } 113 114 template<typename T> Track(T & obj,const std::string & name) const115 void Track( T & obj, const std::string& name ) const 116 { 117 obj.GetMemoryTracer().Activate(obj, name); 118 parents[obj.GetMemoryTracer().GetId()] = id; 119 } 120 GetName(int id)121 static std::string GetName(int id) 122 { 123 return names[id]; 124 } 125 GetName() const126 std::string GetName() const 127 { 128 return names[id]; 129 } 130 131 template<typename T> Activate(T & me,const std::string & name) const132 void Activate(T& me, const std::string& name) const 133 { 134 if(!id) 135 { 136 const_cast<MemoryTracer*>(this)->id = CreateId(name); 137 if constexpr(detail::has_StartMemoryTracing<T>::value) 138 me.StartMemoryTracing(); 139 } 140 else 141 SetName(name); 142 } 143 SetName(const std::string & name) const144 void SetName(const std::string& name) const 145 { 146 names[id] = name; 147 } 148 149 GetNames()150 static const std::vector<std::string> & GetNames() { return names; } GetParents()151 static const std::vector<int> & GetParents() { return parents; } 152 #else // NETGEN_TRACE_MEMORY 153 public: 154 MemoryTracer() {} 155 MemoryTracer( std::string /* name */ ) {} 156 template <typename... TRest> 157 MemoryTracer( std::string /* name */, TRest & ... ) {} 158 159 void Alloc(size_t /* size */) const {} 160 void Free(size_t /* size */) const {} 161 void Swap(...) const {} 162 int GetId() const { return 0; } 163 164 template <typename... TRest> 165 void Track(TRest&...) const {} 166 167 static std::string GetName(int /* id */) { return ""; } 168 std::string GetName() const { return ""; } 169 void SetName(std::string /* name */) const {} 170 #endif // NETGEN_TRACE_MEMORY 171 }; 172 } // namespace ngcore 173 174 #endif // NETGEN_CORE_MEMTRACER_HPP 175