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. */ 64 typedef 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; 76 typedef WINBOOL (WINAPI *PFN_MS_EX) (lMEMORYSTATUSEX*); 77 #endif 78 79 #include "libiberty.h" 80 81 /* Return the total amount of physical memory. */ 82 double 83 physmem_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. */ 186 double 187 physmem_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 292 int 293 main (void) 294 { 295 printf ("%12.f %12.f\n", physmem_total (), physmem_available ()); 296 exit (0); 297 } 298 299 #endif /* DEBUG */ 300 301 /* 302 Local Variables: 303 compile-command: "gcc -DDEBUG -DHAVE_CONFIG_H -I.. -g -O -Wall -W physmem.c" 304 End: 305 */ 306