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