Better getfreememory on linux
Simon Lipp [Fri, 5 Sep 2008 16:16:05 +0000 (16:16 +0000)]
scilab/modules/core/src/c/getmemory.c

index 7543f99..8a7a8cb 100644 (file)
 @sa http://nixdoc.net/man-pages/Tru64/man2/getsysinfo.2.html
 @sa http://www.opensource.apple.com/darwinsource/projects/other/gccfast-1621.1/libiberty/physmem.c
 @sa http://lists.gnu.org/archive/html/bug-gnulib/2003-08/msg00102.html
-* @TODO (Sylvestre Ledru)
-* This file needs some work because the Linux Kernel is caching many memory
-* therefor, the free memory value is pretty wrong
 */
 #include "getmemory.h"
+#include <stdio.h>
+
+#define kooctet 1024
 
 int getfreememory()
 {
-#define kooctet 1024
-#undef MEMOK
 
 #if defined(_MSC_VER)
   {
-    #define MEMOK 1
     MEMORYSTATUS stat;
     GlobalMemoryStatus (&stat);
     return (int)(stat.dwAvailPhys/kooctet);
   }
-#endif
-
-#if defined(hpux)
-#define MEMOK 1
-
+#elif defined(hpux)
  {
    struct pst_static pst;
   /*        pstat_getstatic(&pst, sizeof(pst), (size_t) 1, 0);
         memorysizeKO=(pst.psd_free)/kooctet;*/
   return 0;
  }
-
-#endif
-#if defined(__APPLE__) 
-#define MEMOK 1
+#elif defined(__APPLE__) 
       {
         vm_statistics_data_t page_info;
         vm_size_t pagesize;
@@ -60,10 +50,7 @@ int getfreememory()
         kret = host_statistics (mach_host_self(), HOST_VM_INFO,(host_info_t)&page_info, &count);
         return page_info.free_count*pagesize / 1024;
       }
-#endif
-
-#if HAVE_TABLE && defined TBL_VMSTATS
-#define MEMOK 1
+#elif HAVE_TABLE && defined TBL_VMSTATS
    { /* This works on Tru64 UNIX V4/5.  */
      struct tbl_vmstats vmstats;
 
@@ -78,41 +65,77 @@ int getfreememory()
            return 0;
        }
    }
+#elif defined(__linux__)
+  {
+    char field[9]  = {0};
+    long long data =  0;
+    char unit[4]   = {0};
+    
+    long long free    = -1,
+              buffers = -1,
+              cached  = -1;
+    
+    FILE *fp = fopen("/proc/meminfo", "r");
+    if(fp != NULL)
+    {
+      /* Read Cached, Buffers and MemFree from /proc/meminfo */
+      while(fscanf(fp, "%8s %lld %3s\n", field, &data, unit) != EOF)
+      {
+        if(!strncmp("MemFree:", field, 8))
+          free = data;
+        else if(!strncmp("Buffers:", field, 8))
+          buffers = data;
+        else if(!strncmp("Cached:", field, 8))
+          cached = data;
+      }
+      fclose(fp);
+      
+      /* Read successful, convert unit and return the result */
+      if(buffers >= 0 && cached >= 0 && free >= 0)
+      {
+        free += cached + buffers;
+        switch(unit[0])
+        {
+          case 'g':
+          case 'G':
+            free *= kooctet;
+          case 'm':
+          case 'M':
+            free *= kooctet;
+            break;
+          case 'o':
+          case 'O':
+            free /= kooctet;
+        }
+        return (int)free;
+      }
+    }
+    
+    /* Strange, /proc not mounted ? new and unknown format ?
+       fall back to inaccurate sysconf() */
+    return (sysconf(_SC_AVPHYS_PAGES)*sysconf(_SC_PAGESIZE))/kooctet;
+  }
+#else
+  /* BSD, Solaris and others assumed*/
+  return (sysconf(_SC_AVPHYS_PAGES)*sysconf(_SC_PAGESIZE))/kooctet;
 #endif
-
-#ifndef  MEMOK
-/* Linux ,Solaris and others assumed*/
-      return (sysconf(_SC_AVPHYS_PAGES)*sysconf(_SC_PAGESIZE))/kooctet;
-#endif
-
 }
 /*--------------------------------------------------------------------------*/ 
 int getmemorysize()
 {
-#define kooctet 1024
-#undef MEMOK
-
-
 #if defined(_MSC_VER)
-#define MEMOK 1
   {
     MEMORYSTATUS stat;
     GlobalMemoryStatus (&stat);
     return (int)(stat.dwTotalPhys/kooctet);
   }
-#endif
-
-#if defined(hpux)
-#define MEMOK 1
+#elif defined(hpux)
   {
     struct pst_static pst;
     pstat_getstatic(&pst, sizeof(pst), (size_t) 1, 0);
     return (int)((pst.physical_memory)/kooctet);
   }
-#endif
-
-#if defined(__APPLE__) 
-#define MEMOK 1
+#elif defined(__APPLE__) 
   {
     size_t len;
     int total;
@@ -125,10 +148,7 @@ int getmemorysize()
     sysctl(mib, 2, &total, &len, NULL, 0);
     return  total/1024;
   }
-#endif
-
-#if HAVE_GETSYSINFO && defined GSI_PHYSMEM
-#define MEMOK 1
+#elif HAVE_GETSYSINFO && defined GSI_PHYSMEM
    { /* This works on Tru64 UNIX V4/5.  */
      int physmem;
 
@@ -143,9 +163,7 @@ int getmemorysize()
           return 0;
        }
    }
-#endif
-
-#ifndef  MEMOK
+#else
   /* Linux ,Solaris and others */
   return (sysconf(_SC_PHYS_PAGES)*sysconf(_SC_PAGESIZE))/kooctet;
 #endif