Improve perfmon json table picker 17/16517/2
authorDave Barach <dave@barachs.net>
Mon, 17 Dec 2018 20:55:52 +0000 (15:55 -0500)
committerFlorin Coras <florin.coras@gmail.com>
Mon, 17 Dec 2018 23:12:54 +0000 (23:12 +0000)
Built a tool to chew up https://download.01.org/perfmon/mapfile.csv,
and output a table in this format:

typedef struct {
  u8 model;
  u8 stepping;
  u8 has_stepping;
  char *filename;
} file_by_model_and_stepping_t;

static const file_by_model_and_stepping_t fms_table [] =
{
 /* model, stepping, stepping valid, file */
  { 0x2E, 0x0, 0, "NehalemEX_core_V2.json" },
  { 0x1E, 0x0, 0, "NehalemEP_core_V2.json" },
<snip>
  { 0x55, 0x5, 1, "cascadelakex_core_v1.00.json" },
  { 0x55, 0x6, 1, "cascadelakex_core_v1.00.json" },
  { 0x55, 0x7, 1, "cascadelakex_core_v1.00.json" },
<snip>

Change-Id: Ie0e8a7e851799e9d060b966047745039c066ec7b
Signed-off-by: Dave Barach <dave@barachs.net>
src/plugins/perfmon/CMakeLists.txt
src/plugins/perfmon/mapfile_tool.c [new file with mode: 0644]
src/plugins/perfmon/parse_util.c
src/plugins/perfmon/perfmon.c

index 845dd3c..340c560 100644 (file)
@@ -23,3 +23,11 @@ install(
   DESTINATION share/vpp/plugins/perfmon
   COMPONENT vpp-dev
 )
+
+option(VPP_BUILD_MAPFILE_TOOL "Build perfmon mapfile utility." OFF)
+if(VPP_BUILD_MAPFILE_TOOL)
+  add_vpp_executable(mapfile_tool
+    SOURCES mapfile_tool.c
+    LINK_LIBRARIES vppinfra Threads::Threads
+    )
+endif(VPP_BUILD_MAPFILE_TOOL)
diff --git a/src/plugins/perfmon/mapfile_tool.c b/src/plugins/perfmon/mapfile_tool.c
new file mode 100644 (file)
index 0000000..750e12b
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * mapfile_tool.c - skeleton vpp engine plug-in
+ *
+ * Copyright (c) 2018 Cisco Systems and/or affiliates
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <stdio.h>
+#include <vppinfra/format.h>
+#include <vppinfra/error.h>
+#include <vppinfra/unix.h>
+
+typedef struct
+{
+  u8 *ifile;
+  u8 *ofile;
+  u8 *mapfile;
+  u8 *table;
+  FILE *ofp;
+} mapfile_tool_main_t;
+
+mapfile_tool_main_t mapfile_tool_main;
+
+static char *top_boilerplate =
+  "typedef struct {\n"
+  "  u8 model;\n"
+  "  u8 stepping;\n"
+  "  u8 has_stepping;\n"
+  "  char *filename;\n"
+  "} file_by_model_and_stepping_t;\n\n"
+  "static const file_by_model_and_stepping_t fms_table [] =\n"
+  "{\n" " /* model, stepping, stepping valid, file */\n";
+
+static char *bottom_boilerplate = "};\n";
+
+static void
+print_chunk (mapfile_tool_main_t * mtm, char *chunk)
+{
+  fformat (mtm->ofp, "%s", chunk);
+}
+
+static int
+parse_mapfile (mapfile_tool_main_t * mtm)
+{
+  u8 *cp = mtm->mapfile;
+  int i;
+  char model[3];
+  u8 *stepping = 0;
+  u8 *filename = 0;
+  int has_stepping;
+
+  /* Skip header line */
+  while (*cp && *cp != '\n')
+    cp++;
+
+  if (*cp == 0)
+    {
+      fformat (stderr, "mapfile broken or empty\n");
+      return 1;
+    }
+  /* skip newline */
+  cp++;
+
+  /* GenuineIntel-6-55-[01234],V1.12,/SKX/skylakex_uncore_v1.12.json,uncore */
+  /*    skip 15     ^ */
+
+  /* Across payload lines... */
+  while (1)
+    {
+      if (*cp == 0)
+       return 0;
+
+      for (i = 0; i < 15; i++)
+       {
+         if (*cp == 0)
+           {
+           bad:
+             fformat (stderr, "mapfile broken\n");
+             return 1;
+           }
+         cp++;
+       }
+      /* should point at model */
+      model[0] = *cp++;
+      model[1] = *cp++;
+      model[2] = 0;
+      vec_reset_length (stepping);
+      /* Stepping significant? */
+      if (*cp == '-')
+       {
+         cp += 2;
+         while (*cp != ']')
+           {
+             vec_add1 (stepping, *cp);
+             cp++;
+           }
+         cp++;
+       }
+      /* Skip dirname */
+      while (*cp != '/')
+       cp++;
+      cp++;
+      while (*cp != '/')
+       *cp++;
+      cp++;
+      vec_reset_length (filename);
+      while (*cp != ',')
+       {
+         vec_add1 (filename, *cp);
+         cp++;
+       }
+
+      cp++;
+      /* We only want ",core" entries */
+      if (memcmp (cp, "core", 4))
+       {
+         while (*cp && *cp != '\n')
+           cp++;
+         if (*cp)
+           cp++;
+         continue;
+       }
+
+      /* Skip to start of next line */
+      while (*cp && *cp != '\n')
+       cp++;
+      if (*cp)
+       cp++;
+
+      has_stepping = 1;
+
+      if (vec_len (stepping) == 0)
+       {
+         vec_add1 (stepping, '0');
+         has_stepping = 0;
+       }
+
+      for (i = 0; i < vec_len (stepping); i++)
+       {
+         mtm->table =
+           format (mtm->table, "  { 0x%s, 0x%c, %d, \"%v\" },\n",
+                   model, stepping[i], has_stepping, filename);
+       }
+    }
+
+  /* NOTREACHED */
+  return -11;
+}
+
+static int
+mapfile_main (unformat_input_t * input, mapfile_tool_main_t * mtm)
+{
+  u8 *mapfile;
+  int rv;
+  clib_error_t *error;
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "in %s", &mtm->ifile))
+       ;
+      else if (unformat (input, "out %s", &mtm->ofile))
+       ;
+      else
+       {
+         fformat (stderr, "unknown input '%U'\n", format_unformat_error,
+                  input);
+       usage:
+         fformat (stderr, "usage: mapfile_tool in <ifile> out <ofile>\n");
+         return 1;
+       }
+    }
+
+  if (mtm->ifile == 0)
+    {
+      fformat (stderr, "input file not specified\n");
+      goto usage;
+    }
+
+  if (mtm->ofile == 0)
+    mtm->ofile = format (0, "perfmon_version.c%c", 0);
+
+  mtm->ofp = fopen ((char *) mtm->ofile, "w");
+  if (mtm->ofp == NULL)
+    {
+      fformat (stderr, "Couldn't create '%s'\n", mtm->ofile);
+      return 1;
+    }
+
+  error = unix_proc_file_contents ((char *) mtm->ifile, &mapfile);
+
+  if (error)
+    {
+      clib_error_free (error);
+      fformat (stderr, "Failed to read mapfile from %s", mtm->ifile);
+      return 1;
+    }
+
+  mtm->mapfile = mapfile;
+
+  rv = parse_mapfile (mtm);
+  if (rv)
+    return rv;
+
+  print_chunk (mtm, top_boilerplate);
+  print_chunk (mtm, (char *) mtm->table);
+  print_chunk (mtm, bottom_boilerplate);
+  return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+  unformat_input_t input;
+  mapfile_tool_main_t *mtm = &mapfile_tool_main;
+  int r;
+
+  clib_mem_init (0, 128 << 20);
+
+  unformat_init_command_line (&input, argv);
+  r = mapfile_main (&input, mtm);
+  unformat_free (&input);
+  return r;
+}
+
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
index 6abb645..8c9e9be 100644 (file)
@@ -69,7 +69,8 @@ perfmon_parse_table (perfmon_main_t * pm, char *path, char *table_name)
   if (error)
     {
       vlib_log_err (pm->log_class,
-                   "Failed to read CPU-specific counter table");
+                   "Failed to read CPU-specific counter table %s",
+                   json_filename);
       vlib_log_err (pm->log_class,
                    "Please install the vpp-dev package and then:");
       vlib_log_err
index 5bc3b73..c6a8022 100644 (file)
@@ -28,6 +28,72 @@ perfmon_main_t perfmon_main;
 
 static char *perfmon_json_path = "/usr/share/vpp/plugins/perfmon";
 
+typedef struct
+{
+  u8 model;
+  u8 stepping;
+  u8 has_stepping;
+  char *filename;
+} file_by_model_and_stepping_t;
+
+/* Created by parsing mapfile.csv, see mapfile_tool.c */
+
+static const file_by_model_and_stepping_t fms_table[] = {
+  /* model, stepping, stepping valid, file */
+  {0x2E, 0x0, 0, "NehalemEX_core_V2.json"},
+  {0x1E, 0x0, 0, "NehalemEP_core_V2.json"},
+  {0x1F, 0x0, 0, "NehalemEP_core_V2.json"},
+  {0x1A, 0x0, 0, "NehalemEP_core_V2.json"},
+  {0x2F, 0x0, 0, "WestmereEX_core_V2.json"},
+  {0x25, 0x0, 0, "WestmereEP-SP_core_V2.json"},
+  {0x2C, 0x0, 0, "WestmereEP-DP_core_V2.json"},
+  {0x37, 0x0, 0, "Silvermont_core_V14.json"},
+  {0x4D, 0x0, 0, "Silvermont_core_V14.json"},
+  {0x4C, 0x0, 0, "Silvermont_core_V14.json"},
+  {0x5C, 0x0, 0, "goldmont_core_v13.json"},
+  {0x5F, 0x0, 0, "goldmont_core_v13.json"},
+  {0x1C, 0x0, 0, "Bonnell_core_V4.json"},
+  {0x26, 0x0, 0, "Bonnell_core_V4.json"},
+  {0x27, 0x0, 0, "Bonnell_core_V4.json"},
+  {0x36, 0x0, 0, "Bonnell_core_V4.json"},
+  {0x35, 0x0, 0, "Bonnell_core_V4.json"},
+  {0x2A, 0x0, 0, "sandybridge_core_v16.json"},
+  {0x2D, 0x0, 0, "Jaketown_core_V20.json"},
+  {0x3A, 0x0, 0, "ivybridge_core_v21.json"},
+  {0x3E, 0x0, 0, "ivytown_core_v20.json"},
+  {0x3C, 0x0, 0, "haswell_core_v28.json"},
+  {0x45, 0x0, 0, "haswell_core_v28.json"},
+  {0x46, 0x0, 0, "haswell_core_v28.json"},
+  {0x3F, 0x0, 0, "haswellx_core_v20.json"},
+  {0x3D, 0x0, 0, "broadwell_core_v23.json"},
+  {0x47, 0x0, 0, "broadwell_core_v23.json"},
+  {0x4F, 0x0, 0, "broadwellx_core_v14.json"},
+  {0x56, 0x0, 0, "broadwellde_core_v7.json"},
+  {0x4E, 0x0, 0, "skylake_core_v42.json"},
+  {0x5E, 0x0, 0, "skylake_core_v42.json"},
+  {0x8E, 0x0, 0, "skylake_core_v42.json"},
+  {0x9E, 0x0, 0, "skylake_core_v42.json"},
+  {0x57, 0x0, 0, "KnightsLanding_core_V9.json"},
+  {0x85, 0x0, 0, "KnightsLanding_core_V9.json"},
+  {0x55, 0x0, 1, "skylakex_core_v1.12.json"},
+  {0x55, 0x1, 1, "skylakex_core_v1.12.json"},
+  {0x55, 0x2, 1, "skylakex_core_v1.12.json"},
+  {0x55, 0x3, 1, "skylakex_core_v1.12.json"},
+  {0x55, 0x4, 1, "skylakex_core_v1.12.json"},
+  {0x55, 0x5, 1, "cascadelakex_core_v1.00.json"},
+  {0x55, 0x6, 1, "cascadelakex_core_v1.00.json"},
+  {0x55, 0x7, 1, "cascadelakex_core_v1.00.json"},
+  {0x55, 0x8, 1, "cascadelakex_core_v1.00.json"},
+  {0x55, 0x9, 1, "cascadelakex_core_v1.00.json"},
+  {0x55, 0xA, 1, "cascadelakex_core_v1.00.json"},
+  {0x55, 0xB, 1, "cascadelakex_core_v1.00.json"},
+  {0x55, 0xC, 1, "cascadelakex_core_v1.00.json"},
+  {0x55, 0xD, 1, "cascadelakex_core_v1.00.json"},
+  {0x55, 0xE, 1, "cascadelakex_core_v1.00.json"},
+  {0x55, 0xF, 1, "cascadelakex_core_v1.00.json"},
+  {0x7A, 0x0, 0, "goldmontplus_core_v1.01.json"},
+};
+
 static void
 set_perfmon_json_path ()
 {
@@ -58,15 +124,6 @@ set_perfmon_json_path ()
   perfmon_json_path = (char *) s;
 }
 
-#define foreach_cpuid_table                     \
-_(0x0106E5, NehalemEP_core_V2.json)     /* Intel(R) Xeon(R) CPU X3430  @ 2.40GHz     */        \
-_(0x0306C3, haswell_core_v28.json)      /* Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz   */        \
-_(0x0306F2, haswell_core_v28.json)      /* Intel(R) Xeon(R) CPU E5-2640 v3 @ 2.60GHz */        \
-_(0x040661, haswell_core_v28.json)      /* Intel(R) Core(TM) i7-4870HQ CPU @ 2.50GHz */        \
-_(0x0406D8, Silvermont_core_V14.json)   /* Intel(R) Atom(TM) CPU  C2758  @ 2.40GHz   */        \
-_(0x0406E3, skylake_core_v42.json)      /* Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz  */        \
-_(0x0506E3, skylake_core_v42.json)     /* Intel(R) Core(TM) i5-6600 CPU @ 3.30GHz   */
-
 static inline u32
 get_cpuid (void)
 {
@@ -88,6 +145,8 @@ perfmon_init (vlib_main_t * vm)
   u32 cpuid;
   uword *ht;
   int found_a_table = 0;
+  int i;
+  u8 model, stepping;
 
   pm->vlib_main = vm;
   pm->vnet_main = vnet_get_main ();
@@ -110,23 +169,32 @@ perfmon_init (vlib_main_t * vm)
 
   cpuid = get_cpuid ();
 
-  if (0)
+  for (i = 0; i < ARRAY_LEN (fms_table); i++)
     {
-    }
-#define _(id,table)                                             \
-  else if (cpuid == id)                                         \
-    {                                                           \
-      vlib_log_debug (pm->log_class, "Found table %s", #table); \
-      ht = perfmon_parse_table (pm, perfmon_json_path, #table); \
-      found_a_table = 1;                                        \
-    }
-  foreach_cpuid_table;
-#undef _
+      model = ((cpuid >> 12) & 0xf0) | ((cpuid >> 4) & 0xf);
+      stepping = cpuid & 0xf;
+
+      if (fms_table[i].model != model)
+       continue;
+
+      if (fms_table[i].has_stepping)
+       {
+         if (fms_table[i].stepping != stepping)
+           continue;
+       }
 
+      found_a_table = 1;
+      ht = perfmon_parse_table (pm, perfmon_json_path, fms_table[i].filename);
+      break;
+    }
   pm->perfmon_table = ht;
 
-  if (found_a_table == 0)
-    vlib_log_err (pm->log_class, "No table for cpuid %x", cpuid);
+  if (found_a_table == 0 || pm->perfmon_table == 0 || hash_elts (ht) == 0)
+    {
+      vlib_log_err (pm->log_class, "No table for cpuid %x", cpuid);
+      vlib_log_err (pm->log_class, "  model %x, stepping %x",
+                   model, stepping);
+    }
 
   return error;
 }