219 {
220
221 static MLong virtMemLast = 0;
222 static MLong physMemLast = 0;
223
227 MLong physMemFree = 0;
228 MLong memAvailable = 0;
229
230 {
231
232 MInt fileNotFound = 0;
233 MInt memoryNotFound = 0;
234
235
236 std::ifstream fin;
237 fin.open("/proc/self/status");
238
239 if(!fin) {
240 fileNotFound = 1;
241 }
242
246 std::istringstream iss;
247 std::array<MInt, 5> foundInfo;
248 foundInfo.fill(false);
249
250
252 buffer = 0;
253 iss.str(line);
254 iss.clear();
256 if(name == "VmRSS") {
257 iss >> buffer;
258 physMem = buffer;
259 foundInfo[0] = true;
260 } else if(name == "VmData") {
261 iss >> buffer;
262 virtMem += buffer;
263 foundInfo[1] = true;
264 } else if(name == "VmStk") {
265 iss >> buffer;
266 virtMem += buffer;
267 stackMem = buffer;
268 foundInfo[2] = true;
269 }
270 }
271 fin.close();
272
273
274 fin.open("/proc/meminfo");
275 if(!fin) {
276 fileNotFound = 1;
277 }
278
280 buffer = 0;
281 iss.str(line);
282 iss.clear();
284 if(name == "MemFree") {
285 iss >> buffer;
286 physMemFree = buffer;
287 foundInfo[3] = true;
288 } else if(name == "MemAvailable") {
289 iss >> buffer;
290 memAvailable = buffer;
291 foundInfo[4] = true;
292 }
293 }
294 fin.close();
295
296
297 memoryNotFound = std::any_of(foundInfo.begin(), foundInfo.end(), [](
MBool i) { return !i; });
298
299
300 MPI_Allreduce(MPI_IN_PLACE, &fileNotFound, 1, MPI_INT, MPI_MAX, comm, AT_,
"MPI_IN_PLACE",
"&fileNotFound");
301 MPI_Allreduce(MPI_IN_PLACE, &memoryNotFound, 1, MPI_INT, MPI_MAX, comm, AT_,
"MPI_IN_PLACE",
"&memoryNotFound");
302 MPI_Allreduce(MPI_IN_PLACE, &foundInfo[0], 5, MPI_INT, MPI_MAX, comm, AT_,
"MPI_IN_PLACE",
"&foundInfo");
303
304 if(fileNotFound || memoryNotFound) {
305
306 if(domainId == 0) {
307 std::stringstream ss;
308 ss << "Error in writeMemoryStatistics: Could not determine memory statistics! " << fileNotFound << " "
309 << memoryNotFound << " (";
310 for(
MInt i = 0; i < 5; i++) {
311 ss << " " << foundInfo[i];
312 }
313 ss << ")" << std::endl;
314 std::cerr << ss.str();
316 }
317 return;
318 }
319 }
320
323
324
325 MPI_Gather(&physMem, 1, MPI_LONG, physMemPerProcess.getPointer(), 1, MPI_LONG, 0, comm, AT_,
"physMem",
326 "physMemPerProcess.getPointer()");
327 MPI_Gather(&virtMem, 1, MPI_LONG, virtMemPerProcess.getPointer(), 1, MPI_LONG, 0, comm, AT_,
"virtMem",
328 "virtMemPerProcess.getPointer()");
329
330 MLongScratchSpace physMemDiffPerProcess(noDomains, AT_,
"physMemDiffPerProcess");
331 MLongScratchSpace virtMemDiffPerProcess(noDomains, AT_,
"virtMemDiffPerProcess");
332
333 MLong physMemDiff = physMem - physMemLast;
334 MLong virtMemDiff = virtMem - virtMemLast;
335
336 MPI_Gather(&physMemDiff, 1, MPI_LONG, physMemDiffPerProcess.getPointer(), 1, MPI_LONG, 0, comm, AT_,
"physMem",
337 "physMemDiffPerProcess.getPointer()");
338 MPI_Gather(&virtMemDiff, 1, MPI_LONG, virtMemDiffPerProcess.getPointer(), 1, MPI_LONG, 0, comm, AT_,
"virtMem",
339 "virtMemDiffPerProcess.getPointer()");
340
341
342 physMemLast = physMem;
343 virtMemLast = virtMem;
344
345
347 MPI_Gather(&stackMem, 1, MPI_LONG, stackMemPerProcess.getPointer(), 1, MPI_LONG, 0, comm, AT_,
"stackMem",
348 "stackMemPerProcess.getPointer()");
349
350
351 MLong minPhysMemFree = physMemFree;
352 MPI_Allreduce(MPI_IN_PLACE, &minPhysMemFree, 1, MPI_LONG, MPI_MIN, comm, AT_,
"MPI_IN_PLACE",
"&minPhysMemFree");
353 MLong minMemAvailable = memAvailable;
354 MPI_Allreduce(MPI_IN_PLACE, &minMemAvailable, 1, MPI_LONG, MPI_MIN, comm, AT_,
"MPI_IN_PLACE",
"&minMemAvailable");
355
356
357 if(domainId == 0) {
358 MLong totalPhysMem = 0;
359 MLong totalVirtMem = 0;
360 MLong totalPhysMemDiffSum = 0;
361 MLong totalVirtMemDiffSum = 0;
362 MLong totalPhysMemDiffMax = 0;
363 MLong totalVirtMemDiffMax = 0;
364 MLong maxStackMem = 0;
365
366 for(
MInt i = 0; i < noDomains; i++) {
367
368 totalPhysMem += physMemPerProcess[i];
369 totalVirtMem += virtMemPerProcess[i];
370
371 totalPhysMemDiffSum += physMemDiffPerProcess[i];
372 totalVirtMemDiffSum += virtMemDiffPerProcess[i];
373
374 totalPhysMemDiffMax = std::max(physMemDiffPerProcess[i], totalPhysMemDiffMax);
375 totalVirtMemDiffMax = std::max(virtMemDiffPerProcess[i], totalVirtMemDiffMax);
376
377 maxStackMem = std::max(stackMemPerProcess[i], maxStackMem);
378 }
379
380
381 rlimit rlim;
382 getrlimit(RLIMIT_STACK, &rlim);
383
384 const MUlong rlim_stack = rlim.rlim_cur;
385
386 if(maxStackMem > 0.5 * rlim_stack) {
387 std::stringstream warning;
388 warning << std::endl
389 << "WARNING: maximum stack memory usage >50% of its limit, use 'ulimit -s unlimited' to remove this "
390 "memory restriction and avoid segmentation faults if the stack memory usage exceeds its limit."
391 << std::endl;
392 warning <<
"WARNING: stack memory usage " << (
MFloat)maxStackMem <<
" KB; stack limit "
393 << (
MFloat)rlim_stack / 1024 <<
" KB" << std::endl
394 << std::endl;
395 m_log << warning.str();
396 std::cerr << warning.str();
397 }
398
399
400#ifndef NDEBUG
401
402 for(
MInt i = 0; i < noDomains; i++) {
403 m_log <<
" Process " << i <<
" - Current memory usage: physical = " << (
MFloat)physMemPerProcess[i] / 1024
404 <<
" MB; allocation = " << (
MFloat)virtMemPerProcess[i] / 1024 <<
" MB" << std::endl;
405 }
406#endif
407
408 std::stringstream ss;
409 ss << std::endl;
410 ss << "******************************* MEMORY STATISTICS *******************************" << std::endl;
411 ss << "***** Comment: " << comment << " - #ranks: " << noDomains << std::endl;
412 ss << "***** Location: " << at << std::endl;
413 ss << "***** " << std::endl;
414
415 ss <<
"***** Average memory usage: physical = " << (
MFloat)totalPhysMem / (noDomains * 1024)
416 <<
" MB; allocation = " << (
MFloat)totalVirtMem / (noDomains * 1024) <<
" MB\n";
417
418
419 ss << "***** Minimun memory usage: physical = "
420 << (
MFloat)*std::min_element(physMemPerProcess.begin(), physMemPerProcess.end()) / 1024
421 <<
" MB; allocation = " << (
MFloat)*std::min_element(virtMemPerProcess.begin(), virtMemPerProcess.end()) / 1024
422 << " MB\n";
423 ss << "***** Maximum memory usage: physical = "
424 << (
MFloat)*std::max_element(physMemPerProcess.begin(), physMemPerProcess.end()) / 1024
425 <<
" MB; allocation = " << (
MFloat)*std::max_element(virtMemPerProcess.begin(), virtMemPerProcess.end()) / 1024
426 << " MB\n";
427 ss <<
"***** Maximum diff in memory usage: physical = " << (
MFloat)totalPhysMemDiffMax / 1024
428 <<
" MB; allocation = " << (
MFloat)totalVirtMemDiffMax / 1024 <<
" MB\n";
429
430
431 ss <<
"***** Total physical memory usage (RAM): " << (
MFloat)totalPhysMem / (1024 * 1024) <<
" GB\n";
432 ss <<
"***** Diff total physical memory usage (RAM): " << (
MFloat)totalPhysMemDiffSum / (1024 * 1024) <<
" GB\n";
433 ss <<
"***** Total allocation size (Virtual Memory): " << (
MFloat)totalVirtMem / (1024 * 1024) <<
" GB"
434 << std::endl;
435 ss <<
"***** Diff total allocation size (Virtual Memory): " << (
MFloat)totalVirtMemDiffSum / (1024 * 1024) <<
" GB"
436 << std::endl;
437 ss << "***** " << std::endl;
438 ss <<
"***** Maximum stack memory: " << (
MFloat)maxStackMem <<
" KB; stack limit " << (
MFloat)rlim_stack / 1024
439 << " KB" << std::endl;
440 ss << "***** " << std::endl;
441 ss <<
"***** Minimum available memory per node (meminfo): " << (
MFloat)minMemAvailable / (1024 * 1024) <<
" GB"
442 << std::endl;
443 ss <<
"***** Minimum free memory per node (RAM): " << (
MFloat)minPhysMemFree / (1024 * 1024) <<
" GB" << std::endl;
444 ss << "******************************* MEMORY STATISTICS *******************************" << std::endl << std::endl;
445
446 std::cout << ss.str() << std::endl;
447 m_log << ss.str() << std::endl;
448 }
449}
This class is a ScratchSpace.
int MPI_Allreduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allreduce
int MPI_Gather(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Gather