25ebc7686edd3f690308f9e9f341392515d2e5ae
[occt.git] / src / OSD / OSD_MemInfo.cxx
1 // Created on: 2011-10-05
2 // Created by: Kirill GAVRILOV
3 // Copyright (c) 2013-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #if (defined(_WIN32) || defined(__WIN32__))
17   #include <windows.h>
18   #include <winbase.h>
19   #include <process.h>
20   #include <malloc.h>
21   #include <Psapi.h>
22   #ifdef _MSC_VER
23     #pragma comment(lib, "Psapi.lib")
24   #endif
25 #elif (defined(__APPLE__))
26   #include <mach/task.h>
27   #include <mach/mach.h>
28   #include <malloc/malloc.h>
29 #else
30   #include <unistd.h>
31   #include <malloc.h>
32 #endif
33
34 #include <string>
35 #include <sstream>
36 #include <fstream>
37
38 #include <OSD_MemInfo.hxx>
39
40 // =======================================================================
41 // function : OSD_MemInfo
42 // purpose  :
43 // =======================================================================
44 OSD_MemInfo::OSD_MemInfo()
45 {
46   Update();
47 }
48
49 // =======================================================================
50 // function : Update
51 // purpose  :
52 // =======================================================================
53 void OSD_MemInfo::Update()
54 {
55   // reset values
56   for (Standard_Integer anIter = 0; anIter < MemCounter_NB; ++anIter)
57   {
58     myCounters[anIter] = Standard_Size(-1);
59   }
60
61 #if (defined(_WIN32) || defined(__WIN32__))
62   MEMORYSTATUSEX aStatEx;
63   aStatEx.dwLength = sizeof(aStatEx);
64   GlobalMemoryStatusEx (&aStatEx);
65   myCounters[MemVirtual] = Standard_Size(aStatEx.ullTotalVirtual - aStatEx.ullAvailVirtual);
66
67   // use Psapi library
68   HANDLE aProcess = GetCurrentProcess();
69 #if (_WIN32_WINNT >= 0x0501)
70   PROCESS_MEMORY_COUNTERS_EX aProcMemCnts;
71 #else
72   PROCESS_MEMORY_COUNTERS    aProcMemCnts;
73 #endif
74   if (GetProcessMemoryInfo (aProcess, (PROCESS_MEMORY_COUNTERS* )&aProcMemCnts, sizeof(aProcMemCnts)))
75   {
76   #if (_WIN32_WINNT >= 0x0501)
77     myCounters[MemPrivate]        = aProcMemCnts.PrivateUsage;
78   #endif
79     myCounters[MemWorkingSet]     = aProcMemCnts.WorkingSetSize;
80     myCounters[MemWorkingSetPeak] = aProcMemCnts.PeakWorkingSetSize;
81     myCounters[MemSwapUsage]      = aProcMemCnts.PagefileUsage;
82     myCounters[MemSwapUsagePeak]  = aProcMemCnts.PeakPagefileUsage;
83   }
84
85   _HEAPINFO hinfo;
86   int heapstatus;
87   hinfo._pentry = NULL;
88
89   myCounters[MemHeapUsage] = 0;
90   while((heapstatus = _heapwalk(&hinfo)) == _HEAPOK)
91   {
92     if(hinfo._useflag == _USEDENTRY)
93       myCounters[MemHeapUsage] += hinfo._size;
94   }
95
96 #elif (defined(__linux__) || defined(__linux))
97   // use procfs on Linux
98   char aBuff[4096];
99   snprintf (aBuff, sizeof(aBuff), "/proc/%d/status", getpid());
100   std::ifstream aFile;
101   aFile.open (aBuff);
102   if (!aFile.is_open())
103   {
104     return;
105   }
106
107   while (!aFile.eof())
108   {
109     memset (aBuff, 0, sizeof(aBuff));
110     aFile.getline (aBuff, 4096);
111     if (aBuff[0] == '\0')
112     {
113       continue;
114     }
115
116     if (strncmp (aBuff, "VmSize:", strlen ("VmSize:")) == 0)
117     {
118       myCounters[MemVirtual] = atol (aBuff + strlen ("VmSize:")) * 1024;
119     }
120     //else if (strncmp (aBuff, "VmPeak:", strlen ("VmPeak:")) == 0)
121     //  myVirtualPeak = atol (aBuff + strlen ("VmPeak:")) * 1024;
122     else if (strncmp (aBuff, "VmRSS:", strlen ("VmRSS:")) == 0)
123     {
124       myCounters[MemWorkingSet] = atol (aBuff + strlen ("VmRSS:")) * 1024; // RSS - resident set size
125     }
126     else if (strncmp (aBuff, "VmHWM:", strlen ("VmHWM:")) == 0)
127     {
128       myCounters[MemWorkingSetPeak] = atol (aBuff + strlen ("VmHWM:")) * 1024; // HWM - high water mark
129     }
130     else if (strncmp (aBuff, "VmData:", strlen ("VmData:")) == 0)
131     {
132       if (myCounters[MemPrivate] == Standard_Size(-1)) ++myCounters[MemPrivate];
133       myCounters[MemPrivate] += atol (aBuff + strlen ("VmData:")) * 1024;
134     }
135     else if (strncmp (aBuff, "VmStk:", strlen ("VmStk:")) == 0)
136     {
137       if (myCounters[MemPrivate] == Standard_Size(-1)) ++myCounters[MemPrivate];
138       myCounters[MemPrivate] += atol (aBuff + strlen ("VmStk:")) * 1024;
139     }
140   }
141   aFile.close();
142
143   struct mallinfo aMI = mallinfo();
144   myCounters[MemHeapUsage] = aMI.uordblks;
145
146 #elif (defined(__APPLE__))
147   struct task_basic_info aTaskInfo;
148   mach_msg_type_number_t aTaskInfoCount = TASK_BASIC_INFO_COUNT;
149   if (task_info (mach_task_self(), TASK_BASIC_INFO,
150                  (task_info_t )&aTaskInfo, &aTaskInfoCount) == KERN_SUCCESS)
151   {
152     // On Mac OS X, these values in bytes, not pages!
153     myCounters[MemVirtual]    = aTaskInfo.virtual_size;
154     myCounters[MemWorkingSet] = aTaskInfo.resident_size;
155
156     //Getting malloc statistics
157     malloc_statistics_t aStats;
158     malloc_zone_statistics (NULL, &aStats);
159
160     myCounters[MemHeapUsage] = aStats.size_in_use;
161   }
162 #endif
163 }
164
165 // =======================================================================
166 // function : ToString
167 // purpose  :
168 // =======================================================================
169 TCollection_AsciiString OSD_MemInfo::ToString() const
170 {
171   TCollection_AsciiString anInfo;
172   if (myCounters[MemPrivate] != Standard_Size(-1))
173   {
174     anInfo += TCollection_AsciiString("  Private memory:     ") + Standard_Integer (ValueMiB (MemPrivate)) + " MiB\n";
175   }
176   if (myCounters[MemWorkingSet] != Standard_Size(-1))
177   {
178     anInfo += TCollection_AsciiString("  Working Set:        ") +  Standard_Integer (ValueMiB (MemWorkingSet)) + " MiB";
179     if (myCounters[MemWorkingSetPeak] != Standard_Size(-1))
180     {
181       anInfo += TCollection_AsciiString(" (peak: ") +  Standard_Integer (ValueMiB (MemWorkingSetPeak)) + " MiB)";
182     }
183     anInfo += "\n";
184   }
185   if (myCounters[MemSwapUsage] != Standard_Size(-1))
186   {
187     anInfo += TCollection_AsciiString("  Pagefile usage:     ") +  Standard_Integer (ValueMiB (MemSwapUsage)) + " MiB";
188     if (myCounters[MemSwapUsagePeak] != Standard_Size(-1))
189     {
190       anInfo += TCollection_AsciiString(" (peak: ") +  Standard_Integer (ValueMiB (MemSwapUsagePeak)) + " MiB)";
191     }
192     anInfo += "\n";
193   }
194   if (myCounters[MemVirtual] != Standard_Size(-1))
195   {
196     anInfo += TCollection_AsciiString("  Virtual memory:     ") +  Standard_Integer (ValueMiB (MemVirtual)) + " MiB\n";
197   }
198   if (myCounters[MemHeapUsage] != Standard_Size(-1))
199   {
200     anInfo += TCollection_AsciiString("  Heap memory:     ") +  Standard_Integer (ValueMiB (MemHeapUsage)) + " MiB\n";
201   }
202   return anInfo;
203 }
204
205 // =======================================================================
206 // function : Value
207 // purpose  :
208 // =======================================================================
209 Standard_Size OSD_MemInfo::Value (const OSD_MemInfo::Counter theCounter) const
210 {
211   if (theCounter < 0 || theCounter >= MemCounter_NB)
212   {
213     return Standard_Size(-1);
214   }
215   return myCounters[theCounter];
216 }
217
218 // =======================================================================
219 // function : ValueMiB
220 // purpose  :
221 // =======================================================================
222 Standard_Size OSD_MemInfo::ValueMiB (const OSD_MemInfo::Counter theCounter) const
223 {
224   if (theCounter < 0 || theCounter >= MemCounter_NB)
225   {
226     return Standard_Size(-1);
227   }
228   return (myCounters[theCounter] == Standard_Size(-1))
229        ? Standard_Size(-1) : (myCounters[theCounter] / (1024 * 1024));
230 }
231
232 // =======================================================================
233 // function : ShowInfo
234 // purpose  :
235 // =======================================================================
236 TCollection_AsciiString OSD_MemInfo::PrintInfo()
237 {
238   OSD_MemInfo anInfo;
239   return anInfo.ToString();
240 }