Orfeo Toolbox  3.16
itkMemoryUsageObserver.cxx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkMemoryUsageObserver.cxx,v $
5  Language: C++
6  Date: $Date: 2009-01-25 22:57:26 $
7  Version: $Revision: 1.2 $
8 
9  Copyright (c) Insight Software Consortium. All rights reserved.
10  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
11 
12  This software is distributed WITHOUT ANY WARRANTY; without even
13  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14  PURPOSE. See the above copyright notices for more information.
15 
16 =========================================================================*/
17 
18 #include "itkConfigure.h"
19 #include "itkMemoryUsageObserver.h"
20 
21 #if defined(WIN32) || defined(_WIN32)
22  #include <windows.h>
23  #if defined(SUPPORT_PSAPI)
24  #include <psapi.h>
25  #endif
26 #endif // defined(WIN32) || defined(_WIN32)
27 
28 #ifdef linux
29  #include "itkSmapsFileParser.h"
30 #endif // linux
31 
32 #if defined(__APPLE__) && MAC_OS_X_VERSION >= MAC_OS_X_VERSION_10_2
33  #include "itkSmapsFileParser.h"
34 #endif // Mac OS X
35 
36 #if defined(__SUNPRO_CC) || defined (__sun__)
37  #include <unistd.h>
38  #include <stdio.h>
39  #include <string>
40  #include <sstream>
41 #endif // !defined(__SUNPRO_CC) && !defined (__sun__)
42 
43 #if !defined(WIN32) && !defined(_WIN32)
44  #include <sys/resource.h> // getrusage()
45  #if !defined(__APPLE__) && !defined(__SUNPRO_CC) && !defined (__sun__) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
46  #include <malloc.h> // mallinfo()
47  #endif // !defined(__APPLE__) && !defined(__SUNPRO_CC) && !defined (__sun__)
48 #endif // !defined(WIN32) && !defined(_WIN32)
49 
50 #if defined(__OpenBSD__)
51 #include <stdlib.h>
52 #endif
53 
54 namespace itk
55 {
56 
58 {
59 }
60 
61 
62 #if defined(WIN32) || defined(_WIN32)
63 
66 WindowsMemoryUsageObserver::WindowsMemoryUsageObserver()
67 {
68 #if defined(SUPPORT_TOOLHELP32)
69  m_hNTLib = ::LoadLibraryA("ntdll.dll");
70  if(m_hNTLib)
71  {
72  // load the support function from the kernel
73  ZwQuerySystemInformation = (PZwQuerySystemInformation)::GetProcAddress(m_hNTLib,
74  "ZwQuerySystemInformation");
75  }
76 #endif
77 }
78 
79 WindowsMemoryUsageObserver::~WindowsMemoryUsageObserver()
80 {
81 #if defined (SUPPORT_TOOLHELP32)
82  if(m_hNTLib)
83  {
84  FreeLibrary(m_hNTLib);
85  }
86 #endif
87 }
88 
89 #if defined(SUPPORT_TOOLHELP32)
90 
91 #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
92 
93 typedef LONG KPRIORITY;
94 #define SystemProcessesAndThreadsInformation 5
95 
96 typedef struct _CLIENT_ID {
97  DWORD UniqueProcess;
98  DWORD UniqueThread;
99 } CLIENT_ID;
100 
101 typedef struct _UNICODE_STRING {
102  USHORT Length;
103  USHORT MaximumLength;
104  PWSTR Buffer;
105 } UNICODE_STRING;
106 
107 typedef struct _VM_COUNTERS {
108 #ifdef _WIN64
109  // the following was inferred by painful reverse engineering
110  SIZE_T PeakVirtualSize; // not actually
111  SIZE_T PageFaultCount;
112  SIZE_T PeakWorkingSetSize;
113  SIZE_T WorkingSetSize;
114  SIZE_T QuotaPeakPagedPoolUsage;
115  SIZE_T QuotaPagedPoolUsage;
116  SIZE_T QuotaPeakNonPagedPoolUsage;
117  SIZE_T QuotaNonPagedPoolUsage;
118  SIZE_T PagefileUsage;
119  SIZE_T PeakPagefileUsage;
120  SIZE_T VirtualSize; // not actually
121 #else
122  SIZE_T PeakVirtualSize;
123  SIZE_T VirtualSize;
124  ULONG PageFaultCount;
125  SIZE_T PeakWorkingSetSize;
126  SIZE_T WorkingSetSize;
127  SIZE_T QuotaPeakPagedPoolUsage;
128  SIZE_T QuotaPagedPoolUsage;
129  SIZE_T QuotaPeakNonPagedPoolUsage;
130  SIZE_T QuotaNonPagedPoolUsage;
131  SIZE_T PagefileUsage;
132  SIZE_T PeakPagefileUsage;
133 #endif
134 } VM_COUNTERS;
135 
136 typedef struct _SYSTEM_THREADS {
137  LARGE_INTEGER KernelTime;
138  LARGE_INTEGER UserTime;
139  LARGE_INTEGER CreateTime;
140  ULONG WaitTime;
141  PVOID StartAddress;
142  CLIENT_ID ClientId;
143  KPRIORITY Priority;
144  KPRIORITY BasePriority;
145  ULONG ContextSwitchCount;
146  LONG State;
147  LONG WaitReason;
148 } SYSTEM_THREADS, * PSYSTEM_THREADS;
149 
150 typedef struct _SYSTEM_PROCESSES { // Information Class 5
151  ULONG NextEntryDelta;
152  ULONG ThreadCount;
153  ULONG Reserved1[6];
154  LARGE_INTEGER CreateTime;
155  LARGE_INTEGER UserTime;
156  LARGE_INTEGER KernelTime;
157  UNICODE_STRING ProcessName;
158  KPRIORITY BasePriority;
159 #ifdef _WIN64
160  ULONG pad1;
161  ULONG ProcessId;
162  ULONG pad2;
163  ULONG InheritedFromProcessId;
164  ULONG pad3;
165  ULONG pad4;
166  ULONG pad5;
167 #else
168  ULONG ProcessId;
169  ULONG InheritedFromProcessId;
170 #endif
171  ULONG HandleCount;
172  ULONG Reserved2[2];
173  VM_COUNTERS VmCounters;
174 #if defined(_WIN64) || _WIN32_WINNT >= 0x500
175  IO_COUNTERS IoCounters;
176 #endif
177  SYSTEM_THREADS Threads[1];
178 } SYSTEM_PROCESSES, *PSYSTEM_PROCESSES;
179 #endif
180 
182 WindowsMemoryUsageObserver::GetMemoryUsage()
183 {
184 
185  MemoryLoadType mem = 0;
186 
187 #if defined(SUPPORT_PSAPI)
188  DWORD pid = GetCurrentProcessId();
189  PROCESS_MEMORY_COUNTERS memoryCounters;
190 
191  HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
192  PROCESS_VM_READ,
193  FALSE, pid );
194 
195  if (NULL == hProcess)
196  {
197  // Can't determine memory usage.
198  return 0;
199  }
200 
201  GetProcessMemoryInfo( hProcess, &memoryCounters, sizeof(memoryCounters));
202 
203  mem = static_cast<MemoryLoadType>(
204  static_cast<double>( memoryCounters.PagefileUsage )
205  / 1024.0 );
206 #elif defined(SUPPORT_TOOLHELP32)
207 
208  /* Retrieve memory usage using Windows Native API. For more information,
209  * read the book "Windows NT 2000 Native API Reference"
210  */
211 
212  if(!m_hNTLib)
213  {
214  itkGenericExceptionMacro( << "Can't find ntdll.dll. "
215  << "You should probably disable SUPPORT_TOOLHELP32" );
216  }
217  // the ntdll.dll library could not have been opened (file not found?)
218  if ( !ZwQuerySystemInformation )
219  {
220  itkGenericExceptionMacro( << "The file ntdll.dll is not supported. "
221  << "You should probably disable SUPPORT_TOOLHELP32" );
222  return mem;
223  }
224 
225  DWORD pid = GetCurrentProcessId();
226  ULONG n = 50;
227  PSYSTEM_PROCESSES sp = new SYSTEM_PROCESSES[n];
228  // as we can't know how many processes running, we loop and test a new size everytime.
229  while (ZwQuerySystemInformation(SystemProcessesAndThreadsInformation,
230  sp, n * sizeof *sp, 0)
231  == STATUS_INFO_LENGTH_MISMATCH)
232  {
233  delete [] sp;
234  n = n * 2;
235  sp = new SYSTEM_PROCESSES[n];
236  }
237  bool done = false;
238  for ( PSYSTEM_PROCESSES spp = sp;
239  !done;
240  spp = PSYSTEM_PROCESSES(PCHAR(spp) + spp->NextEntryDelta))
241  {
242  // only the current process is interesting here
243  if (spp->ProcessId == pid)
244  {
245  mem = static_cast<MemoryLoadType>(
246  static_cast<double>( spp->VmCounters.PagefileUsage - sizeof(*sp)) / 1024);
247  break;
248  }
249  done = (spp->NextEntryDelta == 0);
250  }
251  delete [] sp;
252 
253 #else
254 
255  /* This solution is not optimal as it returns the system memory usage
256  * instead of the process memory usage.
257  */
258 
259  MEMORYSTATUSEX statex;
260 
261  statex.dwLength = sizeof (statex);
262 
263  GlobalMemoryStatusEx (&statex);
264 
265  mem = static_cast<MemoryLoadType>(
266  static_cast<double>( statex.ullTotalPhys - statex.ullAvailPhys) / 1024);
267 #endif
268  return mem;
269 }
270 
271 #endif // WIN32
272 
273 #if linux
274 
277 LinuxMemoryUsageObserver::~LinuxMemoryUsageObserver()
278 {
279 }
280 
282 LinuxMemoryUsageObserver::GetMemoryUsage()
283 {
284  SmapsFileParser<SmapsData_2_6> m_ParseSmaps;
285  m_ParseSmaps.ReadFile();
286  return m_ParseSmaps.GetHeapUsage() + m_ParseSmaps.GetStackUsage();
287 }
288 
289 #endif // linux
290 
291 #if defined(__APPLE__) && MAC_OS_X_VERSION >= MAC_OS_X_VERSION_10_2
292 
295 MacOSXMemoryUsageObserver::~MacOSXMemoryUsageObserver()
296 {
297 }
298 
300 MacOSXMemoryUsageObserver::GetMemoryUsage()
301 {
302  VMMapFileParser<VMMapData_10_2> m_ParseVMMmap;
303  m_ParseVMMmap.ReadFile();
304  return m_ParseVMMmap.GetHeapUsage() + m_ParseVMMmap.GetStackUsage();
305 }
306 
307 #endif // Mac OS X
308 
309 #if defined(__SUNPRO_CC) || defined (__sun__)
310 
313 SunSolarisMemoryUsageObserver::~SunSolarisMemoryUsageObserver()
314 {
315 }
331 SunSolarisMemoryUsageObserver::GetMemoryUsage()
332 {
333  MemoryLoadType mem = 0;
334  int pid = getpid();
335 
336  FILE * fp = NULL;
337  std::stringstream command;
338  command << "pmap " << pid << std::endl;
339 
340  if ((fp = popen(command.str().c_str(), "r")) == NULL)
341  {
342  itkGenericExceptionMacro( << "Error using pmap. Can execute pmap command" );
343  }
344  char remaining[256];
345  int pmappid = -1;
346  fscanf(fp,"%d:%s",&pmappid,remaining);
347  //the first word shall be the process ID
348  if ( pmappid != pid)
349  {
350  itkGenericExceptionMacro( << "Error using pmap. 1st line output shall be PID: name" );
351  }
352  bool heapNotFound = true;
353  char address[64],perms[32];
354  int memUsage = 0;
355  std::string mapping;
356  while (heapNotFound)
357  {
358  if ( fscanf(fp,"%s %dK %s",address, &memUsage, perms) != 3 )
359  break;
360  if ( fgets(remaining,256,fp) != NULL )
361  {
362  mapping = remaining;
363  if ( mapping.find("[ heap ]",0) != std::string::npos)
364  {
365  mem = memUsage;
366  heapNotFound = false;
367  break;
368  }
369  // if no [ heap ] token is defined, accumulate all the [ xxx ] tokens
370  else if ( mapping.find("[ ",0) != std::string::npos &&
371  mapping.find(" ]",0) != std::string::npos )
372  {
373  mem += memUsage;
374  }
375  }
376  else
377  {
378  if (ferror (fp))
379  {
380  itkGenericExceptionMacro( << "Error using pmap. Corrupted pmap output" );
381  }
382  }
383  }
384  if (pclose(fp) == -1)
385  {
386  itkGenericExceptionMacro( << "Error using pmap. Can't close pmap output file." );
387  }
388  return mem;
389 }
390 #endif //defined(__SUNPRO_CC) || defined (__sun__)
391 
392 #if !defined(WIN32) && !defined(_WIN32) || defined(__OpenBSD__)
393 
397 {
398 }
399 
402 {
403  // Maybe use getrusage() ??
404  rusage resourceInfo;
405 
406  int who = RUSAGE_SELF;
407  if (getrusage(who, &resourceInfo) == 0)
408  {
409  return resourceInfo.ru_ixrss;
410  }
411 
412  return 0;
413 }
414 
415 #if !defined(__APPLE__) && !defined(__SUNPRO_CC) && !defined (__sun__) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
416 
420 {
421 }
422 
425 {
426  struct mallinfo minfo = mallinfo();
427 
428  MemoryLoadType mem = static_cast<MemoryLoadType>(
429  static_cast<double>( minfo.uordblks ) / 1024.0 );
430  return mem;
431 }
432 
433 #endif // !defined(__APPLE__) && !defined(__SUNPRO_CC) && !defined (__sun__) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
434 
435 #endif // Unix and Mac Platforms !defined(WIN32) && !defined(_WIN32)
436 
437 }//end namespace itk

Generated at Sat Feb 2 2013 23:52:37 for Orfeo Toolbox with doxygen 1.8.1.1