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