physmem.c 7.1 KB

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