Просмотр исходного кода

暂时搁置 datanode_base 的测试

jcsyshc 3 лет назад
Родитель
Сommit
33ee6135c5

+ 17 - 15
src/core/datanode_base.cpp

@@ -107,19 +107,21 @@ namespace sophiar {
             get_manager().register_slot<>(q_this, "trigger", *trigger_slot);
         }
 
-        void create_input_slot(const std::string &name) {
+        uint8_t create_input_slot(const std::string &name) {
             assert(input_total + 1 <= MAX_CHANNEL_CNT);
             auto slot_index = input_total++;
             auto update_slot = new update_slot_impl_type;
             update_slot->p_this = this;
             update_slot->channel_index = slot_index;
             get_manager().register_slot<data_pointer_type>(q_this, name, *update_slot);
+            return slot_index;
         }
 
-        void create_output_signal(const std::string &name) {
+        uint8_t create_output_signal(const std::string &name) {
             assert(output_total + 1 <= MAX_CHANNEL_CNT);
             auto signal_index = output_total++;
             get_manager().register_signal(q_this, name, output_signal[signal_index]);
+            return signal_index;
         }
 
         void load_start_config(const nlohmann::json &config) {
@@ -288,12 +290,12 @@ namespace sophiar {
             co_return ret_val;
         }
 
-        bool cancel_pending() {
-            if (exec_state != exec_state_type::PENDING) return false;
-            if (trigger_mode == trigger_mode_type::PERIODIC) return false;
-            exec_cancel_signal.try_notify_all();
-            return true;
-        }
+//        bool cancel_pending() {
+//            if (exec_state != exec_state_type::PENDING) return false;
+//            if (trigger_mode == trigger_mode_type::PERIODIC) return false;
+//            exec_cancel_signal.try_notify_all();
+//            return true;
+//        }
 
     };
 
@@ -314,17 +316,17 @@ namespace sophiar {
         pimpl->create_trigger_slot();
     }
 
-    void datanode_base::register_input(const std::string &name) {
-        pimpl->create_input_slot(name);
+    uint8_t datanode_base::register_input(const std::string &name) {
+        return pimpl->create_input_slot(name);
     }
 
-    void datanode_base::register_output(const std::string &name) {
-        pimpl->create_output_signal(name);
+    uint8_t datanode_base::register_output(const std::string &name) {
+        return pimpl->create_output_signal(name);
     }
 
-    bool datanode_base::cancel_pending() {
-        return pimpl->cancel_pending();
-    }
+//    bool datanode_base::cancel_pending() {
+//        return pimpl->cancel_pending();
+//    }
 
     datanode_base::data_pointer_type
     datanode_base::get_input_data(uint8_t channel_index) {

+ 3 - 3
src/core/datanode_base.h

@@ -52,13 +52,13 @@ namespace sophiar {
 
 //        std::string get_statistic_info_as_string() const;
 
-        bool cancel_pending();
+//        bool cancel_pending();
 
     protected: // for child class to use
 
-        void register_input(const std::string &name);
+        uint8_t register_input(const std::string &name);
 
-        void register_output(const std::string &name);
+        uint8_t register_output(const std::string &name);
 
         data_pointer_type get_input_data(uint8_t channel_index);
 

+ 16 - 1
src/core/sophiar_manager.cpp

@@ -455,7 +455,6 @@ namespace sophiar {
             auto tristate_ptr = dynamic_cast<tristate_obj *>(obj_ptr);
             if (tristate_ptr == nullptr) return; // not tristate obj
 
-            auto current_ts = current_timestamp();
             assert(config.contains("init_configs"));
             assert(config["init_configs"].is_array());
             for (auto &config_json: config["init_configs"]) {
@@ -615,6 +614,22 @@ namespace sophiar {
         pimpl->on_object_stopped(obj);
     }
 
+#ifdef SOPHIAR_TEST
+
+    sophiar_obj *sophiar_manager::get_object(const std::string &obj_name) const {
+        if (!pimpl->obj_pool.contains(obj_name)) return nullptr;
+        return pimpl->obj_pool[obj_name].ptr;
+    }
+
+    tiny_slot_base *sophiar_manager::get_slot_impl(const std::string &obj_name,
+                                                   const std::string &slot_name) {
+        auto slot_uri = pimpl->get_slot_uri(obj_name, slot_name);
+        assert(pimpl->slot_pool.contains(slot_uri));
+        return pimpl->slot_pool[slot_uri].direct_slot;
+    }
+
+#endif // SOPHIAR_TEST
+
     sophiar_manager::~sophiar_manager() = default;
 
 }

+ 23 - 0
src/core/sophiar_manager.h

@@ -62,6 +62,29 @@ namespace sophiar {
 
         ~sophiar_manager();
 
+#ifdef SOPHIAR_TEST // for test unit only
+
+    public:
+
+        sophiar_obj *get_object(const std::string &obj_name) const;
+
+        template<typename ...Args>
+        typename tiny_signal<Args...>::slot_type &get_slot(const std::string &obj_name,
+                                                           const std::string &slot_name) {
+            using ret_type = typename tiny_signal<Args...>::slot_type;
+            auto slot_base = get_slot_impl(obj_name, slot_name);
+            auto slot_ptr = dynamic_cast<ret_type *>(slot_base);
+            assert(slot_ptr != nullptr);
+            return *slot_ptr;
+        }
+
+    private:
+
+        tiny_slot_base *get_slot_impl(const std::string &obj_name,
+                                      const std::string &slot_name);
+
+#endif // SOPHIAR_TEST
+
     private:
 
         struct impl;

+ 2 - 1
tests/CMakeLists.txt

@@ -3,7 +3,7 @@ find_package (Boost REQUIRED COMPONENTS unit_test_framework)
 include_directories (${Boost_INCLUDE_DIRS})
 
 add_executable (test_core
-        #        core/datanode_base.cpp
+        core/datanode_base.cpp
         core/geometry_types.cpp
         core/small_obj.cpp
         core/sophiar_manager.cpp
@@ -11,4 +11,5 @@ add_executable (test_core
         core/tristate_obj.cpp
         ${EXTERN_DEF_FILES}
         ${CORE_IMPL_FILES})
+target_compile_definitions(test_core PUBLIC SOPHIAR_TEST)
 target_link_libraries (test_core ${Boost_LIBRARIES} ${EXTRA_LIBS})

+ 213 - 123
tests/core/datanode_base.cpp

@@ -15,6 +15,7 @@
 
 #include <algorithm>
 #include <chrono>
+#include <fstream>
 #include <iostream>
 
 using boost::asio::awaitable;
@@ -25,162 +26,251 @@ using boost::asio::use_awaitable;
 using namespace sophiar;
 using namespace std::chrono_literals;
 
-awaitable<void> test_datanode_base_1() {
+struct cnt_node_type : public datanode_base {
+    DEFAULT_NEW_INSTANCE(cnt_node_type);
 
-    struct type_a : public datanode_base<high_freq_tag> {
-        unsigned int cnt = 0;
+    unsigned int cnt = 0;
 
-        awaitable<bool> exec() {
-            ++cnt;
-            co_return true;
-        }
-    } node_a;
+    void load_construct_config(const nlohmann::json &config) override {
+        auto input_index = register_input("input_1");
+        BOOST_TEST(input_index == 0);
+        datanode_base::load_construct_config(config);
+    }
 
-    BOOST_TEST(co_await node_a.init());
-    BOOST_TEST(node_a.set_trigger_mode(type_a::trigger_mode_type::MANUAL));
-    BOOST_TEST(co_await node_a.start());
-    BOOST_TEST(co_await node_a.trigger());
-    BOOST_TEST(node_a.cnt == 1);
+    awaitable<bool> exec() {
+        ++cnt;
+        co_return true;
+    }
+};
 
-    co_await coro_sleep(50ms);
-    node_a.set_minimal_exec_interval(10ms);
-    for (int i = 0; i < 5; ++i) {
-        co_spawn(co_await boost::asio::this_coro::executor, node_a.trigger(), detached);
+struct trigger_node_type : public sophiar_obj {
+    DEFAULT_NEW_INSTANCE(trigger_node_type);
+
+    tiny_signal<> trigger_signal;
+
+    void load_construct_config(const nlohmann::json &config) override {
+        get_manager().register_signal(this, "triggered", trigger_signal);
     }
-    BOOST_TEST(node_a.cnt == 2);
-    co_await coro_sleep(50ms);
-    BOOST_TEST(node_a.cnt == 3);
 
-    node_a.cnt = 0;
+    void trigger() {
+        trigger_signal.emit();
+    }
+};
+
+struct update_node_type : public sophiar_obj {
+    DEFAULT_NEW_INSTANCE(update_node_type);
+
+    tiny_signal<versatile_obj::pointer> trigger_signal;
+
+    void load_construct_config(const nlohmann::json &config) override {
+        get_manager().register_signal(this, "triggered", trigger_signal);
+    }
+
+    void trigger() {
+        trigger_signal.emit(versatile_obj::new_instance());
+    }
+};
+
+struct test_node_type : public datanode_base {
+    DEFAULT_NEW_INSTANCE(test_node_type);
+
+    unsigned int cnt = 0;
+
+    void load_construct_config(const nlohmann::json &config) override {
+        auto input_index = register_input("input_1");
+        BOOST_TEST(input_index == 0);
+        auto output_index = register_output("output_1");
+        BOOST_TEST(output_index == 0);
+        datanode_base::load_construct_config(config);
+    }
+
+    awaitable<bool> exec() {
+        auto input_data = get_input_data(0);
+        cnt = (*input_data)[0];
+        auto output_data = versatile_obj::new_instance();
+        output_data->copy_from(*input_data);
+        (*output_data)[0] += 1.0;
+        set_output_data(0, output_data);
+        co_return true;
+    }
+};
+
+struct speedtest_node_type : public datanode_base {
+    uint64_t cnt = 0;
+
+    void load_construct_config(const nlohmann::json &config) override {
+        auto input_index = register_input("input_1");
+        BOOST_TEST(input_index == 0);
+        auto output_index = register_output("output_1");
+        BOOST_TEST(output_index == 0);
+        datanode_base::load_construct_config(config);
+    }
+
+    awaitable<bool> exec() {
+        auto input_data = get_input_data(0);
+        auto output_data = versatile_obj::new_instance();
+        output_data->copy_from(*input_data);
+        for (size_t i = 0; i < versatile_data::FLOAT_FILED_LENGTH; ++i) {
+            (*output_data)[i] += i;
+        }
+        std::reverse(output_data->floats, output_data->floats + versatile_data::FLOAT_FILED_LENGTH);
+        output_data->timestamp = current_timestamp();
+        cnt = (*output_data)[0];
+        set_output_data(0, output_data);
+        co_return true;
+    }
+};
+
+awaitable<void> test_datanode_base_1() {
+
+    auto trigger_node = dynamic_cast<trigger_node_type *>(global_sophiar_manager.get_object("trigger_node"));
+    auto cnt_node = dynamic_cast<cnt_node_type *>(global_sophiar_manager.get_object("cnt_node"));
+    assert(trigger_node != nullptr);
+    assert(cnt_node != nullptr);
+
+    co_await global_sophiar_manager.switch_mode("mode_a");
+
+    trigger_node->trigger();
+    co_await coro_sleep(10ms);
+    BOOST_TEST(cnt_node->cnt == 1);
+
     co_await coro_sleep(50ms);
-    node_a.set_minimal_exec_interval(10ms);
     for (int i = 0; i < 5; ++i) {
-        co_spawn(co_await boost::asio::this_coro::executor, node_a.trigger(), detached);
+        trigger_node->trigger();
     }
-    BOOST_TEST(node_a.cancel_pending());
-    BOOST_TEST(node_a.cnt == 1);
+    BOOST_TEST(cnt_node->cnt == 2);
     co_await coro_sleep(50ms);
-    BOOST_TEST(node_a.cnt == 1);
-    co_await node_a.stop();
+    BOOST_TEST(cnt_node->cnt == 3);
 
-    node_a.cnt = 0;
-    BOOST_TEST(node_a.set_trigger_mode(type_a::trigger_mode_type::INPUT));
-    node_a.set_trigger_input_mask(1);
-    BOOST_TEST(co_await node_a.start());
-    node_a.update_input_data(0, type_a::data_packet::new_instance());
-    BOOST_TEST(node_a.cnt == 1);
+    co_await global_sophiar_manager.switch_mode("mode_b");
+
+    auto update_node = dynamic_cast<update_node_type *>(global_sophiar_manager.get_object("update_node"));
+    assert(update_node != nullptr);
+
+    cnt_node->cnt = 0;
+    update_node->trigger();
+    co_await coro_sleep(10ms);
+    BOOST_TEST(cnt_node->cnt == 1);
 
     co_await coro_sleep(50ms);
     for (int i = 0; i < 5; ++i) {
-        node_a.update_input_data(0, type_a::data_packet::new_instance());
+        update_node->trigger();
     }
-    BOOST_TEST(node_a.cnt == 2);
+    BOOST_TEST(cnt_node->cnt == 2);
     co_await coro_sleep(50ms);
-    BOOST_TEST(node_a.cnt == 3);
-    co_await node_a.stop();
+    BOOST_TEST(cnt_node->cnt == 3);
 
-    node_a.cnt = 0;
-    BOOST_TEST(node_a.set_trigger_mode(type_a::trigger_mode_type::PERIODIC));
-    node_a.set_trigger_interval(50ms);
+    cnt_node->cnt = 0;
     co_spawn(co_await boost::asio::this_coro::executor, [&]() -> awaitable<void> {
         co_await coro_sleep(275ms);
-        co_await node_a.stop();
+        co_await cnt_node->stop();
     }, detached);
-    co_await node_a.start();
+
+    co_await global_sophiar_manager.switch_mode("mode_c");
     co_await coro_sleep(350ms);
-    BOOST_TEST(node_a.cnt == 6);
-    BOOST_TEST((node_a.get_state() == type_a::state_type::PENDING));
+    BOOST_TEST(cnt_node->cnt == 6);
+    BOOST_TEST((cnt_node->get_state() == datanode_base::state_type::PENDING));
 
-}
+    auto test_node_a = dynamic_cast<test_node_type *>(global_sophiar_manager.get_object("test_node_a"));
+    auto test_node_b = dynamic_cast<test_node_type *>(global_sophiar_manager.get_object("test_node_b"));
+    assert(test_node_a != nullptr);
+    assert(test_node_b != nullptr);
 
-awaitable<void> test_datanode_base_2() {
-    struct test_type : public datanode_base<high_freq_tag> {
-        unsigned int cnt = 0;
-
-        awaitable<bool> exec() {
-            auto input_data = get_input_data(0);
-            cnt = (*input_data)[0];
-            auto output_data = data_packet::new_instance();
-            output_data->copy_content(*input_data);
-            (*output_data)[0] += 1.0;
-            set_output_data(0, output_data);
-            co_return true;
-        }
-    };
-
-    test_type node_a, node_b;
-    test_type::connect(node_a, 0, node_b, 0);
-    co_await node_a.init();
-    co_await node_b.init();
-    node_a.set_trigger_mode(test_type::trigger_mode_type::INPUT);
-    node_b.set_trigger_mode(test_type::trigger_mode_type::INPUT);
-    node_a.set_trigger_input_mask(0b1);
-    node_b.set_trigger_input_mask(0b1);
-    co_await node_a.start();
-    co_await node_b.start();
-    auto packet = test_type::data_packet::new_instance();
-    (*packet)[0] = 101;
-    node_a.update_input_data(0, packet);
-    BOOST_TEST(node_a.cnt == 101);
-    BOOST_TEST(node_b.cnt == 102);
+    auto &test_slot = global_sophiar_manager.get_slot<versatile_obj::pointer>("test_node_a", "input_1");
+
+    co_await global_sophiar_manager.switch_mode("mode_d");
+    auto packet = versatile_obj::new_instance();
+    (*packet)[0] = 100;
+    test_slot.signal_received(std::move(packet));
+    BOOST_TEST(test_node_a->cnt == 100);
+    BOOST_TEST(test_node_b->cnt == 101);
+
+    co_return;
 }
 
 awaitable<void> test_datanode_base_speed(size_t length, size_t repeat) {
-    struct test_type : public datanode_base<high_freq_tag> {
-        uint64_t cnt = 0;
-
-        awaitable<bool> exec() {
-            auto input_data = get_input_data(0);
-            auto output_data = data_packet::new_instance();
-            output_data->copy_content(*input_data);
-            for (size_t i = 0; i < test_type::data_packet::FLOAT_FILED_LENGTH; ++i) {
-                (*output_data)[i] += i;
-            }
-            std::reverse(output_data->floats, output_data->floats + test_type::data_packet::FLOAT_FILED_LENGTH);
-            output_data->timestamp = current_timestamp();
-            cnt = (*output_data)[0];
-            set_output_data(0, output_data);
-            co_return true;
-        }
-    };
-
-    auto pool = new test_type[length];
-    for (size_t i = 0; i < length; ++i) {
-        auto &node = pool[i];
-        co_await node.init();
-        node.set_trigger_mode(test_type::trigger_mode_type::INPUT);
-        node.set_trigger_input_mask(0b1);
-        if (i != 0) {
-            test_type::connect(pool[i - 1], 0, node, 0);
-        }
-        co_await node.start();
-    }
 
-    auto test_data = test_type::data_packet::new_instance();
-    auto start_ts = current_timestamp();
-    for (int i = 0; i < repeat; ++i) {
-        pool[0].update_input_data(0, test_data);
-//        assert(pool[length - 1].cnt == length);
+    std::destroy_at(&global_sophiar_manager);
+    std::construct_at(&global_sophiar_manager);
+
+    nlohmann::json config_json;
+    config_json["mode_list"].push_back({{"name", "test_mode"}});
+
+    nlohmann::json object_config;
+    object_config["type"] = "speedtest_node_type";
+    object_config["enabled_modes"].push_back("test_mode");
+    object_config["construct_config"] = nlohmann::json({});
+    object_config["init_configs"] = nlohmann::json::array();
+
+    nlohmann::json start_config;
+    start_config["modes"].push_back("test_mode");
+    start_config["config"]["trigger_mode"] = "input";
+    start_config["config"]["input_mask"] = 1;
+    object_config["start_configs"].push_back(start_config);
+
+    for (auto i = 0; i < length; ++i) {
+        object_config["name"] = fmt::format("speedtest_node_{}", i);
+        config_json["object_list"].push_back(object_config);
     }
 
-    auto time_used = (current_timestamp() - start_ts) / 1000.0;
-    auto time_left = 1000.0 / repeat - time_used / repeat;
-    std::cout << fmt::format("Length = {}, Repeat = {}, "
-                             "Time used = {:.3f}ms ({:.3f}ms, {:.2f}% left)",
-                             length, repeat, time_used,
-                             time_left, time_left / (10.0 / repeat))
-              << std::endl;
+    std::cout << config_json.dump() << std::endl;
 
-    BOOST_TEST(true);
+    // TODO
+//
+//    auto pool = new test_type[length];
+//    for (size_t i = 0; i < length; ++i) {
+//        auto &node = pool[i];
+//        co_await node.init();
+//        node.set_trigger_mode(test_type::trigger_mode_type::INPUT);
+//        node.set_trigger_input_mask(0b1);
+//        if (i != 0) {
+//            test_type::connect(pool[i - 1], 0, node, 0);
+//        }
+//        co_await node.start();
+//    }
+//
+//    auto test_data = test_type::data_packet::new_instance();
+//    auto start_ts = current_timestamp();
+//    for (int i = 0; i < repeat; ++i) {
+//        pool[0].update_input_data(0, test_data);
+////        assert(pool[length - 1].cnt == length);
+//    }
+//
+//    auto time_used = (current_timestamp() - start_ts) / 1000.0;
+//    auto time_left = 1000.0 / repeat - time_used / repeat;
+//    std::cout << fmt::format("Length = {}, Repeat = {}, "
+//                             "Time used = {:.3f}ms ({:.3f}ms, {:.2f}% left)",
+//                             length, repeat, time_used,
+//                             time_left, time_left / (10.0 / repeat))
+//              << std::endl;
+//
+//    BOOST_TEST(true);
+    co_return;
 }
 
 BOOST_AUTO_TEST_CASE(test_datanode_base) {
-//    co_spawn(high_freq_context, test_datanode_base_1(), detached);
+
+    spdlog::set_level(spdlog::level::trace);
+
+    REGISTER_TYPE(cnt_node_type);
+    REGISTER_TYPE(trigger_node_type);
+    REGISTER_TYPE(update_node_type);
+    REGISTER_TYPE(test_node_type);
+
+    std::ifstream config_file("data/datanode_base_config.json");
+    BOOST_TEST(config_file.is_open());
+
+    global_sophiar_manager.build_from_config(nlohmann::json::parse(config_file));
+
+    co_spawn(global_context, test_datanode_base_1(), detached);
 //    co_spawn(high_freq_context, test_datanode_base_2(), detached);
-//    high_freq_context.run();
-    for (auto length: {1, 4, 16, 64, 128})
-        for (auto repeat: {1, 50, 125, 500, 1000, 2000, 5000, 10000})
-            co_spawn(high_freq_context, test_datanode_base_speed(length, repeat), detached);
-    high_freq_context.run();
+//    for (auto length: {1, 4, 16, 64, 128})
+//        for (auto repeat: {1, 50, 125, 500, 1000, 2000, 5000, 10000})
+//            co_spawn(high_freq_context, test_datanode_base_speed(length, repeat), detached);
+    global_context.run();
 }
 
+BOOST_AUTO_TEST_CASE(test_datanode_speed) {
+    co_spawn(global_context, test_datanode_base_speed(3, 1), detached);
+    global_context.run();
+}

+ 155 - 0
tests/data/datanode_base_config.json

@@ -0,0 +1,155 @@
+{
+  "mode_list": [
+    {
+      "name": "mode_a"
+    },
+    {
+      "name": "mode_b"
+    },
+    {
+      "name": "mode_c"
+    },
+    {
+      "name": "mode_d"
+    }
+  ],
+  "object_list": [
+    {
+      "type": "trigger_node_type",
+      "name": "trigger_node",
+      "enabled_modes": "all",
+      "construct_config": {}
+    },
+    {
+      "type": "update_node_type",
+      "name": "update_node",
+      "enabled_modes": [
+        "mode_b"
+      ],
+      "construct_config": {}
+    },
+    {
+      "type": "cnt_node_type",
+      "name": "cnt_node",
+      "enabled_modes": [
+        "mode_a",
+        "mode_b",
+        "mode_c"
+      ],
+      "construct_config": {},
+      "init_configs": [],
+      "start_configs": [
+        {
+          "modes": [
+            "mode_a"
+          ],
+          "config": {
+            "trigger_mode": "manual",
+            "minimal_exec_interval_ms": 10
+          }
+        },
+        {
+          "modes": [
+            "mode_b"
+          ],
+          "config": {
+            "trigger_mode": "input",
+            "input_mask": 1,
+            "minimal_exec_interval_ms": 10
+          }
+        },
+        {
+          "modes": [
+            "mode_c"
+          ],
+          "config": {
+            "trigger_mode": "periodic",
+            "exec_interval_ms": 50
+          }
+        }
+      ]
+    },
+    {
+      "type": "test_node_type",
+      "name": "test_node_a",
+      "enabled_modes": [
+        "mode_d"
+      ],
+      "construct_config": {},
+      "init_configs": [],
+      "start_configs": [
+        {
+          "modes": [
+            "mode_d"
+          ],
+          "config": {
+            "trigger_mode": "input",
+            "input_mask": 1
+          }
+        }
+      ]
+    },
+    {
+      "type": "test_node_type",
+      "name": "test_node_b",
+      "enabled_modes": [
+        "mode_d"
+      ],
+      "construct_config": {},
+      "init_configs": [],
+      "start_configs": [
+        {
+          "modes": [
+            "mode_d"
+          ],
+          "config": {
+            "trigger_mode": "input",
+            "input_mask": 1
+          }
+        }
+      ]
+    }
+  ],
+  "connection_list": [
+    {
+      "modes": [
+        "mode_a",
+        "mode_b"
+      ],
+      "connections": [
+        {
+          "signal_object": "trigger_node",
+          "signal_name": "triggered",
+          "slot_object": "cnt_node",
+          "slot_name": "trigger"
+        }
+      ]
+    },
+    {
+      "modes": [
+        "mode_b"
+      ],
+      "connections": [
+        {
+          "signal_object": "update_node",
+          "signal_name": "triggered",
+          "slot_object": "cnt_node",
+          "slot_name": "input_1"
+        }
+      ]
+    },
+    {
+      "modes": [
+        "mode_d"
+      ],
+      "connections": [
+        {
+          "signal_object": "test_node_a",
+          "signal_name": "output_1",
+          "slot_object": "test_node_b",
+          "slot_name": "input_1"
+        }
+      ]
+    }
+  ]
+}