variable_utility2.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. #include "core/basic_obj_types.hpp"
  2. #include "core/global_defs.h"
  3. #include "core/sophiar_pool.h"
  4. #include "core/timestamp_helper.hpp"
  5. #include "core/tristate_obj.h"
  6. #include "utility/config_utility.hpp"
  7. #include "utility/versatile_buffer2.hpp"
  8. #include <spdlog/spdlog.h>
  9. #include <fstream>
  10. #include <vector>
  11. using boost::asio::awaitable;
  12. namespace sophiar {
  13. class multi_variable_utility_base : public tristate_obj {
  14. public:
  15. awaitable<void> on_stop() noexcept override {
  16. for (auto cb: cb_pool) {
  17. UNREGISTER_CALLBACK(cb);
  18. }
  19. cb_pool.clear();
  20. co_return;
  21. }
  22. protected:
  23. void register_variables(const nlohmann::json &config) {
  24. if (config.contains("variable_name_list")) {
  25. ENSURE_ARRAY("variable_name_list");
  26. for (auto &item: config["variable_name_list"]) {
  27. assert(item.is_string());
  28. auto var_name = item.get<std::string>();
  29. cb_pool.push_back(create_callback(var_name));
  30. }
  31. } else {
  32. auto var_name = LOAD_STRING_ITEM("variable_name");
  33. cb_pool.push_back(create_callback(var_name));
  34. }
  35. }
  36. virtual sophiar_pool::callback_token_type create_callback(const std::string &var_name) = 0;
  37. private:
  38. std::vector<sophiar_pool::callback_token_type> cb_pool;
  39. };
  40. class variable_debug_watcher : public multi_variable_utility_base {
  41. public:
  42. DEFAULT_NEW_INSTANCE(variable_debug_watcher)
  43. protected:
  44. awaitable<bool> on_start(const nlohmann::json &config) noexcept override {
  45. min_interval = TRY_LOAD_FLOAT_ITEM("minimum_interval_ms", 0) * 1000; // ms -> us
  46. register_variables(config);
  47. co_return true;
  48. }
  49. private:
  50. timestamp_type min_interval = 0;
  51. struct callback_info {
  52. string_writer buffer;
  53. timestamp_type last_print_ts = 0;
  54. };
  55. sophiar_pool::callback_token_type create_callback(const std::string &var_name) override {
  56. auto var_info = global_sophiar_pool->query_variable_information(var_name);
  57. auto cb_info = new callback_info;
  58. auto cb_func = [=, this]() {
  59. auto ts = QUERY_VARIABLE_TS(var_info.index);
  60. if (ts - cb_info->last_print_ts < min_interval) return;
  61. cb_info->last_print_ts = ts;
  62. if (!raw_pointer_is_valid(var_info.placeholder, var_info.type_index)) {
  63. SPDLOG_DEBUG("{} is empty.", var_name);
  64. } else {
  65. raw_pointer_write_to(cb_info->buffer, var_info.placeholder, var_info.type_index);
  66. SPDLOG_DEBUG("{} = {}", var_name, cb_info->buffer.get_string_and_reset());
  67. }
  68. };
  69. auto exit_func = [=]() { delete cb_info; };
  70. auto token = REGISTER_CALLBACK2(cb_func, exit_func);
  71. ATTACH_CALLBACK(var_info.index, token);
  72. return token;
  73. }
  74. };
  75. class variable_validity_watcher : public multi_variable_utility_base {
  76. public:
  77. DEFAULT_NEW_INSTANCE(variable_validity_watcher)
  78. protected:
  79. awaitable<bool> on_start(const nlohmann::json &config) noexcept override {
  80. register_variables(config);
  81. co_return true;
  82. }
  83. private:
  84. sophiar_pool::callback_token_type create_callback(const std::string &var_name) override {
  85. auto var_info = global_sophiar_pool->query_variable_information(var_name);
  86. bool is_valid = raw_pointer_is_valid(var_info.placeholder, var_info.type_index);
  87. auto cb_func = [=]() mutable {
  88. if (raw_pointer_is_valid(var_info.placeholder, var_info.type_index)) {
  89. if (is_valid)[[likely]] return;
  90. SPDLOG_DEBUG("{} becomes valid.", var_name);
  91. is_valid = true;
  92. } else {
  93. if (!is_valid)[[likely]] return;
  94. SPDLOG_DEBUG("{} becomes invalid.", var_name);
  95. is_valid = false;
  96. }
  97. };
  98. auto token = REGISTER_CALLBACK(cb_func);
  99. ATTACH_CALLBACK(var_info.index, token);
  100. return token;
  101. }
  102. };
  103. class variable_recorder : public tristate_obj {
  104. public:
  105. variable_recorder()
  106. : buffer(string_writer(",")) {
  107. }
  108. DEFAULT_NEW_INSTANCE(variable_recorder)
  109. awaitable<bool> on_init(const nlohmann::json &config) noexcept override {
  110. auto var_name = LOAD_STRING_ITEM("variable_name");
  111. auto var_info = global_sophiar_pool->query_variable_information(var_name);
  112. var_index = var_info.index;
  113. auto save_file_path = LOAD_STRING_ITEM("save_file");
  114. ofs = std::ofstream(save_file_path, std::ofstream::out);
  115. assert(ofs.is_open());
  116. auto cb_func = [=, this]() mutable {
  117. auto ts = QUERY_VARIABLE_TS(var_index);
  118. buffer << (static_cast<double>(ts) / 1000.0); // us -> ms
  119. raw_pointer_write_to(buffer, var_info.placeholder, var_info.type_index);
  120. ofs << buffer.get_string_and_reset() << std::endl;
  121. };
  122. assert(cb_token == nullptr);
  123. cb_token = REGISTER_CALLBACK(cb_func);
  124. co_return true;
  125. }
  126. boost::asio::awaitable<bool> on_start(const nlohmann::json &) noexcept override {
  127. assert(ath_token == nullptr);
  128. ath_token = ATTACH_CALLBACK(var_index, cb_token);
  129. co_return true;
  130. }
  131. boost::asio::awaitable<void> on_stop() noexcept override {
  132. DETACH_CALLBACK(ath_token);
  133. ath_token = nullptr;
  134. co_return;
  135. }
  136. boost::asio::awaitable<void> on_reset() noexcept override {
  137. UNREGISTER_CALLBACK(cb_token);
  138. cb_token = nullptr;
  139. co_return;
  140. }
  141. private:
  142. string_writer buffer;
  143. std::ofstream ofs;
  144. variable_index_type var_index = -1;
  145. sophiar_pool::callback_token_type cb_token = nullptr;
  146. sophiar_pool::attach_token_type ath_token = nullptr;
  147. };
  148. void register_variable_utility() {
  149. REGISTER_TYPE2(variable_debug_watcher, "variable_watcher");
  150. REGISTER_TYPE2(variable_validity_watcher, "variable_validity_watcher");
  151. REGISTER_TYPE2(variable_recorder, "variable_recorder");
  152. }
  153. }