first attempt on memory tracing

This commit is contained in:
Matthias Hochsteger 2020-11-18 20:20:35 +01:00
parent c58659883d
commit 1a93fb3fa5
7 changed files with 183 additions and 4 deletions

View File

@ -11,6 +11,7 @@
#include "archive.hpp" #include "archive.hpp"
#include "exception.hpp" #include "exception.hpp"
#include "localheap.hpp" #include "localheap.hpp"
#include "profiler.hpp"
#include "utils.hpp" #include "utils.hpp"
namespace ngcore namespace ngcore
@ -654,6 +655,8 @@ namespace ngcore
/// that's the data we have to delete, nullptr for not owning the memory /// that's the data we have to delete, nullptr for not owning the memory
T * mem_to_delete; T * mem_to_delete;
int mem_tracing_id = 0;
using FlatArray<T,IndexType>::size; using FlatArray<T,IndexType>::size;
using FlatArray<T,IndexType>::data; using FlatArray<T,IndexType>::data;
using FlatArray<T,IndexType>::BASE; using FlatArray<T,IndexType>::BASE;
@ -1038,6 +1041,18 @@ namespace ngcore
ngcore::Swap (data, b.data); ngcore::Swap (data, b.data);
ngcore::Swap (allocsize, b.allocsize); ngcore::Swap (allocsize, b.allocsize);
ngcore::Swap (mem_to_delete, b.mem_to_delete); 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: private:
@ -1053,6 +1068,8 @@ namespace ngcore
{ {
size_t nsize = 2 * allocsize; size_t nsize = 2 * allocsize;
if (nsize < minsize) nsize = minsize; if (nsize < minsize) nsize = minsize;
TraceMemoryAlloc(mem_tracing_id, sizeof(T)*nsize );
T * hdata = data; T * hdata = data;
data = new T[nsize]; data = new T[nsize];
@ -1069,6 +1086,7 @@ namespace ngcore
for (size_t i = 0; i < mins; i++) data[i] = std::move(hdata[i]); for (size_t i = 0; i < mins; i++) data[i] = std::move(hdata[i]);
#endif #endif
delete [] mem_to_delete; delete [] mem_to_delete;
TraceMemoryFree( mem_tracing_id, sizeof(T)*allocsize );
} }
mem_to_delete = data; mem_to_delete = data;

View File

@ -36,6 +36,7 @@ namespace ngcore
// increases trace by a factor of two // increases trace by a factor of two
bool PajeTrace::trace_thread_counter = false; bool PajeTrace::trace_thread_counter = false;
bool PajeTrace::trace_threads = true; bool PajeTrace::trace_threads = true;
bool PajeTrace::mem_tracing_enabled = true;
PajeTrace :: PajeTrace(int anthreads, std::string aname) PajeTrace :: PajeTrace(int anthreads, std::string aname)
{ {
@ -62,6 +63,7 @@ namespace ngcore
jobs.reserve(reserve_size); jobs.reserve(reserve_size);
timer_events.reserve(reserve_size); timer_events.reserve(reserve_size);
memory_events.reserve(1024*1024);
// sync start time when running in parallel // sync start time when running in parallel
#ifdef PARALLEL #ifdef PARALLEL
@ -72,6 +74,7 @@ namespace ngcore
start_time = GetTimeCounter(); start_time = GetTimeCounter();
tracing_enabled = true; tracing_enabled = true;
mem_tracing_enabled = true;
} }
PajeTrace :: ~PajeTrace() PajeTrace :: ~PajeTrace()
@ -94,6 +97,9 @@ namespace ngcore
for(auto & link : llink) for(auto & link : llink)
link.time -= start_time; link.time -= start_time;
for(auto & m : memory_events)
m.time -= start_time;
NgMPI_Comm comm(MPI_COMM_WORLD); NgMPI_Comm comm(MPI_COMM_WORLD);
if(comm.Size()==1) 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_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_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_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_job = paje.DefineStateType( container_type_jobs, "Job" );
const int state_type_task = paje.DefineStateType( container_type_thread, "Task" ); const int state_type_task = paje.DefineStateType( container_type_thread, "Task" );
@ -433,12 +440,20 @@ namespace ngcore
int variable_type_active_threads = 0; int variable_type_active_threads = 0;
if(trace_thread_counter) 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_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" ); 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; int num_nodes = 1; //task_manager ? task_manager->GetNumNodes() : 1;
std::vector <int> thread_aliases; std::vector <int> thread_aliases;
@ -509,6 +524,14 @@ namespace ngcore
paje.PopState( j.stop_time, state_type_job, container_jobs ); 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<int> timer_ids; std::set<int> timer_ids;
std::map<int,int> timer_aliases; std::map<int,int> timer_aliases;
std::map<int,std::string> timer_names; std::map<int,std::string> timer_names;

View File

@ -23,6 +23,7 @@ namespace ngcore
NGCORE_API static size_t max_tracefile_size; NGCORE_API static size_t max_tracefile_size;
NGCORE_API static bool trace_thread_counter; NGCORE_API static bool trace_thread_counter;
NGCORE_API static bool trace_threads; NGCORE_API static bool trace_threads;
NGCORE_API static bool mem_tracing_enabled;
bool tracing_enabled; bool tracing_enabled;
TTimePoint start_time; TTimePoint start_time;
@ -35,6 +36,11 @@ namespace ngcore
// be stopped if any thread reaches this number of events // be stopped if any thread reaches this number of events
unsigned int max_num_events_per_thread; unsigned int max_num_events_per_thread;
static void SetTraceMemory( bool trace_memory )
{
mem_tracing_enabled = trace_memory;
}
static void SetTraceThreads( bool atrace_threads ) static void SetTraceThreads( bool atrace_threads )
{ {
trace_threads = atrace_threads; trace_threads = atrace_threads;
@ -96,10 +102,21 @@ namespace ngcore
bool operator < (const ThreadLink & other) const { return time < other.time; } 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<std::vector<Task> > tasks; std::vector<std::vector<Task> > tasks;
std::vector<Job> jobs; std::vector<Job> jobs;
std::vector<TimerEvent> timer_events; std::vector<TimerEvent> timer_events;
std::vector<std::vector<ThreadLink> > links; std::vector<std::vector<ThreadLink> > links;
std::vector<MemoryEvent> memory_events;
public: public:
NGCORE_API void StopTracing(); NGCORE_API void StopTracing();
@ -129,6 +146,27 @@ namespace ngcore
timer_events.push_back(TimerEvent{timer_id, GetTimeCounter(), false}); 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) NETGEN_INLINE int StartTask(int thread_id, int id, int id_type = Task::ID_NONE, int additional_value = -1)
{ {
if(!tracing_enabled) return -1; if(!tracing_enabled) return -1;

View File

@ -113,5 +113,7 @@ namespace ngcore
NgProfiler prof; // NOLINT NgProfiler prof; // NOLINT
std::vector<std::string> MemoryTracer::names{"root"};
std::map< int, std::vector<int> > MemoryTracer::tree;
} // namespace ngcore } // namespace ngcore

View File

@ -3,6 +3,7 @@
#include <array> #include <array>
#include <chrono> #include <chrono>
#include <functional>
#include <string> #include <string>
#include "logging.hpp" #include "logging.hpp"
@ -299,6 +300,92 @@ namespace ngcore
return tres; return tres;
} }
class MemoryTracer
{
NGCORE_API static std::vector<std::string> 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<int> > tree;
int id;
std::vector<std::function<void()>> tracks;
public:
MemoryTracer( std::string name )
{
id = GetId(name);
}
template <typename... TRest>
MemoryTracer( std::string name, TRest & ... rest )
{
id = GetId(name);
Track(rest...);
}
template <typename T1, typename... TRest>
void Track( T1 & obj, std::string name, TRest & ... rest )
{
Track(obj, name);
Track(rest...);
}
template<typename T>
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<typename T>
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 } // namespace ngcore
// Helper macro to easily add multiple timers in a function for profiling // Helper macro to easily add multiple timers in a function for profiling

View File

@ -247,15 +247,17 @@ threads : int
; ;
py::class_<PajeTrace>(m, "PajeTrace") py::class_<PajeTrace>(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::SetMaxTracefileSize(size_mb*1014*1024);
PajeTrace::SetTraceThreads(threads); PajeTrace::SetTraceThreads(threads);
PajeTrace::SetTraceMemory(memory);
PajeTrace::SetTraceThreadCounter(thread_counter); PajeTrace::SetTraceThreadCounter(thread_counter);
trace = new PajeTrace(TaskManager::GetMaxThreads(), filename); trace = new PajeTrace(TaskManager::GetMaxThreads(), filename);
return trace; return trace;
}), py::arg("filename")="ng.trace", py::arg("size")=1000, }), py::arg("filename")="ng.trace", py::arg("size")=1000,
py::arg("threads")=true, py::arg("thread_counter")=false, py::arg("threads")=true, py::arg("thread_counter")=false,
py::arg("memory")=true,
"size in Megabytes" "size in Megabytes"
) )
.def("__enter__", [](PajeTrace & self) { }) .def("__enter__", [](PajeTrace & self) { })

View File

@ -925,6 +925,15 @@ namespace netgen
shared_ptr<Mesh> Mirror( netgen::Point<3> p, Vec<3> n ); shared_ptr<Mesh> 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) inline ostream& operator<<(ostream& ost, const Mesh& mesh)