scc 2026.07
SystemC components library
global_time_keeper.cpp
1#include "global_time_keeper.h"
2#include <limits>
3#include <tlm_utils/tlm_quantumkeeper.h>
4
5namespace tlm {
6namespace scc {
7namespace qk {
9//
11global_time_keeper::global_time_keeper() = default;
12
13global_time_keeper::~global_time_keeper() {
14 // shutting down time keeper thread
15 stop_it.store(true);
16 update.notify_all();
17}
18// this function will be called from the systemc thread
19void global_time_keeper::start() {
20 std::thread t{&global_time_keeper::sync_local_times, this};
21 t.detach();
22 started = true;
23}
24// this function will be called from the systemc thread
25size_t global_time_keeper::get_channel_index() {
26 if(started)
27 throw std::runtime_error("global_time_keeper already started");
28 client_coms_channels.emplace_back(client_coms_channels.size());
29 update_it = true;
30 return client_coms_channels.size() - 1;
31}
32
33// runs in a background thread
34void global_time_keeper::sync_local_times() {
35 std::unique_lock<std::mutex> lock{upd_mtx};
36 while(true) {
37 update.wait_for(lock, std::chrono::milliseconds(1),
38 [this]() -> bool { return update_it.load(std::memory_order_relaxed) || stop_it.load(std::memory_order_relaxed); });
39 if(update_it.exchange(false)) {
40#ifdef DEBUG_MT_SCHEDULING
41 SCCTRACEALL("global_time_keeper::sync_local_times") << "update loop";
42#endif
43 while(auto res = sc_coms_channel.client2time_keeper.front()) {
44 sc_coms_channel.thread_local_time = res->time_tick;
45 sc_coms_channel.client2time_keeper.pop();
46 }
47 uint64_t min_local_time = std::numeric_limits<uint64_t>::max();
48 for(size_t i = 0; i < client_coms_channels.size(); ++i) {
49 auto& client_coms_channel = client_coms_channels[i];
50 bool has_task = false;
51 bool has_entries = false;
52 while(auto res = client_coms_channel.client2time_keeper.front()) {
53 has_entries = true;
54 client_coms_channel.thread_local_time = res->time_tick;
55 if(res->task.valid()) {
56#ifdef DEBUG_MT_SCHEDULING
57 SCCTRACEALL("global_time_keeper::sync_local_times")
58 << "forwarding task of client " << client_coms_channel.my_id << " with timestamp t=" << res->time_tick;
59#endif
60 pending_tasks.emplace(client_coms_channel.my_id, res->time_tick, std::move(res->task));
61 has_task = true;
62 }
63 client_coms_channel.client2time_keeper.pop();
64 }
65 if(has_entries)
66 client_coms_channel.waiting4sc = has_task;
67 if(!client_coms_channel.waiting4sc)
68 min_local_time = std::min(client_coms_channel.thread_local_time, min_local_time);
69#ifdef DEBUG_MT_SCHEDULING
70 if(has_entries) {
71 SCCTRACEALL("global_time_keeper::sync_local_times")
72 << "thread_local_time[" << i << "]=" << sc_core::sc_time::from_value(client_coms_channel.thread_local_time)
73 << (client_coms_channel.waiting4sc ? " (waiting)" : " (running)");
74 }
75#endif
76 }
77 // if all threads are blocked by SystemC use SystemC time as minimum time
78 if(min_local_time == std::numeric_limits<uint64_t>::max())
79 min_local_time = sc_coms_channel.thread_local_time;
80 client_min_time = min_local_time;
81 // client_max_time = max_local_time;
82 client_max_time = min_local_time + std::max(tlm::tlm_global_quantum::instance().get().value(), sc_time_step.value());
83 sc_kernel_time = sc_coms_channel.thread_local_time;
84#ifdef DEBUG_MT_SCHEDULING
85 SCCTRACEALL("global_time_keeper::sync_local_times") << "window_min_time=" << client_min_time;
86#endif
87 } else if(stop_it.load()) {
88 break;
89 }
90 }
91}
92
93} // namespace qk
94} // namespace scc
95} // namespace tlm
SCC TLM utilities.
Definition axis_tlm.h:56
SystemC TLM.
Definition dmi_mgr.h:19
static global_time_keeper & get()
the singleton getter
const sc_core::sc_time sc_time_step
the maximum timestep the simulator is allowed to do if there are no future events