1 #ifndef NETGEN_CORE_MEMTRACER_HPP
2 #define NETGEN_CORE_MEMTRACER_HPP
3 
4 #include <array>
5 #include <chrono>
6 #include <functional>
7 #include <string>
8 
9 #include "array.hpp"
10 #include "logging.hpp"
11 #include "paje_trace.hpp"
12 #include "utils.hpp"
13 
14 namespace ngcore
15 {
16 
17   class MemoryTracer;
18 
19   namespace detail
20   {
21     //Type trait to check if a class implements a 'void SetMemoryTacing(int)' function
22     template<typename T>
23     struct has_StartMemoryTracing
24     {
25     private:
26       template<typename T2>
27       static constexpr auto check(T2*) ->
28         typename std::is_same<decltype(std::declval<T2>().StartMemoryTracing()),void>::type;
29       template<typename>
30       static constexpr std::false_type check(...);
31       using type = decltype(check<T>(nullptr)); // NOLINT
32     public:
33       static constexpr bool value = type::value;
34     };
35   } // namespace detail
36 
37   class MemoryTracer
38   {
39     #ifdef NETGEN_TRACE_MEMORY
40     NGCORE_API static std::vector<std::string> names;
41     NGCORE_API static std::vector<int> parents;
42 
CreateId(const std::string & name)43     static int CreateId(const std::string& name)
44     {
45       int id = names.size();
46       names.push_back(name);
47       parents.push_back(0);
48       if(id==10*8*1024)
49         std::cerr << "Allocated " << id << " MemoryTracer objects" << std::endl;
50       return id;
51     }
52     int id;
53 
54     public:
55 
MemoryTracer(std::string name)56     MemoryTracer( std::string name )
57     {
58       id = CreateId(name);
59     }
60 
61     // not tracing
MemoryTracer()62     MemoryTracer() : id(0) {}
63 
64     template <typename... TRest>
MemoryTracer(std::string name,TRest &...rest)65     MemoryTracer( std::string name, TRest & ... rest )
66     {
67       id = CreateId(name);
68       Track(rest...);
69     }
70 
Alloc(size_t size) const71     NETGEN_INLINE void Alloc(size_t size) const
72     {
73       if(id && trace)
74         trace->AllocMemory(id, size);
75     }
76 
Free(size_t size) const77     void Free(size_t size) const
78     {
79       if(id && trace)
80         trace->FreeMemory(id, size);
81     }
82 
Swap(size_t mysize,MemoryTracer & other,size_t other_size) const83     void Swap(size_t mysize, MemoryTracer& other, size_t other_size) const
84     {
85       if(!trace || (id == 0 && other.id == 0))
86         return;
87       if(id == 0)
88         return trace->ChangeMemory(other.id, mysize - other_size);
89       if(other.id == 0)
90         return trace->ChangeMemory(id, other_size - mysize);
91 
92       // first decrease memory, otherwise have artificial/wrong high peak memory usage
93       if(mysize<other_size)
94         {
95           trace->ChangeMemory(other.id, mysize-other_size);
96           trace->ChangeMemory(id, other_size-mysize);
97         }
98       else
99         {
100           trace->ChangeMemory(id, other_size-mysize);
101           trace->ChangeMemory(other.id, mysize-other_size);
102         }
103     }
104 
GetId() const105     int GetId() const { return id; }
106 
107     template <typename T1, typename... TRest>
Track(T1 & obj,const std::string & name,TRest &...rest) const108     void Track( T1 & obj, const std::string& name, TRest & ... rest ) const
109     {
110       Track(obj, name);
111       Track(rest...);
112     }
113 
114     template<typename T>
Track(T & obj,const std::string & name) const115     void Track( T & obj, const std::string& name ) const
116     {
117       obj.GetMemoryTracer().Activate(obj, name);
118       parents[obj.GetMemoryTracer().GetId()] = id;
119     }
120 
GetName(int id)121     static std::string GetName(int id)
122     {
123       return names[id];
124     }
125 
GetName() const126     std::string GetName() const
127     {
128       return names[id];
129     }
130 
131     template<typename T>
Activate(T & me,const std::string & name) const132     void Activate(T& me, const std::string& name) const
133     {
134       if(!id)
135         {
136           const_cast<MemoryTracer*>(this)->id = CreateId(name);
137           if constexpr(detail::has_StartMemoryTracing<T>::value)
138             me.StartMemoryTracing();
139         }
140       else
141         SetName(name);
142     }
143 
SetName(const std::string & name) const144     void SetName(const std::string& name) const
145     {
146       names[id] = name;
147     }
148 
149 
GetNames()150     static const std::vector<std::string> & GetNames() { return names; }
GetParents()151     static const std::vector<int> & GetParents() { return parents; }
152 #else // NETGEN_TRACE_MEMORY
153   public:
154     MemoryTracer() {}
155     MemoryTracer( std::string /* name */ ) {}
156     template <typename... TRest>
157     MemoryTracer( std::string /* name */, TRest & ... ) {}
158 
159     void Alloc(size_t /* size */) const {}
160     void Free(size_t /* size */) const {}
161     void Swap(...) const {}
162     int GetId() const { return 0; }
163 
164     template <typename... TRest>
165     void Track(TRest&...) const {}
166 
167     static std::string GetName(int /* id */) { return ""; }
168     std::string GetName() const { return ""; }
169     void SetName(std::string /* name */) const {}
170 #endif // NETGEN_TRACE_MEMORY
171   };
172 } // namespace ngcore
173 
174 #endif // NETGEN_CORE_MEMTRACER_HPP
175