From f6095100fcb703d61ffc418fb66b2ec20c79f0a6 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Fri, 7 Apr 2017 15:35:34 +0200 Subject: [PATCH] Add reporting swap file size to GlobalMemoryStatusEx on Unix (dotnet/coreclr#10700) The swap file size reporting is added using the Linux, OSX and FreeBSD means. Also a new PAL test was added to exercise the function. Commit migrated from https://github.com/dotnet/coreclr/commit/a2ed1fa2420f5aa385007e205e30616dd75fc881 --- src/coreclr/src/pal/src/config.h.in | 3 + src/coreclr/src/pal/src/configure.cmake | 25 ++++++++ src/coreclr/src/pal/src/misc/sysinfo.cpp | 75 ++++++++++++++++++++-- .../tests/palsuite/miscellaneous/CMakeLists.txt | 1 + .../GlobalMemoryStatusEx/CMakeLists.txt | 4 ++ .../GlobalMemoryStatusEx/test1/CMakeLists.txt | 17 +++++ .../GlobalMemoryStatusEx/test1/test.cpp | 55 ++++++++++++++++ .../GlobalMemoryStatusEx/test1/testinfo.dat | 14 ++++ src/coreclr/src/pal/tests/palsuite/paltestlist.txt | 1 + src/coreclr/src/pal/tests/palsuite/palverify.dat | 1 + 10 files changed, 190 insertions(+), 6 deletions(-) create mode 100644 src/coreclr/src/pal/tests/palsuite/miscellaneous/GlobalMemoryStatusEx/CMakeLists.txt create mode 100644 src/coreclr/src/pal/tests/palsuite/miscellaneous/GlobalMemoryStatusEx/test1/CMakeLists.txt create mode 100644 src/coreclr/src/pal/tests/palsuite/miscellaneous/GlobalMemoryStatusEx/test1/test.cpp create mode 100644 src/coreclr/src/pal/tests/palsuite/miscellaneous/GlobalMemoryStatusEx/test1/testinfo.dat diff --git a/src/coreclr/src/pal/src/config.h.in b/src/coreclr/src/pal/src/config.h.in index 77d7bfa..ab5fa03 100644 --- a/src/coreclr/src/pal/src/config.h.in +++ b/src/coreclr/src/pal/src/config.h.in @@ -40,6 +40,7 @@ #cmakedefine01 HAVE_UTIMES #cmakedefine01 HAVE_SYSCTL #cmakedefine01 HAVE_SYSCONF +#cmakedefine01 HAVE_SYSINFO #cmakedefine01 HAVE_LOCALTIME_R #cmakedefine01 HAVE_GMTIME_R #cmakedefine01 HAVE_TIMEGM @@ -57,6 +58,8 @@ #cmakedefine01 HAVE_TTRACE #cmakedefine HAVE_UNW_GET_SAVE_LOC #cmakedefine HAVE_UNW_GET_ACCESSORS +#cmakedefine01 HAVE_XSWDEV +#cmakedefine01 HAVE_XSW_USAGE #cmakedefine01 HAVE_STAT_TIMESPEC #cmakedefine01 HAVE_STAT_NSEC diff --git a/src/coreclr/src/pal/src/configure.cmake b/src/coreclr/src/pal/src/configure.cmake index 4ca1fe9..4d78f54 100644 --- a/src/coreclr/src/pal/src/configure.cmake +++ b/src/coreclr/src/pal/src/configure.cmake @@ -78,6 +78,7 @@ check_function_exists(fsync HAVE_FSYNC) check_function_exists(futimes HAVE_FUTIMES) check_function_exists(utimes HAVE_UTIMES) check_function_exists(sysctl HAVE_SYSCTL) +check_function_exists(sysinfo HAVE_SYSINFO) check_function_exists(sysconf HAVE_SYSCONF) check_function_exists(localtime_r HAVE_LOCALTIME_R) check_function_exists(gmtime_r HAVE_GMTIME_R) @@ -122,6 +123,7 @@ check_struct_has_member ("struct stat" st_atimensec "sys/types.h;sys/stat.h" HAV check_struct_has_member ("struct tm" tm_gmtoff time.h HAVE_TM_GMTOFF) check_struct_has_member ("ucontext_t" uc_mcontext.gregs[0] ucontext.h HAVE_GREGSET_T) check_struct_has_member ("ucontext_t" uc_mcontext.__gregs[0] ucontext.h HAVE___GREGSET_T) +check_struct_has_member ("struct sysinfo" mem_unit "sys/sysinfo.h" HAVE_SYSINFO_WITH_MEM_UNIT) set(CMAKE_EXTRA_INCLUDE_FILES machine/reg.h) check_type_size("struct reg" BSD_REGS_T) @@ -982,6 +984,29 @@ int main(int argc, char **argv) return 0; }" UNWIND_CONTEXT_IS_UCONTEXT_T) +check_cxx_source_compiles(" +#include +#include +#include + +int main(int argc, char **argv) +{ + struct xswdev xsw; + + return 0; +}" HAVE_XSWDEV) + +check_cxx_source_compiles(" +#include +#include + +int main(int argc, char **argv) +{ + struct xsw_usage xsu; + + return 0; +}" HAVE_XSW_USAGE) + set(CMAKE_REQUIRED_LIBRARIES pthread) check_cxx_source_compiles(" #include diff --git a/src/coreclr/src/pal/src/misc/sysinfo.cpp b/src/coreclr/src/pal/src/misc/sysinfo.cpp index 3ccb35a..fff0518 100644 --- a/src/coreclr/src/pal/src/misc/sysinfo.cpp +++ b/src/coreclr/src/pal/src/misc/sysinfo.cpp @@ -32,12 +32,20 @@ Revision History: #error Either sysctl or sysconf is required for GetSystemInfo. #endif +#if HAVE_SYSINFO +#include +#endif + #include #if HAVE_SYS_VMPARAM_H #include #endif // HAVE_SYS_VMPARAM_H +#if HAVE_XSWDEV +#include +#endif // HAVE_XSWDEV + #if HAVE_MACH_VM_TYPES_H #include #endif // HAVE_MACH_VM_TYPES_H @@ -216,6 +224,8 @@ GlobalMemoryStatusEx( lpBuffer->ullAvailExtendedVirtual = 0; BOOL fRetVal = FALSE; + int mib[3]; + int rc; // Get the physical memory size #if HAVE_SYSCONF && HAVE__SC_PHYS_PAGES @@ -226,7 +236,6 @@ GlobalMemoryStatusEx( lpBuffer->ullTotalPhys = (DWORDLONG)physical_memory; fRetVal = TRUE; #elif HAVE_SYSCTL - int mib[2]; int64_t physical_memory; size_t length; @@ -234,7 +243,7 @@ GlobalMemoryStatusEx( mib[0] = CTL_HW; mib[1] = HW_MEMSIZE; length = sizeof(INT64); - int rc = sysctl(mib, 2, &physical_memory, &length, NULL, 0); + rc = sysctl(mib, 2, &physical_memory, &length, NULL, 0); if (rc != 0) { ASSERT("sysctl failed for HW_MEMSIZE (%d)\n", errno); @@ -244,11 +253,65 @@ GlobalMemoryStatusEx( 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 +#endif // HAVE_SYSCTL + + // Get swap file size, consider the ability to get the values optional + // (don't return FALSE from the GlobalMemoryStatusEx) +#if HAVE_XSW_USAGE + // This is available on OSX + struct xsw_usage xsu; + mib[0] = CTL_VM; + mib[1] = VM_SWAPUSAGE; + size_t length = sizeof(xsu); + rc = sysctl(mib, 2, &xsu, &length, NULL, 0); + if (rc == 0) + { + lpBuffer->ullTotalPageFile = xsu.xsu_total; + lpBuffer->ullAvailPageFile = xsu.xsu_avail; + } +#elif HAVE_XSWDEV + // E.g. FreeBSD + struct xswdev xsw; + + size_t length = 2; + rc = sysctlnametomib("vm.swap_info", mib, &length); + if (rc == 0) + { + int pagesize = getpagesize(); + // Aggregate the information for all swap files on the system + for (mib[2] = 0; ; mib[2]++) + { + length = sizeof(xsw); + rc = sysctl(mib, 3, &xsw, &length, NULL, 0); + if ((rc < 0) || (xsw.xsw_version != XSWDEV_VERSION)) + { + // All the swap files were processed or coreclr was built against + // a version of headers not compatible with the current XSWDEV_VERSION. + break; + } + + DWORDLONG avail = xsw.xsw_nblks - xsw.xsw_used; + lpBuffer->ullTotalPageFile += (DWORDLONG)xsw.xsw_nblks * pagesize; + lpBuffer->ullAvailPageFile += (DWORDLONG)avail * pagesize; + } + } +#elif HAVE_SYSINFO + // Linux + struct sysinfo info; + rc = sysinfo(&info); + if (rc == 0) + { + lpBuffer->ullTotalPageFile = info.totalswap; + lpBuffer->ullAvailPageFile = info.freeswap; +#if HAVE_SYSINFO_WITH_MEM_UNIT + // A newer version of the sysinfo structure represents all the sizes + // in mem_unit instead of bytes + lpBuffer->ullTotalPageFile *= info.mem_unit; + lpBuffer->ullAvailPageFile *= info.mem_unit; +#endif // HAVE_SYSINFO_WITH_MEM_UNIT + } +#endif // HAVE_SYSINFO // 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. diff --git a/src/coreclr/src/pal/tests/palsuite/miscellaneous/CMakeLists.txt b/src/coreclr/src/pal/tests/palsuite/miscellaneous/CMakeLists.txt index 0b5fd37..9352ede 100644 --- a/src/coreclr/src/pal/tests/palsuite/miscellaneous/CMakeLists.txt +++ b/src/coreclr/src/pal/tests/palsuite/miscellaneous/CMakeLists.txt @@ -15,6 +15,7 @@ add_subdirectory(GetEnvironmentVariableA) add_subdirectory(GetEnvironmentVariableW) add_subdirectory(GetLastError) add_subdirectory(GetSystemInfo) +add_subdirectory(GlobalMemoryStatusEx) add_subdirectory(GetTickCount) add_subdirectory(InterlockedBit) add_subdirectory(InterlockedCompareExchange) diff --git a/src/coreclr/src/pal/tests/palsuite/miscellaneous/GlobalMemoryStatusEx/CMakeLists.txt b/src/coreclr/src/pal/tests/palsuite/miscellaneous/GlobalMemoryStatusEx/CMakeLists.txt new file mode 100644 index 0000000..f6aa0cb --- /dev/null +++ b/src/coreclr/src/pal/tests/palsuite/miscellaneous/GlobalMemoryStatusEx/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +add_subdirectory(test1) + diff --git a/src/coreclr/src/pal/tests/palsuite/miscellaneous/GlobalMemoryStatusEx/test1/CMakeLists.txt b/src/coreclr/src/pal/tests/palsuite/miscellaneous/GlobalMemoryStatusEx/test1/CMakeLists.txt new file mode 100644 index 0000000..6e74f22 --- /dev/null +++ b/src/coreclr/src/pal/tests/palsuite/miscellaneous/GlobalMemoryStatusEx/test1/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(SOURCES + test.cpp +) + +add_executable(paltest_globalmemorystatusex_test1 + ${SOURCES} +) + +add_dependencies(paltest_globalmemorystatusex_test1 coreclrpal) + +target_link_libraries(paltest_globalmemorystatusex_test1 + ${COMMON_TEST_LIBRARIES} +) diff --git a/src/coreclr/src/pal/tests/palsuite/miscellaneous/GlobalMemoryStatusEx/test1/test.cpp b/src/coreclr/src/pal/tests/palsuite/miscellaneous/GlobalMemoryStatusEx/test1/test.cpp new file mode 100644 index 0000000..460edad --- /dev/null +++ b/src/coreclr/src/pal/tests/palsuite/miscellaneous/GlobalMemoryStatusEx/test1/test.cpp @@ -0,0 +1,55 @@ +// 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. + +/*============================================================ +** +** Source : test.c +** +** Purpose: Test for GlobalMemoryStatusEx() function +** +** +**=========================================================*/ + +#include + +int __cdecl main(int argc, char *argv[]) { + + MEMORYSTATUSEX memoryStatus; + + /* + * Initialize the PAL and return FAILURE if this fails + */ + + if(0 != (PAL_Initialize(argc, argv))) + { + return FAIL; + } + + if (!GlobalMemoryStatusEx(&memoryStatus)) + { + Fail("ERROR: GlobalMemoryStatusEx failed."); + } + + printf("GlobalMemoryStatusEx:\n"); + printf(" ullTotalPhys: %llu\n", memoryStatus.ullTotalPhys); + printf(" ullAvailPhys: %llu\n", memoryStatus.ullAvailPhys); + printf(" ullTotalVirtual: %llu\n", memoryStatus.ullTotalVirtual); + printf(" ullAvailVirtual: %llu\n", memoryStatus.ullAvailVirtual); + printf(" ullTotalPageFile: %llu\n", memoryStatus.ullTotalPageFile); + printf(" ullAvailPageFile: %llu\n", memoryStatus.ullAvailPageFile); + printf(" ullAvailExtendedVirtual: %llu\n", memoryStatus.ullAvailExtendedVirtual); + printf(" dwMemoryLoad: %u\n", memoryStatus.dwMemoryLoad); + + if (memoryStatus.ullTotalPhys == 0 || + memoryStatus.ullAvailPhys == 0 || + memoryStatus.ullTotalVirtual == 0 || + memoryStatus.ullAvailVirtual == 0 + ) + { + Fail("ERROR: GlobalMemoryStatusEx succeeded, but returned zero physical of virtual memory sizes."); + } + + PAL_Terminate(); + return PASS; +} diff --git a/src/coreclr/src/pal/tests/palsuite/miscellaneous/GlobalMemoryStatusEx/test1/testinfo.dat b/src/coreclr/src/pal/tests/palsuite/miscellaneous/GlobalMemoryStatusEx/test1/testinfo.dat new file mode 100644 index 0000000..7ae3b51 --- /dev/null +++ b/src/coreclr/src/pal/tests/palsuite/miscellaneous/GlobalMemoryStatusEx/test1/testinfo.dat @@ -0,0 +1,14 @@ +# 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. + +Version = 1.0 +Section = Miscellaneous +Function = GlobalMemoryStatusEx +Name = Positive Test for GlobalMemoryStatusEx +TYPE = DEFAULT +EXE1 = test +Description += Ensures that invocation of GlobalMemoryStatusEx succeeds and += that it returns nonzero virtual and physical memory sizes + diff --git a/src/coreclr/src/pal/tests/palsuite/paltestlist.txt b/src/coreclr/src/pal/tests/palsuite/paltestlist.txt index 9f0be50..f0dfe3f 100644 --- a/src/coreclr/src/pal/tests/palsuite/paltestlist.txt +++ b/src/coreclr/src/pal/tests/palsuite/paltestlist.txt @@ -668,6 +668,7 @@ miscellaneous/GetEnvironmentVariableW/test5/paltest_getenvironmentvariablew_test miscellaneous/GetEnvironmentVariableW/test6/paltest_getenvironmentvariablew_test6 miscellaneous/GetLastError/test1/paltest_getlasterror_test1 miscellaneous/GetSystemInfo/test1/paltest_getsysteminfo_test1 +miscellaneous/GlobalMemoryStatusEx/test1/paltest_globalmemorystatusex_test1 miscellaneous/GetTickCount/test1/paltest_gettickcount_test1 miscellaneous/InterlockedCompareExchange/test1/paltest_interlockedcompareexchange_test1 miscellaneous/InterlockedCompareExchange/test2/paltest_interlockedcompareexchange_test2 diff --git a/src/coreclr/src/pal/tests/palsuite/palverify.dat b/src/coreclr/src/pal/tests/palsuite/palverify.dat index 1872313..d4cb311 100644 --- a/src/coreclr/src/pal/tests/palsuite/palverify.dat +++ b/src/coreclr/src/pal/tests/palsuite/palverify.dat @@ -753,6 +753,7 @@ miscellaneous/getenvironmentvariablew/test3,1 miscellaneous/getenvironmentvariablew/test4,1 miscellaneous/getlasterror/test1,1 miscellaneous/getsysteminfo/test1,1 +miscellaneous/getglobalmemorystatusex/test1,1 miscellaneous/gettickcount/test1,1 miscellaneous/getversionexa/test1,1 miscellaneous/getversionexw/test1,1 -- 2.7.4