From a5fb8431d9888cbd4b40e6435d4379bf0c86cdec Mon Sep 17 00:00:00 2001 From: Lyonel Vincent Date: Thu, 20 Oct 2016 00:27:58 +0200 Subject: [PATCH 18/43] merge github pull request 23: parse CPU information FIXME: `dimminfo` magic needs cleansing, ugly code getting uglier --- src/core/device-tree.cc | 267 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 237 insertions(+), 30 deletions(-) diff --git a/src/core/device-tree.cc b/src/core/device-tree.cc index c2b7d15..700dff0 100644 --- a/src/core/device-tree.cc +++ b/src/core/device-tree.cc @@ -26,6 +26,8 @@ #include #include #include +#include +#include __ID("@(#) $Id$"); @@ -227,6 +229,42 @@ static string cpubusinfo(int cpu) } +static void set_cpu(hwNode & cpu, int currentcpu, const string & basepath) +{ + cpu.setProduct(get_string(basepath + "/name")); + cpu.claim(); + cpu.setBusInfo(cpubusinfo(currentcpu)); + + cpu.setSize(get_u32(basepath + "/clock-frequency")); + cpu.setClock(get_u32(basepath + "/bus-frequency")); + + if (exists(basepath + "/altivec")) + cpu.addCapability("altivec"); + + if (exists(basepath + "/performance-monitor")) + cpu.addCapability("performance-monitor"); +} + + +static void fill_cache_info(string cache_type, string cachebase, + hwNode & cache, hwNode & icache) +{ + cache.claim(); + cache.setDescription(cache_type); + cache.setSize(get_u32(cachebase + "/d-cache-size")); + + if (exists(cachebase + "/cache-unified")) + cache.setDescription(cache.getDescription() + " (unified)"); + else + { + icache = cache; + cache.setDescription(cache.getDescription() + " (data)"); + icache.setDescription(icache.getDescription() + " (instruction)"); + icache.setSize(get_u32(cachebase + "/i-cache-size")); + } +} + + static void scan_devtree_cpu(hwNode & core) { struct dirent **namelist; @@ -254,14 +292,8 @@ static void scan_devtree_cpu(hwNode & core) hw::strip(get_string(basepath + "/device_type")) != "cpu") break; // oops, not a CPU! - cpu.setProduct(get_string(basepath + "/name")); cpu.setDescription("CPU"); - cpu.claim(); - cpu.setBusInfo(cpubusinfo(currentcpu++)); - cpu.setSize(get_u32(basepath + "/clock-frequency")); - cpu.setClock(get_u32(basepath + "/bus-frequency")); - if (exists(basepath + "/altivec")) - cpu.addCapability("altivec"); + set_cpu(cpu, currentcpu++, basepath); version = get_u32(basepath + "/cpu-version"); if (version != 0) @@ -273,14 +305,11 @@ static void scan_devtree_cpu(hwNode & core) snprintf(buffer, sizeof(buffer), "%lx.%d.%d", (version & 0xffff0000) >> 16, major, minor); cpu.setVersion(buffer); - } + if (hw::strip(get_string(basepath + "/state")) != "running") cpu.disable(); - if (exists(basepath + "/performance-monitor")) - cpu.addCapability("performance-monitor"); - if (exists(basepath + "/d-cache-size")) { hwNode cache("cache", @@ -302,29 +331,19 @@ static void scan_devtree_cpu(hwNode & core) { hwNode cache("cache", hw::memory); + hwNode icache("cache", + hw::memory); string cachebase = basepath + "/" + cachelist[j]->d_name; if (hw::strip(get_string(cachebase + "/device_type")) != "cache" && hw::strip(get_string(cachebase + "/device_type")) != "l2-cache") break; // oops, not a cache! - cache.claim(); - cache.setDescription("L2 Cache"); - cache.setSize(get_u32(cachebase + "/d-cache-size")); - cache.setClock(get_u32(cachebase + "/clock-frequency")); + cache.setClock(get_u32(cachebase + "/clock-frequency")); + fill_cache_info("L2 Cache", cachebase, cache, icache); - if (exists(cachebase + "/cache-unified")) - cache.setDescription(cache.getDescription() + " (unified)"); - else - { - hwNode icache = cache; - cache.setDescription(cache.getDescription() + " (data)"); - icache.setDescription(icache.getDescription() + " (instruction)"); - icache.setSize(get_u32(cachebase + "/i-cache-size")); - - if (icache.getSize() > 0) - cpu.addChild(icache); - } + if (icache.getSize() > 0) + cpu.addChild(icache); if (cache.getSize() > 0) cpu.addChild(cache); @@ -342,6 +361,191 @@ static void scan_devtree_cpu(hwNode & core) } } +static void set_cpu_config_threads(hwNode & cpu, const string & basepath) +{ + static int threads_per_cpu = 0; + + /* In power systems, there are equal no. of threads per cpu-core */ + if (threads_per_cpu == 0) + { + int rc; + struct stat sbuf; + string p = hw::strip(basepath + string("/ibm,ppc-interrupt-server#s")); + + /* + * This file contains as many 32 bit interrupt server numbers, as the + * number of threads per CPU (in hexadecimal format). st_size gives size + * in bytes of a file. Hence, grouping by 4 bytes, we get the thread + * count. + */ + rc = stat(p.c_str(), &sbuf); + if (!rc) + threads_per_cpu = sbuf.st_size / 4; + } + + cpu.setConfig("threads", threads_per_cpu); +} + + +static void scan_devtree_cpu_power(hwNode & core) +{ + int n; + int currentcpu = 0; + struct dirent **namelist; + map > > l2_caches; + map > l3_caches; + + pushd(DEVICETREE "/cpus"); + n = scandir(".", &namelist, selectdir, alphasort); + popd(); + if (n < 0) + return; + + /* + * 'cpus' node contains CPU, L2 and L3 cache nodes. L1 cache information is + * available under CPU node itself. l2-cache (or next-level-cache) property + * contains next level cache node phandle/ibm,phanle number. + * First pass creates cache nodes and second pass will link cache nodes to + * corresponding CPU nodes. + */ + for (int i = 0; i < n; i++) + { + string product; + string basepath = string(DEVICETREE "/cpus/") + string(namelist[i]->d_name); + hwNode cache("cache", hw::memory); + hwNode icache("cache", hw::memory); + vector value; + + if (!exists(basepath + "/device_type")) + continue; + + if (hw::strip(get_string(basepath + "/device_type")) != "cache") + continue; + + product = hw::strip(get_string(basepath + "/name")); + + if (hw::strip(get_string(basepath + "/status")) != "okay") + cache.disable(); + + if (product == "l2-cache") + fill_cache_info("L2 Cache", basepath, cache, icache); + else + fill_cache_info("L3 Cache", basepath, cache, icache); + + if (icache.getSize() > 0) + value.insert(value.begin(), icache); + + if (cache.getSize() > 0) + value.insert(value.begin(), cache); + + if (value.size() > 0) + { + uint32_t phandle = 0; + + if (exists(basepath + "/phandle")) + phandle = get_u32(basepath + "/phandle"); + else if (exists(basepath + "/ibm,phandle")) // on pSeries LPARs + phandle = get_u32(basepath + "/ibm,phandle"); + + if (!phandle) + continue; + + if (product == "l2-cache") + { + uint32_t l3_key = 0; // 0 indicating no next level of cache + + if (exists(basepath + "/l2-cache")) + l3_key = get_u32(basepath + "/l2-cache"); + else if (exists(basepath + "/next-level-cache")) //on OpenPOWER systems + l3_key = get_u32(basepath + "/next-level-cache"); + + pair > p (l3_key, value); + l2_caches[phandle] = p; + } + else if (product == "l3-cache") + { + l3_caches[phandle] = value; + } + } + } // first pass end + + for (int i = 0; i < n; i++) //second and final pass + { + uint32_t l2_key = 0; + uint32_t version = 0; + string basepath = string(DEVICETREE "/cpus/") + string(namelist[i]->d_name); + hwNode cpu("cpu", hw::processor); + + if (!exists(basepath + "/device_type")) + { + free(namelist[i]); + continue; + } + + if (hw::strip(get_string(basepath + "/device_type")) != "cpu") + { + free(namelist[i]); + continue; + } + + cpu.setDescription("CPU"); + set_cpu(cpu, currentcpu++, basepath); + + version = get_u32(basepath + "/cpu-version"); + if (version != 0) + cpu.setVersion(tostring(version)); + + if (hw::strip(get_string(basepath + "/status")) != "okay") + cpu.disable(); + + set_cpu_config_threads(cpu, basepath); + + if (exists(basepath + "/d-cache-size")) + { + hwNode cache("cache", hw::memory); + hwNode icache("cache", hw::memory); + + fill_cache_info("L1 Cache", basepath, cache, icache); + + if (icache.getSize() > 0) + cpu.addChild(icache); + + if (cache.getSize() > 0) + cpu.addChild(cache); + } + + if (exists(basepath + "/l2-cache")) + l2_key = get_u32(basepath + "/l2-cache"); + else if (exists(basepath + "/next-level-cache")) + l2_key = get_u32(basepath + "/next-level-cache"); + + if (l2_key != 0) + { + map > >:: + const_iterator got = l2_caches.find(l2_key); + + if (!(got == l2_caches.end())) + for (uint32_t j = 0; j < (got->second).second.size(); j++) + cpu.addChild((got->second).second[j]); + + if ((got->second).first != 0) // we have another level of cache + { + map >::const_iterator got_l3 = + l3_caches.find ((got->second).first); + + if (!(got_l3 == l3_caches.end())) + for (uint32_t j = 0; j < (got_l3->second).size(); j++) + cpu.addChild((got_l3->second)[j]); + } + } + + core.addChild(cpu); + + free(namelist[i]); + } + free(namelist); +} + void add_memory_bank(string name, string path, hwNode & core) { struct dirent **dirlist; @@ -728,7 +932,7 @@ bool scan_device_tree(hwNode & n) core->addHint("icon", string("board")); scan_devtree_root(*core); scan_devtree_memory_powernv(*core); - scan_devtree_cpu(*core); + scan_devtree_cpu_power(*core); n.addCapability("powernv", "Non-virtualized"); n.addCapability("opal", "OPAL firmware"); } @@ -764,7 +968,7 @@ bool scan_device_tree(hwNode & n) { core->addHint("icon", string("board")); scan_devtree_root(*core); - scan_devtree_cpu(*core); + scan_devtree_cpu_power(*core); core->addCapability("qemu", "QEMU virtualization"); core->addCapability("guest", "Virtualization guest"); } @@ -779,7 +983,10 @@ bool scan_device_tree(hwNode & n) scan_devtree_root(*core); scan_devtree_bootrom(*core); scan_devtree_memory(*core); - scan_devtree_cpu(*core); + if (exists(DEVICETREE "/ibm,lpar-capable")) + scan_devtree_cpu_power(*core); + else + scan_devtree_cpu(*core); } } -- 2.10.2