#ifndef NETGEN_CORE_MEMTRACER_HPP #define NETGEN_CORE_MEMTRACER_HPP #include #include #include #include "array.hpp" #include "logging.hpp" #include "paje_trace.hpp" #include "utils.hpp" namespace ngcore { class MemoryTracer; namespace detail { //Type trait to check if a class implements a 'void SetMemoryTacing(int)' function template struct has_StartMemoryTracing { private: template static constexpr auto check(T2*) -> typename std::is_same().StartMemoryTracing()),void>::type; template static constexpr std::false_type check(...); using type = decltype(check(nullptr)); // NOLINT public: static constexpr bool value = type::value; }; } // namespace detail class MemoryTracer { #ifdef NETGEN_TRACE_MEMORY NGCORE_API static std::vector names; NGCORE_API static std::vector parents; static int CreateId(const std::string& name) { int id = names.size(); names.push_back(name); parents.push_back(0); if(id==10*8*1024) std::cerr << "Allocated " << id << " MemoryTracer objects" << std::endl; return id; } int id; public: MemoryTracer( std::string name ) { id = CreateId(name); } // not tracing MemoryTracer() : id(0) {} template MemoryTracer( std::string name, TRest & ... rest ) { id = CreateId(name); Track(rest...); } NETGEN_INLINE void Alloc(size_t size) const { if(id && trace) trace->AllocMemory(id, size); } void Free(size_t size) const { if(id && trace) trace->FreeMemory(id, size); } void Swap(size_t mysize, MemoryTracer& other, size_t other_size) const { if(!trace || (id == 0 && other.id == 0)) return; if(id == 0) return trace->ChangeMemory(other.id, mysize - other_size); if(other.id == 0) return trace->ChangeMemory(id, other_size - mysize); // first decrease memory, otherwise have artificial/wrong high peak memory usage if(mysizeChangeMemory(other.id, mysize-other_size); trace->ChangeMemory(id, other_size-mysize); } else { trace->ChangeMemory(id, other_size-mysize); trace->ChangeMemory(other.id, mysize-other_size); } } int GetId() const { return id; } template void Track( T1 & obj, const std::string& name, TRest & ... rest ) const { Track(obj, name); Track(rest...); } template void Track( T & obj, const std::string& name ) const { obj.GetMemoryTracer().Activate(obj, name); parents[obj.GetMemoryTracer().GetId()] = id; } static std::string GetName(int id) { return names[id]; } std::string GetName() const { return names[id]; } template void Activate(T& me, const std::string& name) const { if(!id) { const_cast(this)->id = CreateId(name); if constexpr(detail::has_StartMemoryTracing::value) me.StartMemoryTracing(); } else SetName(name); } void SetName(const std::string& name) const { names[id] = name; } static const std::vector & GetNames() { return names; } static const std::vector & GetParents() { return parents; } #else // NETGEN_TRACE_MEMORY public: MemoryTracer() {} MemoryTracer( std::string /* name */ ) {} template MemoryTracer( std::string /* name */, TRest & ... ) {} void Alloc(size_t /* size */) const {} void Free(size_t /* size */) const {} void Swap(...) const {} int GetId() const { return 0; } template void Track(TRest&...) const {} static std::string GetName(int /* id */) { return ""; } std::string GetName() const { return ""; } void SetName(std::string /* name */) const {} #endif // NETGEN_TRACE_MEMORY }; } // namespace ngcore #endif // NETGEN_CORE_MEMTRACER_HPP