198b9484cSchristos /* Calculate the size of physical memory. 2*7e120ff0Schristos Copyright (C) 2000-2024 Free Software Foundation, Inc. 398b9484cSchristos 498b9484cSchristos This program is free software; you can redistribute it and/or modify 598b9484cSchristos it under the terms of the GNU General Public License as published by 698b9484cSchristos the Free Software Foundation; either version 2, or (at your option) 798b9484cSchristos any later version. 898b9484cSchristos 998b9484cSchristos This program is distributed in the hope that it will be useful, 1098b9484cSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of 1198b9484cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1298b9484cSchristos GNU General Public License for more details. 1398b9484cSchristos 1498b9484cSchristos You should have received a copy of the GNU General Public License 1598b9484cSchristos along with this program; if not, write to the Free Software Foundation, 1698b9484cSchristos Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 1798b9484cSchristos 1898b9484cSchristos /* Written by Paul Eggert. */ 1998b9484cSchristos 2098b9484cSchristos #if HAVE_CONFIG_H 2198b9484cSchristos # include <config.h> 2298b9484cSchristos #endif 2398b9484cSchristos 2498b9484cSchristos #if HAVE_UNISTD_H 2598b9484cSchristos # include <unistd.h> 2698b9484cSchristos #endif 2798b9484cSchristos 2898b9484cSchristos #if HAVE_SYS_PSTAT_H 2998b9484cSchristos # include <sys/pstat.h> 3098b9484cSchristos #endif 3198b9484cSchristos 3298b9484cSchristos #if HAVE_SYS_SYSMP_H 3398b9484cSchristos # include <sys/sysmp.h> 3498b9484cSchristos #endif 3598b9484cSchristos 3698b9484cSchristos #if HAVE_SYS_SYSINFO_H && HAVE_MACHINE_HAL_SYSINFO_H 3798b9484cSchristos # include <sys/sysinfo.h> 3898b9484cSchristos # include <machine/hal_sysinfo.h> 3998b9484cSchristos #endif 4098b9484cSchristos 4198b9484cSchristos #if HAVE_SYS_TABLE_H 4298b9484cSchristos # include <sys/table.h> 4398b9484cSchristos #endif 4498b9484cSchristos 4598b9484cSchristos #include <sys/types.h> 4698b9484cSchristos 4798b9484cSchristos #if HAVE_SYS_PARAM_H 4898b9484cSchristos # include <sys/param.h> 4998b9484cSchristos #endif 5098b9484cSchristos 5198b9484cSchristos #if HAVE_SYS_SYSCTL_H 5298b9484cSchristos # include <sys/sysctl.h> 5398b9484cSchristos #endif 5498b9484cSchristos 5598b9484cSchristos #if HAVE_SYS_SYSTEMCFG_H 5698b9484cSchristos # include <sys/systemcfg.h> 5798b9484cSchristos #endif 5898b9484cSchristos 5998b9484cSchristos #ifdef _WIN32 6098b9484cSchristos # define WIN32_LEAN_AND_MEAN 6198b9484cSchristos # include <windows.h> 6298b9484cSchristos /* MEMORYSTATUSEX is missing from older windows headers, so define 6398b9484cSchristos a local replacement. */ 6498b9484cSchristos typedef struct 6598b9484cSchristos { 6698b9484cSchristos DWORD dwLength; 6798b9484cSchristos DWORD dwMemoryLoad; 6898b9484cSchristos DWORDLONG ullTotalPhys; 6998b9484cSchristos DWORDLONG ullAvailPhys; 7098b9484cSchristos DWORDLONG ullTotalPageFile; 7198b9484cSchristos DWORDLONG ullAvailPageFile; 7298b9484cSchristos DWORDLONG ullTotalVirtual; 7398b9484cSchristos DWORDLONG ullAvailVirtual; 7498b9484cSchristos DWORDLONG ullAvailExtendedVirtual; 7598b9484cSchristos } lMEMORYSTATUSEX; 7698b9484cSchristos typedef WINBOOL (WINAPI *PFN_MS_EX) (lMEMORYSTATUSEX*); 7798b9484cSchristos #endif 7898b9484cSchristos 7998b9484cSchristos #include "libiberty.h" 8098b9484cSchristos 8198b9484cSchristos /* Return the total amount of physical memory. */ 8298b9484cSchristos double 8398b9484cSchristos physmem_total (void) 8498b9484cSchristos { 8598b9484cSchristos #if defined _SC_PHYS_PAGES && defined _SC_PAGESIZE 8698b9484cSchristos { /* This works on linux-gnu, solaris2 and cygwin. */ 8798b9484cSchristos double pages = sysconf (_SC_PHYS_PAGES); 8898b9484cSchristos double pagesize = sysconf (_SC_PAGESIZE); 8998b9484cSchristos if (0 <= pages && 0 <= pagesize) 9098b9484cSchristos return pages * pagesize; 9198b9484cSchristos } 9298b9484cSchristos #endif 9398b9484cSchristos 9498b9484cSchristos #if HAVE_PSTAT_GETSTATIC 9598b9484cSchristos { /* This works on hpux11. */ 9698b9484cSchristos struct pst_static pss; 9798b9484cSchristos if (0 <= pstat_getstatic (&pss, sizeof pss, 1, 0)) 9898b9484cSchristos { 9998b9484cSchristos double pages = pss.physical_memory; 10098b9484cSchristos double pagesize = pss.page_size; 10198b9484cSchristos if (0 <= pages && 0 <= pagesize) 10298b9484cSchristos return pages * pagesize; 10398b9484cSchristos } 10498b9484cSchristos } 10598b9484cSchristos #endif 10698b9484cSchristos 10798b9484cSchristos #if HAVE_SYSMP && defined MP_SAGET && defined MPSA_RMINFO && defined _SC_PAGESIZE 10898b9484cSchristos { /* This works on irix6. */ 10998b9484cSchristos struct rminfo realmem; 11098b9484cSchristos if (sysmp (MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0) 11198b9484cSchristos { 11298b9484cSchristos double pagesize = sysconf (_SC_PAGESIZE); 11398b9484cSchristos double pages = realmem.physmem; 11498b9484cSchristos if (0 <= pages && 0 <= pagesize) 11598b9484cSchristos return pages * pagesize; 11698b9484cSchristos } 11798b9484cSchristos } 11898b9484cSchristos #endif 11998b9484cSchristos 12098b9484cSchristos #if HAVE_GETSYSINFO && defined GSI_PHYSMEM 12198b9484cSchristos { /* This works on Tru64 UNIX V4/5. */ 12298b9484cSchristos int physmem; 12398b9484cSchristos 12498b9484cSchristos if (getsysinfo (GSI_PHYSMEM, (caddr_t) &physmem, sizeof (physmem), 12598b9484cSchristos NULL, NULL, NULL) == 1) 12698b9484cSchristos { 12798b9484cSchristos double kbytes = physmem; 12898b9484cSchristos 12998b9484cSchristos if (0 <= kbytes) 13098b9484cSchristos return kbytes * 1024.0; 13198b9484cSchristos } 13298b9484cSchristos } 13398b9484cSchristos #endif 13498b9484cSchristos 13598b9484cSchristos #if HAVE_SYSCTL && defined HW_PHYSMEM 13698b9484cSchristos { /* This works on *bsd and darwin. */ 13798b9484cSchristos unsigned int physmem; 13898b9484cSchristos size_t len = sizeof physmem; 13998b9484cSchristos static int mib[2] = { CTL_HW, HW_PHYSMEM }; 14098b9484cSchristos 14198b9484cSchristos if (sysctl (mib, ARRAY_SIZE (mib), &physmem, &len, NULL, 0) == 0 14298b9484cSchristos && len == sizeof (physmem)) 14398b9484cSchristos return (double) physmem; 14498b9484cSchristos } 14598b9484cSchristos #endif 14698b9484cSchristos 14798b9484cSchristos #if HAVE__SYSTEM_CONFIGURATION 14898b9484cSchristos /* This works on AIX 4.3.3+. */ 14998b9484cSchristos return _system_configuration.physmem; 15098b9484cSchristos #endif 15198b9484cSchristos 15298b9484cSchristos #if defined _WIN32 15398b9484cSchristos { /* this works on windows */ 15498b9484cSchristos PFN_MS_EX pfnex; 15598b9484cSchristos HMODULE h = GetModuleHandle ("kernel32.dll"); 15698b9484cSchristos 15798b9484cSchristos if (!h) 15898b9484cSchristos return 0.0; 15998b9484cSchristos 16098b9484cSchristos /* Use GlobalMemoryStatusEx if available. */ 16198b9484cSchristos if ((pfnex = (PFN_MS_EX) GetProcAddress (h, "GlobalMemoryStatusEx"))) 16298b9484cSchristos { 16398b9484cSchristos lMEMORYSTATUSEX lms_ex; 16498b9484cSchristos lms_ex.dwLength = sizeof lms_ex; 16598b9484cSchristos if (!pfnex (&lms_ex)) 16698b9484cSchristos return 0.0; 16798b9484cSchristos return (double) lms_ex.ullTotalPhys; 16898b9484cSchristos } 16998b9484cSchristos 17098b9484cSchristos /* Fall back to GlobalMemoryStatus which is always available. 17198b9484cSchristos but returns wrong results for physical memory > 4GB. */ 17298b9484cSchristos else 17398b9484cSchristos { 17498b9484cSchristos MEMORYSTATUS ms; 17598b9484cSchristos GlobalMemoryStatus (&ms); 17698b9484cSchristos return (double) ms.dwTotalPhys; 17798b9484cSchristos } 17898b9484cSchristos } 17998b9484cSchristos #endif 18098b9484cSchristos 18198b9484cSchristos /* Return 0 if we can't determine the value. */ 18298b9484cSchristos return 0; 18398b9484cSchristos } 18498b9484cSchristos 18598b9484cSchristos /* Return the amount of physical memory available. */ 18698b9484cSchristos double 18798b9484cSchristos physmem_available (void) 18898b9484cSchristos { 18998b9484cSchristos #if defined _SC_AVPHYS_PAGES && defined _SC_PAGESIZE 19098b9484cSchristos { /* This works on linux-gnu, solaris2 and cygwin. */ 19198b9484cSchristos double pages = sysconf (_SC_AVPHYS_PAGES); 19298b9484cSchristos double pagesize = sysconf (_SC_PAGESIZE); 19398b9484cSchristos if (0 <= pages && 0 <= pagesize) 19498b9484cSchristos return pages * pagesize; 19598b9484cSchristos } 19698b9484cSchristos #endif 19798b9484cSchristos 19898b9484cSchristos #if HAVE_PSTAT_GETSTATIC && HAVE_PSTAT_GETDYNAMIC 19998b9484cSchristos { /* This works on hpux11. */ 20098b9484cSchristos struct pst_static pss; 20198b9484cSchristos struct pst_dynamic psd; 20298b9484cSchristos if (0 <= pstat_getstatic (&pss, sizeof pss, 1, 0) 20398b9484cSchristos && 0 <= pstat_getdynamic (&psd, sizeof psd, 1, 0)) 20498b9484cSchristos { 20598b9484cSchristos double pages = psd.psd_free; 20698b9484cSchristos double pagesize = pss.page_size; 20798b9484cSchristos if (0 <= pages && 0 <= pagesize) 20898b9484cSchristos return pages * pagesize; 20998b9484cSchristos } 21098b9484cSchristos } 21198b9484cSchristos #endif 21298b9484cSchristos 21398b9484cSchristos #if HAVE_SYSMP && defined MP_SAGET && defined MPSA_RMINFO && defined _SC_PAGESIZE 21498b9484cSchristos { /* This works on irix6. */ 21598b9484cSchristos struct rminfo realmem; 21698b9484cSchristos if (sysmp (MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0) 21798b9484cSchristos { 21898b9484cSchristos double pagesize = sysconf (_SC_PAGESIZE); 21998b9484cSchristos double pages = realmem.availrmem; 22098b9484cSchristos if (0 <= pages && 0 <= pagesize) 22198b9484cSchristos return pages * pagesize; 22298b9484cSchristos } 22398b9484cSchristos } 22498b9484cSchristos #endif 22598b9484cSchristos 22698b9484cSchristos #if HAVE_TABLE && defined TBL_VMSTATS 22798b9484cSchristos { /* This works on Tru64 UNIX V4/5. */ 22898b9484cSchristos struct tbl_vmstats vmstats; 22998b9484cSchristos 23098b9484cSchristos if (table (TBL_VMSTATS, 0, &vmstats, 1, sizeof (vmstats)) == 1) 23198b9484cSchristos { 23298b9484cSchristos double pages = vmstats.free_count; 23398b9484cSchristos double pagesize = vmstats.pagesize; 23498b9484cSchristos 23598b9484cSchristos if (0 <= pages && 0 <= pagesize) 23698b9484cSchristos return pages * pagesize; 23798b9484cSchristos } 23898b9484cSchristos } 23998b9484cSchristos #endif 24098b9484cSchristos 24198b9484cSchristos #if HAVE_SYSCTL && defined HW_USERMEM 24298b9484cSchristos { /* This works on *bsd and darwin. */ 24398b9484cSchristos unsigned int usermem; 24498b9484cSchristos size_t len = sizeof usermem; 24598b9484cSchristos static int mib[2] = { CTL_HW, HW_USERMEM }; 24698b9484cSchristos 24798b9484cSchristos if (sysctl (mib, ARRAY_SIZE (mib), &usermem, &len, NULL, 0) == 0 24898b9484cSchristos && len == sizeof (usermem)) 24998b9484cSchristos return (double) usermem; 25098b9484cSchristos } 25198b9484cSchristos #endif 25298b9484cSchristos 25398b9484cSchristos #if defined _WIN32 25498b9484cSchristos { /* this works on windows */ 25598b9484cSchristos PFN_MS_EX pfnex; 25698b9484cSchristos HMODULE h = GetModuleHandle ("kernel32.dll"); 25798b9484cSchristos 25898b9484cSchristos if (!h) 25998b9484cSchristos return 0.0; 26098b9484cSchristos 26198b9484cSchristos /* Use GlobalMemoryStatusEx if available. */ 26298b9484cSchristos if ((pfnex = (PFN_MS_EX) GetProcAddress (h, "GlobalMemoryStatusEx"))) 26398b9484cSchristos { 26498b9484cSchristos lMEMORYSTATUSEX lms_ex; 26598b9484cSchristos lms_ex.dwLength = sizeof lms_ex; 26698b9484cSchristos if (!pfnex (&lms_ex)) 26798b9484cSchristos return 0.0; 26898b9484cSchristos return (double) lms_ex.ullAvailPhys; 26998b9484cSchristos } 27098b9484cSchristos 27198b9484cSchristos /* Fall back to GlobalMemoryStatus which is always available. 27298b9484cSchristos but returns wrong results for physical memory > 4GB */ 27398b9484cSchristos else 27498b9484cSchristos { 27598b9484cSchristos MEMORYSTATUS ms; 27698b9484cSchristos GlobalMemoryStatus (&ms); 27798b9484cSchristos return (double) ms.dwAvailPhys; 27898b9484cSchristos } 27998b9484cSchristos } 28098b9484cSchristos #endif 28198b9484cSchristos 28298b9484cSchristos /* Guess 25% of physical memory. */ 28398b9484cSchristos return physmem_total () / 4; 28498b9484cSchristos } 28598b9484cSchristos 28698b9484cSchristos 28798b9484cSchristos #if DEBUG 28898b9484cSchristos 28998b9484cSchristos # include <stdio.h> 29098b9484cSchristos # include <stdlib.h> 29198b9484cSchristos 29298b9484cSchristos int 29398b9484cSchristos main (void) 29498b9484cSchristos { 29598b9484cSchristos printf ("%12.f %12.f\n", physmem_total (), physmem_available ()); 29698b9484cSchristos exit (0); 29798b9484cSchristos } 29898b9484cSchristos 29998b9484cSchristos #endif /* DEBUG */ 30098b9484cSchristos 30198b9484cSchristos /* 30298b9484cSchristos Local Variables: 30398b9484cSchristos compile-command: "gcc -DDEBUG -DHAVE_CONFIG_H -I.. -g -O -Wall -W physmem.c" 30498b9484cSchristos End: 30598b9484cSchristos */ 306