3ccb35ab8198e1cdbae1e46886594e488ee7aa49
[platform/upstream/coreclr.git] / src / pal / src / misc / sysinfo.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 /*++
6
7
8
9 Module Name:
10
11     sysinfo.c
12
13 Abstract:
14
15     Implements GetSystemInfo.
16
17 Revision History:
18
19
20
21 --*/
22
23 #include "pal/palinternal.h"
24
25 #include <sched.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <sys/types.h>
29 #if HAVE_SYSCTL
30 #include <sys/sysctl.h>
31 #elif !HAVE_SYSCONF
32 #error Either sysctl or sysconf is required for GetSystemInfo.
33 #endif
34
35 #include <sys/param.h>
36
37 #if HAVE_SYS_VMPARAM_H
38 #include <sys/vmparam.h>
39 #endif  // HAVE_SYS_VMPARAM_H
40
41 #if HAVE_MACH_VM_TYPES_H
42 #include <mach/vm_types.h>
43 #endif // HAVE_MACH_VM_TYPES_H
44
45 #if HAVE_MACH_VM_PARAM_H
46 #include <mach/vm_param.h>
47 #endif  // HAVE_MACH_VM_PARAM_H
48
49 #if HAVE_MACHINE_VMPARAM_H
50 #include <machine/vmparam.h>
51 #endif  // HAVE_MACHINE_VMPARAM_H
52
53 #if defined(_TARGET_MAC64)
54 #include <mach/vm_statistics.h>
55 #include <mach/mach_types.h>
56 #include <mach/mach_init.h>
57 #include <mach/mach_host.h>
58 #endif // defined(_TARGET_MAC64)
59
60 // On some platforms sys/user.h ends up defining _DEBUG; if so
61 // remove the definition before including the header and put
62 // back our definition afterwards
63 #if USER_H_DEFINES_DEBUG
64 #define OLD_DEBUG _DEBUG
65 #undef _DEBUG
66 #endif
67 #include <sys/user.h>
68 #if USER_H_DEFINES_DEBUG
69 #undef _DEBUG
70 #define _DEBUG OLD_DEBUG
71 #undef OLD_DEBUG
72 #endif
73
74 #include "pal/dbgmsg.h"
75
76
77 SET_DEFAULT_DEBUG_CHANNEL(MISC);
78
79 #ifndef __APPLE__
80 #if HAVE_SYSCONF && HAVE__SC_AVPHYS_PAGES
81 #define SYSCONF_PAGES _SC_AVPHYS_PAGES
82 #elif HAVE_SYSCONF && HAVE__SC_PHYS_PAGES
83 #define SYSCONF_PAGES _SC_PHYS_PAGES
84 #else
85 #error Dont know how to get page-size on this architecture!
86 #endif
87 #endif // __APPLE__
88
89
90 /*++
91 Function:
92   GetSystemInfo
93
94 GetSystemInfo
95
96 The GetSystemInfo function returns information about the current system.
97
98 Parameters
99
100 lpSystemInfo
101        [out] Pointer to a SYSTEM_INFO structure that receives the information.
102
103 Return Values
104
105 This function does not return a value.
106
107 Note:
108   fields returned by this function are:
109     dwNumberOfProcessors
110     dwPageSize
111 Others are set to zero.
112
113 --*/
114 VOID
115 PALAPI
116 GetSystemInfo(
117           OUT LPSYSTEM_INFO lpSystemInfo)
118 {
119     int nrcpus = 0;
120     long pagesize;
121
122     PERF_ENTRY(GetSystemInfo);
123     ENTRY("GetSystemInfo (lpSystemInfo=%p)\n", lpSystemInfo);
124
125     pagesize = getpagesize();
126
127     lpSystemInfo->wProcessorArchitecture_PAL_Undefined = 0;
128     lpSystemInfo->wReserved_PAL_Undefined = 0;
129     lpSystemInfo->dwPageSize = pagesize;
130     lpSystemInfo->dwActiveProcessorMask_PAL_Undefined = 0;
131
132 #if HAVE_SYSCONF
133     nrcpus = sysconf(_SC_NPROCESSORS_ONLN);
134     if (nrcpus < 1)
135     {
136         ASSERT("sysconf failed for _SC_NPROCESSORS_ONLN (%d)\n", errno);
137     }
138 #elif HAVE_SYSCTL
139     int rc;
140     size_t sz;
141     int mib[2];
142
143     sz = sizeof(nrcpus);
144     mib[0] = CTL_HW;
145     mib[1] = HW_NCPU;
146     rc = sysctl(mib, 2, &nrcpus, &sz, NULL, 0);
147     if (rc != 0)
148     {
149         ASSERT("sysctl failed for HW_NCPU (%d)\n", errno);
150     }
151 #endif // HAVE_SYSCONF
152
153     TRACE("dwNumberOfProcessors=%d\n", nrcpus);
154     lpSystemInfo->dwNumberOfProcessors = nrcpus;
155
156 #ifdef VM_MAXUSER_ADDRESS
157     lpSystemInfo->lpMaximumApplicationAddress = (PVOID) VM_MAXUSER_ADDRESS;
158 #elif defined(__linux__)
159     lpSystemInfo->lpMaximumApplicationAddress = (PVOID) (1ull << 47);
160 #elif defined(USERLIMIT)
161     lpSystemInfo->lpMaximumApplicationAddress = (PVOID) USERLIMIT;
162 #elif defined(_WIN64)
163 #if defined(USRSTACK64)
164     lpSystemInfo->lpMaximumApplicationAddress = (PVOID) USRSTACK64;
165 #else // !USRSTACK64
166 #error How come USRSTACK64 is not defined for 64bit?
167 #endif // USRSTACK64
168 #elif defined(USRSTACK)
169     lpSystemInfo->lpMaximumApplicationAddress = (PVOID) USRSTACK;
170 #else
171 #error The maximum application address is not known on this platform.
172 #endif
173
174     lpSystemInfo->lpMinimumApplicationAddress = (PVOID) pagesize;
175
176     lpSystemInfo->dwProcessorType_PAL_Undefined = 0;
177
178     lpSystemInfo->dwAllocationGranularity = pagesize;
179
180     lpSystemInfo->wProcessorLevel_PAL_Undefined = 0;
181     lpSystemInfo->wProcessorRevision_PAL_Undefined = 0;
182
183     LOGEXIT("GetSystemInfo returns VOID\n");
184     PERF_EXIT(GetSystemInfo);
185 }
186
187 /*++
188 Function:
189   GlobalMemoryStatusEx
190
191 GlobalMemoryStatusEx
192
193 Retrieves information about the system's current usage of both physical and virtual memory.
194
195 Return Values
196
197 This function returns a BOOL to indicate its success status.
198
199 --*/
200 BOOL
201 PALAPI
202 GlobalMemoryStatusEx(
203             IN OUT LPMEMORYSTATUSEX lpBuffer)
204 {
205
206     PERF_ENTRY(GlobalMemoryStatusEx);
207     ENTRY("GlobalMemoryStatusEx (lpBuffer=%p)\n", lpBuffer);
208
209     lpBuffer->dwMemoryLoad = 0;
210     lpBuffer->ullTotalPhys = 0;
211     lpBuffer->ullAvailPhys = 0;
212     lpBuffer->ullTotalPageFile = 0;
213     lpBuffer->ullAvailPageFile = 0;
214     lpBuffer->ullTotalVirtual = 0;
215     lpBuffer->ullAvailVirtual = 0;
216     lpBuffer->ullAvailExtendedVirtual = 0;
217
218     BOOL fRetVal = FALSE;
219
220     // Get the physical memory size
221 #if HAVE_SYSCONF && HAVE__SC_PHYS_PAGES
222     int64_t physical_memory;
223
224     // Get the Physical memory size
225     physical_memory = sysconf( _SC_PHYS_PAGES ) * sysconf( _SC_PAGE_SIZE );
226     lpBuffer->ullTotalPhys = (DWORDLONG)physical_memory;
227     fRetVal = TRUE;
228 #elif HAVE_SYSCTL
229     int mib[2];
230     int64_t physical_memory;
231     size_t length;
232
233     // Get the Physical memory size
234     mib[0] = CTL_HW;
235     mib[1] = HW_MEMSIZE;
236     length = sizeof(INT64);
237     int rc = sysctl(mib, 2, &physical_memory, &length, NULL, 0);
238     if (rc != 0)
239     {
240         ASSERT("sysctl failed for HW_MEMSIZE (%d)\n", errno);
241     }
242     else
243     {
244         lpBuffer->ullTotalPhys = (DWORDLONG)physical_memory;
245         fRetVal = TRUE;
246     }
247 #elif // HAVE_SYSINFO
248     // TODO: implement getting memory details via sysinfo. On Linux, it provides swap file details that
249     // we can use to fill in the xxxPageFile members.
250
251 #endif // HAVE_SYSCONF
252
253     // Get the physical memory in use - from it, we can get the physical memory available.
254     // We do this only when we have the total physical memory available.
255     if (lpBuffer->ullTotalPhys > 0)
256     {
257 #ifndef __APPLE__
258         lpBuffer->ullAvailPhys = sysconf(SYSCONF_PAGES) * sysconf(_SC_PAGE_SIZE);
259         INT64 used_memory = lpBuffer->ullTotalPhys - lpBuffer->ullAvailPhys;
260         lpBuffer->dwMemoryLoad = (DWORD)((used_memory * 100) / lpBuffer->ullTotalPhys);
261 #else
262         vm_size_t page_size;
263         mach_port_t mach_port;
264         mach_msg_type_number_t count;
265         vm_statistics_data_t vm_stats;
266         mach_port = mach_host_self();
267         count = sizeof(vm_stats) / sizeof(natural_t);
268         if (KERN_SUCCESS == host_page_size(mach_port, &page_size))
269         {
270             if (KERN_SUCCESS == host_statistics(mach_port, HOST_VM_INFO, (host_info_t)&vm_stats, &count))
271             {
272                 lpBuffer->ullAvailPhys = (int64_t)vm_stats.free_count * (int64_t)page_size;
273                 INT64 used_memory = ((INT64)vm_stats.active_count + (INT64)vm_stats.inactive_count + (INT64)vm_stats.wire_count) *  (INT64)page_size;
274                 lpBuffer->dwMemoryLoad = (DWORD)((used_memory * 100) / lpBuffer->ullTotalPhys);
275             }
276         }
277         mach_port_deallocate(mach_task_self(), mach_port);
278 #endif // __APPLE__
279     }
280
281     // There is no API to get the total virtual address space size on 
282     // Unix, so we use a constant value representing 128TB, which is 
283     // the approximate size of total user virtual address space on
284     // the currently supported Unix systems.
285     static const UINT64 _128TB = (1ull << 47); 
286     lpBuffer->ullTotalVirtual = _128TB;
287     lpBuffer->ullAvailVirtual = lpBuffer->ullAvailPhys;
288
289     LOGEXIT("GlobalMemoryStatusEx returns %d\n", fRetVal);
290     PERF_EXIT(GlobalMemoryStatusEx);
291
292     return fRetVal;
293 }
294
295 PALIMPORT
296 DWORD
297 PALAPI
298 GetCurrentProcessorNumber()
299 {
300 #if HAVE_SCHED_GETCPU
301     return sched_getcpu();
302 #else //HAVE_SCHED_GETCPU
303     return -1;
304 #endif //HAVE_SCHED_GETCPU
305 }
306
307 BOOL
308 PALAPI
309 PAL_HasGetCurrentProcessorNumber()
310 {
311     return HAVE_SCHED_GETCPU;
312 }
313
314 DWORD
315 PALAPI
316 PAL_GetLogicalCpuCountFromOS()
317 {
318     DWORD numLogicalCores = 0;
319
320 #if HAVE_SYSCONF
321     numLogicalCores = sysconf(_SC_NPROCESSORS_ONLN);
322 #endif
323
324     return numLogicalCores;
325 }
326
327 size_t
328 PALAPI
329 PAL_GetLogicalProcessorCacheSizeFromOS()
330 {
331     size_t cacheSize = 0;
332
333 #ifdef _SC_LEVEL1_DCACHE_SIZE
334     cacheSize = max(cacheSize, sysconf(_SC_LEVEL1_DCACHE_SIZE));
335 #endif
336 #ifdef _SC_LEVEL2_CACHE_SIZE
337     cacheSize = max(cacheSize, sysconf(_SC_LEVEL2_CACHE_SIZE));
338 #endif
339 #ifdef _SC_LEVEL3_CACHE_SIZE
340     cacheSize = max(cacheSize, sysconf(_SC_LEVEL3_CACHE_SIZE));
341 #endif
342 #ifdef _SC_LEVEL4_CACHE_SIZE
343     cacheSize = max(cacheSize, sysconf(_SC_LEVEL4_CACHE_SIZE));
344 #endif
345
346     return cacheSize;
347 }