198038Sache/* Calculate the size of physical memory. 2131447Stjr Copyright (C) 2000, 2001, 2003 Free Software Foundation, Inc. 398038Sache 498038Sache This program is free software; you can redistribute it and/or modify 598038Sache it under the terms of the GNU General Public License as published by 698038Sache the Free Software Foundation; either version 2, or (at your option) 798038Sache any later version. 898038Sache 998038Sache This program is distributed in the hope that it will be useful, 1098038Sache but WITHOUT ANY WARRANTY; without even the implied warranty of 1198038Sache MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1298038Sache GNU General Public License for more details. 1398038Sache 1498038Sache You should have received a copy of the GNU General Public License 1598038Sache along with this program; if not, write to the Free Software Foundation, 1698038Sache Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 1798038Sache 1898038Sache/* Written by Paul Eggert. */ 1998038Sache 2098038Sache#if HAVE_CONFIG_H 2198038Sache# include <config.h> 2298038Sache#endif 2398038Sache 2498038Sache#include "physmem.h" 2598038Sache 2698038Sache#if HAVE_UNISTD_H 2798038Sache# include <unistd.h> 2898038Sache#endif 2998038Sache 3098038Sache#if HAVE_SYS_PSTAT_H 3198038Sache# include <sys/pstat.h> 3298038Sache#endif 3398038Sache 34131447Stjr#if HAVE_SYS_SYSMP_H 35131447Stjr# include <sys/sysmp.h> 36131447Stjr#endif 37131447Stjr 38131447Stjr#if HAVE_SYS_SYSINFO_H && HAVE_MACHINE_HAL_SYSINFO_H 39131447Stjr# include <sys/sysinfo.h> 40131447Stjr# include <machine/hal_sysinfo.h> 41131447Stjr#endif 42131447Stjr 43131447Stjr#if HAVE_SYS_TABLE_H 44131447Stjr# include <sys/table.h> 45131447Stjr#endif 46131447Stjr 47131447Stjr#include <sys/types.h> 48131447Stjr 49131447Stjr#if HAVE_SYS_PARAM_H 50131447Stjr# include <sys/param.h> 51131447Stjr#endif 52131447Stjr 53131447Stjr#if HAVE_SYS_SYSCTL_H 54131447Stjr# include <sys/sysctl.h> 55131447Stjr#endif 56131447Stjr 57131447Stjr#if HAVE_SYS_SYSTEMCFG_H 58131447Stjr# include <sys/systemcfg.h> 59131447Stjr#endif 60131447Stjr 61131447Stjr#ifdef _WIN32 62131447Stjr# define WIN32_LEAN_AND_MEAN 63131447Stjr# include <windows.h> 64131447Stjr/* MEMORYSTATUSEX is missing from older windows headers, so define 65131447Stjr a local replacement. */ 66131447Stjrtypedef struct 67131447Stjr{ 68131447Stjr DWORD dwLength; 69131447Stjr DWORD dwMemoryLoad; 70131447Stjr DWORDLONG ullTotalPhys; 71131447Stjr DWORDLONG ullAvailPhys; 72131447Stjr DWORDLONG ullTotalPageFile; 73131447Stjr DWORDLONG ullAvailPageFile; 74131447Stjr DWORDLONG ullTotalVirtual; 75131447Stjr DWORDLONG ullAvailVirtual; 76131447Stjr DWORDLONG ullAvailExtendedVirtual; 77131447Stjr} lMEMORYSTATUSEX; 78131447Stjrtypedef WINBOOL (WINAPI *PFN_MS_EX) (lMEMORYSTATUSEX*); 79131447Stjr#endif 80131447Stjr 81131447Stjr#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) 82131447Stjr 8398038Sache/* Return the total amount of physical memory. */ 8498038Sachedouble 8598038Sachephysmem_total (void) 8698038Sache{ 8798038Sache#if defined _SC_PHYS_PAGES && defined _SC_PAGESIZE 88131447Stjr { /* This works on linux-gnu, solaris2 and cygwin. */ 8998038Sache double pages = sysconf (_SC_PHYS_PAGES); 9098038Sache double pagesize = sysconf (_SC_PAGESIZE); 9198038Sache if (0 <= pages && 0 <= pagesize) 9298038Sache return pages * pagesize; 9398038Sache } 9498038Sache#endif 9598038Sache 9698038Sache#if HAVE_PSTAT_GETSTATIC 97131447Stjr { /* This works on hpux11. */ 9898038Sache struct pst_static pss; 9998038Sache if (0 <= pstat_getstatic (&pss, sizeof pss, 1, 0)) 10098038Sache { 10198038Sache double pages = pss.physical_memory; 10298038Sache double pagesize = pss.page_size; 10398038Sache if (0 <= pages && 0 <= pagesize) 10498038Sache return pages * pagesize; 10598038Sache } 10698038Sache } 10798038Sache#endif 10898038Sache 109131447Stjr#if HAVE_SYSMP && defined MP_SAGET && defined MPSA_RMINFO && defined _SC_PAGESIZE 110131447Stjr { /* This works on irix6. */ 111131447Stjr struct rminfo realmem; 112131447Stjr if (sysmp (MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0) 113131447Stjr { 114131447Stjr double pagesize = sysconf (_SC_PAGESIZE); 115131447Stjr double pages = realmem.physmem; 116131447Stjr if (0 <= pages && 0 <= pagesize) 117131447Stjr return pages * pagesize; 118131447Stjr } 119131447Stjr } 120131447Stjr#endif 121131447Stjr 122131447Stjr#if HAVE_GETSYSINFO && defined GSI_PHYSMEM 123131447Stjr { /* This works on Tru64 UNIX V4/5. */ 124131447Stjr int physmem; 125131447Stjr 126131447Stjr if (getsysinfo (GSI_PHYSMEM, (caddr_t) &physmem, sizeof (physmem), 127131447Stjr NULL, NULL, NULL) == 1) 128131447Stjr { 129131447Stjr double kbytes = physmem; 130131447Stjr 131131447Stjr if (0 <= kbytes) 132131447Stjr return kbytes * 1024.0; 133131447Stjr } 134131447Stjr } 135131447Stjr#endif 136131447Stjr 137131447Stjr#if HAVE_SYSCTL && defined HW_PHYSMEM 138131447Stjr { /* This works on *bsd and darwin. */ 139131447Stjr unsigned int physmem; 140131447Stjr size_t len = sizeof physmem; 141131447Stjr static int mib[2] = { CTL_HW, HW_PHYSMEM }; 142131447Stjr 143131447Stjr if (sysctl (mib, ARRAY_SIZE (mib), &physmem, &len, NULL, 0) == 0 144131447Stjr && len == sizeof (physmem)) 145131447Stjr return (double) physmem; 146131447Stjr } 147131447Stjr#endif 148131447Stjr 149131447Stjr#if HAVE__SYSTEM_CONFIGURATION 150131447Stjr /* This works on AIX. */ 151131447Stjr return _system_configuration.physmem; 152131447Stjr#endif 153131447Stjr 154131447Stjr#if defined _WIN32 155131447Stjr { /* this works on windows */ 156131447Stjr PFN_MS_EX pfnex; 157131447Stjr HMODULE h = GetModuleHandle ("kernel32.dll"); 158131447Stjr 159131447Stjr if (!h) 160131447Stjr return 0.0; 161131447Stjr 162131447Stjr /* Use GlobalMemoryStatusEx if available. */ 163131447Stjr if ((pfnex = (PFN_MS_EX) GetProcAddress (h, "GlobalMemoryStatusEx"))) 164131447Stjr { 165131447Stjr lMEMORYSTATUSEX lms_ex; 166131447Stjr lms_ex.dwLength = sizeof lms_ex; 167131447Stjr if (!pfnex (&lms_ex)) 168131447Stjr return 0.0; 169131447Stjr return (double) lms_ex.ullTotalPhys; 170131447Stjr } 171131447Stjr 172131447Stjr /* Fall back to GlobalMemoryStatus which is always available. 173131447Stjr but returns wrong results for physical memory > 4GB. */ 174131447Stjr else 175131447Stjr { 176131447Stjr MEMORYSTATUS ms; 177131447Stjr GlobalMemoryStatus (&ms); 178131447Stjr return (double) ms.dwTotalPhys; 179131447Stjr } 180131447Stjr } 181131447Stjr#endif 182131447Stjr 18398038Sache /* Guess 64 MB. It's probably an older host, so guess small. */ 18498038Sache return 64 * 1024 * 1024; 18598038Sache} 18698038Sache 18798038Sache/* Return the amount of physical memory available. */ 18898038Sachedouble 18998038Sachephysmem_available (void) 19098038Sache{ 19198038Sache#if defined _SC_AVPHYS_PAGES && defined _SC_PAGESIZE 192131447Stjr { /* This works on linux-gnu, solaris2 and cygwin. */ 19398038Sache double pages = sysconf (_SC_AVPHYS_PAGES); 19498038Sache double pagesize = sysconf (_SC_PAGESIZE); 19598038Sache if (0 <= pages && 0 <= pagesize) 19698038Sache return pages * pagesize; 19798038Sache } 19898038Sache#endif 19998038Sache 20098038Sache#if HAVE_PSTAT_GETSTATIC && HAVE_PSTAT_GETDYNAMIC 201131447Stjr { /* This works on hpux11. */ 20298038Sache struct pst_static pss; 20398038Sache struct pst_dynamic psd; 20498038Sache if (0 <= pstat_getstatic (&pss, sizeof pss, 1, 0) 20598038Sache && 0 <= pstat_getdynamic (&psd, sizeof psd, 1, 0)) 20698038Sache { 20798038Sache double pages = psd.psd_free; 20898038Sache double pagesize = pss.page_size; 20998038Sache if (0 <= pages && 0 <= pagesize) 21098038Sache return pages * pagesize; 21198038Sache } 21298038Sache } 21398038Sache#endif 21498038Sache 215131447Stjr#if HAVE_SYSMP && defined MP_SAGET && defined MPSA_RMINFO && defined _SC_PAGESIZE 216131447Stjr { /* This works on irix6. */ 217131447Stjr struct rminfo realmem; 218131447Stjr if (sysmp (MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0) 219131447Stjr { 220131447Stjr double pagesize = sysconf (_SC_PAGESIZE); 221131447Stjr double pages = realmem.availrmem; 222131447Stjr if (0 <= pages && 0 <= pagesize) 223131447Stjr return pages * pagesize; 224131447Stjr } 225131447Stjr } 226131447Stjr#endif 227131447Stjr 228131447Stjr#if HAVE_TABLE && defined TBL_VMSTATS 229131447Stjr { /* This works on Tru64 UNIX V4/5. */ 230131447Stjr struct tbl_vmstats vmstats; 231131447Stjr 232131447Stjr if (table (TBL_VMSTATS, 0, &vmstats, 1, sizeof (vmstats)) == 1) 233131447Stjr { 234131447Stjr double pages = vmstats.free_count; 235131447Stjr double pagesize = vmstats.pagesize; 236131447Stjr 237131447Stjr if (0 <= pages && 0 <= pagesize) 238131447Stjr return pages * pagesize; 239131447Stjr } 240131447Stjr } 241131447Stjr#endif 242131447Stjr 243131447Stjr#if HAVE_SYSCTL && defined HW_USERMEM 244131447Stjr { /* This works on *bsd and darwin. */ 245131447Stjr unsigned int usermem; 246131447Stjr size_t len = sizeof usermem; 247131447Stjr static int mib[2] = { CTL_HW, HW_USERMEM }; 248131447Stjr 249131447Stjr if (sysctl (mib, ARRAY_SIZE (mib), &usermem, &len, NULL, 0) == 0 250131447Stjr && len == sizeof (usermem)) 251131447Stjr return (double) usermem; 252131447Stjr } 253131447Stjr#endif 254131447Stjr 255131447Stjr#if defined _WIN32 256131447Stjr { /* this works on windows */ 257131447Stjr PFN_MS_EX pfnex; 258131447Stjr HMODULE h = GetModuleHandle ("kernel32.dll"); 259131447Stjr 260131447Stjr if (!h) 261131447Stjr return 0.0; 262131447Stjr 263131447Stjr /* Use GlobalMemoryStatusEx if available. */ 264131447Stjr if ((pfnex = (PFN_MS_EX) GetProcAddress (h, "GlobalMemoryStatusEx"))) 265131447Stjr { 266131447Stjr lMEMORYSTATUSEX lms_ex; 267131447Stjr lms_ex.dwLength = sizeof lms_ex; 268131447Stjr if (!pfnex (&lms_ex)) 269131447Stjr return 0.0; 270131447Stjr return (double) lms_ex.ullAvailPhys; 271131447Stjr } 272131447Stjr 273131447Stjr /* Fall back to GlobalMemoryStatus which is always available. 274131447Stjr but returns wrong results for physical memory > 4GB */ 275131447Stjr else 276131447Stjr { 277131447Stjr MEMORYSTATUS ms; 278131447Stjr GlobalMemoryStatus (&ms); 279131447Stjr return (double) ms.dwAvailPhys; 280131447Stjr } 281131447Stjr } 282131447Stjr#endif 283131447Stjr 28498038Sache /* Guess 25% of physical memory. */ 28598038Sache return physmem_total () / 4; 28698038Sache} 287131447Stjr 288131447Stjr 289131447Stjr#if DEBUG 290131447Stjr 291131447Stjr# include <stdio.h> 292131447Stjr# include <stdlib.h> 293131447Stjr 294131447Stjrint 295131447Stjrmain (void) 296131447Stjr{ 297131447Stjr printf ("%12.f %12.f\n", physmem_total (), physmem_available ()); 298131447Stjr exit (0); 299131447Stjr} 300131447Stjr 301131447Stjr#endif /* DEBUG */ 302131447Stjr 303131447Stjr/* 304131447StjrLocal Variables: 305131447Stjrcompile-command: "gcc -DDEBUG -DHAVE_CONFIG_H -I.. -g -O -Wall -W physmem.c" 306131447StjrEnd: 307131447Stjr*/ 308