FML
Public Member Functions | Static Public Member Functions
FML::MemoryLog Class Reference

Logs all heap allocations in the code that are larger than min_bytes_to_log. More...

#include <MemoryLogging.h>

Public Member Functions

 MemoryLog (const MemoryLog &arg)=delete
 
 MemoryLog (const MemoryLog &&arg)=delete
 
MemoryLogoperator= (const MemoryLog &arg)=delete
 
MemoryLogoperator= (const MemoryLog &&arg)=delete
 
void add_label (void *ptr, std::string name)
 
void add_label (void *ptr, size_t size, std::string name)
 
void add (void *ptr, size_t size)
 
void clear ()
 
void remove (void *ptr, size_t size)
 
void print ()
 

Static Public Member Functions

static MemoryLogget ()
 

Detailed Description

Logs all heap allocations in the code that are larger than min_bytes_to_log.

Implemented as a singleton so only one instance of this object exists. Thread safe.

Definition at line 45 of file MemoryLogging.h.

Constructor & Destructor Documentation

◆ MemoryLog() [1/2]

FML::MemoryLog::MemoryLog ( const MemoryLog arg)
delete

◆ MemoryLog() [2/2]

FML::MemoryLog::MemoryLog ( const MemoryLog &&  arg)
delete

Member Function Documentation

◆ add()

void FML::MemoryLog::add ( void *  ptr,
size_t  size 
)
inline

Definition at line 115 of file MemoryLogging.h.

115 {
116 if (stop_logging or size < min_bytes_to_log)
117 return;
118 std::lock_guard<std::mutex> guard(mymutex);
119 allocations[ptr] = size;
120
121 memory_in_use += size;
122 if (memory_in_use > peak_memory_use)
123 peak_memory_use = memory_in_use;
124
125 auto time = std::chrono::steady_clock::now();
126 memory_vs_time[time] = memory_in_use;
127 nallocation++;
128
129 // If we have saturated then stop logging
130 stop_logging = nallocation >= max_allocations_to_log;
131 }

◆ add_label() [1/2]

void FML::MemoryLog::add_label ( void *  ptr,
size_t  size,
std::string  name 
)
inline

Definition at line 109 of file MemoryLogging.h.

109 {
110 if (stop_logging or size < min_bytes_to_log)
111 return;
112 add_label(ptr, name);
113 }
void add_label(void *ptr, std::string name)
Definition: MemoryLogging.h:98

◆ add_label() [2/2]

void FML::MemoryLog::add_label ( void *  ptr,
std::string  name 
)
inline

Definition at line 98 of file MemoryLogging.h.

98 {
99 if (stop_logging)
100 return;
101 if (allocations.find(ptr) == allocations.end()) {
102 std::cout << "[MemoryLogging] Warning could not find pointer in allocation list to add label " + name +
103 " to\n";
104 return;
105 }
106 std::lock_guard<std::mutex> guard(mymutex);
107 labels[ptr] = name;
108 }

◆ clear()

void FML::MemoryLog::clear ( )
inline

Definition at line 133 of file MemoryLogging.h.

133 {
134 allocations.clear();
135 memory_vs_time.clear();
136 }

◆ get()

static MemoryLog * FML::MemoryLog::get ( )
inlinestatic

Definition at line 86 of file MemoryLogging.h.

86 {
87 if (not instance)
88 instance = new MemoryLog;
89 return instance;
90 }

◆ operator=() [1/2]

MemoryLog & FML::MemoryLog::operator= ( const MemoryLog &&  arg)
delete

◆ operator=() [2/2]

MemoryLog & FML::MemoryLog::operator= ( const MemoryLog arg)
delete

◆ print()

void FML::MemoryLog::print ( )
inline

Definition at line 159 of file MemoryLogging.h.

159 {
160 // Check if any task has saturated the allocation limit
161 char ok = stop_logging ? 0 : 1;
162#ifdef USE_MPI
163 MPI_Allreduce(MPI_IN_PLACE, &ok, 1, MPI_CHAR, MPI_MIN, MPI_COMM_WORLD);
164#endif
165 if (ok == 0) {
166 clear();
167 stop_logging = true;
168
169 if (ThisTask == 0)
170 std::cout << "Warning: The memory log has stopped working "
171 << " due to max number of allocation having been reached\n";
172 return;
173 }
174
175 // Fetch system memory usage
176 auto sysmem = get_system_memory_use();
177 double min_sys_vmemory = sysmem.first;
178 double max_sys_vmemory = sysmem.first;
179 double mean_sys_vmemory = sysmem.first;
180 double min_sys_rssmemory = sysmem.second;
181 double max_sys_rssmemory = sysmem.second;
182 double mean_sys_rssmemory = sysmem.second;
183
184#ifdef USE_MPI
185 MPI_Allreduce(MPI_IN_PLACE, &min_sys_vmemory, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD);
186 MPI_Allreduce(MPI_IN_PLACE, &max_sys_vmemory, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
187 MPI_Allreduce(MPI_IN_PLACE, &mean_sys_vmemory, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
188 MPI_Allreduce(MPI_IN_PLACE, &min_sys_rssmemory, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD);
189 MPI_Allreduce(MPI_IN_PLACE, &max_sys_rssmemory, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
190 MPI_Allreduce(MPI_IN_PLACE, &mean_sys_rssmemory, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
191#endif
192 mean_sys_vmemory /= NTasks;
193 mean_sys_rssmemory /= NTasks;
194 if (ThisTask == 0) {
195 std::cout << "\n#=====================================================\n";
196 std::cout << "# MemoryLogging\n";
197 std::cout << "#=====================================================\n\n";
198 std::cout << "Info about resident set size:\n";
199 std::cout << "[Current resident set size]:\n";
200 std::cout << "Min over tasks: " << std::setw(15) << min_sys_vmemory / 1.0e6 << " MB\n";
201 std::cout << "Mean over tasks: " << std::setw(15) << mean_sys_vmemory / 1.0e6 << " MB\n";
202 std::cout << "Max over tasks: " << std::setw(15) << max_sys_vmemory / 1.0e6 << " MB\n";
203 std::cout << "[Peak resident set size]:\n";
204 std::cout << "Min over tasks: " << std::setw(15) << min_sys_rssmemory / 1.0e6 << " MB\n";
205 std::cout << "Mean over tasks: " << std::setw(15) << mean_sys_rssmemory / 1.0e6 << " MB\n";
206 std::cout << "Max over tasks: " << std::setw(15) << max_sys_rssmemory / 1.0e6 << " MB\n";
207 }
208
209 if (ThisTask == 0) {
210 std::cout << "\n";
211 std::cout << "For info below we are only tracking allocation of standard\n";
212 std::cout << "container (Vector) and only allocations larger than " << min_bytes_to_log << " bytes\n\n";
213 }
214
215 long long int min_memory = memory_in_use;
216 long long int max_memory = memory_in_use;
217 long long int mean_memory = memory_in_use;
218 long long int peak_memory = peak_memory_use;
219#ifdef USE_MPI
220 MPI_Allreduce(MPI_IN_PLACE, &min_memory, 1, MPI_LONG_LONG, MPI_MIN, MPI_COMM_WORLD);
221 MPI_Allreduce(MPI_IN_PLACE, &max_memory, 1, MPI_LONG_LONG, MPI_MAX, MPI_COMM_WORLD);
222 MPI_Allreduce(MPI_IN_PLACE, &mean_memory, 1, MPI_LONG_LONG, MPI_SUM, MPI_COMM_WORLD);
223 MPI_Allreduce(MPI_IN_PLACE, &peak_memory, 1, MPI_LONG_LONG, MPI_MAX, MPI_COMM_WORLD);
224#endif
225 mean_memory /= NTasks;
226 if (ThisTask == 0) {
227 std::cout << "Memory in use (Task 0): " << std::setw(15) << double(memory_in_use) / 1.0e6 << " MB\n";
228 std::cout << "Min over tasks: " << std::setw(15) << double(min_memory) / 1.0e6 << " MB\n";
229 std::cout << "Mean over tasks: " << std::setw(15) << double(mean_memory) / 1.0e6 << " MB\n";
230 std::cout << "Max over tasks: " << std::setw(15) << double(max_memory) / 1.0e6 << " MB\n";
231 std::cout << "\n";
232 std::cout << "Peak memory use (Task 0): " << std::setw(15) << double(peak_memory_use) / 1.0e6
233 << " MB\n";
234 std::cout << "Max over tasks: " << std::setw(15) << double(peak_memory) / 1.0e6 << " MB\n";
235 std::cout << "\n";
236 }
237 if (not allocations.empty()) {
238 if (ThisTask == 0) {
239 std::cout << "\nWe have the following things allocated on task 0: \n";
240 }
241 for (auto && a : allocations) {
242 if (ThisTask == 0) {
243 std::string name = "";
244 if (labels.find(a.first) != labels.end())
245 name = labels[a.first];
246 std::string bytelabel = " (MB)";
247 double factor = 1e6;
248 std::cout << "Address: " << a.first << " Size: " << double(a.second) / factor << bytelabel
249 << " Label: " << name << "\n";
250 }
251 }
252 if (ThisTask == 0)
253 std::cout << "\n";
254 }
255 if (not memory_vs_time.empty()) {
256 if (ThisTask == 0)
257 std::cout << "Total memory as function of time:\n";
258 for (auto && m : memory_vs_time) {
259 double time_in_sec =
260 std::chrono::duration_cast<std::chrono::duration<double>>(m.first - time_start).count();
261 if (ThisTask == 0) {
262 std::cout << " Time (sec): " << std::setw(13) << time_in_sec;
263 std::string bytelabel = " (MB)";
264 double factor = 1e6;
265 std::cout << " Memory: " << std::setw(13) << double(m.second) / factor << bytelabel << "\n";
266 }
267 }
268 }
269 if (ThisTask == 0) {
270 std::cout << "\n#=====================================================\n";
271 std::cout << std::flush;
272 }
273 }
std::pair< double, double > get_system_memory_use()
Fetch the resident set size currently and the peak value so far of it.
Definition: Global.cpp:223
int ThisTask
The MPI task number.
Definition: Global.cpp:33
int NTasks
Total number of MPI tasks.
Definition: Global.cpp:34

◆ remove()

void FML::MemoryLog::remove ( void *  ptr,
size_t  size 
)
inline

Definition at line 139 of file MemoryLogging.h.

139 {
140 if (stop_logging or size < min_bytes_to_log)
141 return;
142
143#ifdef DEBUG_MEMORYLOG
144 std::string name = labels[ptr];
145 if (ThisTask == 0)
146 std::cout << "===> MemoryLog::remove Freeing[" << name << "]" << std::endl;
147#endif
148 std::lock_guard<std::mutex> guard(mymutex);
149 allocations.erase(ptr);
150 labels.erase(ptr);
151
152 memory_in_use -= size;
153
154 auto time = std::chrono::steady_clock::now();
155 memory_vs_time[time] = memory_in_use;
156 }

The documentation for this class was generated from the following files: