1169695Skan/* Calculate the size of physical memory.
2169695Skan   Copyright 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
3169695Skan
4169695Skan   This program is free software; you can redistribute it and/or modify
5169695Skan   it under the terms of the GNU General Public License as published by
6169695Skan   the Free Software Foundation; either version 2, or (at your option)
7169695Skan   any later version.
8169695Skan
9169695Skan   This program is distributed in the hope that it will be useful,
10169695Skan   but WITHOUT ANY WARRANTY; without even the implied warranty of
11169695Skan   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12169695Skan   GNU General Public License for more details.
13169695Skan
14169695Skan   You should have received a copy of the GNU General Public License
15169695Skan   along with this program; if not, write to the Free Software Foundation,
16169695Skan   Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
17169695Skan
18169695Skan/* Written by Paul Eggert.  */
19169695Skan
20169695Skan#if HAVE_CONFIG_H
21169695Skan# include <config.h>
22169695Skan#endif
23169695Skan
24169695Skan#if HAVE_UNISTD_H
25169695Skan# include <unistd.h>
26169695Skan#endif
27169695Skan
28169695Skan#if HAVE_SYS_PSTAT_H
29169695Skan# include <sys/pstat.h>
30169695Skan#endif
31169695Skan
32169695Skan#if HAVE_SYS_SYSMP_H
33169695Skan# include <sys/sysmp.h>
34169695Skan#endif
35169695Skan
36169695Skan#if HAVE_SYS_SYSINFO_H && HAVE_MACHINE_HAL_SYSINFO_H
37169695Skan# include <sys/sysinfo.h>
38169695Skan# include <machine/hal_sysinfo.h>
39169695Skan#endif
40169695Skan
41169695Skan#if HAVE_SYS_TABLE_H
42169695Skan# include <sys/table.h>
43169695Skan#endif
44169695Skan
45169695Skan#include <sys/types.h>
46169695Skan
47169695Skan#if HAVE_SYS_PARAM_H
48169695Skan# include <sys/param.h>
49169695Skan#endif
50169695Skan
51169695Skan#if HAVE_SYS_SYSCTL_H
52169695Skan# include <sys/sysctl.h>
53169695Skan#endif
54169695Skan
55169695Skan#if HAVE_SYS_SYSTEMCFG_H
56169695Skan# include <sys/systemcfg.h>
57169695Skan#endif
58169695Skan
59169695Skan#ifdef _WIN32
60169695Skan# define WIN32_LEAN_AND_MEAN
61169695Skan# include <windows.h>
62169695Skan/*  MEMORYSTATUSEX is missing from older windows headers, so define
63169695Skan    a local replacement.  */
64169695Skantypedef struct
65169695Skan{
66169695Skan  DWORD dwLength;
67169695Skan  DWORD dwMemoryLoad;
68169695Skan  DWORDLONG ullTotalPhys;
69169695Skan  DWORDLONG ullAvailPhys;
70169695Skan  DWORDLONG ullTotalPageFile;
71169695Skan  DWORDLONG ullAvailPageFile;
72169695Skan  DWORDLONG ullTotalVirtual;
73169695Skan  DWORDLONG ullAvailVirtual;
74169695Skan  DWORDLONG ullAvailExtendedVirtual;
75169695Skan} lMEMORYSTATUSEX;
76169695Skantypedef WINBOOL (WINAPI *PFN_MS_EX) (lMEMORYSTATUSEX*);
77169695Skan#endif
78169695Skan
79169695Skan#include "libiberty.h"
80169695Skan
81169695Skan/* Return the total amount of physical memory.  */
82169695Skandouble
83169695Skanphysmem_total (void)
84169695Skan{
85169695Skan#if defined _SC_PHYS_PAGES && defined _SC_PAGESIZE
86169695Skan  { /* This works on linux-gnu, solaris2 and cygwin.  */
87169695Skan    double pages = sysconf (_SC_PHYS_PAGES);
88169695Skan    double pagesize = sysconf (_SC_PAGESIZE);
89169695Skan    if (0 <= pages && 0 <= pagesize)
90169695Skan      return pages * pagesize;
91169695Skan  }
92169695Skan#endif
93169695Skan
94169695Skan#if HAVE_PSTAT_GETSTATIC
95169695Skan  { /* This works on hpux11.  */
96169695Skan    struct pst_static pss;
97169695Skan    if (0 <= pstat_getstatic (&pss, sizeof pss, 1, 0))
98169695Skan      {
99169695Skan	double pages = pss.physical_memory;
100169695Skan	double pagesize = pss.page_size;
101169695Skan	if (0 <= pages && 0 <= pagesize)
102169695Skan	  return pages * pagesize;
103169695Skan      }
104169695Skan  }
105169695Skan#endif
106169695Skan
107169695Skan#if HAVE_SYSMP && defined MP_SAGET && defined MPSA_RMINFO && defined _SC_PAGESIZE
108169695Skan  { /* This works on irix6. */
109169695Skan    struct rminfo realmem;
110169695Skan    if (sysmp (MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0)
111169695Skan      {
112169695Skan	double pagesize = sysconf (_SC_PAGESIZE);
113169695Skan	double pages = realmem.physmem;
114169695Skan	if (0 <= pages && 0 <= pagesize)
115169695Skan	  return pages * pagesize;
116169695Skan      }
117169695Skan  }
118169695Skan#endif
119169695Skan
120169695Skan#if HAVE_GETSYSINFO && defined GSI_PHYSMEM
121169695Skan  { /* This works on Tru64 UNIX V4/5.  */
122169695Skan    int physmem;
123169695Skan
124169695Skan    if (getsysinfo (GSI_PHYSMEM, (caddr_t) &physmem, sizeof (physmem),
125169695Skan		    NULL, NULL, NULL) == 1)
126169695Skan      {
127169695Skan	double kbytes = physmem;
128169695Skan
129169695Skan	if (0 <= kbytes)
130169695Skan	  return kbytes * 1024.0;
131169695Skan      }
132169695Skan  }
133169695Skan#endif
134169695Skan
135169695Skan#if HAVE_SYSCTL && defined HW_PHYSMEM
136169695Skan  { /* This works on *bsd and darwin.  */
137169695Skan    unsigned int physmem;
138169695Skan    size_t len = sizeof physmem;
139169695Skan    static int mib[2] = { CTL_HW, HW_PHYSMEM };
140169695Skan
141169695Skan    if (sysctl (mib, ARRAY_SIZE (mib), &physmem, &len, NULL, 0) == 0
142169695Skan	&& len == sizeof (physmem))
143169695Skan      return (double) physmem;
144169695Skan  }
145169695Skan#endif
146169695Skan
147169695Skan#if HAVE__SYSTEM_CONFIGURATION
148169695Skan  /* This works on AIX 4.3.3+.  */
149169695Skan  return _system_configuration.physmem;
150169695Skan#endif
151169695Skan
152169695Skan#if defined _WIN32
153169695Skan  { /* this works on windows */
154169695Skan    PFN_MS_EX pfnex;
155169695Skan    HMODULE h = GetModuleHandle ("kernel32.dll");
156169695Skan
157169695Skan    if (!h)
158169695Skan      return 0.0;
159169695Skan
160169695Skan    /*  Use GlobalMemoryStatusEx if available.  */
161169695Skan    if ((pfnex = (PFN_MS_EX) GetProcAddress (h, "GlobalMemoryStatusEx")))
162169695Skan      {
163169695Skan	lMEMORYSTATUSEX lms_ex;
164169695Skan	lms_ex.dwLength = sizeof lms_ex;
165169695Skan	if (!pfnex (&lms_ex))
166169695Skan	  return 0.0;
167169695Skan	return (double) lms_ex.ullTotalPhys;
168169695Skan      }
169169695Skan
170169695Skan    /*  Fall back to GlobalMemoryStatus which is always available.
171169695Skan        but returns wrong results for physical memory > 4GB.  */
172169695Skan    else
173169695Skan      {
174169695Skan	MEMORYSTATUS ms;
175169695Skan	GlobalMemoryStatus (&ms);
176169695Skan	return (double) ms.dwTotalPhys;
177169695Skan      }
178169695Skan  }
179169695Skan#endif
180169695Skan
181169695Skan  /* Return 0 if we can't determine the value.  */
182169695Skan  return 0;
183169695Skan}
184169695Skan
185169695Skan/* Return the amount of physical memory available.  */
186169695Skandouble
187169695Skanphysmem_available (void)
188169695Skan{
189169695Skan#if defined _SC_AVPHYS_PAGES && defined _SC_PAGESIZE
190169695Skan  { /* This works on linux-gnu, solaris2 and cygwin.  */
191169695Skan    double pages = sysconf (_SC_AVPHYS_PAGES);
192169695Skan    double pagesize = sysconf (_SC_PAGESIZE);
193169695Skan    if (0 <= pages && 0 <= pagesize)
194169695Skan      return pages * pagesize;
195169695Skan  }
196169695Skan#endif
197169695Skan
198169695Skan#if HAVE_PSTAT_GETSTATIC && HAVE_PSTAT_GETDYNAMIC
199169695Skan  { /* This works on hpux11.  */
200169695Skan    struct pst_static pss;
201169695Skan    struct pst_dynamic psd;
202169695Skan    if (0 <= pstat_getstatic (&pss, sizeof pss, 1, 0)
203169695Skan	&& 0 <= pstat_getdynamic (&psd, sizeof psd, 1, 0))
204169695Skan      {
205169695Skan	double pages = psd.psd_free;
206169695Skan	double pagesize = pss.page_size;
207169695Skan	if (0 <= pages && 0 <= pagesize)
208169695Skan	  return pages * pagesize;
209169695Skan      }
210169695Skan  }
211169695Skan#endif
212169695Skan
213169695Skan#if HAVE_SYSMP && defined MP_SAGET && defined MPSA_RMINFO && defined _SC_PAGESIZE
214169695Skan  { /* This works on irix6. */
215169695Skan    struct rminfo realmem;
216169695Skan    if (sysmp (MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0)
217169695Skan      {
218169695Skan	double pagesize = sysconf (_SC_PAGESIZE);
219169695Skan	double pages = realmem.availrmem;
220169695Skan	if (0 <= pages && 0 <= pagesize)
221169695Skan	  return pages * pagesize;
222169695Skan      }
223169695Skan  }
224169695Skan#endif
225169695Skan
226169695Skan#if HAVE_TABLE && defined TBL_VMSTATS
227169695Skan  { /* This works on Tru64 UNIX V4/5.  */
228169695Skan    struct tbl_vmstats vmstats;
229169695Skan
230169695Skan    if (table (TBL_VMSTATS, 0, &vmstats, 1, sizeof (vmstats)) == 1)
231169695Skan      {
232169695Skan	double pages = vmstats.free_count;
233169695Skan	double pagesize = vmstats.pagesize;
234169695Skan
235169695Skan	if (0 <= pages && 0 <= pagesize)
236169695Skan	  return pages * pagesize;
237169695Skan      }
238169695Skan  }
239169695Skan#endif
240169695Skan
241169695Skan#if HAVE_SYSCTL && defined HW_USERMEM
242169695Skan  { /* This works on *bsd and darwin.  */
243169695Skan    unsigned int usermem;
244169695Skan    size_t len = sizeof usermem;
245169695Skan    static int mib[2] = { CTL_HW, HW_USERMEM };
246169695Skan
247169695Skan    if (sysctl (mib, ARRAY_SIZE (mib), &usermem, &len, NULL, 0) == 0
248169695Skan	&& len == sizeof (usermem))
249169695Skan      return (double) usermem;
250169695Skan  }
251169695Skan#endif
252169695Skan
253169695Skan#if defined _WIN32
254169695Skan  { /* this works on windows */
255169695Skan    PFN_MS_EX pfnex;
256169695Skan    HMODULE h = GetModuleHandle ("kernel32.dll");
257169695Skan
258169695Skan    if (!h)
259169695Skan      return 0.0;
260169695Skan
261169695Skan    /*  Use GlobalMemoryStatusEx if available.  */
262169695Skan    if ((pfnex = (PFN_MS_EX) GetProcAddress (h, "GlobalMemoryStatusEx")))
263169695Skan      {
264169695Skan	lMEMORYSTATUSEX lms_ex;
265169695Skan	lms_ex.dwLength = sizeof lms_ex;
266169695Skan	if (!pfnex (&lms_ex))
267169695Skan	  return 0.0;
268169695Skan	return (double) lms_ex.ullAvailPhys;
269169695Skan      }
270169695Skan
271169695Skan    /*  Fall back to GlobalMemoryStatus which is always available.
272169695Skan        but returns wrong results for physical memory > 4GB  */
273169695Skan    else
274169695Skan      {
275169695Skan	MEMORYSTATUS ms;
276169695Skan	GlobalMemoryStatus (&ms);
277169695Skan	return (double) ms.dwAvailPhys;
278169695Skan      }
279169695Skan  }
280169695Skan#endif
281169695Skan
282169695Skan  /* Guess 25% of physical memory.  */
283169695Skan  return physmem_total () / 4;
284169695Skan}
285169695Skan
286169695Skan
287169695Skan#if DEBUG
288169695Skan
289169695Skan# include <stdio.h>
290169695Skan# include <stdlib.h>
291169695Skan
292169695Skanint
293169695Skanmain (void)
294169695Skan{
295169695Skan  printf ("%12.f %12.f\n", physmem_total (), physmem_available ());
296169695Skan  exit (0);
297169695Skan}
298169695Skan
299169695Skan#endif /* DEBUG */
300169695Skan
301169695Skan/*
302169695SkanLocal Variables:
303169695Skancompile-command: "gcc -DDEBUG -DHAVE_CONFIG_H -I.. -g -O -Wall -W physmem.c"
304169695SkanEnd:
305169695Skan*/
306