From a69cdc9000794a427a0176e1c63ba7cf423f043e Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Sat, 21 Nov 2020 15:49:07 +0100 Subject: [PATCH] mem tracing compile time option, simplify by MemoryTracer as member --- CMakeLists.txt | 1 + cmake/SuperBuild.cmake | 1 + libsrc/core/CMakeLists.txt | 5 + libsrc/core/array.hpp | 30 +++-- libsrc/core/bitarray.cpp | 7 +- libsrc/core/bitarray.hpp | 9 ++ libsrc/core/paje_trace.cpp | 4 + libsrc/core/paje_trace.hpp | 2 + libsrc/core/profiler.cpp | 2 + libsrc/core/profiler.hpp | 163 +++++++++++++-------------- libsrc/core/python_ngcore_export.cpp | 2 + libsrc/core/table.hpp | 13 +++ libsrc/meshing/boundarylayer.cpp | 3 + 13 files changed, 142 insertions(+), 100 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7916e6ee..26dfc2e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,7 @@ option( BUILD_STUB_FILES "Build stub files for better autocompletion" ON) option( BUILD_FOR_CONDA "Link python libraries only to executables" OFF) option( USE_SUPERBUILD "use ccache" ON) +option( TRACE_MEMORY "Enable memory tracing" OFF) set(NG_COMPILE_FLAGS "" CACHE STRING "Additional compile flags") diff --git a/cmake/SuperBuild.cmake b/cmake/SuperBuild.cmake index 37709768..6e9600df 100644 --- a/cmake/SuperBuild.cmake +++ b/cmake/SuperBuild.cmake @@ -143,6 +143,7 @@ set_vars( NETGEN_CMAKE_ARGS USE_SPDLOG DEBUG_LOG CHECK_RANGE + TRACE_MEMORY BUILD_STUB_FILES BUILD_FOR_CONDA NG_COMPILE_FLAGS diff --git a/libsrc/core/CMakeLists.txt b/libsrc/core/CMakeLists.txt index 8329a195..c3eba6a5 100644 --- a/libsrc/core/CMakeLists.txt +++ b/libsrc/core/CMakeLists.txt @@ -42,6 +42,11 @@ if(CHECK_RANGE OR CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL target_compile_definitions(ngcore PUBLIC NETGEN_ENABLE_CHECK_RANGE) endif(CHECK_RANGE OR CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "DEBUG") +if(TRACE_MEMORY OR CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "DEBUG") + target_compile_definitions(ngcore PUBLIC NETGEN_TRACE_MEMORY) +endif(TRACE_MEMORY OR CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "DEBUG") + + if(USE_SPDLOG) include_directories(${SPDLOG_INCLUDE_DIR}) install(DIRECTORY ${SPDLOG_INCLUDE_DIR} diff --git a/libsrc/core/array.hpp b/libsrc/core/array.hpp index 60132186..752f6f64 100644 --- a/libsrc/core/array.hpp +++ b/libsrc/core/array.hpp @@ -655,7 +655,6 @@ namespace ngcore /// that's the data we have to delete, nullptr for not owning the memory T * mem_to_delete; - int mem_tracing_id = 0; using FlatArray::size; using FlatArray::data; @@ -701,7 +700,7 @@ namespace ngcore NETGEN_INLINE Array (Array && a2) { - TraceMemorySwap(mem_tracing_id, sizeof(T)*allocsize, a2.mem_tracing_id, sizeof(T)*a2.allocsize); + mt.Swap(sizeof(T) * allocsize, a2.mt, sizeof(T) * a2.allocsize); size = a2.size; data = a2.data; @@ -774,7 +773,7 @@ namespace ngcore NETGEN_INLINE ~Array() { delete [] mem_to_delete; - TraceMemoryFree(mem_tracing_id, sizeof(T)*allocsize); + mt.Free(sizeof(T)*allocsize); } // Only provide this function if T is archivable @@ -829,7 +828,7 @@ namespace ngcore NETGEN_INLINE const Array & Assign (size_t asize, LocalHeap & lh) { delete [] mem_to_delete; - TraceMemoryFree(mem_tracing_id, sizeof(T)*allocsize); + mt.Free(sizeof(T)*allocsize); size = allocsize = asize; data = lh.Alloc (asize); mem_to_delete = nullptr; @@ -937,7 +936,7 @@ namespace ngcore NETGEN_INLINE void DeleteAll () { delete [] mem_to_delete; - TraceMemoryFree(mem_tracing_id, sizeof(T)*allocsize); + mt.Free(sizeof(T)*allocsize); mem_to_delete = NULL; data = 0; size = allocsize = 0; @@ -969,7 +968,7 @@ namespace ngcore /// steal array NETGEN_INLINE Array & operator= (Array && a2) { - TraceMemorySwap(mem_tracing_id, sizeof(T)*allocsize, a2.mem_tracing_id, sizeof(T)*a2.allocsize); + mt.Swap(sizeof(T)*allocsize, a2.mt, sizeof(T)*a2.allocsize); ngcore::Swap (size, a2.size); ngcore::Swap (data, a2.data); @@ -1044,7 +1043,7 @@ namespace ngcore NETGEN_INLINE void Swap (Array & b) { - TraceMemorySwap(mem_tracing_id, sizeof(T)*allocsize, b.mem_tracing_id, sizeof(T)*b.allocsize); + mt.Swap(sizeof(T) * allocsize, b.mt, sizeof(T) * b.allocsize); ngcore::Swap (size, b.size); ngcore::Swap (data, b.data); @@ -1052,21 +1051,18 @@ namespace ngcore ngcore::Swap (mem_to_delete, b.mem_to_delete); } - NETGEN_INLINE void SetMemoryTracing (int mem_id) + NETGEN_INLINE void StartMemoryTracing () const { - if(!mem_tracing_id && mem_id) - TraceMemoryAlloc(mem_id, sizeof(T)*allocsize); - - if(mem_tracing_id && !mem_id) - TraceMemoryFree(mem_tracing_id, sizeof(T)*allocsize); - - mem_tracing_id = mem_id; + mt.Alloc(sizeof(T) * allocsize); } + const MemoryTracer& GetMemoryTracer() const { return mt; } + private: /// resize array, at least to size minsize. copy contents NETGEN_INLINE void ReSize (size_t minsize); + MemoryTracer mt; }; @@ -1079,7 +1075,7 @@ namespace ngcore T * hdata = data; data = new T[nsize]; - TraceMemoryAlloc(mem_tracing_id, sizeof(T)*nsize ); + mt.Alloc(sizeof(T) * nsize); if (hdata) { @@ -1093,7 +1089,7 @@ namespace ngcore for (size_t i = 0; i < mins; i++) data[i] = std::move(hdata[i]); #endif delete [] mem_to_delete; - TraceMemoryFree( mem_tracing_id, sizeof(T)*allocsize ); + mt.Free(sizeof(T) * allocsize); } mem_to_delete = data; diff --git a/libsrc/core/bitarray.cpp b/libsrc/core/bitarray.cpp index bc923ef1..6b1deac5 100644 --- a/libsrc/core/bitarray.cpp +++ b/libsrc/core/bitarray.cpp @@ -36,10 +36,15 @@ namespace ngcore void BitArray :: SetSize (size_t asize) { if (size == asize) return; - if (owns_data) delete [] data; + if (owns_data) + { + delete [] data; + mt.Free(Addr(size)+1); + } size = asize; data = new unsigned char [Addr (size)+1]; + mt.Alloc(Addr(size)+1); } BitArray & BitArray :: Set () throw() diff --git a/libsrc/core/bitarray.hpp b/libsrc/core/bitarray.hpp index 768b40df..cd8979de 100644 --- a/libsrc/core/bitarray.hpp +++ b/libsrc/core/bitarray.hpp @@ -150,6 +150,14 @@ public: NGCORE_API void DoArchive(Archive& archive); NGCORE_API auto * Data() const { return data; } + + const MemoryTracer& GetMemoryTracer() const { return mt; } + void StartMemoryTracing() const + { + if(owns_data) + mt.Alloc(Addr(size)+1); + } + private: /// unsigned char Mask (size_t i) const @@ -159,6 +167,7 @@ private: size_t Addr (size_t i) const { return (i / CHAR_BIT); } + MemoryTracer mt; }; diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index 4e5331e6..4e387ec2 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -743,7 +743,9 @@ namespace ngcore } } WriteTimingChart(); +#ifdef NETGEN_TRACE_MEMORY WriteMemoryChart(""); +#endif // NETGEN_TRACE_MEMORY paje.WriteEvents(); } @@ -930,6 +932,7 @@ namespace ngcore } +#ifdef NETGEN_TRACE_MEMORY void PajeTrace::WriteMemoryChart( std::string fname ) { if(fname=="") @@ -1053,6 +1056,7 @@ namespace ngcore WriteSunburstHTML( root, fname, false ); } +#endif // NETGEN_TRACE_MEMORY void PajeTrace::WriteTimingChart( ) { diff --git a/libsrc/core/paje_trace.hpp b/libsrc/core/paje_trace.hpp index 421f866e..c153c0cd 100644 --- a/libsrc/core/paje_trace.hpp +++ b/libsrc/core/paje_trace.hpp @@ -31,7 +31,9 @@ namespace ngcore public: NGCORE_API void WriteTimingChart(); +#ifdef NETGEN_TRACE_MEMORY NGCORE_API void WriteMemoryChart( std::string fname ); +#endif // NETGEN_TRACE_MEMORY // Approximate number of events to trace. Tracing will // be stopped if any thread reaches this number of events diff --git a/libsrc/core/profiler.cpp b/libsrc/core/profiler.cpp index 73aad63d..66365321 100644 --- a/libsrc/core/profiler.cpp +++ b/libsrc/core/profiler.cpp @@ -113,7 +113,9 @@ namespace ngcore NgProfiler prof; // NOLINT +#ifdef NETGEN_TRACE_MEMORY std::vector MemoryTracer::names{"root"}; std::map< int, std::vector > MemoryTracer::tree; +#endif // NETGEN_TRACE_MEMORY } // namespace ngcore diff --git a/libsrc/core/profiler.hpp b/libsrc/core/profiler.hpp index cb07d053..cdd945bd 100644 --- a/libsrc/core/profiler.hpp +++ b/libsrc/core/profiler.hpp @@ -304,45 +304,29 @@ namespace ngcore namespace detail { - //Type trait to check if a class implements a 'const MemoryTracer& GetMemoryTracer()' function - template - struct has_GetMemoryTracer - { - private: - template - static constexpr auto check(T2*) -> - typename std::is_same().GetMemoryTracer()),const MemoryTracer &>::type; - template - static constexpr std::false_type check(...); - using type = decltype(check(nullptr)); // NOLINT - public: - static constexpr bool value = type::value; - }; - //Type trait to check if a class implements a 'void SetMemoryTacing(int)' function template - struct has_SetMemoryTracing + struct has_StartMemoryTracing { private: template static constexpr auto check(T2*) -> - typename std::is_same().SetMemoryTracing(0)),void>::type; + 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::map< int, std::vector > tree; - static int GetId(std::string name) + static int CreateId(const std::string& name) { int id = names.size(); names.push_back(name); @@ -350,48 +334,73 @@ namespace ngcore std::cerr << "Allocated " << id << " MemoryTracer objects" << std::endl; return id; } - - int id; public: MemoryTracer( std::string name ) { - id = GetId(name); + id = CreateId(name); } + // not tracing + MemoryTracer() : id(0) {} + template MemoryTracer( std::string name, TRest & ... rest ) { - id = GetId(name); + 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, std::string name, TRest & ... rest ) const + void Track( T1 & obj, const std::string& name, TRest & ... rest ) const { Track(obj, name); Track(rest...); } template - void Track( T & obj, std::string name ) const + void Track( T & obj, const std::string& name ) const { - if constexpr(detail::has_SetMemoryTracing::value) - { - int child_id = GetId(name); - tree[id].push_back(child_id); - obj.SetMemoryTracing(child_id); - } - if constexpr(detail::has_GetMemoryTracer::value) - { - auto & mt = obj.GetMemoryTracer(); - int child_id = mt.id; - if(name!="") - names[mt.id] = name; - tree[id].push_back(child_id); - } + obj.GetMemoryTracer().Activate(obj, name); + tree[id].push_back(obj.GetMemoryTracer().GetId()); } static std::string GetName(int id) @@ -404,7 +413,20 @@ namespace ngcore return names[id]; } - void SetName(std::string name) const + 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; } @@ -412,49 +434,26 @@ namespace ngcore static const std::vector & GetNames() { return names; } static const std::map> & GetTree() { return tree; } +#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 }; - - NETGEN_INLINE void TraceMemoryAlloc( int mem_id, size_t size ) - { - if(mem_id && trace) - trace->AllocMemory(mem_id, size); - } - - NETGEN_INLINE void TraceMemoryFree( int mem_id, size_t size ) - { - if(mem_id && trace) - trace->FreeMemory(mem_id, size); - } - - NETGEN_INLINE void TraceMemoryChange( int mem_id, long long size ) - { - if(mem_id && trace) - trace->ChangeMemory(mem_id, size); - } - - NETGEN_INLINE void TraceMemorySwap( int mem_id, size_t size, int mem_id2, size_t size2 ) - { - if(!trace || (mem_id==0 && mem_id2==0)) - return; - if(mem_id == 0) - return trace->ChangeMemory(mem_id2, size-size2); - if(mem_id2 == 0) - return trace->ChangeMemory(mem_id, size2-size); - - // first decrease memory, otherwise have artificial/wrong high peak memory usage - if(sizeChangeMemory(mem_id2, size-size2); - trace->ChangeMemory(mem_id, size2-size); - } - else - { - trace->ChangeMemory(mem_id, size2-size); - trace->ChangeMemory(mem_id2, size-size2); - } - } - } // namespace ngcore // Helper macro to easily add multiple timers in a function for profiling diff --git a/libsrc/core/python_ngcore_export.cpp b/libsrc/core/python_ngcore_export.cpp index 59d1a13f..abdceb0e 100644 --- a/libsrc/core/python_ngcore_export.cpp +++ b/libsrc/core/python_ngcore_export.cpp @@ -266,7 +266,9 @@ threads : int .def_static("SetTraceThreads", &PajeTrace::SetTraceThreads) .def_static("SetTraceThreadCounter", &PajeTrace::SetTraceThreadCounter) .def_static("SetMaxTracefileSize", &PajeTrace::SetMaxTracefileSize) +#ifdef NETGEN_TRACE_MEMORY .def_static("WriteMemoryChart", [](string filename){ if(trace) trace->WriteMemoryChart(filename); }, py::arg("filename")="memory" ) +#endif // NETGEN_TRACE_MEMORY ; diff --git a/libsrc/core/table.hpp b/libsrc/core/table.hpp index 8db44f9d..7471b6a3 100644 --- a/libsrc/core/table.hpp +++ b/libsrc/core/table.hpp @@ -159,6 +159,7 @@ namespace ngcore NETGEN_INLINE Table (Table && tab2) : FlatTable(0, nullptr, nullptr) { + tab2.mt.Free(tab2.GetMemUsage()); Swap (size, tab2.size); Swap (index, tab2.index); Swap (data, tab2.data); @@ -166,6 +167,7 @@ namespace ngcore NETGEN_INLINE Table & operator= (Table && tab2) { + mt.Swap(GetMemUsage(), tab2.mt, tab2.GetMemUsage()); Swap (size, tab2.size); Swap (index, tab2.index); Swap (data, tab2.data); @@ -177,6 +179,7 @@ namespace ngcore /// Delete data NETGEN_INLINE ~Table () { + mt.Free(GetMemUsage()); delete [] data; delete [] index; } @@ -188,6 +191,16 @@ namespace ngcore NETGEN_INLINE size_t NElements() const { return index[size]; } using FlatTable::operator[]; + + NETGEN_INLINE void StartMemoryTracing (int mem_id) + { + mt.Alloc(GetMemUsage()); + } + const MemoryTracer& GetMemoryTracer() const { return mt; } + + private: + size_t GetMemUsage() const { return size == 0 ? 0 : sizeof(T)*index[size] + sizeof(IndexType) * size+1; } + MemoryTracer mt; }; diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index bd5427ef..89baa018 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -90,6 +90,9 @@ namespace netgen void GenerateBoundaryLayer(Mesh& mesh, const BoundaryLayerParameters& blp) { + static Timer timer("Create Boundarylayers"); + RegionTimer regt(timer); + int max_edge_nr = -1; for(const auto& seg : mesh.LineSegments()) if(seg.edgenr > max_edge_nr)