jcsyshc 3 лет назад
Сommit
aeb908e683

+ 19 - 0
CMakeLists.txt

@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 3.0)
+
+set(PROJECT_NAME Sophiar2)
+set(CMAKE_CXX_STANDARD 20)
+
+project(${PROJECT_NAME})
+
+include_directories(./src)
+
+find_package(Boost REQUIRED)
+include_directories(${Boost_INCLUDE_DIRS})
+
+file(GLOB_RECURSE SRC_FILES ./src/*.cpp)
+add_executable(${PROJECT_NAME} ${SRC_FILES})
+
+find_package(benchmark REQUIRED)
+
+add_executable(benchmark_small_obj benchmark/small_obj/main.cpp)
+target_link_libraries(benchmark_small_obj benchmark::benchmark)

+ 39 - 0
benchmark/small_obj/main.cpp

@@ -0,0 +1,39 @@
+#include "core/small_obj.hpp"
+
+#include <benchmark/benchmark.h>
+
+#include <memory>
+
+template<size_t length>
+static void BM_std_shared_ptr(benchmark::State &state) {
+    struct test_type {
+        double data[length];
+    };
+    for (auto _: state) {
+        benchmark::DoNotOptimize(std::make_shared<test_type>());
+    }
+}
+
+BENCHMARK(BM_std_shared_ptr<0>);
+BENCHMARK(BM_std_shared_ptr<1>);
+BENCHMARK(BM_std_shared_ptr<8>);
+BENCHMARK(BM_std_shared_ptr<128>);
+BENCHMARK(BM_std_shared_ptr<1024>);
+
+template<size_t length>
+static void BM_small_obj(benchmark::State &state) {
+    struct test_type : public sophiar::small_obj<test_type> {
+        double data[length];
+    };
+    for (auto _: state) {
+        benchmark::DoNotOptimize(test_type::new_instance());
+    }
+}
+
+BENCHMARK(BM_small_obj<0>);
+BENCHMARK(BM_small_obj<1>);
+BENCHMARK(BM_small_obj<8>);
+BENCHMARK(BM_small_obj<128>);
+BENCHMARK(BM_small_obj<1024>);
+
+BENCHMARK_MAIN();

+ 32 - 0
src/core/datanode_base.hpp

@@ -0,0 +1,32 @@
+#ifndef SOPHIAR2_DATANODE_BASE_HPP
+#define SOPHIAR2_DATANODE_BASE_HPP
+
+#include "core/small_obj.hpp"
+#include "core/timestamp_helper.hpp"
+
+#include <boost/logic/tribool.hpp>
+
+namespace sophiar {
+
+//    template<typename T>
+//    concept DataNode_Impl = requires(T a) {
+//        { a.exec() } -> std::convertible_to<boost::tribool>;
+//    };
+
+    struct data_packet : small_obj<data_packet> {
+
+        static const size_t DATA_PACKET_LENGTH = 14;
+
+        uint32_t user_data;
+        uint64_t timestamp;
+        double data[DATA_PACKET_LENGTH];
+
+        void make_timestamp_current() {
+            timestamp = current_timestamp();
+        }
+
+    };
+
+}
+
+#endif //SOPHIAR2_DATANODE_BASE_HPP

+ 50 - 0
src/core/small_obj.hpp

@@ -0,0 +1,50 @@
+#ifndef SOPHIAR2_SMALL_OBJ_H
+#define SOPHIAR2_SMALL_OBJ_H
+
+#include <boost/pool/object_pool.hpp>
+#include <boost/smart_ptr/intrusive_ptr.hpp>
+
+#include <memory>
+#include <type_traits>
+
+namespace sophiar {
+
+    template<typename DeriveT>
+    struct small_obj_ref_counter {
+        uint32_t ref_count = 0;
+    };
+
+    template<typename DeriveT>
+    void intrusive_ptr_add_ref(small_obj_ref_counter<DeriveT> *pointer) {
+        ++pointer->ref_count;
+    }
+
+    template<typename DeriveT>
+    void intrusive_ptr_release(small_obj_ref_counter<DeriveT> *pointer) {
+        if (--pointer->ref_count == 0) {
+            DeriveT::allocator.destroy(static_cast<DeriveT *>(pointer));
+        }
+    }
+
+    template<typename DeriveT>
+    struct small_obj : public small_obj_ref_counter<DeriveT> {
+
+        using pointer = boost::intrusive_ptr<DeriveT>;
+        using allocator_type = boost::object_pool<DeriveT>;
+
+        static allocator_type allocator;
+
+        template<typename... Args>
+        std::enable_if_t<std::is_constructible_v<DeriveT, Args...>, pointer>
+        static new_instance(Args &&... args) {
+            return allocator.construct();
+        }
+
+    };
+
+    template<typename DeriveT>
+    typename small_obj<DeriveT>::allocator_type small_obj<DeriveT>::allocator{};
+
+}
+
+#endif //SOPHIAR2_SMALL_OBJ_H

+ 21 - 0
src/core/timestamp_helper.hpp

@@ -0,0 +1,21 @@
+#ifndef SOPHIAR2_TIMESTAMP_HELPER_HPP
+#define SOPHIAR2_TIMESTAMP_HELPER_HPP
+
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+namespace sophiar {
+
+    auto get_local_time() {
+        return boost::posix_time::microsec_clock::local_time();
+    }
+
+    static const auto program_start_time = get_local_time();
+
+    auto current_timestamp() {
+        auto time_diff = get_local_time() - program_start_time;
+        return time_diff.total_microseconds();
+    }
+
+}
+
+#endif //SOPHIAR2_TIMESTAMP_HELPER_HPP

+ 152 - 0
src/core/tristate_obj.h

@@ -0,0 +1,152 @@
+#ifndef SOPHIAR2_TRISTATE_OBJ_H
+#define SOPHIAR2_TRISTATE_OBJ_H
+
+#include <boost/logic/tribool.hpp>
+
+namespace sophiar {
+
+//    template<typename T>
+//    concept Tristate_Impl = requires(T a) {
+//        { a.on_init() } -> std::convertible_to<boost::tribool>;
+//        { a.on_start() } -> std::convertible_to<boost::tribool>;
+//        a.on_stop();
+//        a.on_reset();
+//    };
+
+    template<typename DeriveT>
+    class tristate_obj {
+    public:
+
+        using state_type = uint8_t;
+        static const state_type ST_INITIAL = 0;
+        static const state_type ST_INITIALIZING = 1;
+        static const state_type ST_PENDING = 2;
+        static const state_type ST_STARING = 3;
+        static const state_type ST_RUNNING = 4;
+
+        state_type state = ST_INITIAL;
+
+        boost::tribool init() {
+            if (state == ST_INITIAL) {
+                auto ret_val = get_real_ptr()->on_init();
+                if (ret_val == false) {
+                    get_real_ptr()->on_reset();
+                    return false;
+                }
+                if (ret_val == true) {
+                    state = ST_PENDING;
+                    call_after_init();
+                } else {
+                    state = ST_INITIALIZING;
+                }
+                return ret_val;
+            }
+            if (state == ST_INITIALIZING) {
+                return boost::indeterminate;
+            }
+            return true;
+        }
+
+        boost::tribool start() {
+            if (state < ST_PENDING) {
+                return false;
+            }
+            if (state == ST_PENDING) {
+                auto ret_val = get_real_ptr()->on_start();
+                if (ret_val == false) {
+                    get_real_ptr()->on_stop();
+                    return false;
+                }
+                if (ret_val == true) {
+                    state = ST_RUNNING;
+                    call_after_start();
+                } else {
+                    state = ST_STARING;
+                }
+                return ret_val;
+            }
+            if (state == ST_STARING) {
+                return boost::indeterminate;
+            }
+            return true;
+        }
+
+        void stop() {
+            if (state < ST_STARING) return;
+            get_real_ptr()->on_stop();
+            auto old_state = state;
+            state = ST_PENDING;
+            if (old_state == ST_RUNNING) {
+                call_after_stop();
+            }
+        }
+
+        void reset() {
+            if (state == ST_INITIAL) return;
+            if (state > ST_PENDING) {
+                stop();
+            }
+            get_real_ptr()->on_reset();
+            auto old_state = state;
+            state = ST_INITIAL;
+            if (old_state == ST_PENDING) {
+                call_after_reset();
+            }
+        }
+
+    protected:
+
+        void init_finished(bool flag = true) {
+            if (state != ST_INITIALIZING) return;
+            if (flag) {
+                state = ST_PENDING;
+                call_after_init();
+            } else {
+                get_real_ptr()->on_reset();
+                state = ST_INITIAL;
+            }
+        }
+
+        void start_finished(bool flag = true) {
+            if (state != ST_STARING) return;
+            if (flag) {
+                state = ST_RUNNING;
+                call_after_start();
+            } else {
+                get_real_ptr()->on_stop();
+                state = ST_PENDING;
+            }
+        }
+
+    private:
+
+        auto get_real_ptr() {
+            return static_cast<DeriveT *>(this);
+        }
+
+#define CHECK_AND_CALL_AFTER(cmd, old_state) \
+        void call_after_##cmd() { \
+            if constexpr(requires(DeriveT a) { \
+                a.after_##cmd(); \
+            }) { \
+                get_real_ptr()->after_##cmd(); \
+            } \
+            if constexpr(requires(DeriveT a) { \
+                a.ater_state_change(state_type{}); \
+            }) { \
+                get_real_ptr()->after_state_change(old_state); \
+            } \
+        }
+
+        CHECK_AND_CALL_AFTER(init, ST_INITIAL)
+        CHECK_AND_CALL_AFTER(start, ST_PENDING)
+        CHECK_AND_CALL_AFTER(stop, ST_RUNNING)
+        CHECK_AND_CALL_AFTER(reset, ST_PENDING)
+
+#undef CHECK_AND_CALL_AFTER
+
+    };
+
+}
+
+#endif //SOPHIAR2_TRISTATE_OBJ_H

+ 28 - 0
src/main.cpp

@@ -0,0 +1,28 @@
+#include <iostream>
+
+#include "core/small_obj.hpp"
+#include "core/tristate_obj.h"
+#include "core/datanode_base.hpp"
+
+struct test_impl : public sophiar::tristate_obj<test_impl> {
+    bool on_init() { return true; }
+
+    bool on_start() { return true; }
+
+    void on_stop() {}
+
+    void on_reset() {}
+};
+
+auto func() {
+    auto ret = sophiar::data_packet::new_instance();
+    ret->make_timestamp_current();
+    return ret;
+}
+
+int main() {
+    test_impl a;
+    a.init();
+    a.start();
+    std::cout << (int) a.state << std::endl;
+}