/* Calculate the size of physical memory. Copyright (C) 2000-2001, 2003, 2005-2006, 2009-2024 Free Software Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ /* Written by Paul Eggert. */ #include #include "physmem.h" #include #if HAVE_SYS_PSTAT_H # include #endif #if HAVE_SYS_SYSMP_H # include #endif #if HAVE_SYS_SYSINFO_H # include #endif #if HAVE_MACHINE_HAL_SYSINFO_H # include #endif #if HAVE_SYS_TABLE_H # include #endif #include #if HAVE_SYS_PARAM_H # include #endif #if HAVE_SYS_SYSCTL_H && !(defined __GLIBC__ && defined __linux__) # include #endif #if HAVE_SYS_SYSTEMCFG_H # include #endif #ifdef _WIN32 # define WIN32_LEAN_AND_MEAN # include /* Don't assume that UNICODE is not defined. */ # undef GetModuleHandle # define GetModuleHandle GetModuleHandleA /* Avoid warnings from gcc -Wcast-function-type. */ # define GetProcAddress \ (void *) GetProcAddress /* MEMORYSTATUSEX is missing from older windows headers, so define a local replacement. */ typedef struct { DWORD dwLength; DWORD dwMemoryLoad; DWORDLONG ullTotalPhys; DWORDLONG ullAvailPhys; DWORDLONG ullTotalPageFile; DWORDLONG ullAvailPageFile; DWORDLONG ullTotalVirtual; DWORDLONG ullAvailVirtual; DWORDLONG ullAvailExtendedVirtual; } lMEMORYSTATUSEX; typedef BOOL (WINAPI *PFN_MS_EX) (lMEMORYSTATUSEX*); #endif #define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) /* Return the total amount of physical memory. */ double physmem_total (void) { #if defined _SC_PHYS_PAGES && defined _SC_PAGESIZE { /* This works on linux-gnu, kfreebsd-gnu, solaris2, and cygwin. */ double pages = sysconf (_SC_PHYS_PAGES); double pagesize = sysconf (_SC_PAGESIZE); if (0 <= pages && 0 <= pagesize) return pages * pagesize; } #endif #if HAVE_SYSINFO && HAVE_STRUCT_SYSINFO_MEM_UNIT { /* This works on linux. */ struct sysinfo si; if (sysinfo(&si) == 0) return (double) si.totalram * si.mem_unit; } #endif #if HAVE_PSTAT_GETSTATIC { /* This works on hpux11. */ struct pst_static pss; if (0 <= pstat_getstatic (&pss, sizeof pss, 1, 0)) { double pages = pss.physical_memory; double pagesize = pss.page_size; if (0 <= pages && 0 <= pagesize) return pages * pagesize; } } #endif #if HAVE_SYSMP && defined MP_SAGET && defined MPSA_RMINFO && defined _SC_PAGESIZE { /* This works on irix6. */ struct rminfo realmem; if (sysmp (MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0) { double pagesize = sysconf (_SC_PAGESIZE); double pages = realmem.physmem; if (0 <= pages && 0 <= pagesize) return pages * pagesize; } } #endif #if HAVE_GETSYSINFO && defined GSI_PHYSMEM { /* This works on Tru64 UNIX V4/5. */ int physmem; if (getsysinfo (GSI_PHYSMEM, (caddr_t) &physmem, sizeof (physmem), NULL, NULL, NULL) == 1) { double kbytes = physmem; if (0 <= kbytes) return kbytes * 1024.0; } } #endif #if HAVE_SYSCTL && !(defined __GLIBC__ && defined __linux__) && defined HW_PHYSMEM { /* This works on *bsd, kfreebsd-gnu, and darwin. */ unsigned int physmem; size_t len = sizeof physmem; static int mib[2] = { CTL_HW, HW_PHYSMEM }; if (sysctl (mib, ARRAY_SIZE (mib), &physmem, &len, NULL, 0) == 0 && len == sizeof (physmem)) return (double) physmem; } #endif #if HAVE__SYSTEM_CONFIGURATION /* This works on AIX. */ return _system_configuration.physmem; #endif #if defined _WIN32 { /* this works on windows */ PFN_MS_EX pfnex; HMODULE h = GetModuleHandle ("kernel32.dll"); if (!h) return 0.0; /* Use GlobalMemoryStatusEx if available. */ if ((pfnex = (PFN_MS_EX) GetProcAddress (h, "GlobalMemoryStatusEx"))) { lMEMORYSTATUSEX lms_ex; lms_ex.dwLength = sizeof lms_ex; if (!pfnex (&lms_ex)) return 0.0; return (double) lms_ex.ullTotalPhys; } /* Fall back to GlobalMemoryStatus which is always available. but returns wrong results for physical memory > 4GB. */ else { MEMORYSTATUS ms; GlobalMemoryStatus (&ms); return (double) ms.dwTotalPhys; } } #endif /* Guess 64 MB. It's probably an older host, so guess small. */ return 64 * 1024 * 1024; } /* Return the amount of physical memory available. */ double physmem_available (void) { #if defined _SC_AVPHYS_PAGES && defined _SC_PAGESIZE { /* This works on linux-gnu, kfreebsd-gnu, solaris2, and cygwin. */ double pages = sysconf (_SC_AVPHYS_PAGES); double pagesize = sysconf (_SC_PAGESIZE); if (0 <= pages && 0 <= pagesize) return pages * pagesize; } #endif #if HAVE_SYSINFO && HAVE_STRUCT_SYSINFO_MEM_UNIT { /* This works on linux. */ struct sysinfo si; if (sysinfo(&si) == 0) return ((double) si.freeram + si.bufferram) * si.mem_unit; } #endif #if HAVE_PSTAT_GETSTATIC && HAVE_PSTAT_GETDYNAMIC { /* This works on hpux11. */ struct pst_static pss; struct pst_dynamic psd; if (0 <= pstat_getstatic (&pss, sizeof pss, 1, 0) && 0 <= pstat_getdynamic (&psd, sizeof psd, 1, 0)) { double pages = psd.psd_free; double pagesize = pss.page_size; if (0 <= pages && 0 <= pagesize) return pages * pagesize; } } #endif #if HAVE_SYSMP && defined MP_SAGET && defined MPSA_RMINFO && defined _SC_PAGESIZE { /* This works on irix6. */ struct rminfo realmem; if (sysmp (MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0) { double pagesize = sysconf (_SC_PAGESIZE); double pages = realmem.availrmem; if (0 <= pages && 0 <= pagesize) return pages * pagesize; } } #endif #if HAVE_TABLE && defined TBL_VMSTATS { /* This works on Tru64 UNIX V4/5. */ struct tbl_vmstats vmstats; if (table (TBL_VMSTATS, 0, &vmstats, 1, sizeof (vmstats)) == 1) { double pages = vmstats.free_count; double pagesize = vmstats.pagesize; if (0 <= pages && 0 <= pagesize) return pages * pagesize; } } #endif #if HAVE_SYSCTL && !(defined __GLIBC__ && defined __linux__) && defined HW_USERMEM { /* This works on *bsd, kfreebsd-gnu, and darwin. */ unsigned int usermem; size_t len = sizeof usermem; static int mib[2] = { CTL_HW, HW_USERMEM }; if (sysctl (mib, ARRAY_SIZE (mib), &usermem, &len, NULL, 0) == 0 && len == sizeof (usermem)) return (double) usermem; } #endif #if defined _WIN32 { /* this works on windows */ PFN_MS_EX pfnex; HMODULE h = GetModuleHandle ("kernel32.dll"); if (!h) return 0.0; /* Use GlobalMemoryStatusEx if available. */ if ((pfnex = (PFN_MS_EX) GetProcAddress (h, "GlobalMemoryStatusEx"))) { lMEMORYSTATUSEX lms_ex; lms_ex.dwLength = sizeof lms_ex; if (!pfnex (&lms_ex)) return 0.0; return (double) lms_ex.ullAvailPhys; } /* Fall back to GlobalMemoryStatus which is always available. but returns wrong results for physical memory > 4GB */ else { MEMORYSTATUS ms; GlobalMemoryStatus (&ms); return (double) ms.dwAvailPhys; } } #endif /* Guess 25% of physical memory. */ return physmem_total () / 4; } #if DEBUG # include # include int main (void) { printf ("%12.f %12.f\n", physmem_total (), physmem_available ()); exit (0); } #endif /* DEBUG */ /* Local Variables: compile-command: "gcc -DDEBUG -g -O -Wall -W physmem.c" End: */