Vlasiator ebf0dd394 on dev (v5.4.0 + 1054 commits)
Loading...
Searching...
No Matches
memory_report.cpp
Go to the documentation of this file.
1/*
2 * This file is part of Vlasiator.
3 * Copyright 2010-2016 Finnish Meteorological Institute
4 *
5 * For details of usage, see the COPYING file and read the "Rules of the Road"
6 * at http://www.physics.helsinki.fi/vlasiator/
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23#include "common.h"
24#include <cstdint>
25#include <cstdlib>
26#include <iostream>
27#include <sstream>
28
29#ifdef _OPENMP
30 #include <omp.h>
31#endif
32#include "grid.h"
33#include "logger.h"
34#include "object_wrapper.h"
35
36#include "memory_report.h"
37
38#ifdef PAPI_MEM
39#include "papi.h"
40#endif
41
42#ifdef USE_GPU
43#include "arch/gpu_base.hpp"
44#endif
45extern Logger logFile;
46
49void report_cell_and_block_counts(const dccrg::Dccrg<spatial_cell::SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid){
50 cint maxRefLevel = mpiGrid.get_maximum_refinement_level();
51 const std::vector<CellID> localCells = getLocalCells();
52 cint popCount = getObjectWrapper().particleSpecies.size();
53
54 // popCount+1 as we store the spatial cell counts and then the populations' v_cell counts.
55 // maxRefLevel+1 as e.g. there's 2 levels at maxRefLevel == 1
56 std::vector<int64_t> localCounts((popCount+1)*(maxRefLevel+1), 0), globalCounts((popCount+1)*(maxRefLevel+1), 0);
57
58 for (const auto cellid : localCells) {
59 cint level = mpiGrid.get_refinement_level(cellid);
60 localCounts[level]++;
61 for(int pop=0; pop<popCount; pop++) {
62 localCounts[maxRefLevel+1 + level*popCount + pop] += mpiGrid[cellid]->get_number_of_velocity_blocks(pop);
63 }
64 }
65
66 MPI_Reduce(localCounts.data(), globalCounts.data(), (popCount+1)*(maxRefLevel+1), MPI_INT64_T, MPI_SUM, MASTER_RANK, MPI_COMM_WORLD);
67
68 logFile << "(CELLS) tstep = " << P::tstep << " time = " << P::t << " spatial cells [ ";
69 for(int level = 0; level <= maxRefLevel; level++) {
70 logFile << globalCounts[level] << " ";
71 }
72 logFile << "] blocks ";
73 for(int pop=0; pop<popCount; pop++) {
74 logFile << getObjectWrapper().particleSpecies[pop].name << " [ ";
75 for(int level = 0; level <= maxRefLevel; level++) {
76 logFile << globalCounts[maxRefLevel+1 + level*popCount + pop] << " ";
77 }
78 logFile << "] ";
79 }
80 logFile << std::endl << std::flush;
81
82}
83
86 uint64_t mem_proc_free = 0;
87 FILE * in_file = fopen("/proc/meminfo", "r");
88 char attribute_name[200];
89 uint64_t memory=0;
90 char memory_unit[10];
91 const char * memfree_attribute_name = "MemFree:";
92 if (in_file) {
93 while (!feof(in_file)) {
94 int retval = fscanf(in_file, "%199s %lu %9s", attribute_name, &memory, memory_unit);
95 if (retval >= 2) {
96 if (strcmp(attribute_name, memfree_attribute_name) == 0) {
97 // free memory in KB, transform to B
98 mem_proc_free = memory * 1024;
99 break;
100 }
101 } else {
102 //Skip line
103 if (fscanf(in_file, "%*[^\n]\n") == EOF) {
104 break;
105 }
106 }
107 }
108 fclose(in_file);
109 }
110
111 return mem_proc_free;
112}
113
119 const dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
120 double extra_bytes/*=0*/
121){
122 /*Report memory consumption into logfile*/
123
124 char nodename[MPI_MAX_PROCESSOR_NAME];
125 int namelength, nodehash;
126 int rank, nProcs, nodeRank, interRank;
127 int nNodes;
128 const double GiB = pow(2,30);
129
130 std::hash<std::string> hasher;
131 MPI_Comm nodeComm;
132 MPI_Comm interComm;
133
134
135 MPI_Comm_size(MPI_COMM_WORLD, &nProcs);
136 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
137
138 //get name of this node
139 MPI_Get_processor_name(nodename,&namelength);
140 nodehash=(int)(hasher(std::string(nodename)) % std::numeric_limits<int>::max());
141
142 //intra-node communicator
143 MPI_Comm_split(MPI_COMM_WORLD, nodehash, rank, &nodeComm);
144 MPI_Comm_rank(nodeComm,&nodeRank);
145 //create communicator for inter-node communication
146 MPI_Comm_split(MPI_COMM_WORLD, nodeRank, rank, &interComm);
147 MPI_Comm_rank(interComm, &interRank);
148 MPI_Comm_size(interComm, &nNodes);
149
150 // Report /proc/meminfo memory consumption first so we then get resident and HWM from Papi below, easier to compare by eye in logfile in this order.
151 double mem_proc_free = (double)get_node_free_memory();
152 double total_mem_proc = 0;
153 double min_free,max_free;
154 const int numberOfParameters = 1;
155 MPI_Reduce( &mem_proc_free, &total_mem_proc, numberOfParameters, MPI_DOUBLE, MPI_SUM, 0, interComm );
156 MPI_Reduce( &mem_proc_free, &min_free, numberOfParameters, MPI_DOUBLE, MPI_MIN, MASTER_RANK, MPI_COMM_WORLD );
157 MPI_Reduce( &mem_proc_free, &max_free, numberOfParameters, MPI_DOUBLE, MPI_MAX, MASTER_RANK, MPI_COMM_WORLD );
158
159 char reportstring[512];
160 snprintf(reportstring,512, "(MEM) tstep %i t %.3g %-21s (GiB/node; avg, min, max, sum): %-8.3g %-8.3g %-8.3g %-8.3g on %i nodes\n",
161 P::tstep, P::t, "Free", total_mem_proc/nNodes/GiB, min_free/GiB, max_free/GiB, total_mem_proc/GiB, nNodes);
162 logFile << reportstring;
163
164#ifdef PAPI_MEM
165 /*If we have PAPI, we can report the resident usage of the process*/
166 if (PAPI_library_init(PAPI_VER_CURRENT) == PAPI_VER_CURRENT) {
167 PAPI_dmem_info_t dmem;
168 PAPI_get_dmem_info(&dmem);
169 double mem_papi[4] = {};
170 double node_mem_papi[4] = {};
171 double sum_mem_papi[4];
172 double min_mem_papi[4];
173 double max_mem_papi[4];
174 /*PAPI returns memory in KB units, transform to bytes*/
175 mem_papi[0] = dmem.high_water_mark * 1024;
176 mem_papi[1] = dmem.resident * 1024 + extra_bytes;
177 mem_papi[2] = dmem.resident * 1024;
178 mem_papi[3] = extra_bytes;
179 //sum node mem
180 MPI_Reduce(mem_papi, node_mem_papi, 4, MPI_DOUBLE, MPI_SUM, 0, nodeComm);
181
182 //rank 0 on all nodes do total reduces
183 if(nodeRank == 0) {
184 MPI_Reduce(node_mem_papi, sum_mem_papi, 4, MPI_DOUBLE, MPI_SUM, 0, interComm);
185 MPI_Reduce(node_mem_papi, min_mem_papi, 4, MPI_DOUBLE, MPI_MIN, 0, interComm);
186 MPI_Reduce(node_mem_papi, max_mem_papi, 4, MPI_DOUBLE, MPI_MAX, 0, interComm);
187 if (max_mem_papi[3] != 0.0) {
188 logFile << "(MEM) Estimating increased high water mark from refinement" << std::endl;
189 }
190 snprintf(reportstring,512, "(MEM) tstep %i t %.3g %-21s (GiB/node; avg, min, max, sum): %-8.3g %-8.3g %-8.3g %-8.3g on %i nodes\n",
191 P::tstep, P::t, "Resident", sum_mem_papi[2]/nNodes/GiB, min_mem_papi[2]/GiB, max_mem_papi[2]/GiB, sum_mem_papi[2]/GiB, nNodes);
192 logFile << reportstring;
193 snprintf(reportstring,512, "(MEM) tstep %i t %.3g %-21s (GiB/node; avg, min, max, sum): %-8.3g %-8.3g %-8.3g %-8.3g on %i nodes\n",
194 P::tstep, P::t, "High water mark \U0001F30A ", sum_mem_papi[0]/nNodes/GiB, min_mem_papi[0]/GiB, max_mem_papi[0]/GiB, sum_mem_papi[0]/GiB, nNodes);
195 logFile << reportstring;
196 if (max_mem_papi[3] != 0.0) {
197 snprintf(reportstring,512, "(MEM) tstep %i t %.3g %-21s (GiB/node; avg, min, max, sum): %-8.3g %-8.3g %-8.3g %-8.3g on %i nodes\n",
198 P::tstep, P::t, "Resident with refines", sum_mem_papi[1]/nNodes/GiB, min_mem_papi[1]/GiB, max_mem_papi[1]/GiB, sum_mem_papi[1]/GiB, nNodes);
199 logFile << reportstring;
200 }
201 }
202 if(rank == MASTER_RANK) {
203 bailout(max_mem_papi[0]/GiB > P::bailout_max_memory, "Memory high water mark per node exceeds bailout threshold", __FILE__, __LINE__);
204 bailout(max_mem_papi[1]/GiB > P::bailout_max_memory, "Estimated resident per node exceeds bailout threshold", __FILE__, __LINE__);
205 }
206 }
207#endif
208
209 /*now report memory consumption of mpiGrid specifically into logfile*/
210 const std::vector<CellID>& cells = getLocalCells();
211 const std::vector<CellID> remote_cells = mpiGrid.get_remote_cells_on_process_boundary();
212
213 /* Compute memory statistics of the memory consumption of the spatial cells.
214 * Internally we use double as MPI does
215 * not define proper uint64_t datatypes for MAXLOCNot Real, as we
216 * want double here not to loose accuracy.
217 */
218
219 /*report data for memory needed by blocks*/
220 double mem[6] = {0};
221 double sum_mem[6];
222
223 for(unsigned int i=0;i<cells.size();i++){
224 #ifdef USE_GPU
225 // GPU version keeps track of largest attained velocity mesh throughout acceleration cycles
226 mem[0] += mpiGrid[cells[i]]->largestvmesh * WID3 * sizeof(Realf);
227 #else
228 mem[0] += mpiGrid[cells[i]]->get_cell_memory_size();
229 #endif
230 mem[3] += mpiGrid[cells[i]]->get_cell_memory_capacity();
231 }
232
233 for(unsigned int i=0;i<remote_cells.size();i++){
234 if(mpiGrid[remote_cells[i]] != NULL) {
235 mem[1] += mpiGrid[remote_cells[i]]->get_cell_memory_size();
236 mem[4] += mpiGrid[remote_cells[i]]->get_cell_memory_capacity();
237 }
238 }
239
240 mem[2] = mem[0] + mem[1];//total memory according to size()
241 mem[5] = mem[3] + mem[4];//total memory according to capacity()
242
243
244 MPI_Reduce(mem, sum_mem, 6, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
245
246
247 struct {
248 double val;
249 int rank;
250 } max_mem[3],mem_usage_loc[3],min_mem[3];
251 for(uint i = 0; i<3; i++){
252 mem_usage_loc[i].val = mem[i + 3]; //report on capacity numbers (6: local cells, 7: remote cells, 8: all cells)
253 mem_usage_loc[i].rank = rank;
254 }
255
256 MPI_Reduce(mem_usage_loc, max_mem, 3, MPI_DOUBLE_INT, MPI_MAXLOC, 0, MPI_COMM_WORLD);
257 MPI_Reduce(mem_usage_loc, min_mem, 3, MPI_DOUBLE_INT, MPI_MINLOC, 0, MPI_COMM_WORLD);
258
259
260 snprintf(reportstring,512, "(MEM) tstep %i t %.3g %-21s (GiB/rank; avg, min, max, sum): %-8.3g %-8.3g %-8.3g %-8.3g min rank %i max rank %i\n",
261 P::tstep, P::t, "Local cells capacity", sum_mem[3]/nProcs/GiB, min_mem[0].val/GiB, max_mem[0].val/GiB, sum_mem[3]/GiB, min_mem[0].rank, max_mem[0].rank);
262 logFile << reportstring;
263 snprintf(reportstring,512, "(MEM) tstep %i t %.3g %-21s (GiB/rank; avg, min, max, sum): %-8.3g %-8.3g %-8.3g %-8.3g min rank %i max rank %i\n",
264 P::tstep, P::t, "Remote cells capacity", sum_mem[4]/nProcs/GiB, min_mem[1].val/GiB, max_mem[1].val/GiB, sum_mem[4]/GiB, min_mem[1].rank, max_mem[1].rank);
265 logFile << reportstring;
266 snprintf(reportstring,512, "(MEM) tstep %i t %.3g %-21s (GiB/rank; avg, min, max, sum): %-8.3g %-8.3g %-8.3g %-8.3g min rank %i max rank %i\n",
267 P::tstep, P::t, "Total cells capacity", sum_mem[5]/nProcs/GiB, min_mem[2].val/GiB, max_mem[2].val/GiB, sum_mem[5]/GiB, min_mem[2].rank, max_mem[2].rank);
268 logFile << reportstring;
269
270 snprintf(reportstring,512, "(MEM) tstep %i t %.3g Total size and capacity of SpatialCells (GiB): %-8.3g %-8.3g\n",
271 P::tstep, P::t, sum_mem[2]/GiB, sum_mem[5]/GiB);
272 logFile << reportstring;
273
275
276 MPI_Comm_free(&interComm);
277 MPI_Comm_free(&nodeComm);
278
279 #ifdef USE_GPU
280 // TODO: Clear duplicate output
281 // (local_cells_capacity, ghost_cells_capacity, local_cells_size, ghost_cells_size)
282 gpu_reportMemory(mem[3], mem[4], mem[0], mem[1]);
283
284 #endif
285}
fclose(file)
for i
Definition Dispersion.m:24
void bailout(const bool condition, const std::string &message, const char *const file, const int line)
A function to stop the simulation if the boolean condition is true. Raises a flag which gets MPI_Redu...
Definition common.cpp:36
const std::vector< CellID > & getLocalCells()
Definition main.cpp:39
#define MASTER_RANK
Definition common.h:67
const int WID3
Definition common.h:517
const int cint
Definition definitions.h:45
float Realf
Definition definitions.h:33
int gpu_reportMemory(const size_t local_cells_capacity, const size_t ghost_cells_capacity, const size_t local_cells_size, const size_t ghost_cells_size)
Definition gpu_base.cpp:266
Logger logFile
Definition main.cpp:25
ObjectWrapper & getObjectWrapper()
Definition main.cpp:33
Logger & writeVerbose(Logger &logger)
Definition logger.cpp:177
void report_memory_consumption(const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, double extra_bytes)
void report_cell_and_block_counts(const dccrg::Dccrg< spatial_cell::SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid)
uint64_t get_node_free_memory()
std::vector< species::Species > particleSpecies
static Real bailout_max_memory
Definition parameters.h:187
static Real t
Definition parameters.h:52
static uint tstep
Definition parameters.h:73