* bug 4299 fixed - getmemory is reporting bad total memory on system
[scilab.git] / scilab / modules / core / src / c / getmemory.c
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2005 - INRIA - Allan CORNET
4  * Copyright (C) 2009 - Dan McMahill (Fix of bug 4299 and 4312)
5  * 
6  * This file must be used under the terms of the CeCILL.
7  * This source file is licensed as described in the file COPYING, which
8  * you should have received as part of this distribution.  The terms
9  * are also available at    
10  * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
11  *
12  */
13
14 /* References
15 @sa http://nixdoc.net/man-pages/Tru64/man2/getsysinfo.2.html
16 @sa http://www.opensource.apple.com/darwinsource/projects/other/gccfast-1621.1/libiberty/physmem.c
17 @sa http://lists.gnu.org/archive/html/bug-gnulib/2003-08/msg00102.html
18 @sa http://netbsd.gw.com/cgi-bin/man-cgi?sysctl+3+NetBSD-4.0
19 @sa http://cvsweb.netbsd.org/bsdweb.cgi/pkgsrc/math/scilab/patches/patch-aj?annotate=1.9
20 */
21 #include "getmemory.h"
22
23 #if defined(__NetBSD__) || defined(__DragonFly__)
24 #include <sys/param.h>
25 #include <sys/sysctl.h>
26 #define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
27 #define PAGESHIFT_UNDEF -100
28 #endif
29
30 #include <stdio.h>
31 #define kooctet 1024
32 int getfreememory(void)
33 {
34
35 #if defined(_MSC_VER)
36   {
37     MEMORYSTATUS stat;
38     GlobalMemoryStatus (&stat);
39     return (int)(stat.dwAvailPhys/kooctet);
40   }
41 #elif defined(hpux)
42  {
43    struct pst_static pst;
44   /*        pstat_getstatic(&pst, sizeof(pst), (size_t) 1, 0);
45         memorysizeKO=(pst.psd_free)/kooctet;*/
46   return 0;
47  }
48 #elif defined(__APPLE__) 
49       {
50         vm_statistics_data_t page_info;
51         vm_size_t pagesize;
52         mach_msg_type_number_t count;
53         kern_return_t kret;
54     
55         pagesize = 0;
56         kret = host_page_size (mach_host_self(), &pagesize);
57         count = HOST_VM_INFO_COUNT;
58     
59         kret = host_statistics (mach_host_self(), HOST_VM_INFO,(host_info_t)&page_info, &count);
60         return page_info.free_count*pagesize / 1024;
61       }
62 #elif HAVE_TABLE && defined TBL_VMSTATS
63    { /* This works on Tru64 UNIX V4/5.  */
64      struct tbl_vmstats vmstats;
65
66      if (table (TBL_VMSTATS, 0, &vmstats, 1, sizeof (vmstats)) == 1)
67        {
68          double pages = vmstats.free_count;
69          double pagesize = vmstats.pagesize;
70
71          if (0 <= pages && 0 <= pagesize)
72            return pages * pagesize;
73          else
74            return 0;
75        }
76    }
77 #elif defined(__linux__)
78   {
79     char field[9]  = {0};
80     long long data =  0;
81     char unit[4]   = {0};
82     
83     long long free    = -1,
84               buffers = -1,
85               cached  = -1;
86     
87     FILE *fp = fopen("/proc/meminfo", "r");
88     if(fp != NULL)
89     {
90       /* Read Cached, Buffers and MemFree from /proc/meminfo */
91       while(fscanf(fp, "%8s %lld %3s\n", field, &data, unit) != EOF)
92       {
93         if(!strncmp("MemFree:", field, 8))
94           free = data;
95         else if(!strncmp("Buffers:", field, 8))
96           buffers = data;
97         else if(!strncmp("Cached:", field, 8))
98           cached = data;
99       }
100       fclose(fp);
101       
102       /* Read successful, convert unit and return the result */
103       if(buffers >= 0 && cached >= 0 && free >= 0)
104       {
105         free += cached + buffers;
106         switch(unit[0])
107         {
108           case 'g':
109           case 'G':
110             free *= kooctet;
111           case 'm':
112           case 'M':
113             free *= kooctet;
114             break;
115           case 'o':
116           case 'O':
117             free /= kooctet;
118         }
119         return (int)free;
120       }
121     }
122     
123     /* Strange, /proc not mounted ? new and unknown format ?
124        fall back to inaccurate sysconf() */
125     return (sysconf(_SC_AVPHYS_PAGES)*sysconf(_SC_PAGESIZE))/kooctet;
126   }
127 #elif defined(__NetBSD__) || defined(__DragonFly__)
128   { /* This works on *bsd.  */
129     int mib[2];
130     struct uvmexp_sysctl uvmexp;
131     long freemem;
132     size_t lenu = sizeof uvmexp;
133     unsigned int pagesize;
134     static int pageshift = PAGESHIFT_UNDEF;
135     size_t lenp = sizeof pagesize;
136
137     mib[0] = CTL_HW;
138     if (pageshift == PAGESHIFT_UNDEF) {
139         /* Figure out the page size */
140         mib[1] = HW_PAGESIZE;
141         if (sysctl (mib, ARRAY_SIZE (mib), &pagesize, &lenp, NULL, 0) != 0 || lenp != sizeof (pagesize) ) {
142             /* sysctl failed -- what to do?? */
143             return 0;
144         }
145         pageshift = 0;
146         while (pagesize > 1) {
147             pageshift++;
148             pagesize >>= 1;
149         }
150
151         /* convert to kB */
152         pageshift -= 10;
153     }
154
155     mib[0] = CTL_VM;
156     mib[1] = VM_UVMEXP2;
157     if ( (sysctl (mib, ARRAY_SIZE (mib), &uvmexp, &lenu, NULL, 0) == 0) && (lenu == sizeof (uvmexp)) ) {
158        return  (uvmexp.free << pageshift);
159     }
160
161     return 0;
162   }
163 #else
164   /* Solaris and others assumed*/
165   return (sysconf(_SC_AVPHYS_PAGES)/kooctet)*sysconf(_SC_PAGESIZE);
166 #endif
167 }
168 /*--------------------------------------------------------------------------*/ 
169 int getmemorysize()
170 {
171 #if defined(_MSC_VER)
172   {
173     MEMORYSTATUS stat;
174     GlobalMemoryStatus (&stat);
175     return (int)(stat.dwTotalPhys/kooctet);
176   }
177 #elif defined(hpux)
178   {
179     struct pst_static pst;
180     pstat_getstatic(&pst, sizeof(pst), (size_t) 1, 0);
181     return (int)((pst.physical_memory)/kooctet);
182   }
183 #elif defined(__APPLE__) || defined(__NetBSD__) || defined(__DragonFly__)
184   { /* this works on *bsd and darwin */
185     size_t len;
186     int total;
187     int mib[2];
188
189     mib[0] = CTL_HW;
190     mib[1] = HW_PHYSMEM;
191     len = sizeof (total);
192  
193     sysctl(mib, 2, &total, &len, NULL, 0);
194     return  total/1024;
195   }
196 #elif HAVE_GETSYSINFO && defined GSI_PHYSMEM
197    { /* This works on Tru64 UNIX V4/5.  */
198      int physmem;
199
200      if (getsysinfo (GSI_PHYSMEM, (caddr_t) &physmem, sizeof (physmem),
201                     NULL, NULL, NULL) == 1)
202        {
203         double kbytes = physmem;
204
205         if (0 <= kbytes)
206           return kbytes * 1024.0;
207         else
208           return 0;
209        }
210    }
211 #else
212   /* Linux ,Solaris and others */
213   return (sysconf(_SC_PHYS_PAGES)/kooctet)*sysconf(_SC_PAGESIZE);
214 #endif
215 }
216 /*--------------------------------------------------------------------------*/