From 1a93fb3fa5da003be01ed72c547dd97337b97f54 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 18 Nov 2020 20:20:35 +0100 Subject: [PATCH] first attempt on memory tracing --- libsrc/core/array.hpp | 18 ++++++ libsrc/core/paje_trace.cpp | 29 +++++++++- libsrc/core/paje_trace.hpp | 38 ++++++++++++ libsrc/core/profiler.cpp | 2 + libsrc/core/profiler.hpp | 87 ++++++++++++++++++++++++++++ libsrc/core/python_ngcore_export.cpp | 4 +- libsrc/meshing/meshclass.hpp | 9 +++ 7 files changed, 183 insertions(+), 4 deletions(-) diff --git a/libsrc/core/array.hpp b/libsrc/core/array.hpp index 864fd454..350eb58e 100644 --- a/libsrc/core/array.hpp +++ b/libsrc/core/array.hpp @@ -11,6 +11,7 @@ #include "archive.hpp" #include "exception.hpp" #include "localheap.hpp" +#include "profiler.hpp" #include "utils.hpp" namespace ngcore @@ -654,6 +655,8 @@ 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; using FlatArray::BASE; @@ -1038,6 +1041,18 @@ namespace ngcore ngcore::Swap (data, b.data); ngcore::Swap (allocsize, b.allocsize); ngcore::Swap (mem_to_delete, b.mem_to_delete); + ngcore::Swap (mem_tracing_id, b.mem_tracing_id); + } + + NETGEN_INLINE void SetMemoryTracing (int mem_id) + { + 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; } private: @@ -1053,6 +1068,8 @@ namespace ngcore { size_t nsize = 2 * allocsize; if (nsize < minsize) nsize = minsize; + + TraceMemoryAlloc(mem_tracing_id, sizeof(T)*nsize ); T * hdata = data; data = new T[nsize]; @@ -1069,6 +1086,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 ); } mem_to_delete = data; diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index c58912a4..1c4843a6 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -36,6 +36,7 @@ namespace ngcore // increases trace by a factor of two bool PajeTrace::trace_thread_counter = false; bool PajeTrace::trace_threads = true; + bool PajeTrace::mem_tracing_enabled = true; PajeTrace :: PajeTrace(int anthreads, std::string aname) { @@ -62,6 +63,7 @@ namespace ngcore jobs.reserve(reserve_size); timer_events.reserve(reserve_size); + memory_events.reserve(1024*1024); // sync start time when running in parallel #ifdef PARALLEL @@ -72,6 +74,7 @@ namespace ngcore start_time = GetTimeCounter(); tracing_enabled = true; + mem_tracing_enabled = true; } PajeTrace :: ~PajeTrace() @@ -94,6 +97,9 @@ namespace ngcore for(auto & link : llink) link.time -= start_time; + for(auto & m : memory_events) + m.time -= start_time; + NgMPI_Comm comm(MPI_COMM_WORLD); if(comm.Size()==1) @@ -426,6 +432,7 @@ namespace ngcore const int container_type_thread = paje.DefineContainerType( container_type_task_manager, "Thread"); const int container_type_timer = container_type_thread; //paje.DefineContainerType( container_type_task_manager, "Timers"); const int container_type_jobs = paje.DefineContainerType( container_type_task_manager, "Jobs"); + const int container_type_memory = paje.DefineContainerType( container_type_task_manager, "Memory usage"); const int state_type_job = paje.DefineStateType( container_type_jobs, "Job" ); const int state_type_task = paje.DefineStateType( container_type_thread, "Task" ); @@ -433,12 +440,20 @@ namespace ngcore int variable_type_active_threads = 0; if(trace_thread_counter) - paje.DefineVariableType( container_type_jobs, "Active threads" ); + variable_type_active_threads = paje.DefineVariableType( container_type_jobs, "Active threads" ); const int container_task_manager = paje.CreateContainer( container_type_task_manager, 0, "The task manager" ); const int container_jobs = paje.CreateContainer( container_type_jobs, container_task_manager, "Jobs" ); - if(trace_thread_counter) - paje.SetVariable( 0, variable_type_active_threads, container_jobs, 0.0 ); + + int variable_type_memory = 0; + if(mem_tracing_enabled) + { + variable_type_memory = paje.DefineVariableType( container_type_task_manager, "Memory [MB]" ); + paje.SetVariable( 0, variable_type_memory, container_type_memory, 0.0 ); + } + + const int container_memory = paje.CreateContainer( container_type_memory, container_task_manager, "Memory" ); + int num_nodes = 1; //task_manager ? task_manager->GetNumNodes() : 1; std::vector thread_aliases; @@ -509,6 +524,14 @@ namespace ngcore paje.PopState( j.stop_time, state_type_job, container_jobs ); } + for(const auto & m : memory_events) + { + if(m.is_alloc) + paje.AddVariable( m.time, variable_type_memory, container_memory, 1.0*m.size / (1024*1024)); + else + paje.SubVariable( m.time, variable_type_memory, container_memory, 1.0*m.size / (1024*1024)); + } + std::set timer_ids; std::map timer_aliases; std::map timer_names; diff --git a/libsrc/core/paje_trace.hpp b/libsrc/core/paje_trace.hpp index 95c42d4a..84227fb4 100644 --- a/libsrc/core/paje_trace.hpp +++ b/libsrc/core/paje_trace.hpp @@ -23,6 +23,7 @@ namespace ngcore NGCORE_API static size_t max_tracefile_size; NGCORE_API static bool trace_thread_counter; NGCORE_API static bool trace_threads; + NGCORE_API static bool mem_tracing_enabled; bool tracing_enabled; TTimePoint start_time; @@ -35,6 +36,11 @@ namespace ngcore // be stopped if any thread reaches this number of events unsigned int max_num_events_per_thread; + static void SetTraceMemory( bool trace_memory ) + { + mem_tracing_enabled = trace_memory; + } + static void SetTraceThreads( bool atrace_threads ) { trace_threads = atrace_threads; @@ -96,10 +102,21 @@ namespace ngcore bool operator < (const ThreadLink & other) const { return time < other.time; } }; + struct MemoryEvent + { + TTimePoint time; + size_t size; + int region_id; + bool is_alloc; + + bool operator < (const MemoryEvent & other) const { return time < other.time; } + }; + std::vector > tasks; std::vector jobs; std::vector timer_events; std::vector > links; + std::vector memory_events; public: NGCORE_API void StopTracing(); @@ -129,6 +146,27 @@ namespace ngcore timer_events.push_back(TimerEvent{timer_id, GetTimeCounter(), false}); } + void AllocMemory(int id, size_t size) + { + if(!mem_tracing_enabled) return; + memory_events.push_back(MemoryEvent{GetTimeCounter(), size, id, true}); + } + + void FreeMemory(int id, size_t size) + { + if(!mem_tracing_enabled) return; + memory_events.push_back(MemoryEvent{GetTimeCounter(), size, id, false}); + } + + void ChangeMemory(int id, long long size) + { + if(size>0) + AllocMemory(id, size); + if(size<0) + FreeMemory(id, -size); + } + + NETGEN_INLINE int StartTask(int thread_id, int id, int id_type = Task::ID_NONE, int additional_value = -1) { if(!tracing_enabled) return -1; diff --git a/libsrc/core/profiler.cpp b/libsrc/core/profiler.cpp index 1190e6fe..73aad63d 100644 --- a/libsrc/core/profiler.cpp +++ b/libsrc/core/profiler.cpp @@ -113,5 +113,7 @@ namespace ngcore NgProfiler prof; // NOLINT + std::vector MemoryTracer::names{"root"}; + std::map< int, std::vector > MemoryTracer::tree; } // namespace ngcore diff --git a/libsrc/core/profiler.hpp b/libsrc/core/profiler.hpp index c16c242c..12233db1 100644 --- a/libsrc/core/profiler.hpp +++ b/libsrc/core/profiler.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include "logging.hpp" @@ -299,6 +300,92 @@ namespace ngcore return tres; } + + class MemoryTracer + { + NGCORE_API static std::vector names; + static int GetId(std::string name) + { + int id = names.size(); + names.push_back(name); + if(id==10*NgProfiler::SIZE) + std::cerr << "Allocated " << id << " MemoryTracer objects" << std::endl; + return id; + } + + NGCORE_API static std::map< int, std::vector > tree; + + int id; + std::vector> tracks; + + public: + + MemoryTracer( std::string name ) + { + id = GetId(name); + } + + template + MemoryTracer( std::string name, TRest & ... rest ) + { + id = GetId(name); + Track(rest...); + } + + template + void Track( T1 & obj, std::string name, TRest & ... rest ) + { + Track(obj, name); + Track(rest...); + } + + template + void Track( T & obj, std::string name ) + { + int child_id = GetId(name); + tree[id].push_back(child_id); + obj.SetMemoryTracing(child_id); + tracks.push_back( [&obj] () { obj.SetMemoryTracing(0); } ); + } + + template + void Track( T & obj ) + { + auto & mt = obj.GetMemoryTracer(); + int child_id = mt.id; + tree[id].push_back(child_id); + } + + void StopTracking() + { + for(auto & f : tracks) + f(); + tracks.clear(); + } + + static std::string GetName(int id) + { + return names[id]; + } + + ~MemoryTracer() + { + StopTracking(); + } + }; + + 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); + } + } // 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 4f93168e..08d41ef4 100644 --- a/libsrc/core/python_ngcore_export.cpp +++ b/libsrc/core/python_ngcore_export.cpp @@ -247,15 +247,17 @@ threads : int ; py::class_(m, "PajeTrace") - .def(py::init( [] (string filename, size_t size_mb, bool threads, bool thread_counter) + .def(py::init( [] (string filename, size_t size_mb, bool threads, bool thread_counter, bool memory) { PajeTrace::SetMaxTracefileSize(size_mb*1014*1024); PajeTrace::SetTraceThreads(threads); + PajeTrace::SetTraceMemory(memory); PajeTrace::SetTraceThreadCounter(thread_counter); trace = new PajeTrace(TaskManager::GetMaxThreads(), filename); return trace; }), py::arg("filename")="ng.trace", py::arg("size")=1000, py::arg("threads")=true, py::arg("thread_counter")=false, + py::arg("memory")=true, "size in Megabytes" ) .def("__enter__", [](PajeTrace & self) { }) diff --git a/libsrc/meshing/meshclass.hpp b/libsrc/meshing/meshclass.hpp index 1de31c97..aab4e87a 100644 --- a/libsrc/meshing/meshclass.hpp +++ b/libsrc/meshing/meshclass.hpp @@ -925,6 +925,15 @@ namespace netgen shared_ptr Mirror( netgen::Point<3> p, Vec<3> n ); + private: + MemoryTracer mem_tracer = {"Mesh", + points, "points", + segments, "segments", + surfelements, "surfelements", + volelements, "volelements" + }; + public: + const MemoryTracer & GetMemoryTracer() { return mem_tracer; } }; inline ostream& operator<<(ostream& ost, const Mesh& mesh)