1/* Calculate the size of physical memory. 2 Copyright 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc. 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 2, or (at your option) 7 any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program; if not, write to the Free Software Foundation, 16 Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 17 18/* Written by Paul Eggert. */ 19 20#if HAVE_CONFIG_H 21# include <config.h> 22#endif 23 24#if HAVE_UNISTD_H 25# include <unistd.h> 26#endif 27 28#if HAVE_SYS_PSTAT_H 29# include <sys/pstat.h> 30#endif 31 32#if HAVE_SYS_SYSMP_H 33# include <sys/sysmp.h> 34#endif 35 36#if HAVE_SYS_SYSINFO_H && HAVE_MACHINE_HAL_SYSINFO_H 37# include <sys/sysinfo.h> 38# include <machine/hal_sysinfo.h> 39#endif 40 41#if HAVE_SYS_TABLE_H 42# include <sys/table.h> 43#endif 44 45#include <sys/types.h> 46 47#if HAVE_SYS_PARAM_H 48# include <sys/param.h> 49#endif 50 51#if HAVE_SYS_SYSCTL_H 52# include <sys/sysctl.h> 53#endif 54 55#if HAVE_SYS_SYSTEMCFG_H 56# include <sys/systemcfg.h> 57#endif 58 59#ifdef _WIN32 60# define WIN32_LEAN_AND_MEAN 61# include <windows.h> 62/* MEMORYSTATUSEX is missing from older windows headers, so define 63 a local replacement. */ 64typedef struct 65{ 66 DWORD dwLength; 67 DWORD dwMemoryLoad; 68 DWORDLONG ullTotalPhys; 69 DWORDLONG ullAvailPhys; 70 DWORDLONG ullTotalPageFile; 71 DWORDLONG ullAvailPageFile; 72 DWORDLONG ullTotalVirtual; 73 DWORDLONG ullAvailVirtual; 74 DWORDLONG ullAvailExtendedVirtual; 75} lMEMORYSTATUSEX; 76typedef WINBOOL (WINAPI *PFN_MS_EX) (lMEMORYSTATUSEX*); 77#endif 78 79#include "libiberty.h" 80 81/* Return the total amount of physical memory. */ 82double 83physmem_total (void) 84{ 85#if defined _SC_PHYS_PAGES && defined _SC_PAGESIZE 86 { /* This works on linux-gnu, solaris2 and cygwin. */ 87 double pages = sysconf (_SC_PHYS_PAGES); 88 double pagesize = sysconf (_SC_PAGESIZE); 89 if (0 <= pages && 0 <= pagesize) 90 return pages * pagesize; 91 } 92#endif 93 94#if HAVE_PSTAT_GETSTATIC 95 { /* This works on hpux11. */ 96 struct pst_static pss; 97 if (0 <= pstat_getstatic (&pss, sizeof pss, 1, 0)) 98 { 99 double pages = pss.physical_memory; 100 double pagesize = pss.page_size; 101 if (0 <= pages && 0 <= pagesize) 102 return pages * pagesize; 103 } 104 } 105#endif 106 107#if HAVE_SYSMP && defined MP_SAGET && defined MPSA_RMINFO && defined _SC_PAGESIZE 108 { /* This works on irix6. */ 109 struct rminfo realmem; 110 if (sysmp (MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0) 111 { 112 double pagesize = sysconf (_SC_PAGESIZE); 113 double pages = realmem.physmem; 114 if (0 <= pages && 0 <= pagesize) 115 return pages * pagesize; 116 } 117 } 118#endif 119 120#if HAVE_GETSYSINFO && defined GSI_PHYSMEM 121 { /* This works on Tru64 UNIX V4/5. */ 122 int physmem; 123 124 if (getsysinfo (GSI_PHYSMEM, (caddr_t) &physmem, sizeof (physmem), 125 NULL, NULL, NULL) == 1) 126 { 127 double kbytes = physmem; 128 129 if (0 <= kbytes) 130 return kbytes * 1024.0; 131 } 132 } 133#endif 134 135#if HAVE_SYSCTL && defined HW_PHYSMEM 136 { /* This works on *bsd and darwin. */ 137 unsigned int physmem; 138 size_t len = sizeof physmem; 139 static int mib[2] = { CTL_HW, HW_PHYSMEM }; 140 141 if (sysctl (mib, ARRAY_SIZE (mib), &physmem, &len, NULL, 0) == 0 142 && len == sizeof (physmem)) 143 return (double) physmem; 144 } 145#endif 146 147#if HAVE__SYSTEM_CONFIGURATION 148 /* This works on AIX 4.3.3+. */ 149 return _system_configuration.physmem; 150#endif 151 152#if defined _WIN32 153 { /* this works on windows */ 154 PFN_MS_EX pfnex; 155 HMODULE h = GetModuleHandle ("kernel32.dll"); 156 157 if (!h) 158 return 0.0; 159 160 /* Use GlobalMemoryStatusEx if available. */ 161 if ((pfnex = (PFN_MS_EX) GetProcAddress (h, "GlobalMemoryStatusEx"))) 162 { 163 lMEMORYSTATUSEX lms_ex; 164 lms_ex.dwLength = sizeof lms_ex; 165 if (!pfnex (&lms_ex)) 166 return 0.0; 167 return (double) lms_ex.ullTotalPhys; 168 } 169 170 /* Fall back to GlobalMemoryStatus which is always available. 171 but returns wrong results for physical memory > 4GB. */ 172 else 173 { 174 MEMORYSTATUS ms; 175 GlobalMemoryStatus (&ms); 176 return (double) ms.dwTotalPhys; 177 } 178 } 179#endif 180 181 /* Return 0 if we can't determine the value. */ 182 return 0; 183} 184 185/* Return the amount of physical memory available. */ 186double 187physmem_available (void) 188{ 189#if defined _SC_AVPHYS_PAGES && defined _SC_PAGESIZE 190 { /* This works on linux-gnu, solaris2 and cygwin. */ 191 double pages = sysconf (_SC_AVPHYS_PAGES); 192 double pagesize = sysconf (_SC_PAGESIZE); 193 if (0 <= pages && 0 <= pagesize) 194 return pages * pagesize; 195 } 196#endif 197 198#if HAVE_PSTAT_GETSTATIC && HAVE_PSTAT_GETDYNAMIC 199 { /* This works on hpux11. */ 200 struct pst_static pss; 201 struct pst_dynamic psd; 202 if (0 <= pstat_getstatic (&pss, sizeof pss, 1, 0) 203 && 0 <= pstat_getdynamic (&psd, sizeof psd, 1, 0)) 204 { 205 double pages = psd.psd_free; 206 double pagesize = pss.page_size; 207 if (0 <= pages && 0 <= pagesize) 208 return pages * pagesize; 209 } 210 } 211#endif 212 213#if HAVE_SYSMP && defined MP_SAGET && defined MPSA_RMINFO && defined _SC_PAGESIZE 214 { /* This works on irix6. */ 215 struct rminfo realmem; 216 if (sysmp (MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0) 217 { 218 double pagesize = sysconf (_SC_PAGESIZE); 219 double pages = realmem.availrmem; 220 if (0 <= pages && 0 <= pagesize) 221 return pages * pagesize; 222 } 223 } 224#endif 225 226#if HAVE_TABLE && defined TBL_VMSTATS 227 { /* This works on Tru64 UNIX V4/5. */ 228 struct tbl_vmstats vmstats; 229 230 if (table (TBL_VMSTATS, 0, &vmstats, 1, sizeof (vmstats)) == 1) 231 { 232 double pages = vmstats.free_count; 233 double pagesize = vmstats.pagesize; 234 235 if (0 <= pages && 0 <= pagesize) 236 return pages * pagesize; 237 } 238 } 239#endif 240 241#if HAVE_SYSCTL && defined HW_USERMEM 242 { /* This works on *bsd and darwin. */ 243 unsigned int usermem; 244 size_t len = sizeof usermem; 245 static int mib[2] = { CTL_HW, HW_USERMEM }; 246 247 if (sysctl (mib, ARRAY_SIZE (mib), &usermem, &len, NULL, 0) == 0 248 && len == sizeof (usermem)) 249 return (double) usermem; 250 } 251#endif 252 253#if defined _WIN32 254 { /* this works on windows */ 255 PFN_MS_EX pfnex; 256 HMODULE h = GetModuleHandle ("kernel32.dll"); 257 258 if (!h) 259 return 0.0; 260 261 /* Use GlobalMemoryStatusEx if available. */ 262 if ((pfnex = (PFN_MS_EX) GetProcAddress (h, "GlobalMemoryStatusEx"))) 263 { 264 lMEMORYSTATUSEX lms_ex; 265 lms_ex.dwLength = sizeof lms_ex; 266 if (!pfnex (&lms_ex)) 267 return 0.0; 268 return (double) lms_ex.ullAvailPhys; 269 } 270 271 /* Fall back to GlobalMemoryStatus which is always available. 272 but returns wrong results for physical memory > 4GB */ 273 else 274 { 275 MEMORYSTATUS ms; 276 GlobalMemoryStatus (&ms); 277 return (double) ms.dwAvailPhys; 278 } 279 } 280#endif 281 282 /* Guess 25% of physical memory. */ 283 return physmem_total () / 4; 284} 285 286 287#if DEBUG 288 289# include <stdio.h> 290# include <stdlib.h> 291 292int 293main (void) 294{ 295 printf ("%12.f %12.f\n", physmem_total (), physmem_available ()); 296 exit (0); 297} 298 299#endif /* DEBUG */ 300 301/* 302Local Variables: 303compile-command: "gcc -DDEBUG -DHAVE_CONFIG_H -I.. -g -O -Wall -W physmem.c" 304End: 305*/ 306