xref: /dflybsd-src/contrib/binutils-2.34/libiberty/physmem.c (revision b52ef7118d1621abed722c5bbbd542210290ecef)
1*fae548d3Szrj /* Calculate the size of physical memory.
2*fae548d3Szrj    Copyright (C) 2000-2020 Free Software Foundation, Inc.
3*fae548d3Szrj 
4*fae548d3Szrj    This program is free software; you can redistribute it and/or modify
5*fae548d3Szrj    it under the terms of the GNU General Public License as published by
6*fae548d3Szrj    the Free Software Foundation; either version 2, or (at your option)
7*fae548d3Szrj    any later version.
8*fae548d3Szrj 
9*fae548d3Szrj    This program is distributed in the hope that it will be useful,
10*fae548d3Szrj    but WITHOUT ANY WARRANTY; without even the implied warranty of
11*fae548d3Szrj    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*fae548d3Szrj    GNU General Public License for more details.
13*fae548d3Szrj 
14*fae548d3Szrj    You should have received a copy of the GNU General Public License
15*fae548d3Szrj    along with this program; if not, write to the Free Software Foundation,
16*fae548d3Szrj    Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
17*fae548d3Szrj 
18*fae548d3Szrj /* Written by Paul Eggert.  */
19*fae548d3Szrj 
20*fae548d3Szrj #if HAVE_CONFIG_H
21*fae548d3Szrj # include <config.h>
22*fae548d3Szrj #endif
23*fae548d3Szrj 
24*fae548d3Szrj #if HAVE_UNISTD_H
25*fae548d3Szrj # include <unistd.h>
26*fae548d3Szrj #endif
27*fae548d3Szrj 
28*fae548d3Szrj #if HAVE_SYS_PSTAT_H
29*fae548d3Szrj # include <sys/pstat.h>
30*fae548d3Szrj #endif
31*fae548d3Szrj 
32*fae548d3Szrj #if HAVE_SYS_SYSMP_H
33*fae548d3Szrj # include <sys/sysmp.h>
34*fae548d3Szrj #endif
35*fae548d3Szrj 
36*fae548d3Szrj #if HAVE_SYS_SYSINFO_H && HAVE_MACHINE_HAL_SYSINFO_H
37*fae548d3Szrj # include <sys/sysinfo.h>
38*fae548d3Szrj # include <machine/hal_sysinfo.h>
39*fae548d3Szrj #endif
40*fae548d3Szrj 
41*fae548d3Szrj #if HAVE_SYS_TABLE_H
42*fae548d3Szrj # include <sys/table.h>
43*fae548d3Szrj #endif
44*fae548d3Szrj 
45*fae548d3Szrj #include <sys/types.h>
46*fae548d3Szrj 
47*fae548d3Szrj #if HAVE_SYS_PARAM_H
48*fae548d3Szrj # include <sys/param.h>
49*fae548d3Szrj #endif
50*fae548d3Szrj 
51*fae548d3Szrj #if HAVE_SYS_SYSCTL_H
52*fae548d3Szrj # include <sys/sysctl.h>
53*fae548d3Szrj #endif
54*fae548d3Szrj 
55*fae548d3Szrj #if HAVE_SYS_SYSTEMCFG_H
56*fae548d3Szrj # include <sys/systemcfg.h>
57*fae548d3Szrj #endif
58*fae548d3Szrj 
59*fae548d3Szrj #ifdef _WIN32
60*fae548d3Szrj # define WIN32_LEAN_AND_MEAN
61*fae548d3Szrj # include <windows.h>
62*fae548d3Szrj /*  MEMORYSTATUSEX is missing from older windows headers, so define
63*fae548d3Szrj     a local replacement.  */
64*fae548d3Szrj typedef struct
65*fae548d3Szrj {
66*fae548d3Szrj   DWORD dwLength;
67*fae548d3Szrj   DWORD dwMemoryLoad;
68*fae548d3Szrj   DWORDLONG ullTotalPhys;
69*fae548d3Szrj   DWORDLONG ullAvailPhys;
70*fae548d3Szrj   DWORDLONG ullTotalPageFile;
71*fae548d3Szrj   DWORDLONG ullAvailPageFile;
72*fae548d3Szrj   DWORDLONG ullTotalVirtual;
73*fae548d3Szrj   DWORDLONG ullAvailVirtual;
74*fae548d3Szrj   DWORDLONG ullAvailExtendedVirtual;
75*fae548d3Szrj } lMEMORYSTATUSEX;
76*fae548d3Szrj typedef WINBOOL (WINAPI *PFN_MS_EX) (lMEMORYSTATUSEX*);
77*fae548d3Szrj #endif
78*fae548d3Szrj 
79*fae548d3Szrj #include "libiberty.h"
80*fae548d3Szrj 
81*fae548d3Szrj /* Return the total amount of physical memory.  */
82*fae548d3Szrj double
physmem_total(void)83*fae548d3Szrj physmem_total (void)
84*fae548d3Szrj {
85*fae548d3Szrj #if defined _SC_PHYS_PAGES && defined _SC_PAGESIZE
86*fae548d3Szrj   { /* This works on linux-gnu, solaris2 and cygwin.  */
87*fae548d3Szrj     double pages = sysconf (_SC_PHYS_PAGES);
88*fae548d3Szrj     double pagesize = sysconf (_SC_PAGESIZE);
89*fae548d3Szrj     if (0 <= pages && 0 <= pagesize)
90*fae548d3Szrj       return pages * pagesize;
91*fae548d3Szrj   }
92*fae548d3Szrj #endif
93*fae548d3Szrj 
94*fae548d3Szrj #if HAVE_PSTAT_GETSTATIC
95*fae548d3Szrj   { /* This works on hpux11.  */
96*fae548d3Szrj     struct pst_static pss;
97*fae548d3Szrj     if (0 <= pstat_getstatic (&pss, sizeof pss, 1, 0))
98*fae548d3Szrj       {
99*fae548d3Szrj 	double pages = pss.physical_memory;
100*fae548d3Szrj 	double pagesize = pss.page_size;
101*fae548d3Szrj 	if (0 <= pages && 0 <= pagesize)
102*fae548d3Szrj 	  return pages * pagesize;
103*fae548d3Szrj       }
104*fae548d3Szrj   }
105*fae548d3Szrj #endif
106*fae548d3Szrj 
107*fae548d3Szrj #if HAVE_SYSMP && defined MP_SAGET && defined MPSA_RMINFO && defined _SC_PAGESIZE
108*fae548d3Szrj   { /* This works on irix6. */
109*fae548d3Szrj     struct rminfo realmem;
110*fae548d3Szrj     if (sysmp (MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0)
111*fae548d3Szrj       {
112*fae548d3Szrj 	double pagesize = sysconf (_SC_PAGESIZE);
113*fae548d3Szrj 	double pages = realmem.physmem;
114*fae548d3Szrj 	if (0 <= pages && 0 <= pagesize)
115*fae548d3Szrj 	  return pages * pagesize;
116*fae548d3Szrj       }
117*fae548d3Szrj   }
118*fae548d3Szrj #endif
119*fae548d3Szrj 
120*fae548d3Szrj #if HAVE_GETSYSINFO && defined GSI_PHYSMEM
121*fae548d3Szrj   { /* This works on Tru64 UNIX V4/5.  */
122*fae548d3Szrj     int physmem;
123*fae548d3Szrj 
124*fae548d3Szrj     if (getsysinfo (GSI_PHYSMEM, (caddr_t) &physmem, sizeof (physmem),
125*fae548d3Szrj 		    NULL, NULL, NULL) == 1)
126*fae548d3Szrj       {
127*fae548d3Szrj 	double kbytes = physmem;
128*fae548d3Szrj 
129*fae548d3Szrj 	if (0 <= kbytes)
130*fae548d3Szrj 	  return kbytes * 1024.0;
131*fae548d3Szrj       }
132*fae548d3Szrj   }
133*fae548d3Szrj #endif
134*fae548d3Szrj 
135*fae548d3Szrj #if HAVE_SYSCTL && defined HW_PHYSMEM
136*fae548d3Szrj   { /* This works on *bsd and darwin.  */
137*fae548d3Szrj     unsigned int physmem;
138*fae548d3Szrj     size_t len = sizeof physmem;
139*fae548d3Szrj     static int mib[2] = { CTL_HW, HW_PHYSMEM };
140*fae548d3Szrj 
141*fae548d3Szrj     if (sysctl (mib, ARRAY_SIZE (mib), &physmem, &len, NULL, 0) == 0
142*fae548d3Szrj 	&& len == sizeof (physmem))
143*fae548d3Szrj       return (double) physmem;
144*fae548d3Szrj   }
145*fae548d3Szrj #endif
146*fae548d3Szrj 
147*fae548d3Szrj #if HAVE__SYSTEM_CONFIGURATION
148*fae548d3Szrj   /* This works on AIX 4.3.3+.  */
149*fae548d3Szrj   return _system_configuration.physmem;
150*fae548d3Szrj #endif
151*fae548d3Szrj 
152*fae548d3Szrj #if defined _WIN32
153*fae548d3Szrj   { /* this works on windows */
154*fae548d3Szrj     PFN_MS_EX pfnex;
155*fae548d3Szrj     HMODULE h = GetModuleHandle ("kernel32.dll");
156*fae548d3Szrj 
157*fae548d3Szrj     if (!h)
158*fae548d3Szrj       return 0.0;
159*fae548d3Szrj 
160*fae548d3Szrj     /*  Use GlobalMemoryStatusEx if available.  */
161*fae548d3Szrj     if ((pfnex = (PFN_MS_EX) GetProcAddress (h, "GlobalMemoryStatusEx")))
162*fae548d3Szrj       {
163*fae548d3Szrj 	lMEMORYSTATUSEX lms_ex;
164*fae548d3Szrj 	lms_ex.dwLength = sizeof lms_ex;
165*fae548d3Szrj 	if (!pfnex (&lms_ex))
166*fae548d3Szrj 	  return 0.0;
167*fae548d3Szrj 	return (double) lms_ex.ullTotalPhys;
168*fae548d3Szrj       }
169*fae548d3Szrj 
170*fae548d3Szrj     /*  Fall back to GlobalMemoryStatus which is always available.
171*fae548d3Szrj         but returns wrong results for physical memory > 4GB.  */
172*fae548d3Szrj     else
173*fae548d3Szrj       {
174*fae548d3Szrj 	MEMORYSTATUS ms;
175*fae548d3Szrj 	GlobalMemoryStatus (&ms);
176*fae548d3Szrj 	return (double) ms.dwTotalPhys;
177*fae548d3Szrj       }
178*fae548d3Szrj   }
179*fae548d3Szrj #endif
180*fae548d3Szrj 
181*fae548d3Szrj   /* Return 0 if we can't determine the value.  */
182*fae548d3Szrj   return 0;
183*fae548d3Szrj }
184*fae548d3Szrj 
185*fae548d3Szrj /* Return the amount of physical memory available.  */
186*fae548d3Szrj double
physmem_available(void)187*fae548d3Szrj physmem_available (void)
188*fae548d3Szrj {
189*fae548d3Szrj #if defined _SC_AVPHYS_PAGES && defined _SC_PAGESIZE
190*fae548d3Szrj   { /* This works on linux-gnu, solaris2 and cygwin.  */
191*fae548d3Szrj     double pages = sysconf (_SC_AVPHYS_PAGES);
192*fae548d3Szrj     double pagesize = sysconf (_SC_PAGESIZE);
193*fae548d3Szrj     if (0 <= pages && 0 <= pagesize)
194*fae548d3Szrj       return pages * pagesize;
195*fae548d3Szrj   }
196*fae548d3Szrj #endif
197*fae548d3Szrj 
198*fae548d3Szrj #if HAVE_PSTAT_GETSTATIC && HAVE_PSTAT_GETDYNAMIC
199*fae548d3Szrj   { /* This works on hpux11.  */
200*fae548d3Szrj     struct pst_static pss;
201*fae548d3Szrj     struct pst_dynamic psd;
202*fae548d3Szrj     if (0 <= pstat_getstatic (&pss, sizeof pss, 1, 0)
203*fae548d3Szrj 	&& 0 <= pstat_getdynamic (&psd, sizeof psd, 1, 0))
204*fae548d3Szrj       {
205*fae548d3Szrj 	double pages = psd.psd_free;
206*fae548d3Szrj 	double pagesize = pss.page_size;
207*fae548d3Szrj 	if (0 <= pages && 0 <= pagesize)
208*fae548d3Szrj 	  return pages * pagesize;
209*fae548d3Szrj       }
210*fae548d3Szrj   }
211*fae548d3Szrj #endif
212*fae548d3Szrj 
213*fae548d3Szrj #if HAVE_SYSMP && defined MP_SAGET && defined MPSA_RMINFO && defined _SC_PAGESIZE
214*fae548d3Szrj   { /* This works on irix6. */
215*fae548d3Szrj     struct rminfo realmem;
216*fae548d3Szrj     if (sysmp (MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0)
217*fae548d3Szrj       {
218*fae548d3Szrj 	double pagesize = sysconf (_SC_PAGESIZE);
219*fae548d3Szrj 	double pages = realmem.availrmem;
220*fae548d3Szrj 	if (0 <= pages && 0 <= pagesize)
221*fae548d3Szrj 	  return pages * pagesize;
222*fae548d3Szrj       }
223*fae548d3Szrj   }
224*fae548d3Szrj #endif
225*fae548d3Szrj 
226*fae548d3Szrj #if HAVE_TABLE && defined TBL_VMSTATS
227*fae548d3Szrj   { /* This works on Tru64 UNIX V4/5.  */
228*fae548d3Szrj     struct tbl_vmstats vmstats;
229*fae548d3Szrj 
230*fae548d3Szrj     if (table (TBL_VMSTATS, 0, &vmstats, 1, sizeof (vmstats)) == 1)
231*fae548d3Szrj       {
232*fae548d3Szrj 	double pages = vmstats.free_count;
233*fae548d3Szrj 	double pagesize = vmstats.pagesize;
234*fae548d3Szrj 
235*fae548d3Szrj 	if (0 <= pages && 0 <= pagesize)
236*fae548d3Szrj 	  return pages * pagesize;
237*fae548d3Szrj       }
238*fae548d3Szrj   }
239*fae548d3Szrj #endif
240*fae548d3Szrj 
241*fae548d3Szrj #if HAVE_SYSCTL && defined HW_USERMEM
242*fae548d3Szrj   { /* This works on *bsd and darwin.  */
243*fae548d3Szrj     unsigned int usermem;
244*fae548d3Szrj     size_t len = sizeof usermem;
245*fae548d3Szrj     static int mib[2] = { CTL_HW, HW_USERMEM };
246*fae548d3Szrj 
247*fae548d3Szrj     if (sysctl (mib, ARRAY_SIZE (mib), &usermem, &len, NULL, 0) == 0
248*fae548d3Szrj 	&& len == sizeof (usermem))
249*fae548d3Szrj       return (double) usermem;
250*fae548d3Szrj   }
251*fae548d3Szrj #endif
252*fae548d3Szrj 
253*fae548d3Szrj #if defined _WIN32
254*fae548d3Szrj   { /* this works on windows */
255*fae548d3Szrj     PFN_MS_EX pfnex;
256*fae548d3Szrj     HMODULE h = GetModuleHandle ("kernel32.dll");
257*fae548d3Szrj 
258*fae548d3Szrj     if (!h)
259*fae548d3Szrj       return 0.0;
260*fae548d3Szrj 
261*fae548d3Szrj     /*  Use GlobalMemoryStatusEx if available.  */
262*fae548d3Szrj     if ((pfnex = (PFN_MS_EX) GetProcAddress (h, "GlobalMemoryStatusEx")))
263*fae548d3Szrj       {
264*fae548d3Szrj 	lMEMORYSTATUSEX lms_ex;
265*fae548d3Szrj 	lms_ex.dwLength = sizeof lms_ex;
266*fae548d3Szrj 	if (!pfnex (&lms_ex))
267*fae548d3Szrj 	  return 0.0;
268*fae548d3Szrj 	return (double) lms_ex.ullAvailPhys;
269*fae548d3Szrj       }
270*fae548d3Szrj 
271*fae548d3Szrj     /*  Fall back to GlobalMemoryStatus which is always available.
272*fae548d3Szrj         but returns wrong results for physical memory > 4GB  */
273*fae548d3Szrj     else
274*fae548d3Szrj       {
275*fae548d3Szrj 	MEMORYSTATUS ms;
276*fae548d3Szrj 	GlobalMemoryStatus (&ms);
277*fae548d3Szrj 	return (double) ms.dwAvailPhys;
278*fae548d3Szrj       }
279*fae548d3Szrj   }
280*fae548d3Szrj #endif
281*fae548d3Szrj 
282*fae548d3Szrj   /* Guess 25% of physical memory.  */
283*fae548d3Szrj   return physmem_total () / 4;
284*fae548d3Szrj }
285*fae548d3Szrj 
286*fae548d3Szrj 
287*fae548d3Szrj #if DEBUG
288*fae548d3Szrj 
289*fae548d3Szrj # include <stdio.h>
290*fae548d3Szrj # include <stdlib.h>
291*fae548d3Szrj 
292*fae548d3Szrj int
main(void)293*fae548d3Szrj main (void)
294*fae548d3Szrj {
295*fae548d3Szrj   printf ("%12.f %12.f\n", physmem_total (), physmem_available ());
296*fae548d3Szrj   exit (0);
297*fae548d3Szrj }
298*fae548d3Szrj 
299*fae548d3Szrj #endif /* DEBUG */
300*fae548d3Szrj 
301*fae548d3Szrj /*
302*fae548d3Szrj Local Variables:
303*fae548d3Szrj compile-command: "gcc -DDEBUG -DHAVE_CONFIG_H -I.. -g -O -Wall -W physmem.c"
304*fae548d3Szrj End:
305*fae548d3Szrj */
306