0030901: Visualization - OSD_MemInfo moving memory computation out of the constructor
[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))
120   // use procfs on Linux
121   char aBuff[4096];
122   snprintf (aBuff, sizeof(aBuff), "/proc/%d/status", getpid());
123   std::ifstream aFile;
124   aFile.open (aBuff);
125   if (!aFile.is_open())
126   {
127     return;
128   }
129
130   while (!aFile.eof())
131   {
132     memset (aBuff, 0, sizeof(aBuff));
133     aFile.getline (aBuff, 4096);
134     if (aBuff[0] == '\0')
135     {
136       continue;
137     }
138
139     if (strncmp (aBuff, "VmSize:", strlen ("VmSize:")) == 0)
140     {
141       myCounters[MemVirtual] = atol (aBuff + strlen ("VmSize:")) * 1024;
142     }
143     //else if (strncmp (aBuff, "VmPeak:", strlen ("VmPeak:")) == 0)
144     //  myVirtualPeak = atol (aBuff + strlen ("VmPeak:")) * 1024;
145     else if (strncmp (aBuff, "VmRSS:", strlen ("VmRSS:")) == 0)
146     {
147       myCounters[MemWorkingSet] = atol (aBuff + strlen ("VmRSS:")) * 1024; // RSS - resident set size
148     }
149     else if (strncmp (aBuff, "VmHWM:", strlen ("VmHWM:")) == 0)
150     {
151       myCounters[MemWorkingSetPeak] = atol (aBuff + strlen ("VmHWM:")) * 1024; // HWM - high water mark
152     }
153     else if (strncmp (aBuff, "VmData:", strlen ("VmData:")) == 0)
154     {
155       if (myCounters[MemPrivate] == Standard_Size(-1)) ++myCounters[MemPrivate];
156       myCounters[MemPrivate] += atol (aBuff + strlen ("VmData:")) * 1024;
157     }
158     else if (strncmp (aBuff, "VmStk:", strlen ("VmStk:")) == 0)
159     {
160       if (myCounters[MemPrivate] == Standard_Size(-1)) ++myCounters[MemPrivate];
161       myCounters[MemPrivate] += atol (aBuff + strlen ("VmStk:")) * 1024;
162     }
163   }
164   aFile.close();
165
166   struct mallinfo aMI = mallinfo();
167   myCounters[MemHeapUsage] = aMI.uordblks;
168
169 #elif (defined(__APPLE__))
170   struct task_basic_info aTaskInfo;
171   mach_msg_type_number_t aTaskInfoCount = TASK_BASIC_INFO_COUNT;
172   if (task_info (mach_task_self(), TASK_BASIC_INFO,
173                  (task_info_t )&aTaskInfo, &aTaskInfoCount) == KERN_SUCCESS)
174   {
175     // On Mac OS X, these values in bytes, not pages!
176     myCounters[MemVirtual]    = aTaskInfo.virtual_size;
177     myCounters[MemWorkingSet] = aTaskInfo.resident_size;
178
179     //Getting malloc statistics
180     malloc_statistics_t aStats;
181     malloc_zone_statistics (NULL, &aStats);
182
183     myCounters[MemHeapUsage] = aStats.size_in_use;
184   }
185 #endif
186 #endif
187 }
188
189 // =======================================================================
190 // function : ToString
191 // purpose  :
192 // =======================================================================
193 TCollection_AsciiString OSD_MemInfo::ToString() const
194 {
195   TCollection_AsciiString anInfo;
196   if (myCounters[MemPrivate] != Standard_Size(-1))
197   {
198     anInfo += TCollection_AsciiString("  Private memory:     ") + Standard_Integer (ValueMiB (MemPrivate)) + " MiB\n";
199   }
200   if (myCounters[MemWorkingSet] != Standard_Size(-1))
201   {
202     anInfo += TCollection_AsciiString("  Working Set:        ") +  Standard_Integer (ValueMiB (MemWorkingSet)) + " MiB";
203     if (myCounters[MemWorkingSetPeak] != Standard_Size(-1))
204     {
205       anInfo += TCollection_AsciiString(" (peak: ") +  Standard_Integer (ValueMiB (MemWorkingSetPeak)) + " MiB)";
206     }
207     anInfo += "\n";
208   }
209   if (myCounters[MemSwapUsage] != Standard_Size(-1))
210   {
211     anInfo += TCollection_AsciiString("  Pagefile usage:     ") +  Standard_Integer (ValueMiB (MemSwapUsage)) + " MiB";
212     if (myCounters[MemSwapUsagePeak] != Standard_Size(-1))
213     {
214       anInfo += TCollection_AsciiString(" (peak: ") +  Standard_Integer (ValueMiB (MemSwapUsagePeak)) + " MiB)";
215     }
216     anInfo += "\n";
217   }
218   if (myCounters[MemVirtual] != Standard_Size(-1))
219   {
220     anInfo += TCollection_AsciiString("  Virtual memory:     ") +  Standard_Integer (ValueMiB (MemVirtual)) + " MiB\n";
221   }
222   if (myCounters[MemHeapUsage] != Standard_Size(-1))
223   {
224     anInfo += TCollection_AsciiString("  Heap memory:     ") +  Standard_Integer (ValueMiB (MemHeapUsage)) + " MiB\n";
225   }
226   return anInfo;
227 }
228
229 // =======================================================================
230 // function : Value
231 // purpose  :
232 // =======================================================================
233 Standard_Size OSD_MemInfo::Value (const OSD_MemInfo::Counter theCounter) const
234 {
235   if (theCounter < 0 || theCounter >= MemCounter_NB)
236   {
237     return Standard_Size(-1);
238   }
239   return myCounters[theCounter];
240 }
241
242 // =======================================================================
243 // function : ValueMiB
244 // purpose  :
245 // =======================================================================
246 Standard_Size OSD_MemInfo::ValueMiB (const OSD_MemInfo::Counter theCounter) const
247 {
248   if (theCounter < 0 || theCounter >= MemCounter_NB)
249   {
250     return Standard_Size(-1);
251   }
252   return (myCounters[theCounter] == Standard_Size(-1))
253        ? Standard_Size(-1) : (myCounters[theCounter] / (1024 * 1024));
254 }
255
256 // =======================================================================
257 // function : ValuePreciseMiB
258 // purpose  :
259 // =======================================================================
260 Standard_Real OSD_MemInfo::ValuePreciseMiB (const OSD_MemInfo::Counter theCounter) const
261 {
262   if (theCounter < 0 || theCounter >= MemCounter_NB)
263   {
264     return -1.0;
265   }
266   return (myCounters[theCounter] == Standard_Size(-1))
267        ? -1.0 : ((Standard_Real )myCounters[theCounter] / (1024.0 * 1024.0));
268 }
269
270 // =======================================================================
271 // function : ShowInfo
272 // purpose  :
273 // =======================================================================
274 TCollection_AsciiString OSD_MemInfo::PrintInfo()
275 {
276   OSD_MemInfo anInfo;
277   return anInfo.ToString();
278 }