/ src / core / mem.cc
mem.cc
  1  /*
  2   * mem.cc
  3   *
  4   * This scan tries to guess the size of system memory by looking at several
  5   * sources:
  6   * - the size of /proc/kcore
  7   * - the value returned by the sysconf libc function
  8   * - the sum of sizes of kernel hotplug memory blocks
  9   * - the sum of sizes of individual memory banks
 10   *
 11   * NOTE: In the first two cases this guess can be widely inaccurate, as the
 12   * kernel itself limits the memory addressable by userspace processes.
 13   * Because of that, this module reports the biggest value found if it can't
 14   * access the size of individual memory banks (information filled in by other
 15   * scans like DMI (on PCs) or OpenFirmare device-tree (on Macs).
 16   *
 17   */
 18  
 19  #include "version.h"
 20  #include "config.h"
 21  #include "sysfs.h"
 22  #include "mem.h"
 23  #include <sys/types.h>
 24  #include <sys/stat.h>
 25  #include <fcntl.h>
 26  #include <unistd.h>
 27  
 28  __ID("@(#) $Id$");
 29  
 30  static unsigned long long get_kcore_size()
 31  {
 32    struct stat buf;
 33  
 34    if (stat("/proc/kcore", &buf) != 0)
 35      return 0;
 36    else
 37      return buf.st_size;
 38  }
 39  
 40  
 41  static unsigned long long get_sysconf_size()
 42  {
 43    long pagesize = 0;
 44    long physpages = 0;
 45    unsigned long long logicalmem = 0;
 46  
 47    pagesize = sysconf(_SC_PAGESIZE);
 48    physpages = sysconf(_SC_PHYS_PAGES);
 49    if ((pagesize > 0) && (physpages > 0))
 50      logicalmem =
 51        (unsigned long long) pagesize *(unsigned long long) physpages;
 52  
 53    return logicalmem;
 54  }
 55  
 56  
 57  static unsigned long long get_hotplug_size()
 58  {
 59    vector < sysfs::entry > entries = sysfs::entries_by_bus("memory");
 60  
 61    if (entries.empty())
 62      return 0;
 63  
 64    unsigned long long memblocksize =
 65      sysfs::entry::byPath("/system/memory").hex_attr("block_size_bytes");
 66    if (memblocksize == 0)
 67      return 0;
 68  
 69    unsigned long long totalsize = 0;
 70    for (vector < sysfs::entry >::iterator it = entries.begin();
 71        it != entries.end(); ++it)
 72    {
 73      const sysfs::entry & e = *it;
 74      if (e.string_attr("online") != "1")
 75        continue;
 76      totalsize += memblocksize;
 77    }
 78    return totalsize;
 79  }
 80  
 81  
 82  static unsigned long long count_memorybanks_size(hwNode & n)
 83  {
 84    hwNode *memory = n.getChild("core/memory");
 85  
 86    if (memory)
 87    {
 88      unsigned long long size = 0;
 89  
 90      memory->claim(true);                          // claim memory and all its children
 91  
 92      for (unsigned int i = 0; i < memory->countChildren(); i++)
 93        if (memory->getChild(i)->getClass() == hw::memory)
 94          size += memory->getChild(i)->getSize();
 95  
 96      memory->setSize(size);
 97      return size;
 98    }
 99    else
100      return 0;
101  }
102  
103  
104  static void claim_memory(hwNode & n)
105  {
106    hwNode *core = n.getChild("core");
107  
108    if (core)
109    {
110      for (unsigned int i = 0; i < core->countChildren(); i++)
111        if (core->getChild(i)->getClass() == hw::memory)
112          if(core->getChild(i)->claimed())
113            core->getChild(i)->claim(true);         // claim memory and all its children
114    }
115  }
116  
117  
118  bool scan_memory(hwNode & n)
119  {
120    hwNode *memory = n.getChild("core/memory");
121    unsigned long long logicalmem = 0;
122    unsigned long long kcore = 0;
123    unsigned long long hotplug_size = 0;
124  
125    logicalmem = get_sysconf_size();
126    kcore = get_kcore_size();
127    hotplug_size = get_hotplug_size();
128    count_memorybanks_size(n);
129    claim_memory(n);
130  
131    if (!memory)
132    {
133      hwNode *core = n.getChild("core");
134  
135      if (!core)
136      {
137        n.addChild(hwNode("core", hw::bus));
138        core = n.getChild("core");
139      }
140  
141      if (core)
142      {
143        core->addChild(hwNode("memory", hw::memory));
144        memory = core->getChild("memory");
145      }
146    }
147  
148    if (memory)
149    {
150      memory->claim();
151      memory->addHint("icon", string("memory"));
152  
153      if (memory->getDescription() == "")
154        memory->setDescription(_("System memory"));
155  
156      if (memory->getSize() > logicalmem)           // we already have a value
157        return true;
158  
159      if (hotplug_size > logicalmem)
160        memory->setSize(hotplug_size);
161      else if ((logicalmem == 0)
162        || ((kcore > logicalmem) && (kcore < 2 * logicalmem)))
163        memory->setSize(kcore);
164      else
165        memory->setSize(logicalmem);
166  
167      return true;
168    }
169  
170    return false;
171  }