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 }