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

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