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