17#include "tcp4tlm_server.h"
18#include "scc/report.h"
19#include "scc/tcp4tlm/messages.h"
20#include "tlm/scc/tlm_extensions.h"
21#include "tlm/scc/tlm_gp_shared.h"
24#include <boost/asio.hpp>
28#include <sysc/kernel/sc_module.h>
29#include <sysc/kernel/sc_simcontext.h>
30#include <sysc/kernel/sc_time.h>
33#define GETCLOCK(X) clock_gettime(CLOCK_REALTIME, X)
36using namespace std::chrono_literals;
38tcp4tlm_server::tcp4tlm_server(sc_core::sc_module_name name,
size_t no_of_ports)
39: sc_core::sc_module(name)
40, tcp4tlm::server<tcp4tlm::request_message, tcp4tlm::response_message>(2)
41, signals{
"signals", no_of_ports}
43#ifdef GENERATE_STATISTICS
49 SC_THREAD(timing_thread);
50 SC_THREAD(process_task_que);
51 SC_THREAD(process_timed_task_que);
52#ifdef GENERATE_STATISTICS
59#ifdef GENERATE_STATISTICS
60void tcp4tlm_server::statistics::updateStat(
unsigned long rt) {
70 int idx = indexer.getIndexFromAddr(rt);
73 SCCERR(SCMOD) <<
"Could not find index for " << rt;
75 if(histogram.size() <=
static_cast<unsigned>(idx)) {
76 histogram.resize(idx + 1);
86tcp4tlm_server::~tcp4tlm_server() { shutdown_server(); }
88void tcp4tlm_server::start_of_simulation() {
89 SCCINFO(SCMOD) <<
"starting server on port " << this_host_port.get_value();
90 server::start_server(this_host_port.get_value());
93void tcp4tlm_server::end_of_simulation() {
94 if(is_server_running()) {
97#ifdef GENERATE_STATISTICS
98 const char* stream_type =
typeid(get_acceptor()) ==
typeid(boost::asio::ip::tcp::acceptor) ?
"tcp" :
"stream";
100 for(
size_t idx = 0; idx < 10; ++idx) {
101 indexer.setTargetRange(idx, idx * 10000, 10000);
103 for(
size_t idx = 10; idx < 20; ++idx) {
104 indexer.setTargetRange(idx, 100000 * (idx - 9), 100000);
106 for(
size_t idx = 20; idx < 30; ++idx) {
107 indexer.setTargetRange(idx, 1000000 * (idx - 19), 1000000);
109 for(
size_t idx = 30; idx < 40; ++idx) {
110 indexer.setTargetRange(idx, 10000000 * (idx - 29), 10000000);
112 statistics stat_tx(indexer, 40, txt[0]), stat_send(indexer, 40, rtto[0]), stat_rx(indexer, 30, rxt[0]);
113 for(
size_t i = 0; i < txt.size(); ++i) {
114 stat_tx.updateStat(txt[i]);
115 stat_send.updateStat(rtto[i]);
116 stat_rx.updateStat(rxt[i]);
118 cout <<
"Statistics for " << stream_type <<
" socket based communication" << endl;
119 cout <<
"Send times for " << txt.size() <<
" transactions in ns for writing (min,avg,max): " << stat_tx << endl;
120 cout <<
"Transmit times for " << txt.size() <<
" transactions in ns for writing (min,avg,max): " << stat_send << endl;
121 cout <<
"Receive times for " << txt.size() <<
" transactions in ns for reading (min,avg,max): " << stat_rx << endl;
122 stat_tx.print_histogram =
true;
123 cout <<
"Send times histogram:" << endl << stat_tx;
124 stat_rx.print_histogram =
true;
125 cout <<
"Receive times histogram:" << endl << stat_rx;
129inline long long int get_time_of_day_us() {
131#if defined __x86_64__
132 gettimeofday(&checkpoint, 0);
133 return checkpoint.tv_sec * 100000 + checkpoint.tv_usec;
139void tcp4tlm_server::timing_thread() {
140 wait(sc_core::SC_ZERO_TIME);
145 const auto usecs_to_sleep = 1000LL;
146 if(wall_time_simulation_speed.get_value()) {
147 SCCDEBUG(SCMOD) <<
"Running in wall time mode";
148#if defined __x86_64__
149 auto duration = usecs_to_sleep;
150 auto checkpoint_us = get_time_of_day_us();
152 wait(usecs_to_sleep, sc_core::SC_US);
153 auto act_us = get_time_of_day_us();
154 auto consumed = act_us - checkpoint_us;
155 if(consumed > 0 && duration > consumed) {
157 tv.tv_sec =
static_cast<time_t
>(duration - consumed) / 1000000;
158 tv.tv_nsec =
static_cast<decltype(tv.tv_nsec)
>((duration - consumed) * 1000);
161 checkpoint_us = get_time_of_day_us();
164 std::posix_time::time_duration duration = std::posix_time::microsec(usecsToSleep);
165 std::posix_time::ptime checkpoint = std::posix_time::microsec_clock::local_time();
167 wait(usecsToSleep, sc_core::SC_US);
168 std::posix_time::time_duration consumed = std::posix_time::microsec_clock::local_time() - checkpoint;
169 if(duration > consumed) {
170 std::this_thread::sleep(duration - consumed);
172 checkpoint = std::posix_time::microsec_clock::local_time();
176 SCCDEBUG(SCMOD) <<
"Running in simulated time mode";
178 while(next_time_stamp.empty()) {
179 wait(sc_core::SC_ZERO_TIME);
180 std::this_thread::yield();
182 auto next = *next_time_stamp.front();
183 SCCTRACEALL(SCMOD) <<
"Got time stamp, advancing to " << next;
184 next_time_stamp.pop();
185 if(next > sc_core::sc_time_stamp()) {
186 wait(next - sc_core::sc_time_stamp());
192tlm::scc::tlm_gp_shared_ptr tcp4tlm_server::init_gp(
const tcp4tlm::BusOpMsg*
const msg) {
195 gp->set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
196 gp->set_address(msg->address());
197 gp->set_streaming_width(msg->size());
198 gp->set_data_length(msg->size());
199 ext->set_size(msg->size());
200 gp->set_data_ptr(ext->get_buf_ptr());
201 if(msg->data() ==
nullptr || msg->data()->size() == 0) {
202 gp->set_command(tlm::TLM_READ_COMMAND);
204 gp->set_command(tlm::TLM_WRITE_COMMAND);
205 std::memcpy(gp->get_data_ptr(), msg->data()->Data(), gp->get_data_length());
210void tcp4tlm_server::server_receive_completed(con_ptr& con,
const tcp4tlm::request_message*
const result) {
211 const auto* request = result ? result->root() :
nullptr;
212 if(request ==
nullptr) {
213 auto msg = tcp4tlm::make_response(uint32_t{0}, tcp4tlm::declined);
214 con->async_write(msg);
218 auto okmsg = tcp4tlm::make_response(request);
219 switch(request->payload_type()) {
220 case tcp4tlm::RequestPayload_NotifyEndpointMsg: {
221 SCCTRACE(SCMOD) <<
"Got NotifyEndpointMsg";
222 const auto* msg = request->payload_as_NotifyEndpointMsg();
223 callback_task task([
this, msg, con]() {
224 auto okmsg = tcp4tlm::make_response(msg->id());
225 con->async_write(okmsg);
228 timed_task tup{std::move(task), sc_core::SC_ZERO_TIME};
229 task_que.emplace(std::move(tup));
230 con_est.store(
true, std::memory_order_acq_rel);
231 con_est_sig.notify_all();
233 case tcp4tlm::RequestPayload_BusOpMsg: {
234 SCCTRACE(SCMOD) <<
"Got BusOpMsg";
235 const auto* msg = request->payload_as_BusOpMsg();
236 auto time_point = sc_core::sc_time::from_value(msg->time_stamp());
237 callback_task task([
this, msg, con]() {
238 auto gp = init_gp(msg);
239 auto delay = sc_core::sc_time::from_value(msg->time_offset());
240 isckt->b_transport(*gp, delay);
243 auto dmsg = tcp4tlm::make_bus_data_msg(msg->id(), ext->data(),
244 gp->get_response_status() == tlm::TLM_OK_RESPONSE ? tcp4tlm::ok : tcp4tlm::failure);
245 con->async_write(dmsg);
246 }
else if(gp->get_response_status() != tlm::TLM_OK_RESPONSE) {
247 auto failmsg = tcp4tlm::make_response(msg->id(), tcp4tlm::failure);
248 con->async_write(failmsg);
249 }
else if(!msg->no_response()) {
250 auto okmsg = tcp4tlm::make_response(msg->id());
251 con->async_write(okmsg);
255 std::future<bool> fut = task.get_future();
256 timed_task tup{std::move(task), time_point};
257 task_que.emplace(std::move(tup));
258 next_time_stamp.push(time_point);
262 case tcp4tlm::RequestPayload_SyncMsg: {
263 SCCTRACE(SCMOD) <<
"Got SyncMsg";
264 const auto* msg = request->payload_as_SyncMsg();
265 auto time_point = sc_core::sc_time::from_value(msg->time_stamp());
266 next_time_stamp.push(time_point);
269 case tcp4tlm::RequestPayload_SigOpMsg: {
270 SCCTRACE(SCMOD) <<
"Got SigOpMsg";
271 const auto* msg = request->payload_as_SigOpMsg();
272 if(signals.size() > msg->index()) {
273 callback_task task([
this, &msg]() {
274 signals[msg->index()] = msg->value();
277 std::future<bool> fut = task.get_future();
278 timed_task tup{std::move(task), sc_core::SC_ZERO_TIME};
279 task_que.emplace(std::move(tup));
282 con->async_write(okmsg);
284 auto declined_msg = tcp4tlm::make_response(request, tcp4tlm::declined);
285 con->async_write(declined_msg);
288 case tcp4tlm::RequestPayload_NotifyShutdownMsg: {
289 SCCTRACE(SCMOD) <<
"Got NotifyShutdownMsg";
290 if(is_server_running()) {
293 callback_task task([
this]() {
294 this->shutdown_evt.notify(sc_core::SC_ZERO_TIME);
297 std::future<bool> fut = task.get_future();
298 timed_task tup{std::move(task), sc_core::SC_ZERO_TIME};
299 task_que.emplace(std::move(tup));
305 SCCWARN(SCMOD) <<
"Got an unhandled message";
306 auto msg = tcp4tlm::make_response(request, tcp4tlm::declined);
307 con->async_write(msg);
313void tcp4tlm_server::process_task_que() {
316 while(task_que.try_get(res)) {
317 SCCTRACEALL(SCMOD) <<
"Got a task @" << res.timepoint;
318 if(no_systemc_sync.get_value() || sc_core::sc_time_stamp() > res.timepoint) {
321 auto time_point = res.timepoint - sc_core::sc_time_stamp();
322 timed_task_que.notify(std::move(res.t), time_point);
325 wait(task_que.data_event());
329void tcp4tlm_server::process_timed_task_que() {
331 wait(timed_task_que.event());
332 auto task = timed_task_que.get();
333 SCCTRACEALL(SCMOD) <<
"Executing a task";
Extension for data buffering.