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 <stdlib.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 <stdlib.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 // =======================================================================
OSD_MemInfo(const Standard_Boolean theImmediateUpdate)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 // =======================================================================
SetActive(const Standard_Boolean theActive)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 // =======================================================================
Clear()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 // =======================================================================
Update()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 // =======================================================================
ToString() const286 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 // =======================================================================
Value(const OSD_MemInfo::Counter theCounter) const326 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 // =======================================================================
ValueMiB(const OSD_MemInfo::Counter theCounter) const339 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 // =======================================================================
ValuePreciseMiB(const OSD_MemInfo::Counter theCounter) const353 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 // =======================================================================
PrintInfo()367 TCollection_AsciiString OSD_MemInfo::PrintInfo()
368 {
369 OSD_MemInfo anInfo;
370 return anInfo.ToString();
371 }
372