0030904: Visualization - OSD_MemInfo provide Update with parameter of computation...
[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 (const Standard_Boolean theImmediateUpdate)
45 {
46   SetActive (Standard_True);
47   if (theImmediateUpdate)
48   {
49     Update();
50   }
51   else
52   {
53     Clear();
54   }
55 }
56
57 // =======================================================================
58 // function : SetActive
59 // purpose  :
60 // =======================================================================
61 void OSD_MemInfo::SetActive (const Standard_Boolean theActive)
62 {
63   for (Standard_Integer anIter = 0; anIter < MemCounter_NB; ++anIter)
64   {
65     SetActive ((Counter)anIter, theActive);
66   }
67 }
68
69 // =======================================================================
70 // function : Clear
71 // purpose  :
72 // =======================================================================
73 void OSD_MemInfo::Clear()
74 {
75   for (Standard_Integer anIter = 0; anIter < MemCounter_NB; ++anIter)
76   {
77     myCounters[anIter] = Standard_Size(-1);
78   }
79 }
80
81 // =======================================================================
82 // function : Update
83 // purpose  :
84 // =======================================================================
85 void OSD_MemInfo::Update()
86 {
87   Clear();
88 #ifndef OCCT_UWP
89 #if defined(_WIN32)
90 #if (_WIN32_WINNT >= 0x0500)
91   if (IsActive (MemVirtual))
92   {
93     MEMORYSTATUSEX aStatEx;
94     aStatEx.dwLength = sizeof(aStatEx);
95     GlobalMemoryStatusEx (&aStatEx);
96     myCounters[MemVirtual] = Standard_Size(aStatEx.ullTotalVirtual - aStatEx.ullAvailVirtual);
97   }
98 #else
99   if (IsActive (MemVirtual))
100   {
101     MEMORYSTATUS aStat;
102     aStat.dwLength = sizeof(aStat);
103     GlobalMemoryStatus (&aStat);
104     myCounters[MemVirtual] = Standard_Size(aStat.dwTotalVirtual - aStat.dwAvailVirtual);
105   }
106 #endif
107
108   if (IsActive (MemPrivate)
109    || IsActive (MemWorkingSet)
110    || IsActive (MemWorkingSetPeak)
111    || IsActive (MemSwapUsage)
112    || IsActive (MemSwapUsagePeak))
113   {
114     // use Psapi library
115     HANDLE aProcess = GetCurrentProcess();
116   #if (_WIN32_WINNT >= 0x0501)
117     PROCESS_MEMORY_COUNTERS_EX aProcMemCnts;
118   #else
119     PROCESS_MEMORY_COUNTERS    aProcMemCnts;
120   #endif
121     if (GetProcessMemoryInfo (aProcess, (PROCESS_MEMORY_COUNTERS* )&aProcMemCnts, sizeof(aProcMemCnts)))
122     {
123     #if (_WIN32_WINNT >= 0x0501)
124       myCounters[MemPrivate]        = aProcMemCnts.PrivateUsage;
125     #endif
126       myCounters[MemWorkingSet]     = aProcMemCnts.WorkingSetSize;
127       myCounters[MemWorkingSetPeak] = aProcMemCnts.PeakWorkingSetSize;
128       myCounters[MemSwapUsage]      = aProcMemCnts.PagefileUsage;
129       myCounters[MemSwapUsagePeak]  = aProcMemCnts.PeakPagefileUsage;
130     }
131   }
132
133   if (IsActive (MemHeapUsage))
134   {
135     _HEAPINFO hinfo;
136     int heapstatus;
137     hinfo._pentry = NULL;
138
139     myCounters[MemHeapUsage] = 0;
140     while((heapstatus = _heapwalk(&hinfo)) == _HEAPOK)
141     {
142       if (hinfo._useflag == _USEDENTRY)
143       {
144         myCounters[MemHeapUsage] += hinfo._size;
145       }
146     }
147   }
148
149 #elif (defined(__linux__) || defined(__linux) || defined(__EMSCRIPTEN__))
150   const struct mallinfo aMI = mallinfo();
151   if (IsActive (MemHeapUsage))
152   {
153     myCounters[MemHeapUsage] = aMI.uordblks;
154   }
155 #if defined(__EMSCRIPTEN__)
156   // /proc/%d/status is not emulated - get more info from mallinfo()
157   if (IsActive (MemWorkingSet))
158   {
159     myCounters[MemWorkingSet]     = aMI.uordblks;
160   }
161   if (IsActive (MemWorkingSetPeak))
162   {
163     myCounters[MemWorkingSetPeak] = aMI.usmblks;
164   }
165 #endif
166
167   // use procfs on Linux
168   char aBuff[4096];
169   snprintf (aBuff, sizeof(aBuff), "/proc/%d/status", getpid());
170   std::ifstream aFile;
171   aFile.open (aBuff);
172   if (!aFile.is_open())
173   {
174     return;
175   }
176
177   while (!aFile.eof())
178   {
179     memset (aBuff, 0, sizeof(aBuff));
180     aFile.getline (aBuff, 4096);
181     if (aBuff[0] == '\0')
182     {
183       continue;
184     }
185
186     if (IsActive (MemVirtual)
187      && strncmp (aBuff, "VmSize:", strlen ("VmSize:")) == 0)
188     {
189       myCounters[MemVirtual] = atol (aBuff + strlen ("VmSize:")) * 1024;
190     }
191     //else if (strncmp (aBuff, "VmPeak:", strlen ("VmPeak:")) == 0)
192     //  myVirtualPeak = atol (aBuff + strlen ("VmPeak:")) * 1024;
193     else if (IsActive (MemWorkingSet)
194           && strncmp (aBuff, "VmRSS:", strlen ("VmRSS:")) == 0)
195     {
196       myCounters[MemWorkingSet] = atol (aBuff + strlen ("VmRSS:")) * 1024; // RSS - resident set size
197     }
198     else if (IsActive (MemWorkingSetPeak)
199           && strncmp (aBuff, "VmHWM:", strlen ("VmHWM:")) == 0)
200     {
201       myCounters[MemWorkingSetPeak] = atol (aBuff + strlen ("VmHWM:")) * 1024; // HWM - high water mark
202     }
203     else if (IsActive (MemPrivate)
204           && strncmp (aBuff, "VmData:", strlen ("VmData:")) == 0)
205     {
206       if (myCounters[MemPrivate] == Standard_Size(-1)) ++myCounters[MemPrivate];
207       myCounters[MemPrivate] += atol (aBuff + strlen ("VmData:")) * 1024;
208     }
209     else if (IsActive (MemPrivate)
210           && strncmp (aBuff, "VmStk:", strlen ("VmStk:")) == 0)
211     {
212       if (myCounters[MemPrivate] == Standard_Size(-1)) ++myCounters[MemPrivate];
213       myCounters[MemPrivate] += atol (aBuff + strlen ("VmStk:")) * 1024;
214     }
215   }
216   aFile.close();
217 #elif (defined(__APPLE__))
218   if (IsActive (MemVirtual)
219    || IsActive (MemWorkingSet)
220    || IsActive (MemHeapUsage))
221   {
222     struct task_basic_info aTaskInfo;
223     mach_msg_type_number_t aTaskInfoCount = TASK_BASIC_INFO_COUNT;
224     if (task_info (mach_task_self(), TASK_BASIC_INFO,
225                    (task_info_t )&aTaskInfo, &aTaskInfoCount) == KERN_SUCCESS)
226     {
227       // On Mac OS X, these values in bytes, not pages!
228       myCounters[MemVirtual]    = aTaskInfo.virtual_size;
229       myCounters[MemWorkingSet] = aTaskInfo.resident_size;
230
231       //Getting malloc statistics
232       malloc_statistics_t aStats;
233       malloc_zone_statistics (NULL, &aStats);
234
235       myCounters[MemHeapUsage] = aStats.size_in_use;
236     }
237   }
238 #endif
239 #endif
240 }
241
242 // =======================================================================
243 // function : ToString
244 // purpose  :
245 // =======================================================================
246 TCollection_AsciiString OSD_MemInfo::ToString() const
247 {
248   TCollection_AsciiString anInfo;
249   if (hasValue (MemPrivate))
250   {
251     anInfo += TCollection_AsciiString("  Private memory:     ") + Standard_Integer (ValueMiB (MemPrivate)) + " MiB\n";
252   }
253   if (hasValue (MemWorkingSet))
254   {
255     anInfo += TCollection_AsciiString("  Working Set:        ") +  Standard_Integer (ValueMiB (MemWorkingSet)) + " MiB";
256     if (hasValue (MemWorkingSetPeak))
257     {
258       anInfo += TCollection_AsciiString(" (peak: ") +  Standard_Integer (ValueMiB (MemWorkingSetPeak)) + " MiB)";
259     }
260     anInfo += "\n";
261   }
262   if (hasValue (MemSwapUsage))
263   {
264     anInfo += TCollection_AsciiString("  Pagefile usage:     ") +  Standard_Integer (ValueMiB (MemSwapUsage)) + " MiB";
265     if (hasValue (MemSwapUsagePeak))
266     {
267       anInfo += TCollection_AsciiString(" (peak: ") +  Standard_Integer (ValueMiB (MemSwapUsagePeak)) + " MiB)";
268     }
269     anInfo += "\n";
270   }
271   if (hasValue (MemVirtual))
272   {
273     anInfo += TCollection_AsciiString("  Virtual memory:     ") +  Standard_Integer (ValueMiB (MemVirtual)) + " MiB\n";
274   }
275   if (hasValue (MemHeapUsage))
276   {
277     anInfo += TCollection_AsciiString("  Heap memory:     ") +  Standard_Integer (ValueMiB (MemHeapUsage)) + " MiB\n";
278   }
279   return anInfo;
280 }
281
282 // =======================================================================
283 // function : Value
284 // purpose  :
285 // =======================================================================
286 Standard_Size OSD_MemInfo::Value (const OSD_MemInfo::Counter theCounter) const
287 {
288   if (theCounter < 0 || theCounter >= MemCounter_NB || !IsActive (theCounter))
289   {
290     return Standard_Size(-1);
291   }
292   return myCounters[theCounter];
293 }
294
295 // =======================================================================
296 // function : ValueMiB
297 // purpose  :
298 // =======================================================================
299 Standard_Size OSD_MemInfo::ValueMiB (const OSD_MemInfo::Counter theCounter) const
300 {
301   if (theCounter < 0 || theCounter >= MemCounter_NB || !IsActive (theCounter))
302   {
303     return Standard_Size(-1);
304   }
305   return (myCounters[theCounter] == Standard_Size(-1))
306        ? Standard_Size(-1) : (myCounters[theCounter] / (1024 * 1024));
307 }
308
309 // =======================================================================
310 // function : ValuePreciseMiB
311 // purpose  :
312 // =======================================================================
313 Standard_Real OSD_MemInfo::ValuePreciseMiB (const OSD_MemInfo::Counter theCounter) const
314 {
315   if (theCounter < 0 || theCounter >= MemCounter_NB || !IsActive (theCounter))
316   {
317     return -1.0;
318   }
319   return (myCounters[theCounter] == Standard_Size(-1))
320        ? -1.0 : ((Standard_Real )myCounters[theCounter] / (1024.0 * 1024.0));
321 }
322
323 // =======================================================================
324 // function : ShowInfo
325 // purpose  :
326 // =======================================================================
327 TCollection_AsciiString OSD_MemInfo::PrintInfo()
328 {
329   OSD_MemInfo anInfo;
330   return anInfo.ToString();
331 }