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

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