Blame SOURCES/0018-merge-github-pull-request-23-parse-CPU-information.patch

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