123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552 |
- #include "network_model_emesh_hop_by_hop.h"
- #include "core.h"
- #include "simulator.h"
- #include "config.h"
- #include "utils.h"
- #include "packet_type.h"
- #include "queue_model_history_list.h"
- #include "memory_manager_base.h"
- #include "dvfs_manager.h"
- #include "stats.h"
- #include "config.hpp"
- #include <math.h>
- #include <stdlib.h>
- const char* output_direction_names[] = {
- "up", "down", "left", "right", "---", "self", "peer", "destination"
- };
- static_assert(NetworkModelEMeshHopByHop::MAX_OUTPUT_DIRECTIONS == sizeof(output_direction_names) / sizeof(output_direction_names[0]),
- "Not enough values in output_direction_names");
- const char* OutputDirectionString(NetworkModelEMeshHopByHop::OutputDirection direction)
- {
- LOG_ASSERT_ERROR(direction < NetworkModelEMeshHopByHop::MAX_OUTPUT_DIRECTIONS, "Invalid output direction %d", direction);
- return output_direction_names[direction];
- }
- NetworkModelEMeshHopByHop::NetworkModelEMeshHopByHop(Network* net, EStaticNetwork net_type):
- NetworkModel(net, net_type),
- m_enabled(false),
- m_total_bytes_sent(0),
- m_total_packets_sent(0),
- m_total_bytes_received(0),
- m_total_packets_received(0),
- m_total_contention_delay(SubsecondTime::Zero()),
- m_total_packet_latency(SubsecondTime::Zero()),
- m_fake_node(false),
- m_core_id(getNetwork()->getCore()->getId()),
- // Placeholders. These values will be overwritten in a derived class.
- m_link_bandwidth(Sim()->getDvfsManager()->getCoreDomain(m_core_id), 0),
- m_hop_latency(Sim()->getDvfsManager()->getCoreDomain(m_core_id), 0)
- {
- // Get the Link Bandwidth, Hop Latency and if it has broadcast tree mechanism
- try
- {
- // Link Bandwidth is specified in bits/clock_cycle
- m_link_bandwidth = ComponentBandwidthPerCycle(Sim()->getDvfsManager()->getCoreDomain(m_core_id), Sim()->getCfg()->getInt("network/emesh_hop_by_hop/link_bandwidth"));
- // Hop Latency is specified in cycles
- m_hop_latency = ComponentLatency(Sim()->getDvfsManager()->getCoreDomain(m_core_id), Sim()->getCfg()->getInt("network/emesh_hop_by_hop/hop_latency"));
- UInt32 smt_cores = Sim()->getCfg()->getInt("perf_model/core/logical_cpus");
- m_concentration = Sim()->getCfg()->getInt("network/emesh_hop_by_hop/concentration") * smt_cores;
- m_dimensions = Sim()->getCfg()->getInt("network/emesh_hop_by_hop/dimensions");
- m_wrap_around = Sim()->getCfg()->getBool("network/emesh_hop_by_hop/wrap_around");
- // Queue Model enabled? If no, this degrades into a hop counter model
- m_queue_model_enabled = Sim()->getCfg()->getBool("network/emesh_hop_by_hop/queue_model/enabled");
- m_queue_model_type = Sim()->getCfg()->getString("network/emesh_hop_by_hop/queue_model/type");
- m_broadcast_tree_enabled = Sim()->getCfg()->getBool("network/emesh_hop_by_hop/broadcast_tree/enabled");
- }
- catch(...)
- {
- LOG_PRINT_ERROR("Could not read parameters from the configuration file");
- }
- String name = String("network.")+EStaticNetworkStrings[net_type]+".mesh";
- registerStatsMetric(name, m_core_id, "bytes-out", &m_total_bytes_sent);
- registerStatsMetric(name, m_core_id, "packets-out", &m_total_packets_sent);
- registerStatsMetric(name, m_core_id, "bytes-in", &m_total_bytes_received);
- registerStatsMetric(name, m_core_id, "packets-in", &m_total_packets_received);
- registerStatsMetric(name, m_core_id, "contention-delay", &m_total_contention_delay);
- registerStatsMetric(name, m_core_id, "total-delay", &m_total_packet_latency);
- computeMeshDimensions(m_mesh_width, m_mesh_height);
- if (m_core_id % m_concentration != 0 || m_core_id >= m_concentration * m_mesh_width * m_mesh_height)
- {
- m_fake_node = true;
- return;
- }
- createQueueModels(name);
- }
- NetworkModelEMeshHopByHop::~NetworkModelEMeshHopByHop()
- {
- if (m_fake_node)
- return;
- for (UInt32 i = 0; i < NUM_OUTPUT_DIRECTIONS; i++)
- {
- if (m_queue_models[i])
- delete m_queue_models[i];
- }
- delete m_injection_port_queue_model;
- delete m_ejection_port_queue_model;
- }
- void
- NetworkModelEMeshHopByHop::createQueueModels(String name)
- {
- SubsecondTime min_processing_time = m_link_bandwidth.getPeriod();
- // Initialize the queue models for all the '4' output directions
- m_queue_models[DOWN] = QueueModel::create(name+".link-down", m_core_id, m_queue_model_type, min_processing_time);
- m_queue_models[LEFT] = QueueModel::create(name+".link-left", m_core_id, m_queue_model_type, min_processing_time);
- m_queue_models[UP] = QueueModel::create(name+".link-up", m_core_id, m_queue_model_type, min_processing_time);
- m_queue_models[RIGHT] = QueueModel::create(name+".link-right", m_core_id, m_queue_model_type, min_processing_time);
- m_injection_port_queue_model = QueueModel::create(name+".link-in", m_core_id, m_queue_model_type, min_processing_time);
- m_ejection_port_queue_model = QueueModel::create(name+".link-out", m_core_id, m_queue_model_type, min_processing_time);
- }
- void
- NetworkModelEMeshHopByHop::routePacket(const NetPacket &pkt, std::vector<Hop> &nextHops)
- {
- ScopedLock sl(m_lock);
- core_id_t requester = INVALID_CORE_ID;
- if (pkt.type == SHARED_MEM_1)
- requester = getNetwork()->getCore()->getMemoryManager()->getShmemRequester(pkt.data);
- else // Other Packet types
- requester = pkt.sender;
- LOG_ASSERT_ERROR((requester >= 0) && (requester < (core_id_t) Config::getSingleton()->getTotalCores()),
- "requester(%i)", requester);
- UInt32 pkt_length = getNetwork()->getModeledLength(pkt);
- LOG_PRINT("pkt length(%u)", pkt_length);
- if (pkt.sender == m_core_id)
- {
- m_total_packets_sent ++;
- m_total_bytes_sent += pkt_length;
- }
- if (pkt.receiver == NetPacket::BROADCAST)
- {
- if (m_fake_node)
- {
- for (core_id_t i = 0; i < (core_id_t) Config::getSingleton()->getTotalCores(); i++)
- {
- addHop(DESTINATION, i, i, pkt.time, pkt_length, nextHops, requester);
- }
- }
- else if (m_broadcast_tree_enabled)
- {
- // Injection Port Modeling
- SubsecondTime injection_port_queue_delay = SubsecondTime::Zero();
- if (pkt.sender == m_core_id)
- injection_port_queue_delay = computeInjectionPortQueueDelay(pkt.receiver, pkt.time, pkt_length);
- SubsecondTime curr_time = pkt.time + injection_port_queue_delay;
- // Broadcast tree is enabled
- // Build the broadcast tree
- SInt32 sx, sy, cx, cy;
- computePosition(pkt.sender, sx, sy);
- computePosition(m_core_id, cx, cy);
- if (cy >= sy)
- addHop(UP, NetPacket::BROADCAST, computeCoreId(cx,cy+1), curr_time, pkt_length, nextHops, requester);
- if (cy <= sy)
- addHop(DOWN, NetPacket::BROADCAST, computeCoreId(cx,cy-1), curr_time, pkt_length, nextHops, requester);
- if (cy == sy)
- {
- if (cx >= sx)
- addHop(RIGHT, NetPacket::BROADCAST, computeCoreId(cx+1,cy), curr_time, pkt_length, nextHops, requester);
- if (cx <= sx)
- addHop(LEFT, NetPacket::BROADCAST, computeCoreId(cx-1,cy), curr_time, pkt_length, nextHops, requester);
- if (cx == sx)
- addHop(SELF, m_core_id, m_core_id, curr_time, pkt_length, nextHops, requester);
- }
- }
- else
- {
- // Broadcast tree is not enabled
- // Here, broadcast messages are sent as a collection of unicast messages
- LOG_ASSERT_ERROR(pkt.sender == m_core_id,
- "BROADCAST message to be sent at (%i), original sender(%i), Tree not enabled",
- m_core_id, pkt.sender);
- for (core_id_t i = 0; i < (core_id_t) Config::getSingleton()->getTotalCores(); i++)
- {
- // Injection Port Modeling
- SubsecondTime injection_port_queue_delay = computeInjectionPortQueueDelay(i, pkt.time, pkt_length);
- SubsecondTime curr_time = pkt.time + injection_port_queue_delay;
- // Unicast message to each core
- OutputDirection direction;
- core_id_t next_dest = getNextDest(i, direction);
- addHop(direction, i, next_dest, curr_time, pkt_length, nextHops, requester);
- }
- }
- }
- else if (m_fake_node)
- {
- addHop(DESTINATION, pkt.receiver, pkt.receiver, pkt.time, pkt_length, nextHops, requester);
- }
- else
- {
- // Injection Port Modeling
- SubsecondTime injection_port_queue_delay = SubsecondTime::Zero();
- if (pkt.sender == m_core_id)
- {
- injection_port_queue_delay = computeInjectionPortQueueDelay(pkt.receiver, pkt.time, pkt_length);
- *(subsecond_time_t*)&pkt.queue_delay += injection_port_queue_delay;
- }
- SubsecondTime curr_time = pkt.time + injection_port_queue_delay;
- // A Unicast packet
- OutputDirection direction;
- core_id_t next_dest = getNextDest(pkt.receiver, direction);
- addHop(direction, pkt.receiver, next_dest, curr_time, pkt_length, nextHops, requester, (subsecond_time_t*)&pkt.queue_delay);
- }
- }
- void
- NetworkModelEMeshHopByHop::processReceivedPacket(NetPacket& pkt)
- {
- ScopedLock sl(m_lock);
- UInt32 pkt_length = getNetwork()->getModeledLength(pkt);
- core_id_t requester = INVALID_CORE_ID;
- if (pkt.type == SHARED_MEM_1)
- requester = getNetwork()->getCore()->getMemoryManager()->getShmemRequester(pkt.data);
- else // Other Packet types
- requester = pkt.sender;
- LOG_ASSERT_ERROR((requester >= 0) && (requester < (core_id_t) Config::getSingleton()->getTotalCores()),
- "requester(%i)", requester);
- if ( (!m_enabled) || (requester >= (core_id_t) Config::getSingleton()->getApplicationCores())
- || (m_core_id >= (core_id_t) Config::getSingleton()->getApplicationCores()))
- return;
- SubsecondTime packet_latency = pkt.time - pkt.start_time;
- SubsecondTime contention_delay = packet_latency - (computeDistance(pkt.sender, m_core_id) * m_hop_latency.getLatency());
- if (pkt.sender != m_core_id && !m_fake_node)
- {
- SubsecondTime processing_time = computeProcessingTime(pkt_length);
- SubsecondTime ejection_port_queue_delay = computeEjectionPortQueueDelay(pkt.time, pkt_length);
- packet_latency += (ejection_port_queue_delay + processing_time);
- contention_delay += ejection_port_queue_delay;
- pkt.time += (ejection_port_queue_delay + processing_time);
- pkt.queue_delay += ejection_port_queue_delay;
- }
- m_total_packets_received ++;
- m_total_bytes_received += pkt_length;
- m_total_packet_latency += packet_latency;
- m_total_contention_delay += contention_delay;
- }
- void
- NetworkModelEMeshHopByHop::addHop(OutputDirection direction,
- core_id_t final_dest, core_id_t next_dest,
- SubsecondTime pkt_time, UInt32 pkt_length,
- std::vector<Hop>& nextHops, core_id_t requester,
- subsecond_time_t *queue_delay_stats)
- {
- Hop h;
- h.final_dest = final_dest;
- h.next_dest = next_dest;
- if (direction > NUM_OUTPUT_DIRECTIONS)
- h.time = pkt_time;
- else
- h.time = pkt_time + computeLatency(direction, pkt_time, pkt_length, requester, queue_delay_stats);
- nextHops.push_back(h);
- }
- SInt32
- NetworkModelEMeshHopByHop::computeDistance(core_id_t sender, core_id_t receiver)
- {
- SInt32 sx, sy, dx, dy;
- computePosition(sender, sx, sy);
- computePosition(receiver, dx, dy);
- if (m_wrap_around)
- return std::min(abs(sx - dx), m_mesh_width - abs(sx - dx))
- + std::min(abs(sy - dy), m_mesh_height - abs(sy - dy));
- else
- return abs(sx - dx) + abs(sy - dy);
- }
- void
- NetworkModelEMeshHopByHop::computePosition(core_id_t core_id, SInt32 &x, SInt32 &y)
- {
- x = (core_id / m_concentration) % m_mesh_width;
- y = (core_id / m_concentration) / m_mesh_width;
- }
- core_id_t
- NetworkModelEMeshHopByHop::computeCoreId(SInt32 x, SInt32 y)
- {
- x = (x + m_mesh_width) % m_mesh_width;
- y = (y + m_mesh_height) % m_mesh_height;
- return (y * m_mesh_width + x) * m_concentration;
- }
- SubsecondTime
- NetworkModelEMeshHopByHop::computeLatency(OutputDirection direction, SubsecondTime pkt_time, UInt32 pkt_length, core_id_t requester, subsecond_time_t *queue_delay_stats)
- {
- LOG_ASSERT_ERROR(!m_fake_node, "Cannot computeLatency on a fake network node");
- LOG_ASSERT_ERROR((direction >= 0) && (direction < NUM_OUTPUT_DIRECTIONS),
- "Invalid Direction(%u)", direction);
- if ( (!m_enabled) || (requester >= (core_id_t) Config::getSingleton()->getApplicationCores()) )
- return SubsecondTime::Zero();
- SubsecondTime processing_time = computeProcessingTime(pkt_length);
- SubsecondTime queue_delay = SubsecondTime::Zero();
- if (m_queue_model_enabled)
- {
- queue_delay = m_queue_models[direction]->computeQueueDelay(pkt_time, processing_time);
- if (queue_delay_stats)
- *queue_delay_stats += queue_delay;
- }
- LOG_PRINT("Queue Delay(%s), Hop Latency(%s)", itostr(queue_delay).c_str(), itostr(m_hop_latency.getLatency()).c_str());
- SubsecondTime packet_latency = m_hop_latency.getLatency() + queue_delay;
- return packet_latency;
- }
- SubsecondTime
- NetworkModelEMeshHopByHop::computeInjectionPortQueueDelay(core_id_t pkt_receiver, SubsecondTime pkt_time, UInt32 pkt_length)
- {
- LOG_ASSERT_ERROR(!m_fake_node, "Cannot computeInjectionPortQueueDelay on a fake network node");
- if (!m_queue_model_enabled)
- return SubsecondTime::Zero();
- if (pkt_receiver == m_core_id)
- return SubsecondTime::Zero();
- SubsecondTime processing_time = computeProcessingTime(pkt_length);
- return m_injection_port_queue_model->computeQueueDelay(pkt_time, processing_time);
- }
- SubsecondTime
- NetworkModelEMeshHopByHop::computeEjectionPortQueueDelay(SubsecondTime pkt_time, UInt32 pkt_length)
- {
- LOG_ASSERT_ERROR(!m_fake_node, "Cannot computeEjectionPortQueueDelay on a fake network node");
- if (!m_queue_model_enabled)
- return SubsecondTime::Zero();
- SubsecondTime processing_time = computeProcessingTime(pkt_length);
- return m_ejection_port_queue_model->computeQueueDelay(pkt_time, processing_time);
- }
- SubsecondTime
- NetworkModelEMeshHopByHop::computeProcessingTime(UInt32 pkt_length)
- {
- LOG_ASSERT_ERROR(!m_fake_node, "Cannot computeProcessingTime on a fake network node");
- // Send: (pkt_length * 8) bits
- // Bandwidth: (m_link_bandwidth) bits/cycle
- UInt32 num_bits = pkt_length * 8;
- return m_link_bandwidth.getRoundedLatency(num_bits);
- }
- SInt32
- NetworkModelEMeshHopByHop::getNextDest(SInt32 final_dest, OutputDirection& direction)
- {
- // Do dimension-order routing
- // Curently, do store-and-forward routing
- // FIXME: Should change this to wormhole routing eventually
- if (final_dest >= (core_id_t)Config::getSingleton()->getApplicationCores())
- {
- // We are a fake core (not an application core): warp straight to the destination
- direction = DESTINATION;
- return final_dest;
- }
- else if (m_core_id / m_concentration == final_dest / m_concentration)
- {
- // Destination is self, a peer on our concentrated node
- direction = DESTINATION;
- return final_dest;
- }
- else if (m_fake_node)
- {
- // We are a concentrated node but not the master: first send to master
- direction = PEER;
- return m_core_id - m_core_id % m_concentration;
- }
- SInt32 sx, sy, dx, dy;
- computePosition(m_core_id, sx, sy);
- computePosition(final_dest, dx, dy);
- if ((sx > dx) ^ (m_wrap_around && abs(sx - dx) > (m_mesh_width+1) / 2))
- {
- direction = LEFT;
- return computeCoreId(sx-1,sy);
- }
- else if (sx != dx)
- {
- direction = RIGHT;
- return computeCoreId(sx+1,sy);
- }
- else if ((sy > dy) ^ (m_wrap_around && abs(sy - dy) > (m_mesh_height+1) / 2))
- {
- direction = DOWN;
- return computeCoreId(sx,sy-1);
- }
- else if (sy != dy)
- {
- direction = UP;
- return computeCoreId(sx,sy+1);
- }
- else
- {
- // A send to itself
- direction = SELF;
- return m_core_id;
- }
- }
- void
- NetworkModelEMeshHopByHop::enable()
- {
- m_enabled = true;
- }
- void
- NetworkModelEMeshHopByHop::disable()
- {
- m_enabled = false;
- }
- bool
- NetworkModelEMeshHopByHop::isEnabled()
- {
- return m_enabled;
- }
- void
- NetworkModelEMeshHopByHop::computeMeshDimensions(SInt32 &mesh_width, SInt32 &mesh_height)
- {
- SInt32 core_count = Config::getSingleton()->getApplicationCores();
- UInt32 smt_cores = Sim()->getCfg()->getInt("perf_model/core/logical_cpus");
- SInt32 concentration = Sim()->getCfg()->getInt("network/emesh_hop_by_hop/concentration") * smt_cores;
- SInt32 dimensions = Sim()->getCfg()->getInt("network/emesh_hop_by_hop/dimensions");
- String size = Sim()->getCfg()->getString("network/emesh_hop_by_hop/size");
- if (size == "")
- {
- switch(dimensions)
- {
- case 1: // line / ring
- mesh_width = core_count / concentration;
- mesh_height = 1;
- break;
- case 2: // 2-d mesh / torus
- mesh_width = (SInt32) floor (sqrt(core_count / concentration));
- mesh_height = (SInt32) ceil (1.0 * core_count / concentration / mesh_width);
- break;
- default:
- LOG_PRINT_ERROR("Invalid value %d for dimensions, only 1 (line/ring) and 2 (mesh/torus) are currently supported", dimensions);
- }
- LOG_ASSERT_ERROR(core_count == (concentration * mesh_height * mesh_width), "Cannot build a mesh with %d cores (concentration %d), increase NumApplicationCores to %d for a %d x %d mesh or configure network/emesh_hop_by_hop/size=WIDTH:HEIGHT to manually specify mesh dimensions", core_count, concentration, concentration * mesh_width * mesh_height, mesh_width, mesh_height);
- }
- else
- {
- // ":"-separated, "," is for heterogeneity
- int res = sscanf(size.c_str(), "%d:%d", &mesh_width, &mesh_height);
- LOG_ASSERT_ERROR(res == 2, "Invalid mesh size \"%s\", expected \"width:height\"", size.c_str());
- LOG_ASSERT_ERROR(core_count == (concentration * mesh_height * mesh_width), "Invalid mesh size %s for %d cores (concentration %d): %d x %d (x %d) == %d != %d", size.c_str(), core_count, concentration, mesh_width, mesh_height, concentration, concentration * mesh_width * mesh_height, core_count);
- }
- }
- std::pair<bool,SInt32>
- NetworkModelEMeshHopByHop::computeCoreCountConstraints(SInt32 core_count)
- {
- SInt32 mesh_width, mesh_height;
- computeMeshDimensions(mesh_width, mesh_height);
- assert(core_count <= mesh_width * mesh_height);
- assert(core_count > (mesh_width - 1) * mesh_height);
- assert(core_count > mesh_width * (mesh_height - 1));
- return std::make_pair(true,mesh_height * mesh_width);
- }
- std::pair<bool, std::vector<core_id_t> >
- NetworkModelEMeshHopByHop::computeMemoryControllerPositions(SInt32 num_memory_controllers, SInt32 core_count)
- {
- UInt32 smt_cores = Sim()->getCfg()->getInt("perf_model/core/logical_cpus");
- SInt32 concentration = Sim()->getCfg()->getInt("network/emesh_hop_by_hop/concentration") * smt_cores;
- SInt32 dimensions = Sim()->getCfg()->getInt("network/emesh_hop_by_hop/dimensions");
- SInt32 mesh_width, mesh_height;
- computeMeshDimensions(mesh_width, mesh_height);
- // core_id_list_along_perimeter : list of cores along the perimeter of the chip in clockwise order starting from (0,0)
- std::vector<core_id_t> core_id_list_along_perimeter;
- for (SInt32 i = 0; i < mesh_width; i++)
- core_id_list_along_perimeter.push_back(i);
- if (dimensions > 1 && mesh_height > 1)
- {
- for (SInt32 i = 1; i < (mesh_height-1); i++)
- core_id_list_along_perimeter.push_back((i * mesh_width) + mesh_width-1);
- for (SInt32 i = mesh_width-1; i >= 0; i--)
- core_id_list_along_perimeter.push_back(((mesh_height-1) * mesh_width) + i);
- for (SInt32 i = mesh_height-2; i >= 1; i--)
- core_id_list_along_perimeter.push_back(i * mesh_width);
- assert(core_id_list_along_perimeter.size() == (UInt32) (2 * (mesh_width + mesh_height - 2)));
- }
- LOG_ASSERT_ERROR(core_id_list_along_perimeter.size() >= (UInt32) num_memory_controllers,
- "num cores along perimeter(%u), num memory controllers(%i)",
- core_id_list_along_perimeter.size(), num_memory_controllers);
- SInt32 spacing_between_memory_controllers = core_id_list_along_perimeter.size() / num_memory_controllers;
- // core_id_list_with_memory_controllers : list of cores that have memory controllers attached to them
- std::vector<core_id_t> core_id_list_with_memory_controllers;
- for (SInt32 i = 0; i < num_memory_controllers; i++)
- {
- SInt32 index = (i * spacing_between_memory_controllers + mesh_width/2) % core_id_list_along_perimeter.size();
- core_id_list_with_memory_controllers.push_back(concentration * core_id_list_along_perimeter[index]);
- }
- return (std::make_pair(true, core_id_list_with_memory_controllers));
- }
|