fw4spl
PosixMemoryMonitorTools.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2017.
3  * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
4  * published by the Free Software Foundation.
5  * ****** END LICENSE BLOCK ****** */
6 
7 #if defined(linux) || defined(__linux)
8 
9 #include "fwMemory/tools/PosixMemoryMonitorTools.hpp"
10 
11 #include <fwCore/base.hpp>
12 
13 #include <fcntl.h>
14 #include <unistd.h>
15 
16 #include <boost/filesystem/convenience.hpp>
17 #include <boost/filesystem/operations.hpp>
18 #include <boost/filesystem/path.hpp>
19 #include <boost/lexical_cast.hpp>
20 #include <boost/regex.hpp>
21 
22 #include <sys/resource.h>
23 #include <sys/time.h>
24 #include <sys/types.h>
25 
26 #include <cctype>
27 #include <cerrno>
28 #include <cstdio>
29 #include <cstdlib>
30 #include <fstream>
31 #include <iomanip>
32 #include <iostream>
33 #include <sstream>
34 #include <string>
35 
36 namespace fwMemory
37 {
38 namespace tools
39 {
40 
41 std::uint64_t PosixMemoryMonitorTools::s_pageSize = sysconf(_SC_PAGE_SIZE);
42 std::uint64_t PosixMemoryMonitorTools::s_totalMemory = sysconf(_SC_PHYS_PAGES) * s_pageSize;
43 
44 //-----------------------------------------------------------------------------
45 
46 PosixMemoryMonitorTools::PosixMemoryMonitorTools()
47 {
48 }
49 
50 //-----------------------------------------------------------------------------
51 
52 PosixMemoryMonitorTools::~PosixMemoryMonitorTools()
53 {
54 }
55 
56 //-----------------------------------------------------------------------------
57 
58 std::uint64_t PosixMemoryMonitorTools::estimateFreeMem()
59 {
60  std::uint64_t freeMemory = 0;
61 
62 // std::uint64_t systemMemoryAverageInNormalCase = 500 * 1024 * 1024; // 500 Mo
63 // std::uint64_t memoryUsedByProcess = MemoryMonitor::getDefault()->totalUsedSizeInBytes()
64 // + 50 * 1024 * 1024; // + 50 Mo of librairies;
65 // freeMemory = ( getTotalSystemMemory() < systemMemoryAverageInNormalCase + memoryUsedByProcess?
66 // 0:
67 // getTotalSystemMemory() - systemMemoryAverageInNormalCase - memoryUsedByProcess
68 // );
69 
70  freeMemory = getFreeSystemMemory();
71 
72  return freeMemory;
73 }
74 
75 //-----------------------------------------------------------------------------
76 
77 void PosixMemoryMonitorTools::printProcessMemoryInformation()
78 {
79  Status stat;
80  getStatusOfPid( getpid(), stat );
81  printStatus(stat);
82 }
83 
84 //-----------------------------------------------------------------------------
85 
86 void PosixMemoryMonitorTools::printSystemMemoryInformation()
87 {
88  MemInfo memory;
89  get_memory_stats(memory);
90  std::uint64_t oToKMo = 1024*1024;
91 
92  OSLM_INFO("Total memory: " << memory.total/oToKMo<< " Mo");
93  OSLM_INFO("Free memory: " << memory.free/oToKMo << " Mo");
94  OSLM_INFO("Buffered: " << memory.buffered/oToKMo << " Mo");
95  OSLM_INFO("Cached: " << memory.cached/oToKMo << " Mo");
96  OSLM_INFO("Swap Cached: " << memory.swapcached/oToKMo << " Mo");
97  OSLM_INFO("Swap Total: " << memory.swaptotal/oToKMo << " Mo");
98  OSLM_INFO("Swap Free: " << memory.swapfree/oToKMo << " Mo");
99 
100  Status allStat;
101  getAllStatus( allStat );
102  printStatus( allStat );
103 
104  std::uint64_t computedFree = ( memory.total - allStat.VmRSS ) / oToKMo;
105  std::uint64_t free = memory.free / oToKMo;
106  OSLM_INFO( "(ComputedFree, Free, Diff) - ( "
107  << std::setw(5) << computedFree
108  << std::setw(5) << free
109  << std::setw(5) << computedFree -free
110  << " )" );
111  (void)computedFree; // Fixes "unused variable" warnings
112  (void)free;
113 }
114 
115 //-----------------------------------------------------------------------------
116 
117 void PosixMemoryMonitorTools::printMemoryInformation()
118 {
119  printSystemMemoryInformation();
120  printProcessMemoryInformation();
121 }
122 
123 //-----------------------------------------------------------------------------
124 
125 std::uint64_t PosixMemoryMonitorTools::getTotalSystemMemory()
126 {
127  return s_totalMemory;
128 }
129 
130 //-----------------------------------------------------------------------------
131 
132 std::uint64_t PosixMemoryMonitorTools::getUsedSystemMemory()
133 {
134  return getTotalSystemMemory() - getFreeSystemMemory();
135 }
136 
137 //-----------------------------------------------------------------------------
138 
139 std::uint64_t PosixMemoryMonitorTools::getFreeSystemMemory()
140 {
141  //Status allStat;
142  //getAllStatus( allStat );
143  MemInfo memory;
144  get_memory_stats(memory);
145  return sysconf(_SC_AVPHYS_PAGES) * s_pageSize + memory.cached;
146 }
147 
148 //-----------------------------------------------------------------------------
149 
150 std::uint64_t PosixMemoryMonitorTools::getUsedProcessMemory()
151 {
152  Status stat;
153  getStatusOfPid( getpid(), stat );
154  return stat.VmSize;
155 }
156 
157 //-----------------------------------------------------------------------------
158 
159 //------------------------------------------------------------------------------
160 
161 std::uint64_t PosixMemoryMonitorTools::extract_number(char* str, int start, int end)
162 {
163  int i, j;
164  char buf[end-start];
165 
166  for (i = start, j = 0; i < end; i++)
167  {
168  isdigit(str[i]) && (buf[j++] = str[i]);
169  }
170  buf[j] = '\0';
171 
172  return strtoul(buf, NULL, 0) * 1024;
173 }
174 
175 //------------------------------------------------------------------------------
176 
177 void PosixMemoryMonitorTools::get_memory_stats( MemInfo& meminfo )
178 {
179 /*
180  // We are bothered about only the first 338 bytes of the /proc/meminfo file
181  char buf[338];
182  int in;
183 
184  in = open("/proc/meminfo", O_RDONLY);
185 
186  read(in, buf, sizeof(buf));
187 
188  close(in);
189 
190  meminfo.total = extract_number(buf, 9, 22);
191  meminfo.free = extract_number(buf, 35, 49);
192  meminfo.buffered = extract_number(buf, 61, 75);
193  meminfo.cached = extract_number(buf, 86, 101);
194  meminfo.swapcached = extract_number(buf, 116, 127);
195  meminfo.swaptotal = extract_number(buf, 297, 309);
196  meminfo.swapfree = extract_number(buf, 322, 335);
197  */
198 
199  std::ifstream input( "/proc/meminfo" );
200 
201  std::string line;
202  if ( input.is_open() )
203  {
204  while ( !input.eof() )
205  {
206  getline( input, line );
207  analyseMemInfo( line, meminfo );
208  }
209  input.close();
210  }
211 
212 }
213 
214 //------------------------------------------------------------------------------
215 
216 void PosixMemoryMonitorTools::analyseMemInfo( std::string& line, MemInfo& meminfo )
217 {
218  ::boost::regex e("([A-Za-z:]+)([ \t]+)([0-9]+)([ \t]+)kB(.*)");
219  std::string machine_format = "\\3";
220  if ( line.find("MemTotal") != std::string::npos )
221  {
222  std::string size = regex_replace(line, e, machine_format, ::boost::match_default | ::boost::format_sed);
223  meminfo.total = ::boost::lexical_cast< std::uint64_t >(size) * 1024;
224  }
225  else if ( line.find("MemFree") != std::string::npos )
226  {
227  std::string size = regex_replace(line, e, machine_format, ::boost::match_default | ::boost::format_sed);
228  meminfo.free = ::boost::lexical_cast< std::uint64_t >(size) * 1024;
229  }
230  else if ( line.find("Buffers") != std::string::npos )
231  {
232  std::string size = regex_replace(line, e, machine_format, ::boost::match_default | ::boost::format_sed);
233  meminfo.buffered = ::boost::lexical_cast< std::uint64_t >(size) * 1024;
234  }
235  else if ( line.find("SwapCached") != std::string::npos ) // Test before => line.find("Cached")
236  {
237  std::string size = regex_replace(line, e, machine_format, ::boost::match_default | ::boost::format_sed);
238  meminfo.swapcached = ::boost::lexical_cast< std::uint64_t >(size) * 1024;
239  }
240  else if ( line.find("Cached") != std::string::npos )
241  {
242  std::string size = regex_replace(line, e, machine_format, ::boost::match_default | ::boost::format_sed);
243  meminfo.cached = ::boost::lexical_cast< std::uint64_t >(size) * 1024;
244  }
245  else if ( line.find("SwapTotal") != std::string::npos )
246  {
247  std::string size = regex_replace(line, e, machine_format, ::boost::match_default | ::boost::format_sed);
248  meminfo.swaptotal = ::boost::lexical_cast< std::uint64_t >(size) * 1024;
249  }
250  else if ( line.find("SwapFree") != std::string::npos )
251  {
252  std::string size = regex_replace(line, e, machine_format, ::boost::match_default | ::boost::format_sed);
253  meminfo.swapfree = ::boost::lexical_cast< std::uint64_t >(size) * 1024;
254  }
255 }
256 
257 //------------------------------------------------------------------------------
258 //------------------------------------------------------------------------------
259 
260 void PosixMemoryMonitorTools::printStatus( Status& stat )
261 {
262  int oToMo = 1024 * 1024;
263  OSLM_DEBUG("VmPeak = " << stat.VmPeak / oToMo << " Mo" );
264  OSLM_DEBUG("VmSize = " << stat.VmSize / oToMo << " Mo" );
265  OSLM_DEBUG("VmLck = " << stat.VmLck / oToMo << " Mo" );
266  OSLM_DEBUG("VmHWM = " << stat.VmHWM / oToMo << " Mo" );
267  OSLM_DEBUG("VmRSS = " << stat.VmRSS / oToMo << " Mo" );
268  OSLM_DEBUG("VmData = " << stat.VmData / oToMo << " Mo" );
269  OSLM_DEBUG("VmStk = " << stat.VmStk / oToMo << " Mo" );
270  OSLM_DEBUG("VmExe = " << stat.VmExe / oToMo << " Mo" );
271  OSLM_DEBUG("VmLib = " << stat.VmLib / oToMo << " Mo" );
272  OSLM_DEBUG("VmPTE = " << stat.VmPTE / oToMo << " Mo" );
273  (void)oToMo; // Fixes "unused variable" warnings
274 }
275 
276 //------------------------------------------------------------------------------
277 
278 void PosixMemoryMonitorTools::analyseStatusLine( std::string& line, Status& stat )
279 {
280  ::boost::regex e("([A-Za-z:]+)([ \t]+)([0-9]+)([ \t]+)kB(.*)");
281  std::string machine_format = "\\3";
282  if ( line.find("VmPeak") != std::string::npos )
283  {
284  std::string size = regex_replace(line, e, machine_format, ::boost::match_default | ::boost::format_sed);
285  stat.VmPeak = ::boost::lexical_cast< std::uint64_t >(size) * 1024;
286  }
287  else if ( line.find("VmSize") != std::string::npos )
288  {
289  std::string size = regex_replace(line, e, machine_format, ::boost::match_default | ::boost::format_sed);
290  stat.VmSize = ::boost::lexical_cast< std::uint64_t >(size) * 1024;
291  }
292  else if ( line.find("VmLck") != std::string::npos )
293  {
294  std::string size = regex_replace(line, e, machine_format, ::boost::match_default | ::boost::format_sed);
295  stat.VmLck = ::boost::lexical_cast< std::uint64_t >(size) * 1024;
296  }
297  else if ( line.find("VmHWM") != std::string::npos )
298  {
299  std::string size = regex_replace(line, e, machine_format, ::boost::match_default | ::boost::format_sed);
300  stat.VmHWM = ::boost::lexical_cast< std::uint64_t >(size) * 1024;
301  }
302  else if ( line.find("VmRSS") != std::string::npos )
303  {
304  std::string size = regex_replace(line, e, machine_format, ::boost::match_default | ::boost::format_sed);
305  stat.VmRSS = ::boost::lexical_cast< std::uint64_t >(size) * 1024;
306  }
307  else if ( line.find("VmData") != std::string::npos )
308  {
309  std::string size = regex_replace(line, e, machine_format, ::boost::match_default | ::boost::format_sed);
310  stat.VmData = ::boost::lexical_cast< std::uint64_t >(size) * 1024;
311  }
312  else if ( line.find("VmStk") != std::string::npos )
313  {
314  std::string size = regex_replace(line, e, machine_format, ::boost::match_default | ::boost::format_sed);
315  stat.VmStk = ::boost::lexical_cast< std::uint64_t >(size) * 1024;
316  }
317  else if ( line.find("VmExe") != std::string::npos )
318  {
319  std::string size = regex_replace(line, e, machine_format, ::boost::match_default | ::boost::format_sed);
320  stat.VmExe = ::boost::lexical_cast< std::uint64_t >(size) * 1024;
321  }
322  else if ( line.find("VmLib") != std::string::npos )
323  {
324  std::string size = regex_replace(line, e, machine_format, ::boost::match_default | ::boost::format_sed);
325  stat.VmLib = ::boost::lexical_cast< std::uint64_t >(size) * 1024;
326  }
327  else if ( line.find("VmPTE") != std::string::npos )
328  {
329  std::string size = regex_replace(line, e, machine_format, ::boost::match_default | ::boost::format_sed);
330  stat.VmPTE = ::boost::lexical_cast< std::uint64_t >(size) * 1024;
331  }
332 }
333 
334 //------------------------------------------------------------------------------
335 
336 void PosixMemoryMonitorTools::getStatusOfPid( int pid, Status& stat)
337 {
338  std::stringstream file;
339  file << "/proc/" << pid << "/status";
340  std::ifstream input( file.str().c_str() );
341 
342  std::string line;
343  if ( input.is_open() )
344  {
345  while ( !input.eof() )
346  {
347  getline( input, line );
348  analyseStatusLine(line, stat);
349  }
350  input.close();
351  }
352 }
353 
354 //------------------------------------------------------------------------------
355 
356 void PosixMemoryMonitorTools::getAllStatus( Status& allStat )
357 {
358  ::boost::filesystem::path path("/proc");
359  ::boost::regex e("[0-9]+");
360 
361  allStat.VmPeak = 0;
362  allStat.VmSize = 0;
363  allStat.VmLck = 0;
364  allStat.VmHWM = 0;
365  allStat.VmRSS = 0;
366  allStat.VmData = 0;
367  allStat.VmStk = 0;
368  allStat.VmExe = 0;
369  allStat.VmLib = 0;
370  allStat.VmPTE = 0;
371 
372  for( ::boost::filesystem::directory_iterator it(path);
373  it != ::boost::filesystem::directory_iterator();
374  ++it )
375  {
376 
377  if( ::boost::filesystem::is_directory(*it) )
378  {
379  ::boost::filesystem::path tmpPath = (*it);
380  std::string dirName = tmpPath.filename().string();
381  if ( regex_match(dirName, e) )
382  {
383  int pid = strtoul(dirName.c_str(), NULL, 0);
384  Status stat;
385  getStatusOfPid( pid, stat);
386  allStat.VmPeak += stat.VmPeak;
387  allStat.VmSize += stat.VmSize;
388  allStat.VmLck += stat.VmLck;
389  allStat.VmHWM += stat.VmHWM;
390  allStat.VmRSS += stat.VmRSS;
391  allStat.VmData += stat.VmData;
392  allStat.VmStk += stat.VmStk;
393  allStat.VmExe += stat.VmExe;
394  allStat.VmLib += stat.VmLib;
395  allStat.VmPTE += stat.VmPTE;
396  }
397  }
398  }
399 }
400 
401 //------------------------------------------------------------------------------
402 
403 void PosixMemoryMonitorTools::printAllStatus()
404 {
405  ::boost::filesystem::path path("/proc");
406  ::boost::regex e("[0-9]+");
407  int oToMo = 1024 * 1024;
408 
409  std::uint64_t totalVmPeak = 0;
410  std::uint64_t totalVmSize = 0;
411  std::uint64_t totalVmLck = 0;
412  std::uint64_t totalVmHWM = 0;
413  std::uint64_t totalVmRSS = 0;
414  std::uint64_t totalVmData = 0;
415  std::uint64_t totalVmStk = 0;
416  std::uint64_t totalVmExe = 0;
417  std::uint64_t totalVmLib = 0;
418  std::uint64_t totalVmPTE = 0;
419 
420  for( ::boost::filesystem::directory_iterator it(path);
421  it != ::boost::filesystem::directory_iterator();
422  ++it )
423  {
424 
425  if( ::boost::filesystem::is_directory(*it) )
426  {
427  ::boost::filesystem::path tmpPath = (*it);
428  std::string dirName = tmpPath.filename().string();
429  if ( regex_match(dirName, e) )
430  {
431  int pid = strtoul(dirName.c_str(), NULL, 0);
432  Status stat;
433  getStatusOfPid( pid, stat);
434  totalVmPeak += stat.VmPeak;
435  totalVmSize += stat.VmSize;
436  totalVmLck += stat.VmLck;
437  totalVmHWM += stat.VmHWM;
438  totalVmRSS += stat.VmRSS;
439  totalVmData += stat.VmData;
440  totalVmStk += stat.VmStk;
441  totalVmExe += stat.VmExe;
442  totalVmLib += stat.VmLib;
443  totalVmPTE += stat.VmPTE;
444  }
445  }
446  }
447  totalVmPeak /= oToMo;
448  totalVmSize /= oToMo;
449  totalVmLck /= oToMo;
450  totalVmHWM /= oToMo;
451  totalVmRSS /= oToMo;
452  totalVmData /= oToMo;
453  totalVmStk /= oToMo;
454  totalVmExe /= oToMo;
455  totalVmLib /= oToMo;
456  totalVmPTE /= oToMo;
457 
458  OSLM_DEBUG("( " << totalVmPeak << std::setw(5) << totalVmSize << std::setw(5) << totalVmLck << std::setw(
459  5) << totalVmHWM << std::setw(5) << totalVmRSS << std::setw(5) << totalVmData << std::setw(
460  5) << totalVmStk << std::setw(5) << totalVmExe << std::setw(5) << totalVmLib << std::setw(
461  5) << totalVmPTE << " )");
462 
463  /*
464  OSLM_DEBUG("totalVmPeak = " << totalVmPeak / oToMo << " Mo" );
465  OSLM_DEBUG("totalVmSize = " << totalVmSize / oToMo << " Mo" );
466  OSLM_DEBUG("totalVmLck = " << totalVmLck / oToMo << " Mo" );
467  OSLM_DEBUG("totalVmHWM = " << totalVmHWM / oToMo << " Mo" );
468  OSLM_DEBUG("totalVmRSS = " << totalVmRSS / oToMo << " Mo" );
469  OSLM_DEBUG("totalVmData = " << totalVmData / oToMo << " Mo" );
470  OSLM_DEBUG("totalVmStk = " << totalVmStk / oToMo << " Mo" );
471  OSLM_DEBUG("totalVmExe = " << totalVmExe / oToMo << " Mo" );
472  OSLM_DEBUG("totalVmLib = " << totalVmLib / oToMo << " Mo" );
473  OSLM_DEBUG("totalVmPTE = " << totalVmPTE / oToMo << " Mo" );
474  */
475 }
476 
477 } // namespace tools
478 } // namespace fwMemory
479 
480 #endif //defined(linux) || defined(__linux)
The namespace fwMemory contains tools to manage memory. Use for dump.
Definition: SReader.hpp:20
#define OSLM_INFO(message)
Definition: spyLog.hpp:252
The namespace memory contains tools to manage memory. It is used for dump. It allows to define the bu...
#define OSLM_DEBUG(message)
Definition: spyLog.hpp:241