1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
|
/* Calculate the size of physical memory.
Copyright (C) 2000-2020 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
/* Written by Paul Eggert. */
#if HAVE_CONFIG_H
# include <config.h>
#endif
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#if HAVE_SYS_PSTAT_H
# include <sys/pstat.h>
#endif
#if HAVE_SYS_SYSMP_H
# include <sys/sysmp.h>
#endif
#if HAVE_SYS_SYSINFO_H && HAVE_MACHINE_HAL_SYSINFO_H
# include <sys/sysinfo.h>
# include <machine/hal_sysinfo.h>
#endif
#if HAVE_SYS_TABLE_H
# include <sys/table.h>
#endif
#include <sys/types.h>
#if HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
#if HAVE_SYS_SYSCTL_H
# include <sys/sysctl.h>
#endif
#if HAVE_SYS_SYSTEMCFG_H
# include <sys/systemcfg.h>
#endif
#ifdef _WIN32
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
/* 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 WINBOOL (WINAPI *PFN_MS_EX) (lMEMORYSTATUSEX*);
#endif
#include "libiberty.h"
/* Return the total amount of physical memory. */
double
physmem_total (void)
{
#if defined _SC_PHYS_PAGES && defined _SC_PAGESIZE
{ /* This works on linux-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_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 HW_PHYSMEM
{ /* This works on *bsd 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 4.3.3+. */
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
/* Return 0 if we can't determine the value. */
return 0;
}
/* Return the amount of physical memory available. */
double
physmem_available (void)
{
#if defined _SC_AVPHYS_PAGES && defined _SC_PAGESIZE
{ /* This works on linux-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_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 HW_USERMEM
{ /* This works on *bsd 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 <stdio.h>
# include <stdlib.h>
int
main (void)
{
printf ("%12.f %12.f\n", physmem_total (), physmem_available ());
exit (0);
}
#endif /* DEBUG */
/*
Local Variables:
compile-command: "gcc -DDEBUG -DHAVE_CONFIG_H -I.. -g -O -Wall -W physmem.c"
End:
*/
|