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
185261188Spfg/* APPLE LOCAL begin retune gc params 6124839 */
186261188Spfgunsigned int
187261188Spfgncpu_available (void)
188261188Spfg{
189261188Spfg#if HAVE_SYSCTL && defined HW_AVAILCPU
190261188Spfg  { /* This works on *bsd and darwin.  */
191261188Spfg    unsigned int ncpu;
192261188Spfg    size_t len = sizeof ncpu;
193261188Spfg    static int mib[2] = { CTL_HW, HW_AVAILCPU };
194261188Spfg
195261188Spfg    if (sysctl (mib, ARRAY_SIZE (mib), &ncpu, &len, NULL, 0) == 0
196261188Spfg	&& len == sizeof (ncpu))
197261188Spfg      return ncpu;
198261188Spfg  }
199261188Spfg#endif
200261188Spfg#if HAVE_SYSCTL && defined HW_NCPU
201261188Spfg  { /* This works on *bsd and darwin.  */
202261188Spfg    unsigned int ncpu;
203261188Spfg    size_t len = sizeof ncpu;
204261188Spfg    static int mib[2] = { CTL_HW, HW_NCPU };
205261188Spfg
206261188Spfg    if (sysctl (mib, ARRAY_SIZE (mib), &ncpu, &len, NULL, 0) == 0
207261188Spfg	&& len == sizeof (ncpu))
208261188Spfg      return ncpu;
209261188Spfg  }
210261188Spfg#endif
211261188Spfg  return 1;
212261188Spfg}
213261188Spfg/* APPLE LOCAL end retune gc params 6124839 */
214261188Spfg
215169695Skan/* Return the amount of physical memory available.  */
216169695Skandouble
217169695Skanphysmem_available (void)
218169695Skan{
219169695Skan#if defined _SC_AVPHYS_PAGES && defined _SC_PAGESIZE
220169695Skan  { /* This works on linux-gnu, solaris2 and cygwin.  */
221169695Skan    double pages = sysconf (_SC_AVPHYS_PAGES);
222169695Skan    double pagesize = sysconf (_SC_PAGESIZE);
223169695Skan    if (0 <= pages && 0 <= pagesize)
224169695Skan      return pages * pagesize;
225169695Skan  }
226169695Skan#endif
227169695Skan
228169695Skan#if HAVE_PSTAT_GETSTATIC && HAVE_PSTAT_GETDYNAMIC
229169695Skan  { /* This works on hpux11.  */
230169695Skan    struct pst_static pss;
231169695Skan    struct pst_dynamic psd;
232169695Skan    if (0 <= pstat_getstatic (&pss, sizeof pss, 1, 0)
233169695Skan	&& 0 <= pstat_getdynamic (&psd, sizeof psd, 1, 0))
234169695Skan      {
235169695Skan	double pages = psd.psd_free;
236169695Skan	double pagesize = pss.page_size;
237169695Skan	if (0 <= pages && 0 <= pagesize)
238169695Skan	  return pages * pagesize;
239169695Skan      }
240169695Skan  }
241169695Skan#endif
242169695Skan
243169695Skan#if HAVE_SYSMP && defined MP_SAGET && defined MPSA_RMINFO && defined _SC_PAGESIZE
244169695Skan  { /* This works on irix6. */
245169695Skan    struct rminfo realmem;
246169695Skan    if (sysmp (MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0)
247169695Skan      {
248169695Skan	double pagesize = sysconf (_SC_PAGESIZE);
249169695Skan	double pages = realmem.availrmem;
250169695Skan	if (0 <= pages && 0 <= pagesize)
251169695Skan	  return pages * pagesize;
252169695Skan      }
253169695Skan  }
254169695Skan#endif
255169695Skan
256169695Skan#if HAVE_TABLE && defined TBL_VMSTATS
257169695Skan  { /* This works on Tru64 UNIX V4/5.  */
258169695Skan    struct tbl_vmstats vmstats;
259169695Skan
260169695Skan    if (table (TBL_VMSTATS, 0, &vmstats, 1, sizeof (vmstats)) == 1)
261169695Skan      {
262169695Skan	double pages = vmstats.free_count;
263169695Skan	double pagesize = vmstats.pagesize;
264169695Skan
265169695Skan	if (0 <= pages && 0 <= pagesize)
266169695Skan	  return pages * pagesize;
267169695Skan      }
268169695Skan  }
269169695Skan#endif
270169695Skan
271169695Skan#if HAVE_SYSCTL && defined HW_USERMEM
272169695Skan  { /* This works on *bsd and darwin.  */
273169695Skan    unsigned int usermem;
274169695Skan    size_t len = sizeof usermem;
275169695Skan    static int mib[2] = { CTL_HW, HW_USERMEM };
276169695Skan
277169695Skan    if (sysctl (mib, ARRAY_SIZE (mib), &usermem, &len, NULL, 0) == 0
278169695Skan	&& len == sizeof (usermem))
279169695Skan      return (double) usermem;
280169695Skan  }
281169695Skan#endif
282169695Skan
283169695Skan#if defined _WIN32
284169695Skan  { /* this works on windows */
285169695Skan    PFN_MS_EX pfnex;
286169695Skan    HMODULE h = GetModuleHandle ("kernel32.dll");
287169695Skan
288169695Skan    if (!h)
289169695Skan      return 0.0;
290169695Skan
291169695Skan    /*  Use GlobalMemoryStatusEx if available.  */
292169695Skan    if ((pfnex = (PFN_MS_EX) GetProcAddress (h, "GlobalMemoryStatusEx")))
293169695Skan      {
294169695Skan	lMEMORYSTATUSEX lms_ex;
295169695Skan	lms_ex.dwLength = sizeof lms_ex;
296169695Skan	if (!pfnex (&lms_ex))
297169695Skan	  return 0.0;
298169695Skan	return (double) lms_ex.ullAvailPhys;
299169695Skan      }
300169695Skan
301169695Skan    /*  Fall back to GlobalMemoryStatus which is always available.
302169695Skan        but returns wrong results for physical memory > 4GB  */
303169695Skan    else
304169695Skan      {
305169695Skan	MEMORYSTATUS ms;
306169695Skan	GlobalMemoryStatus (&ms);
307169695Skan	return (double) ms.dwAvailPhys;
308169695Skan      }
309169695Skan  }
310169695Skan#endif
311169695Skan
312169695Skan  /* Guess 25% of physical memory.  */
313169695Skan  return physmem_total () / 4;
314169695Skan}
315169695Skan
316169695Skan
317169695Skan#if DEBUG
318169695Skan
319169695Skan# include <stdio.h>
320169695Skan# include <stdlib.h>
321169695Skan
322169695Skanint
323169695Skanmain (void)
324169695Skan{
325169695Skan  printf ("%12.f %12.f\n", physmem_total (), physmem_available ());
326169695Skan  exit (0);
327169695Skan}
328169695Skan
329169695Skan#endif /* DEBUG */
330169695Skan
331169695Skan/*
332169695SkanLocal Variables:
333169695Skancompile-command: "gcc -DDEBUG -DHAVE_CONFIG_H -I.. -g -O -Wall -W physmem.c"
334169695SkanEnd:
335169695Skan*/
336