mirror of
https://github.com/NGSolve/netgen.git
synced 2024-12-24 04:50:34 +05:00
separate memtracer.hpp
This commit is contained in:
parent
85f26ac5fa
commit
a96a1e4624
@ -69,7 +69,7 @@ install(TARGETS ngcore DESTINATION ${NG_INSTALL_DIR} COMPONENT netgen)
|
||||
|
||||
target_link_libraries(ngcore PUBLIC netgen_mpi PRIVATE "$<BUILD_INTERFACE:netgen_python>" ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
install(FILES ngcore.hpp archive.hpp type_traits.hpp version.hpp ngcore_api.hpp logging.hpp
|
||||
install(FILES ngcore.hpp archive.hpp type_traits.hpp version.hpp ngcore_api.hpp logging.hpp memtracer.hpp
|
||||
exception.hpp symboltable.hpp paje_trace.hpp utils.hpp profiler.hpp mpi_wrapper.hpp
|
||||
array.hpp taskmanager.hpp concurrentqueue.h localheap.hpp python_ngcore.hpp flags.hpp
|
||||
xbool.hpp signal.hpp bitarray.hpp table.hpp hashtable.hpp ranges.hpp
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "archive.hpp"
|
||||
#include "exception.hpp"
|
||||
#include "localheap.hpp"
|
||||
#include "profiler.hpp"
|
||||
#include "memtracer.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
namespace ngcore
|
||||
|
174
libsrc/core/memtracer.hpp
Normal file
174
libsrc/core/memtracer.hpp
Normal file
@ -0,0 +1,174 @@
|
||||
#ifndef NETGEN_CORE_MEMTRACER_HPP
|
||||
#define NETGEN_CORE_MEMTRACER_HPP
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include "array.hpp"
|
||||
#include "logging.hpp"
|
||||
#include "paje_trace.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
namespace ngcore
|
||||
{
|
||||
|
||||
class MemoryTracer;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
//Type trait to check if a class implements a 'void SetMemoryTacing(int)' function
|
||||
template<typename T>
|
||||
struct has_StartMemoryTracing
|
||||
{
|
||||
private:
|
||||
template<typename T2>
|
||||
static constexpr auto check(T2*) ->
|
||||
typename std::is_same<decltype(std::declval<T2>().StartMemoryTracing()),void>::type;
|
||||
template<typename>
|
||||
static constexpr std::false_type check(...);
|
||||
using type = decltype(check<T>(nullptr)); // NOLINT
|
||||
public:
|
||||
static constexpr bool value = type::value;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
class MemoryTracer
|
||||
{
|
||||
#ifdef NETGEN_TRACE_MEMORY
|
||||
NGCORE_API static std::vector<std::string> names;
|
||||
NGCORE_API static std::vector<int> parents;
|
||||
|
||||
static int CreateId(const std::string& name)
|
||||
{
|
||||
int id = names.size();
|
||||
names.push_back(name);
|
||||
parents.push_back(0);
|
||||
if(id==10*8*1024)
|
||||
std::cerr << "Allocated " << id << " MemoryTracer objects" << std::endl;
|
||||
return id;
|
||||
}
|
||||
int id;
|
||||
|
||||
public:
|
||||
|
||||
MemoryTracer( std::string name )
|
||||
{
|
||||
id = CreateId(name);
|
||||
}
|
||||
|
||||
// not tracing
|
||||
MemoryTracer() : id(0) {}
|
||||
|
||||
template <typename... TRest>
|
||||
MemoryTracer( std::string name, TRest & ... rest )
|
||||
{
|
||||
id = CreateId(name);
|
||||
Track(rest...);
|
||||
}
|
||||
|
||||
NETGEN_INLINE void Alloc(size_t size) const
|
||||
{
|
||||
if(id && trace)
|
||||
trace->AllocMemory(id, size);
|
||||
}
|
||||
|
||||
void Free(size_t size) const
|
||||
{
|
||||
if(id && trace)
|
||||
trace->FreeMemory(id, size);
|
||||
}
|
||||
|
||||
void Swap(size_t mysize, MemoryTracer& other, size_t other_size) const
|
||||
{
|
||||
if(!trace || (id == 0 && other.id == 0))
|
||||
return;
|
||||
if(id == 0)
|
||||
return trace->ChangeMemory(other.id, mysize - other_size);
|
||||
if(other.id == 0)
|
||||
return trace->ChangeMemory(id, other_size - mysize);
|
||||
|
||||
// first decrease memory, otherwise have artificial/wrong high peak memory usage
|
||||
if(mysize<other_size)
|
||||
{
|
||||
trace->ChangeMemory(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 <typename T1, typename... TRest>
|
||||
void Track( T1 & obj, const std::string& name, TRest & ... rest ) const
|
||||
{
|
||||
Track(obj, name);
|
||||
Track(rest...);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Track( T & obj, const std::string& name ) const
|
||||
{
|
||||
obj.GetMemoryTracer().Activate(obj, name);
|
||||
parents[obj.GetMemoryTracer().GetId()] = id;
|
||||
}
|
||||
|
||||
static std::string GetName(int id)
|
||||
{
|
||||
return names[id];
|
||||
}
|
||||
|
||||
std::string GetName() const
|
||||
{
|
||||
return names[id];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Activate(T& me, const std::string& name) const
|
||||
{
|
||||
if(!id)
|
||||
{
|
||||
const_cast<MemoryTracer*>(this)->id = CreateId(name);
|
||||
if constexpr(detail::has_StartMemoryTracing<T>::value)
|
||||
me.StartMemoryTracing();
|
||||
}
|
||||
else
|
||||
SetName(name);
|
||||
}
|
||||
|
||||
void SetName(const std::string& name) const
|
||||
{
|
||||
names[id] = name;
|
||||
}
|
||||
|
||||
|
||||
static const std::vector<std::string> & GetNames() { return names; }
|
||||
static const std::vector<int> & GetParents() { return parents; }
|
||||
#else // NETGEN_TRACE_MEMORY
|
||||
public:
|
||||
MemoryTracer() {}
|
||||
MemoryTracer( std::string /* name */ ) {}
|
||||
template <typename... TRest>
|
||||
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 <typename... TRest>
|
||||
void Track(TRest&...) const {}
|
||||
|
||||
static std::string GetName(int /* id */) { return ""; }
|
||||
std::string GetName() const { return ""; }
|
||||
void SetName(std::string /* name */) const {}
|
||||
#endif // NETGEN_TRACE_MEMORY
|
||||
};
|
||||
} // namespace ngcore
|
||||
|
||||
#endif // NETGEN_CORE_MEMTRACER_HPP
|
@ -6,8 +6,10 @@
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include "array.hpp"
|
||||
#include "logging.hpp"
|
||||
#include "paje_trace.hpp"
|
||||
#include "taskmanager.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
namespace ngcore
|
||||
@ -300,161 +302,6 @@ namespace ngcore
|
||||
return tres;
|
||||
}
|
||||
|
||||
class MemoryTracer;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
//Type trait to check if a class implements a 'void SetMemoryTacing(int)' function
|
||||
template<typename T>
|
||||
struct has_StartMemoryTracing
|
||||
{
|
||||
private:
|
||||
template<typename T2>
|
||||
static constexpr auto check(T2*) ->
|
||||
typename std::is_same<decltype(std::declval<T2>().StartMemoryTracing()),void>::type;
|
||||
template<typename>
|
||||
static constexpr std::false_type check(...);
|
||||
using type = decltype(check<T>(nullptr)); // NOLINT
|
||||
public:
|
||||
static constexpr bool value = type::value;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
class MemoryTracer
|
||||
{
|
||||
#ifdef NETGEN_TRACE_MEMORY
|
||||
NGCORE_API static std::vector<std::string> names;
|
||||
NGCORE_API static std::vector<int> 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;
|
||||
}
|
||||
int id;
|
||||
|
||||
public:
|
||||
|
||||
MemoryTracer( std::string name )
|
||||
{
|
||||
id = CreateId(name);
|
||||
}
|
||||
|
||||
// not tracing
|
||||
MemoryTracer() : id(0) {}
|
||||
|
||||
template <typename... TRest>
|
||||
MemoryTracer( std::string name, TRest & ... rest )
|
||||
{
|
||||
id = CreateId(name);
|
||||
Track(rest...);
|
||||
}
|
||||
|
||||
NETGEN_INLINE void Alloc(size_t size) const
|
||||
{
|
||||
if(id && trace)
|
||||
trace->AllocMemory(id, size);
|
||||
}
|
||||
|
||||
void Free(size_t size) const
|
||||
{
|
||||
if(id && trace)
|
||||
trace->FreeMemory(id, size);
|
||||
}
|
||||
|
||||
void Swap(size_t mysize, MemoryTracer& other, size_t other_size) const
|
||||
{
|
||||
if(!trace || (id == 0 && other.id == 0))
|
||||
return;
|
||||
if(id == 0)
|
||||
return trace->ChangeMemory(other.id, mysize - other_size);
|
||||
if(other.id == 0)
|
||||
return trace->ChangeMemory(id, other_size - mysize);
|
||||
|
||||
// first decrease memory, otherwise have artificial/wrong high peak memory usage
|
||||
if(mysize<other_size)
|
||||
{
|
||||
trace->ChangeMemory(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 <typename T1, typename... TRest>
|
||||
void Track( T1 & obj, const std::string& name, TRest & ... rest ) const
|
||||
{
|
||||
Track(obj, name);
|
||||
Track(rest...);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Track( T & obj, const std::string& name ) const
|
||||
{
|
||||
obj.GetMemoryTracer().Activate(obj, name);
|
||||
parents[obj.GetMemoryTracer().GetId()] = id;
|
||||
}
|
||||
|
||||
static std::string GetName(int id)
|
||||
{
|
||||
return names[id];
|
||||
}
|
||||
|
||||
std::string GetName() const
|
||||
{
|
||||
return names[id];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Activate(T& me, const std::string& name) const
|
||||
{
|
||||
if(!id)
|
||||
{
|
||||
const_cast<MemoryTracer*>(this)->id = CreateId(name);
|
||||
if constexpr(detail::has_StartMemoryTracing<T>::value)
|
||||
me.StartMemoryTracing();
|
||||
}
|
||||
else
|
||||
SetName(name);
|
||||
}
|
||||
|
||||
void SetName(const std::string& name) const
|
||||
{
|
||||
names[id] = name;
|
||||
}
|
||||
|
||||
|
||||
static const std::vector<std::string> & GetNames() { return names; }
|
||||
static const std::vector<int> & GetParents() { return parents; }
|
||||
#else // NETGEN_TRACE_MEMORY
|
||||
public:
|
||||
MemoryTracer() {}
|
||||
MemoryTracer( std::string /* name */ ) {}
|
||||
template <typename... TRest>
|
||||
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 <typename... TRest>
|
||||
void Track(TRest&...) const {}
|
||||
|
||||
static std::string GetName(int /* id */) { return ""; }
|
||||
std::string GetName() const { return ""; }
|
||||
void SetName(std::string /* name */) const {}
|
||||
#endif // NETGEN_TRACE_MEMORY
|
||||
};
|
||||
} // namespace ngcore
|
||||
|
||||
// Helper macro to easily add multiple timers in a function for profiling
|
||||
|
@ -13,8 +13,10 @@
|
||||
|
||||
#include "array.hpp"
|
||||
#include "bitarray.hpp"
|
||||
#include "taskmanager.hpp"
|
||||
#include "memtracer.hpp"
|
||||
#include "ngcore_api.hpp"
|
||||
#include "profiler.hpp"
|
||||
#include "taskmanager.hpp"
|
||||
|
||||
namespace ngcore
|
||||
{
|
||||
@ -672,6 +674,69 @@ namespace ngcore
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
// Helper function to calculate coloring of a set of indices for parallel processing of independent elements/points/etc.
|
||||
// Assigns a color to each of colors.Size() elements, such that two elements with the same color don't share a common 'dof',
|
||||
// the mapping from element to dofs is provided by the function getDofs(int) -> iterable<int>
|
||||
//
|
||||
// Returns the number of used colors
|
||||
template <typename Tmask>
|
||||
int ComputeColoring( FlatArray<int> colors, size_t ndofs, Tmask const & getDofs)
|
||||
{
|
||||
static Timer timer("ComputeColoring - "+Demangle(typeid(Tmask).name())); RegionTimer rt(timer);
|
||||
static_assert(sizeof(unsigned int)==4, "Adapt type of mask array");
|
||||
size_t n = colors.Size();
|
||||
|
||||
Array<unsigned int> mask(ndofs);
|
||||
|
||||
size_t colored_blocks = 0;
|
||||
|
||||
// We are coloring with 32 colors at once and use each bit to mask conflicts
|
||||
unsigned int check = 0;
|
||||
unsigned int checkbit = 0;
|
||||
|
||||
int current_color = 0;
|
||||
colors = -1;
|
||||
int maxcolor = 0;
|
||||
|
||||
while(colored_blocks<n)
|
||||
{
|
||||
mask = 0;
|
||||
for (auto i : Range(n) )
|
||||
{
|
||||
if(colors[i]>-1) continue;
|
||||
check = 0;
|
||||
const auto & dofs = getDofs(i);
|
||||
|
||||
// Check if adjacent dofs are already marked by current color
|
||||
for (auto dof : dofs)
|
||||
check|=mask[dof];
|
||||
|
||||
// Did we find a free color?
|
||||
if(check != 0xFFFFFFFF)
|
||||
{
|
||||
checkbit = 1;
|
||||
int color = current_color;
|
||||
// find the actual color, which is free (out of 32)
|
||||
while (check & checkbit)
|
||||
{
|
||||
color++;
|
||||
checkbit *= 2;
|
||||
}
|
||||
colors[i] = color;
|
||||
maxcolor = color > maxcolor ? color : maxcolor;
|
||||
colored_blocks++;
|
||||
// mask all adjacent dofs with the found color
|
||||
for (auto dof : dofs)
|
||||
mask[dof] |= checkbit;
|
||||
}
|
||||
}
|
||||
current_color+=32;
|
||||
}
|
||||
return maxcolor+1;
|
||||
}
|
||||
|
||||
|
||||
typedef DynamicTable<int> IntTable;
|
||||
|
||||
} // namespace ngcore
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
#include "array.hpp"
|
||||
#include "paje_trace.hpp"
|
||||
#include "profiler.hpp"
|
||||
#include "taskmanager.hpp"
|
||||
|
||||
#ifdef USE_NUMA
|
||||
#include <numa.h>
|
||||
@ -1058,68 +1058,6 @@ public:
|
||||
|
||||
#endif // USE_NUMA
|
||||
|
||||
// Helper function to calculate coloring of a set of indices for parallel processing of independent elements/points/etc.
|
||||
// Assigns a color to each of colors.Size() elements, such that two elements with the same color don't share a common 'dof',
|
||||
// the mapping from element to dofs is provided by the function getDofs(int) -> iterable<int>
|
||||
//
|
||||
// Returns the number of used colors
|
||||
template <typename Tmask>
|
||||
int ComputeColoring( FlatArray<int> colors, size_t ndofs, Tmask const & getDofs)
|
||||
{
|
||||
static Timer timer("ComputeColoring - "+Demangle(typeid(Tmask).name())); RegionTimer rt(timer);
|
||||
static_assert(sizeof(unsigned int)==4, "Adapt type of mask array");
|
||||
size_t n = colors.Size();
|
||||
|
||||
Array<unsigned int> mask(ndofs);
|
||||
|
||||
size_t colored_blocks = 0;
|
||||
|
||||
// We are coloring with 32 colors at once and use each bit to mask conflicts
|
||||
unsigned int check = 0;
|
||||
unsigned int checkbit = 0;
|
||||
|
||||
int current_color = 0;
|
||||
colors = -1;
|
||||
int maxcolor = 0;
|
||||
|
||||
while(colored_blocks<n)
|
||||
{
|
||||
mask = 0;
|
||||
for (auto i : Range(n) )
|
||||
{
|
||||
if(colors[i]>-1) continue;
|
||||
check = 0;
|
||||
const auto & dofs = getDofs(i);
|
||||
|
||||
// Check if adjacent dofs are already marked by current color
|
||||
for (auto dof : dofs)
|
||||
check|=mask[dof];
|
||||
|
||||
// Did we find a free color?
|
||||
if(check != 0xFFFFFFFF)
|
||||
{
|
||||
checkbit = 1;
|
||||
int color = current_color;
|
||||
// find the actual color, which is free (out of 32)
|
||||
while (check & checkbit)
|
||||
{
|
||||
color++;
|
||||
checkbit *= 2;
|
||||
}
|
||||
colors[i] = color;
|
||||
maxcolor = color > maxcolor ? color : maxcolor;
|
||||
colored_blocks++;
|
||||
// mask all adjacent dofs with the found color
|
||||
for (auto dof : dofs)
|
||||
mask[dof] |= checkbit;
|
||||
}
|
||||
}
|
||||
current_color+=32;
|
||||
}
|
||||
return maxcolor+1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user