File: itkMemoryUsageObserver.cxx

package info (click to toggle)
insighttoolkit 3.20.1%2Bgit20120521-5
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 80,672 kB
  • ctags: 85,253
  • sloc: cpp: 458,133; ansic: 196,222; fortran: 28,000; python: 3,839; tcl: 1,811; sh: 1,184; java: 583; makefile: 428; csh: 220; perl: 193; xml: 20
file content (440 lines) | stat: -rw-r--r-- 12,113 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkMemoryUsageObserver.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "itkConfigure.h"
#include "itkMemoryUsageObserver.h"

#if defined(WIN32) || defined(_WIN32)
  #include <windows.h>
  #if defined(SUPPORT_PSAPI)
    #include <psapi.h>
  #endif
#endif // defined(WIN32) || defined(_WIN32)

#ifdef linux
  #include "itkSmapsFileParser.h"
#endif // linux

#if defined(__APPLE__) && MAC_OS_X_VERSION >= MAC_OS_X_VERSION_10_2
  #include "itkSmapsFileParser.h"
#endif // Mac OS X

#if defined(__SUNPRO_CC) || defined (__sun__)
  #include <unistd.h>
  #include <stdio.h>
  #include <string>
  #include <sstream>
#endif // !defined(__SUNPRO_CC) && !defined (__sun__)

#if !defined(WIN32) && !defined(_WIN32)
  #include <sys/resource.h>     // getrusage()
  #if !defined( __APPLE__ ) && !defined( __SUNPRO_CC ) && !defined ( __sun__ ) && !defined( __FreeBSD__ ) \
  && !defined( __OpenBSD__ )
    #include <malloc.h>           // mallinfo()
  #endif // !defined(__APPLE__) && !defined(__SUNPRO_CC) && !defined (__sun__)
#endif // !defined(WIN32) && !defined(_WIN32)

#if defined( __OpenBSD__ )
#include <stdlib.h>
#endif

namespace itk
{

MemoryUsageObserverBase::~MemoryUsageObserverBase()
{
}


#if defined(WIN32) || defined(_WIN32)

/**         ----         Windows Memory Usage Observer       ----       */ 

WindowsMemoryUsageObserver::WindowsMemoryUsageObserver()
{
#if defined(SUPPORT_TOOLHELP32)
  m_hNTLib = ::LoadLibraryA("ntdll.dll");
  if(m_hNTLib)
    {
    // load the support function from the kernel
    ZwQuerySystemInformation = (PZwQuerySystemInformation)::GetProcAddress(m_hNTLib, 
                                                                           "ZwQuerySystemInformation");
    }
#endif
}

WindowsMemoryUsageObserver::~WindowsMemoryUsageObserver()
{
#if defined (SUPPORT_TOOLHELP32)
  if(m_hNTLib)
    {
    FreeLibrary(m_hNTLib);
    }
#endif
}

#if defined(SUPPORT_TOOLHELP32)

#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)

typedef LONG    KPRIORITY;
#define SystemProcessesAndThreadsInformation    5

typedef struct _CLIENT_ID {
  DWORD        UniqueProcess;
  DWORD        UniqueThread;
} CLIENT_ID;

typedef struct _UNICODE_STRING {
  USHORT        Length;
  USHORT        MaximumLength;
  PWSTR        Buffer;
} UNICODE_STRING;

typedef struct _VM_COUNTERS {
#ifdef _WIN64
  // the following was inferred by painful reverse engineering
  SIZE_T         PeakVirtualSize;     // not actually
  SIZE_T         PageFaultCount;
  SIZE_T         PeakWorkingSetSize;
  SIZE_T         WorkingSetSize;
  SIZE_T         QuotaPeakPagedPoolUsage;
  SIZE_T         QuotaPagedPoolUsage;
  SIZE_T         QuotaPeakNonPagedPoolUsage;
  SIZE_T         QuotaNonPagedPoolUsage;
  SIZE_T         PagefileUsage;
  SIZE_T         PeakPagefileUsage;
  SIZE_T         VirtualSize;         // not actually
#else
  SIZE_T         PeakVirtualSize;
  SIZE_T         VirtualSize;
  ULONG          PageFaultCount;
  SIZE_T         PeakWorkingSetSize;
  SIZE_T         WorkingSetSize;
  SIZE_T         QuotaPeakPagedPoolUsage;
  SIZE_T         QuotaPagedPoolUsage;
  SIZE_T         QuotaPeakNonPagedPoolUsage;
  SIZE_T         QuotaNonPagedPoolUsage;
  SIZE_T         PagefileUsage;
  SIZE_T         PeakPagefileUsage;
#endif
} VM_COUNTERS;

typedef struct _SYSTEM_THREADS {
  LARGE_INTEGER   KernelTime;
  LARGE_INTEGER   UserTime;
  LARGE_INTEGER   CreateTime;
  ULONG           WaitTime;
  PVOID           StartAddress;
  CLIENT_ID       ClientId;
  KPRIORITY       Priority;
  KPRIORITY       BasePriority;
  ULONG           ContextSwitchCount;
  LONG            State;
  LONG            WaitReason;
} SYSTEM_THREADS, * PSYSTEM_THREADS;

typedef struct _SYSTEM_PROCESSES { // Information Class 5
  ULONG NextEntryDelta;
  ULONG ThreadCount;
  ULONG Reserved1[6];
  LARGE_INTEGER CreateTime;
  LARGE_INTEGER UserTime;
  LARGE_INTEGER KernelTime;
  UNICODE_STRING ProcessName;
  KPRIORITY BasePriority;
#ifdef _WIN64
  ULONG  pad1;
  ULONG  ProcessId;
  ULONG  pad2;
  ULONG  InheritedFromProcessId;
  ULONG  pad3;
  ULONG  pad4;
  ULONG  pad5;
#else
  ULONG  ProcessId;
  ULONG  InheritedFromProcessId;
#endif
  ULONG HandleCount;
  ULONG Reserved2[2];
  VM_COUNTERS VmCounters;
#if defined(_WIN64) || _WIN32_WINNT >= 0x500
  IO_COUNTERS        IoCounters;
#endif
  SYSTEM_THREADS Threads[1];
} SYSTEM_PROCESSES, *PSYSTEM_PROCESSES;
#endif
  
MemoryUsageObserverBase::MemoryLoadType 
WindowsMemoryUsageObserver::GetMemoryUsage()
{

  MemoryLoadType mem = 0;

#if defined(SUPPORT_PSAPI)
  DWORD pid = GetCurrentProcessId();
  PROCESS_MEMORY_COUNTERS memoryCounters;

  HANDLE  hProcess = OpenProcess(  PROCESS_QUERY_INFORMATION |
                                   PROCESS_VM_READ,
                                   FALSE, pid );

  if (NULL == hProcess)
    {
    // Can't determine memory usage.
    return 0;
    }

  GetProcessMemoryInfo( hProcess, &memoryCounters, sizeof(memoryCounters));

  mem = static_cast<MemoryLoadType>( 
    static_cast<double>( memoryCounters.PagefileUsage )
    / 1024.0 ); 
#elif defined(SUPPORT_TOOLHELP32)

  /* Retrieve memory usage using Windows Native API. For more information, 
   * read the book "Windows NT 2000 Native API Reference" 
  */

  if(!m_hNTLib)
    {
    itkGenericExceptionMacro( << "Can't find ntdll.dll. "
                              << "You should probably disable SUPPORT_TOOLHELP32" );
    }
  // the ntdll.dll library could not have been opened (file not found?)
  if ( !ZwQuerySystemInformation )
    {
    itkGenericExceptionMacro( << "The file ntdll.dll is not supported. "
                              << "You should probably disable SUPPORT_TOOLHELP32" );
    return mem;
    }

  DWORD pid = GetCurrentProcessId();
  ULONG n = 50;
  PSYSTEM_PROCESSES sp = new SYSTEM_PROCESSES[n];
  // as we can't know how many processes running, we loop and test a new size everytime.
  while (ZwQuerySystemInformation(SystemProcessesAndThreadsInformation,
                                  sp, n * sizeof *sp, 0)
         == STATUS_INFO_LENGTH_MISMATCH)
    {
    delete [] sp;
    n = n * 2;
    sp = new SYSTEM_PROCESSES[n];
    }
  bool done = false;
  for ( PSYSTEM_PROCESSES spp = sp; 
        !done; 
        spp = PSYSTEM_PROCESSES(PCHAR(spp) + spp->NextEntryDelta))
    {
    // only the current process is interesting here
    if (spp->ProcessId == pid)
      {
      mem = static_cast<MemoryLoadType>( 
        static_cast<double>( spp->VmCounters.PagefileUsage - sizeof(*sp)) / 1024);
      break;
      }
    done = (spp->NextEntryDelta == 0);
    }
  delete [] sp;
  
#else

  /* This solution is not optimal as it returns the system memory usage 
   * instead of the process memory usage. 
  */

  MEMORYSTATUSEX statex;

  statex.dwLength = sizeof (statex);

  GlobalMemoryStatusEx (&statex);

  mem   = static_cast<MemoryLoadType>( 
    static_cast<double>( statex.ullTotalPhys - statex.ullAvailPhys) / 1024);
#endif
  return mem;
}

#endif // WIN32

#if linux

/**         ----         Linux Memory Usage Observer       ----       */ 

LinuxMemoryUsageObserver::~LinuxMemoryUsageObserver()
{
}

MemoryUsageObserverBase::MemoryLoadType 
LinuxMemoryUsageObserver::GetMemoryUsage()
{
  SmapsFileParser<SmapsData_2_6> m_ParseSmaps;
  m_ParseSmaps.ReadFile();
  return m_ParseSmaps.GetHeapUsage() + m_ParseSmaps.GetStackUsage();
}

#endif // linux

#if defined(__APPLE__) && MAC_OS_X_VERSION >= MAC_OS_X_VERSION_10_2

/**         ----         Mac OS X Memory Usage Observer       ----       */ 

MacOSXMemoryUsageObserver::~MacOSXMemoryUsageObserver()
{
}

MemoryUsageObserverBase::MemoryLoadType 
MacOSXMemoryUsageObserver::GetMemoryUsage()
{
  VMMapFileParser<VMMapData_10_2> m_ParseVMMmap;
  m_ParseVMMmap.ReadFile();
  return m_ParseVMMmap.GetHeapUsage() + m_ParseVMMmap.GetStackUsage();
}

#endif // Mac OS X

#if defined(__SUNPRO_CC) || defined (__sun__)

/**         ----         Sun Solaris Memory Usage Observer       ----       */ 

SunSolarisMemoryUsageObserver::~SunSolarisMemoryUsageObserver()
{
}
/** On Sun Solaris machines, the system call pmap returns information on process.
 *  calling "pmap PID", the output shall be like the following:
 *  102905:    *my_app*
 *  00010000    192K r-x--  /usr/bin/my_app
 *  00042000     40K rwx--    [ heap ]
 *  FF180000    664K r-x--  /usr/lib/libc.so.1
 *  FF236000     24K rwx--  /usr/lib/libc.so.1
 *  FF23C000      8K rwx--  /usr/lib/libc.so.1
 *  FF250000      8K rwx--    [ anon ]
 *  ...       ...    ...    ...
 *  FF3F6000      8K rwx--  /usr/lib/ld.so.1
 *  FFBFC000     16K rw---    [ stack ]
 *   total     1880K
 */
MemoryUsageObserverBase::MemoryLoadType 
SunSolarisMemoryUsageObserver::GetMemoryUsage()
{
  MemoryLoadType mem = 0;
  int pid = getpid();

  FILE * fp = NULL;
  std::stringstream command;
  command << "pmap " << pid << std::endl;
  
  if ((fp = popen(command.str().c_str(), "r")) == NULL)
    {
    itkGenericExceptionMacro( << "Error using pmap. Can execute pmap command" );
    }
  char remaining[256];
  int pmappid = -1;
  fscanf(fp,"%d:%s",&pmappid,remaining);
  //the first word shall be the process ID
  if ( pmappid != pid)
    {
    itkGenericExceptionMacro( << "Error using pmap. 1st line output shall be PID: name" );
    }
  bool heapNotFound = true;
  char address[64],perms[32];
  int memUsage = 0;
  std::string mapping;
  while (heapNotFound)
    {
    if ( fscanf(fp,"%s %dK %s",address, &memUsage, perms) != 3 )
      break;
    if ( fgets(remaining,256,fp) != NULL )
      {
      mapping = remaining;
      if ( mapping.find("[ heap ]",0) != std::string::npos)
        {
        mem = memUsage;
        heapNotFound = false;
        break;
        }
      // if no [ heap ] token is defined, accumulate all the [ xxx ] tokens
      else if ( mapping.find("[ ",0) != std::string::npos && 
                mapping.find(" ]",0) != std::string::npos )
        {  
        mem += memUsage;
        }
      }
    else
      {
      if (ferror (fp))
        {
        itkGenericExceptionMacro( << "Error using pmap. Corrupted pmap output" );
        }
      }
    }
  if (pclose(fp) == -1)
    {
    itkGenericExceptionMacro( << "Error using pmap. Can't close pmap output file." );
    }
  return mem;
}
#endif //defined(__SUNPRO_CC) || defined (__sun__)

#if !defined( WIN32 ) && !defined( _WIN32 ) || defined( __OpenBSD__ )

/**         ----         SysResource Memory Usage Observer       ----       */ 

SysResourceMemoryUsageObserver::~SysResourceMemoryUsageObserver()
{
}

MemoryUsageObserverBase::MemoryLoadType 
SysResourceMemoryUsageObserver::GetMemoryUsage()
{
  // Maybe use getrusage() ??
  rusage resourceInfo;

  int who = RUSAGE_SELF;
  if (getrusage(who, &resourceInfo) == 0)
    {
    return resourceInfo.ru_ixrss;
    }

  return 0;
}

#if !defined( __APPLE__ ) && !defined( __SUNPRO_CC ) && !defined ( __sun__ ) && !defined( __FreeBSD__ ) \
  && !defined( __OpenBSD__ )

/**         ----         Mallinfo Memory Usage Observer       ----       */ 

MallinfoMemoryUsageObserver::~MallinfoMemoryUsageObserver()
{
}

MemoryUsageObserverBase::MemoryLoadType 
MallinfoMemoryUsageObserver::GetMemoryUsage()
{
  struct mallinfo minfo = mallinfo(); 

  MemoryLoadType mem = static_cast<MemoryLoadType>( 
    static_cast<double>( minfo.uordblks ) / 1024.0 );
  return mem;
}

#endif //  !defined(__APPLE__) && !defined(__SUNPRO_CC) && !defined (__sun__) &&
       // !defined(__FreeBSD__) && !defined(__OpenBSD__)

#endif // Unix and Mac Platforms !defined(WIN32) && !defined(_WIN32) 

}//end namespace itk