nouveau/mme: Add some generic builder tests
authorFaith Ekstrand <faith.ekstrand@collabora.com>
Tue, 31 Jan 2023 02:12:06 +0000 (20:12 -0600)
committerMarge Bot <emma+marge@anholt.net>
Fri, 4 Aug 2023 21:32:03 +0000 (21:32 +0000)
These don't need hardware and instead run entirely in the simulator.
The goal is to have something that we can run in CI and which ensures
consistency between the Turing and Fermi MMEs.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24326>

src/nouveau/mme/meson.build
src/nouveau/mme/tests/mme_builder_test.cpp [new file with mode: 0644]
src/nouveau/mme/tests/mme_runner.cpp
src/nouveau/mme/tests/mme_runner.h

index f0db473..74f853b 100644 (file)
@@ -109,6 +109,24 @@ idep_nouveau_mme = declare_dependency(
 )
 
 if with_tests and not with_platform_android
+  test('mme_builder',
+    executable(
+      'mme_builder_test',
+      files('tests/mme_runner.cpp', 'tests/mme_builder_test.cpp'),
+      gnu_symbol_visibility : 'hidden',
+      include_directories : [inc_include, inc_src],
+      dependencies : [
+        dep_libdrm,
+        idep_gtest,
+        idep_mesautil,
+        idep_nvidia_headers,
+        idep_nouveau_mme,
+        idep_nouveau_ws
+      ],
+    ),
+    suite : ['nouveau'],
+  )
+
   executable(
     'mme_fermi_sim_hw_test',
     files('tests/mme_runner.cpp', 'tests/mme_fermi_sim_hw_test.cpp'),
diff --git a/src/nouveau/mme/tests/mme_builder_test.cpp b/src/nouveau/mme/tests/mme_builder_test.cpp
new file mode 100644 (file)
index 0000000..48d720f
--- /dev/null
@@ -0,0 +1,179 @@
+#include "mme_runner.h"
+#include "mme_tu104_sim.h"
+
+#include <vector>
+
+#include "nvk_clc597.h"
+
+class mme_builder_test : public ::testing::Test {
+public:
+   mme_builder_test();
+   ~mme_builder_test();
+
+   std::vector<mme_runner *> sims;
+   uint32_t expected[DATA_DWORDS];
+
+private:
+   mme_fermi_sim_runner fermi_sim;
+   mme_tu104_sim_runner tu104_sim;
+};
+
+#define DATA_ADDR 0xc0ffee00
+
+mme_builder_test::mme_builder_test() :
+   fermi_sim(DATA_ADDR),
+   tu104_sim(DATA_ADDR)
+{
+   memset(expected, 0, sizeof(expected));
+   sims.push_back(&fermi_sim);
+   sims.push_back(&tu104_sim);
+}
+
+mme_builder_test::~mme_builder_test()
+{ }
+
+#define ASSERT_SIM_DATA(sim) do {               \
+   for (uint32_t i = 0; i < DATA_DWORDS; i++)   \
+      ASSERT_EQ((sim)->data[i], expected[i]);   \
+} while (0)
+
+TEST_F(mme_builder_test, sanity)
+{
+   const uint32_t canary = 0xc0ffee01;
+
+   expected[0] = canary;
+
+   for (auto sim : sims) {
+      mme_builder b;
+      mme_builder_init(&b, sim->devinfo);
+
+      sim->mme_store_data(&b, 0, mme_imm(canary));
+
+      auto macro = mme_builder_finish_vec(&b);
+
+      std::vector<uint32_t> params;
+      sim->run_macro(macro, params);
+      ASSERT_SIM_DATA(sim);
+   }
+}
+
+static uint32_t
+merge(uint32_t x, uint32_t y,
+      uint16_t dst_pos, uint16_t bits, uint16_t src_pos)
+{
+   x &= ~(BITFIELD_MASK(bits) << dst_pos);
+   y &= (BITFIELD_MASK(bits) << src_pos);
+   return x | ((y >> src_pos) << dst_pos);
+}
+
+static const uint32_t add_cases[] = {
+   0x00000001,
+   0xffffffff,
+   0x0000ffff,
+   0x00008000,
+   0x0001ffff,
+   0xffff8000,
+   0x00010000,
+   0x00020000,
+   0xfffc0000,
+   0xfffe0000,
+};
+
+TEST_F(mme_builder_test, add)
+{
+   for (auto sim : sims) {
+      mme_builder b;
+      mme_builder_init(&b, sim->devinfo);
+
+      mme_value x = mme_load(&b);
+      mme_value y = mme_load(&b);
+
+      sim->mme_store_data(&b, 0, mme_add(&b, x, y));
+
+      auto macro = mme_builder_finish_vec(&b);
+
+      for (uint32_t i = 0; i < ARRAY_SIZE(add_cases); i++) {
+         for (uint32_t j = 0; j < ARRAY_SIZE(add_cases); j++) {
+            std::vector<uint32_t> params;
+            params.push_back(add_cases[i]);
+            params.push_back(add_cases[j]);
+
+            sim->run_macro(macro, params);
+            ASSERT_EQ(sim->data[0], add_cases[i] + add_cases[j]);
+         }
+      }
+   }
+}
+
+TEST_F(mme_builder_test, add_imm)
+{
+   for (auto sim : sims) {
+      mme_builder b;
+      mme_builder_init(&b, sim->devinfo);
+
+      mme_value x = mme_load(&b);
+
+      for (uint32_t j = 0; j < ARRAY_SIZE(add_cases); j++) {
+         mme_value y = mme_imm(add_cases[j]);
+         sim->mme_store_data(&b, j, mme_add(&b, x, y), true);
+      }
+
+      auto macro = mme_builder_finish_vec(&b);
+
+      for (uint32_t i = 0; i < ARRAY_SIZE(add_cases); i++) {
+         std::vector<uint32_t> params;
+         params.push_back(add_cases[i]);
+
+         sim->run_macro(macro, params);
+
+         for (uint32_t j = 0; j < ARRAY_SIZE(add_cases); j++)
+            ASSERT_EQ(sim->data[j], add_cases[i] + add_cases[j]);
+      }
+   }
+}
+
+TEST_F(mme_builder_test, merge)
+{
+   static const struct {
+      uint16_t dst_pos;
+      uint16_t bits;
+      uint16_t src_pos;
+   } cases[] = {
+      { 12, 12, 20 },
+      { 12, 8,  20 },
+      { 8,  12, 20 },
+      { 12, 16, 8 },
+      { 24, 12, 8 },
+   };
+
+   static const uint32_t x = 0x0c406fe0;
+   static const uint32_t y = 0x76543210;
+
+   for (uint32_t i = 0; i < ARRAY_SIZE(cases); i++) {
+      expected[i] = merge(x, y, cases[i].dst_pos,
+                          cases[i].bits, cases[i].src_pos);
+   }
+
+   for (auto sim : sims) {
+      mme_builder b;
+      mme_builder_init(&b, sim->devinfo);
+
+      mme_value xv = mme_load(&b);
+      mme_value yv = mme_load(&b);
+
+      for (uint32_t i = 0; i < ARRAY_SIZE(cases); i++) {
+         mme_value mv = mme_merge(&b, xv, yv, cases[i].dst_pos,
+                                  cases[i].bits, cases[i].src_pos);
+         sim->mme_store_data(&b, i, mv, true);
+      }
+
+      auto macro = mme_builder_finish_vec(&b);
+
+      std::vector<uint32_t> params;
+      params.push_back(x);
+      params.push_back(y);
+
+      sim->run_macro(macro, params);
+      ASSERT_SIM_DATA(sim);
+   }
+}
index 542c769..440d8a1 100644 (file)
@@ -7,6 +7,8 @@
 #include "mme_fermi_sim.h"
 #include "mme_tu104_sim.h"
 
+#include "nvk_clc597.h"
+
 #include "nouveau_bo.h"
 #include "nouveau_context.h"
 
@@ -29,6 +31,13 @@ mme_hw_runner::mme_hw_runner() :
    memset(&push, 0, sizeof(push));
 }
 
+void
+mme_runner::mme_store_data(mme_builder *b, uint32_t dw_idx,
+                           mme_value data, bool free_reg)
+{
+   mme_store_imm_addr(b, data_addr + dw_idx * 4, data, free_reg);
+}
+
 mme_hw_runner::~mme_hw_runner()
 {
    if (push_bo) {
@@ -178,3 +187,69 @@ mme_hw_runner::run_macro(const std::vector<uint32_t>& macro,
 
    submit_push();
 }
+
+mme_fermi_sim_runner::mme_fermi_sim_runner(uint64_t data_addr)
+{
+   memset(&info, 0, sizeof(info));
+   info.cls_eng3d = FERMI_A;
+
+   memset(data_store, 0, sizeof(data_store));
+
+   this->devinfo = &info;
+   this->data_addr = data_addr,
+   this->data = data_store;
+}
+
+mme_fermi_sim_runner::~mme_fermi_sim_runner()
+{ }
+
+void
+mme_fermi_sim_runner::run_macro(const std::vector<uint32_t>& macro,
+                                const std::vector<uint32_t>& params)
+{
+   std::vector<mme_fermi_inst> insts(macro.size());
+   mme_fermi_decode(&insts[0], &macro[0], macro.size());
+
+   /* First, make a copy of the data and simulate the macro */
+   mme_fermi_sim_mem sim_mem = {
+      .addr = data_addr,
+      .data = data,
+      .size = DATA_BO_SIZE,
+   };
+   mme_fermi_sim(insts.size(), &insts[0],
+                 params.size(), &params[0],
+                 1, &sim_mem);
+}
+
+mme_tu104_sim_runner::mme_tu104_sim_runner(uint64_t data_addr)
+{
+   memset(&info, 0, sizeof(info));
+   info.cls_eng3d = TURING_A;
+
+   memset(data_store, 0, sizeof(data_store));
+
+   this->devinfo = &info;
+   this->data_addr = data_addr,
+   this->data = data_store;
+}
+
+mme_tu104_sim_runner::~mme_tu104_sim_runner()
+{ }
+
+void
+mme_tu104_sim_runner::run_macro(const std::vector<uint32_t>& macro,
+                               const std::vector<uint32_t>& params)
+{
+   std::vector<mme_tu104_inst> insts(macro.size());
+   mme_tu104_decode(&insts[0], &macro[0], macro.size());
+
+   /* First, make a copy of the data and simulate the macro */
+   mme_tu104_sim_mem sim_mem = {
+      .addr = data_addr,
+      .data = data,
+      .size = DATA_BO_SIZE,
+   };
+   mme_tu104_sim(insts.size(), &insts[0],
+                 params.size(), &params[0],
+                 1, &sim_mem);
+}
index 8f3cbd5..d57dda6 100644 (file)
@@ -11,6 +11,7 @@ struct nouveau_ws_device;
 #include "nvk_cl9097.h"
 
 #define DATA_BO_SIZE 4096
+#define DATA_DWORDS 1024
 
 class mme_runner {
 public:
@@ -20,6 +21,9 @@ public:
    virtual void run_macro(const std::vector<uint32_t>& macro,
                           const std::vector<uint32_t>& params) = 0;
 
+   void mme_store_data(mme_builder *b, uint32_t dw_idx,
+                       mme_value data, bool free_reg = false);
+
    const nv_device_info *devinfo;
    uint64_t data_addr;
    uint32_t *data;
@@ -49,6 +53,32 @@ private:
    struct nv_push push;
 };
 
+class mme_fermi_sim_runner : public mme_runner {
+public:
+   mme_fermi_sim_runner(uint64_t data_addr);
+   virtual ~mme_fermi_sim_runner();
+
+   virtual void run_macro(const std::vector<uint32_t>& macro,
+                          const std::vector<uint32_t>& params);
+
+private:
+   struct nv_device_info info;
+   uint32_t data_store[DATA_DWORDS];
+};
+
+class mme_tu104_sim_runner : public mme_runner {
+public:
+   mme_tu104_sim_runner(uint64_t data_addr);
+   virtual ~mme_tu104_sim_runner();
+
+   virtual void run_macro(const std::vector<uint32_t>& macro,
+                          const std::vector<uint32_t>& params);
+
+private:
+   struct nv_device_info info;
+   uint32_t data_store[DATA_DWORDS];
+};
+
 inline std::vector<uint32_t>
 mme_builder_finish_vec(mme_builder *b)
 {