File net_delay.h
File List > includes > net_delay.h
Go to the documentation of this file.
#pragma once
#include <fstream>
#include <map>
#include "global_define.h"
#include "spdlog/spdlog.h"
#define PAC_PAYLOAD_BIT 512
#define PAC_PAYLOAD_BYTE (PAC_PAYLOAD_BIT / 8)
class NetworkDelayItem {
public:
InterChiplet::InnerTimeType m_cycle;
uint64_t m_id;
InterChiplet::AddrType m_src;
InterChiplet::AddrType m_dst;
long m_desc;
std::vector<InterChiplet::InnerTimeType> m_delay_list;
public:
NetworkDelayItem() {}
NetworkDelayItem(InterChiplet::InnerTimeType __cycle, const InterChiplet::AddrType& __src,
const InterChiplet::AddrType& __dst, long __desc,
const std::vector<InterChiplet::InnerTimeType>& __delay_list)
: m_cycle(__cycle), m_dst(__dst), m_src(__src), m_delay_list(__delay_list) {}
friend std::ostream& operator<<(std::ostream& os, const NetworkDelayItem& __item) {
os << __item.m_cycle << " " << DIM_X(__item.m_src) << " " << DIM_Y(__item.m_src) << " "
<< DIM_Y(__item.m_dst) << " " << DIM_X(__item.m_dst) << " " << __item.m_desc << " "
<< __item.m_delay_list.size();
for (auto& delay : __item.m_delay_list) {
os << " " << delay;
}
return os;
}
friend std::istream& operator>>(std::istream& os, NetworkDelayItem& __item) {
os >> __item.m_cycle;
long src_x, src_y, dst_x, dst_y;
os >> src_x >> src_y >> dst_x >> dst_y;
__item.m_src.push_back(src_x);
__item.m_src.push_back(src_y);
__item.m_dst.push_back(dst_x);
__item.m_dst.push_back(dst_y);
os >> __item.m_desc;
int delay_cnt = 0;
os >> delay_cnt;
for (int i = 0; i < delay_cnt; i++) {
InterChiplet::TimeType delay;
os >> delay;
__item.m_delay_list.push_back(delay);
}
return os;
}
};
typedef std::tuple<InterChiplet::InnerTimeType, InterChiplet::InnerTimeType> CmdDelayPair;
#define SRC_DELAY(pair) std::get<0>(pair)
#define DST_DELAY(pair) std::get<1>(pair)
typedef std::multimap<InterChiplet::InnerTimeType, NetworkDelayItem> NetworkDelayOrder;
class NetworkDelayMap : public std::map<InterChiplet::AddrType, NetworkDelayOrder> {
public:
void insert(const InterChiplet::AddrType& __addr, InterChiplet::InnerTimeType __cycle,
const NetworkDelayItem& __item) {
if (find(__addr) == end()) {
(*this)[__addr] = NetworkDelayOrder();
}
(*this)[__addr].insert(
std::pair<InterChiplet::InnerTimeType, NetworkDelayItem>(__cycle, __item));
}
bool hasAddr(const InterChiplet::AddrType& __addr) {
// If there is no address, return false.
if (find(__addr) == end()) {
return false;
}
// If there is no delay information for the address, return false.
return at(__addr).size() > 0;
}
bool hasAddr(const InterChiplet::AddrType& __addr, const InterChiplet::AddrType& __src,
const InterChiplet::AddrType& __dst) {
// If there is no address, return false.
if (find(__addr) == end()) {
return false;
}
// If there is no delay information for the address, return false.
for (NetworkDelayOrder::iterator it = (*this)[__addr].begin(); it != (*this)[__addr].end();
it++) {
if (it->second.m_src == __src && it->second.m_dst == __dst) {
return true;
}
}
return false;
}
NetworkDelayItem front(const InterChiplet::AddrType& __addr) {
// If there is no destination address, return empty.
if (find(__addr) == end()) {
return NetworkDelayItem();
}
// If there is no delay information for the address, return false.
if (at(__addr).size() == 0) {
return NetworkDelayItem();
}
return at(__addr).begin()->second;
}
NetworkDelayItem front(const InterChiplet::AddrType& __addr,
const InterChiplet::AddrType& __src,
const InterChiplet::AddrType& __dst) {
// If there is no destination address, return empty.
if (find(__addr) == end()) {
return NetworkDelayItem();
}
// If there is no delay information for the address, return false.
for (NetworkDelayOrder::iterator it = (*this)[__addr].begin(); it != (*this)[__addr].end();
it++) {
if (it->second.m_src == __src && it->second.m_dst == __dst) {
return it->second;
}
}
return NetworkDelayItem();
}
void pop(const InterChiplet::AddrType& __addr) {
// If there is no destination address, do nothing.
if (find(__addr) == end()) {
return;
}
// If there is no delay information for the address, do nothing.
if (at(__addr).size() == 0) {
return;
}
at(__addr).erase(at(__addr).begin());
}
void pop(const InterChiplet::AddrType& __addr, const InterChiplet::AddrType& __src,
const InterChiplet::AddrType& __dst) {
// If there is no destination address, do nothing.
if (find(__addr) == end()) {
return;
}
// If there is no delay information for the address, return false.
for (NetworkDelayOrder::iterator it = (*this)[__addr].begin(); it != (*this)[__addr].end();
it++) {
if (it->second.m_src == __src && it->second.m_dst == __dst) {
(*this)[__addr].erase(it);
return;
}
}
}
bool checkOrderOfCommand(const InterChiplet::SyncCommand& __cmd) {
// If the source does not exist, return false.
if (find(__cmd.m_src) == end()) {
return true;
}
// If the source has no packet, return false.
if ((*this)[__cmd.m_src].size() == 0) {
return true;
}
NetworkDelayItem& delay_item = (*this)[__cmd.m_src].begin()->second;
// Return true if command matches the first item in delay information list.
if (delay_item.m_src == __cmd.m_src && delay_item.m_dst == __cmd.m_dst &&
delay_item.m_desc == __cmd.m_desc) {
return true;
} else {
spdlog::warn("Delay info from {},{} to {},{} with flag {}.", delay_item.m_src[0],
delay_item.m_src[1], delay_item.m_dst[0], delay_item.m_dst[1],
delay_item.m_desc);
spdlog::warn("Command from {},{} to {},{} with flag {}.", __cmd.m_src[0],
__cmd.m_src[1], __cmd.m_dst[0], __cmd.m_dst[1], __cmd.m_desc);
return false;
}
}
};
class NetworkDelayStruct {
public:
NetworkDelayStruct() : m_item_count(0) {}
int size() const { return m_item_count; }
public:
void loadDelayInfo(const std::string& __file_name, double __clock_rate) {
std::ifstream bench_if(__file_name, std::ios::in);
m_item_count = 0;
while (bench_if) {
// Load item from file.
NetworkDelayItem item;
bench_if >> item;
if (!bench_if) break;
item.m_cycle = item.m_cycle / __clock_rate;
for (std::size_t i = 0; i < item.m_delay_list.size(); i++) {
item.m_delay_list[i] = item.m_delay_list[i] / __clock_rate;
}
m_item_count += 1;
// Source map.
m_src_delay_map.insert(item.m_src, item.m_cycle, item);
// Ordering of barrier, launch, lock and unlock.
if (item.m_desc & 0xF0000) {
InterChiplet::InnerTimeType end_cycle = item.m_cycle + item.m_delay_list[1];
if (item.m_desc & InterChiplet::SPD_BARRIER) {
m_barrier_delay_map.insert(item.m_dst, end_cycle, item);
} else if (item.m_desc & InterChiplet::SPD_LAUNCH) {
m_launch_delay_map.insert(item.m_dst, end_cycle, item);
} else if (item.m_desc & InterChiplet::SPD_LOCK) {
m_lock_delay_map.insert(item.m_dst, end_cycle, item);
} else if (item.m_desc & InterChiplet::SPD_UNLOCK) {
m_unlock_delay_map.insert(item.m_dst, end_cycle, item);
}
}
}
}
bool checkOrderOfCommand(const InterChiplet::SyncCommand& __cmd) {
return m_src_delay_map.checkOrderOfCommand(__cmd);
}
void clearDelayInfo() {
// Launch delay list
m_src_delay_map.clear();
// Launch order.
m_launch_delay_map.clear();
// Barrier order.
m_barrier_delay_map.clear();
// Lock order.
m_lock_delay_map.clear();
// Unlock order.
m_unlock_delay_map.clear();
}
public:
inline bool hasLaunch(const InterChiplet::AddrType& __dst) {
return m_launch_delay_map.hasAddr(__dst);
}
inline InterChiplet::AddrType frontLaunchSrc(const InterChiplet::AddrType& __dst) {
return m_launch_delay_map.front(__dst).m_src;
}
inline void popLaunch(const InterChiplet::AddrType& __dst) { m_launch_delay_map.pop(__dst); }
inline bool hasLock(const InterChiplet::AddrType& __dst) {
return m_lock_delay_map.hasAddr(__dst);
}
inline InterChiplet::AddrType frontLockSrc(const InterChiplet::AddrType& __dst) {
return m_lock_delay_map.front(__dst).m_src;
}
inline void popLock(const InterChiplet::AddrType& __dst) { m_lock_delay_map.pop(__dst); }
public:
CmdDelayPair getEndCycle(const InterChiplet::SyncCommand& __write_cmd,
const InterChiplet::SyncCommand& __read_cmd) {
if (!m_src_delay_map.hasAddr(__write_cmd.m_src, __write_cmd.m_src, __write_cmd.m_dst)) {
return getDefaultEndCycle(__write_cmd, __read_cmd);
}
NetworkDelayItem delay_info =
m_src_delay_map.front(__write_cmd.m_src, __write_cmd.m_src, __write_cmd.m_dst);
m_src_delay_map.pop(__write_cmd.m_src, __write_cmd.m_src, __write_cmd.m_dst);
// Launch/Barrier/Lock/Unlock communication.
if (__write_cmd.m_desc & (InterChiplet::SPD_LAUNCH | InterChiplet::SPD_BARRIER |
InterChiplet::SPD_LOCK | InterChiplet::SPD_UNLOCK)) {
// Forward packet.
InterChiplet::InnerTimeType pac_delay_src = delay_info.m_delay_list[0];
InterChiplet::InnerTimeType pac_delay_dst = delay_info.m_delay_list[1];
InterChiplet::InnerTimeType write_end_time = __write_cmd.m_cycle + pac_delay_src;
InterChiplet::InnerTimeType read_end_time = __write_cmd.m_cycle + pac_delay_dst;
if (__read_cmd.m_cycle > read_end_time) {
read_end_time = __read_cmd.m_cycle;
}
// Acknowledge packet.
InterChiplet::InnerTimeType ack_delay_src = delay_info.m_delay_list[2];
InterChiplet::InnerTimeType ack_delay_dst = delay_info.m_delay_list[3];
read_end_time = read_end_time + ack_delay_src;
write_end_time = read_end_time - ack_delay_src + ack_delay_dst;
return CmdDelayPair(write_end_time, read_end_time);
}
// Normal communication.
else {
// Forward packet.
InterChiplet::InnerTimeType pac_delay_src = delay_info.m_delay_list[0];
InterChiplet::InnerTimeType pac_delay_dst = delay_info.m_delay_list[1];
InterChiplet::InnerTimeType write_end_time = __write_cmd.m_cycle + pac_delay_src;
InterChiplet::InnerTimeType read_end_time = __write_cmd.m_cycle + pac_delay_dst;
if (__read_cmd.m_cycle > read_end_time) {
read_end_time = __read_cmd.m_cycle;
}
return CmdDelayPair(write_end_time, read_end_time);
}
}
InterChiplet::InnerTimeType getBarrierCycle(
const std::vector<InterChiplet::SyncCommand>& barrier_items) {
InterChiplet::InnerTimeType barrier_cycle = 0;
for (auto& item : barrier_items) {
InterChiplet::InnerTimeType t_cycle = 0;
if (!m_src_delay_map.hasAddr(item.m_src, item.m_src, item.m_dst)) {
t_cycle = getDefaultEndCycle(item);
} else {
NetworkDelayItem delay_info =
m_src_delay_map.front(item.m_src, item.m_src, item.m_dst);
t_cycle = delay_info.m_cycle + delay_info.m_delay_list[1];
}
if (t_cycle > barrier_cycle) {
barrier_cycle = t_cycle;
}
}
return barrier_cycle;
}
public:
InterChiplet::InnerTimeType getDefaultEndCycle(const InterChiplet::SyncCommand& write_cmd) {
// TODO: Get more accurate end cycle.
int pac_size = write_cmd.m_nbytes / PAC_PAYLOAD_BYTE +
((write_cmd.m_nbytes % PAC_PAYLOAD_BYTE) > 0 ? 1 : 0) + 1;
return write_cmd.m_cycle + pac_size;
}
CmdDelayPair getDefaultEndCycle(const InterChiplet::SyncCommand& write_cmd,
const InterChiplet::SyncCommand& read_cmd) {
// TODO: Get more accurate end cycle.
int pac_size = write_cmd.m_nbytes / PAC_PAYLOAD_BYTE +
((write_cmd.m_nbytes % PAC_PAYLOAD_BYTE) > 0 ? 1 : 0) + 1;
if (write_cmd.m_cycle >= read_cmd.m_cycle) {
return CmdDelayPair(write_cmd.m_cycle + pac_size, write_cmd.m_cycle + pac_size);
} else {
return CmdDelayPair(read_cmd.m_cycle + pac_size, read_cmd.m_cycle + pac_size);
}
}
private:
int m_item_count;
NetworkDelayMap m_src_delay_map;
NetworkDelayMap m_launch_delay_map;
NetworkDelayMap m_barrier_delay_map;
NetworkDelayMap m_lock_delay_map;
NetworkDelayMap m_unlock_delay_map;
};