Proto
Proto_MemInfo.H
1 #ifndef PROTO_MEMINFO_H
2 #define PROTO_MEMINFO_H
3 
4 #include<map>
5 #include<iostream>
6 #include<vector>
7 #include <fstream>
8 #include<Proto_MemType.H>
9 #include<assert.h>
10 #include <sys/resource.h>
11 
12 namespace Proto
13 {
15  {
16  public:
18 
23  {
24  dataSize += in.dataSize;
25  count += in.count;
26  return *this;
27  }
28 
29  double dataSize;
30  long unsigned int count;
31  };
32 
33  // we use size_t because it's the type used in cudaMemGetInfo
34  class traceInfo
35  {
36  public:
37  typedef std::pair<size_t,size_t> pairType;
38 
40 
44  void addElem(size_t a_currentSize)
45  {
46  if(m_maxSize < a_currentSize)
47  m_maxSize = a_currentSize;
48  pairType tracePoint = std::make_pair (a_currentSize, m_maxSize);
49  m_info.push_back(tracePoint);
50 
51  }
52 
54 
58  void writeFile (std::ofstream &file)
59  {
60  for(auto &it : m_info)
61  {
62  file << it.first << " " << it.second << std::endl;
63  }
64  }
65 
67 
70  size_t size()
71  {
72  return m_info.size();
73  }
74 
75  private:
76  size_t m_maxSize = 0;
77  std::vector<pairType> m_info;
78  };
79 
80 
81  template<MemType MEMTYPE=MEMTYPE_DEFAULT>
82  class memInfo
83  {
84  public:
86 
89  memInfo() {}
91 
99  void enterInfo(std::string file, unsigned int line, unsigned long int dataSize)
100  {
101  std::pair<std::string,unsigned int> position = std::make_pair(file,line);
102  auto elem = m_info.find(position);
103  if(elem != m_info.end())
104  {
105  auto& item = elem->second;
106  double& mem = item.dataSize;
107  long unsigned int& count = item.count;
108  mem += dataSize;
109  count++;
110  }
111  else
112  {
113  describeInfo item;
114  item.dataSize = dataSize;
115  item.count = 1;
116  m_info[position] = item;
117  }
118  }
119 
121 
128  void enterInfos(std::pair<std::string,unsigned int> a_position, describeInfo& a_elem)
129  {
130  auto elem = m_info.find(a_position);
131  if(elem != m_info.end())
132  {
133  auto& item = elem->second;
134  item += a_elem;
135  }
136  else
137  {
138  m_info[a_position] = a_elem;
139  }
140  }
141 
142 
144 
148  {
149 #ifdef PROTO_CUDA
150  size_t tmp_free = 0;
151  size_t tmp_tot = 0;
152  protoMemGetInfo(&tmp_free,&tmp_tot);
153  assert(tmp_tot > tmp_free);
154  size_t tmp_current_size = tmp_tot - tmp_free;
155  m_trace.addElem(tmp_current_size);
156 #endif
157  }
158 
160 
164  {
165  int who = RUSAGE_SELF;
166  struct rusage usage;
167  getrusage(who, &usage); // kilobytes
168  size_t tmp_current_size = usage.ru_maxrss * 1000; // kilobytes to bytes
169  m_trace.addElem(tmp_current_size);
170  }
171 
173 
176  bool fexists(std::string filename)
177  {
178  std::ifstream ifile(filename);
179  return !(ifile.fail());
180  }
181 
182  // display function
186  void printInfo()
187  {
188 #ifdef PR_MPI_TMP
189  mpiCollectInfo();
190  int rank = procID();
191  int size = numProc();
192  if(rank == 0) // we display only the rank 0
193  {
194 #endif
195  std::cout << " print mem Info " << std::endl << std::endl;
196  for(auto& it : m_info)
197  {
198  auto& position = it.first;
199  std::string file = position.first;
200  unsigned int line = position.second;
201  double dataSize = it.second.dataSize;
202  long unsigned int count = it.second.count;
203  std::cout << " In " << file << " line " << line << " we allocated "
204  << dataSize * 1E-9 << " GB, in " << count << " allocation(s)"
205  << std::endl;
206  }
207 #ifdef PR_MPI_TMP
208  }
209  std::string baseline = "trace-rank-" + std::to_string(rank);
210 #else
211  std::string baseline = "trace";
212 #endif
213  std::string filename = baseline + ".txt";
214  int i = 1;
215  while(fexists(filename))
216  {
217  filename = baseline + "-" + std::to_string(i) + ".txt";
218  i++;
219  }
220  std::cout << " write memory trace in " << filename << std::endl << std::endl;
221  std::ofstream file(filename);
222  m_trace.writeFile(file);
223  }
224 
229  {
230  static memInfo global_info;
231  return global_info;
232  }
233 #ifdef PR_MPI_TMP
234 
237  void mpiCollectInfo()
238  {
239  int rank = procID();
240  int size = numProc();
241  if(size == 1) return; // only one MPI process
242  // get m_size and m_trace size
243  std::vector<int> info_sizes;
244  if(rank==0)
245  {
246  info_sizes.resize(size);
247  }
248  size_t mySize = m_info.size();
249  MPI_Gather( &mySize,
250  1,
251  MPI_INT,
252  info_sizes.data(),
253  1,
254  MPI_INT,
255  0,
256  Proto_MPI<void>::comm);
257 
258  // pack data
259  if(rank!= 0)
260  {
261  std::vector<std::pair<std::pair<std::string,unsigned int>, describeInfo>> toSend;
262  for(auto it:m_info)
263  {
264  auto item = std::make_pair(it.first,it.second);
265  toSend.push_back(item);
266  }
267  size_t nBytes = sizeof(std::pair<std::pair<std::string,unsigned int>, describeInfo>)*mySize;
268  MPI_Send(
269  toSend.data(),
270  nBytes,
271  MPI_CHAR,
272  0,
273  666+rank,
274  Proto_MPI<void>::comm);
275  }
276  else
277  {
278  for(size_t i = 0 ; i < size ; i++) std::cout << " rank: " << rank << " size "<< info_sizes[i] << std::endl;
279 
280  for(size_t otherRank = 1 ; otherRank < size ; otherRank++)
281  {
282  std::vector<std::pair<std::pair<std::string,unsigned int>, describeInfo>> toRecv;
283  size_t otherSize = info_sizes[otherRank];
284  toRecv.resize(otherSize);
285  size_t nBytes = sizeof(std::pair<std::pair<std::string,unsigned int>, describeInfo>)*otherSize;
286  MPI_Status status;
287  MPI_Recv(
288  toRecv.data(),
289  nBytes,
290  MPI_CHAR,
291  otherRank,
292  666+otherRank,
293  MPI_COMM_WORLD,
294  &status);
295 
296  // unpack data
297  for(auto it : toRecv)
298  {
299  enterInfos(it.first,it.second);
300  }
301 
302  }
303  }
304  }
305 #endif //PR_MPI
306 
307  private:
308  std::map<std::pair<std::string,unsigned int>, describeInfo> m_info;
309  traceInfo m_trace;
310  }; // end memInfo class
311 
312 } // end PROTO namespace
313 
314 // Display memory footprint per position in the code
315 // Extended to host and device allocations
316 // This function works only if the storeMemInfo is used
317 //turned off to kill compiler warning that it was not used
318 #if 0
319 static void PRINT_MEMORY_INFO()
320 {
321 #ifdef memoryFootPrint
322 #ifdef PROTO_CUDA
323  std::cout << " -------------- device ----------- " << std::endl << std::endl;
325  tmpInfoDevice.printInfo();
326  std::cout << " --------------- host ------------ " << std::endl << std::endl;
327 #endif
329  tmpInfoHost.printInfo();
330 #else
331  std::cout << " The memory footprint option is not activated. flag: -DmemoryFootPrint (performance overhead if activated)" << std::endl;
332 #endif
333 }
334 #endif
335 
336 
337 // here are the macros defined to check the memory used in Proto_gpu.H and Proto_cpu.H
338 #ifdef memoryFootPrint
339  // tmp_ to avoid doublons
340  #define countMallocDevice(cond) \
341  { \
342  cond;\
343  Proto::memInfo<Proto::DEVICE>& tmpInfo = Proto::memInfo<Proto::DEVICE>::getMemInfo();\
344  tmpInfo.addTracePoint();\
345  };
346 
347  #define countMallocHost(cond) \
348  { \
349  cond;\
350  Proto::memInfo<Proto::HOST>& tmpInfo = Proto::memInfo<Proto::HOST>::getMemInfo();\
351  tmpInfo.addTracePointHost();\
352  };
353 
354  #define storeMemInfo(MEM,B) \
355  { \
356  using Proto::HOST;\
357  using Proto::DEVICE;\
358  Proto::memInfo<MEM>& tmpInfo = Proto::memInfo<MEM>::getMemInfo();\
359  tmpInfo.enterInfo(__FILE__,__LINE__,B);\
360  };
361 #else
362  #define countMallocDevice(cond) cond
363  #define countMallocHost(cond) cond
364  #define storeMemInfo(MEMTYPE,BYTES)
365 #endif
366 #endif //PROTO_MEMINFO_H
describeInfo & operator+=(describeInfo &in)
describe operator+
Definition: Proto_MemInfo.H:22
unsigned int numProc()
number of parallel processes
Definition: Proto_SPMD.H:72
long unsigned int count
number of malloc for a given position
Definition: Proto_MemInfo.H:30
size_t size()
accessor function
Definition: Proto_MemInfo.H:70
void enterInfo(std::string file, unsigned int line, unsigned long int dataSize)
insert function
Definition: Proto_MemInfo.H:99
double dataSize
size of accumulated memory in bytes
Definition: Proto_MemInfo.H:29
void writeFile(std::ofstream &file)
output function
Definition: Proto_MemInfo.H:58
void addElem(size_t a_currentSize)
insert function
Definition: Proto_MemInfo.H:44
int procID()
local process ID
Definition: Proto_SPMD.H:52
void addTracePoint()
insert function
Definition: Proto_MemInfo.H:147
memInfo()
constructor
Definition: Proto_MemInfo.H:89
void printInfo()
Definition: Proto_MemInfo.H:186
void addTracePointHost()
insert function
Definition: Proto_MemInfo.H:163
Definition: Proto_MemInfo.H:82
Definition: Proto_Box.H:11
static memInfo< MEMTYPE > & getMemInfo()
Definition: Proto_MemInfo.H:228
Definition: Proto_MemInfo.H:14
bool fexists(std::string filename)
check function
Definition: Proto_MemInfo.H:176
void enterInfos(std::pair< std::string, unsigned int > a_position, describeInfo &a_elem)
insert function
Definition: Proto_MemInfo.H:128
Definition: Proto_MemInfo.H:34