// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. /*++ Module Name: sysinfo.c Abstract: Implements GetSystemInfo. Revision History: --*/ #include "pal/palinternal.h" #include #include #include #include #if HAVE_SYSCTL #include #elif !HAVE_SYSCONF #error Either sysctl or sysconf is required for GetSystemInfo. #endif #include #if HAVE_SYS_VMPARAM_H #include #endif // HAVE_SYS_VMPARAM_H #if HAVE_MACH_VM_TYPES_H #include #endif // HAVE_MACH_VM_TYPES_H #if HAVE_MACH_VM_PARAM_H #include #endif // HAVE_MACH_VM_PARAM_H #if HAVE_MACHINE_VMPARAM_H #include #endif // HAVE_MACHINE_VMPARAM_H #if defined(_TARGET_MAC64) #include #include #include #include #endif // defined(_TARGET_MAC64) // On some platforms sys/user.h ends up defining _DEBUG; if so // remove the definition before including the header and put // back our definition afterwards #if USER_H_DEFINES_DEBUG #define OLD_DEBUG _DEBUG #undef _DEBUG #endif #include #if USER_H_DEFINES_DEBUG #undef _DEBUG #define _DEBUG OLD_DEBUG #undef OLD_DEBUG #endif #include "pal/dbgmsg.h" SET_DEFAULT_DEBUG_CHANNEL(MISC); #if defined(_HPUX_) && ( defined (_IA64_) || defined (__hppa__) ) #include #include #endif #ifndef __APPLE__ #if HAVE_SYSCONF && HAVE__SC_AVPHYS_PAGES #define SYSCONF_PAGES _SC_AVPHYS_PAGES #elif HAVE_SYSCONF && HAVE__SC_PHYS_PAGES #define SYSCONF_PAGES _SC_PHYS_PAGES #else #error Dont know how to get page-size on this architecture! #endif #endif // __APPLE__ /*++ Function: GetSystemInfo GetSystemInfo The GetSystemInfo function returns information about the current system. Parameters lpSystemInfo [out] Pointer to a SYSTEM_INFO structure that receives the information. Return Values This function does not return a value. Note: fields returned by this function are: dwNumberOfProcessors dwPageSize Others are set to zero. --*/ VOID PALAPI GetSystemInfo( OUT LPSYSTEM_INFO lpSystemInfo) { int nrcpus = 0; long pagesize; PERF_ENTRY(GetSystemInfo); ENTRY("GetSystemInfo (lpSystemInfo=%p)\n", lpSystemInfo); pagesize = getpagesize(); lpSystemInfo->wProcessorArchitecture_PAL_Undefined = 0; lpSystemInfo->wReserved_PAL_Undefined = 0; lpSystemInfo->dwPageSize = pagesize; lpSystemInfo->dwActiveProcessorMask_PAL_Undefined = 0; #if HAVE_SYSCONF #if defined(_HPUX_) && ( defined (_IA64_) || defined (__hppa__) ) struct pst_dynamic psd; if (pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0) != -1) { nrcpus = psd.psd_proc_cnt; } else { ASSERT("pstat_getdynamic failed (%d)\n", errno); } #else // !__hppa__ nrcpus = sysconf(_SC_NPROCESSORS_ONLN); if (nrcpus < 1) { ASSERT("sysconf failed for _SC_NPROCESSORS_ONLN (%d)\n", errno); } #endif // __hppa__ #elif HAVE_SYSCTL int rc; size_t sz; int mib[2]; sz = sizeof(nrcpus); mib[0] = CTL_HW; mib[1] = HW_NCPU; rc = sysctl(mib, 2, &nrcpus, &sz, NULL, 0); if (rc != 0) { ASSERT("sysctl failed for HW_NCPU (%d)\n", errno); } #endif // HAVE_SYSCONF TRACE("dwNumberOfProcessors=%d\n", nrcpus); lpSystemInfo->dwNumberOfProcessors = nrcpus; #ifdef VM_MAXUSER_ADDRESS lpSystemInfo->lpMaximumApplicationAddress = (PVOID) VM_MAXUSER_ADDRESS; #elif defined(__sun__) || defined(_AIX) || defined(__hppa__) || ( defined (_IA64_) && defined (_HPUX_) ) || defined(__linux__) lpSystemInfo->lpMaximumApplicationAddress = (PVOID) (1ull << 47); #elif defined(USERLIMIT) lpSystemInfo->lpMaximumApplicationAddress = (PVOID) USERLIMIT; #elif defined(_WIN64) #if defined(USRSTACK64) lpSystemInfo->lpMaximumApplicationAddress = (PVOID) USRSTACK64; #else // !USRSTACK64 #error How come USRSTACK64 is not defined for 64bit? #endif // USRSTACK64 #elif defined(USRSTACK) lpSystemInfo->lpMaximumApplicationAddress = (PVOID) USRSTACK; #else #error The maximum application address is not known on this platform. #endif lpSystemInfo->lpMinimumApplicationAddress = (PVOID) pagesize; lpSystemInfo->dwProcessorType_PAL_Undefined = 0; lpSystemInfo->dwAllocationGranularity = pagesize; lpSystemInfo->wProcessorLevel_PAL_Undefined = 0; lpSystemInfo->wProcessorRevision_PAL_Undefined = 0; LOGEXIT("GetSystemInfo returns VOID\n"); PERF_EXIT(GetSystemInfo); } /*++ Function: GlobalMemoryStatusEx GlobalMemoryStatusEx Retrieves information about the system's current usage of both physical and virtual memory. Return Values This function returns a BOOL to indicate its success status. --*/ BOOL PALAPI GlobalMemoryStatusEx( IN OUT LPMEMORYSTATUSEX lpBuffer) { PERF_ENTRY(GlobalMemoryStatusEx); ENTRY("GlobalMemoryStatusEx (lpBuffer=%p)\n", lpBuffer); lpBuffer->dwMemoryLoad = 0; lpBuffer->ullTotalPhys = 0; lpBuffer->ullAvailPhys = 0; lpBuffer->ullTotalPageFile = 0; lpBuffer->ullAvailPageFile = 0; lpBuffer->ullTotalVirtual = 0; lpBuffer->ullAvailVirtual = 0; lpBuffer->ullAvailExtendedVirtual = 0; BOOL fRetVal = FALSE; // Get the physical memory size #if HAVE_SYSCONF && HAVE__SC_PHYS_PAGES int64_t physical_memory; // Get the Physical memory size physical_memory = sysconf( _SC_PHYS_PAGES ) * sysconf( _SC_PAGE_SIZE ); lpBuffer->ullTotalPhys = (DWORDLONG)physical_memory; fRetVal = TRUE; #elif HAVE_SYSCTL int mib[2]; int64_t physical_memory; size_t length; // Get the Physical memory size mib[0] = CTL_HW; mib[1] = HW_MEMSIZE; length = sizeof(INT64); int rc = sysctl(mib, 2, &physical_memory, &length, NULL, 0); if (rc != 0) { ASSERT("sysctl failed for HW_MEMSIZE (%d)\n", errno); } else { lpBuffer->ullTotalPhys = (DWORDLONG)physical_memory; fRetVal = TRUE; } #elif // HAVE_SYSINFO // TODO: implement getting memory details via sysinfo. On Linux, it provides swap file details that // we can use to fill in the xxxPageFile members. #endif // HAVE_SYSCONF // Get the physical memory in use - from it, we can get the physical memory available. // We do this only when we have the total physical memory available. if (lpBuffer->ullTotalPhys > 0) { #ifndef __APPLE__ lpBuffer->ullAvailPhys = sysconf(SYSCONF_PAGES) * sysconf(_SC_PAGE_SIZE); INT64 used_memory = lpBuffer->ullTotalPhys - lpBuffer->ullAvailPhys; lpBuffer->dwMemoryLoad = (DWORD)((used_memory * 100) / lpBuffer->ullTotalPhys); #else vm_size_t page_size; mach_port_t mach_port; mach_msg_type_number_t count; vm_statistics_data_t vm_stats; mach_port = mach_host_self(); count = sizeof(vm_stats) / sizeof(natural_t); if (KERN_SUCCESS == host_page_size(mach_port, &page_size)) { if (KERN_SUCCESS == host_statistics(mach_port, HOST_VM_INFO, (host_info_t)&vm_stats, &count)) { lpBuffer->ullAvailPhys = (int64_t)vm_stats.free_count * (int64_t)page_size; INT64 used_memory = ((INT64)vm_stats.active_count + (INT64)vm_stats.inactive_count + (INT64)vm_stats.wire_count) * (INT64)page_size; lpBuffer->dwMemoryLoad = (DWORD)((used_memory * 100) / lpBuffer->ullTotalPhys); } } mach_port_deallocate(mach_task_self(), mach_port); #endif // __APPLE__ } // There is no API to get the total virtual address space size on // Unix, so we use a constant value representing 128TB, which is // the approximate size of total user virtual address space on // the currently supported Unix systems. static const UINT64 _128TB = (1ull << 47); lpBuffer->ullTotalVirtual = _128TB; lpBuffer->ullAvailVirtual = lpBuffer->ullAvailPhys; LOGEXIT("GlobalMemoryStatusEx returns %d\n", fRetVal); PERF_EXIT(GlobalMemoryStatusEx); return fRetVal; } PALIMPORT DWORD PALAPI GetCurrentProcessorNumber() { #if HAVE_SCHED_GETCPU return sched_getcpu(); #else //HAVE_SCHED_GETCPU return -1; #endif //HAVE_SCHED_GETCPU } BOOL PALAPI PAL_HasGetCurrentProcessorNumber() { return HAVE_SCHED_GETCPU; } DWORD PALAPI PAL_GetLogicalCpuCountFromOS() { DWORD numLogicalCores = 0; #if HAVE_SYSCONF numLogicalCores = sysconf(_SC_NPROCESSORS_ONLN); #endif return numLogicalCores; } size_t PALAPI PAL_GetLogicalProcessorCacheSizeFromOS() { size_t cacheSize = 0; #ifdef _SC_LEVEL1_DCACHE_SIZE cacheSize = max(cacheSize, sysconf(_SC_LEVEL1_DCACHE_SIZE)); #endif #ifdef _SC_LEVEL2_CACHE_SIZE cacheSize = max(cacheSize, sysconf(_SC_LEVEL2_CACHE_SIZE)); #endif #ifdef _SC_LEVEL3_CACHE_SIZE cacheSize = max(cacheSize, sysconf(_SC_LEVEL3_CACHE_SIZE)); #endif #ifdef _SC_LEVEL4_CACHE_SIZE cacheSize = max(cacheSize, sysconf(_SC_LEVEL4_CACHE_SIZE)); #endif return cacheSize; }