From 1a93fb3fa5da003be01ed72c547dd97337b97f54 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 18 Nov 2020 20:20:35 +0100 Subject: [PATCH 01/24] 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) From f143995f27e140155d851636d176d9107cde3288 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 18 Nov 2020 21:45:00 +0100 Subject: [PATCH 02/24] clean up memory tracing --- libsrc/core/paje_trace.cpp | 10 +++++----- libsrc/core/profiler.hpp | 14 -------------- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index 1c4843a6..23dcb154 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -446,14 +446,13 @@ namespace ngcore const int container_jobs = paje.CreateContainer( container_type_jobs, container_task_manager, "Jobs" ); int variable_type_memory = 0; + const int container_memory = paje.CreateContainer( container_type_memory, container_task_manager, "Memory" ); 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 ); + paje.SetVariable( 0, variable_type_memory, container_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; @@ -526,10 +525,11 @@ namespace ngcore for(const auto & m : memory_events) { + double size = 1.0*m.size/(1024*1024); if(m.is_alloc) - paje.AddVariable( m.time, variable_type_memory, container_memory, 1.0*m.size / (1024*1024)); + paje.AddVariable( m.time, variable_type_memory, container_memory, size); else - paje.SubVariable( m.time, variable_type_memory, container_memory, 1.0*m.size / (1024*1024)); + paje.SubVariable( m.time, variable_type_memory, container_memory, size); } std::set timer_ids; diff --git a/libsrc/core/profiler.hpp b/libsrc/core/profiler.hpp index 12233db1..d3b06746 100644 --- a/libsrc/core/profiler.hpp +++ b/libsrc/core/profiler.hpp @@ -316,7 +316,6 @@ namespace ngcore NGCORE_API static std::map< int, std::vector > tree; int id; - std::vector> tracks; public: @@ -345,7 +344,6 @@ namespace ngcore int child_id = GetId(name); tree[id].push_back(child_id); obj.SetMemoryTracing(child_id); - tracks.push_back( [&obj] () { obj.SetMemoryTracing(0); } ); } template @@ -356,22 +354,10 @@ namespace ngcore 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 ) From a17066a387b28b7ae277a3a82ed8adac5f425c93 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 19 Nov 2020 14:57:45 +0100 Subject: [PATCH 03/24] html chart for peak memory consumption, some Array tracing fixes --- libsrc/core/array.hpp | 12 +- libsrc/core/paje_trace.cpp | 277 ++++++++++++++++++++++++++---------- libsrc/core/paje_trace.hpp | 2 +- libsrc/core/profiler.hpp | 89 ++++++++++-- libsrc/core/taskmanager.cpp | 2 +- 5 files changed, 290 insertions(+), 92 deletions(-) diff --git a/libsrc/core/array.hpp b/libsrc/core/array.hpp index 350eb58e..db5d7561 100644 --- a/libsrc/core/array.hpp +++ b/libsrc/core/array.hpp @@ -701,6 +701,8 @@ namespace ngcore NETGEN_INLINE Array (Array && a2) { + TraceMemoryChange(mem_tracing_id, sizeof(T)*(a2.allocsize-allocsize)); + size = a2.size; data = a2.data; allocsize = a2.allocsize; @@ -772,6 +774,7 @@ namespace ngcore NETGEN_INLINE ~Array() { delete [] mem_to_delete; + TraceMemoryFree(mem_tracing_id, sizeof(T)*allocsize); } // Only provide this function if T is archivable @@ -826,6 +829,7 @@ namespace ngcore NETGEN_INLINE const Array & Assign (size_t asize, LocalHeap & lh) { delete [] mem_to_delete; + TraceMemoryFree(mem_tracing_id, sizeof(T)*allocsize); size = allocsize = asize; data = lh.Alloc (asize); mem_to_delete = nullptr; @@ -933,6 +937,7 @@ namespace ngcore NETGEN_INLINE void DeleteAll () { delete [] mem_to_delete; + TraceMemoryFree(mem_tracing_id, sizeof(T)*allocsize); mem_to_delete = NULL; data = 0; size = allocsize = 0; @@ -964,6 +969,8 @@ namespace ngcore /// steal array NETGEN_INLINE Array & operator= (Array && a2) { + TraceMemoryChange(mem_tracing_id, sizeof(T)*(a2.allocsize-allocsize)); + ngcore::Swap (size, a2.size); ngcore::Swap (data, a2.data); ngcore::Swap (allocsize, a2.allocsize); @@ -1037,6 +1044,8 @@ namespace ngcore NETGEN_INLINE void Swap (Array & b) { + TraceMemoryChange(mem_tracing_id, sizeof(T)*(b.allocsize-allocsize)); + ngcore::Swap (size, b.size); ngcore::Swap (data, b.data); ngcore::Swap (allocsize, b.allocsize); @@ -1068,11 +1077,10 @@ 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]; + TraceMemoryAlloc(mem_tracing_id, sizeof(T)*nsize ); if (hdata) { diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index 23dcb154..fdf8a28b 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -243,7 +243,8 @@ namespace ngcore PajeFile( const std::string & filename) { - ctrace_stream = fopen (filename.c_str(),"w"); // NOLINT + std::string fname = filename + ".trace"; + ctrace_stream = fopen (fname.c_str(),"w"); // NOLINT fprintf(ctrace_stream, "%s", header ); // NOLINT alias_counter = 0; } @@ -809,24 +810,25 @@ namespace ngcore int id = 0; std::map children; double chart_size = 0.0; // time without children (the chart lib accumulates children sizes again) - double time = 0.0; - double min_time = 1e99; - double max_time = 0.0; - size_t calls = 0; + double size = 0.0; + double min_size = 1e99; + double max_size = 0.0; std::string name; + + size_t calls = 0; TTimePoint start_time = 0; }; - void PrintNode (const TreeNode &n, int &level, std::ofstream & f); - void PrintNode (const TreeNode &n, int &level, std::ofstream & f) + void PrintNode (const TreeNode &n, std::ofstream & f) { f << "{ name: \"" + n.name + "\""; f << ", calls: " << n.calls; f << ", size: " << n.chart_size; - f << ", time: " << n.time; - f << ", min: " << n.min_time; - f << ", max: " << n.max_time; - f << ", avg: " << n.time/n.calls; + f << ", value: " << n.size; + f << ", min: " << n.min_size; + f << ", max: " << n.max_size; + if(n.calls) + f << ", avg: " << n.size/n.calls; int size = n.children.size(); if(size>0) { @@ -834,7 +836,7 @@ namespace ngcore f << ", children: ["; for(auto & c : n.children) { - PrintNode(c.second, level, f); + PrintNode(c.second, f); if(++i + + + + +)CODE_"; + if(!time_or_memory) + f << "Maximum Memory Consumption\n"; + f << R"CODE_( + + +
+ + + +)CODE_" << std::endl; + + + } + + void WriteMemorySunburstHTML( std::vector & events, std::string filename ) + { + size_t mem_allocated; + size_t max_mem_allocated; + size_t imax_mem_allocated; + + const auto & names = MemoryTracer::GetNames(); + const auto & tree = MemoryTracer::GetTree(); + auto N = names.size(); + + Array mem_allocated_id(N); + mem_allocated_id = 0; + + // Find point with maximum memory allocation, check for missing allocs/frees + for(auto i : IntRange(events.size())) + { + const auto & ev = events[i]; + + if(ev.is_alloc) + { + mem_allocated += ev.size; + mem_allocated_id[ev.id] += ev.size; + if(mem_allocated > max_mem_allocated) + { + imax_mem_allocated = i; + max_mem_allocated = mem_allocated; + } + } + else + { + if(ev.size > mem_allocated) + std::cerr << "Error in memory tracer: have total allocated memory < 0" << std::endl; + if(ev.size > mem_allocated_id[ev.id]) + std::cerr << "Error in memory tracer: have allocated memory < 0 in tracer " << names[ev.id] << std::endl; + + mem_allocated -= ev.size; + mem_allocated_id[ev.id] -= ev.size; + } + } + + // reconstruct again the memory consumption after event imax_mem_allocated + mem_allocated_id = 0; + for(auto i : IntRange(imax_mem_allocated+1)) + { + const auto & ev = events[i]; + + if(ev.is_alloc) + mem_allocated_id[ev.id] += ev.size; + else + mem_allocated_id[ev.id] -= ev.size; + } + + TreeNode root; + root.name="all"; + + Array nodes(N); + nodes = nullptr; + + // find root nodes in memory tracer tree, i.e. they have no parents + Array parents(N); + parents = -1; + for( const auto & [iparent, children] : tree ) + for (auto child_id : children) + { + if(parents[child_id] != -1) + std::cerr << "Error in memory tracer: multiple parents found for " << names[child_id] << std::endl; + parents[child_id] = iparent; + } + + for(auto i : IntRange(1, N)) + { + TreeNode * parent = &root; + if(parents[i]!=-1) + parent = nodes[parents[i]]; + + auto & node = parent->children[i]; + nodes[i] = &node; + node.id = i; + node.chart_size = mem_allocated_id[i]; + node.size = mem_allocated_id[i]; + node.name = names[i]; + } + + for(auto i : IntRange(1, N)) + if(parents[N-i]==-1) + root.size += nodes[N-i]->size; + else + nodes[parents[N-i]]->size += nodes[N-i]->size; + + WriteSunburstHTML( root, filename, false ); + + } + void PajeTrace::WriteSunburstHTML( ) { std::vector events; @@ -884,10 +1063,10 @@ namespace ngcore std::sort (events.begin(), events.end()); - root.time = 1000.0*static_cast(stop_time) * seconds_per_tick; + root.size = 1000.0*static_cast(stop_time) * seconds_per_tick; root.calls = 1; - root.min_time = root.time; - root.max_time = root.time; + root.min_size = root.size; + root.max_size = root.size; for(auto & event : events) { @@ -904,7 +1083,7 @@ namespace ngcore if(need_init) { current->name = is_timer_event ? GetTimerName(id) : job_names[id]; - current->time = 0.0; + current->size = 0.0; current->id = id; } @@ -916,73 +1095,23 @@ namespace ngcore std::cout << "node stack empty!" << std::endl; break; } - double time = 1000.0*static_cast(event.time-current->start_time) * seconds_per_tick; - current->time += time; - current->chart_size += time; - current->min_time = std::min(current->min_time, time); - current->max_time = std::max(current->max_time, time); + double size = 1000.0*static_cast(event.time-current->start_time) * seconds_per_tick; + current->size += size; + current->chart_size += size; + current->min_size = std::min(current->min_size, size); + current->max_size = std::max(current->max_size, size); current->calls++; current = node_stack.back(); - current->chart_size -= time; + current->chart_size -= size; node_stack.pop_back(); } } root.chart_size = 0.0; - int level = 0; - std::ofstream f(tracefile_name+".html"); - f.precision(4); - f << R"CODE_( - - - - - - - -
- - - -)CODE_" << std::endl; + ngcore::WriteSunburstHTML( root, tracefile_name, true ); + WriteMemorySunburstHTML( memory_events, tracefile_name+"_memory" ); } } // namespace ngcore diff --git a/libsrc/core/paje_trace.hpp b/libsrc/core/paje_trace.hpp index 84227fb4..22fd0f50 100644 --- a/libsrc/core/paje_trace.hpp +++ b/libsrc/core/paje_trace.hpp @@ -106,7 +106,7 @@ namespace ngcore { TTimePoint time; size_t size; - int region_id; + int id; bool is_alloc; bool operator < (const MemoryEvent & other) const { return time < other.time; } diff --git a/libsrc/core/profiler.hpp b/libsrc/core/profiler.hpp index d3b06746..ab9785ea 100644 --- a/libsrc/core/profiler.hpp +++ b/libsrc/core/profiler.hpp @@ -300,10 +300,48 @@ namespace ngcore return tres; } + class MemoryTracer; + + 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 + { + private: + template + static constexpr auto check(T2*) -> + typename std::is_same().SetMemoryTracing(0)),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 { NGCORE_API static std::vector names; + NGCORE_API static std::map< int, std::vector > tree; + static int GetId(std::string name) { int id = names.size(); @@ -313,7 +351,6 @@ namespace ngcore return id; } - NGCORE_API static std::map< int, std::vector > tree; int id; @@ -332,32 +369,50 @@ namespace ngcore } template - void Track( T1 & obj, std::string name, TRest & ... rest ) + void Track( T1 & obj, std::string name, TRest & ... rest ) const { Track(obj, name); Track(rest...); } template - void Track( T & obj, std::string name ) + void Track( T & obj, std::string name ) const { - int child_id = GetId(name); - tree[id].push_back(child_id); - obj.SetMemoryTracing(child_id); - } - - template - void Track( T & obj ) - { - auto & mt = obj.GetMemoryTracer(); - int child_id = mt.id; - tree[id].push_back(child_id); + 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); + } } static std::string GetName(int id) { return names[id]; } + + std::string GetName() const + { + return names[id]; + } + + void SetName(std::string name) const + { + names[id] = name; + } + + + static const std::vector & GetNames() { return names; } + static const std::map> & GetTree() { return tree; } + }; NETGEN_INLINE void TraceMemoryAlloc( int mem_id, size_t size ) @@ -372,6 +427,12 @@ namespace ngcore trace->FreeMemory(mem_id, size); } + NETGEN_INLINE void TraceMemoryChange( int mem_id, long long size ) + { + if(mem_id && trace) + trace->ChangeMemory(mem_id, size); + } + } // namespace ngcore // Helper macro to easily add multiple timers in a function for profiling diff --git a/libsrc/core/taskmanager.cpp b/libsrc/core/taskmanager.cpp index be345321..a1049a1c 100644 --- a/libsrc/core/taskmanager.cpp +++ b/libsrc/core/taskmanager.cpp @@ -160,7 +160,7 @@ namespace ngcore static int cnt = 0; if (use_paje_trace) - trace = new PajeTrace(num_threads, "ng" + ToString(cnt++) + ".trace"); + trace = new PajeTrace(num_threads, "ng" + ToString(cnt++)); } From b00c56a012064e61dc9070cbd7eb63e6caaa5b81 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 19 Nov 2020 14:58:16 +0100 Subject: [PATCH 04/24] mem tracing - set name for tempmesh in delaunay --- libsrc/meshing/delaunay.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libsrc/meshing/delaunay.cpp b/libsrc/meshing/delaunay.cpp index adc64712..cd675ef3 100644 --- a/libsrc/meshing/delaunay.cpp +++ b/libsrc/meshing/delaunay.cpp @@ -772,6 +772,7 @@ namespace netgen // improve delaunay - mesh by swapping !!!! Mesh tempmesh; + tempmesh.GetMemoryTracer().SetName("delaunay-tempmesh"); for (auto & meshpoint : mesh.Points()) tempmesh.AddPoint (meshpoint); From 6f98123e98c098e7a512e283591d20692e7454ca Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 19 Nov 2020 16:16:39 +0100 Subject: [PATCH 05/24] mem tracing - use topological sorting, some fixes --- libsrc/core/paje_trace.cpp | 57 ++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index fdf8a28b..856e2214 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -931,15 +931,16 @@ namespace ngcore void WriteMemorySunburstHTML( std::vector & events, std::string filename ) { - size_t mem_allocated; - size_t max_mem_allocated; - size_t imax_mem_allocated; + size_t mem_allocated = 0; + size_t max_mem_allocated = 0; + size_t imax_mem_allocated = 0; const auto & names = MemoryTracer::GetNames(); const auto & tree = MemoryTracer::GetTree(); - auto N = names.size(); + size_t N = names.size(); - Array mem_allocated_id(N); + Array mem_allocated_id; + mem_allocated_id.SetSize(N); mem_allocated_id = 0; // Find point with maximum memory allocation, check for missing allocs/frees @@ -984,11 +985,16 @@ namespace ngcore TreeNode root; root.name="all"; - Array nodes(N); + Array nodes; + nodes.SetSize(N); nodes = nullptr; + Array sorting; // topological sorting (parents before children) + sorting.SetAllocSize(N); + ArrayMem stack; // find root nodes in memory tracer tree, i.e. they have no parents - Array parents(N); + Array parents; + parents.SetSize(N); parents = -1; for( const auto & [iparent, children] : tree ) for (auto child_id : children) @@ -999,10 +1005,29 @@ namespace ngcore } for(auto i : IntRange(1, N)) + if(parents[i]==-1) + { + sorting.Append(i); + if(tree.count(i)) + stack.Append(i); + } + + while(stack.Size()) { - TreeNode * parent = &root; - if(parents[i]!=-1) - parent = nodes[parents[i]]; + auto current = stack.Last(); + stack.DeleteLast(); + + for(const auto child : tree.at(current)) + { + sorting.Append(child); + if(tree.count(child)) + stack.Append(child); + } + } + + for(auto i : sorting) + { + TreeNode * parent = (parents[i]==-1) ? &root : nodes[parents[i]]; auto & node = parent->children[i]; nodes[i] = &node; @@ -1012,11 +1037,15 @@ namespace ngcore node.name = names[i]; } - for(auto i : IntRange(1, N)) - if(parents[N-i]==-1) - root.size += nodes[N-i]->size; + for(auto i_ : Range(sorting)) + { + // reverse topological order to accumulate total memory usage of all children + auto i = sorting[sorting.Size()-1-i_]; + if(parents[i]==-1) + root.size += nodes[i]->size; else - nodes[parents[N-i]]->size += nodes[N-i]->size; + nodes[parents[i]]->size += nodes[i]->size; + } WriteSunburstHTML( root, filename, false ); From f0152baacfdf79a1353e1a88fc21540fcfcc7903 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 19 Nov 2020 17:35:29 +0100 Subject: [PATCH 06/24] mem tracing - TraceMemorySwap helper function --- libsrc/core/array.hpp | 7 +++---- libsrc/core/profiler.hpp | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/libsrc/core/array.hpp b/libsrc/core/array.hpp index db5d7561..60132186 100644 --- a/libsrc/core/array.hpp +++ b/libsrc/core/array.hpp @@ -701,7 +701,7 @@ namespace ngcore NETGEN_INLINE Array (Array && a2) { - TraceMemoryChange(mem_tracing_id, sizeof(T)*(a2.allocsize-allocsize)); + TraceMemorySwap(mem_tracing_id, sizeof(T)*allocsize, a2.mem_tracing_id, sizeof(T)*a2.allocsize); size = a2.size; data = a2.data; @@ -969,7 +969,7 @@ namespace ngcore /// steal array NETGEN_INLINE Array & operator= (Array && a2) { - TraceMemoryChange(mem_tracing_id, sizeof(T)*(a2.allocsize-allocsize)); + TraceMemorySwap(mem_tracing_id, sizeof(T)*allocsize, a2.mem_tracing_id, sizeof(T)*a2.allocsize); ngcore::Swap (size, a2.size); ngcore::Swap (data, a2.data); @@ -1044,13 +1044,12 @@ namespace ngcore NETGEN_INLINE void Swap (Array & b) { - TraceMemoryChange(mem_tracing_id, sizeof(T)*(b.allocsize-allocsize)); + TraceMemorySwap(mem_tracing_id, sizeof(T)*allocsize, b.mem_tracing_id, sizeof(T)*b.allocsize); ngcore::Swap (size, b.size); 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) diff --git a/libsrc/core/profiler.hpp b/libsrc/core/profiler.hpp index ab9785ea..cb07d053 100644 --- a/libsrc/core/profiler.hpp +++ b/libsrc/core/profiler.hpp @@ -433,6 +433,28 @@ namespace ngcore 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 From 87623981a6c66df3d439ba951b64e9dc700361d6 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 19 Nov 2020 19:29:04 +0100 Subject: [PATCH 07/24] export PajeTrace.WriteMemoryChart() to python --- libsrc/core/paje_trace.cpp | 18 ++++++++++-------- libsrc/core/paje_trace.hpp | 3 ++- libsrc/core/python_ngcore_export.cpp | 7 ++++--- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index 856e2214..4e5331e6 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -742,7 +742,8 @@ namespace ngcore } } } - WriteSunburstHTML(); + WriteTimingChart(); + WriteMemoryChart(""); paje.WriteEvents(); } @@ -929,8 +930,10 @@ namespace ngcore } - void WriteMemorySunburstHTML( std::vector & events, std::string filename ) + void PajeTrace::WriteMemoryChart( std::string fname ) { + if(fname=="") + fname = tracefile_name + "_memory"; size_t mem_allocated = 0; size_t max_mem_allocated = 0; size_t imax_mem_allocated = 0; @@ -944,9 +947,9 @@ namespace ngcore mem_allocated_id = 0; // Find point with maximum memory allocation, check for missing allocs/frees - for(auto i : IntRange(events.size())) + for(auto i : IntRange(memory_events.size())) { - const auto & ev = events[i]; + const auto & ev = memory_events[i]; if(ev.is_alloc) { @@ -974,7 +977,7 @@ namespace ngcore mem_allocated_id = 0; for(auto i : IntRange(imax_mem_allocated+1)) { - const auto & ev = events[i]; + const auto & ev = memory_events[i]; if(ev.is_alloc) mem_allocated_id[ev.id] += ev.size; @@ -1047,11 +1050,11 @@ namespace ngcore nodes[parents[i]]->size += nodes[i]->size; } - WriteSunburstHTML( root, filename, false ); + WriteSunburstHTML( root, fname, false ); } - void PajeTrace::WriteSunburstHTML( ) + void PajeTrace::WriteTimingChart( ) { std::vector events; @@ -1140,7 +1143,6 @@ namespace ngcore root.chart_size = 0.0; ngcore::WriteSunburstHTML( root, tracefile_name, true ); - WriteMemorySunburstHTML( memory_events, tracefile_name+"_memory" ); } } // namespace ngcore diff --git a/libsrc/core/paje_trace.hpp b/libsrc/core/paje_trace.hpp index 22fd0f50..421f866e 100644 --- a/libsrc/core/paje_trace.hpp +++ b/libsrc/core/paje_trace.hpp @@ -30,7 +30,8 @@ namespace ngcore int nthreads; public: - void WriteSunburstHTML(); + NGCORE_API void WriteTimingChart(); + NGCORE_API void WriteMemoryChart( std::string fname ); // Approximate number of events to trace. Tracing will // be stopped if any thread reaches this number of events diff --git a/libsrc/core/python_ngcore_export.cpp b/libsrc/core/python_ngcore_export.cpp index 08d41ef4..59d1a13f 100644 --- a/libsrc/core/python_ngcore_export.cpp +++ b/libsrc/core/python_ngcore_export.cpp @@ -263,9 +263,10 @@ threads : int .def("__enter__", [](PajeTrace & self) { }) .def("__exit__", [](PajeTrace & self, py::args) { self.StopTracing(); }) .def("__del__", [](PajeTrace & self) { trace = nullptr; }) - .def("SetTraceThreads", &PajeTrace::SetTraceThreads) - .def("SetTraceThreadCounter", &PajeTrace::SetTraceThreadCounter) - .def("SetMaxTracefileSize", &PajeTrace::SetMaxTracefileSize) + .def_static("SetTraceThreads", &PajeTrace::SetTraceThreads) + .def_static("SetTraceThreadCounter", &PajeTrace::SetTraceThreadCounter) + .def_static("SetMaxTracefileSize", &PajeTrace::SetMaxTracefileSize) + .def_static("WriteMemoryChart", [](string filename){ if(trace) trace->WriteMemoryChart(filename); }, py::arg("filename")="memory" ) ; From a69cdc9000794a427a0176e1c63ba7cf423f043e Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Sat, 21 Nov 2020 15:49:07 +0100 Subject: [PATCH 08/24] 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) From 922ad16213970138b05ef21ab36eaee3786f92f9 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Sat, 21 Nov 2020 22:32:41 +0100 Subject: [PATCH 09/24] if more memory is deallocated than allocated set memtracer to 0 not negative values --- libsrc/core/paje_trace.cpp | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index 4e387ec2..9b4ac053 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -967,12 +967,19 @@ namespace ngcore else { if(ev.size > mem_allocated) - std::cerr << "Error in memory tracer: have total allocated memory < 0" << std::endl; + { + std::cerr << "Error in memory tracer: have total allocated memory < 0" << std::endl; + mem_allocated = 0; + } + else + mem_allocated -= ev.size; if(ev.size > mem_allocated_id[ev.id]) - std::cerr << "Error in memory tracer: have allocated memory < 0 in tracer " << names[ev.id] << std::endl; - - mem_allocated -= ev.size; - mem_allocated_id[ev.id] -= ev.size; + { + std::cerr << "Error in memory tracer: have allocated memory < 0 in tracer " << names[ev.id] << std::endl; + mem_allocated_id[ev.id] = 0; + } + else + mem_allocated_id[ev.id] -= ev.size; } } @@ -985,7 +992,12 @@ namespace ngcore if(ev.is_alloc) mem_allocated_id[ev.id] += ev.size; else - mem_allocated_id[ev.id] -= ev.size; + { + if(ev.size > mem_allocated_id[ev.id]) + mem_allocated_id[ev.id] = 0; + else + mem_allocated_id[ev.id] -= ev.size; + } } TreeNode root; From 7e78056ade10be3ff66d1a285c1695a1ef101c24 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Mon, 23 Nov 2020 23:48:49 +0100 Subject: [PATCH 10/24] Boundarylayer grows pyramids if created on interior bnd --- libsrc/meshing/boundarylayer.cpp | 107 +++++++++++++++++++++++++++-- tests/pytest/test_boundarylayer.py | 15 ++++ 2 files changed, 116 insertions(+), 6 deletions(-) diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index bd5427ef..0aeb59ec 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -408,6 +408,10 @@ namespace netgen } } + BitArray fixed_points(np+1); + fixed_points.Clear(); + BitArray moveboundarypoint(np+1); + moveboundarypoint.Clear(); for(SurfaceElementIndex si = 0; si < nse; si++) { // copy because surfaceels array will be resized! @@ -436,10 +440,29 @@ namespace netgen newel.SetIndex(si_map[sel.GetIndex()]); mesh.AddSurfaceElement(newel); } + else + { + bool has_moved = false; + for(auto p : sel.PNums()) + if(mapto[p].Size()) + has_moved = true; + if(has_moved) + for(auto p : sel.PNums()) + { + if(!mapto[p].Size()) + { + fixed_points.SetBit(p); + if(move_boundaries.Test(sel.GetIndex())) + moveboundarypoint.SetBit(p); + } + } + } if(move_boundaries.Test(sel.GetIndex())) - for(auto& p : mesh[si].PNums()) - if(mapto[p].Size()) - p = mapto[p].Last(); + { + for(auto& p : mesh[si].PNums()) + if(mapto[p].Size()) + p = mapto[p].Last(); + } } for(SegmentIndex sei = 0; sei < nseg; sei++) @@ -453,13 +476,85 @@ namespace netgen for(ElementIndex ei = 0; ei < ne; ei++) { - auto& el = mesh[ei]; - if(!domains[el.GetIndex()]) + auto el = mesh[ei]; + ArrayMem fixed; + ArrayMem moved; + bool moved_bnd = false; + for(const auto& p : el.PNums()) { - for(auto& p : el.PNums()) + if(fixed_points.Test(p)) + fixed.Append(p); + if(mapto[p].Size()) + moved.Append(p); + if(moveboundarypoint.Test(p)) + moved_bnd = true; + } + + bool do_move, do_insert; + if(domains.Test(el.GetIndex())) + { + do_move = fixed.Size() && moved_bnd; + do_insert = do_move; + } + else + { + do_move = !fixed.Size() || moved_bnd; + do_insert = !do_move; + } + + if(do_move) + { + for(auto& p : mesh[ei].PNums()) if(mapto[p].Size()) p = mapto[p].Last(); } + if(do_insert) + { + if(el.GetType() != TET) + throw Exception("Boundarylayer only implemented for tets outside yet!"); + if(moved.Size() == 2) + { + if(fixed.Size() == 2) + throw Exception("This should not be possible!"); + PointIndex p1 = moved[0]; + PointIndex p2 = moved[1]; + for(auto i : Range(blp.heights)) + { + PointIndex p3 = mapto[moved[1]][i]; + PointIndex p4 = mapto[moved[0]][i]; + Element nel(PYRAMID); + nel[0] = p1; + nel[1] = p2; + nel[2] = p3; + nel[3] = p4; + nel[4] = el[0] + el[1] + el[2] + el[3] - fixed[0] - moved[0] - moved[1]; + if(Cross(mesh[p2]-mesh[p1], mesh[p4]-mesh[p1]) * (mesh[nel[4]]-mesh[nel[1]]) > 0) + Swap(nel[1], nel[3]); + nel.SetIndex(el.GetIndex()); + mesh.AddVolumeElement(nel); + p1 = p4; + p2 = p3; + } + } + if(moved.Size() == 1 && fixed.Size() == 1) + { + PointIndex p1 = moved[0]; + for(auto i : Range(blp.heights)) + { + Element nel = el; + PointIndex p2 = mapto[moved[0]][i]; + for(auto& p : nel.PNums()) + { + if(p == moved[0]) + p = p2; + if(p == fixed[0]) + p = p1; + } + p1 = p2; + mesh.AddVolumeElement(nel); + } + } + } } for(auto i : Range(1, fd_old+1)) diff --git a/tests/pytest/test_boundarylayer.py b/tests/pytest/test_boundarylayer.py index 04c0ee8c..f9310955 100644 --- a/tests/pytest/test_boundarylayer.py +++ b/tests/pytest/test_boundarylayer.py @@ -92,3 +92,18 @@ def test_splitted_surface(): mesh = ngs.Mesh(mesh) assert ngs.Integrate(1, mesh) == pytest.approx(1) assert ngs.Integrate(1, mesh.Materials("slot")) == pytest.approx(0.4) + +@pytest.mark.parametrize("outside", [True, False]) +def test_pyramids(outside): + geo = CSGeometry() + box = OrthoBrick((0,0,0), (1,1,1)) + plate = OrthoBrick((0.3,0.3,0.4),(0.7,0.7,1)) * Plane((0,0,0.6), (0,0,1)).bc("top") + geo.Add((box-plate).mat("air")) + geo.Add(plate.mat("plate")) + mesh = geo.GenerateMesh() + mesh.BoundaryLayer("top", [0.01], "layer", "plate", outside=outside) + ngs = pytest.importorskip("ngsolve") + mesh = ngs.Mesh(mesh) + assert ngs.Integrate(1, mesh.Materials("plate")) == pytest.approx(0.032 if outside else 0.0304) + assert ngs.Integrate(1, mesh.Materials("layer")) == pytest.approx(0.0016) + assert ngs.Integrate(1, mesh.Materials("air")) == pytest.approx(0.9664 if outside else 0.968) From d7a1dda0429d5e84d99bca6cff6bccb985e48cd7 Mon Sep 17 00:00:00 2001 From: mhochsteger Date: Mon, 16 Nov 2020 16:10:46 +0100 Subject: [PATCH 11/24] cmake - add version info to netgen.exe on Windows --- CMakeLists.txt | 2 +- ng/CMakeLists.txt | 13 +++++++------ windows/.gitignore | 1 + windows/CMakeLists.txt | 4 ++++ windows/{netgen.rc => netgen.rc.template} | 12 ++++++------ 5 files changed, 19 insertions(+), 13 deletions(-) create mode 100644 windows/.gitignore rename windows/{netgen.rc => netgen.rc.template} (82%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7916e6ee..9e07e4ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -417,12 +417,12 @@ endif(USE_CGNS) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/netgen_version.hpp ${CMAKE_CURRENT_BINARY_DIR}/netgen_config.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/include COMPONENT netgen_devel) +add_subdirectory(windows) add_subdirectory(libsrc) add_subdirectory(ng) add_subdirectory(tutorials) add_subdirectory(py_tutorials) add_subdirectory(doc) -add_subdirectory(windows) add_subdirectory(nglib) if (USE_PYTHON) add_subdirectory(python) diff --git a/ng/CMakeLists.txt b/ng/CMakeLists.txt index 82d8ea91..82350afc 100644 --- a/ng/CMakeLists.txt +++ b/ng/CMakeLists.txt @@ -4,13 +4,11 @@ else() add_definitions(-DINTERNAL_TCL_DEFAULT=0) endif() -set(netgen_sources ngappinit.cpp onetcl.cpp) if(WIN32) - # add icon to netgen executable - enable_language(RC) - set(netgen_sources ${netgen_sources} ../windows/netgen.rc) - # Don't use ccache here due to incompatibility with the resource compiler - set_directory_properties(PROPERTIES RULE_LAUNCH_COMPILE "") + # add icon and version info to netgen executable + enable_language(RC) + # Don't use ccache here due to incompatibility with the resource compiler + set_directory_properties(PROPERTIES RULE_LAUNCH_COMPILE "") endif(WIN32) if(USE_GUI) @@ -23,6 +21,9 @@ if(USE_GUI) ) add_executable(netgen ngappinit.cpp) + if(WIN32) + target_sources(netgen PRIVATE ../windows/netgen.rc) + endif(WIN32) target_link_libraries( gui PUBLIC nglib ) target_link_libraries( gui PRIVATE ${LIBTOGL} ${ZLIB_LIBRARIES} ${JPEG_LIBRARIES} ${FFMPEG_LIBRARIES} ${X11_Xmu_LIB} ${X11_X11_LIB} ${OCC_LIBRARIES} ) diff --git a/windows/.gitignore b/windows/.gitignore new file mode 100644 index 00000000..73a41fa4 --- /dev/null +++ b/windows/.gitignore @@ -0,0 +1 @@ +netgen.rc diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt index e69de29b..e1ef0a93 100644 --- a/windows/CMakeLists.txt +++ b/windows/CMakeLists.txt @@ -0,0 +1,4 @@ +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/netgen.rc.template" + "${CMAKE_CURRENT_SOURCE_DIR}/netgen.rc" + IMMEDIATE @ONLY) diff --git a/windows/netgen.rc b/windows/netgen.rc.template similarity index 82% rename from windows/netgen.rc rename to windows/netgen.rc.template index 047feb6f..6280e2fa 100644 --- a/windows/netgen.rc +++ b/windows/netgen.rc.template @@ -7,7 +7,7 @@ // // Generated from the TEXTINCLUDE 2 resource. // -#include "afxres.h" +#include ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS @@ -35,8 +35,8 @@ LANGUAGE LANG_GERMAN, SUBLANG_GERMAN // VS_VERSION_INFO VERSIONINFO - FILEVERSION 5,1,0,0 - PRODUCTVERSION 5,1,0,0 + FILEVERSION @NETGEN_VERSION_MAJOR@,@NETGEN_VERSION_MINOR@,@NETGEN_VERSION_PATCH@,@NETGEN_VERSION_TWEAK@ + PRODUCTVERSION @NETGEN_VERSION_MAJOR@,@NETGEN_VERSION_MINOR@,@NETGEN_VERSION_PATCH@,@NETGEN_VERSION_TWEAK@ FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x3L @@ -51,14 +51,14 @@ BEGIN BEGIN BLOCK "040904b0" BEGIN - VALUE "CompanyName", "Vienna UT" + VALUE "CompanyName", "TU Wien" VALUE "FileDescription", "Netgen Meshing Software" - VALUE "FileVersion", "5.1-dev" + VALUE "FileVersion", "@NETGEN_VERSION@" VALUE "InternalName", "Netgen" VALUE "LegalCopyright", "GNU Public License (GPL)" VALUE "OriginalFilename", "Netgen.exe" VALUE "ProductName", "Netgen" - VALUE "ProductVersion", "5.1-dev" + VALUE "ProductVersion", "@NETGEN_VERSION@" END END BLOCK "VarFileInfo" From 2287c5c0c939ecd8434058d22f06673833f85c9f Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Tue, 24 Nov 2020 11:58:26 +0100 Subject: [PATCH 12/24] boundarylayers - fix inverted tets --- libsrc/meshing/boundarylayer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index 0aeb59ec..07bc8dca 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -546,9 +546,9 @@ namespace netgen for(auto& p : nel.PNums()) { if(p == moved[0]) - p = p2; - if(p == fixed[0]) p = p1; + else if(p == fixed[0]) + p = p2; } p1 = p2; mesh.AddVolumeElement(nel); From da4f959a0fd19796c8a92cc88e1b7a79b1e1cfb2 Mon Sep 17 00:00:00 2001 From: mhochsteger Date: Tue, 24 Nov 2020 12:11:27 +0100 Subject: [PATCH 13/24] fix license name in resource file --- windows/netgen.rc.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/netgen.rc.template b/windows/netgen.rc.template index 6280e2fa..bbdab4a7 100644 --- a/windows/netgen.rc.template +++ b/windows/netgen.rc.template @@ -55,7 +55,7 @@ BEGIN VALUE "FileDescription", "Netgen Meshing Software" VALUE "FileVersion", "@NETGEN_VERSION@" VALUE "InternalName", "Netgen" - VALUE "LegalCopyright", "GNU Public License (GPL)" + VALUE "LegalCopyright", "GNU Lesser General Public License (LGPL)" VALUE "OriginalFilename", "Netgen.exe" VALUE "ProductName", "Netgen" VALUE "ProductVersion", "@NETGEN_VERSION@" From efdc57885af52d12f6f33844e9c06f6ead0a282d Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 24 Nov 2020 15:47:25 +0100 Subject: [PATCH 14/24] memory tracing - store parents array instead of children table --- libsrc/core/paje_trace.cpp | 32 ++++++++++---------------------- libsrc/core/profiler.cpp | 4 ++-- libsrc/core/profiler.hpp | 7 ++++--- 3 files changed, 16 insertions(+), 27 deletions(-) diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index 9b4ac053..1a1c9303 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -942,7 +942,7 @@ namespace ngcore size_t imax_mem_allocated = 0; const auto & names = MemoryTracer::GetNames(); - const auto & tree = MemoryTracer::GetTree(); + const auto & parents = MemoryTracer::GetParents(); size_t N = names.size(); Array mem_allocated_id; @@ -1006,39 +1006,27 @@ namespace ngcore Array nodes; nodes.SetSize(N); nodes = nullptr; + Array> children(N); + Array sorting; // topological sorting (parents before children) sorting.SetAllocSize(N); - ArrayMem stack; - - // find root nodes in memory tracer tree, i.e. they have no parents - Array parents; - parents.SetSize(N); - parents = -1; - for( const auto & [iparent, children] : tree ) - for (auto child_id : children) - { - if(parents[child_id] != -1) - std::cerr << "Error in memory tracer: multiple parents found for " << names[child_id] << std::endl; - parents[child_id] = iparent; - } for(auto i : IntRange(1, N)) - if(parents[i]==-1) - { - sorting.Append(i); - if(tree.count(i)) - stack.Append(i); - } + children[parents[i]].Append(i); + + ArrayMem stack; + sorting.Append(0); + stack.Append(0); while(stack.Size()) { auto current = stack.Last(); stack.DeleteLast(); - for(const auto child : tree.at(current)) + for(const auto child : children[current]) { sorting.Append(child); - if(tree.count(child)) + if(children[child].Size()) stack.Append(child); } } diff --git a/libsrc/core/profiler.cpp b/libsrc/core/profiler.cpp index 66365321..33ef98f4 100644 --- a/libsrc/core/profiler.cpp +++ b/libsrc/core/profiler.cpp @@ -114,8 +114,8 @@ namespace ngcore NgProfiler prof; // NOLINT #ifdef NETGEN_TRACE_MEMORY - std::vector MemoryTracer::names{"root"}; - std::map< int, std::vector > MemoryTracer::tree; + std::vector MemoryTracer::names{"all"}; + std::vector MemoryTracer::parents{-1}; #endif // NETGEN_TRACE_MEMORY } // namespace ngcore diff --git a/libsrc/core/profiler.hpp b/libsrc/core/profiler.hpp index cdd945bd..208b7a4e 100644 --- a/libsrc/core/profiler.hpp +++ b/libsrc/core/profiler.hpp @@ -324,12 +324,13 @@ namespace ngcore { #ifdef NETGEN_TRACE_MEMORY NGCORE_API static std::vector names; - NGCORE_API static std::map< int, std::vector > tree; + 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*NgProfiler::SIZE) std::cerr << "Allocated " << id << " MemoryTracer objects" << std::endl; return id; @@ -400,7 +401,7 @@ namespace ngcore void Track( T & obj, const std::string& name ) const { obj.GetMemoryTracer().Activate(obj, name); - tree[id].push_back(obj.GetMemoryTracer().GetId()); + parents[obj.GetMemoryTracer().GetId()] = id; } static std::string GetName(int id) @@ -433,7 +434,7 @@ namespace ngcore static const std::vector & GetNames() { return names; } - static const std::map> & GetTree() { return tree; } + static const std::vector & GetParents() { return parents; } #else // NETGEN_TRACE_MEMORY public: MemoryTracer() {} From b55264e0ee6cf0f29bbddebd27a9ea83ff9bfeac Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 24 Nov 2020 19:20:21 +0100 Subject: [PATCH 15/24] memory tracing - handle multiple consecutive tracers correctly --- libsrc/core/paje_trace.cpp | 33 +++++++++++++++++++++++++++------ libsrc/core/paje_trace.hpp | 3 ++- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index 1a1c9303..bfe3fad0 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -29,6 +29,8 @@ namespace ngcore #endif // PARALLEL } + std::vector PajeTrace::memory_events; + // Produce no traces by default size_t PajeTrace::max_tracefile_size = 0; @@ -75,6 +77,7 @@ namespace ngcore start_time = GetTimeCounter(); tracing_enabled = true; mem_tracing_enabled = true; + n_memory_events_at_start = memory_events.size(); } PajeTrace :: ~PajeTrace() @@ -97,8 +100,8 @@ namespace ngcore for(auto & link : llink) link.time -= start_time; - for(auto & m : memory_events) - m.time -= start_time; + for(auto i : IntRange(n_memory_events_at_start, memory_events.size())) + memory_events[i].time -= start_time; NgMPI_Comm comm(MPI_COMM_WORLD); @@ -451,7 +454,6 @@ namespace ngcore if(mem_tracing_enabled) { variable_type_memory = paje.DefineVariableType( container_type_task_manager, "Memory [MB]" ); - paje.SetVariable( 0, variable_type_memory, container_memory, 0.0 ); } @@ -524,8 +526,23 @@ namespace ngcore paje.PopState( j.stop_time, state_type_job, container_jobs ); } - for(const auto & m : memory_events) + size_t memory_at_start = 0; + + for(const auto & i : IntRange(0, n_memory_events_at_start)) { + if(memory_events[i].is_alloc) + memory_at_start += memory_events[i].size; + else + memory_at_start -= memory_events[i].size; + } + + paje.SetVariable( 0, variable_type_memory, container_memory, 1.0*memory_at_start/(1024*1024)); + + for(const auto & i : IntRange(n_memory_events_at_start, memory_events.size())) + { + auto & m = memory_events[i]; + if(m.size==0) + continue; double size = 1.0*m.size/(1024*1024); if(m.is_alloc) paje.AddVariable( m.time, variable_type_memory, container_memory, size); @@ -958,7 +975,7 @@ namespace ngcore { mem_allocated += ev.size; mem_allocated_id[ev.id] += ev.size; - if(mem_allocated > max_mem_allocated) + if(mem_allocated > max_mem_allocated && i>=n_memory_events_at_start) { imax_mem_allocated = i; max_mem_allocated = mem_allocated; @@ -1006,6 +1023,7 @@ namespace ngcore Array nodes; nodes.SetSize(N); nodes = nullptr; + nodes[0] = &root; Array> children(N); Array sorting; // topological sorting (parents before children) @@ -1033,7 +1051,10 @@ namespace ngcore for(auto i : sorting) { - TreeNode * parent = (parents[i]==-1) ? &root : nodes[parents[i]]; + if(i==0) + continue; + + TreeNode * parent = nodes[parents[i]]; auto & node = parent->children[i]; nodes[i] = &node; diff --git a/libsrc/core/paje_trace.hpp b/libsrc/core/paje_trace.hpp index c153c0cd..5444a96c 100644 --- a/libsrc/core/paje_trace.hpp +++ b/libsrc/core/paje_trace.hpp @@ -28,6 +28,7 @@ namespace ngcore bool tracing_enabled; TTimePoint start_time; int nthreads; + size_t n_memory_events_at_start; public: NGCORE_API void WriteTimingChart(); @@ -119,7 +120,7 @@ namespace ngcore std::vector jobs; std::vector timer_events; std::vector > links; - std::vector memory_events; + NGCORE_API static std::vector memory_events; public: NGCORE_API void StopTracing(); From 91f127ef712af95377bf1a34ac3cacc639229e08 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 25 Nov 2020 14:34:29 +0100 Subject: [PATCH 16/24] memory tracer - fix memory accumulation of children --- libsrc/core/paje_trace.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index bfe3fad0..56fb0c12 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -1068,10 +1068,9 @@ namespace ngcore { // reverse topological order to accumulate total memory usage of all children auto i = sorting[sorting.Size()-1-i_]; - if(parents[i]==-1) - root.size += nodes[i]->size; - else - nodes[parents[i]]->size += nodes[i]->size; + if(i==0) + continue; + nodes[parents[i]]->size += nodes[i]->size; } WriteSunburstHTML( root, fname, false ); From fbeb6137eb14492299d5355080f8ec31388aa191 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 25 Nov 2020 17:55:44 +0100 Subject: [PATCH 17/24] Fix SwapImprove2 Don't allow swaps if an adjacent element was deleted in the current optimization pass. Also update test restults. --- libsrc/meshing/improve3.cpp | 17 ++++- tests/pytest/results.json | 134 ++++++++++++++++++------------------ 2 files changed, 83 insertions(+), 68 deletions(-) diff --git a/libsrc/meshing/improve3.cpp b/libsrc/meshing/improve3.cpp index 3ddc0733..071817e3 100644 --- a/libsrc/meshing/improve3.cpp +++ b/libsrc/meshing/improve3.cpp @@ -3716,6 +3716,18 @@ double MeshOptimize3d :: SwapImprove2 ( Mesh & mesh, OPTIMIZEGOAL goal, ElementI FlatArray row = elementsonnode[pi1]; + for(auto ei : row) + if (mesh[ei].IsDeleted()) return 0.0; + + for(auto ei : elementsonnode[pi2]) + if (mesh[ei].IsDeleted()) return 0.0; + + for(auto ei : elementsonnode[pi3]) + if (mesh[ei].IsDeleted()) return 0.0; + + for(auto ei : elementsonnode[pi4]) + if (mesh[ei].IsDeleted()) return 0.0; + for (int k = 0; k < row.Size(); k++) { ElementIndex eli2 = row[k]; @@ -3723,7 +3735,6 @@ double MeshOptimize3d :: SwapImprove2 ( Mesh & mesh, OPTIMIZEGOAL goal, ElementI if ( eli1 != eli2 ) { Element & elem2 = mesh[eli2]; - if (elem2.IsDeleted()) continue; if (elem2.GetType() != TET) continue; @@ -3992,8 +4003,12 @@ void MeshOptimize3d :: SwapImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) QuickSort(faces_with_improvement); for (auto [dummy, eli,j] : faces_with_improvement) + { + if(mesh[eli].IsDeleted()) + continue; if(SwapImprove2( mesh, goal, eli, j, elementsonnode, belementsonnode, false) < 0.0) cnt++; + } PrintMessage (5, cnt, " swaps performed"); diff --git a/tests/pytest/results.json b/tests/pytest/results.json index 04cb980d..74f0e308 100644 --- a/tests/pytest/results.json +++ b/tests/pytest/results.json @@ -293,18 +293,18 @@ }, { "angles_tet": [ - 14.466, - 161.38 + 16.89, + 158.0 ], "angles_trig": [ - 13.564, - 150.65 + 16.739, + 133.14 ], "ne1d": 32, "ne2d": 220, - "ne3d": 563, - "quality_histogram": "[0, 0, 0, 3, 3, 7, 24, 22, 35, 34, 40, 43, 45, 60, 61, 53, 58, 41, 27, 7]", - "total_badness": 960.07699692 + "ne3d": 551, + "quality_histogram": "[0, 0, 0, 0, 0, 3, 4, 16, 23, 34, 48, 43, 50, 61, 70, 53, 51, 48, 37, 10]", + "total_badness": 860.81905284 }, { "angles_tet": [ @@ -473,7 +473,7 @@ "ne2d": 726, "ne3d": 2167, "quality_histogram": "[0, 4, 17, 35, 75, 117, 114, 112, 77, 51, 58, 86, 115, 177, 248, 293, 239, 204, 118, 27]", - "total_badness": 4176.9278168 + "total_badness": 4176.9284057 }, { "angles_tet": [ @@ -860,18 +860,18 @@ }, { "angles_tet": [ - 16.061, - 157.39 + 8.4923, + 161.34 ], "angles_trig": [ - 16.851, + 20.122, 127.45 ], "ne1d": 36, "ne2d": 152, - "ne3d": 385, - "quality_histogram": "[0, 0, 0, 0, 0, 10, 8, 21, 24, 22, 29, 37, 42, 28, 43, 24, 38, 22, 25, 12]", - "total_badness": 647.21940974 + "ne3d": 358, + "quality_histogram": "[0, 0, 1, 0, 0, 2, 5, 11, 21, 19, 22, 22, 31, 29, 35, 39, 57, 37, 17, 10]", + "total_badness": 559.67849284 }, { "angles_tet": [ @@ -1014,18 +1014,18 @@ }, { "angles_tet": [ - 5.7043, - 170.47 + 5.6074, + 169.95 ], "angles_trig": [ - 8.0227, - 160.66 + 7.5945, + 159.99 ], "ne1d": 0, "ne2d": 192, - "ne3d": 749, - "quality_histogram": "[0, 2, 30, 63, 86, 89, 71, 68, 67, 54, 50, 43, 27, 28, 17, 23, 13, 9, 7, 2]", - "total_badness": 2339.9827516 + "ne3d": 748, + "quality_histogram": "[0, 0, 30, 62, 87, 77, 80, 61, 72, 38, 54, 43, 34, 27, 27, 20, 18, 10, 7, 1]", + "total_badness": 2287.1659209 }, { "angles_tet": [ @@ -1391,9 +1391,9 @@ ], "ne1d": 5988, "ne2d": 11102, - "ne3d": 29343, - "quality_histogram": "[3, 4, 5, 8, 14, 42, 121, 248, 691, 1040, 1542, 2504, 3118, 3920, 4331, 4281, 3366, 2421, 1367, 317]", - "total_badness": 43497.876838 + "ne3d": 29344, + "quality_histogram": "[3, 4, 5, 8, 14, 45, 122, 251, 692, 1044, 1527, 2497, 3115, 3927, 4328, 4293, 3367, 2421, 1363, 318]", + "total_badness": 43503.906462 }, { "angles_tet": [ @@ -1408,7 +1408,7 @@ "ne2d": 23964, "ne3d": 80995, "quality_histogram": "[2, 14, 4, 20, 18, 40, 94, 225, 485, 1115, 2415, 4537, 7493, 10248, 12753, 13190, 12020, 9207, 5660, 1455]", - "total_badness": 111934.52308 + "total_badness": 111934.5334 } ], "hinge.stl": [ @@ -1490,7 +1490,7 @@ { "angles_tet": [ 20.701, - 144.6 + 141.98 ], "angles_trig": [ 22.443, @@ -1498,9 +1498,9 @@ ], "ne1d": 1862, "ne2d": 19474, - "ne3d": 136546, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 12, 59, 281, 864, 2538, 6435, 13014, 21236, 29154, 31109, 24006, 7837]", - "total_badness": 165965.29798 + "ne3d": 136541, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 8, 59, 274, 862, 2533, 6435, 12998, 21248, 29157, 31131, 24003, 7832]", + "total_badness": 165944.59425 } ], "lense.in2d": [ @@ -1795,7 +1795,7 @@ "ne2d": 830, "ne3d": 2488, "quality_histogram": "[0, 0, 3, 37, 71, 155, 161, 102, 158, 211, 284, 276, 249, 203, 195, 139, 108, 79, 42, 15]", - "total_badness": 5146.3098744 + "total_badness": 5146.3098762 }, { "angles_tet": [ @@ -2045,18 +2045,18 @@ }, { "angles_tet": [ - 11.213, - 163.54 + 11.356, + 162.52 ], "angles_trig": [ - 13.446, - 152.87 + 16.741, + 141.37 ], "ne1d": 232, "ne2d": 598, - "ne3d": 1380, - "quality_histogram": "[0, 0, 0, 2, 10, 15, 36, 48, 63, 92, 116, 131, 160, 158, 151, 113, 125, 91, 56, 13]", - "total_badness": 2309.6335564 + "ne3d": 1418, + "quality_histogram": "[0, 0, 0, 2, 9, 14, 27, 47, 66, 97, 109, 150, 161, 159, 147, 133, 119, 96, 66, 16]", + "total_badness": 2344.2576172 }, { "angles_tet": [ @@ -2132,8 +2132,8 @@ "ne1d": 570, "ne2d": 1202, "ne3d": 1839, - "quality_histogram": "[2, 21, 37, 57, 67, 78, 110, 136, 161, 177, 190, 158, 155, 149, 115, 78, 69, 51, 24, 4]", - "total_badness": 4553.9697099 + "quality_histogram": "[2, 21, 37, 57, 66, 75, 111, 134, 161, 173, 193, 158, 151, 145, 117, 81, 73, 54, 25, 5]", + "total_badness": 4538.6020288 }, { "angles_tet": [ @@ -2445,8 +2445,8 @@ }, { "angles_tet": [ - 15.158, - 158.0 + 15.154, + 159.78 ], "angles_trig": [ 17.101, @@ -2454,14 +2454,14 @@ ], "ne1d": 410, "ne2d": 606, - "ne3d": 796, - "quality_histogram": "[0, 0, 0, 0, 1, 3, 5, 6, 28, 40, 56, 62, 82, 83, 128, 96, 88, 75, 29, 14]", - "total_badness": 1204.2331383 + "ne3d": 791, + "quality_histogram": "[0, 0, 0, 0, 2, 3, 4, 7, 33, 42, 54, 61, 88, 86, 118, 92, 89, 72, 29, 11]", + "total_badness": 1208.0636246 }, { "angles_tet": [ 12.907, - 159.86 + 158.51 ], "angles_trig": [ 11.963, @@ -2469,9 +2469,9 @@ ], "ne1d": 510, "ne2d": 1004, - "ne3d": 1838, - "quality_histogram": "[0, 0, 0, 4, 9, 30, 35, 80, 75, 109, 121, 152, 156, 200, 242, 206, 210, 105, 80, 24]", - "total_badness": 3018.9734455 + "ne3d": 1859, + "quality_histogram": "[0, 0, 0, 3, 7, 29, 43, 74, 68, 95, 115, 158, 153, 213, 250, 232, 206, 107, 81, 25]", + "total_badness": 3021.4076425 }, { "angles_tet": [ @@ -2997,18 +2997,18 @@ }, { "angles_tet": [ - 1.6657, - 174.24 + 1.9786, + 173.68 ], "angles_trig": [ - 4.1081, - 164.43 + 3.8198, + 165.45 ], "ne1d": 0, "ne2d": 692, - "ne3d": 2737, - "quality_histogram": "[17, 200, 365, 335, 363, 301, 234, 187, 154, 143, 106, 84, 56, 48, 38, 45, 27, 19, 12, 3]", - "total_badness": 13234.755766 + "ne3d": 2726, + "quality_histogram": "[19, 190, 366, 339, 352, 304, 237, 182, 157, 143, 110, 86, 53, 46, 34, 43, 30, 24, 10, 1]", + "total_badness": 13096.6735 }, { "angles_tet": [ @@ -3365,33 +3365,33 @@ }, { "angles_tet": [ - 19.944, - 152.59 + 20.148, + 153.82 ], "angles_trig": [ 25.599, - 123.4 + 118.3 ], "ne1d": 68, "ne2d": 100, - "ne3d": 130, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 1, 3, 6, 7, 9, 5, 13, 21, 16, 21, 19, 7, 1]", - "total_badness": 187.02414176 + "ne3d": 135, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 0, 4, 5, 2, 9, 5, 18, 25, 16, 22, 20, 7, 1]", + "total_badness": 190.82756065 }, { "angles_tet": [ 12.268, - 164.21 + 164.96 ], "angles_trig": [ - 15.1, - 144.2 + 15.698, + 145.1 ], "ne1d": 102, "ne2d": 238, - "ne3d": 468, - "quality_histogram": "[0, 0, 1, 10, 5, 27, 33, 42, 51, 36, 38, 28, 35, 40, 29, 26, 37, 24, 4, 2]", - "total_badness": 980.42864262 + "ne3d": 471, + "quality_histogram": "[0, 0, 1, 6, 3, 23, 25, 45, 63, 40, 34, 29, 30, 34, 27, 33, 43, 25, 8, 2]", + "total_badness": 950.55701299 }, { "angles_tet": [ From cb0d8295bf9f527edc756cbb4f70c45b54151b57 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Wed, 25 Nov 2020 22:07:07 +0100 Subject: [PATCH 18/24] fix hashing of bitarray (uninitialized value in HashArchive & random values at end) --- libsrc/core/archive.hpp | 2 +- libsrc/core/bitarray.cpp | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/libsrc/core/archive.hpp b/libsrc/core/archive.hpp index 2a006693..d56e3f7f 100644 --- a/libsrc/core/archive.hpp +++ b/libsrc/core/archive.hpp @@ -916,7 +916,7 @@ namespace ngcore class NGCORE_API HashArchive : public Archive { - size_t hash_value; + size_t hash_value = 0; char* h; int offset = 0; public: diff --git a/libsrc/core/bitarray.cpp b/libsrc/core/bitarray.cpp index 6b1deac5..1ddd3435 100644 --- a/libsrc/core/bitarray.cpp +++ b/libsrc/core/bitarray.cpp @@ -141,7 +141,20 @@ namespace ngcore archive & size; if(archive.Input()) SetSize(size); - archive.Do(data, size/CHAR_BIT+1); + if(archive.GetVersion("netgen") < "v6.2.2009-20") + archive.Do(data, size/CHAR_BIT+1); + else + { + archive.NeedsVersion("netgen", "v6.2.2009-20"); + archive.Do(data, size/CHAR_BIT); + for(size_t i = 0; i < size%CHAR_BIT; i++) + { + size_t index = CHAR_BIT * (size/CHAR_BIT) + i; + bool b = Test(index); + archive & b; + b ? SetBit(index) : Clear(index); + } + } } else { From 7ae460b2e526c5e1ac72d3410bac8edb003e532d Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Fri, 27 Nov 2020 15:28:48 +0100 Subject: [PATCH 19/24] Fix .surf file reading. See https://ngsolve.org/forum/ngspy-forum/1275-bug-surf-file-read-incorrectly --- libsrc/interface/readuser.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libsrc/interface/readuser.cpp b/libsrc/interface/readuser.cpp index 29b16afa..f211f38e 100644 --- a/libsrc/interface/readuser.cpp +++ b/libsrc/interface/readuser.cpp @@ -42,12 +42,11 @@ namespace netgen { Point3d p; in >> p.X() >> p.Y() >> p.Z(); - p.Z() *= 10; mesh.AddPoint (p); } mesh.ClearFaceDescriptors(); - mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0)); + mesh.AddFaceDescriptor (FaceDescriptor(1,1,0,0)); in >> nbe; // int invert = globflags.GetDefineFlag ("invertsurfacemesh"); From 1c6051371e24e5b529eb276ebb03a5738cc1a6f6 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 27 Nov 2020 16:40:17 +0100 Subject: [PATCH 20/24] updateSignal for Mesh class --- libsrc/meshing/meshclass.cpp | 1 + libsrc/meshing/meshclass.hpp | 1 + 2 files changed, 2 insertions(+) diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index 66d28355..6234f1eb 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -6642,6 +6642,7 @@ namespace netgen paralleltop->UpdateCoarseGrid(); } #endif + updateSignal.Emit(); } void Mesh :: BuildCurvedElements (const Refinement * ref, int aorder, bool arational) diff --git a/libsrc/meshing/meshclass.hpp b/libsrc/meshing/meshclass.hpp index aab4e87a..3bdaf219 100644 --- a/libsrc/meshing/meshclass.hpp +++ b/libsrc/meshing/meshclass.hpp @@ -172,6 +172,7 @@ namespace netgen const int element) const; public: + Signal<> updateSignal; // store coarse mesh before hp-refinement unique_ptr> hpelements; From 657360818d5dca451e372910ccece2f8203f4311 Mon Sep 17 00:00:00 2001 From: Christoph Wintersteiger Date: Wed, 2 Dec 2020 17:51:47 +0100 Subject: [PATCH 21/24] rewrite loop to avoid index correction --- libsrc/meshing/python_mesh.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index 083ef684..1b1a35a9 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -1136,8 +1136,8 @@ project_boundaries : Optional[str] = None .def ("Scale", [](Mesh & self, double factor) { - for(auto i = 0; i Date: Fri, 4 Dec 2020 14:36:35 +0100 Subject: [PATCH 22/24] add contributors license agreement and contributing guidelines --- CLA.pdf | Bin 0 -> 23494 bytes CONTRIBUTING.md | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 CLA.pdf create mode 100644 CONTRIBUTING.md diff --git a/CLA.pdf b/CLA.pdf new file mode 100644 index 0000000000000000000000000000000000000000..389f1dcdef18ac43b27f0ce9693deb2d27a71157 GIT binary patch literal 23494 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. + +Place a pull request on GitHub. From there we will pull it into our internal testing environment and, if approved, merge it into the main codebase. + +If you have any questions feel free to ask on the [forum](https://ngsolve.com/forum). From e87b238060bdc2314289249b4485b7ef2879d40a Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Fri, 4 Dec 2020 14:38:25 +0100 Subject: [PATCH 23/24] fix links in contributing --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f5bcdbf3..e96b1902 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,7 +3,7 @@ ## Reporting issues -If you have a problem using Netgen/NGSolve consider asking a question in our [forum](https://ngsolve.com/forum). +If you have a problem using Netgen/NGSolve consider asking a question in our [forum](https://ngsolve.org/forum). If you found a bug create an issue in the [Github Issue Tracker](https://github.com/NGSolve/netgen/issues). Please be as specific as possible, issues with a reproducible minimal script will get more attention than unspecific one liners :) @@ -11,8 +11,8 @@ If you found a bug create an issue in the [Github Issue Tracker](https://github. We love and want to encourage community engagement and will review and accept patches and contributions to this project. There are just a few steps to follow: -On your first contribution, to clear any legal questions, we ask you to sign our [Contributor License Agreement](https://github.com/NGSolve/netgen/blob/master/CLA.pdf. Generally you have to sign this only once for Netgen or NGSolve. Please send the signed agreement to . +On your first contribution, to clear any legal questions, we ask you to sign our [Contributor License Agreement](CLA.pdf). Generally you have to sign this only once for Netgen or NGSolve. Please send the signed agreement to . Place a pull request on GitHub. From there we will pull it into our internal testing environment and, if approved, merge it into the main codebase. -If you have any questions feel free to ask on the [forum](https://ngsolve.com/forum). +If you have any questions feel free to ask on the [forum](https://ngsolve.org/forum). From 77c87ba76ece00f4b3cf97d409d844b677ab3245 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Fri, 4 Dec 2020 14:41:56 +0100 Subject: [PATCH 24/24] change script -> failing example --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e96b1902..15bb16b2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,7 +5,7 @@ If you have a problem using Netgen/NGSolve consider asking a question in our [forum](https://ngsolve.org/forum). -If you found a bug create an issue in the [Github Issue Tracker](https://github.com/NGSolve/netgen/issues). Please be as specific as possible, issues with a reproducible minimal script will get more attention than unspecific one liners :) +If you found a bug create an issue in the [Github Issue Tracker](https://github.com/NGSolve/netgen/issues). Please be as specific as possible, issues with a reproducible minimal failing example will get more attention than unspecific one liners :) ## Contributing patches