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