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