diff --git a/src/sysc/scc/async_thread.h b/src/sysc/scc/async_thread.h index e8d1a578e..f643544f0 100644 --- a/src/sysc/scc/async_thread.h +++ b/src/sysc/scc/async_thread.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -11,7 +12,8 @@ namespace scc { struct async_thread : sc_core::sc_prim_channel { - async_thread() = default; + async_thread() + : sc_core::sc_prim_channel{sc_core::sc_gen_unique_name("async_thread")} {} explicit async_thread(const char* nm) : sc_core::sc_prim_channel{nm} {} @@ -22,7 +24,7 @@ struct async_thread : sc_core::sc_prim_channel { } void start(std::function const& f) { - SCCTRACE(SCMOD) << "Starting new thread"; + SCCTRACE(SCOBJ) << "Starting new thread"; t1 = std::move(std::thread([this, f]() { try { finish_time.store(f().value()); @@ -41,7 +43,7 @@ struct async_thread : sc_core::sc_prim_channel { auto end_time = sc_core::sc_time::from_value(finish_time.load()); finish_event.notify(end_time > sc_core::sc_time_stamp() ? end_time - sc_core::sc_time_stamp() : sc_core::SC_ZERO_TIME); active = false; - SCCTRACEALL(SCOBJ) << "Finished execution of thread"; + SCCTRACE(SCOBJ) << "Finished execution of thread"; } std::thread t1; sc_core::sc_event finish_event; diff --git a/src/sysc/scc/peq.h b/src/sysc/scc/peq.h index 3f4c35f80..cc2c678bf 100644 --- a/src/sysc/scc/peq.h +++ b/src/sysc/scc/peq.h @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -168,6 +169,11 @@ template struct peq : public sc_core::sc_object { */ bool has_next() { return !(m_scheduled_events.empty() || m_scheduled_events.begin()->first > sc_core::sc_time_stamp()); } + sc_core::sc_time get_next_time_stamp() { + return m_scheduled_events.empty() ? sc_core::sc_time::from_value(std::numeric_limits::max()) + : m_scheduled_events.begin()->first; + } + void clear() { while(!m_scheduled_events.empty()) { auto queue = m_scheduled_events.begin()->second; diff --git a/src/sysc/scc/report.cpp b/src/sysc/scc/report.cpp index 96a626b77..824f479c9 100644 --- a/src/sysc/scc/report.cpp +++ b/src/sysc/scc/report.cpp @@ -381,6 +381,7 @@ auto scc::stream_redirection::sync() -> int { static void configure_logging() { std::lock_guard lock(log_cfg.mtx); + std::lock_guard lock2(verbosity_mtx); static bool spdlog_initialized = false; if(!log_cfg.dont_create_broker) scc::init_cci("SCCBroker"); @@ -514,6 +515,7 @@ void scc::init_logging(const scc::LogConfig& log_config) { } void scc::set_logging_level(scc::log level) { + std::lock_guard lock(verbosity_mtx); log_cfg.level = level; sc_report_handler::set_verbosity_level(verbosity[static_cast(level)]); log_cfg.console_logger->set_level( @@ -604,8 +606,8 @@ auto scc::LogConfig::installHandler(bool v) -> scc::LogConfig& { } namespace { std::mutex mtx; -sc_core::sc_verbosity __get_log_verbosity(string current_name, char const* str, cci::cci_broker_handle const& broker, - sc_core::sc_verbosity verb) { +auto get_log_verbosity_from_broker(string current_name, char const* str, cci::cci_broker_handle const& broker, sc_core::sc_verbosity verb) + -> sc_core::sc_verbosity { std::lock_guard lk(mtx); while(true) { string param_name = (current_name.empty()) ? SCC_LOG_LEVEL_PARAM_NAME : current_name + "." SCC_LOG_LEVEL_PARAM_NAME; @@ -633,15 +635,13 @@ sc_core::sc_verbosity __get_log_verbosity(string current_name, char const* str, } } } - return verb; } + return verb; } } // namespace auto scc::get_log_verbosity(char const* str) -> sc_core::sc_verbosity { - std::unique_lock lock(verbosity_mtx); - auto global_verb = static_cast(::sc_core::sc_report_handler::get_verbosity_level()); - lock.unlock(); + auto global_verb = verbosity[static_cast(log_cfg.level)]; if(inst_based_logging()) { auto res = lut.get(str); if(std::get<0>(res)) @@ -650,10 +650,10 @@ auto scc::get_log_verbosity(char const* str) -> sc_core::sc_verbosity { if(strchr(str, '.') == nullptr || curr_object) { string current_name = std::string(str); if(log_cfg.broker) - return __get_log_verbosity(current_name, str, log_cfg.broker.value(), global_verb); + return get_log_verbosity_from_broker(current_name, str, log_cfg.broker.value(), global_verb); else { - return __get_log_verbosity(current_name, str, curr_object ? cci::cci_get_broker() : cci::cci_get_global_broker(originator), - global_verb); + return get_log_verbosity_from_broker( + current_name, str, curr_object ? cci::cci_get_broker() : cci::cci_get_global_broker(originator), global_verb); } } } diff --git a/src/sysc/scc/report.h b/src/sysc/scc/report.h index 0107b231e..61af3846f 100644 --- a/src/sysc/scc/report.h +++ b/src/sysc/scc/report.h @@ -384,10 +384,16 @@ template struct ScLogger { * */ virtual ~ScLogger() noexcept(false) { - std::lock_guard lock(verbosity_mtx); - auto verb = ::sc_core::sc_report_handler::set_verbosity_level(1000); + int verb = 100; + { + std::lock_guard lock(verbosity_mtx); + verb = ::sc_core::sc_report_handler::set_verbosity_level(1000); + } ::sc_core::sc_report_handler::report(SEVERITY, t ? t : "SystemC", os.str().c_str(), level, file, line); - ::sc_core::sc_report_handler::set_verbosity_level(verb); + { + std::lock_guard lock(verbosity_mtx); + ::sc_core::sc_report_handler::set_verbosity_level(verb); + } } /** * @fn ScLogger& type() diff --git a/src/sysc/tlm/scc/qk/global_time_keeper.cpp b/src/sysc/tlm/scc/qk/global_time_keeper.cpp index 77051df74..88b3e20f6 100644 --- a/src/sysc/tlm/scc/qk/global_time_keeper.cpp +++ b/src/sysc/tlm/scc/qk/global_time_keeper.cpp @@ -1,4 +1,5 @@ #include "global_time_keeper.h" +#include #include namespace tlm { @@ -11,7 +12,7 @@ global_time_keeper::global_time_keeper() = default; global_time_keeper::~global_time_keeper() { // shutting down time keeper thread - stop_it.store(true, std::memory_order_acq_rel); + stop_it.store(true); update.notify_all(); } // this function will be called from the systemc thread @@ -39,12 +40,11 @@ void global_time_keeper::sync_local_times() { #ifdef DEBUG_MT_SCHEDULING SCCTRACEALL("global_time_keeper::sync_local_times") << "update loop"; #endif - uint64_t min_local_time = std::numeric_limits::max(); - bool tail = false; while(auto res = sc_coms_channel.client2time_keeper.front()) { sc_coms_channel.thread_local_time = res->time_tick; sc_coms_channel.client2time_keeper.pop(); } + uint64_t min_local_time = std::numeric_limits::max(); for(size_t i = 0; i < client_coms_channels.size(); ++i) { auto& client_coms_channel = client_coms_channels[i]; bool has_task = false; @@ -74,14 +74,15 @@ void global_time_keeper::sync_local_times() { } #endif } - window_min_time = min_local_time; - sc_coms_channel.time_keeper2client.store(min_local_time); - auto window_max_time = min_local_time + std::max(tlm::tlm_global_quantum::instance().get().value(), sc_time_step.value()); - for(auto& client_coms_channel : client_coms_channels) { - client_coms_channel.time_keeper2client.store(window_max_time); - } + // if all threads are blocked by SystemC use SystemC time as minimum time + if(min_local_time == std::numeric_limits::max()) + min_local_time = sc_coms_channel.thread_local_time; + client_min_time = min_local_time; + // client_max_time = max_local_time; + client_max_time = min_local_time + std::max(tlm::tlm_global_quantum::instance().get().value(), sc_time_step.value()); + sc_kernel_time = sc_coms_channel.thread_local_time; #ifdef DEBUG_MT_SCHEDULING - SCCTRACEALL("global_time_keeper::sync_local_times") << "window_min_time=" << window_min_time; + SCCTRACEALL("global_time_keeper::sync_local_times") << "window_min_time=" << client_min_time; #endif } else if(stop_it.load()) { break; diff --git a/src/sysc/tlm/scc/qk/global_time_keeper.h b/src/sysc/tlm/scc/qk/global_time_keeper.h index 61454d119..4d0b66c3c 100644 --- a/src/sysc/tlm/scc/qk/global_time_keeper.h +++ b/src/sysc/tlm/scc/qk/global_time_keeper.h @@ -40,21 +40,21 @@ struct global_time_keeper { * * @return uint64_t the absolute number of ticks */ - inline uint64_t get_min_time_ticks() { return window_min_time; } + inline uint64_t get_client_min_time_ticks() { return client_min_time; } /** * @brief Get the maximum time ticks a client thread is allowed to advance * * @param idx the id of the client thread, to be obtained using get_channel_index() * @return uint64_t the absolute number of maximum ticks, if no new information it returns -1 */ - inline uint64_t get_max_time_ticks(size_t idx) { return client_coms_channels[idx].time_keeper2client.load(); } + inline uint64_t get_client_max_time_ticks(size_t idx) { return client_max_time; } /** * @brief updates the global time keeper with the local time ticks of a clinet thread * * @param idx the id of the client thread, to be obtained using get_channel_index() * @param tick the absolute number of actual ticks */ - inline void update_time_ticks(size_t idx, uint64_t tick) { + inline void update_client_time_ticks(size_t idx, uint64_t tick) { client_coms_channels[idx].client2time_keeper.push(std::move(comms_entry{tick, std::move(callback_task())})); update_it.store(true); std::unique_lock lk(upd_mtx); @@ -78,7 +78,7 @@ struct global_time_keeper { * * @return uint64_t the absolute number of ticks */ - inline uint64_t get_max_sc_time_ticks() { return sc_coms_channel.time_keeper2client.load(); } + inline uint64_t get_sc_time_ticks() { return sc_kernel_time.load(); } /** * @brief updates the global time keeper with the local time ticks of the SystemC thread * @@ -86,9 +86,6 @@ struct global_time_keeper { */ inline void update_sc_time_ticks(uint64_t tick) { sc_coms_channel.client2time_keeper.push(std::move(comms_entry{tick, std::move(callback_task())})); -#ifdef DEBUG_MT_SCHEDULING - SCCTRACEALL("global_time_keeper::update_sc_time_ticks") << "sc_time=" << sc_core::sc_time::from_value(tick); -#endif update_it.store(true); std::unique_lock lk(upd_mtx); update.notify_all(); @@ -111,7 +108,9 @@ struct global_time_keeper { std::atomic stop_it{false}; std::atomic update_it{false}; - std::atomic_uint64_t window_min_time; + std::atomic_uint64_t client_min_time; + std::atomic_uint64_t client_max_time; + std::atomic_uint64_t sc_kernel_time; std::mutex upd_mtx; std::condition_variable update; thread_comms_channel sc_coms_channel{-1ULL}; diff --git a/src/sysc/tlm/scc/qk/sc_time_syncronizer.cpp b/src/sysc/tlm/scc/qk/sc_time_syncronizer.cpp index c93cda031..ac17d72fb 100644 --- a/src/sysc/tlm/scc/qk/sc_time_syncronizer.cpp +++ b/src/sysc/tlm/scc/qk/sc_time_syncronizer.cpp @@ -1,5 +1,10 @@ #include "sc_time_syncronizer.h" #include "global_time_keeper.h" +#include +#include +#include +#include +#include #include #include @@ -8,82 +13,95 @@ namespace scc { namespace qk { sc_time_syncronizer::sc_time_syncronizer(global_time_keeper& gtk) : gtk(gtk) { - sc_core::sc_register_stage_callback(*this, sc_core::SC_PRE_TIMESTEP | sc_core::SC_POST_END_OF_ELABORATION); + sc_core::sc_register_stage_callback(*this, sc_core::SC_POST_END_OF_ELABORATION | sc_core::SC_POST_START_OF_SIMULATION | + sc_core::SC_PRE_TIMESTEP); sc_core::sc_spawn_options opt; opt.spawn_method(); - sc_core::sc_spawn([this]() { method_callback(); }, nullptr, &opt); + sc_core::sc_spawn([this]() { sc_method(); }, nullptr, &opt); } -void sc_time_syncronizer::method_callback() { - auto res = this->gtk.get_max_sc_time_ticks(); - if(res != std::numeric_limits::max()) { - sc_max_time.store(res, std::memory_order_seq_cst); - } +bool sc_time_syncronizer::process_pending_tasks() { + auto res = this->gtk.get_sc_time_ticks(); auto& pending_tasks = this->gtk.pending_tasks; if(pending_tasks.size()) { -#ifdef DEBUG_MT_SCHEDULING - SCCTRACEALL(__PRETTY_FUNCTION__) << "updating pending tasks"; -#endif while(pending_tasks.size()) { auto res = pending_tasks.front(); auto idx = std::get<0>(*res); auto t = std::get<1>(*res); - auto& peq = sc_task_que[idx]; if(t > sc_core::sc_time_stamp().value()) { auto d = sc_core::sc_time::from_value(t) - sc_core::sc_time_stamp(); #ifdef DEBUG_MT_SCHEDULING SCCDEBUG(__PRETTY_FUNCTION__) << "scheduling task from client " << idx << " with t=" << t << " with delay " << d; #endif - peq.notify(std::move(std::get<2>(*res)), d); + notify_task(idx, std::move(std::get<2>(*res)), d); } else { #ifdef DEBUG_MT_SCHEDULING SCCDEBUG(__PRETTY_FUNCTION__) << "scheduling task from client " << idx << " with t=" << t << " now"; #endif - peq.notify(std::move(std::get<2>(*res)), sc_core::SC_ZERO_TIME); + notify_task(idx, std::move(std::get<2>(*res)), sc_core::SC_ZERO_TIME); } pending_tasks.pop(); } + return true; + } + return false; +} + +void sc_time_syncronizer::sc_method() { + if(process_pending_tasks()) { sc_core::next_trigger(sc_core::SC_ZERO_TIME); - } else if(sc_core::sc_get_curr_simcontext()->pending_activity_at_current_time()) { + return; + } + if(state == sync_state::INITIAL) + state = sync_state::PROCESSING; + auto time_to_next_evt = sc_core::sc_time_to_pending_activity(sc_core::sc_get_curr_simcontext()); + if(sc_core::sc_get_curr_simcontext()->pending_activity_at_current_time()) { #ifdef DEBUG_MT_SCHEDULING - SCCTRACEALL(__PRETTY_FUNCTION__) << "yield to next delta cycle"; + SCCTRACEALL(__PRETTY_FUNCTION__) << "yield to next delta cycle (pending activity time: " << time_to_next_evt << ")"; #endif sc_core::next_trigger(sc_core::SC_ZERO_TIME); - } else { - auto time_to_next_evt = sc_core::sc_time_to_pending_activity(sc_core::sc_get_curr_simcontext()); - if(!sc_is_free_running) { - auto min_time = sc_core::sc_time::from_value(gtk.get_max_sc_time_ticks()); - auto abs_time_to_next_evt = sc_core::sc_time_stamp() + time_to_next_evt; - if(min_time < abs_time_to_next_evt) { - if(min_time > sc_core::sc_time_stamp()) { - sc_core::next_trigger(min_time - sc_core::sc_time_stamp()); - } else { - // slow down systemc execution to be the slower than client threads - std::this_thread::yield(); - // std::this_thread::sleep_for(std::chrono::microseconds{1}); - sc_core::next_trigger(sc_core::SC_ZERO_TIME); // play it again, Sam - } - } else { + return; + } + if(!sc_is_free_running) { + auto min_time = sc_core::sc_time::from_value(gtk.get_client_min_time_ticks()); + auto abs_time_of_next_evt = sc_core::sc_time_stamp() + time_to_next_evt; + if(min_time < abs_time_of_next_evt) { + if(min_time > sc_core::sc_time_stamp()) { #ifdef DEBUG_MT_SCHEDULING - SCCTRACEALL(__PRETTY_FUNCTION__) << "advancing SC time lockstepped to " << abs_time_to_next_evt; + SCCTRACEALL(__PRETTY_FUNCTION__) << "advancing SC time lockstepped to " << min_time; #endif - sc_core::next_trigger(time_to_next_evt); - } - } else { - // all threads are blocked by SystemC, so we can run freely but to avoid starving the kernel we only proceed to the - // time of the slowest client thread as this one is waiting to be served - auto next_time_point = sc_core::sc_time_stamp() + time_to_next_evt; - if(next_time_point.value() == std::numeric_limits::max()) { - time_to_next_evt = tlm_utils::tlm_quantumkeeper::get_global_quantum(); - if(time_to_next_evt == sc_core::SC_ZERO_TIME) - time_to_next_evt = 1_us; + sc_core::next_trigger(min_time - sc_core::sc_time_stamp()); + return; } + // slow down systemc execution to be the slower than client threads + std::this_thread::yield(); + // std::this_thread::sleep_for(std::chrono::microseconds{1}); + sc_core::next_trigger(sc_core::SC_ZERO_TIME); // play it again, Sam + return; + } #ifdef DEBUG_MT_SCHEDULING - SCCTRACEALL(__PRETTY_FUNCTION__) << "advancing SC time free running to " << next_time_point; + SCCTRACEALL(__PRETTY_FUNCTION__) << "advancing SC time lockstepped to " << abs_time_of_next_evt; #endif - sc_core::next_trigger(time_to_next_evt); - } + sc_core::next_trigger(time_to_next_evt); + return; + } + if(state == sync_state::PROCESSING) { + state = sync_state::ARMED; + sc_core::next_trigger(sc_core::SC_ZERO_TIME); + return; + } + // all threads are blocked by SystemC, so we can run freely but to avoid starving the kernel we only proceed to the + // time of the slowest client thread as this one is waiting to be served + auto next_time_point = sc_core::sc_time_stamp() + time_to_next_evt; + if(next_time_point.value() == std::numeric_limits::max()) { + time_to_next_evt = tlm_utils::tlm_quantumkeeper::get_global_quantum(); + if(time_to_next_evt == sc_core::SC_ZERO_TIME) + time_to_next_evt = 1_us; } +#ifdef DEBUG_MT_SCHEDULING + SCCTRACEALL(__PRETTY_FUNCTION__) << "advancing SC time free running to " << next_time_point; +#endif + sc_core::next_trigger(time_to_next_evt); } void sc_time_syncronizer::stage_callback(const sc_core::sc_stage& stage) { @@ -92,13 +110,20 @@ void sc_time_syncronizer::stage_callback(const sc_core::sc_stage& stage) { sc_core::sc_time next_time; if(sc_core::sc_get_curr_simcontext()->next_time(next_time)) { gtk.update_sc_time_ticks(next_time.value()); + while(gtk.get_sc_time_ticks() != next_time.value()) + std::this_thread::yield(); } + state = sync_state::INITIAL; #ifdef DEBUG_MT_SCHEDULING - SCCTRACEALL(__PRETTY_FUNCTION__) << "advancing SystemC kernel time to " << next_time << ", get_min_time()=" << get_min_time(); + SCCTRACEALL(__PRETTY_FUNCTION__) << "advancing SystemC kernel time to " << next_time << ", get_min_time()=" << get_min_time() + << ", sc_is_free_running=" << sc_is_free_running; #endif } break; case sc_core::SC_POST_END_OF_ELABORATION: gtk.start(); + /* fall thru */ + case sc_core::SC_POST_START_OF_SIMULATION: + gtk.update_sc_time_ticks(sc_core::sc_time_stamp().value()); break; default: break; diff --git a/src/sysc/tlm/scc/qk/sc_time_syncronizer.h b/src/sysc/tlm/scc/qk/sc_time_syncronizer.h index bfd6b3eb9..8d4ddd382 100644 --- a/src/sysc/tlm/scc/qk/sc_time_syncronizer.h +++ b/src/sysc/tlm/scc/qk/sc_time_syncronizer.h @@ -7,6 +7,14 @@ namespace tlm { namespace scc { namespace qk { +struct client_deputy { + ::scc::peq peq; + bool blocked; + client_deputy(char const* nm) + : peq{nm} + , blocked(false) {} +}; + /** *the SystemC time keeper, a singleton in the SystemC thread */ @@ -30,36 +38,26 @@ struct sc_time_syncronizer : sc_core::sc_stage_callback_if, sc_core::sc_process_ */ size_t get_channel_index() { auto idx = gtk.get_channel_index(); - sc_task_que.emplace_back(); - blocked_channels.emplace_back(true); - auto& sctq = sc_task_que[sc_task_que.size() - 1]; + client_deputies.emplace_back(); + auto& client = client_deputies[client_deputies.size() - 1]; sc_core::sc_spawn( - [this, &sctq, idx]() { - wait(sc_core::SC_ZERO_TIME); + [this, &client, idx]() { while(true) { - // while(!sctq.has_next()) { - // sc_core::wait(sctq.event()); - // } - // this->notify_client_blocked(idx, true); - sctq.get()(); - // this->notify_client_blocked(idx, false); + client.peq.get()(); + if(!client.peq.has_next()) + this->notify_client_blocked(idx, false); } }, sc_core::sc_gen_unique_name("peq_cb", false)); return idx; } - /** - * @brief Get the current sc kernel time - * - * @return sc_core::sc_time - */ - inline sc_core::sc_time get_sc_kernel_time() { return sc_core::sc_time::from_value(sc_max_time.load(std::memory_order_seq_cst)); } inline void notify_client_blocked(size_t idx, bool is_blocked) { - assert(idx < blocked_channels.size()); - blocked_channels[idx] = is_blocked; - sc_is_free_running = !std::any_of(std::begin(blocked_channels), std::end(blocked_channels), [](bool b) { return !b; }); + assert(idx < client_deputies.size()); + client_deputies[idx].blocked = is_blocked; + sc_is_free_running = + !std::any_of(std::begin(client_deputies), std::end(client_deputies), [](client_deputy const& d) { return !d.blocked; }); #ifdef DEBUG_MT_SCHEDULING SCCTRACEALL(__PRETTY_FUNCTION__) << (is_blocked ? "blocking" : "unblocking") << " thread " << idx << ", sc_is_free_running=" << sc_is_free_running; @@ -67,15 +65,21 @@ struct sc_time_syncronizer : sc_core::sc_stage_callback_if, sc_core::sc_process_ } private: + enum class sync_state { INITIAL, PROCESSING, ARMED }; sc_time_syncronizer(global_time_keeper& gtk); - void method_callback(); + void sc_method(); + bool process_pending_tasks(); + sync_state state{sync_state::INITIAL}; void stage_callback(const sc_core::sc_stage& stage) override; - sc_core::sc_time get_min_time() { return sc_core::sc_time::from_value(gtk.get_min_time_ticks()); } + inline void notify_task(size_t idx, callback_task&& task, sc_core::sc_time const& d) { + client_deputies[idx].peq.notify(std::move(task), d); + notify_client_blocked(idx, true); + } + sc_core::sc_time get_min_time() { return sc_core::sc_time::from_value(gtk.get_client_min_time_ticks()); } + global_time_keeper& gtk; - sc_core::sc_vector<::scc::peq> sc_task_que; - std::atomic_int64_t sc_max_time{0}; + sc_core::sc_vector client_deputies; sc_core::sc_process_handle method_handle; - std::vector blocked_channels; bool sc_is_free_running{true}; }; } // namespace qk diff --git a/src/sysc/tlm/scc/qk/types.h b/src/sysc/tlm/scc/qk/types.h index eabae72f3..7f8b47e3d 100644 --- a/src/sysc/tlm/scc/qk/types.h +++ b/src/sysc/tlm/scc/qk/types.h @@ -5,6 +5,8 @@ #include #include +// #define DEBUG_MT_SCHEDULING + namespace tlm { namespace scc { namespace qk { @@ -38,8 +40,7 @@ struct thread_comms_channel { * @param my_id */ thread_comms_channel(uint64_t my_id) - : time_keeper2client(0) - , client2time_keeper(7) + : client2time_keeper(7) , my_id(my_id) {} /** * @brief Construct a new thread comms channel object @@ -47,19 +48,17 @@ struct thread_comms_channel { * @param o */ thread_comms_channel(thread_comms_channel const& o) - : my_id(o.my_id) - , client2time_keeper(o.client2time_keeper.capacity()) - , time_keeper2client(0) + : client2time_keeper(o.client2time_keeper.capacity()) + , my_id(o.my_id) , thread_local_time(o.thread_local_time) { assert(o.client2time_keeper.size() == 0); }; - alignas(64) std::atomic time_keeper2client; rigtorp::SPSCQueue client2time_keeper; const uint64_t my_id; - bool waiting4sc; - uint64_t thread_local_time; + bool waiting4sc{true}; + uint64_t thread_local_time{0}; }; } // namespace qk } // namespace scc diff --git a/src/sysc/tlm/scc/quantum_keeper.h b/src/sysc/tlm/scc/quantum_keeper.h index 284291e54..7b5b2f361 100644 --- a/src/sysc/tlm/scc/quantum_keeper.h +++ b/src/sysc/tlm/scc/quantum_keeper.h @@ -11,7 +11,6 @@ using quantumkeeper_mt = quantumkeeper_st; } // namespace tlm #else #include "quantum_keeper_mt.h" -#define DEBUG_MT_SCHEDULING #endif namespace tlm { namespace scc { diff --git a/src/sysc/tlm/scc/quantum_keeper_mt.h b/src/sysc/tlm/scc/quantum_keeper_mt.h index 0bbdb4064..fce59ceed 100644 --- a/src/sysc/tlm/scc/quantum_keeper_mt.h +++ b/src/sysc/tlm/scc/quantum_keeper_mt.h @@ -3,6 +3,7 @@ #include "qk/sc_time_syncronizer.h" #include +#include #if SC_VERSION_MAJOR < 3 #error "Multithreaded quantum keeper is only supported with SystemC 3.0 and newer" @@ -14,13 +15,14 @@ namespace scc { /** * the multi threading quantum keeper */ -struct quantumkeeper_mt { +struct quantumkeeper_mt : sc_core::sc_object { /** * @brief Construct a new quantumkeeper mt object * */ quantumkeeper_mt() - : gtk_idx(qk::sc_time_syncronizer::get().get_channel_index()) { + : sc_core::sc_object("qk") + , gtk_idx(qk::sc_time_syncronizer::get().get_channel_index()) { sc_core::sc_spawn_options opt; opt.spawn_method(); opt.set_sensitivity(&keep_alive); @@ -33,7 +35,13 @@ struct quantumkeeper_mt { void run_thread(std::function f) { qk::sc_time_syncronizer::get().notify_client_blocked(gtk_idx, false); - thread_executor.start(f); + reset(sc_core::sc_time_stamp()); + thread_executor.start([this, f]() { + this->check_and_sync(sc_core::SC_ZERO_TIME); + auto ret = f(); + qk::sc_time_syncronizer::get().notify_client_blocked(gtk_idx, true); + return ret; + }); wait(thread_executor.thread_finish_event()); } /** @@ -43,9 +51,7 @@ struct quantumkeeper_mt { */ inline void inc(sc_core::sc_time const& core_inc) { local_absolute_time += core_inc; - auto res = qk::global_time_keeper::get().get_max_time_ticks(gtk_idx); - if(res != std::numeric_limits::max()) - local_time_ticks_limit = res; + local_time_ticks_limit = qk::global_time_keeper::get().get_client_max_time_ticks(gtk_idx); } /** * @brief checks the local time against the global time keeper and holds the thread until it is within the quantum @@ -54,13 +60,11 @@ struct quantumkeeper_mt { */ inline void check_and_sync(sc_core::sc_time const& core_inc) { inc(core_inc); - qk::global_time_keeper::get().update_time_ticks(gtk_idx, local_absolute_time.value()); + qk::global_time_keeper::get().update_client_time_ticks(gtk_idx, local_absolute_time.value()); // wait until the SystemC thread advanced to the same time then we are minus the global quantum while(local_absolute_time.value() > local_time_ticks_limit) { std::this_thread::yield(); // should do the same than __builtin_ia32_pause() or _mm_pause() on MSVC - auto res = qk::global_time_keeper::get().get_max_time_ticks(gtk_idx); - if(res != std::numeric_limits::max()) - local_time_ticks_limit = res; + local_time_ticks_limit = qk::global_time_keeper::get().get_client_max_time_ticks(gtk_idx); } } /** @@ -78,17 +82,12 @@ struct quantumkeeper_mt { inline void execute_on_sysc(std::function& fct, sc_core::sc_time when) { qk::callback_task task([this, &fct]() { auto t0 = sc_core::sc_time_stamp(); - qk::sc_time_syncronizer::get().notify_client_blocked(gtk_idx, true); fct(); - qk::sc_time_syncronizer::get().notify_client_blocked(gtk_idx, false); return sc_core::sc_time_stamp() - t0; }); auto ret = task.get_future(); qk::global_time_keeper::get().schedule_task(gtk_idx, std::move(task), when.value()); auto duration = ret.get(); -#ifdef DEBUG_MT_SCHEDULING - SCCTRACEALL("quantumkeeper_mt") << "execute_on_sysc took " << duration; -#endif check_and_sync(duration); } /** @@ -108,7 +107,7 @@ struct quantumkeeper_mt { * * @return sc_core::sc_time the time of the SystemC kernel */ - sc_core::sc_time get_current_sc_time() const { return qk::sc_time_syncronizer::get().get_sc_kernel_time(); } + sc_core::sc_time get_current_sc_time() const { return sc_core::sc_time::from_value(qk::global_time_keeper::get().get_sc_time_ticks()); } /** * @brief resets the local time of this thread to the SystemC kernel time * @@ -121,7 +120,7 @@ struct quantumkeeper_mt { */ void reset(sc_core::sc_time const& abs_time) { local_absolute_time = sc_core::sc_time_stamp(); } - void unblock_thread() { qk::global_time_keeper::get().update_time_ticks(gtk_idx, local_absolute_time.value()); } + void unblock_thread() { qk::global_time_keeper::get().update_client_time_ticks(gtk_idx, local_absolute_time.value()); } protected: size_t gtk_idx;