]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
s390: Autodetect cache info. These are the final bits to fix BZ 275800.
authorFlorian Krohm <florian@eich-krohm.de>
Fri, 2 Nov 2012 22:00:59 +0000 (22:00 +0000)
committerFlorian Krohm <florian@eich-krohm.de>
Fri, 2 Nov 2012 22:00:59 +0000 (22:00 +0000)
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@13100

NEWS
README.s390
coregrind/m_cache.c

diff --git a/NEWS b/NEWS
index 825f77e8ab68e040a63a311aa18f5f1a1ce3d717..76c414077235043f1271766ac4e9793216400fb3 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -33,6 +33,7 @@ m = merged into 3_8_BRANCH
 252955    [390] Impossible to compile with ccache
 274695    [390] s390x: Support "compare to/from logical" instructions (z196)
 275800    [390] s390x: Add support for the ecag instruction (part 1)
+275800    [390] s390x: Autodetect cache info (part 2)
 305948    [390] ppc64: code generation for ShlD64 / ShrD64 asserts
 306054    [390] s390x: Condition code computation for convert-to-int/logical
 307155    [390] filter_gdb should filter out syscall-template.S T_PSEUDO
index c16782bd363a1ee231e957921a9cbef459780a32..28e7f1f0581abe1ee1ad76f5f61c5bebd011f236 100644 (file)
@@ -11,10 +11,12 @@ Limitations
 - 31-bit client programs are not supported.
 - Hexadecimal floating point is not supported.
 - Decimal floating point is not supported yet.
-- Currently, only memcheck, massif, lackey, and none are supported
+- memcheck, massif, lackey, and none are supported.
+- cachegrind is supported on z10 and newer models. On older models,
+  a z10 cache architecture will be assumed.
+- callgrind and all experimental tools are currently not supported.
 - helgrind and drd seem to work on SLES10,11 and RHEL5,6 on z9,z10 and z196
   but might fail on other hardware/software combinations.
-- exp-sgcheck, cachegrind, and callgrind are currently not supported.
 - Some gcc versions use mvc to copy 4/8 byte values. This will affect some
   debug messages. Valgrind will complain about 4 or 8 one-byte reads/writes
   instead of just 1 read/write.
index 41ef04a51925c445d7c0fc50f0ed3e43a34586c9..117c6db2f6e3421b739112c54d3b2a9a43a466f0 100644 (file)
@@ -551,12 +551,114 @@ get_cache_info(VexArchInfo *vai)
 
 #elif defined(VGA_s390x)
 
+static ULong
+ecag(UInt ai, UInt li, UInt ti)
+{
+   register ULong result asm("2") = 0;
+   register ULong input  asm("3") = (ai << 4) | (li << 1) | ti;
+
+   asm volatile(".short 0xeb20\n\t"
+                ".long  0x3000004c\n\t"
+                 : "=d" (result) : "d" (input));
+
+   return result;
+}
+
+static UInt
+get_cache_info_for_level(ULong topology, UInt level)
+{
+   return (topology >> (56 - level * 8)) & 0xff;
+}
+
+static ULong
+get_line_size(UInt level, Bool is_insn_cache)
+{
+   return ecag(1, level, is_insn_cache);
+}
+
+static ULong
+get_total_size(UInt level, Bool is_insn_cache)
+{
+   return ecag(2, level, is_insn_cache);
+}
+
+static ULong
+get_associativity(UInt level, Bool is_insn_cache)
+{
+   return ecag(3, level, is_insn_cache);
+}
+
+static VexCache
+get_cache(UInt level, VexCacheKind kind)
+{
+   Bool is_insn_cache = kind == INSN_CACHE;
+   UInt size = get_total_size(level, is_insn_cache);
+   UInt line_size = get_line_size(level, is_insn_cache);
+   UInt assoc = get_associativity(level, is_insn_cache);
+
+   return VEX_CACHE_INIT(kind, level + 1, size, line_size, assoc);
+}
+
 static Bool
 get_cache_info(VexArchInfo *vai)
 {
-   vai->hwcache_info.icaches_maintain_coherence = True;
+   VexCacheInfo *ci = &vai->hwcache_info;
 
-   return False;   // not yet
+   ci->icaches_maintain_coherence = True;
+
+   if (! vai->hwcaps & VEX_HWCAPS_S390X_GIE) {
+      // ECAG is not available
+      return False;
+   }
+
+   UInt level, cache_kind, info, i;
+   ULong topology = ecag(0, 0, 0);   // get summary
+
+   /* ECAG supports at most 8 levels of cache. Find out how many levels
+      of cache and how many caches there are. */
+   ci->num_levels = 0;
+   ci->num_caches = 0;
+   for (level = 0; level < 8; level++) {
+      info = get_cache_info_for_level(topology, level);
+
+      if ((info & 0xc) == 0) break;  // cache does not exist at this level
+      ++ci->num_levels;
+
+      cache_kind = info & 0x3;
+      switch (cache_kind) {
+      case 0:  ci->num_caches += 2; break; /* separate data and insn cache */
+      case 1:  ci->num_caches += 1; break; /* only insn cache */
+      case 2:  ci->num_caches += 1; break; /* only data cache */
+      case 3:  ci->num_caches += 1; break; /* unified data and insn cache */
+      }
+   }
+
+   ci->caches = VG_(malloc)("m_cache", ci->num_caches * sizeof *ci->caches);
+
+   i = 0;
+   for (level = 0; level < ci->num_levels; level++) {
+      info = get_cache_info_for_level(topology, level);
+      cache_kind = info & 0x3;
+      switch (cache_kind) {
+      case 0:   /* separate data and insn cache */
+         ci->caches[i++] = get_cache(level, INSN_CACHE);
+         ci->caches[i++] = get_cache(level, DATA_CACHE);
+         break;
+
+      case 1:   /* only insn cache */
+         ci->caches[i++] = get_cache(level, INSN_CACHE);
+         break;
+
+      case 2:   /* only data cache */
+         ci->caches[i++] = get_cache(level, DATA_CACHE);
+         break;
+
+      case 3:   /* unified data and insn cache */
+         ci->caches[i++] = get_cache(level, UNIFIED_CACHE);
+         break;
+      }
+   }
+   return True;
 }
 
 #else