From 829bcb539f5c6668896eb788b97e38eda40de9f0 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Mon, 24 Mar 2025 14:34:38 -0700 Subject: [PATCH 01/47] misc: SRNoC model This is a model of a statically-scheduled circuit-switched NoC for superconductors. Modeled off the SRNoC paper by Michelogiannakis et al. --- src/network/DataCell.cc | 114 +++++++++ src/network/DataCell.hh | 56 +++++ src/network/DataCell.py | 9 + src/network/Layer.cc | 20 ++ src/network/Layer.hh | 23 ++ src/network/Layer.py | 12 + src/network/NetworkScheduler.cc | 166 +++++++++++++ src/network/NetworkScheduler.hh | 48 ++++ src/network/SConscript | 14 ++ src/network/SuperNetwork.cc | 423 ++++++++++++++++++++++++++++++++ src/network/SuperNetwork.hh | 92 +++++++ src/network/SuperNetwork.py | 24 ++ 12 files changed, 1001 insertions(+) create mode 100644 src/network/DataCell.cc create mode 100644 src/network/DataCell.hh create mode 100644 src/network/DataCell.py create mode 100644 src/network/Layer.cc create mode 100644 src/network/Layer.hh create mode 100644 src/network/Layer.py create mode 100644 src/network/NetworkScheduler.cc create mode 100644 src/network/NetworkScheduler.hh create mode 100644 src/network/SConscript create mode 100644 src/network/SuperNetwork.cc create mode 100644 src/network/SuperNetwork.hh create mode 100644 src/network/SuperNetwork.py diff --git a/src/network/DataCell.cc b/src/network/DataCell.cc new file mode 100644 index 0000000000..4593426ee1 --- /dev/null +++ b/src/network/DataCell.cc @@ -0,0 +1,114 @@ +#include "network/DataCell.hh" + +#include "debug/DataCell.hh" +#include "sim/sim_exit.hh" +#include "sim/stats.hh" +#include "sim/system.hh" + +namespace gem5 +{ + +DataCell::DataCell(const DataCellParams& params) : + ClockedObject(params), + data(0), + addr(0), + stats(this) +{ +} + +void +DataCell::setData(uint64_t data) +{ + this->data = data; +} + +uint64_t +DataCell::getData() +{ + return data; +} + +void +DataCell::setAddr(uint64_t addr) +{ + this->addr = addr; +} + +uint64_t +DataCell::getAddr() +{ + return addr; +} + +void +DataCell::assignPacket(uint64_t destAddr) +{ + packetQueue.push(destAddr); + DPRINTF(DataCell, "DataCell %d assigned packet to destination %d\n", + addr, destAddr); +} + +uint64_t +DataCell::getNextPacket() +{ + if (!packetQueue.empty()) { + uint64_t nextPacket = packetQueue.front(); + packetQueue.pop(); + stats.sentPackets++; + return nextPacket; + } + return 0; // Indicate no packet available +} + +bool +DataCell::hasPackets() const +{ + return !packetQueue.empty(); +} + +void +DataCell::receiveData(uint64_t receivedData, uint64_t srcAddr) +{ + DPRINTF(DataCell, "DataCell %d received data %d from source %d\n", + addr, receivedData, srcAddr); + + + lastReceivedData = receivedData; + lastReceivedFrom = srcAddr; + + receivedPackets++; + stats.receivedPackets++; +} + +uint64_t +DataCell::peekNextPacket() const +{ + if (!packetQueue.empty()) { + return packetQueue.front(); + } + return -1; +} + + +DataCell::DataCellStats::DataCellStats(DataCell* dataCell) : + statistics::Group(dataCell), + ADD_STAT(sentPackets, statistics::units::Count::get(), + "Packets sent from this cell"), + ADD_STAT(receivedPackets, statistics::units::Count::get(), + "Packets received by this cell") +{ +} + +void +DataCell::DataCellStats::regStats() +{ + using namespace statistics; + + sentPackets.name("sentPackets") + .desc("Number of packets sent from this cell"); + + receivedPackets.name("receivedPackets") + .desc("Number of packets received by this cell"); +} + +} diff --git a/src/network/DataCell.hh b/src/network/DataCell.hh new file mode 100644 index 0000000000..f004e66bef --- /dev/null +++ b/src/network/DataCell.hh @@ -0,0 +1,56 @@ +#ifndef __NETWORK_DATACELL_HH__ +#define __NETWORK_DATACELL_HH__ + +#include + +#include "params/DataCell.hh" +#include "sim/clocked_object.hh" + +namespace gem5 +{ + +class DataCell : public ClockedObject +{ + private: + uint64_t data; + uint64_t addr; + std::queue packetQueue; + + // For tracking packets + uint64_t sentPackets = 0; + uint64_t receivedPackets = 0; + + // Store last received data for debugging/verification + uint64_t lastReceivedData = 0; + uint64_t lastReceivedFrom = 0; + + struct DataCellStats : public statistics::Group + { + statistics::Scalar sentPackets; + statistics::Scalar receivedPackets; + + DataCellStats(DataCell* dataCell); + void regStats() override; + }; + + DataCellStats stats; + + public: + DataCell(const DataCellParams& params); + void setData(uint64_t data); + uint64_t getData(); + void setAddr(uint64_t addr); + uint64_t getAddr(); + void assignPacket(uint64_t destAddr); + void receiveData(uint64_t receivedData, uint64_t srcAddr); + uint64_t getNextPacket(); + bool hasPackets() const; + uint64_t getSentPackets() const { return sentPackets; } + uint64_t getReceivedPackets() const { return receivedPackets; } + uint64_t getLastReceivedData() const { return lastReceivedData; } + uint64_t getLastReceivedFrom() const { return lastReceivedFrom; } + uint64_t peekNextPacket() const; +}; +} + +#endif diff --git a/src/network/DataCell.py b/src/network/DataCell.py new file mode 100644 index 0000000000..1460024d62 --- /dev/null +++ b/src/network/DataCell.py @@ -0,0 +1,9 @@ +from m5.objects.ClockedObject import ClockedObject +from m5.params import * +from m5.proxy import * + + +class DataCell(ClockedObject): + type = "DataCell" + cxx_header = "network/DataCell.hh" + cxx_class = "gem5::DataCell" diff --git a/src/network/Layer.cc b/src/network/Layer.cc new file mode 100644 index 0000000000..c783112341 --- /dev/null +++ b/src/network/Layer.cc @@ -0,0 +1,20 @@ +#include "network/Layer.hh" + +#include "sim/sim_exit.hh" +#include "sim/stats.hh" +#include "sim/system.hh" + +namespace gem5 +{ + Layer::Layer(const LayerParams& params) : + ClockedObject(params), + rangeSize(params.range_size) + { + } + + uint64_t + Layer::getRangeSize() const + { + return rangeSize; + } +} // namespace gem5 diff --git a/src/network/Layer.hh b/src/network/Layer.hh new file mode 100644 index 0000000000..badda41d00 --- /dev/null +++ b/src/network/Layer.hh @@ -0,0 +1,23 @@ +#ifndef __NETWORK_LAYER_HH__ +#define __NETWORK_LAYER_HH__ + +#include "params/Layer.hh" +#include "sim/clocked_object.hh" + +namespace gem5 +{ + +class Layer : public ClockedObject +{ + private: + uint64_t rangeSize; + + public: + Layer(const LayerParams& params); + + uint64_t getRangeSize() const; +}; + +} // namespace gem5 + +#endif // __NETWORK_LAYER_HH__ diff --git a/src/network/Layer.py b/src/network/Layer.py new file mode 100644 index 0000000000..c6b51d2518 --- /dev/null +++ b/src/network/Layer.py @@ -0,0 +1,12 @@ +from m5.objects.ClockedObject import ClockedObject +from m5.params import * +from m5.proxy import * + + +class Layer(ClockedObject): + type = "Layer" + cxx_header = "network/Layer.hh" + cxx_class = "gem5::Layer" + + # Layer parameters + range_size = Param.UInt64("Range size of the layer (dynamic range)") diff --git a/src/network/NetworkScheduler.cc b/src/network/NetworkScheduler.cc new file mode 100644 index 0000000000..a2013d2014 --- /dev/null +++ b/src/network/NetworkScheduler.cc @@ -0,0 +1,166 @@ +#include "network/NetworkScheduler.hh" + +#include + +#include "debug/NetworkScheduler.hh" + +namespace gem5 { + +NetworkScheduler::NetworkScheduler( +uint64_t maxPackets, +const std::string& schedulePath, +const std::vector& cells +) +: maxPackets(maxPackets), + schedulePath(schedulePath), + dataCells(cells) +{} + +void +NetworkScheduler::initialize() +{ + if (maxPackets == 0 && schedulePath.empty()) { + fatal("Either max_packets or schedule_path must be provided.\n"); + } else if (maxPackets != 0 && schedulePath.empty()) { + generateRandomSchedule(); + } else if (maxPackets != 0 && !schedulePath.empty()) { + if (fileExists(schedulePath)) { + warn("schedule_path %s exists; it will be overwritten.\n", + schedulePath); + } + generateRandomSchedule(); + saveSchedule(); + } else if (maxPackets == 0 && !schedulePath.empty()) { + loadSchedule(); + } +} + +void +NetworkScheduler::generateRandomSchedule() +{ + // Clear any existing schedule + clear(); + + if (dataCells.empty()) { + warn("No DataCells available for scheduling.\n"); + return; + } + + // Generate schedule with src and dest pairs + std::random_device rd; + std::mt19937 gen(rd()); + + for (uint64_t i = 0; i < maxPackets; i++) { + int srcIndex = gen() % dataCells.size(); + int destIndex = gen() % dataCells.size(); + uint64_t srcAddr = dataCells[srcIndex]->getAddr(); + uint64_t destAddr = dataCells[destIndex]->getAddr(); + scheduleQueue.push(std::make_pair(srcAddr, destAddr)); + } + + DPRINTF(NetworkScheduler, + "Random schedule generated with %d packets.\n", + scheduleQueue.size()); +} + +void +NetworkScheduler::saveSchedule() +{ + std::ofstream ofs(schedulePath); + if (!ofs.is_open()) { + fatal("Failed to open schedule file %s for writing.\n", schedulePath); + } + + std::queue> tempQueue = scheduleQueue; + while (!tempQueue.empty()) { + auto entry = tempQueue.front(); + ofs << entry.first << " " << entry.second << "\n"; + tempQueue.pop(); + } + + ofs.close(); + DPRINTF(NetworkScheduler, "Schedule saved to %s.\n", schedulePath); +} + +void +NetworkScheduler::loadSchedule() +{ + std::ifstream ifs(schedulePath); + if (!ifs.is_open()) { + fatal("Failed to open schedule file %s for reading.\n", schedulePath); + } + + clear(); + + std::vector> fileEntries; + uint64_t src, dest; + while (ifs >> src >> dest) { + fileEntries.emplace_back(src, dest); + } + + uint64_t packetCount = loadScheduleEntries(fileEntries); + DPRINTF(NetworkScheduler, + "Schedule loaded from %s with %d entries.\n", + schedulePath, packetCount); +} + +uint64_t +NetworkScheduler::loadScheduleEntries(const std::vector>& fileEntries) +{ + uint64_t packetCount = 0; + + if (maxPackets > 0) { + uint64_t remaining = maxPackets; + while (remaining > 0) { + uint64_t entriesThisRound = std::min(remaining, + (uint64_t)fileEntries.size()); + for (uint64_t i = 0; i < entriesThisRound; i++) { + scheduleQueue.push(fileEntries[i]); + packetCount++; + } + remaining -= entriesThisRound; + } + } else { + for (const auto& entry : fileEntries) { + scheduleQueue.push(entry); + packetCount++; + } + } + + return packetCount; +} + +bool +NetworkScheduler::fileExists(const std::string& path) const +{ + std::ifstream ifs(path); + return ifs.good(); +} + +bool +NetworkScheduler::hasPackets() const +{ + return !scheduleQueue.empty(); +} + +std::pair +NetworkScheduler::getNextPacket() +{ + if (scheduleQueue.empty()) { + return {0, 0}; + } + + auto packet = scheduleQueue.front(); + scheduleQueue.pop(); + return packet; +} + +void +NetworkScheduler::clear() +{ + std::queue> empty; + std::swap(scheduleQueue, empty); +} + +} // namespace gem5 diff --git a/src/network/NetworkScheduler.hh b/src/network/NetworkScheduler.hh new file mode 100644 index 0000000000..cc56425cc9 --- /dev/null +++ b/src/network/NetworkScheduler.hh @@ -0,0 +1,48 @@ +#ifndef __NETWORK_SCHEDULER_HH__ +#define __NETWORK_SCHEDULER_HH__ + +#include +#include +#include +#include +#include +#include +#include + +#include "base/logging.hh" +#include "network/DataCell.hh" + +namespace gem5 { + +class NetworkScheduler +{ +public: + NetworkScheduler(uint64_t maxPackets, + const std::string& schedulePath, + const std::vector& cells + ); + + void initialize(); + void generateRandomSchedule(); + void saveSchedule(); + void loadSchedule(); + uint64_t loadScheduleEntries(const std::vector>& fileEntries + ); + + bool hasPackets() const; + std::pair getNextPacket(); + void clear(); + +private: + bool fileExists(const std::string& path) const; + + uint64_t maxPackets; + std::string schedulePath; + const std::vector& dataCells; + std::queue> scheduleQueue; +}; + +} // namespace gem5 + +#endif // __NETWORK_SCHEDULER_HH__ diff --git a/src/network/SConscript b/src/network/SConscript new file mode 100644 index 0000000000..d25c0bba5c --- /dev/null +++ b/src/network/SConscript @@ -0,0 +1,14 @@ +Import("*") + +SimObject("DataCell.py", sim_objects=["DataCell"]) +SimObject("SuperNetwork.py", sim_objects=["SuperNetwork"]) +SimObject("Layer.py", sim_objects=["Layer"]) + +Source("DataCell.cc") +Source("SuperNetwork.cc") +Source("Layer.cc") +Source('NetworkScheduler.cc') + +DebugFlag("SuperNetwork") +DebugFlag("DataCell") +DebugFlag("NetworkScheduler") diff --git a/src/network/SuperNetwork.cc b/src/network/SuperNetwork.cc new file mode 100644 index 0000000000..b412f88b58 --- /dev/null +++ b/src/network/SuperNetwork.cc @@ -0,0 +1,423 @@ +#include "network/SuperNetwork.hh" + +#include +#include +#include +#include +#include + +#include "debug/SuperNetwork.hh" +#include "network/NetworkScheduler.hh" +#include "sim/sim_exit.hh" +#include "sim/stats.hh" +#include "sim/system.hh" + +namespace gem5 { + +// Hardware Constants (from SRNoC paper) +namespace HardwareConstants { + // Time in picoseconds + constexpr double CROSSPOINT_DELAY = 4.1; + constexpr double MERGER_DELAY = 8.84; + constexpr double SPLITTER_DELAY = 2.06; + constexpr double CIRCUIT_VARIABILITY = 1.2; + constexpr double VARIABILITY_COUNTING_NETWORK = 4.38; + constexpr double CROSSPOINT_SETUP_TIME = 8; + + // Static power in microwatts + constexpr double SPLITTER_STATIC_POWER = 5.98; + constexpr double MERGER_STATIC_POWER = 5; + constexpr double CROSSPOINT_STATIC_POWER = 7.9; + // 1x4 counting network + constexpr double COUNTING_NETWORK_STATIC_POWER = 66.82; + constexpr double TFF_STATIC_POWER = 10.8; + + // Active power in nanowatts + constexpr double SPLITTER_ACTIVE_POWER = 83.2; + constexpr double MERGER_ACTIVE_POWER = 69.6; + constexpr double CROSSPOINT_ACTIVE_POWER = 60.7; + // 1x4 counting network + constexpr double COUNTING_NETWORK_ACTIVE_POWER = 163; + constexpr double TFF_ACTIVE_POWER = 105.6; + + // Number of JJs + constexpr int SPLITTER_JJ = 3; + constexpr int MERGER_JJ = 5; + constexpr int CROSSPOINT_JJ = 13; + // 1x4 counting network + constexpr int COUNTING_NETWORK_JJ = 60; + constexpr int TFF_JJ = 10; +} + +SuperNetwork::SuperNetwork(const SuperNetworkParams& params) : + ClockedObject(params), + maxPackets(params.max_packets), + schedulePath(params.schedule_path), + scheduler(params.max_packets, params.schedule_path, params.dataCells), + currentTimeSlotIndex(0), + nextNetworkEvent([this]{ processNextNetworkEvent(); }, + name() + ".nextNetworkEvent"), + stats(this) +{ + initializeNetworkLayers(params.layers); + initializeDataCells(params.dataCells); + scheduler.initialize(); + assignPacketsFromSchedule(); + computeNetworkParameters(); + calculatePowerAndArea(); + scheduleInitialEvent(); +} + +void +SuperNetwork::initializeNetworkLayers(const std::vector& layers) +{ + if (layers.empty()) { + fatal("At least one Layer must be provided to SuperNetwork.\n"); + } + + Layer* currentLayer = layers[0]; + dynamicRange = currentLayer->getRangeSize(); + DPRINTF(SuperNetwork, "Dynamic range: %d\n", dynamicRange); +} + +void +SuperNetwork::initializeDataCells(const std::vector& cells) +{ + if (cells.empty()) { + return; + } + + assignRadix(cells.size() * 2); // I/O ports are double the # of DataCells + + for (uint64_t i = 0; i < cells.size(); i++) { + DataCell* cell = cells[i]; + cell->setAddr(i); + + uint64_t randomData = random() % dynamicRange; + cell->setData(randomData); + + DPRINTF(SuperNetwork, "DataCell %d: addr=%d, data=%d\n", + i, cell->getAddr(), cell->getData()); + + addDataCell(cell); + } +} + +void +SuperNetwork::assignPacketsFromSchedule() +{ + uint64_t packetCount = 0; + + while (scheduler.hasPackets()) { + auto [srcAddr, destAddr] = scheduler.getNextPacket(); + + DataCell* cell = getDataCell(srcAddr); + if (cell != nullptr) { + DPRINTF(SuperNetwork, + "Assigning packet: src=%d, dest=%d\n", + srcAddr, destAddr + ); + cell->assignPacket(destAddr); + packetCount++; + } + } + + DPRINTF(SuperNetwork, "Total packets assigned: %d\n", packetCount); +} + +void +SuperNetwork::computeNetworkParameters() +{ + // Compute time slot and print + assignTimeSlot(); + DPRINTF(SuperNetwork, "Time slot: %.0f ps\n", getTimeSlot()); + + // Assign connection window + assignConnectionWindow(dynamicRange * getTimeSlot()); + DPRINTF(SuperNetwork, "Connection window: %d\n", getConnectionWindow()); +} + +void +SuperNetwork::scheduleInitialEvent() +{ + bool hasPackets = false; + for (DataCell* cell : dataCells) { + if (cell->hasPackets()) { + hasPackets = true; + break; + } + } + + if (!dataCells.empty() && hasPackets) { + DPRINTF(SuperNetwork, "Scheduling first network event\n"); + scheduleNextNetworkEvent(curTick() + 1); // Start at the next tick + } else { + DPRINTF(SuperNetwork, "No packets to process\n"); + } +} + +void +SuperNetwork::calculatePowerAndArea() +{ + using namespace HardwareConstants; + + // Scale up 1x4 counting network power to match the radix + double countingNetworkRatio = (((getRadix()/2) + 1) / 4.0); + double countingNetworkActivePower = + COUNTING_NETWORK_ACTIVE_POWER * countingNetworkRatio; + double countingNetworkStaticPower = + COUNTING_NETWORK_STATIC_POWER * countingNetworkRatio; + int countingNetworkJJ = COUNTING_NETWORK_JJ * countingNetworkRatio; + + // Calculate number of components based on network radix + int r = radix/2; + int numCountingNetworks = r; + int numCrosspoints = r * r; + int numSplitters = r * (r * (r - 1) + 1); + int numMergers = r * (r * (r - 1) + 1); + + // Calculate active power (nanowatts) + double activePower = + numCountingNetworks * countingNetworkActivePower + + numCrosspoints * CROSSPOINT_ACTIVE_POWER + + numSplitters * SPLITTER_ACTIVE_POWER + + numMergers * MERGER_ACTIVE_POWER; + + // Calculate static power (microwatts) + double staticPower = + numCountingNetworks * countingNetworkStaticPower + + numCrosspoints * CROSSPOINT_STATIC_POWER + + numSplitters * SPLITTER_STATIC_POWER + + numMergers * MERGER_STATIC_POWER; + + // Convert units to watts + activePower *= 1e-9; // nanowatts to watts + staticPower *= 1e-6; // microwatts to watts + double totalPower = activePower + staticPower; + + // Calculate total Josephson Junctions + int totalJJ = + numCountingNetworks * countingNetworkJJ + + numCrosspoints * CROSSPOINT_JJ + + numSplitters * SPLITTER_JJ + + numMergers * MERGER_JJ; + + // Log and store results + DPRINTF(SuperNetwork, "Active power: %.6f W\n", activePower); + DPRINTF(SuperNetwork, "Static power: %.6f W\n", staticPower); + DPRINTF(SuperNetwork, "Total power: %.6f W\n", totalPower); + DPRINTF(SuperNetwork, "Total JJ: %d\n", totalJJ); + + stats.activePower = activePower; + stats.staticPower = staticPower; + stats.totalPower = totalPower; + stats.totalJJ = totalJJ; +} + +void +SuperNetwork::assignTimeSlot() +{ + using namespace HardwareConstants; + + double SE_adjusted = std::max(0.0, + CROSSPOINT_SETUP_TIME - CIRCUIT_VARIABILITY + ); + double calculatedTimeSlot = CIRCUIT_VARIABILITY * ( + CROSSPOINT_DELAY + SE_adjusted + + SPLITTER_DELAY * (radix - 1) + + MERGER_DELAY * (radix - 1) + + VARIABILITY_COUNTING_NETWORK); + + this->timeSlot = std::ceil(calculatedTimeSlot); +} + +void +SuperNetwork::addDataCell(DataCell* dataCell) +{ + dataCells.push_back(dataCell); + uint64_t addr = dataCell->getAddr(); + dataCellMap[addr] = dataCell; +} + +DataCell* +SuperNetwork::getDataCell(uint64_t addr) +{ + auto it = dataCellMap.find(addr); + return (it != dataCellMap.end()) ? it->second : nullptr; +} + +void +SuperNetwork::processNextNetworkEvent() +{ + bool packetsRemaining = false; + uint64_t packetsProcessedThisWindow = 0; + + // Build static schedule for the current time slot + std::unordered_map staticSchedule = + buildStaticSchedule(); + + // Process packets according to the static schedule + packetsRemaining = processPackets( + staticSchedule, + packetsProcessedThisWindow + ); + + // Update statistics + stats.totalWindowsUsed++; + + // Advance the time slot for the next event + currentTimeSlotIndex++; + + // Schedule next network event if needed + if (packetsRemaining) { + scheduleNextNetworkEvent(curTick() + connectionWindow); + } else { + DPRINTF(SuperNetwork, "All packets processed\n"); + exitSimLoop("All packets processed"); + } +} + +std::unordered_map +SuperNetwork::buildStaticSchedule() +{ + std::unordered_map staticSchedule; + + for (DataCell* cell : dataCells) { + uint64_t srcAddr = cell->getAddr(); + uint64_t allowedDest = + (srcAddr + currentTimeSlotIndex) % dataCells.size(); + staticSchedule[srcAddr] = allowedDest; + + DPRINTF(SuperNetwork, + "Window %lu: allowed transmission from DataCell %lu to %lu\n", + currentTimeSlotIndex, srcAddr, allowedDest + ); + } + + return staticSchedule; +} + +bool +SuperNetwork::processPackets( + const std::unordered_map& staticSchedule, + uint64_t& packetsProcessedThisWindow) +{ + bool packetsRemaining = false; + + for (DataCell* cell : dataCells) { + if (!cell->hasPackets()) { + continue; + } + + uint64_t srcAddr = cell->getAddr(); + uint64_t allowedDest = staticSchedule.at(srcAddr); + uint64_t packetDest = cell->peekNextPacket(); + + if (packetDest == allowedDest) { + // Allowed: remove the packet and process it + cell->getNextPacket(); + uint64_t payload = cell->getData(); + + DPRINTF(SuperNetwork, + "Processing packet: src=%lu, dest=%lu, data=%lu\n", + srcAddr, allowedDest, payload + ); + + // Deliver packet to destination + deliverPacket(srcAddr, allowedDest, payload); + packetsProcessedThisWindow++; + } else { + // Not allowed to send this packet in the current time slot + DPRINTF(SuperNetwork, + "DataCell %lu: packet for %lu not scheduled (allowed: %lu)\n", + srcAddr, packetDest, allowedDest + ); + } + + // Check if cell still has packets + if (cell->hasPackets()) { + packetsRemaining = true; + } + } + + return packetsRemaining; +} + +void +SuperNetwork::deliverPacket(uint64_t srcAddr, + uint64_t destAddr, uint64_t payload) +{ + DataCell* destCell = getDataCell(destAddr); + if (destCell != nullptr) { + destCell->receiveData(payload, srcAddr); + DPRINTF(SuperNetwork, + "Packet delivered: src=%lu, dest=%lu, data=%lu\n", + srcAddr, destAddr, payload + ); + stats.totalPacketsProcessed++; + } else { + DPRINTF(SuperNetwork, + "Error: Destination cell %lu not found\n", + destAddr + ); + } +} + +void +SuperNetwork::scheduleNextNetworkEvent(Tick when) +{ + if (!nextNetworkEvent.scheduled()) { + schedule(nextNetworkEvent, when); + } +} + +SuperNetwork::SuperNetworkStats::SuperNetworkStats( + SuperNetwork* superNetwork + ) : statistics::Group(superNetwork), + ADD_STAT(activePower, statistics::units::Watt::get(), "Active power"), + ADD_STAT(staticPower, statistics::units::Watt::get(), "Static power"), + ADD_STAT(totalPower, statistics::units::Watt::get(), "Total power"), + ADD_STAT(totalJJ, statistics::units::Count::get(), "Total JJ"), + ADD_STAT(totalPacketsProcessed, statistics::units::Count::get(), + "Total packets processed"), + ADD_STAT(totalWindowsUsed, statistics::units::Count::get(), + "Number of connection windows used"), + ADD_STAT(pktsPerWindow, statistics::units::Count::get(), + "Average packets per window") +{ +} + +void +SuperNetwork::SuperNetworkStats::regStats() +{ + using namespace statistics; + + activePower.name("activePower") + .desc("Active power") + .precision(6); + + staticPower.name("staticPower") + .desc("Static power") + .precision(6); + + totalPower.name("totalPower") + .desc("Total power") + .precision(6); + + totalJJ.name("totalJJ") + .desc("Total number of Josephson Junctions"); + + totalPacketsProcessed.name("totalPacketsProcessed") + .desc("Total number of packets processed"); + + totalWindowsUsed.name("totalWindowsUsed") + .desc("Number of connection windows used"); + + pktsPerWindow.name("pktsPerWindow") + .desc("Average packets processed per window") + .precision(2) + .flags(nozero) + = totalPacketsProcessed / totalWindowsUsed; +} + +} // namespace gem5 diff --git a/src/network/SuperNetwork.hh b/src/network/SuperNetwork.hh new file mode 100644 index 0000000000..76a5bd1099 --- /dev/null +++ b/src/network/SuperNetwork.hh @@ -0,0 +1,92 @@ +#ifndef __NETWORK_SUPERNETWORK_HH__ +#define __NETWORK_SUPERNETWORK_HH__ + +#include +#include +#include +#include + +#include "base/statistics.hh" +#include "base/stats/group.hh" +#include "network/DataCell.hh" +#include "network/Layer.hh" +#include "network/NetworkScheduler.hh" +#include "params/SuperNetwork.hh" +#include "sim/clocked_object.hh" +#include "sim/eventq.hh" + +namespace gem5 +{ + +class SuperNetwork : public ClockedObject +{ +private: + std::vector dataCells; + std::unordered_map dataCellMap; + uint64_t dynamicRange; + uint64_t radix; + float timeSlot; + int connectionWindow; + uint64_t currentTimeSlotIndex; + uint64_t maxPackets; // 0 means not provided. + std::string schedulePath; // empty means not provided. + std::queue> scheduleQueue; + NetworkScheduler scheduler; + + // Initialization methods + void initializeNetworkLayers(const std::vector& layers); + void initializeDataCells(const std::vector& cells); + void assignPacketsFromSchedule(); + void computeNetworkParameters(); + void scheduleInitialEvent(); + + // Processing packets + std::unordered_map buildStaticSchedule(); + bool processPackets( + const std::unordered_map& staticSchedule, + uint64_t& packetsProcessedThisWindow + ); + void deliverPacket(uint64_t srcAddr, uint64_t destAddr, uint64_t payload); + + struct SuperNetworkStats: public statistics::Group + { + // SRNoC statistics + statistics::Formula activePower; + statistics::Formula staticPower; + statistics::Formula totalPower; + statistics::Formula totalJJ; + // Round-robin statistics + statistics::Scalar totalPacketsProcessed; + statistics::Scalar totalWindowsUsed; + statistics::Formula pktsPerWindow; + + SuperNetworkStats(SuperNetwork* superNetwork); + void regStats() override; + }; + + SuperNetworkStats stats; + EventFunctionWrapper nextNetworkEvent; + void processNextNetworkEvent(); + void scheduleNextNetworkEvent(Tick when); + +public: + SuperNetwork(const SuperNetworkParams& params); + + void addDataCell(DataCell* dataCell); + DataCell* getDataCell(uint64_t addr); + + void assignRadix(uint64_t radix) { this->radix = radix; } + uint64_t getRadix() const { return radix; } + + void assignTimeSlot(); + float getTimeSlot() const { return timeSlot; } + + void assignConnectionWindow(int window) { connectionWindow = window; } + int getConnectionWindow() const { return connectionWindow; } + + void calculatePowerAndArea(); +}; + +} // namespace gem5 + +#endif // __NETWORK_SUPERNETWORK_HH__ diff --git a/src/network/SuperNetwork.py b/src/network/SuperNetwork.py new file mode 100644 index 0000000000..9ad74237b0 --- /dev/null +++ b/src/network/SuperNetwork.py @@ -0,0 +1,24 @@ +from m5.objects.ClockedObject import ClockedObject +from m5.params import * + + +class SuperNetwork(ClockedObject): + type = "SuperNetwork" + cxx_header = "network/SuperNetwork.hh" + cxx_class = "gem5::SuperNetwork" + + # Vector of data cells in the network + dataCells = VectorParam.DataCell("Data cells in the network") + + # Vector of layers in the network + layers = VectorParam.Layer("Layers in the network") + + # max_packets: 0 means not provided + max_packets = Param.UInt64( + 0, "Maximum number of packets to schedule; 0 means not provided" + ) + + # schedule_path: empty string means not provided + schedule_path = Param.String( + "", "File path for schedule (empty means not provided)" + ) From a04257d743e40de0333cc2a35fcc8f63c44978d2 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Tue, 25 Mar 2025 10:35:30 -0700 Subject: [PATCH 02/47] misc: Add comments and license Comments for better code understandability added. License added. --- src/network/DataCell.cc | 68 +++++++++++++---- src/network/DataCell.hh | 78 ++++++++++++++++++-- src/network/DataCell.py | 26 +++++++ src/network/Layer.cc | 52 ++++++++++--- src/network/Layer.hh | 30 ++++++++ src/network/Layer.py | 26 +++++++ src/network/NetworkScheduler.cc | 78 ++++++++++++++++++-- src/network/NetworkScheduler.hh | 49 ++++++++++++ src/network/SuperNetwork.cc | 127 +++++++++++++++++++++++++++----- src/network/SuperNetwork.hh | 81 ++++++++++++++++---- src/network/SuperNetwork.py | 26 +++++++ 11 files changed, 569 insertions(+), 72 deletions(-) diff --git a/src/network/DataCell.cc b/src/network/DataCell.cc index 4593426ee1..be5ddd9ded 100644 --- a/src/network/DataCell.cc +++ b/src/network/DataCell.cc @@ -1,3 +1,31 @@ +/* + * Copyright (c) 2025 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + #include "network/DataCell.hh" #include "debug/DataCell.hh" @@ -8,88 +36,101 @@ namespace gem5 { +// Constructor for DataCell class +// Initializes the cell with default values and links to the statistics group DataCell::DataCell(const DataCellParams& params) : ClockedObject(params), - data(0), - addr(0), - stats(this) + data(0), // Initialize data to 0 + addr(0), // Initialize address to 0 + stats(this) // Link the stats object to this cell { } +// Sets the data value in the cell void DataCell::setData(uint64_t data) { this->data = data; } +// Retrieves the current data value in the cell uint64_t DataCell::getData() { return data; } +// Sets the address of the cell void DataCell::setAddr(uint64_t addr) { this->addr = addr; } +// Retrieves the address of the cell uint64_t DataCell::getAddr() { return addr; } +// Assigns a packet to the cell by pushing the dest address into queue void DataCell::assignPacket(uint64_t destAddr) { - packetQueue.push(destAddr); + packetQueue.push(destAddr); // Queue the dest DPRINTF(DataCell, "DataCell %d assigned packet to destination %d\n", addr, destAddr); } +// Retrieves and removes the next packet from the queue +// Returns 0 if no packets are available uint64_t DataCell::getNextPacket() { if (!packetQueue.empty()) { + // Get the next packet and remove it from the queue uint64_t nextPacket = packetQueue.front(); packetQueue.pop(); stats.sentPackets++; return nextPacket; } - return 0; // Indicate no packet available + return 0; // No packet available } +// Checks if there are any packets in the queue bool DataCell::hasPackets() const { return !packetQueue.empty(); } +// Handles receiving data by updating the last received values and stats void DataCell::receiveData(uint64_t receivedData, uint64_t srcAddr) { DPRINTF(DataCell, "DataCell %d received data %d from source %d\n", addr, receivedData, srcAddr); + lastReceivedData = receivedData; // Store the last received data + lastReceivedFrom = srcAddr; // Store the source of the data - lastReceivedData = receivedData; - lastReceivedFrom = srcAddr; - - receivedPackets++; - stats.receivedPackets++; + receivedPackets++; // Increment the local received counter + stats.receivedPackets++; // Increment the statistics counter } +// Returns the next packet without removing it from the queue +// Returns -1 if no packets are available uint64_t DataCell::peekNextPacket() const { if (!packetQueue.empty()) { return packetQueue.front(); } - return -1; + return -1; // No packet available } - +// Constructor for the statistics group associated with the DataCell DataCell::DataCellStats::DataCellStats(DataCell* dataCell) : statistics::Group(dataCell), ADD_STAT(sentPackets, statistics::units::Count::get(), @@ -99,6 +140,7 @@ DataCell::DataCellStats::DataCellStats(DataCell* dataCell) : { } +// Registers statistics for the DataCell void DataCell::DataCellStats::regStats() { @@ -111,4 +153,4 @@ DataCell::DataCellStats::regStats() .desc("Number of packets received by this cell"); } -} +} // namespace gem5 diff --git a/src/network/DataCell.hh b/src/network/DataCell.hh index f004e66bef..c2bda9bcd8 100644 --- a/src/network/DataCell.hh +++ b/src/network/DataCell.hh @@ -1,3 +1,31 @@ +/* + * Copyright (c) 2025 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + #ifndef __NETWORK_DATACELL_HH__ #define __NETWORK_DATACELL_HH__ @@ -9,48 +37,86 @@ namespace gem5 { +// The DataCell class represents a single node in the network responsible for +// storing, sending, and receiving packets. It tracks its data, address, +// and maintains statistics for sent and received packets. class DataCell : public ClockedObject { private: + // The data value stored in the cell uint64_t data; + + // The address identifier of the cell uint64_t addr; + + // Queue to hold packets (destination addresses) assigned to the cell std::queue packetQueue; - // For tracking packets + // Counters for the # of packets sent and received by the cell uint64_t sentPackets = 0; uint64_t receivedPackets = 0; - // Store last received data for debugging/verification + // Variables to store the most recent received data and source addr uint64_t lastReceivedData = 0; uint64_t lastReceivedFrom = 0; + // Statistics struct to track sent and received packets struct DataCellStats : public statistics::Group { - statistics::Scalar sentPackets; - statistics::Scalar receivedPackets; + statistics::Scalar sentPackets; // # of packets sent + statistics::Scalar receivedPackets; // # of packets received + // Constructor for the statistics group DataCellStats(DataCell* dataCell); + + // Registers the statistics with gem5's statistics system void regStats() override; }; + // Statistics instance associated with the current DataCell DataCellStats stats; public: + // Constructor: Initializes the DataCell with parameters DataCell(const DataCellParams& params); + + // Sets the data value in the cell void setData(uint64_t data); + + // Retrieves the current data value uint64_t getData(); + + // Sets the address of the cell void setAddr(uint64_t addr); + + // Retrieves the address of the cell uint64_t getAddr(); + + // Assigns a packet to the queue with the given destination address void assignPacket(uint64_t destAddr); + + // Receives data from another cell + // Stores the received value and source void receiveData(uint64_t receivedData, uint64_t srcAddr); + + // Retrieves and removes the next packet from the queue uint64_t getNextPacket(); + + // Checks if the cell has any packets in its queue bool hasPackets() const; + + // Getters for tracking statistics uint64_t getSentPackets() const { return sentPackets; } uint64_t getReceivedPackets() const { return receivedPackets; } + + // Getters for the last received data and source information uint64_t getLastReceivedData() const { return lastReceivedData; } uint64_t getLastReceivedFrom() const { return lastReceivedFrom; } + + // Peeks at the next packet without removing it from the queue uint64_t peekNextPacket() const; }; -} -#endif +} // namespace gem5 + +#endif // __NETWORK_DATACELL_HH__ diff --git a/src/network/DataCell.py b/src/network/DataCell.py index 1460024d62..e1285253bc 100644 --- a/src/network/DataCell.py +++ b/src/network/DataCell.py @@ -1,3 +1,29 @@ +# Copyright (c) 2022 The Regents of the University of California +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + from m5.objects.ClockedObject import ClockedObject from m5.params import * from m5.proxy import * diff --git a/src/network/Layer.cc b/src/network/Layer.cc index c783112341..7b65e5491e 100644 --- a/src/network/Layer.cc +++ b/src/network/Layer.cc @@ -1,3 +1,31 @@ +/* + * Copyright (c) 2025 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + #include "network/Layer.hh" #include "sim/sim_exit.hh" @@ -6,15 +34,19 @@ namespace gem5 { - Layer::Layer(const LayerParams& params) : - ClockedObject(params), - rangeSize(params.range_size) - { - } - uint64_t - Layer::getRangeSize() const - { - return rangeSize; - } +// Constructor for the Layer class +Layer::Layer(const LayerParams& params) : + ClockedObject(params), + rangeSize(params.range_size) +{ +} + +// Returns the range size of the Layer +uint64_t +Layer::getRangeSize() const +{ + return rangeSize; +} + } // namespace gem5 diff --git a/src/network/Layer.hh b/src/network/Layer.hh index badda41d00..ee3a879ad1 100644 --- a/src/network/Layer.hh +++ b/src/network/Layer.hh @@ -1,3 +1,31 @@ +/* + * Copyright (c) 2025 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + #ifndef __NETWORK_LAYER_HH__ #define __NETWORK_LAYER_HH__ @@ -13,8 +41,10 @@ class Layer : public ClockedObject uint64_t rangeSize; public: + // Constructor: Initializes the Layer with given parameters Layer(const LayerParams& params); + // Returns the range size of the Layer uint64_t getRangeSize() const; }; diff --git a/src/network/Layer.py b/src/network/Layer.py index c6b51d2518..047ea3300b 100644 --- a/src/network/Layer.py +++ b/src/network/Layer.py @@ -1,3 +1,29 @@ +# Copyright (c) 2022 The Regents of the University of California +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + from m5.objects.ClockedObject import ClockedObject from m5.params import * from m5.proxy import * diff --git a/src/network/NetworkScheduler.cc b/src/network/NetworkScheduler.cc index a2013d2014..3a80e4de38 100644 --- a/src/network/NetworkScheduler.cc +++ b/src/network/NetworkScheduler.cc @@ -1,55 +1,95 @@ +/* + * Copyright (c) 2025 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + #include "network/NetworkScheduler.hh" -#include +#include // For random number generation #include "debug/NetworkScheduler.hh" namespace gem5 { +// Constructor for NetworkScheduler +// Initializes the scheduler with maximum packets, +// schedule path, and list of DataCells NetworkScheduler::NetworkScheduler( -uint64_t maxPackets, -const std::string& schedulePath, -const std::vector& cells + uint64_t maxPackets, + const std::string& schedulePath, + const std::vector& cells ) : maxPackets(maxPackets), schedulePath(schedulePath), dataCells(cells) {} +// Initializes the scheduler by either generating or loading a schedule void NetworkScheduler::initialize() { if (maxPackets == 0 && schedulePath.empty()) { + // Error: No packets and no schedule path specified fatal("Either max_packets or schedule_path must be provided.\n"); } else if (maxPackets != 0 && schedulePath.empty()) { + // Generate a random schedule if no path is specified generateRandomSchedule(); } else if (maxPackets != 0 && !schedulePath.empty()) { + // If both max packets and schedule path are provided if (fileExists(schedulePath)) { + // Warn if the schedule file already exists warn("schedule_path %s exists; it will be overwritten.\n", schedulePath); } generateRandomSchedule(); saveSchedule(); } else if (maxPackets == 0 && !schedulePath.empty()) { + // Load an existing schedule from the specified path loadSchedule(); } } +// Generates a random schedule of packets void NetworkScheduler::generateRandomSchedule() { - // Clear any existing schedule + // Clear any existing schedule before generating a new one clear(); if (dataCells.empty()) { + // Warn if there are no DataCells available warn("No DataCells available for scheduling.\n"); return; } - // Generate schedule with src and dest pairs - std::random_device rd; - std::mt19937 gen(rd()); + // Random number generator setup + std::random_device rd; // Random seed + std::mt19937 gen(rd()); // Mersenne Twister random generator + // Generate random src-dest packet pairs for (uint64_t i = 0; i < maxPackets; i++) { int srcIndex = gen() % dataCells.size(); int destIndex = gen() % dataCells.size(); @@ -63,14 +103,17 @@ NetworkScheduler::generateRandomSchedule() scheduleQueue.size()); } +// Saves the current schedule to a file void NetworkScheduler::saveSchedule() { std::ofstream ofs(schedulePath); if (!ofs.is_open()) { + // Fatal error if the file cannot be opened for writing fatal("Failed to open schedule file %s for writing.\n", schedulePath); } + // Write each src-dest packet pair to the file std::queue> tempQueue = scheduleQueue; while (!tempQueue.empty()) { auto entry = tempQueue.front(); @@ -82,28 +125,35 @@ NetworkScheduler::saveSchedule() DPRINTF(NetworkScheduler, "Schedule saved to %s.\n", schedulePath); } +// Loads a schedule from a file void NetworkScheduler::loadSchedule() { std::ifstream ifs(schedulePath); if (!ifs.is_open()) { + // Fatal error if the file cannot be opened for reading fatal("Failed to open schedule file %s for reading.\n", schedulePath); } + // Clear any existing schedule clear(); std::vector> fileEntries; uint64_t src, dest; + + // Read src-dest pairs from the file while (ifs >> src >> dest) { fileEntries.emplace_back(src, dest); } + // Load the read entries into the schedule queue uint64_t packetCount = loadScheduleEntries(fileEntries); DPRINTF(NetworkScheduler, "Schedule loaded from %s with %d entries.\n", schedulePath, packetCount); } +// Adds schedule entries from the file into the queue uint64_t NetworkScheduler::loadScheduleEntries(const std::vector>& fileEntries) @@ -111,17 +161,23 @@ NetworkScheduler::loadScheduleEntries(const std::vector 0) { + // If maxPackets is specified, only load up to that limit uint64_t remaining = maxPackets; + + // Add entries in rounds until the maxPackets limit is reached while (remaining > 0) { uint64_t entriesThisRound = std::min(remaining, (uint64_t)fileEntries.size()); + for (uint64_t i = 0; i < entriesThisRound; i++) { scheduleQueue.push(fileEntries[i]); packetCount++; } + remaining -= entriesThisRound; } } else { + // If no maxPackets limit, load all entries for (const auto& entry : fileEntries) { scheduleQueue.push(entry); packetCount++; @@ -131,6 +187,7 @@ NetworkScheduler::loadScheduleEntries(const std::vector NetworkScheduler::getNextPacket() { if (scheduleQueue.empty()) { + // Return a default packet with {0, 0} if the queue is empty return {0, 0}; } + // Retrieve and remove the next packet from the queue auto packet = scheduleQueue.front(); scheduleQueue.pop(); return packet; } +// Clears the current schedule by swapping with an empty queue void NetworkScheduler::clear() { diff --git a/src/network/NetworkScheduler.hh b/src/network/NetworkScheduler.hh index cc56425cc9..0744c07779 100644 --- a/src/network/NetworkScheduler.hh +++ b/src/network/NetworkScheduler.hh @@ -1,3 +1,31 @@ +/* + * Copyright (c) 2025 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + #ifndef __NETWORK_SCHEDULER_HH__ #define __NETWORK_SCHEDULER_HH__ @@ -14,32 +42,53 @@ namespace gem5 { +// NetworkScheduler class handles scheduling packets between DataCells class NetworkScheduler { public: + // Constructor that initializes the scheduler NetworkScheduler(uint64_t maxPackets, const std::string& schedulePath, const std::vector& cells ); + // Initializes the scheduler void initialize(); + + // Generates a random schedule for packets between DataCells void generateRandomSchedule(); + + // Saves the current schedule to a specified file void saveSchedule(); + + // Loads a schedule from a specified file void loadSchedule(); + + // Loads schedule entries from a given list of source-destination pairs uint64_t loadScheduleEntries(const std::vector>& fileEntries ); + // Checks if there are any packets left in the schedule bool hasPackets() const; + + // Returns the next packet in the schedule std::pair getNextPacket(); + + // Clears the current schedule, effectively resetting the scheduler void clear(); private: + // Checks if a given file exists at the specified path bool fileExists(const std::string& path) const; + // Maximum number of packets to be scheduled uint64_t maxPackets; + // Path to the file where the schedule is saved/loaded std::string schedulePath; + // List of DataCells involved in the network const std::vector& dataCells; + // Scheduled packets (source-destination pairs) std::queue> scheduleQueue; }; diff --git a/src/network/SuperNetwork.cc b/src/network/SuperNetwork.cc index b412f88b58..1bd82ae8de 100644 --- a/src/network/SuperNetwork.cc +++ b/src/network/SuperNetwork.cc @@ -1,3 +1,31 @@ +/* + * Copyright (c) 2025 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + #include "network/SuperNetwork.hh" #include @@ -14,9 +42,10 @@ namespace gem5 { -// Hardware Constants (from SRNoC paper) +// Hardware Constants namespace containing predefined values for various +// network components based on the SRNoC paper namespace HardwareConstants { - // Time in picoseconds + // Timing delays in picoseconds for different network components constexpr double CROSSPOINT_DELAY = 4.1; constexpr double MERGER_DELAY = 8.84; constexpr double SPLITTER_DELAY = 2.06; @@ -24,99 +53,127 @@ namespace HardwareConstants { constexpr double VARIABILITY_COUNTING_NETWORK = 4.38; constexpr double CROSSPOINT_SETUP_TIME = 8; - // Static power in microwatts + // Static power consumption in microwatts for various components constexpr double SPLITTER_STATIC_POWER = 5.98; constexpr double MERGER_STATIC_POWER = 5; constexpr double CROSSPOINT_STATIC_POWER = 7.9; - // 1x4 counting network constexpr double COUNTING_NETWORK_STATIC_POWER = 66.82; constexpr double TFF_STATIC_POWER = 10.8; - // Active power in nanowatts + // Active power consumption in nanowatts for various components constexpr double SPLITTER_ACTIVE_POWER = 83.2; constexpr double MERGER_ACTIVE_POWER = 69.6; constexpr double CROSSPOINT_ACTIVE_POWER = 60.7; - // 1x4 counting network constexpr double COUNTING_NETWORK_ACTIVE_POWER = 163; constexpr double TFF_ACTIVE_POWER = 105.6; - // Number of JJs + // Number of Josephson Junctions (JJs) for each component type constexpr int SPLITTER_JJ = 3; constexpr int MERGER_JJ = 5; constexpr int CROSSPOINT_JJ = 13; - // 1x4 counting network constexpr int COUNTING_NETWORK_JJ = 60; constexpr int TFF_JJ = 10; } +// Constructor for the SuperNetwork class +// Initializes the network with given parameters, sets up data cells, +// and prepares for packet scheduling SuperNetwork::SuperNetwork(const SuperNetworkParams& params) : ClockedObject(params), maxPackets(params.max_packets), schedulePath(params.schedule_path), scheduler(params.max_packets, params.schedule_path, params.dataCells), currentTimeSlotIndex(0), + // Event for processing the next network event nextNetworkEvent([this]{ processNextNetworkEvent(); }, name() + ".nextNetworkEvent"), stats(this) { + // Initialize network layers initializeNetworkLayers(params.layers); + + // Initialize data cells with random data initializeDataCells(params.dataCells); + + // Initialize the network scheduler scheduler.initialize(); + + // Assign packets from the predefined schedule assignPacketsFromSchedule(); + + // Compute network parameters like time slot and connection window computeNetworkParameters(); + + // Calculate power consumption and area requirements calculatePowerAndArea(); + + // Schedule the initial network event scheduleInitialEvent(); } +// Initialize network layers, setting the dynamic range void SuperNetwork::initializeNetworkLayers(const std::vector& layers) { + // Ensure at least one layer is provided if (layers.empty()) { fatal("At least one Layer must be provided to SuperNetwork.\n"); } + // Set dynamic range from the first layer Layer* currentLayer = layers[0]; dynamicRange = currentLayer->getRangeSize(); DPRINTF(SuperNetwork, "Dynamic range: %d\n", dynamicRange); } +// Initialize data cells with random data and unique addresses void SuperNetwork::initializeDataCells(const std::vector& cells) { + // Skip if no data cells are provided if (cells.empty()) { return; } - assignRadix(cells.size() * 2); // I/O ports are double the # of DataCells + // Set network radix + assignRadix(cells.size() * 2); + // Populate data cells with addresses and random data for (uint64_t i = 0; i < cells.size(); i++) { DataCell* cell = cells[i]; cell->setAddr(i); + // Generate random data within the dynamic range uint64_t randomData = random() % dynamicRange; cell->setData(randomData); DPRINTF(SuperNetwork, "DataCell %d: addr=%d, data=%d\n", i, cell->getAddr(), cell->getData()); + // Add the cell to the network addDataCell(cell); } } +// Assign packets to data cells based on the predefined schedule void SuperNetwork::assignPacketsFromSchedule() { uint64_t packetCount = 0; + // Process all packets in the scheduler while (scheduler.hasPackets()) { + // Get the next packet's source and destination addresses auto [srcAddr, destAddr] = scheduler.getNextPacket(); + // Find the source data cell DataCell* cell = getDataCell(srcAddr); if (cell != nullptr) { DPRINTF(SuperNetwork, "Assigning packet: src=%d, dest=%d\n", srcAddr, destAddr ); + // Assign the packet to the source cell cell->assignPacket(destAddr); packetCount++; } @@ -125,22 +182,25 @@ SuperNetwork::assignPacketsFromSchedule() DPRINTF(SuperNetwork, "Total packets assigned: %d\n", packetCount); } +// Compute key network parameters like time slot and connection window void SuperNetwork::computeNetworkParameters() { - // Compute time slot and print + // Calculate and assign the time slot assignTimeSlot(); DPRINTF(SuperNetwork, "Time slot: %.0f ps\n", getTimeSlot()); - // Assign connection window + // Calculate and assign the connection window assignConnectionWindow(dynamicRange * getTimeSlot()); DPRINTF(SuperNetwork, "Connection window: %d\n", getConnectionWindow()); } +// Schedule the initial network event if there are packets to process void SuperNetwork::scheduleInitialEvent() { bool hasPackets = false; + // Check if any data cell has packets for (DataCell* cell : dataCells) { if (cell->hasPackets()) { hasPackets = true; @@ -148,6 +208,7 @@ SuperNetwork::scheduleInitialEvent() } } + // Schedule the first network event if packets exist if (!dataCells.empty() && hasPackets) { DPRINTF(SuperNetwork, "Scheduling first network event\n"); scheduleNextNetworkEvent(curTick() + 1); // Start at the next tick @@ -156,12 +217,13 @@ SuperNetwork::scheduleInitialEvent() } } +// Calculate power consumption and area requirements for the network void SuperNetwork::calculatePowerAndArea() { using namespace HardwareConstants; - // Scale up 1x4 counting network power to match the radix + // Scale counting network power based on network radix double countingNetworkRatio = (((getRadix()/2) + 1) / 4.0); double countingNetworkActivePower = COUNTING_NETWORK_ACTIVE_POWER * countingNetworkRatio; @@ -176,21 +238,21 @@ SuperNetwork::calculatePowerAndArea() int numSplitters = r * (r * (r - 1) + 1); int numMergers = r * (r * (r - 1) + 1); - // Calculate active power (nanowatts) + // Calculate active power consumption double activePower = numCountingNetworks * countingNetworkActivePower + numCrosspoints * CROSSPOINT_ACTIVE_POWER + numSplitters * SPLITTER_ACTIVE_POWER + numMergers * MERGER_ACTIVE_POWER; - // Calculate static power (microwatts) + // Calculate static power consumption double staticPower = numCountingNetworks * countingNetworkStaticPower + numCrosspoints * CROSSPOINT_STATIC_POWER + numSplitters * SPLITTER_STATIC_POWER + numMergers * MERGER_STATIC_POWER; - // Convert units to watts + // Convert power units activePower *= 1e-9; // nanowatts to watts staticPower *= 1e-6; // microwatts to watts double totalPower = activePower + staticPower; @@ -202,7 +264,7 @@ SuperNetwork::calculatePowerAndArea() numSplitters * SPLITTER_JJ + numMergers * MERGER_JJ; - // Log and store results + // Log and store power and area statistics DPRINTF(SuperNetwork, "Active power: %.6f W\n", activePower); DPRINTF(SuperNetwork, "Static power: %.6f W\n", staticPower); DPRINTF(SuperNetwork, "Total power: %.6f W\n", totalPower); @@ -214,23 +276,29 @@ SuperNetwork::calculatePowerAndArea() stats.totalJJ = totalJJ; } +// Calculate the time slot based on network component delays void SuperNetwork::assignTimeSlot() { using namespace HardwareConstants; + // Adjust setup time considering circuit variability double SE_adjusted = std::max(0.0, CROSSPOINT_SETUP_TIME - CIRCUIT_VARIABILITY ); + + // Calculate time slot considering delays of various network components double calculatedTimeSlot = CIRCUIT_VARIABILITY * ( CROSSPOINT_DELAY + SE_adjusted + SPLITTER_DELAY * (radix - 1) + MERGER_DELAY * (radix - 1) + VARIABILITY_COUNTING_NETWORK); + // Round up the calculated time slot this->timeSlot = std::ceil(calculatedTimeSlot); } +// Add a data cell to the network's data cell collection void SuperNetwork::addDataCell(DataCell* dataCell) { @@ -239,6 +307,7 @@ SuperNetwork::addDataCell(DataCell* dataCell) dataCellMap[addr] = dataCell; } +// Retrieve a data cell by its address DataCell* SuperNetwork::getDataCell(uint64_t addr) { @@ -246,13 +315,14 @@ SuperNetwork::getDataCell(uint64_t addr) return (it != dataCellMap.end()) ? it->second : nullptr; } +// Process the next network event in the simulation void SuperNetwork::processNextNetworkEvent() { bool packetsRemaining = false; uint64_t packetsProcessedThisWindow = 0; - // Build static schedule for the current time slot + // Build a static schedule for the current time slot std::unordered_map staticSchedule = buildStaticSchedule(); @@ -268,7 +338,7 @@ SuperNetwork::processNextNetworkEvent() // Advance the time slot for the next event currentTimeSlotIndex++; - // Schedule next network event if needed + // Schedule next network event or exit simulation if (packetsRemaining) { scheduleNextNetworkEvent(curTick() + connectionWindow); } else { @@ -277,11 +347,13 @@ SuperNetwork::processNextNetworkEvent() } } +// Build a static schedule for packet transmission in the current time slot std::unordered_map SuperNetwork::buildStaticSchedule() { std::unordered_map staticSchedule; + // Determine allowed destination for each data cell for (DataCell* cell : dataCells) { uint64_t srcAddr = cell->getAddr(); uint64_t allowedDest = @@ -297,6 +369,7 @@ SuperNetwork::buildStaticSchedule() return staticSchedule; } +// Process packets according to the static schedule bool SuperNetwork::processPackets( const std::unordered_map& staticSchedule, @@ -304,7 +377,9 @@ SuperNetwork::processPackets( { bool packetsRemaining = false; + // Iterate through all data cells for (DataCell* cell : dataCells) { + // Skip cells without packets if (!cell->hasPackets()) { continue; } @@ -313,8 +388,9 @@ SuperNetwork::processPackets( uint64_t allowedDest = staticSchedule.at(srcAddr); uint64_t packetDest = cell->peekNextPacket(); + // Check if packet can be sent in the current time slot if (packetDest == allowedDest) { - // Allowed: remove the packet and process it + // Remove and process the packet cell->getNextPacket(); uint64_t payload = cell->getData(); @@ -327,7 +403,7 @@ SuperNetwork::processPackets( deliverPacket(srcAddr, allowedDest, payload); packetsProcessedThisWindow++; } else { - // Not allowed to send this packet in the current time slot + // Packet not allowed in the current time slot DPRINTF(SuperNetwork, "DataCell %lu: packet for %lu not scheduled (allowed: %lu)\n", srcAddr, packetDest, allowedDest @@ -343,17 +419,21 @@ SuperNetwork::processPackets( return packetsRemaining; } +// Deliver a packet to its destination data cell void SuperNetwork::deliverPacket(uint64_t srcAddr, uint64_t destAddr, uint64_t payload) { + // Find the destination data cell DataCell* destCell = getDataCell(destAddr); if (destCell != nullptr) { + // Receive data at the destination cell destCell->receiveData(payload, srcAddr); DPRINTF(SuperNetwork, "Packet delivered: src=%lu, dest=%lu, data=%lu\n", srcAddr, destAddr, payload ); + // Update total packets processed stats.totalPacketsProcessed++; } else { DPRINTF(SuperNetwork, @@ -363,17 +443,21 @@ SuperNetwork::deliverPacket(uint64_t srcAddr, } } +// Schedule the next network event void SuperNetwork::scheduleNextNetworkEvent(Tick when) { + // Schedule only if not already scheduled if (!nextNetworkEvent.scheduled()) { schedule(nextNetworkEvent, when); } } +// Constructor for SuperNetwork statistics SuperNetwork::SuperNetworkStats::SuperNetworkStats( SuperNetwork* superNetwork ) : statistics::Group(superNetwork), + // Define statistics to track ADD_STAT(activePower, statistics::units::Watt::get(), "Active power"), ADD_STAT(staticPower, statistics::units::Watt::get(), "Static power"), ADD_STAT(totalPower, statistics::units::Watt::get(), "Total power"), @@ -387,11 +471,13 @@ SuperNetwork::SuperNetworkStats::SuperNetworkStats( { } +// Register statistics for detailed tracking and reporting void SuperNetwork::SuperNetworkStats::regStats() { using namespace statistics; + // Configure statistics with names, descriptions, and formatting activePower.name("activePower") .desc("Active power") .precision(6); @@ -413,6 +499,7 @@ SuperNetwork::SuperNetworkStats::regStats() totalWindowsUsed.name("totalWindowsUsed") .desc("Number of connection windows used"); + // Calculate average packets per window pktsPerWindow.name("pktsPerWindow") .desc("Average packets processed per window") .precision(2) diff --git a/src/network/SuperNetwork.hh b/src/network/SuperNetwork.hh index 76a5bd1099..20dbc0fe48 100644 --- a/src/network/SuperNetwork.hh +++ b/src/network/SuperNetwork.hh @@ -1,3 +1,31 @@ +/* + * Copyright (c) 2025 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + #ifndef __NETWORK_SUPERNETWORK_HH__ #define __NETWORK_SUPERNETWORK_HH__ @@ -21,60 +49,82 @@ namespace gem5 class SuperNetwork : public ClockedObject { private: - std::vector dataCells; + std::vector dataCells; // Stores all data cells in the network std::unordered_map dataCellMap; - uint64_t dynamicRange; - uint64_t radix; - float timeSlot; - int connectionWindow; - uint64_t currentTimeSlotIndex; - uint64_t maxPackets; // 0 means not provided. - std::string schedulePath; // empty means not provided. + + // Network configuration parameters + uint64_t dynamicRange; // The dynamic range of the network + uint64_t radix; // Radix for the network, used in the topology + float timeSlot; // Time slot for scheduling packets + int connectionWindow; // Time window for establishing network connections + uint64_t currentTimeSlotIndex; // Current index for the time slot + uint64_t maxPackets; // Maximum number of packets, 0 means no limit + std::string schedulePath; // Path to the schedule file std::queue> scheduleQueue; - NetworkScheduler scheduler; + NetworkScheduler scheduler; // Scheduler for the network - // Initialization methods + // Initialization methods to set up network layers and data cells void initializeNetworkLayers(const std::vector& layers); void initializeDataCells(const std::vector& cells); void assignPacketsFromSchedule(); void computeNetworkParameters(); void scheduleInitialEvent(); - // Processing packets + // Methods for processing packets + // Builds a static schedule for the current time slot std::unordered_map buildStaticSchedule(); bool processPackets( const std::unordered_map& staticSchedule, uint64_t& packetsProcessedThisWindow ); + // Method for delivering a packet to its destination void deliverPacket(uint64_t srcAddr, uint64_t destAddr, uint64_t payload); + // Struct to hold statistics related to the SuperNetwork struct SuperNetworkStats: public statistics::Group { - // SRNoC statistics + // Statistics for SRNoC (Source-Routed NoC) + + // Active power consumption of the network statistics::Formula activePower; + // Static power consumption of the network statistics::Formula staticPower; + // Total power consumption of the network statistics::Formula totalPower; + // Total Josephson Junctions used in the network statistics::Formula totalJJ; - // Round-robin statistics + + // Statistics for round-robin scheduling + + // Total number of packets processed statistics::Scalar totalPacketsProcessed; + // Number of scheduling windows used statistics::Scalar totalWindowsUsed; + // Number of packets processed per time window statistics::Formula pktsPerWindow; + // Constructor that links stats to the SuperNetwork instance SuperNetworkStats(SuperNetwork* superNetwork); + + // Registers the statistics with the simulator void regStats() override; }; SuperNetworkStats stats; EventFunctionWrapper nextNetworkEvent; - void processNextNetworkEvent(); - void scheduleNextNetworkEvent(Tick when); + void processNextNetworkEvent(); // Processes the next network event + void scheduleNextNetworkEvent(Tick when); // Schedules the next event public: + // Constructor for initializing a SuperNetwork with parameters SuperNetwork(const SuperNetworkParams& params); + // Methods for adding and retrieving data cells in the network void addDataCell(DataCell* dataCell); DataCell* getDataCell(uint64_t addr); + // Methods for assigning and retrieving radix, + // time slot, and connection window values void assignRadix(uint64_t radix) { this->radix = radix; } uint64_t getRadix() const { return radix; } @@ -84,6 +134,7 @@ public: void assignConnectionWindow(int window) { connectionWindow = window; } int getConnectionWindow() const { return connectionWindow; } + // Method for calculating the power and area used by the network void calculatePowerAndArea(); }; diff --git a/src/network/SuperNetwork.py b/src/network/SuperNetwork.py index 9ad74237b0..a7de288736 100644 --- a/src/network/SuperNetwork.py +++ b/src/network/SuperNetwork.py @@ -1,3 +1,29 @@ +# Copyright (c) 2022 The Regents of the University of California +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + from m5.objects.ClockedObject import ClockedObject from m5.params import * From 636407db3d212e8855a8b7050c03714b1d3e6230 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Tue, 25 Mar 2025 10:39:30 -0700 Subject: [PATCH 03/47] misc: Add test script to configs Test Script for SRNoC model --- configs/supernetwork/SRNoC.py | 105 ++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 configs/supernetwork/SRNoC.py diff --git a/configs/supernetwork/SRNoC.py b/configs/supernetwork/SRNoC.py new file mode 100644 index 0000000000..2915352707 --- /dev/null +++ b/configs/supernetwork/SRNoC.py @@ -0,0 +1,105 @@ +# Copyright (c) 2025 The Regents of the University of California +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import argparse +import random + +import m5 +from m5.objects import * +from m5.params import * + +# Parse command-line arguments +parser = argparse.ArgumentParser(description="SuperNetwork Simulation") + +parser.add_argument( + "--maximum-packets", + type=int, + help="Maximum number of packets to process", + default=None, +) +parser.add_argument( + "--file-path", type=str, help="Path to the input file", default=None +) + +parser.add_argument( + "--num-cells", type=int, default=10, help="Number of DataCells to create" +) +parser.add_argument( + "--dynamic-range", + type=int, + default=1000, + help="Maximum value for random data generation", +) + +args = parser.parse_args() + +# Ensure that at least one of --maximum-packets or --file-path is provided +if args.maximum_packets is None and args.file_path is None: + parser.error( + "At least one of --maximum-packets or --file-path must be provided." + ) + +# Create the root SimObject and system +root = Root(full_system=False) +root.system = System() + +# Set up the clock domain and voltage domain +root.system.clk_domain = SrcClockDomain() +root.system.clk_domain.clock = "1GHz" +root.system.clk_domain.voltage_domain = VoltageDomain() + +# Create several DataCells +num_cells = args.num_cells +data_cells = [DataCell() for _ in range(num_cells)] + +layers = [Layer(range_size=args.dynamic_range)] + +# Create the SuperNetwork and add the DataCells +super_network = SuperNetwork() +super_network.dataCells = data_cells +super_network.layers = layers +super_network.max_packets = args.maximum_packets +super_network.schedule_path = args.file_path + +# Add everything to the system +root.system.super_network = super_network + +# Print test configuration +print("SRNoC Test Configuration") +print("==============================") +print(f"Number of DataCells: {num_cells}") +print(f"Dynamic Range: {args.dynamic_range}") + +if args.maximum_packets: + print(f"Maximum Packets: {args.maximum_packets}") +if args.file_path: + print(f"File Path: {args.file_path}") + +print() + +m5.instantiate() +exit_event = m5.simulate() +print(f"Exiting @ tick {m5.curTick()} because {exit_event.getCause()}") From 4ed063c2f40b65fc8c725ecaa0cfed358db6f90b Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Fri, 28 Mar 2025 22:46:00 -0700 Subject: [PATCH 04/47] misc: Encoding for zero in SRNoC One additional time slot for zero. Also, event added to show when a packet is delivered within a connection window. --- src/network/SuperNetwork.cc | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/network/SuperNetwork.cc b/src/network/SuperNetwork.cc index 1bd82ae8de..1913767706 100644 --- a/src/network/SuperNetwork.cc +++ b/src/network/SuperNetwork.cc @@ -36,6 +36,7 @@ #include "debug/SuperNetwork.hh" #include "network/NetworkScheduler.hh" +#include "sim/eventq.hh" #include "sim/sim_exit.hh" #include "sim/stats.hh" #include "sim/system.hh" @@ -123,6 +124,10 @@ SuperNetwork::initializeNetworkLayers(const std::vector& layers) // Set dynamic range from the first layer Layer* currentLayer = layers[0]; dynamicRange = currentLayer->getRangeSize(); + + // we need an encoding for 0, so increase the dynamic range by 1 + dynamicRange++; + DPRINTF(SuperNetwork, "Dynamic range: %d\n", dynamicRange); } @@ -394,13 +399,32 @@ SuperNetwork::processPackets( cell->getNextPacket(); uint64_t payload = cell->getData(); + // Calculate precise delivery time + // within the connection window + // Use the payload value -> RACE LOGIC + Tick payloadSpecificDelay = + ((payload + 1) % dynamicRange) * (getTimeSlot()); + + DPRINTF(SuperNetwork, - "Processing packet: src=%lu, dest=%lu, data=%lu\n", - srcAddr, allowedDest, payload + "Processing packet: src=%lu, dest=%lu, + data=%lu, specific delay=%lu ps\n", + srcAddr, allowedDest, payload, payloadSpecificDelay ); - // Deliver packet to destination - deliverPacket(srcAddr, allowedDest, payload); + // Schedule packet delivery with payload-specific timing + schedule(new EventFunctionWrapper([this, + srcAddr, allowedDest, payload]() { + deliverPacket(srcAddr, allowedDest, payload); + }, "deliverPacketEvent"), curTick() + payloadSpecificDelay); + + // DPRINTF(SuperNetwork, + // "Processing packet: src=%lu, dest=%lu, data=%lu\n", + // srcAddr, allowedDest, payload + // ); + + // // Deliver packet to destination + // deliverPacket(srcAddr, allowedDest, payload); packetsProcessedThisWindow++; } else { // Packet not allowed in the current time slot From f60b4389b38c5e808e1152c07f91ee8a68a73a55 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Fri, 28 Mar 2025 23:11:10 -0700 Subject: [PATCH 05/47] misc: Add more traffic patterns Hotspot and All-to-All Not integrated as selectable options yet --- src/network/NetworkScheduler.cc | 67 +++++++++++++++++++++++++++++++++ src/network/NetworkScheduler.hh | 8 ++++ 2 files changed, 75 insertions(+) diff --git a/src/network/NetworkScheduler.cc b/src/network/NetworkScheduler.cc index 3a80e4de38..b2b9bd809c 100644 --- a/src/network/NetworkScheduler.cc +++ b/src/network/NetworkScheduler.cc @@ -72,6 +72,73 @@ NetworkScheduler::initialize() } } +void +NetworkScheduler::generateAllToAllSchedule() +{ + clear(); + if (dataCells.empty()) { + warn("No DataCells available for scheduling.\n"); + return; + } + + // For each cell as a source, + // schedule packets to all other cells as destinations. + for (size_t i = 0; i < dataCells.size(); i++) { + for (size_t j = 0; j < dataCells.size(); j++) { + if (i != j) { + uint64_t srcAddr = dataCells[i]->getAddr(); + uint64_t destAddr = dataCells[j]->getAddr(); + scheduleQueue.push(std::make_pair(srcAddr, destAddr)); + } + } + } + DPRINTF(NetworkScheduler, + "All-to-All schedule generated with %d packets.\n", + scheduleQueue.size() + ); +} + +void +NetworkScheduler::generateHotspotSchedule( + uint64_t hotspotAddr, + double hotspotFraction +) +{ + clear(); + if (dataCells.empty()) { + warn("No DataCells available for scheduling.\n"); + return; + } + + // Calculate the number of hotspot packets based on hotspotFraction. + uint64_t hotspotPackets = maxPackets * hotspotFraction; + uint64_t otherPackets = maxPackets - hotspotPackets; + std::random_device rd; + std::mt19937 gen(rd()); + + // Generate packets targeting the hotspot. + for (uint64_t i = 0; i < hotspotPackets; i++) { + int srcIndex = gen() % dataCells.size(); + uint64_t srcAddr = dataCells[srcIndex]->getAddr(); + scheduleQueue.push(std::make_pair(srcAddr, hotspotAddr)); + } + + // Generate remaining random packets. + for (uint64_t i = 0; i < otherPackets; i++) { + int srcIndex = gen() % dataCells.size(); + int destIndex = gen() % dataCells.size(); + uint64_t srcAddr = dataCells[srcIndex]->getAddr(); + uint64_t destAddr = dataCells[destIndex]->getAddr(); + scheduleQueue.push(std::make_pair(srcAddr, destAddr)); + } + + DPRINTF(NetworkScheduler, + "Hotspot schedule generated: %d packets targeting hotspot %d.\n", + hotspotPackets, hotspotAddr + ); +} + + // Generates a random schedule of packets void NetworkScheduler::generateRandomSchedule() diff --git a/src/network/NetworkScheduler.hh b/src/network/NetworkScheduler.hh index 0744c07779..1f79cabc01 100644 --- a/src/network/NetworkScheduler.hh +++ b/src/network/NetworkScheduler.hh @@ -58,6 +58,14 @@ public: // Generates a random schedule for packets between DataCells void generateRandomSchedule(); + // Generates an all-to-all schedule for packets between DataCells + void generateAllToAllSchedule(); + + // Generates a hotspot schedule for packets between DataCells + void generateHotspotSchedule(uint64_t hotspotAddr, + double hotspotFraction + ); + // Saves the current schedule to a specified file void saveSchedule(); From 57ba6d8d4d2e439c9159a9d7a40f3950f29a7a8c Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Mon, 31 Mar 2025 16:48:30 -0700 Subject: [PATCH 06/47] misc: Update SRNoC model Move hardware constants out of model into Python script. Delays are now model parameters. Refactor formula stats of power and area out. --- configs/supernetwork/SRNoC.py | 113 ++++++++++++++++++++++ src/network/SuperNetwork.cc | 175 +++++++++++----------------------- src/network/SuperNetwork.hh | 21 ++-- src/network/SuperNetwork.py | 15 ++- 4 files changed, 189 insertions(+), 135 deletions(-) diff --git a/configs/supernetwork/SRNoC.py b/configs/supernetwork/SRNoC.py index 2915352707..99aad5c123 100644 --- a/configs/supernetwork/SRNoC.py +++ b/configs/supernetwork/SRNoC.py @@ -26,11 +26,110 @@ import argparse import random +from enum import Enum as PyEnum import m5 from m5.objects import * from m5.params import * + +class NetworkDelays(PyEnum): + CROSSPOINT_DELAY = 4.1 # picoseconds + MERGER_DELAY = 8.84 + SPLITTER_DELAY = 2.06 + CIRCUIT_VARIABILITY = 1.2 + VARIABILITY_COUNTING_NETWORK = 4.38 + CROSSPOINT_SETUP_TIME = 8.0 + + +class ComponentPower(PyEnum): + # Static power consumption in microwatts + SPLITTER_STATIC = 5.98 + MERGER_STATIC = 5.0 + CROSSPOINT_STATIC = 7.9 + COUNTING_NETWORK_STATIC = 66.82 + TFF_STATIC = 10.8 + + # Active power consumption in nanowatts + SPLITTER_ACTIVE = 83.2 + MERGER_ACTIVE = 69.6 + CROSSPOINT_ACTIVE = 60.7 + COUNTING_NETWORK_ACTIVE = 163.0 + TFF_ACTIVE = 105.6 + + +class ComponentJJ(PyEnum): + # Number of Josephson Junctions (JJs) + SPLITTER = 3 + MERGER = 5 + CROSSPOINT = 13 + COUNTING_NETWORK = 60 + TFF = 10 + + +def calculate_power_and_area(radix): + # Scale counting network power based on network radix + counting_network_ratio = ((radix / 2) + 1) / 4.0 + counting_network_active_power = ( + ComponentPower.COUNTING_NETWORK_ACTIVE.value * counting_network_ratio + ) + counting_network_static_power = ( + ComponentPower.COUNTING_NETWORK_STATIC.value * counting_network_ratio + ) + counting_network_jj = int( + ComponentJJ.COUNTING_NETWORK.value * counting_network_ratio + ) + + # Calculate number of components based on network radix + r = radix // 2 + num_counting_networks = r + num_crosspoints = r * r + num_splitters = r * (r * (r - 1) + 1) + num_mergers = r * (r * (r - 1) + 1) + + # Calculate active power consumption + active_power = ( + num_counting_networks * counting_network_active_power + + num_crosspoints * ComponentPower.CROSSPOINT_ACTIVE.value + + num_splitters * ComponentPower.SPLITTER_ACTIVE.value + + num_mergers * ComponentPower.MERGER_ACTIVE.value + ) + + # Calculate static power consumption + static_power = ( + num_counting_networks * counting_network_static_power + + num_crosspoints * ComponentPower.CROSSPOINT_STATIC.value + + num_splitters * ComponentPower.SPLITTER_STATIC.value + + num_mergers * ComponentPower.MERGER_STATIC.value + ) + + # Convert power units + active_power *= 1e-9 # nanowatts to watts + static_power *= 1e-6 # microwatts to watts + total_power = active_power + static_power + + # Calculate total Josephson Junctions + total_jj = ( + num_counting_networks * counting_network_jj + + num_crosspoints * ComponentJJ.CROSSPOINT.value + + num_splitters * ComponentJJ.SPLITTER.value + + num_mergers * ComponentJJ.MERGER.value + ) + + # Log and store power and area statistics + print(f"Active power: {active_power:.6f} W") + print(f"Static power: {static_power:.6f} W") + print(f"Total power: {total_power:.6f} W") + print(f"Total JJ: {total_jj}") + + return { + "active_power": active_power, + "static_power": static_power, + "total_power": total_power, + "total_jj": total_jj, + } + + # Parse command-line arguments parser = argparse.ArgumentParser(description="SuperNetwork Simulation") @@ -83,6 +182,14 @@ super_network.layers = layers super_network.max_packets = args.maximum_packets super_network.schedule_path = args.file_path +super_network.crosspoint_delay = NetworkDelays.CROSSPOINT_DELAY.value +super_network.merger_delay = NetworkDelays.MERGER_DELAY.value +super_network.splitter_delay = NetworkDelays.SPLITTER_DELAY.value +super_network.circuit_variability = NetworkDelays.CIRCUIT_VARIABILITY.value +super_network.variability_counting_network = ( + NetworkDelays.VARIABILITY_COUNTING_NETWORK.value +) +super_network.crosspoint_setup_time = NetworkDelays.CROSSPOINT_SETUP_TIME.value # Add everything to the system root.system.super_network = super_network @@ -93,6 +200,12 @@ print(f"Number of DataCells: {num_cells}") print(f"Dynamic Range: {args.dynamic_range}") +print() +print("Power and Area Statistics") +print("==============================") +power_and_area = calculate_power_and_area(radix=(num_cells * 2)) +print() + if args.maximum_packets: print(f"Maximum Packets: {args.maximum_packets}") if args.file_path: diff --git a/src/network/SuperNetwork.cc b/src/network/SuperNetwork.cc index 1913767706..9502e0cb7a 100644 --- a/src/network/SuperNetwork.cc +++ b/src/network/SuperNetwork.cc @@ -43,38 +43,38 @@ namespace gem5 { -// Hardware Constants namespace containing predefined values for various -// network components based on the SRNoC paper -namespace HardwareConstants { - // Timing delays in picoseconds for different network components - constexpr double CROSSPOINT_DELAY = 4.1; - constexpr double MERGER_DELAY = 8.84; - constexpr double SPLITTER_DELAY = 2.06; - constexpr double CIRCUIT_VARIABILITY = 1.2; - constexpr double VARIABILITY_COUNTING_NETWORK = 4.38; - constexpr double CROSSPOINT_SETUP_TIME = 8; - - // Static power consumption in microwatts for various components - constexpr double SPLITTER_STATIC_POWER = 5.98; - constexpr double MERGER_STATIC_POWER = 5; - constexpr double CROSSPOINT_STATIC_POWER = 7.9; - constexpr double COUNTING_NETWORK_STATIC_POWER = 66.82; - constexpr double TFF_STATIC_POWER = 10.8; - - // Active power consumption in nanowatts for various components - constexpr double SPLITTER_ACTIVE_POWER = 83.2; - constexpr double MERGER_ACTIVE_POWER = 69.6; - constexpr double CROSSPOINT_ACTIVE_POWER = 60.7; - constexpr double COUNTING_NETWORK_ACTIVE_POWER = 163; - constexpr double TFF_ACTIVE_POWER = 105.6; - - // Number of Josephson Junctions (JJs) for each component type - constexpr int SPLITTER_JJ = 3; - constexpr int MERGER_JJ = 5; - constexpr int CROSSPOINT_JJ = 13; - constexpr int COUNTING_NETWORK_JJ = 60; - constexpr int TFF_JJ = 10; -} +// // Hardware Constants namespace containing predefined values for various +// // network components based on the SRNoC paper +// namespace HardwareConstants { +// // Timing delays in picoseconds for different network components +// constexpr double CROSSPOINT_DELAY = 4.1; +// constexpr double MERGER_DELAY = 8.84; +// constexpr double SPLITTER_DELAY = 2.06; +// constexpr double CIRCUIT_VARIABILITY = 1.2; +// constexpr double VARIABILITY_COUNTING_NETWORK = 4.38; +// constexpr double CROSSPOINT_SETUP_TIME = 8; + +// // Static power consumption in microwatts for various components +// constexpr double SPLITTER_STATIC_POWER = 5.98; +// constexpr double MERGER_STATIC_POWER = 5; +// constexpr double CROSSPOINT_STATIC_POWER = 7.9; +// constexpr double COUNTING_NETWORK_STATIC_POWER = 66.82; +// constexpr double TFF_STATIC_POWER = 10.8; + +// // Active power consumption in nanowatts for various components +// constexpr double SPLITTER_ACTIVE_POWER = 83.2; +// constexpr double MERGER_ACTIVE_POWER = 69.6; +// constexpr double CROSSPOINT_ACTIVE_POWER = 60.7; +// constexpr double COUNTING_NETWORK_ACTIVE_POWER = 163; +// constexpr double TFF_ACTIVE_POWER = 105.6; + +// // Number of Josephson Junctions (JJs) for each component type +// constexpr int SPLITTER_JJ = 3; +// constexpr int MERGER_JJ = 5; +// constexpr int CROSSPOINT_JJ = 13; +// constexpr int COUNTING_NETWORK_JJ = 60; +// constexpr int TFF_JJ = 10; +// } // Constructor for the SuperNetwork class // Initializes the network with given parameters, sets up data cells, @@ -84,12 +84,25 @@ SuperNetwork::SuperNetwork(const SuperNetworkParams& params) : maxPackets(params.max_packets), schedulePath(params.schedule_path), scheduler(params.max_packets, params.schedule_path, params.dataCells), + crosspointDelay(params.crosspoint_delay), + mergerDelay(params.merger_delay), + splitterDelay(params.splitter_delay), + circuitVariability(params.circuit_variability), + variabilityCountingNetwork(params.variability_counting_network), + crosspointSetupTime(params.crosspoint_setup_time), currentTimeSlotIndex(0), // Event for processing the next network event nextNetworkEvent([this]{ processNextNetworkEvent(); }, name() + ".nextNetworkEvent"), stats(this) { + assert(params.crosspoint_delay >= 0); + assert(params.merger_delay >= 0); + assert(params.splitter_delay >= 0); + assert(params.circuit_variability >= 0); + assert(params.variability_counting_network >= 0); + assert(params.crosspoint_setup_time >= 0); + // Initialize network layers initializeNetworkLayers(params.layers); @@ -106,7 +119,6 @@ SuperNetwork::SuperNetwork(const SuperNetworkParams& params) : computeNetworkParameters(); // Calculate power consumption and area requirements - calculatePowerAndArea(); // Schedule the initial network event scheduleInitialEvent(); @@ -216,88 +228,28 @@ SuperNetwork::scheduleInitialEvent() // Schedule the first network event if packets exist if (!dataCells.empty() && hasPackets) { DPRINTF(SuperNetwork, "Scheduling first network event\n"); - scheduleNextNetworkEvent(curTick() + 1); // Start at the next tick + scheduleNextNetworkEvent(curTick()); // Start at this tick } else { DPRINTF(SuperNetwork, "No packets to process\n"); } } -// Calculate power consumption and area requirements for the network -void -SuperNetwork::calculatePowerAndArea() -{ - using namespace HardwareConstants; - - // Scale counting network power based on network radix - double countingNetworkRatio = (((getRadix()/2) + 1) / 4.0); - double countingNetworkActivePower = - COUNTING_NETWORK_ACTIVE_POWER * countingNetworkRatio; - double countingNetworkStaticPower = - COUNTING_NETWORK_STATIC_POWER * countingNetworkRatio; - int countingNetworkJJ = COUNTING_NETWORK_JJ * countingNetworkRatio; - - // Calculate number of components based on network radix - int r = radix/2; - int numCountingNetworks = r; - int numCrosspoints = r * r; - int numSplitters = r * (r * (r - 1) + 1); - int numMergers = r * (r * (r - 1) + 1); - - // Calculate active power consumption - double activePower = - numCountingNetworks * countingNetworkActivePower + - numCrosspoints * CROSSPOINT_ACTIVE_POWER + - numSplitters * SPLITTER_ACTIVE_POWER + - numMergers * MERGER_ACTIVE_POWER; - - // Calculate static power consumption - double staticPower = - numCountingNetworks * countingNetworkStaticPower + - numCrosspoints * CROSSPOINT_STATIC_POWER + - numSplitters * SPLITTER_STATIC_POWER + - numMergers * MERGER_STATIC_POWER; - - // Convert power units - activePower *= 1e-9; // nanowatts to watts - staticPower *= 1e-6; // microwatts to watts - double totalPower = activePower + staticPower; - - // Calculate total Josephson Junctions - int totalJJ = - numCountingNetworks * countingNetworkJJ + - numCrosspoints * CROSSPOINT_JJ + - numSplitters * SPLITTER_JJ + - numMergers * MERGER_JJ; - - // Log and store power and area statistics - DPRINTF(SuperNetwork, "Active power: %.6f W\n", activePower); - DPRINTF(SuperNetwork, "Static power: %.6f W\n", staticPower); - DPRINTF(SuperNetwork, "Total power: %.6f W\n", totalPower); - DPRINTF(SuperNetwork, "Total JJ: %d\n", totalJJ); - - stats.activePower = activePower; - stats.staticPower = staticPower; - stats.totalPower = totalPower; - stats.totalJJ = totalJJ; -} - // Calculate the time slot based on network component delays void SuperNetwork::assignTimeSlot() { - using namespace HardwareConstants; - // Adjust setup time considering circuit variability double SE_adjusted = std::max(0.0, - CROSSPOINT_SETUP_TIME - CIRCUIT_VARIABILITY + crosspointSetupTime - circuitVariability ); // Calculate time slot considering delays of various network components - double calculatedTimeSlot = CIRCUIT_VARIABILITY * ( - CROSSPOINT_DELAY + SE_adjusted + - SPLITTER_DELAY * (radix - 1) + - MERGER_DELAY * (radix - 1) + - VARIABILITY_COUNTING_NETWORK); + double calculatedTimeSlot = circuitVariability * ( + crosspointDelay + SE_adjusted + + splitterDelay * (radix - 1) + + mergerDelay * (radix - 1) + + variabilityCountingNetwork + ); // Round up the calculated time slot this->timeSlot = std::ceil(calculatedTimeSlot); @@ -407,7 +359,7 @@ SuperNetwork::processPackets( DPRINTF(SuperNetwork, - "Processing packet: src=%lu, dest=%lu, + "Processing packet: src=%lu, dest=%lu, \ data=%lu, specific delay=%lu ps\n", srcAddr, allowedDest, payload, payloadSpecificDelay ); @@ -481,11 +433,6 @@ SuperNetwork::scheduleNextNetworkEvent(Tick when) SuperNetwork::SuperNetworkStats::SuperNetworkStats( SuperNetwork* superNetwork ) : statistics::Group(superNetwork), - // Define statistics to track - ADD_STAT(activePower, statistics::units::Watt::get(), "Active power"), - ADD_STAT(staticPower, statistics::units::Watt::get(), "Static power"), - ADD_STAT(totalPower, statistics::units::Watt::get(), "Total power"), - ADD_STAT(totalJJ, statistics::units::Count::get(), "Total JJ"), ADD_STAT(totalPacketsProcessed, statistics::units::Count::get(), "Total packets processed"), ADD_STAT(totalWindowsUsed, statistics::units::Count::get(), @@ -502,20 +449,6 @@ SuperNetwork::SuperNetworkStats::regStats() using namespace statistics; // Configure statistics with names, descriptions, and formatting - activePower.name("activePower") - .desc("Active power") - .precision(6); - - staticPower.name("staticPower") - .desc("Static power") - .precision(6); - - totalPower.name("totalPower") - .desc("Total power") - .precision(6); - - totalJJ.name("totalJJ") - .desc("Total number of Josephson Junctions"); totalPacketsProcessed.name("totalPacketsProcessed") .desc("Total number of packets processed"); diff --git a/src/network/SuperNetwork.hh b/src/network/SuperNetwork.hh index 20dbc0fe48..063325abb6 100644 --- a/src/network/SuperNetwork.hh +++ b/src/network/SuperNetwork.hh @@ -52,13 +52,21 @@ private: std::vector dataCells; // Stores all data cells in the network std::unordered_map dataCellMap; + // network delay parameters + double crosspointDelay; + double mergerDelay; + double splitterDelay; + double circuitVariability; + double variabilityCountingNetwork; + double crosspointSetupTime; + // Network configuration parameters uint64_t dynamicRange; // The dynamic range of the network uint64_t radix; // Radix for the network, used in the topology float timeSlot; // Time slot for scheduling packets int connectionWindow; // Time window for establishing network connections uint64_t currentTimeSlotIndex; // Current index for the time slot - uint64_t maxPackets; // Maximum number of packets, 0 means no limit + int maxPackets; // Maximum number of packets, -1 means no limit std::string schedulePath; // Path to the schedule file std::queue> scheduleQueue; NetworkScheduler scheduler; // Scheduler for the network @@ -85,15 +93,6 @@ private: { // Statistics for SRNoC (Source-Routed NoC) - // Active power consumption of the network - statistics::Formula activePower; - // Static power consumption of the network - statistics::Formula staticPower; - // Total power consumption of the network - statistics::Formula totalPower; - // Total Josephson Junctions used in the network - statistics::Formula totalJJ; - // Statistics for round-robin scheduling // Total number of packets processed @@ -134,8 +133,6 @@ public: void assignConnectionWindow(int window) { connectionWindow = window; } int getConnectionWindow() const { return connectionWindow; } - // Method for calculating the power and area used by the network - void calculatePowerAndArea(); }; } // namespace gem5 diff --git a/src/network/SuperNetwork.py b/src/network/SuperNetwork.py index a7de288736..6e0e16e21b 100644 --- a/src/network/SuperNetwork.py +++ b/src/network/SuperNetwork.py @@ -40,11 +40,22 @@ class SuperNetwork(ClockedObject): layers = VectorParam.Layer("Layers in the network") # max_packets: 0 means not provided - max_packets = Param.UInt64( - 0, "Maximum number of packets to schedule; 0 means not provided" + max_packets = Param.Int( + -1, "Maximum number of packets to schedule; 0 means not provided" ) # schedule_path: empty string means not provided schedule_path = Param.String( "", "File path for schedule (empty means not provided)" ) + + crosspoint_delay = Param.Float(-1, "Crosspoint delay in picoseconds") + merger_delay = Param.Float(-1, "Merger delay in picoseconds") + splitter_delay = Param.Float(-1, "Splitter delay in picoseconds") + circuit_variability = Param.Float(-1, "Circuit variability in picoseconds") + variability_counting_network = Param.Float( + -1, "Variability in counting network in picoseconds" + ) + crosspoint_setup_time = Param.Float( + -1, "Crosspoint setup time in picoseconds" + ) From 1c1103558fc7cbac48eb1ff89fdc294bc4ce8ba2 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Mon, 31 Mar 2025 17:08:36 -0700 Subject: [PATCH 07/47] misc: Update SRNoC stats Packets per window is a histogram. Also, minor change to Param description in SuperNetwork to align with default. --- src/network/SuperNetwork.cc | 17 +++++++++++------ src/network/SuperNetwork.hh | 4 ++-- src/network/SuperNetwork.py | 2 +- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/network/SuperNetwork.cc b/src/network/SuperNetwork.cc index 9502e0cb7a..d96f4ab10b 100644 --- a/src/network/SuperNetwork.cc +++ b/src/network/SuperNetwork.cc @@ -292,6 +292,9 @@ SuperNetwork::processNextNetworkEvent() // Update statistics stats.totalWindowsUsed++; + // Update packets per window distribution + stats.pktsPerWindow.sample(packetsProcessedThisWindow); + // Advance the time slot for the next event currentTimeSlotIndex++; @@ -438,7 +441,7 @@ SuperNetwork::SuperNetworkStats::SuperNetworkStats( ADD_STAT(totalWindowsUsed, statistics::units::Count::get(), "Number of connection windows used"), ADD_STAT(pktsPerWindow, statistics::units::Count::get(), - "Average packets per window") + "Distribution of packets per window") { } @@ -457,11 +460,13 @@ SuperNetwork::SuperNetworkStats::regStats() .desc("Number of connection windows used"); // Calculate average packets per window - pktsPerWindow.name("pktsPerWindow") - .desc("Average packets processed per window") - .precision(2) - .flags(nozero) - = totalPacketsProcessed / totalWindowsUsed; + // pktsPerWindow.name("pktsPerWindow") + // .desc("Average packets processed per window") + // .precision(2) + // .flags(nozero) + // = totalPacketsProcessed / totalWindowsUsed; + + pktsPerWindow.init(64); } } // namespace gem5 diff --git a/src/network/SuperNetwork.hh b/src/network/SuperNetwork.hh index 063325abb6..275cf246e0 100644 --- a/src/network/SuperNetwork.hh +++ b/src/network/SuperNetwork.hh @@ -99,8 +99,8 @@ private: statistics::Scalar totalPacketsProcessed; // Number of scheduling windows used statistics::Scalar totalWindowsUsed; - // Number of packets processed per time window - statistics::Formula pktsPerWindow; + // Distribution of packets processed per time window + statistics::Histogram pktsPerWindow; // Constructor that links stats to the SuperNetwork instance SuperNetworkStats(SuperNetwork* superNetwork); diff --git a/src/network/SuperNetwork.py b/src/network/SuperNetwork.py index 6e0e16e21b..5410673f4a 100644 --- a/src/network/SuperNetwork.py +++ b/src/network/SuperNetwork.py @@ -41,7 +41,7 @@ class SuperNetwork(ClockedObject): # max_packets: 0 means not provided max_packets = Param.Int( - -1, "Maximum number of packets to schedule; 0 means not provided" + -1, "Maximum number of packets to schedule; -1 means not provided" ) # schedule_path: empty string means not provided From de5cf2314be110b1ba9c5946d300f0905088f914 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Mon, 31 Mar 2025 21:52:04 -0700 Subject: [PATCH 08/47] misc: Fix exitSimLoop bug Fixed a bug where the simulation exited before the last packet was delivered. --- src/network/SuperNetwork.cc | 19 +++++++++++++++---- src/network/SuperNetwork.hh | 1 + 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/network/SuperNetwork.cc b/src/network/SuperNetwork.cc index d96f4ab10b..5d98fa654c 100644 --- a/src/network/SuperNetwork.cc +++ b/src/network/SuperNetwork.cc @@ -301,9 +301,6 @@ SuperNetwork::processNextNetworkEvent() // Schedule next network event or exit simulation if (packetsRemaining) { scheduleNextNetworkEvent(curTick() + connectionWindow); - } else { - DPRINTF(SuperNetwork, "All packets processed\n"); - exitSimLoop("All packets processed"); } } @@ -336,6 +333,7 @@ SuperNetwork::processPackets( uint64_t& packetsProcessedThisWindow) { bool packetsRemaining = false; + Tick payloadSpecificDelay; // Iterate through all data cells for (DataCell* cell : dataCells) { @@ -357,7 +355,7 @@ SuperNetwork::processPackets( // Calculate precise delivery time // within the connection window // Use the payload value -> RACE LOGIC - Tick payloadSpecificDelay = + payloadSpecificDelay = ((payload + 1) % dynamicRange) * (getTimeSlot()); @@ -395,6 +393,19 @@ SuperNetwork::processPackets( } } + if (!packetsRemaining) { + DPRINTF(SuperNetwork, "All packets processed in window %lu\n", + currentTimeSlotIndex); + DPRINTF(SuperNetwork, "Payload specific delay: %lu\n", + payloadSpecificDelay + ); + // schedule exit + exitSimLoop("All packets processed", 0, + curTick() + payloadSpecificDelay, 0, + false + ); + } + return packetsRemaining; } diff --git a/src/network/SuperNetwork.hh b/src/network/SuperNetwork.hh index 275cf246e0..11d4c0ce25 100644 --- a/src/network/SuperNetwork.hh +++ b/src/network/SuperNetwork.hh @@ -67,6 +67,7 @@ private: int connectionWindow; // Time window for establishing network connections uint64_t currentTimeSlotIndex; // Current index for the time slot int maxPackets; // Maximum number of packets, -1 means no limit + int pendingDeliveries; // Number of pending packet deliveries std::string schedulePath; // Path to the schedule file std::queue> scheduleQueue; NetworkScheduler scheduler; // Scheduler for the network From ce40530c8e6710af904035dea949c165fc815027 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Mon, 31 Mar 2025 23:19:43 -0700 Subject: [PATCH 09/47] misc: Effect of Frequency on SRNoC Frequency now affects time slot and connection window. --- src/network/SuperNetwork.cc | 23 ++++++++++++++++------- src/network/SuperNetwork.hh | 8 ++++---- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/network/SuperNetwork.cc b/src/network/SuperNetwork.cc index 5d98fa654c..a6111975d9 100644 --- a/src/network/SuperNetwork.cc +++ b/src/network/SuperNetwork.cc @@ -205,11 +205,19 @@ SuperNetwork::computeNetworkParameters() { // Calculate and assign the time slot assignTimeSlot(); - DPRINTF(SuperNetwork, "Time slot: %.0f ps\n", getTimeSlot()); + DPRINTF(SuperNetwork, "Time slot: %d Cycles\n", getTimeSlot()); + DPRINTF(SuperNetwork, "Time slot: %d ps\n", + getTimeSlot() * clockPeriod()/714 + ); // Calculate and assign the connection window - assignConnectionWindow(dynamicRange * getTimeSlot()); - DPRINTF(SuperNetwork, "Connection window: %d\n", getConnectionWindow()); + assignConnectionWindow(Cycles(dynamicRange * getTimeSlot())); + DPRINTF(SuperNetwork, "Connection window: %d Cycles\n", + getConnectionWindow() + ); + DPRINTF(SuperNetwork, "Connection window: %d ps\n", + getConnectionWindow() * clockPeriod()/714 + ); } // Schedule the initial network event if there are packets to process @@ -252,7 +260,7 @@ SuperNetwork::assignTimeSlot() ); // Round up the calculated time slot - this->timeSlot = std::ceil(calculatedTimeSlot); + this->timeSlot = Cycles(std::ceil(calculatedTimeSlot)); } // Add a data cell to the network's data cell collection @@ -300,7 +308,8 @@ SuperNetwork::processNextNetworkEvent() // Schedule next network event or exit simulation if (packetsRemaining) { - scheduleNextNetworkEvent(curTick() + connectionWindow); + scheduleNextNetworkEvent(curTick() + + connectionWindow * clockPeriod()/714); } } @@ -355,8 +364,8 @@ SuperNetwork::processPackets( // Calculate precise delivery time // within the connection window // Use the payload value -> RACE LOGIC - payloadSpecificDelay = - ((payload + 1) % dynamicRange) * (getTimeSlot()); + payloadSpecificDelay = ((payload + 1) % dynamicRange) * + (getTimeSlot()) * clockPeriod()/714; DPRINTF(SuperNetwork, diff --git a/src/network/SuperNetwork.hh b/src/network/SuperNetwork.hh index 11d4c0ce25..3a5a2d653f 100644 --- a/src/network/SuperNetwork.hh +++ b/src/network/SuperNetwork.hh @@ -63,8 +63,8 @@ private: // Network configuration parameters uint64_t dynamicRange; // The dynamic range of the network uint64_t radix; // Radix for the network, used in the topology - float timeSlot; // Time slot for scheduling packets - int connectionWindow; // Time window for establishing network connections + Cycles timeSlot; // Time slot for scheduling packets + Cycles connectionWindow; // Connection window uint64_t currentTimeSlotIndex; // Current index for the time slot int maxPackets; // Maximum number of packets, -1 means no limit int pendingDeliveries; // Number of pending packet deliveries @@ -129,9 +129,9 @@ public: uint64_t getRadix() const { return radix; } void assignTimeSlot(); - float getTimeSlot() const { return timeSlot; } + Cycles getTimeSlot() const { return timeSlot; } - void assignConnectionWindow(int window) { connectionWindow = window; } + void assignConnectionWindow(Cycles window) { connectionWindow = window; } int getConnectionWindow() const { return connectionWindow; } }; From 539ce83de3aeff37b5fcbf141d5c99c34d439cc8 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Tue, 1 Apr 2025 16:14:29 -0700 Subject: [PATCH 10/47] misc: Refactor out precomputed schedule Now, destination is computed in the network event If it is allowed, send it. If not, push it into the buffer and send when allowed. --- src/network/NetworkScheduler.cc | 65 ++++++++++++++++++- src/network/NetworkScheduler.hh | 10 +++ src/network/SuperNetwork.cc | 108 +++++++++++++++++++++----------- src/network/SuperNetwork.hh | 2 +- 4 files changed, 144 insertions(+), 41 deletions(-) diff --git a/src/network/NetworkScheduler.cc b/src/network/NetworkScheduler.cc index b2b9bd809c..8a05ce78f0 100644 --- a/src/network/NetworkScheduler.cc +++ b/src/network/NetworkScheduler.cc @@ -192,6 +192,66 @@ NetworkScheduler::saveSchedule() DPRINTF(NetworkScheduler, "Schedule saved to %s.\n", schedulePath); } +// Generates a random packet using the given src. +// It picks a random destination from dataCells. +uint64_t +NetworkScheduler::generateRandomPacket(uint64_t src) +{ + if (dataCells.empty()) { + warn("No DataCells available for scheduling.\n"); + return -1; + } + + // Random number generator setup + std::random_device rd; + std::mt19937 gen(rd()); + + uint64_t destAddr = src; + if (dataCells.size() > 1) { + int destIndex = gen() % dataCells.size(); + destAddr = dataCells[destIndex]->getAddr(); + } + + return destAddr; +} + +// Generates a hotspot packet using the +// given src, hotspotAddr and hotspotFraction. +// It generates a packet targeting the hotspot with +// probability hotspotFraction. +uint64_t +NetworkScheduler::generateHotspotPacket( + uint64_t src, + uint64_t hotspotAddr, + double hotspotFraction +) +{ + if (dataCells.empty()) { + warn("No DataCells available for scheduling.\n"); + return -1; + } + + // Random number generator setup + std::random_device rd; + std::mt19937 gen(rd()); + + // Generate a packet targeting the hotspot + // with probability hotspotFraction. + if (gen() % 100 < hotspotFraction * 100) { + return hotspotAddr; + } + + // Generate a random packet targeting a random destination. + uint64_t destAddr = src; + if (dataCells.size() > 1) { + int destIndex = gen() % dataCells.size(); + destAddr = dataCells[destIndex]->getAddr(); + } + + return destAddr; +} + + // Loads a schedule from a file void NetworkScheduler::loadSchedule() @@ -274,8 +334,9 @@ std::pair NetworkScheduler::getNextPacket() { if (scheduleQueue.empty()) { - // Return a default packet with {0, 0} if the queue is empty - return {0, 0}; + // Return a default packet with {-1, -1} + // if the queue is empty + return {-1, -1}; } // Retrieve and remove the next packet from the queue diff --git a/src/network/NetworkScheduler.hh b/src/network/NetworkScheduler.hh index 1f79cabc01..cd88afeff8 100644 --- a/src/network/NetworkScheduler.hh +++ b/src/network/NetworkScheduler.hh @@ -58,6 +58,9 @@ public: // Generates a random schedule for packets between DataCells void generateRandomSchedule(); + // Generates a random packet using the given src + uint64_t generateRandomPacket(uint64_t src); + // Generates an all-to-all schedule for packets between DataCells void generateAllToAllSchedule(); @@ -66,6 +69,13 @@ public: double hotspotFraction ); + // Generates a hotspot packet + // using the given src, hotspotAddr and hotspotFraction + uint64_t generateHotspotPacket(uint64_t src, + uint64_t hotspotAddr, + double hotspotFraction + ); + // Saves the current schedule to a specified file void saveSchedule(); diff --git a/src/network/SuperNetwork.cc b/src/network/SuperNetwork.cc index a6111975d9..1daeca6cd7 100644 --- a/src/network/SuperNetwork.cc +++ b/src/network/SuperNetwork.cc @@ -90,6 +90,7 @@ SuperNetwork::SuperNetwork(const SuperNetworkParams& params) : circuitVariability(params.circuit_variability), variabilityCountingNetwork(params.variability_counting_network), crosspointSetupTime(params.crosspoint_setup_time), + packetsDelivered(0), currentTimeSlotIndex(0), // Event for processing the next network event nextNetworkEvent([this]{ processNextNetworkEvent(); }, @@ -113,15 +114,13 @@ SuperNetwork::SuperNetwork(const SuperNetworkParams& params) : scheduler.initialize(); // Assign packets from the predefined schedule - assignPacketsFromSchedule(); + // assignPacketsFromSchedule(); // Compute network parameters like time slot and connection window computeNetworkParameters(); - // Calculate power consumption and area requirements - // Schedule the initial network event - scheduleInitialEvent(); + scheduleNextNetworkEvent(curTick()); } // Initialize network layers, setting the dynamic range @@ -284,7 +283,6 @@ SuperNetwork::getDataCell(uint64_t addr) void SuperNetwork::processNextNetworkEvent() { - bool packetsRemaining = false; uint64_t packetsProcessedThisWindow = 0; // Build a static schedule for the current time slot @@ -292,22 +290,18 @@ SuperNetwork::processNextNetworkEvent() buildStaticSchedule(); // Process packets according to the static schedule - packetsRemaining = processPackets( + bool packetsRemaining = processPackets( staticSchedule, packetsProcessedThisWindow ); - // Update statistics stats.totalWindowsUsed++; - // Update packets per window distribution - stats.pktsPerWindow.sample(packetsProcessedThisWindow); - // Advance the time slot for the next event currentTimeSlotIndex++; - // Schedule next network event or exit simulation - if (packetsRemaining) { + // Schedule next network event + if (packetsDelivered < maxPackets) { scheduleNextNetworkEvent(curTick() + connectionWindow * clockPeriod()/714); } @@ -335,30 +329,41 @@ SuperNetwork::buildStaticSchedule() return staticSchedule; } +// Process packets according to the static schedule // Process packets according to the static schedule bool SuperNetwork::processPackets( const std::unordered_map& staticSchedule, uint64_t& packetsProcessedThisWindow) { - bool packetsRemaining = false; - Tick payloadSpecificDelay; + Tick payloadSpecificDelay = 0; // Iterate through all data cells for (DataCell* cell : dataCells) { - // Skip cells without packets - if (!cell->hasPackets()) { - continue; + // Check if we've already reached the maximum packets + if (packetsDelivered >= maxPackets) { + break; // Exit the loop immediately if we've reached max packets } uint64_t srcAddr = cell->getAddr(); uint64_t allowedDest = staticSchedule.at(srcAddr); - uint64_t packetDest = cell->peekNextPacket(); + + uint64_t packetDest; + // Check if there's already a packet in the buffer first + if (cell->hasPackets()) { + packetDest = cell->peekNextPacket(); + } else { + // Only generate a new packet if there's nothing in the buffer + packetDest = scheduler.generateRandomPacket(srcAddr); + assert(packetDest != -1); + } // Check if packet can be sent in the current time slot if (packetDest == allowedDest) { - // Remove and process the packet - cell->getNextPacket(); + // Remove the packet if it was from the buffer + if (cell->hasPackets()) { + cell->getNextPacket(); + } uint64_t payload = cell->getData(); // Calculate precise delivery time @@ -367,12 +372,14 @@ SuperNetwork::processPackets( payloadSpecificDelay = ((payload + 1) % dynamicRange) * (getTimeSlot()) * clockPeriod()/714; - DPRINTF(SuperNetwork, "Processing packet: src=%lu, dest=%lu, \ data=%lu, specific delay=%lu ps\n", srcAddr, allowedDest, payload, payloadSpecificDelay ); + stats.totalPacketsProcessed++; + packetsDelivered++; + packetsProcessedThisWindow++; // Schedule packet delivery with payload-specific timing schedule(new EventFunctionWrapper([this, @@ -380,29 +387,56 @@ SuperNetwork::processPackets( deliverPacket(srcAddr, allowedDest, payload); }, "deliverPacketEvent"), curTick() + payloadSpecificDelay); - // DPRINTF(SuperNetwork, - // "Processing packet: src=%lu, dest=%lu, data=%lu\n", - // srcAddr, allowedDest, payload - // ); - - // // Deliver packet to destination - // deliverPacket(srcAddr, allowedDest, payload); - packetsProcessedThisWindow++; + // Check if we've reached max packets after processing this one + if (packetsDelivered >= maxPackets) { + break; + } + // } else if (cell->hasPackets() && + // cell->peekNextPacket() == allowedDest) { + // cell->getNextPacket(); + // Above call should remove the packet from the queue + // uint64_t payload = cell->getData(); + + // // Calculate precise delivery time (as before) + // payloadSpecificDelay = ((payload + 1) % dynamicRange) * + // (getTimeSlot()) * clockPeriod() / 714; + + // DPRINTF(SuperNetwork, + // "Processing packet: src=%lu, dest=%lu, data=%lu, + // specific delay=%lu ps\n", + // srcAddr, allowedDest, payload, payloadSpecificDelay + // ); + + // packetsDelivered++; + // packetsProcessedThisWindow++; + + // // Schedule packet delivery with payload-specific timing + // schedule(new EventFunctionWrapper([this, + // srcAddr, allowedDest, payload]() { + // deliverPacket(srcAddr, allowedDest, payload); + // }, "deliverPacketEvent"), curTick() + payloadSpecificDelay); + + // // Check if we've reached max packets after processing this one + // if (packetsDelivered >= maxPackets) { + // break; + // } } else { // Packet not allowed in the current time slot + cell->assignPacket(packetDest); DPRINTF(SuperNetwork, "DataCell %lu: packet for %lu not scheduled (allowed: %lu)\n", srcAddr, packetDest, allowedDest ); - } - - // Check if cell still has packets - if (cell->hasPackets()) { - packetsRemaining = true; + DPRINTF(SuperNetwork, + "DataCell %lu: packet for %lu assigned to buffer\n", + srcAddr, packetDest + ); } } - if (!packetsRemaining) { + stats.pktsPerWindow.sample(packetsProcessedThisWindow); + + if (packetsDelivered >= maxPackets) { DPRINTF(SuperNetwork, "All packets processed in window %lu\n", currentTimeSlotIndex); DPRINTF(SuperNetwork, "Payload specific delay: %lu\n", @@ -415,7 +449,7 @@ SuperNetwork::processPackets( ); } - return packetsRemaining; + return (packetsDelivered < maxPackets); } // Deliver a packet to its destination data cell @@ -432,8 +466,6 @@ SuperNetwork::deliverPacket(uint64_t srcAddr, "Packet delivered: src=%lu, dest=%lu, data=%lu\n", srcAddr, destAddr, payload ); - // Update total packets processed - stats.totalPacketsProcessed++; } else { DPRINTF(SuperNetwork, "Error: Destination cell %lu not found\n", diff --git a/src/network/SuperNetwork.hh b/src/network/SuperNetwork.hh index 3a5a2d653f..9e74abaab5 100644 --- a/src/network/SuperNetwork.hh +++ b/src/network/SuperNetwork.hh @@ -67,7 +67,7 @@ private: Cycles connectionWindow; // Connection window uint64_t currentTimeSlotIndex; // Current index for the time slot int maxPackets; // Maximum number of packets, -1 means no limit - int pendingDeliveries; // Number of pending packet deliveries + int packetsDelivered; // Number of packet deliveries std::string schedulePath; // Path to the schedule file std::queue> scheduleQueue; NetworkScheduler scheduler; // Scheduler for the network From f2b8a57a73da6297bbbab0dd2f43634ad35c2f5f Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Tue, 1 Apr 2025 22:32:02 -0700 Subject: [PATCH 11/47] misc: SuperNetwork functionality moved to Layer Layer send packets based on scheduling Network now has a vector of Layers Config script also changed to reflect this change --- configs/supernetwork/SRNoC.py | 16 +- src/network/Layer.cc | 453 ++++++++++++++++++++++++++++- src/network/Layer.hh | 110 ++++++- src/network/Layer.py | 19 +- src/network/SConscript | 1 + src/network/SuperNetwork.cc | 519 ++++------------------------------ src/network/SuperNetwork.hh | 91 +----- src/network/SuperNetwork.py | 15 +- 8 files changed, 635 insertions(+), 589 deletions(-) diff --git a/configs/supernetwork/SRNoC.py b/configs/supernetwork/SRNoC.py index 99aad5c123..b8af5ab6e7 100644 --- a/configs/supernetwork/SRNoC.py +++ b/configs/supernetwork/SRNoC.py @@ -167,21 +167,27 @@ def calculate_power_and_area(radix): # Set up the clock domain and voltage domain root.system.clk_domain = SrcClockDomain() -root.system.clk_domain.clock = "1GHz" +root.system.clk_domain.clock = "1.4GHz" root.system.clk_domain.voltage_domain = VoltageDomain() # Create several DataCells num_cells = args.num_cells data_cells = [DataCell() for _ in range(num_cells)] -layers = [Layer(range_size=args.dynamic_range)] +layers = [ + Layer( + dynamic_range=args.dynamic_range, + data_cells=data_cells, + max_packets=args.maximum_packets, + schedule_path=args.file_path, + ) +] # Create the SuperNetwork and add the DataCells super_network = SuperNetwork() -super_network.dataCells = data_cells + super_network.layers = layers -super_network.max_packets = args.maximum_packets -super_network.schedule_path = args.file_path + super_network.crosspoint_delay = NetworkDelays.CROSSPOINT_DELAY.value super_network.merger_delay = NetworkDelays.MERGER_DELAY.value super_network.splitter_delay = NetworkDelays.SPLITTER_DELAY.value diff --git a/src/network/Layer.cc b/src/network/Layer.cc index 7b65e5491e..b77be91ac5 100644 --- a/src/network/Layer.cc +++ b/src/network/Layer.cc @@ -28,25 +28,464 @@ #include "network/Layer.hh" +#include +#include +#include +#include +#include + +#include "debug/Layer.hh" +#include "network/NetworkScheduler.hh" +#include "sim/eventq.hh" #include "sim/sim_exit.hh" #include "sim/stats.hh" #include "sim/system.hh" -namespace gem5 -{ +namespace gem5 { + +// // Hardware Constants namespace containing predefined values for various +// // network components based on the SRNoC paper +// namespace HardwareConstants { +// // Timing delays in picoseconds for different network components +// constexpr double CROSSPOINT_DELAY = 4.1; +// constexpr double MERGER_DELAY = 8.84; +// constexpr double SPLITTER_DELAY = 2.06; +// constexpr double CIRCUIT_VARIABILITY = 1.2; +// constexpr double VARIABILITY_COUNTING_NETWORK = 4.38; +// constexpr double CROSSPOINT_SETUP_TIME = 8; + +// // Static power consumption in microwatts for various components +// constexpr double SPLITTER_STATIC_POWER = 5.98; +// constexpr double MERGER_STATIC_POWER = 5; +// constexpr double CROSSPOINT_STATIC_POWER = 7.9; +// constexpr double COUNTING_NETWORK_STATIC_POWER = 66.82; +// constexpr double TFF_STATIC_POWER = 10.8; + +// // Active power consumption in nanowatts for various components +// constexpr double SPLITTER_ACTIVE_POWER = 83.2; +// constexpr double MERGER_ACTIVE_POWER = 69.6; +// constexpr double CROSSPOINT_ACTIVE_POWER = 60.7; +// constexpr double COUNTING_NETWORK_ACTIVE_POWER = 163; +// constexpr double TFF_ACTIVE_POWER = 105.6; + +// // Number of Josephson Junctions (JJs) for each component type +// constexpr int SPLITTER_JJ = 3; +// constexpr int MERGER_JJ = 5; +// constexpr int CROSSPOINT_JJ = 13; +// constexpr int COUNTING_NETWORK_JJ = 60; +// constexpr int TFF_JJ = 10; +// } // Constructor for the Layer class +// Initializes the network with given parameters, sets up data cells, +// and prepares for packet scheduling Layer::Layer(const LayerParams& params) : ClockedObject(params), - rangeSize(params.range_size) + maxPackets(params.max_packets), + schedulePath(params.schedule_path), + scheduler(params.max_packets, params.schedule_path, params.data_cells), + dynamicRange(params.dynamic_range), + packetsDelivered(0), + currentTimeSlotIndex(0), + // Event for processing the next network event + nextNetworkEvent([this]{ processNextNetworkEvent(); }, + name() + ".nextNetworkEvent"), + stats(this) +{ + + // Initialize data cells with random data + initializeDataCells(params.data_cells); + + // Initialize the network scheduler + scheduler.initialize(); + + // Assign packets from the predefined schedule + // assignPacketsFromSchedule(); + + // Compute network parameters like time slot and connection window + // computeNetworkParameters(); + + // // Schedule the initial network event + // scheduleNextNetworkEvent(curTick()); +} + +// Initialize data cells with random data and unique addresses +void +Layer::initializeDataCells(const std::vector& cells) { + // Skip if no data cells are provided + if (cells.empty()) { + return; + } + + // Set network radix + assignRadix(cells.size() * 2); + + // Populate data cells with addresses and random data + for (uint64_t i = 0; i < cells.size(); i++) { + DataCell* cell = cells[i]; + cell->setAddr(i); + + // Generate random data within the dynamic range + uint64_t randomData = random() % dynamicRange; + cell->setData(randomData); + + DPRINTF(Layer, "DataCell %d: addr=%d, data=%d\n", + i, cell->getAddr(), cell->getData()); + + // Add the cell to the network + addDataCell(cell); + } } -// Returns the range size of the Layer -uint64_t -Layer::getRangeSize() const +// Assign packets to data cells based on the predefined schedule +void +Layer::assignPacketsFromSchedule() { - return rangeSize; + uint64_t packetCount = 0; + + // Process all packets in the scheduler + while (scheduler.hasPackets()) { + // Get the next packet's source and destination addresses + auto [srcAddr, destAddr] = scheduler.getNextPacket(); + + // Find the source data cell + DataCell* cell = getDataCell(srcAddr); + if (cell != nullptr) { + DPRINTF(Layer, + "Assigning packet: src=%d, dest=%d\n", + srcAddr, destAddr + ); + // Assign the packet to the source cell + cell->assignPacket(destAddr); + packetCount++; + } + } + + DPRINTF(Layer, "Total packets assigned: %d\n", packetCount); +} + +// Compute key network parameters like time slot and connection window +// void +// Layer::computeNetworkParameters() +// { +// // Calculate and assign the time slot +// assignTimeSlot(); +// DPRINTF(Layer, "Time slot: %d Cycles\n", getTimeSlot()); +// DPRINTF(Layer, "Time slot: %d ps\n", +// getTimeSlot() * clockPeriod()/714 +// ); + +// // Calculate and assign the connection window +// assignConnectionWindow(Cycles(dynamicRange * getTimeSlot())); +// DPRINTF(Layer, "Connection window: %d Cycles\n", +// getConnectionWindow() +// ); +// DPRINTF(Layer, "Connection window: %d ps\n", +// getConnectionWindow() * clockPeriod()/714 +// ); +// } + +// Schedule the initial network event if there are packets to process +// void +// Layer::scheduleInitialEvent() +// { +// bool hasPackets = false; +// // Check if any data cell has packets +// for (DataCell* cell : dataCells) { +// if (cell->hasPackets()) { +// hasPackets = true; +// break; +// } +// } + +// // Schedule the first network event if packets exist +// if (!dataCells.empty() && hasPackets) { +// DPRINTF(Layer, "Scheduling first network event\n"); +// scheduleNextNetworkEvent(curTick()); // Start at this tick +// } else { +// DPRINTF(Layer, "No packets to process\n"); +// } +// } + +// Calculate the time slot based on network component delays +// void +// Layer::assignTimeSlot() +// { +// // Adjust setup time considering circuit variability +// double SE_adjusted = std::max(0.0, +// crosspointSetupTime - circuitVariability +// ); + +// // Calculate time slot considering delays of various network components +// double calculatedTimeSlot = circuitVariability * ( +// crosspointDelay + SE_adjusted + +// splitterDelay * (radix - 1) + +// mergerDelay * (radix - 1) + +// variabilityCountingNetwork +// ); + +// // Round up the calculated time slot +// this->timeSlot = Cycles(std::ceil(calculatedTimeSlot)); +// } + +// Add a data cell to the network's data cell collection +void +Layer::addDataCell(DataCell* dataCell) +{ + dataCells.push_back(dataCell); + uint64_t addr = dataCell->getAddr(); + dataCellMap[addr] = dataCell; +} + +// Retrieve a data cell by its address +DataCell* +Layer::getDataCell(uint64_t addr) +{ + auto it = dataCellMap.find(addr); + return (it != dataCellMap.end()) ? it->second : nullptr; +} + +// Process the next network event in the simulation +void +Layer::processNextNetworkEvent() +{ + uint64_t packetsProcessedThisWindow = 0; + + // Build a static schedule for the current time slot + std::unordered_map staticSchedule = + buildStaticSchedule(); + + // Process packets according to the static schedule + bool packetsRemaining = processPackets( + staticSchedule, + packetsProcessedThisWindow + ); + + stats.totalWindowsUsed++; + + // Advance the time slot for the next event + currentTimeSlotIndex++; + + // Schedule next network event + if (packetsDelivered < maxPackets) { + scheduleNextNetworkEvent(curTick() + + connectionWindow * clockPeriod()/714); + } +} + +// Build a static schedule for packet transmission in the current time slot +std::unordered_map +Layer::buildStaticSchedule() +{ + std::unordered_map staticSchedule; + + // Determine allowed destination for each data cell + for (DataCell* cell : dataCells) { + uint64_t srcAddr = cell->getAddr(); + uint64_t allowedDest = + (srcAddr + currentTimeSlotIndex) % dataCells.size(); + staticSchedule[srcAddr] = allowedDest; + + DPRINTF(Layer, + "Window %lu: allowed transmission from DataCell %lu to %lu\n", + currentTimeSlotIndex, srcAddr, allowedDest + ); + } + + return staticSchedule; +} + +// Process packets according to the static schedule +// Process packets according to the static schedule +bool +Layer::processPackets( + const std::unordered_map& staticSchedule, + uint64_t& packetsProcessedThisWindow) +{ + Tick payloadSpecificDelay = 0; + + // Iterate through all data cells + for (DataCell* cell : dataCells) { + // Check if we've already reached the maximum packets + if (packetsDelivered >= maxPackets) { + break; // Exit the loop immediately if we've reached max packets + } + + uint64_t srcAddr = cell->getAddr(); + uint64_t allowedDest = staticSchedule.at(srcAddr); + + uint64_t packetDest; + // Check if there's already a packet in the buffer first + if (cell->hasPackets()) { + packetDest = cell->peekNextPacket(); + } else { + // Only generate a new packet if there's nothing in the buffer + packetDest = scheduler.generateRandomPacket(srcAddr); + assert(packetDest != -1); + } + + // Check if packet can be sent in the current time slot + if (packetDest == allowedDest) { + // Remove the packet if it was from the buffer + if (cell->hasPackets()) { + cell->getNextPacket(); + } + uint64_t payload = cell->getData(); + + // Calculate precise delivery time + // within the connection window + // Use the payload value -> RACE LOGIC + payloadSpecificDelay = ((payload + 1) % dynamicRange) * + (getTimeSlot()) * clockPeriod()/714; + + DPRINTF(Layer, + "Processing packet: src=%lu, dest=%lu, \ + data=%lu, specific delay=%lu ps\n", + srcAddr, allowedDest, payload, payloadSpecificDelay + ); + stats.totalPacketsProcessed++; + packetsDelivered++; + packetsProcessedThisWindow++; + + // Schedule packet delivery with payload-specific timing + schedule(new EventFunctionWrapper([this, + srcAddr, allowedDest, payload]() { + deliverPacket(srcAddr, allowedDest, payload); + }, "deliverPacketEvent"), curTick() + payloadSpecificDelay); + + // Check if we've reached max packets after processing this one + if (packetsDelivered >= maxPackets) { + break; + } + // } else if (cell->hasPackets() && + // cell->peekNextPacket() == allowedDest) { + // cell->getNextPacket(); + // Above call should remove the packet from the queue + // uint64_t payload = cell->getData(); + + // // Calculate precise delivery time (as before) + // payloadSpecificDelay = ((payload + 1) % dynamicRange) * + // (getTimeSlot()) * clockPeriod() / 714; + + // DPRINTF(Layer, + // "Processing packet: src=%lu, dest=%lu, data=%lu, + // specific delay=%lu ps\n", + // srcAddr, allowedDest, payload, payloadSpecificDelay + // ); + + // packetsDelivered++; + // packetsProcessedThisWindow++; + + // // Schedule packet delivery with payload-specific timing + // schedule(new EventFunctionWrapper([this, + // srcAddr, allowedDest, payload]() { + // deliverPacket(srcAddr, allowedDest, payload); + // }, "deliverPacketEvent"), curTick() + payloadSpecificDelay); + + // // Check if we've reached max packets after processing this one + // if (packetsDelivered >= maxPackets) { + // break; + // } + } else { + // Packet not allowed in the current time slot + cell->assignPacket(packetDest); + DPRINTF(Layer, + "DataCell %lu: packet for %lu not scheduled (allowed: %lu)\n", + srcAddr, packetDest, allowedDest + ); + DPRINTF(Layer, + "DataCell %lu: packet for %lu assigned to buffer\n", + srcAddr, packetDest + ); + } + } + + stats.pktsPerWindow.sample(packetsProcessedThisWindow); + + if (packetsDelivered >= maxPackets) { + DPRINTF(Layer, "All packets processed in window %lu\n", + currentTimeSlotIndex); + DPRINTF(Layer, "Payload specific delay: %lu\n", + payloadSpecificDelay + ); + // schedule exit + exitSimLoop("All packets processed", 0, + curTick() + payloadSpecificDelay, 0, + false + ); + } + + return (packetsDelivered < maxPackets); +} + +// Deliver a packet to its destination data cell +void +Layer::deliverPacket(uint64_t srcAddr, + uint64_t destAddr, uint64_t payload) +{ + // Find the destination data cell + DataCell* destCell = getDataCell(destAddr); + if (destCell != nullptr) { + // Receive data at the destination cell + destCell->receiveData(payload, srcAddr); + DPRINTF(Layer, + "Packet delivered: src=%lu, dest=%lu, data=%lu\n", + srcAddr, destAddr, payload + ); + } else { + DPRINTF(Layer, + "Error: Destination cell %lu not found\n", + destAddr + ); + } +} + +// Schedule the next network event +void +Layer::scheduleNextNetworkEvent(Tick when) +{ + // Schedule only if not already scheduled + if (!nextNetworkEvent.scheduled()) { + schedule(nextNetworkEvent, when); + } +} + +// Constructor for Layer statistics +Layer::LayerStats::LayerStats( + Layer* Layer + ) : statistics::Group(Layer), + ADD_STAT(totalPacketsProcessed, statistics::units::Count::get(), + "Total packets processed"), + ADD_STAT(totalWindowsUsed, statistics::units::Count::get(), + "Number of connection windows used"), + ADD_STAT(pktsPerWindow, statistics::units::Count::get(), + "Distribution of packets per window") +{ +} + +// Register statistics for detailed tracking and reporting +void +Layer::LayerStats::regStats() +{ + using namespace statistics; + + // Configure statistics with names, descriptions, and formatting + + totalPacketsProcessed.name("totalPacketsProcessed") + .desc("Total number of packets processed"); + + totalWindowsUsed.name("totalWindowsUsed") + .desc("Number of connection windows used"); + + // Calculate average packets per window + // pktsPerWindow.name("pktsPerWindow") + // .desc("Average packets processed per window") + // .precision(2) + // .flags(nozero) + // = totalPacketsProcessed / totalWindowsUsed; + + pktsPerWindow.init(64); } } // namespace gem5 diff --git a/src/network/Layer.hh b/src/network/Layer.hh index ee3a879ad1..110b5d7d53 100644 --- a/src/network/Layer.hh +++ b/src/network/Layer.hh @@ -26,28 +26,120 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __NETWORK_LAYER_HH__ -#define __NETWORK_LAYER_HH__ +#ifndef __NETWORK_Layer_HH__ +#define __NETWORK_Layer_HH__ +#include +#include +#include +#include + +#include "base/statistics.hh" +#include "base/stats/group.hh" +#include "network/DataCell.hh" +#include "network/Layer.hh" +#include "network/NetworkScheduler.hh" #include "params/Layer.hh" #include "sim/clocked_object.hh" +#include "sim/eventq.hh" namespace gem5 { class Layer : public ClockedObject { - private: - uint64_t rangeSize; +private: + std::vector dataCells; // Stores all data cells in the network + std::unordered_map dataCellMap; + + // network delay parameters + // double crosspointDelay; + // double mergerDelay; + // double splitterDelay; + // double circuitVariability; + // double variabilityCountingNetwork; + // double crosspointSetupTime; + + // Network configuration parameters + uint64_t dynamicRange; // The dynamic range of the network + uint64_t radix; // Radix for the network, used in the topology + Cycles timeSlot; // Time slot for scheduling packets + Cycles connectionWindow; // Connection window + uint64_t currentTimeSlotIndex; // Current index for the time slot + int maxPackets; // Maximum number of packets, -1 means no limit + int packetsDelivered; // Number of packet deliveries + std::string schedulePath; // Path to the schedule file + std::queue> scheduleQueue; + NetworkScheduler scheduler; // Scheduler for the network + + // Initialization methods to set up network layers and data cells + void initializeNetworkLayers(const std::vector& layers); + void initializeDataCells(const std::vector& cells); + void assignPacketsFromSchedule(); + void computeNetworkParameters(); + + // Methods for processing packets + // Builds a static schedule for the current time slot + std::unordered_map buildStaticSchedule(); + bool processPackets( + const std::unordered_map& staticSchedule, + uint64_t& packetsProcessedThisWindow + ); + // Method for delivering a packet to its destination + void deliverPacket(uint64_t srcAddr, uint64_t destAddr, uint64_t payload); + + // Struct to hold statistics related to the Layer + struct LayerStats: public statistics::Group + { + // Statistics for SRNoC (Source-Routed NoC) + + // Statistics for round-robin scheduling + + // Total number of packets processed + statistics::Scalar totalPacketsProcessed; + // Number of scheduling windows used + statistics::Scalar totalWindowsUsed; + // Distribution of packets processed per time window + statistics::Histogram pktsPerWindow; + + // Constructor that links stats to the Layer instance + LayerStats(Layer* Layer); - public: - // Constructor: Initializes the Layer with given parameters + // Registers the statistics with the simulator + void regStats() override; + }; + + LayerStats stats; + EventFunctionWrapper nextNetworkEvent; + void processNextNetworkEvent(); // Processes the next network event + +public: + // Constructor for initializing a Layer with parameters Layer(const LayerParams& params); - // Returns the range size of the Layer - uint64_t getRangeSize() const; + // Methods for adding and retrieving data cells in the network + void addDataCell(DataCell* dataCell); + DataCell* getDataCell(uint64_t addr); + + uint64_t getDynamicRange() const { return dynamicRange; } + + // Methods for assigning and retrieving radix, + // time slot, and connection window values + void assignRadix(uint64_t radix) { this->radix = radix; } + uint64_t getRadix() const { return radix; } + + void assignTimeSlot(); + Cycles getTimeSlot() const { return timeSlot; } + void setTimeSlot(Cycles timeSlot) { this->timeSlot = timeSlot; } + + void setConnectionWindow(Cycles window) { connectionWindow = window; } + int getConnectionWindow() const { return connectionWindow; } + + void scheduleNextNetworkEvent(Tick when); // Schedules the next event + + }; } // namespace gem5 -#endif // __NETWORK_LAYER_HH__ +#endif // __NETWORK_Layer_HH__ diff --git a/src/network/Layer.py b/src/network/Layer.py index 047ea3300b..859a5dca90 100644 --- a/src/network/Layer.py +++ b/src/network/Layer.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022 The Regents of the University of California +# Copyright (c) 2025 The Regents of the University of California # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -26,7 +26,6 @@ from m5.objects.ClockedObject import ClockedObject from m5.params import * -from m5.proxy import * class Layer(ClockedObject): @@ -34,5 +33,17 @@ class Layer(ClockedObject): cxx_header = "network/Layer.hh" cxx_class = "gem5::Layer" - # Layer parameters - range_size = Param.UInt64("Range size of the layer (dynamic range)") + # Vector of data cells in the network + data_cells = VectorParam.DataCell("Data cells in the layer") + + dynamic_range = Param.UInt64("Range size of the layer (dynamic range)") + + # max_packets: 0 means not provided + max_packets = Param.Int( + -1, "Maximum number of packets to schedule; -1 means not provided" + ) + + # schedule_path: empty string means not provided + schedule_path = Param.String( + "", "File path for schedule (empty means not provided)" + ) diff --git a/src/network/SConscript b/src/network/SConscript index d25c0bba5c..02d1471745 100644 --- a/src/network/SConscript +++ b/src/network/SConscript @@ -12,3 +12,4 @@ Source('NetworkScheduler.cc') DebugFlag("SuperNetwork") DebugFlag("DataCell") DebugFlag("NetworkScheduler") +DebugFlag("Layer") diff --git a/src/network/SuperNetwork.cc b/src/network/SuperNetwork.cc index 1daeca6cd7..f7703dcb4f 100644 --- a/src/network/SuperNetwork.cc +++ b/src/network/SuperNetwork.cc @@ -35,490 +35,71 @@ #include #include "debug/SuperNetwork.hh" +#include "network/Layer.hh" #include "network/NetworkScheduler.hh" #include "sim/eventq.hh" #include "sim/sim_exit.hh" #include "sim/stats.hh" #include "sim/system.hh" -namespace gem5 { - -// // Hardware Constants namespace containing predefined values for various -// // network components based on the SRNoC paper -// namespace HardwareConstants { -// // Timing delays in picoseconds for different network components -// constexpr double CROSSPOINT_DELAY = 4.1; -// constexpr double MERGER_DELAY = 8.84; -// constexpr double SPLITTER_DELAY = 2.06; -// constexpr double CIRCUIT_VARIABILITY = 1.2; -// constexpr double VARIABILITY_COUNTING_NETWORK = 4.38; -// constexpr double CROSSPOINT_SETUP_TIME = 8; - -// // Static power consumption in microwatts for various components -// constexpr double SPLITTER_STATIC_POWER = 5.98; -// constexpr double MERGER_STATIC_POWER = 5; -// constexpr double CROSSPOINT_STATIC_POWER = 7.9; -// constexpr double COUNTING_NETWORK_STATIC_POWER = 66.82; -// constexpr double TFF_STATIC_POWER = 10.8; - -// // Active power consumption in nanowatts for various components -// constexpr double SPLITTER_ACTIVE_POWER = 83.2; -// constexpr double MERGER_ACTIVE_POWER = 69.6; -// constexpr double CROSSPOINT_ACTIVE_POWER = 60.7; -// constexpr double COUNTING_NETWORK_ACTIVE_POWER = 163; -// constexpr double TFF_ACTIVE_POWER = 105.6; - -// // Number of Josephson Junctions (JJs) for each component type -// constexpr int SPLITTER_JJ = 3; -// constexpr int MERGER_JJ = 5; -// constexpr int CROSSPOINT_JJ = 13; -// constexpr int COUNTING_NETWORK_JJ = 60; -// constexpr int TFF_JJ = 10; -// } - -// Constructor for the SuperNetwork class -// Initializes the network with given parameters, sets up data cells, -// and prepares for packet scheduling -SuperNetwork::SuperNetwork(const SuperNetworkParams& params) : - ClockedObject(params), - maxPackets(params.max_packets), - schedulePath(params.schedule_path), - scheduler(params.max_packets, params.schedule_path, params.dataCells), - crosspointDelay(params.crosspoint_delay), - mergerDelay(params.merger_delay), - splitterDelay(params.splitter_delay), - circuitVariability(params.circuit_variability), - variabilityCountingNetwork(params.variability_counting_network), - crosspointSetupTime(params.crosspoint_setup_time), - packetsDelivered(0), - currentTimeSlotIndex(0), - // Event for processing the next network event - nextNetworkEvent([this]{ processNextNetworkEvent(); }, - name() + ".nextNetworkEvent"), - stats(this) -{ - assert(params.crosspoint_delay >= 0); - assert(params.merger_delay >= 0); - assert(params.splitter_delay >= 0); - assert(params.circuit_variability >= 0); - assert(params.variability_counting_network >= 0); - assert(params.crosspoint_setup_time >= 0); - - // Initialize network layers - initializeNetworkLayers(params.layers); - - // Initialize data cells with random data - initializeDataCells(params.dataCells); - - // Initialize the network scheduler - scheduler.initialize(); - - // Assign packets from the predefined schedule - // assignPacketsFromSchedule(); - - // Compute network parameters like time slot and connection window - computeNetworkParameters(); - - // Schedule the initial network event - scheduleNextNetworkEvent(curTick()); -} - -// Initialize network layers, setting the dynamic range -void -SuperNetwork::initializeNetworkLayers(const std::vector& layers) -{ - // Ensure at least one layer is provided - if (layers.empty()) { - fatal("At least one Layer must be provided to SuperNetwork.\n"); - } - - // Set dynamic range from the first layer - Layer* currentLayer = layers[0]; - dynamicRange = currentLayer->getRangeSize(); - - // we need an encoding for 0, so increase the dynamic range by 1 - dynamicRange++; - - DPRINTF(SuperNetwork, "Dynamic range: %d\n", dynamicRange); -} - -// Initialize data cells with random data and unique addresses -void -SuperNetwork::initializeDataCells(const std::vector& cells) -{ - // Skip if no data cells are provided - if (cells.empty()) { - return; - } - - // Set network radix - assignRadix(cells.size() * 2); - - // Populate data cells with addresses and random data - for (uint64_t i = 0; i < cells.size(); i++) { - DataCell* cell = cells[i]; - cell->setAddr(i); - - // Generate random data within the dynamic range - uint64_t randomData = random() % dynamicRange; - cell->setData(randomData); - - DPRINTF(SuperNetwork, "DataCell %d: addr=%d, data=%d\n", - i, cell->getAddr(), cell->getData()); - - // Add the cell to the network - addDataCell(cell); - } -} - -// Assign packets to data cells based on the predefined schedule -void -SuperNetwork::assignPacketsFromSchedule() -{ - uint64_t packetCount = 0; - - // Process all packets in the scheduler - while (scheduler.hasPackets()) { - // Get the next packet's source and destination addresses - auto [srcAddr, destAddr] = scheduler.getNextPacket(); - - // Find the source data cell - DataCell* cell = getDataCell(srcAddr); - if (cell != nullptr) { - DPRINTF(SuperNetwork, - "Assigning packet: src=%d, dest=%d\n", - srcAddr, destAddr +namespace gem5 +{ + SuperNetwork::SuperNetwork(const SuperNetworkParams& params) + : ClockedObject(params), + crosspointDelay(params.crosspoint_delay), + mergerDelay(params.merger_delay), + splitterDelay(params.splitter_delay), + circuitVariability(params.circuit_variability), + variabilityCountingNetwork(params.variability_counting_network), + crosspointSetupTime(params.crosspoint_setup_time) + { + assert(params.crosspoint_delay >= 0); + assert(params.merger_delay >= 0); + assert(params.splitter_delay >= 0); + assert(params.circuit_variability >= 0); + assert(params.variability_counting_network >= 0); + assert(params.crosspoint_setup_time >= 0); + + // Initialize the network layers + // for (int i = 0; i < params.layers.size(); i++) { + // Layer* layer = new Layer(params.layers[i]); + // layers.push_back(layer); + // } + + for (auto layer : params.layers) { + layer->setTimeSlot(calculateTimeSlot(layer->getRadix())); + DPRINTF(SuperNetwork, "Layer %d: time slot = %d\n", + layer->getRadix(), layer->getTimeSlot() ); - // Assign the packet to the source cell - cell->assignPacket(destAddr); - packetCount++; - } - } - - DPRINTF(SuperNetwork, "Total packets assigned: %d\n", packetCount); -} - -// Compute key network parameters like time slot and connection window -void -SuperNetwork::computeNetworkParameters() -{ - // Calculate and assign the time slot - assignTimeSlot(); - DPRINTF(SuperNetwork, "Time slot: %d Cycles\n", getTimeSlot()); - DPRINTF(SuperNetwork, "Time slot: %d ps\n", - getTimeSlot() * clockPeriod()/714 - ); - - // Calculate and assign the connection window - assignConnectionWindow(Cycles(dynamicRange * getTimeSlot())); - DPRINTF(SuperNetwork, "Connection window: %d Cycles\n", - getConnectionWindow() - ); - DPRINTF(SuperNetwork, "Connection window: %d ps\n", - getConnectionWindow() * clockPeriod()/714 - ); -} - -// Schedule the initial network event if there are packets to process -void -SuperNetwork::scheduleInitialEvent() -{ - bool hasPackets = false; - // Check if any data cell has packets - for (DataCell* cell : dataCells) { - if (cell->hasPackets()) { - hasPackets = true; - break; - } - } - - // Schedule the first network event if packets exist - if (!dataCells.empty() && hasPackets) { - DPRINTF(SuperNetwork, "Scheduling first network event\n"); - scheduleNextNetworkEvent(curTick()); // Start at this tick - } else { - DPRINTF(SuperNetwork, "No packets to process\n"); - } -} - -// Calculate the time slot based on network component delays -void -SuperNetwork::assignTimeSlot() -{ - // Adjust setup time considering circuit variability - double SE_adjusted = std::max(0.0, - crosspointSetupTime - circuitVariability - ); - - // Calculate time slot considering delays of various network components - double calculatedTimeSlot = circuitVariability * ( - crosspointDelay + SE_adjusted + - splitterDelay * (radix - 1) + - mergerDelay * (radix - 1) + - variabilityCountingNetwork - ); - - // Round up the calculated time slot - this->timeSlot = Cycles(std::ceil(calculatedTimeSlot)); -} - -// Add a data cell to the network's data cell collection -void -SuperNetwork::addDataCell(DataCell* dataCell) -{ - dataCells.push_back(dataCell); - uint64_t addr = dataCell->getAddr(); - dataCellMap[addr] = dataCell; -} - -// Retrieve a data cell by its address -DataCell* -SuperNetwork::getDataCell(uint64_t addr) -{ - auto it = dataCellMap.find(addr); - return (it != dataCellMap.end()) ? it->second : nullptr; -} - -// Process the next network event in the simulation -void -SuperNetwork::processNextNetworkEvent() -{ - uint64_t packetsProcessedThisWindow = 0; - - // Build a static schedule for the current time slot - std::unordered_map staticSchedule = - buildStaticSchedule(); - - // Process packets according to the static schedule - bool packetsRemaining = processPackets( - staticSchedule, - packetsProcessedThisWindow - ); - - stats.totalWindowsUsed++; - - // Advance the time slot for the next event - currentTimeSlotIndex++; - - // Schedule next network event - if (packetsDelivered < maxPackets) { - scheduleNextNetworkEvent(curTick() + - connectionWindow * clockPeriod()/714); - } -} - -// Build a static schedule for packet transmission in the current time slot -std::unordered_map -SuperNetwork::buildStaticSchedule() -{ - std::unordered_map staticSchedule; - - // Determine allowed destination for each data cell - for (DataCell* cell : dataCells) { - uint64_t srcAddr = cell->getAddr(); - uint64_t allowedDest = - (srcAddr + currentTimeSlotIndex) % dataCells.size(); - staticSchedule[srcAddr] = allowedDest; - - DPRINTF(SuperNetwork, - "Window %lu: allowed transmission from DataCell %lu to %lu\n", - currentTimeSlotIndex, srcAddr, allowedDest - ); - } - - return staticSchedule; -} - -// Process packets according to the static schedule -// Process packets according to the static schedule -bool -SuperNetwork::processPackets( - const std::unordered_map& staticSchedule, - uint64_t& packetsProcessedThisWindow) -{ - Tick payloadSpecificDelay = 0; - - // Iterate through all data cells - for (DataCell* cell : dataCells) { - // Check if we've already reached the maximum packets - if (packetsDelivered >= maxPackets) { - break; // Exit the loop immediately if we've reached max packets - } - - uint64_t srcAddr = cell->getAddr(); - uint64_t allowedDest = staticSchedule.at(srcAddr); - - uint64_t packetDest; - // Check if there's already a packet in the buffer first - if (cell->hasPackets()) { - packetDest = cell->peekNextPacket(); - } else { - // Only generate a new packet if there's nothing in the buffer - packetDest = scheduler.generateRandomPacket(srcAddr); - assert(packetDest != -1); - } - - // Check if packet can be sent in the current time slot - if (packetDest == allowedDest) { - // Remove the packet if it was from the buffer - if (cell->hasPackets()) { - cell->getNextPacket(); - } - uint64_t payload = cell->getData(); - - // Calculate precise delivery time - // within the connection window - // Use the payload value -> RACE LOGIC - payloadSpecificDelay = ((payload + 1) % dynamicRange) * - (getTimeSlot()) * clockPeriod()/714; - - DPRINTF(SuperNetwork, - "Processing packet: src=%lu, dest=%lu, \ - data=%lu, specific delay=%lu ps\n", - srcAddr, allowedDest, payload, payloadSpecificDelay - ); - stats.totalPacketsProcessed++; - packetsDelivered++; - packetsProcessedThisWindow++; - - // Schedule packet delivery with payload-specific timing - schedule(new EventFunctionWrapper([this, - srcAddr, allowedDest, payload]() { - deliverPacket(srcAddr, allowedDest, payload); - }, "deliverPacketEvent"), curTick() + payloadSpecificDelay); - - // Check if we've reached max packets after processing this one - if (packetsDelivered >= maxPackets) { - break; - } - // } else if (cell->hasPackets() && - // cell->peekNextPacket() == allowedDest) { - // cell->getNextPacket(); - // Above call should remove the packet from the queue - // uint64_t payload = cell->getData(); - - // // Calculate precise delivery time (as before) - // payloadSpecificDelay = ((payload + 1) % dynamicRange) * - // (getTimeSlot()) * clockPeriod() / 714; - - // DPRINTF(SuperNetwork, - // "Processing packet: src=%lu, dest=%lu, data=%lu, - // specific delay=%lu ps\n", - // srcAddr, allowedDest, payload, payloadSpecificDelay - // ); - - // packetsDelivered++; - // packetsProcessedThisWindow++; - - // // Schedule packet delivery with payload-specific timing - // schedule(new EventFunctionWrapper([this, - // srcAddr, allowedDest, payload]() { - // deliverPacket(srcAddr, allowedDest, payload); - // }, "deliverPacketEvent"), curTick() + payloadSpecificDelay); - - // // Check if we've reached max packets after processing this one - // if (packetsDelivered >= maxPackets) { - // break; - // } - } else { - // Packet not allowed in the current time slot - cell->assignPacket(packetDest); - DPRINTF(SuperNetwork, - "DataCell %lu: packet for %lu not scheduled (allowed: %lu)\n", - srcAddr, packetDest, allowedDest - ); - DPRINTF(SuperNetwork, - "DataCell %lu: packet for %lu assigned to buffer\n", - srcAddr, packetDest + layer->setConnectionWindow(Cycles(layer->getDynamicRange() * + timeSlot)); + DPRINTF(SuperNetwork, "Layer %d: connection window = %d\n", + layer->getRadix(), layer->getConnectionWindow() ); + layer->scheduleNextNetworkEvent(curTick()); } } - stats.pktsPerWindow.sample(packetsProcessedThisWindow); - - if (packetsDelivered >= maxPackets) { - DPRINTF(SuperNetwork, "All packets processed in window %lu\n", - currentTimeSlotIndex); - DPRINTF(SuperNetwork, "Payload specific delay: %lu\n", - payloadSpecificDelay - ); - // schedule exit - exitSimLoop("All packets processed", 0, - curTick() + payloadSpecificDelay, 0, - false + Cycles + SuperNetwork::calculateTimeSlot(uint64_t radix) + { + // Adjust setup time considering circuit variability + double SE_adjusted = std::max(0.0, + crosspointSetupTime - circuitVariability ); - } - return (packetsDelivered < maxPackets); -} - -// Deliver a packet to its destination data cell -void -SuperNetwork::deliverPacket(uint64_t srcAddr, - uint64_t destAddr, uint64_t payload) -{ - // Find the destination data cell - DataCell* destCell = getDataCell(destAddr); - if (destCell != nullptr) { - // Receive data at the destination cell - destCell->receiveData(payload, srcAddr); - DPRINTF(SuperNetwork, - "Packet delivered: src=%lu, dest=%lu, data=%lu\n", - srcAddr, destAddr, payload - ); - } else { - DPRINTF(SuperNetwork, - "Error: Destination cell %lu not found\n", - destAddr + // Calculate time slot considering delays of various network components + double calculatedTimeSlot = circuitVariability * ( + crosspointDelay + SE_adjusted + + splitterDelay * (radix - 1) + + mergerDelay * (radix - 1) + + variabilityCountingNetwork ); - } -} - -// Schedule the next network event -void -SuperNetwork::scheduleNextNetworkEvent(Tick when) -{ - // Schedule only if not already scheduled - if (!nextNetworkEvent.scheduled()) { - schedule(nextNetworkEvent, when); - } -} - -// Constructor for SuperNetwork statistics -SuperNetwork::SuperNetworkStats::SuperNetworkStats( - SuperNetwork* superNetwork - ) : statistics::Group(superNetwork), - ADD_STAT(totalPacketsProcessed, statistics::units::Count::get(), - "Total packets processed"), - ADD_STAT(totalWindowsUsed, statistics::units::Count::get(), - "Number of connection windows used"), - ADD_STAT(pktsPerWindow, statistics::units::Count::get(), - "Distribution of packets per window") -{ -} -// Register statistics for detailed tracking and reporting -void -SuperNetwork::SuperNetworkStats::regStats() -{ - using namespace statistics; - - // Configure statistics with names, descriptions, and formatting - - totalPacketsProcessed.name("totalPacketsProcessed") - .desc("Total number of packets processed"); + // Round up the calculated time slot + this->timeSlot = Cycles(std::ceil(calculatedTimeSlot)); + return this->timeSlot; - totalWindowsUsed.name("totalWindowsUsed") - .desc("Number of connection windows used"); - - // Calculate average packets per window - // pktsPerWindow.name("pktsPerWindow") - // .desc("Average packets processed per window") - // .precision(2) - // .flags(nozero) - // = totalPacketsProcessed / totalWindowsUsed; - - pktsPerWindow.init(64); -} + } } // namespace gem5 diff --git a/src/network/SuperNetwork.hh b/src/network/SuperNetwork.hh index 9e74abaab5..4c6103ad8b 100644 --- a/src/network/SuperNetwork.hh +++ b/src/network/SuperNetwork.hh @@ -29,28 +29,24 @@ #ifndef __NETWORK_SUPERNETWORK_HH__ #define __NETWORK_SUPERNETWORK_HH__ -#include -#include -#include -#include - -#include "base/statistics.hh" -#include "base/stats/group.hh" #include "network/DataCell.hh" #include "network/Layer.hh" #include "network/NetworkScheduler.hh" #include "params/SuperNetwork.hh" #include "sim/clocked_object.hh" #include "sim/eventq.hh" +#include "sim/sim_exit.hh" +#include "sim/stats.hh" namespace gem5 { class SuperNetwork : public ClockedObject { -private: - std::vector dataCells; // Stores all data cells in the network - std::unordered_map dataCellMap; + private: + std::vector layers; + + Cycles timeSlot; // network delay parameters double crosspointDelay; @@ -60,79 +56,12 @@ private: double variabilityCountingNetwork; double crosspointSetupTime; - // Network configuration parameters - uint64_t dynamicRange; // The dynamic range of the network - uint64_t radix; // Radix for the network, used in the topology - Cycles timeSlot; // Time slot for scheduling packets - Cycles connectionWindow; // Connection window - uint64_t currentTimeSlotIndex; // Current index for the time slot - int maxPackets; // Maximum number of packets, -1 means no limit - int packetsDelivered; // Number of packet deliveries - std::string schedulePath; // Path to the schedule file - std::queue> scheduleQueue; - NetworkScheduler scheduler; // Scheduler for the network - - // Initialization methods to set up network layers and data cells - void initializeNetworkLayers(const std::vector& layers); - void initializeDataCells(const std::vector& cells); - void assignPacketsFromSchedule(); - void computeNetworkParameters(); - void scheduleInitialEvent(); - - // Methods for processing packets - // Builds a static schedule for the current time slot - std::unordered_map buildStaticSchedule(); - bool processPackets( - const std::unordered_map& staticSchedule, - uint64_t& packetsProcessedThisWindow - ); - // Method for delivering a packet to its destination - void deliverPacket(uint64_t srcAddr, uint64_t destAddr, uint64_t payload); - - // Struct to hold statistics related to the SuperNetwork - struct SuperNetworkStats: public statistics::Group - { - // Statistics for SRNoC (Source-Routed NoC) - - // Statistics for round-robin scheduling - - // Total number of packets processed - statistics::Scalar totalPacketsProcessed; - // Number of scheduling windows used - statistics::Scalar totalWindowsUsed; - // Distribution of packets processed per time window - statistics::Histogram pktsPerWindow; - - // Constructor that links stats to the SuperNetwork instance - SuperNetworkStats(SuperNetwork* superNetwork); - - // Registers the statistics with the simulator - void regStats() override; - }; - - SuperNetworkStats stats; - EventFunctionWrapper nextNetworkEvent; - void processNextNetworkEvent(); // Processes the next network event - void scheduleNextNetworkEvent(Tick when); // Schedules the next event - -public: - // Constructor for initializing a SuperNetwork with parameters + public: + // Constructor: Initializes the SuperNetwork with given parameters SuperNetwork(const SuperNetworkParams& params); - // Methods for adding and retrieving data cells in the network - void addDataCell(DataCell* dataCell); - DataCell* getDataCell(uint64_t addr); - - // Methods for assigning and retrieving radix, - // time slot, and connection window values - void assignRadix(uint64_t radix) { this->radix = radix; } - uint64_t getRadix() const { return radix; } - - void assignTimeSlot(); - Cycles getTimeSlot() const { return timeSlot; } - - void assignConnectionWindow(Cycles window) { connectionWindow = window; } - int getConnectionWindow() const { return connectionWindow; } + // Calculate time slot + Cycles calculateTimeSlot(uint64_t radix); }; diff --git a/src/network/SuperNetwork.py b/src/network/SuperNetwork.py index 5410673f4a..aecb57bc59 100644 --- a/src/network/SuperNetwork.py +++ b/src/network/SuperNetwork.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022 The Regents of the University of California +# Copyright (c) 2025 The Regents of the University of California # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -33,22 +33,9 @@ class SuperNetwork(ClockedObject): cxx_header = "network/SuperNetwork.hh" cxx_class = "gem5::SuperNetwork" - # Vector of data cells in the network - dataCells = VectorParam.DataCell("Data cells in the network") - # Vector of layers in the network layers = VectorParam.Layer("Layers in the network") - # max_packets: 0 means not provided - max_packets = Param.Int( - -1, "Maximum number of packets to schedule; -1 means not provided" - ) - - # schedule_path: empty string means not provided - schedule_path = Param.String( - "", "File path for schedule (empty means not provided)" - ) - crosspoint_delay = Param.Float(-1, "Crosspoint delay in picoseconds") merger_delay = Param.Float(-1, "Merger delay in picoseconds") splitter_delay = Param.Float(-1, "Splitter delay in picoseconds") From 56b6802bef6b1aedd0b8f5faf31bc42aa2031242 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Tue, 1 Apr 2025 22:37:46 -0700 Subject: [PATCH 12/47] misc: Minor style changes Removed some unused commented code Changed year on license from 2022 to 2025 --- src/network/DataCell.py | 2 +- src/network/Layer.cc | 33 --------------------------------- src/network/SuperNetwork.cc | 6 ------ 3 files changed, 1 insertion(+), 40 deletions(-) diff --git a/src/network/DataCell.py b/src/network/DataCell.py index e1285253bc..99efe333ad 100644 --- a/src/network/DataCell.py +++ b/src/network/DataCell.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022 The Regents of the University of California +# Copyright (c) 2025 The Regents of the University of California # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/src/network/Layer.cc b/src/network/Layer.cc index b77be91ac5..6ec2c69ef0 100644 --- a/src/network/Layer.cc +++ b/src/network/Layer.cc @@ -43,39 +43,6 @@ namespace gem5 { -// // Hardware Constants namespace containing predefined values for various -// // network components based on the SRNoC paper -// namespace HardwareConstants { -// // Timing delays in picoseconds for different network components -// constexpr double CROSSPOINT_DELAY = 4.1; -// constexpr double MERGER_DELAY = 8.84; -// constexpr double SPLITTER_DELAY = 2.06; -// constexpr double CIRCUIT_VARIABILITY = 1.2; -// constexpr double VARIABILITY_COUNTING_NETWORK = 4.38; -// constexpr double CROSSPOINT_SETUP_TIME = 8; - -// // Static power consumption in microwatts for various components -// constexpr double SPLITTER_STATIC_POWER = 5.98; -// constexpr double MERGER_STATIC_POWER = 5; -// constexpr double CROSSPOINT_STATIC_POWER = 7.9; -// constexpr double COUNTING_NETWORK_STATIC_POWER = 66.82; -// constexpr double TFF_STATIC_POWER = 10.8; - -// // Active power consumption in nanowatts for various components -// constexpr double SPLITTER_ACTIVE_POWER = 83.2; -// constexpr double MERGER_ACTIVE_POWER = 69.6; -// constexpr double CROSSPOINT_ACTIVE_POWER = 60.7; -// constexpr double COUNTING_NETWORK_ACTIVE_POWER = 163; -// constexpr double TFF_ACTIVE_POWER = 105.6; - -// // Number of Josephson Junctions (JJs) for each component type -// constexpr int SPLITTER_JJ = 3; -// constexpr int MERGER_JJ = 5; -// constexpr int CROSSPOINT_JJ = 13; -// constexpr int COUNTING_NETWORK_JJ = 60; -// constexpr int TFF_JJ = 10; -// } - // Constructor for the Layer class // Initializes the network with given parameters, sets up data cells, // and prepares for packet scheduling diff --git a/src/network/SuperNetwork.cc b/src/network/SuperNetwork.cc index f7703dcb4f..f08bf52866 100644 --- a/src/network/SuperNetwork.cc +++ b/src/network/SuperNetwork.cc @@ -60,12 +60,6 @@ namespace gem5 assert(params.variability_counting_network >= 0); assert(params.crosspoint_setup_time >= 0); - // Initialize the network layers - // for (int i = 0; i < params.layers.size(); i++) { - // Layer* layer = new Layer(params.layers[i]); - // layers.push_back(layer); - // } - for (auto layer : params.layers) { layer->setTimeSlot(calculateTimeSlot(layer->getRadix())); DPRINTF(SuperNetwork, "Layer %d: time slot = %d\n", From 77e24cc87376fa4319baee150bdcf7d98345e57a Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Wed, 2 Apr 2025 00:11:36 -0700 Subject: [PATCH 13/47] misc: Miscellaneous changes to SRNoC Model DPRINTF output to show layer number. Multiple dynamic ranges, which dictate number of layers. Payload Specific delay had a small bug in it. --- configs/supernetwork/SRNoC.py | 9 +++++---- src/network/Layer.cc | 2 +- src/network/SuperNetwork.cc | 10 ++++++---- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/configs/supernetwork/SRNoC.py b/configs/supernetwork/SRNoC.py index b8af5ab6e7..ff7ab0e3a2 100644 --- a/configs/supernetwork/SRNoC.py +++ b/configs/supernetwork/SRNoC.py @@ -149,10 +149,10 @@ def calculate_power_and_area(radix): parser.add_argument( "--dynamic-range", type=int, - default=1000, - help="Maximum value for random data generation", + nargs="+", + default=[1000], + help="Maximum value(s) for random data generation. Multiple values create multiple layers.", ) - args = parser.parse_args() # Ensure that at least one of --maximum-packets or --file-path is provided @@ -176,11 +176,12 @@ def calculate_power_and_area(radix): layers = [ Layer( - dynamic_range=args.dynamic_range, + dynamic_range=dr, data_cells=data_cells, max_packets=args.maximum_packets, schedule_path=args.file_path, ) + for dr in args.dynamic_range ] # Create the SuperNetwork and add the DataCells diff --git a/src/network/Layer.cc b/src/network/Layer.cc index 6ec2c69ef0..ac4c159de4 100644 --- a/src/network/Layer.cc +++ b/src/network/Layer.cc @@ -303,7 +303,7 @@ Layer::processPackets( // Calculate precise delivery time // within the connection window // Use the payload value -> RACE LOGIC - payloadSpecificDelay = ((payload + 1) % dynamicRange) * + payloadSpecificDelay = ((payload + 1)) * (getTimeSlot()) * clockPeriod()/714; DPRINTF(Layer, diff --git a/src/network/SuperNetwork.cc b/src/network/SuperNetwork.cc index f08bf52866..d9dfeaf94f 100644 --- a/src/network/SuperNetwork.cc +++ b/src/network/SuperNetwork.cc @@ -60,17 +60,19 @@ namespace gem5 assert(params.variability_counting_network >= 0); assert(params.crosspoint_setup_time >= 0); + int layerIndex = 0; for (auto layer : params.layers) { layer->setTimeSlot(calculateTimeSlot(layer->getRadix())); DPRINTF(SuperNetwork, "Layer %d: time slot = %d\n", - layer->getRadix(), layer->getTimeSlot() + layerIndex, layer->getTimeSlot() ); - layer->setConnectionWindow(Cycles(layer->getDynamicRange() * - timeSlot)); + layer->setConnectionWindow( + Cycles(layer->getDynamicRange() * timeSlot)); DPRINTF(SuperNetwork, "Layer %d: connection window = %d\n", - layer->getRadix(), layer->getConnectionWindow() + layerIndex, layer->getConnectionWindow() ); layer->scheduleNextNetworkEvent(curTick()); + layerIndex++; } } From aba23dfd0872f503309edc70a5104a6ee046f8e6 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Thu, 3 Apr 2025 23:11:37 -0700 Subject: [PATCH 14/47] misc: Infinite packets implemented If max packets is -1, then the model generates and delivers infinite packets --- src/network/Layer.cc | 33 ++++++++++++++++++++------------- src/network/Layer.py | 2 +- src/network/NetworkScheduler.cc | 14 ++++++++++++-- src/network/NetworkScheduler.hh | 3 +++ 4 files changed, 36 insertions(+), 16 deletions(-) diff --git a/src/network/Layer.cc b/src/network/Layer.cc index ac4c159de4..63bed4540a 100644 --- a/src/network/Layer.cc +++ b/src/network/Layer.cc @@ -64,7 +64,7 @@ Layer::Layer(const LayerParams& params) : initializeDataCells(params.data_cells); // Initialize the network scheduler - scheduler.initialize(); + // scheduler.initialize(); // Assign packets from the predefined schedule // assignPacketsFromSchedule(); @@ -224,7 +224,7 @@ Layer::processNextNetworkEvent() buildStaticSchedule(); // Process packets according to the static schedule - bool packetsRemaining = processPackets( + processPackets( staticSchedule, packetsProcessedThisWindow ); @@ -234,8 +234,10 @@ Layer::processNextNetworkEvent() // Advance the time slot for the next event currentTimeSlotIndex++; - // Schedule next network event - if (packetsDelivered < maxPackets) { + // Schedule next network event. + // In infinite mode (maxPackets == -1) we always schedule the next event. + if (maxPackets == static_cast(-1) + || packetsDelivered < maxPackets) { scheduleNextNetworkEvent(curTick() + connectionWindow * clockPeriod()/714); } @@ -263,7 +265,6 @@ Layer::buildStaticSchedule() return staticSchedule; } -// Process packets according to the static schedule // Process packets according to the static schedule bool Layer::processPackets( @@ -271,11 +272,13 @@ Layer::processPackets( uint64_t& packetsProcessedThisWindow) { Tick payloadSpecificDelay = 0; + // Determine if we are in infinite mode + bool infiniteMode = (maxPackets == static_cast(-1)); // Iterate through all data cells for (DataCell* cell : dataCells) { // Check if we've already reached the maximum packets - if (packetsDelivered >= maxPackets) { + if (packetsDelivered >= maxPackets && !infiniteMode) { break; // Exit the loop immediately if we've reached max packets } @@ -322,7 +325,8 @@ Layer::processPackets( }, "deliverPacketEvent"), curTick() + payloadSpecificDelay); // Check if we've reached max packets after processing this one - if (packetsDelivered >= maxPackets) { + // If not in infinite mode, check for termination condition. + if (!infiniteMode && packetsDelivered >= maxPackets) { break; } // } else if (cell->hasPackets() && @@ -370,20 +374,23 @@ Layer::processPackets( stats.pktsPerWindow.sample(packetsProcessedThisWindow); - if (packetsDelivered >= maxPackets) { - DPRINTF(Layer, "All packets processed in window %lu\n", - currentTimeSlotIndex); - DPRINTF(Layer, "Payload specific delay: %lu\n", + // Only exit simulation if not in infinite mode + if (!infiniteMode && packetsDelivered >= maxPackets) { + DPRINTF(Layer, + "All packets processed in window %lu\n", + currentTimeSlotIndex + ); + DPRINTF(Layer, + "Payload specific delay: %lu\n", payloadSpecificDelay ); - // schedule exit exitSimLoop("All packets processed", 0, curTick() + payloadSpecificDelay, 0, false ); } - return (packetsDelivered < maxPackets); + return infiniteMode ? true : (packetsDelivered < maxPackets); } // Deliver a packet to its destination data cell diff --git a/src/network/Layer.py b/src/network/Layer.py index 859a5dca90..c3a91901f8 100644 --- a/src/network/Layer.py +++ b/src/network/Layer.py @@ -40,7 +40,7 @@ class Layer(ClockedObject): # max_packets: 0 means not provided max_packets = Param.Int( - -1, "Maximum number of packets to schedule; -1 means not provided" + -1, "Maximum number of packets to schedule; -1 means infinite" ) # schedule_path: empty string means not provided diff --git a/src/network/NetworkScheduler.cc b/src/network/NetworkScheduler.cc index 8a05ce78f0..769ff648e9 100644 --- a/src/network/NetworkScheduler.cc +++ b/src/network/NetworkScheduler.cc @@ -44,7 +44,8 @@ NetworkScheduler::NetworkScheduler( ) : maxPackets(maxPackets), schedulePath(schedulePath), - dataCells(cells) + dataCells(cells), + infiniteMode(maxPackets == static_cast(-1)) {} // Initializes the scheduler by either generating or loading a schedule @@ -152,6 +153,15 @@ NetworkScheduler::generateRandomSchedule() return; } + // In infinite mode we do not pre-generate the schedule. + if (infiniteMode) { + DPRINTF(NetworkScheduler, + "Infinite mode active: schedule will \ + be generated on demand.\n" + ); + return; + } + // Random number generator setup std::random_device rd; // Random seed std::mt19937 gen(rd()); // Mersenne Twister random generator @@ -326,7 +336,7 @@ NetworkScheduler::fileExists(const std::string& path) const bool NetworkScheduler::hasPackets() const { - return !scheduleQueue.empty(); + return infiniteMode ? true : (!scheduleQueue.empty()); } // Retrieves the next packet in the schedule diff --git a/src/network/NetworkScheduler.hh b/src/network/NetworkScheduler.hh index cd88afeff8..71b922e574 100644 --- a/src/network/NetworkScheduler.hh +++ b/src/network/NetworkScheduler.hh @@ -97,6 +97,9 @@ public: void clear(); private: + // To check if we are in infinite mode + bool infiniteMode; + // Checks if a given file exists at the specified path bool fileExists(const std::string& path) const; From 921375c71327b986854a0805a10d545d5b557bed Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Fri, 4 Apr 2025 00:26:31 -0700 Subject: [PATCH 15/47] misc: Fix bug related to multiple layers Multiple layers did not follow maximum packets Fixed it by making exit simulation at the network level Layers inform the network when they are done processing When all layers reach maximum packets, exit --- src/network/Layer.cc | 17 ++++++++++---- src/network/Layer.hh | 13 +++++++++++ src/network/SuperNetwork.cc | 46 ++++++++++++++++++++++++++++++++++++- src/network/SuperNetwork.hh | 10 ++++++++ 4 files changed, 81 insertions(+), 5 deletions(-) diff --git a/src/network/Layer.cc b/src/network/Layer.cc index 63bed4540a..2d6bc399e2 100644 --- a/src/network/Layer.cc +++ b/src/network/Layer.cc @@ -36,6 +36,7 @@ #include "debug/Layer.hh" #include "network/NetworkScheduler.hh" +#include "network/SuperNetwork.hh" #include "sim/eventq.hh" #include "sim/sim_exit.hh" #include "sim/stats.hh" @@ -54,6 +55,7 @@ Layer::Layer(const LayerParams& params) : dynamicRange(params.dynamic_range), packetsDelivered(0), currentTimeSlotIndex(0), + isFinished(false), // Event for processing the next network event nextNetworkEvent([this]{ processNextNetworkEvent(); }, name() + ".nextNetworkEvent"), @@ -217,6 +219,9 @@ Layer::getDataCell(uint64_t addr) void Layer::processNextNetworkEvent() { + if (isFinished) { + return; + } uint64_t packetsProcessedThisWindow = 0; // Build a static schedule for the current time slot @@ -384,10 +389,14 @@ Layer::processPackets( "Payload specific delay: %lu\n", payloadSpecificDelay ); - exitSimLoop("All packets processed", 0, - curTick() + payloadSpecificDelay, 0, - false - ); + isFinished = true; + if (superNetwork != nullptr) { + superNetwork->notifyLayerFinished(this); + } + // exitSimLoop("All packets processed", 0, + // curTick() + payloadSpecificDelay, 0, + // false + // ); } return infiniteMode ? true : (packetsDelivered < maxPackets); diff --git a/src/network/Layer.hh b/src/network/Layer.hh index 110b5d7d53..e7d9d92bd2 100644 --- a/src/network/Layer.hh +++ b/src/network/Layer.hh @@ -46,6 +46,9 @@ namespace gem5 { +// Forward declaration of the SuperNetwork class +class SuperNetwork; + class Layer : public ClockedObject { private: @@ -68,9 +71,11 @@ private: uint64_t currentTimeSlotIndex; // Current index for the time slot int maxPackets; // Maximum number of packets, -1 means no limit int packetsDelivered; // Number of packet deliveries + bool isFinished; // Flag to indicate if the layer has finished std::string schedulePath; // Path to the schedule file std::queue> scheduleQueue; NetworkScheduler scheduler; // Scheduler for the network + SuperNetwork* superNetwork; // Pointer to the super network // Initialization methods to set up network layers and data cells void initializeNetworkLayers(const std::vector& layers); @@ -137,6 +142,14 @@ public: void scheduleNextNetworkEvent(Tick when); // Schedules the next event + void registerSuperNetwork(SuperNetwork* superNetwork) + { + this->superNetwork = superNetwork; + } + SuperNetwork* getSuperNetwork() const { return superNetwork; } + + bool hasFinished() const { return isFinished; } + }; diff --git a/src/network/SuperNetwork.cc b/src/network/SuperNetwork.cc index d9dfeaf94f..2e294a1d47 100644 --- a/src/network/SuperNetwork.cc +++ b/src/network/SuperNetwork.cc @@ -51,7 +51,9 @@ namespace gem5 splitterDelay(params.splitter_delay), circuitVariability(params.circuit_variability), variabilityCountingNetwork(params.variability_counting_network), - crosspointSetupTime(params.crosspoint_setup_time) + crosspointSetupTime(params.crosspoint_setup_time), + numLayers(params.layers.size()), + finishedLayers(0) { assert(params.crosspoint_delay >= 0); assert(params.merger_delay >= 0); @@ -72,6 +74,8 @@ namespace gem5 layerIndex, layer->getConnectionWindow() ); layer->scheduleNextNetworkEvent(curTick()); + layer->registerSuperNetwork(this); + managedLayers.push_back(layer); layerIndex++; } } @@ -98,4 +102,44 @@ namespace gem5 } + void + SuperNetwork::notifyLayerFinished(Layer* layer) + { + + DPRINTF(SuperNetwork, "Received finish notification from Layer"); + + // Increment the counter + finishedLayers++; + + DPRINTF(SuperNetwork, + "Finished layers: %d / %d\n", + finishedLayers, numLayers + ); + + // Check if all layers are now finished + checkCompletionAndExit(); + } + + void + SuperNetwork::checkCompletionAndExit() + { + if (finishedLayers < 0 || finishedLayers > numLayers) { + panic("SuperNetwork finishedLayers count (%d) \ + is out of bounds [0, %d]!", + finishedLayers, numLayers + ); + } + + if (finishedLayers == numLayers) { + DPRINTF(SuperNetwork, + "All %d layers have finished processing.\n", + numLayers + ); + // Use exitSimLoop for a clean exit in event-driven simulation + exitSimLoop("SuperNetwork: \ + All layers finished processing packets." + ); + } + } + } // namespace gem5 diff --git a/src/network/SuperNetwork.hh b/src/network/SuperNetwork.hh index 4c6103ad8b..1638d54708 100644 --- a/src/network/SuperNetwork.hh +++ b/src/network/SuperNetwork.hh @@ -56,13 +56,23 @@ class SuperNetwork : public ClockedObject double variabilityCountingNetwork; double crosspointSetupTime; + std::vector managedLayers; // Store pointers to layers + const int numLayers; // Total number of layers managed + int finishedLayers; // Counter for finished layers + public: // Constructor: Initializes the SuperNetwork with given parameters SuperNetwork(const SuperNetworkParams& params); + // Function for layers to notify when they finish processing + void notifyLayerFinished(Layer* layer); + // Calculate time slot Cycles calculateTimeSlot(uint64_t radix); + // Function to check if all layers have finished processing + // and exit the simulation if they have + void checkCompletionAndExit(); }; } // namespace gem5 From 24a4090be310bb48cecc57522327070d8ad7722b Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Fri, 4 Apr 2025 16:23:25 -0700 Subject: [PATCH 16/47] misc: Move delay parameters into Layer Crosspoint delay, merger delay etc. are now part of a Layer. --- configs/supernetwork/SRNoC.py | 22 +++++---- src/network/Layer.cc | 88 ++++++++++++++++++++--------------- src/network/Layer.hh | 21 +++++---- src/network/Layer.py | 11 +++++ src/network/SuperNetwork.cc | 59 +++++++++-------------- src/network/SuperNetwork.hh | 11 ----- src/network/SuperNetwork.py | 11 ----- 7 files changed, 109 insertions(+), 114 deletions(-) diff --git a/configs/supernetwork/SRNoC.py b/configs/supernetwork/SRNoC.py index ff7ab0e3a2..a2f4678957 100644 --- a/configs/supernetwork/SRNoC.py +++ b/configs/supernetwork/SRNoC.py @@ -180,6 +180,12 @@ def calculate_power_and_area(radix): data_cells=data_cells, max_packets=args.maximum_packets, schedule_path=args.file_path, + crosspoint_delay=NetworkDelays.CROSSPOINT_DELAY.value, + merger_delay=NetworkDelays.MERGER_DELAY.value, + splitter_delay=NetworkDelays.SPLITTER_DELAY.value, + circuit_variability=NetworkDelays.CIRCUIT_VARIABILITY.value, + variability_counting_network=NetworkDelays.VARIABILITY_COUNTING_NETWORK.value, + crosspoint_setup_time=NetworkDelays.CROSSPOINT_SETUP_TIME.value, ) for dr in args.dynamic_range ] @@ -189,14 +195,14 @@ def calculate_power_and_area(radix): super_network.layers = layers -super_network.crosspoint_delay = NetworkDelays.CROSSPOINT_DELAY.value -super_network.merger_delay = NetworkDelays.MERGER_DELAY.value -super_network.splitter_delay = NetworkDelays.SPLITTER_DELAY.value -super_network.circuit_variability = NetworkDelays.CIRCUIT_VARIABILITY.value -super_network.variability_counting_network = ( - NetworkDelays.VARIABILITY_COUNTING_NETWORK.value -) -super_network.crosspoint_setup_time = NetworkDelays.CROSSPOINT_SETUP_TIME.value +# super_network.crosspoint_delay = NetworkDelays.CROSSPOINT_DELAY.value +# super_network.merger_delay = NetworkDelays.MERGER_DELAY.value +# super_network.splitter_delay = NetworkDelays.SPLITTER_DELAY.value +# super_network.circuit_variability = NetworkDelays.CIRCUIT_VARIABILITY.value +# super_network.variability_counting_network = ( +# NetworkDelays.VARIABILITY_COUNTING_NETWORK.value +# ) +# super_network.crosspoint_setup_time = NetworkDelays.CROSSPOINT_SETUP_TIME.value # Add everything to the system root.system.super_network = super_network diff --git a/src/network/Layer.cc b/src/network/Layer.cc index 2d6bc399e2..023f4fd97c 100644 --- a/src/network/Layer.cc +++ b/src/network/Layer.cc @@ -53,6 +53,12 @@ Layer::Layer(const LayerParams& params) : schedulePath(params.schedule_path), scheduler(params.max_packets, params.schedule_path, params.data_cells), dynamicRange(params.dynamic_range), + crosspointDelay(params.crosspoint_delay), + mergerDelay(params.merger_delay), + splitterDelay(params.splitter_delay), + circuitVariability(params.circuit_variability), + variabilityCountingNetwork(params.variability_counting_network), + crosspointSetupTime(params.crosspoint_setup_time), packetsDelivered(0), currentTimeSlotIndex(0), isFinished(false), @@ -61,6 +67,12 @@ Layer::Layer(const LayerParams& params) : name() + ".nextNetworkEvent"), stats(this) { + assert(params.crosspoint_delay >= 0); + assert(params.merger_delay >= 0); + assert(params.splitter_delay >= 0); + assert(params.circuit_variability >= 0); + assert(params.variability_counting_network >= 0); + assert(params.crosspoint_setup_time >= 0); // Initialize data cells with random data initializeDataCells(params.data_cells); @@ -135,25 +147,25 @@ Layer::assignPacketsFromSchedule() } // Compute key network parameters like time slot and connection window -// void -// Layer::computeNetworkParameters() -// { -// // Calculate and assign the time slot -// assignTimeSlot(); -// DPRINTF(Layer, "Time slot: %d Cycles\n", getTimeSlot()); -// DPRINTF(Layer, "Time slot: %d ps\n", -// getTimeSlot() * clockPeriod()/714 -// ); - -// // Calculate and assign the connection window -// assignConnectionWindow(Cycles(dynamicRange * getTimeSlot())); -// DPRINTF(Layer, "Connection window: %d Cycles\n", -// getConnectionWindow() -// ); -// DPRINTF(Layer, "Connection window: %d ps\n", -// getConnectionWindow() * clockPeriod()/714 -// ); -// } +void +Layer::computeTimingParameters() +{ + // Calculate and assign the time slot + assignTimeSlot(); + DPRINTF(Layer, "Time slot: %d Cycles\n", getTimeSlot()); + DPRINTF(Layer, "Time slot: %d ps\n", + getTimeSlot() * clockPeriod()/714 + ); + + // Calculate and assign the connection window + setConnectionWindow(Cycles(dynamicRange * getTimeSlot())); + DPRINTF(Layer, "Connection window: %d Cycles\n", + getConnectionWindow() + ); + DPRINTF(Layer, "Connection window: %d ps\n", + getConnectionWindow() * clockPeriod()/714 + ); +} // Schedule the initial network event if there are packets to process // void @@ -178,25 +190,25 @@ Layer::assignPacketsFromSchedule() // } // Calculate the time slot based on network component delays -// void -// Layer::assignTimeSlot() -// { -// // Adjust setup time considering circuit variability -// double SE_adjusted = std::max(0.0, -// crosspointSetupTime - circuitVariability -// ); - -// // Calculate time slot considering delays of various network components -// double calculatedTimeSlot = circuitVariability * ( -// crosspointDelay + SE_adjusted + -// splitterDelay * (radix - 1) + -// mergerDelay * (radix - 1) + -// variabilityCountingNetwork -// ); - -// // Round up the calculated time slot -// this->timeSlot = Cycles(std::ceil(calculatedTimeSlot)); -// } +void +Layer::assignTimeSlot() +{ + // Adjust setup time considering circuit variability + double SE_adjusted = std::max(0.0, + crosspointSetupTime - circuitVariability + ); + + // Calculate time slot considering delays of various network components + double calculatedTimeSlot = circuitVariability * ( + crosspointDelay + SE_adjusted + + splitterDelay * (radix - 1) + + mergerDelay * (radix - 1) + + variabilityCountingNetwork + ); + + // Round up the calculated time slot + this->timeSlot = Cycles(std::ceil(calculatedTimeSlot)); +} // Add a data cell to the network's data cell collection void diff --git a/src/network/Layer.hh b/src/network/Layer.hh index e7d9d92bd2..752bfe886c 100644 --- a/src/network/Layer.hh +++ b/src/network/Layer.hh @@ -56,12 +56,12 @@ private: std::unordered_map dataCellMap; // network delay parameters - // double crosspointDelay; - // double mergerDelay; - // double splitterDelay; - // double circuitVariability; - // double variabilityCountingNetwork; - // double crosspointSetupTime; + double crosspointDelay; + double mergerDelay; + double splitterDelay; + double circuitVariability; + double variabilityCountingNetwork; + double crosspointSetupTime; // Network configuration parameters uint64_t dynamicRange; // The dynamic range of the network @@ -81,7 +81,9 @@ private: void initializeNetworkLayers(const std::vector& layers); void initializeDataCells(const std::vector& cells); void assignPacketsFromSchedule(); - void computeNetworkParameters(); + + // Method to calculate the time slot based on network parameters + void assignTimeSlot(); // Methods for processing packets // Builds a static schedule for the current time slot @@ -96,7 +98,6 @@ private: // Struct to hold statistics related to the Layer struct LayerStats: public statistics::Group { - // Statistics for SRNoC (Source-Routed NoC) // Statistics for round-robin scheduling @@ -122,6 +123,9 @@ public: // Constructor for initializing a Layer with parameters Layer(const LayerParams& params); + // Methods for computing layer timing parameters + void computeTimingParameters(); + // Methods for adding and retrieving data cells in the network void addDataCell(DataCell* dataCell); DataCell* getDataCell(uint64_t addr); @@ -133,7 +137,6 @@ public: void assignRadix(uint64_t radix) { this->radix = radix; } uint64_t getRadix() const { return radix; } - void assignTimeSlot(); Cycles getTimeSlot() const { return timeSlot; } void setTimeSlot(Cycles timeSlot) { this->timeSlot = timeSlot; } diff --git a/src/network/Layer.py b/src/network/Layer.py index c3a91901f8..7afada0e71 100644 --- a/src/network/Layer.py +++ b/src/network/Layer.py @@ -47,3 +47,14 @@ class Layer(ClockedObject): schedule_path = Param.String( "", "File path for schedule (empty means not provided)" ) + + crosspoint_delay = Param.Float(-1, "Crosspoint delay in picoseconds") + merger_delay = Param.Float(-1, "Merger delay in picoseconds") + splitter_delay = Param.Float(-1, "Splitter delay in picoseconds") + circuit_variability = Param.Float(-1, "Circuit variability in picoseconds") + variability_counting_network = Param.Float( + -1, "Variability in counting network in picoseconds" + ) + crosspoint_setup_time = Param.Float( + -1, "Crosspoint setup time in picoseconds" + ) diff --git a/src/network/SuperNetwork.cc b/src/network/SuperNetwork.cc index 2e294a1d47..19de9f4542 100644 --- a/src/network/SuperNetwork.cc +++ b/src/network/SuperNetwork.cc @@ -46,30 +46,15 @@ namespace gem5 { SuperNetwork::SuperNetwork(const SuperNetworkParams& params) : ClockedObject(params), - crosspointDelay(params.crosspoint_delay), - mergerDelay(params.merger_delay), - splitterDelay(params.splitter_delay), - circuitVariability(params.circuit_variability), - variabilityCountingNetwork(params.variability_counting_network), - crosspointSetupTime(params.crosspoint_setup_time), numLayers(params.layers.size()), finishedLayers(0) { - assert(params.crosspoint_delay >= 0); - assert(params.merger_delay >= 0); - assert(params.splitter_delay >= 0); - assert(params.circuit_variability >= 0); - assert(params.variability_counting_network >= 0); - assert(params.crosspoint_setup_time >= 0); - int layerIndex = 0; for (auto layer : params.layers) { - layer->setTimeSlot(calculateTimeSlot(layer->getRadix())); + layer->computeTimingParameters(); DPRINTF(SuperNetwork, "Layer %d: time slot = %d\n", layerIndex, layer->getTimeSlot() ); - layer->setConnectionWindow( - Cycles(layer->getDynamicRange() * timeSlot)); DPRINTF(SuperNetwork, "Layer %d: connection window = %d\n", layerIndex, layer->getConnectionWindow() ); @@ -80,27 +65,27 @@ namespace gem5 } } - Cycles - SuperNetwork::calculateTimeSlot(uint64_t radix) - { - // Adjust setup time considering circuit variability - double SE_adjusted = std::max(0.0, - crosspointSetupTime - circuitVariability - ); - - // Calculate time slot considering delays of various network components - double calculatedTimeSlot = circuitVariability * ( - crosspointDelay + SE_adjusted + - splitterDelay * (radix - 1) + - mergerDelay * (radix - 1) + - variabilityCountingNetwork - ); - - // Round up the calculated time slot - this->timeSlot = Cycles(std::ceil(calculatedTimeSlot)); - return this->timeSlot; - - } + // Cycles + // SuperNetwork::calculateTimeSlot(uint64_t radix) + // { + // // Adjust setup time considering circuit variability + // double SE_adjusted = std::max(0.0, + // crosspointSetupTime - circuitVariability + // ); + + //// Calculate time slot considering delays of various network components + // double calculatedTimeSlot = circuitVariability * ( + // crosspointDelay + SE_adjusted + + // splitterDelay * (radix - 1) + + // mergerDelay * (radix - 1) + + // variabilityCountingNetwork + // ); + + // // Round up the calculated time slot + // this->timeSlot = Cycles(std::ceil(calculatedTimeSlot)); + // return this->timeSlot; + + // } void SuperNetwork::notifyLayerFinished(Layer* layer) diff --git a/src/network/SuperNetwork.hh b/src/network/SuperNetwork.hh index 1638d54708..1c2f6ced15 100644 --- a/src/network/SuperNetwork.hh +++ b/src/network/SuperNetwork.hh @@ -48,14 +48,6 @@ class SuperNetwork : public ClockedObject Cycles timeSlot; - // network delay parameters - double crosspointDelay; - double mergerDelay; - double splitterDelay; - double circuitVariability; - double variabilityCountingNetwork; - double crosspointSetupTime; - std::vector managedLayers; // Store pointers to layers const int numLayers; // Total number of layers managed int finishedLayers; // Counter for finished layers @@ -67,9 +59,6 @@ class SuperNetwork : public ClockedObject // Function for layers to notify when they finish processing void notifyLayerFinished(Layer* layer); - // Calculate time slot - Cycles calculateTimeSlot(uint64_t radix); - // Function to check if all layers have finished processing // and exit the simulation if they have void checkCompletionAndExit(); diff --git a/src/network/SuperNetwork.py b/src/network/SuperNetwork.py index aecb57bc59..edafc172e3 100644 --- a/src/network/SuperNetwork.py +++ b/src/network/SuperNetwork.py @@ -35,14 +35,3 @@ class SuperNetwork(ClockedObject): # Vector of layers in the network layers = VectorParam.Layer("Layers in the network") - - crosspoint_delay = Param.Float(-1, "Crosspoint delay in picoseconds") - merger_delay = Param.Float(-1, "Merger delay in picoseconds") - splitter_delay = Param.Float(-1, "Splitter delay in picoseconds") - circuit_variability = Param.Float(-1, "Circuit variability in picoseconds") - variability_counting_network = Param.Float( - -1, "Variability in counting network in picoseconds" - ) - crosspoint_setup_time = Param.Float( - -1, "Crosspoint setup time in picoseconds" - ) From 895e2accb836a9c74a5ab00ff68bcea9ba322f3e Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Fri, 4 Apr 2025 19:43:08 -0700 Subject: [PATCH 17/47] misc: Implement ability to choose traffic mode Random and hotspot are currently supported. Implemented via enums and exposed function in Layer to set the traffic mode. Edited main SRNoC config script to accept traffic mode as well. --- configs/supernetwork/SRNoC.py | 78 +++++++++++++++++++++------------ src/network/Layer.cc | 11 ++++- src/network/Layer.hh | 18 ++++++++ src/network/Layer.py | 6 +++ src/network/NetworkScheduler.cc | 6 +++ src/network/enums.cc | 39 +++++++++++++++++ src/network/enums.hh | 44 +++++++++++++++++++ 7 files changed, 173 insertions(+), 29 deletions(-) create mode 100644 src/network/enums.cc create mode 100644 src/network/enums.hh diff --git a/configs/supernetwork/SRNoC.py b/configs/supernetwork/SRNoC.py index a2f4678957..d087a46b00 100644 --- a/configs/supernetwork/SRNoC.py +++ b/configs/supernetwork/SRNoC.py @@ -130,47 +130,76 @@ def calculate_power_and_area(radix): } -# Parse command-line arguments -parser = argparse.ArgumentParser(description="SuperNetwork Simulation") - -parser.add_argument( +# Create a parent parser for the common (global) arguments. +parent_parser = argparse.ArgumentParser(add_help=False) +parent_parser.add_argument( "--maximum-packets", type=int, help="Maximum number of packets to process", default=None, ) -parser.add_argument( +parent_parser.add_argument( "--file-path", type=str, help="Path to the input file", default=None ) - -parser.add_argument( +parent_parser.add_argument( "--num-cells", type=int, default=10, help="Number of DataCells to create" ) -parser.add_argument( +parent_parser.add_argument( "--dynamic-range", type=int, nargs="+", default=[1000], help="Maximum value(s) for random data generation. Multiple values create multiple layers.", ) + +# Main parser that includes a sub-command for traffic mode. +parser = argparse.ArgumentParser( + description="SuperNetwork Simulation", parents=[parent_parser] +) +subparsers = parser.add_subparsers( + dest="traffic_mode", required=True, help="Traffic mode sub-commands" +) + +# Sub-command for random traffic mode. +random_parser = subparsers.add_parser( + "random", help="Random traffic mode", parents=[parent_parser] +) + +# Sub-command for hotspot traffic mode with additional required parameters. +hotspot_parser = subparsers.add_parser( + "hotspot", help="Hotspot traffic mode", parents=[parent_parser] +) +hotspot_parser.add_argument( + "--hotspot-addr", + type=int, + required=True, + help="Hotspot address for hotspot traffic mode", +) +hotspot_parser.add_argument( + "--hotspot-fraction", + type=float, + required=True, + help="Hotspot fraction for hotspot traffic mode", +) + args = parser.parse_args() -# Ensure that at least one of --maximum-packets or --file-path is provided +# Check that at least one of --maximum-packets or --file-path is provided. if args.maximum_packets is None and args.file_path is None: parser.error( "At least one of --maximum-packets or --file-path must be provided." ) -# Create the root SimObject and system +# Create the root SimObject and system. root = Root(full_system=False) root.system = System() -# Set up the clock domain and voltage domain +# Set up the clock and voltage domains. root.system.clk_domain = SrcClockDomain() root.system.clk_domain.clock = "1.4GHz" root.system.clk_domain.voltage_domain = VoltageDomain() -# Create several DataCells +# Create the DataCells. num_cells = args.num_cells data_cells = [DataCell() for _ in range(num_cells)] @@ -190,29 +219,16 @@ def calculate_power_and_area(radix): for dr in args.dynamic_range ] -# Create the SuperNetwork and add the DataCells +# Create the SuperNetwork and add the layers. super_network = SuperNetwork() - super_network.layers = layers - -# super_network.crosspoint_delay = NetworkDelays.CROSSPOINT_DELAY.value -# super_network.merger_delay = NetworkDelays.MERGER_DELAY.value -# super_network.splitter_delay = NetworkDelays.SPLITTER_DELAY.value -# super_network.circuit_variability = NetworkDelays.CIRCUIT_VARIABILITY.value -# super_network.variability_counting_network = ( -# NetworkDelays.VARIABILITY_COUNTING_NETWORK.value -# ) -# super_network.crosspoint_setup_time = NetworkDelays.CROSSPOINT_SETUP_TIME.value - -# Add everything to the system root.system.super_network = super_network -# Print test configuration +# Print test configuration. print("SRNoC Test Configuration") print("==============================") print(f"Number of DataCells: {num_cells}") print(f"Dynamic Range: {args.dynamic_range}") - print() print("Power and Area Statistics") print("==============================") @@ -223,9 +239,15 @@ def calculate_power_and_area(radix): print(f"Maximum Packets: {args.maximum_packets}") if args.file_path: print(f"File Path: {args.file_path}") - print() m5.instantiate() +# Set the traffic mode based on the chosen sub-command. +if args.traffic_mode == "hotspot": + for layer in layers: + layer.setHotspotTrafficMode(args.hotspot_addr, args.hotspot_fraction) +else: # Random mode selected. + for layer in layers: + layer.setRandomTrafficMode() exit_event = m5.simulate() print(f"Exiting @ tick {m5.curTick()} because {exit_event.getCause()}") diff --git a/src/network/Layer.cc b/src/network/Layer.cc index 023f4fd97c..ac43152cdd 100644 --- a/src/network/Layer.cc +++ b/src/network/Layer.cc @@ -307,8 +307,17 @@ Layer::processPackets( if (cell->hasPackets()) { packetDest = cell->peekNextPacket(); } else { + if (trafficMode == TrafficMode::RANDOM) { + // Generate a random packet destination + packetDest = scheduler.generateRandomPacket(srcAddr); + } else if (trafficMode == TrafficMode::HOTSPOT) { + // Use the static schedule for the current time slot + packetDest = scheduler.generateHotspotPacket( + srcAddr, hotspotAddr, hotspotFraction + ); + } // Only generate a new packet if there's nothing in the buffer - packetDest = scheduler.generateRandomPacket(srcAddr); + // packetDest = scheduler.generateRandomPacket(srcAddr); assert(packetDest != -1); } diff --git a/src/network/Layer.hh b/src/network/Layer.hh index 752bfe886c..5c6ac6af88 100644 --- a/src/network/Layer.hh +++ b/src/network/Layer.hh @@ -39,6 +39,7 @@ #include "network/DataCell.hh" #include "network/Layer.hh" #include "network/NetworkScheduler.hh" +#include "network/enums.hh" #include "params/Layer.hh" #include "sim/clocked_object.hh" #include "sim/eventq.hh" @@ -76,6 +77,11 @@ private: std::queue> scheduleQueue; NetworkScheduler scheduler; // Scheduler for the network SuperNetwork* superNetwork; // Pointer to the super network + TrafficMode trafficMode; // Traffic mode for the network + + // Hotspot parameters + uint64_t hotspotAddr; // Address of the hotspot + double hotspotFraction; // Fraction of packets targeting the hotspot // Initialization methods to set up network layers and data cells void initializeNetworkLayers(const std::vector& layers); @@ -153,7 +159,19 @@ public: bool hasFinished() const { return isFinished; } + // setters for TrafficMode + void setRandomTrafficMode() + { + trafficMode = TrafficMode::RANDOM; + } + void setHotspotTrafficMode(uint64_t hotspotAddr, + double hotspotFraction) + { + this->hotspotAddr = hotspotAddr; + this->hotspotFraction = hotspotFraction; + trafficMode = TrafficMode::HOTSPOT; + } }; } // namespace gem5 diff --git a/src/network/Layer.py b/src/network/Layer.py index 7afada0e71..f84409cc37 100644 --- a/src/network/Layer.py +++ b/src/network/Layer.py @@ -26,6 +26,7 @@ from m5.objects.ClockedObject import ClockedObject from m5.params import * +from m5.util.pybind import PyBindMethod class Layer(ClockedObject): @@ -58,3 +59,8 @@ class Layer(ClockedObject): crosspoint_setup_time = Param.Float( -1, "Crosspoint setup time in picoseconds" ) + + cxx_exports = [ + PyBindMethod("setRandomTrafficMode"), + PyBindMethod("setHotspotTrafficMode"), + ] diff --git a/src/network/NetworkScheduler.cc b/src/network/NetworkScheduler.cc index 769ff648e9..41e4a193bb 100644 --- a/src/network/NetworkScheduler.cc +++ b/src/network/NetworkScheduler.cc @@ -241,6 +241,12 @@ NetworkScheduler::generateHotspotPacket( return -1; } + // Check if the hotspot address is valid + if (hotspotAddr >= dataCells.size()) { + fatal("Invalid hotspot address %lu.\n", hotspotAddr); + return -1; + } + // Random number generator setup std::random_device rd; std::mt19937 gen(rd()); diff --git a/src/network/enums.cc b/src/network/enums.cc new file mode 100644 index 0000000000..6b7fd52f67 --- /dev/null +++ b/src/network/enums.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "network/enums.hh" + +namespace gem5 +{ + +const char* TrafficModeNames[NUM_TRAFFIC_MODES] = { + "RANDOM", + "HOTSPOT" +}; + +} // namespace gem5 diff --git a/src/network/enums.hh b/src/network/enums.hh new file mode 100644 index 0000000000..53f7ee17cb --- /dev/null +++ b/src/network/enums.hh @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __NETWORK_ENUMS_HH__ +#define __NETWORK_ENUMS_HH__ + +namespace gem5 +{ + +enum TrafficMode +{ + RANDOM, + HOTSPOT, + NUM_TRAFFIC_MODES +}; +extern const char* TrafficModeNames[NUM_TRAFFIC_MODES]; +} // namespace gem5 + +#endif // __NETWORK_ENUMS_HH__ From 6e4ae6d218484efc86b951b594c11e02a0be345a Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Sat, 5 Apr 2025 00:19:31 -0700 Subject: [PATCH 18/47] misc: Implement file-based schedule & other misc changes Providing a file input loads a schedule from that file. Fixed a bug where the last packet was not fully delivered before exiting the simulation. Rename .cc and .hh files to match gem5 specifications. Changed some local variables to snake case as well. Removed some unused commented code. --- configs/supernetwork/SRNoC.py | 278 ++++++++++-------- src/network/DataCell.py | 2 +- src/network/Layer.py | 2 +- src/network/SConscript | 8 +- src/network/SuperNetwork.py | 2 +- src/network/{DataCell.cc => data_cell.cc} | 2 +- src/network/{DataCell.hh => data_cell.hh} | 0 src/network/{Layer.cc => layer.cc} | 115 ++++---- src/network/{Layer.hh => layer.hh} | 8 +- ...tworkScheduler.cc => network_scheduler.cc} | 17 +- ...tworkScheduler.hh => network_scheduler.hh} | 4 +- .../{SuperNetwork.cc => super_network.cc} | 38 +-- .../{SuperNetwork.hh => super_network.hh} | 6 +- 13 files changed, 247 insertions(+), 235 deletions(-) rename src/network/{DataCell.cc => data_cell.cc} (99%) rename src/network/{DataCell.hh => data_cell.hh} (100%) rename src/network/{Layer.cc => layer.cc} (84%) rename src/network/{Layer.hh => layer.hh} (97%) rename src/network/{NetworkScheduler.cc => network_scheduler.cc} (94%) rename src/network/{NetworkScheduler.hh => network_scheduler.hh} (97%) rename src/network/{SuperNetwork.cc => super_network.cc} (76%) rename src/network/{SuperNetwork.hh => super_network.hh} (96%) diff --git a/configs/supernetwork/SRNoC.py b/configs/supernetwork/SRNoC.py index d087a46b00..78d08343b8 100644 --- a/configs/supernetwork/SRNoC.py +++ b/configs/supernetwork/SRNoC.py @@ -25,7 +25,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import argparse -import random from enum import Enum as PyEnum import m5 @@ -130,124 +129,165 @@ def calculate_power_and_area(radix): } -# Create a parent parser for the common (global) arguments. -parent_parser = argparse.ArgumentParser(add_help=False) -parent_parser.add_argument( - "--maximum-packets", - type=int, - help="Maximum number of packets to process", - default=None, -) -parent_parser.add_argument( - "--file-path", type=str, help="Path to the input file", default=None -) -parent_parser.add_argument( - "--num-cells", type=int, default=10, help="Number of DataCells to create" -) -parent_parser.add_argument( - "--dynamic-range", - type=int, - nargs="+", - default=[1000], - help="Maximum value(s) for random data generation. Multiple values create multiple layers.", -) - -# Main parser that includes a sub-command for traffic mode. -parser = argparse.ArgumentParser( - description="SuperNetwork Simulation", parents=[parent_parser] -) -subparsers = parser.add_subparsers( - dest="traffic_mode", required=True, help="Traffic mode sub-commands" -) - -# Sub-command for random traffic mode. -random_parser = subparsers.add_parser( - "random", help="Random traffic mode", parents=[parent_parser] -) - -# Sub-command for hotspot traffic mode with additional required parameters. -hotspot_parser = subparsers.add_parser( - "hotspot", help="Hotspot traffic mode", parents=[parent_parser] -) -hotspot_parser.add_argument( - "--hotspot-addr", - type=int, - required=True, - help="Hotspot address for hotspot traffic mode", -) -hotspot_parser.add_argument( - "--hotspot-fraction", - type=float, - required=True, - help="Hotspot fraction for hotspot traffic mode", -) - -args = parser.parse_args() - -# Check that at least one of --maximum-packets or --file-path is provided. -if args.maximum_packets is None and args.file_path is None: - parser.error( - "At least one of --maximum-packets or --file-path must be provided." +def create_base_parser(): + """ + Create the base argument parser with common arguments. + """ + parser = argparse.ArgumentParser(description="SuperNetwork Simulation") + # Global argument for number of cells is common to all modes + parser.add_argument( + "--num-cells", type=int, default=10, help="Number of DataCells" ) + parser.add_argument( + "--dynamic-range", + type=int, + nargs="+", + default=[1000], + help="Dynamic range settings", + ) + # Global maximum packets (optional) + parser.add_argument( + "--maximum-packets", type=int, default=0, help="Maximum packets" + ) + return parser + + +def add_random_traffic_subparser(subparsers): + """ + Add the random traffic mode subparser. + """ + random_parser = subparsers.add_parser("random", help="Random traffic mode") + # Random mode uses global arguments; additional random-specific arguments can be added here if needed. + return random_parser + + +def add_hotspot_traffic_subparser(subparsers): + """ + Add the hotspot traffic mode subparser. + """ + hotspot_parser = subparsers.add_parser( + "hotspot", help="Hotspot traffic mode" + ) + hotspot_parser.add_argument( + "--hotspot-addr", type=int, required=True, help="Hotspot address" + ) + hotspot_parser.add_argument( + "--hotspot-fraction", + type=float, + required=True, + help="Fraction of hotspot traffic", + ) + return hotspot_parser + -# Create the root SimObject and system. -root = Root(full_system=False) -root.system = System() - -# Set up the clock and voltage domains. -root.system.clk_domain = SrcClockDomain() -root.system.clk_domain.clock = "1.4GHz" -root.system.clk_domain.voltage_domain = VoltageDomain() - -# Create the DataCells. -num_cells = args.num_cells -data_cells = [DataCell() for _ in range(num_cells)] - -layers = [ - Layer( - dynamic_range=dr, - data_cells=data_cells, - max_packets=args.maximum_packets, - schedule_path=args.file_path, - crosspoint_delay=NetworkDelays.CROSSPOINT_DELAY.value, - merger_delay=NetworkDelays.MERGER_DELAY.value, - splitter_delay=NetworkDelays.SPLITTER_DELAY.value, - circuit_variability=NetworkDelays.CIRCUIT_VARIABILITY.value, - variability_counting_network=NetworkDelays.VARIABILITY_COUNTING_NETWORK.value, - crosspoint_setup_time=NetworkDelays.CROSSPOINT_SETUP_TIME.value, +def add_file_traffic_subparser(subparsers): + """ + Add the file-based traffic mode subparser. + """ + file_parser = subparsers.add_parser("file", help="File-based traffic mode") + file_parser.add_argument( + "--file-path", type=str, required=True, help="Path to the traffic file" ) - for dr in args.dynamic_range -] - -# Create the SuperNetwork and add the layers. -super_network = SuperNetwork() -super_network.layers = layers -root.system.super_network = super_network - -# Print test configuration. -print("SRNoC Test Configuration") -print("==============================") -print(f"Number of DataCells: {num_cells}") -print(f"Dynamic Range: {args.dynamic_range}") -print() -print("Power and Area Statistics") -print("==============================") -power_and_area = calculate_power_and_area(radix=(num_cells * 2)) -print() - -if args.maximum_packets: - print(f"Maximum Packets: {args.maximum_packets}") -if args.file_path: - print(f"File Path: {args.file_path}") -print() - -m5.instantiate() -# Set the traffic mode based on the chosen sub-command. -if args.traffic_mode == "hotspot": - for layer in layers: - layer.setHotspotTrafficMode(args.hotspot_addr, args.hotspot_fraction) -else: # Random mode selected. - for layer in layers: - layer.setRandomTrafficMode() -exit_event = m5.simulate() -print(f"Exiting @ tick {m5.curTick()} because {exit_event.getCause()}") + return file_parser + + +def parse_arguments(): + """ + Set up the main parser with subparsers and return the parsed arguments. + """ + base_parser = create_base_parser() + subparsers = base_parser.add_subparsers(dest="traffic_mode", required=True) + + # Add traffic mode subparsers + add_random_traffic_subparser(subparsers) + add_hotspot_traffic_subparser(subparsers) + add_file_traffic_subparser(subparsers) + + args = base_parser.parse_args() + + # Validate that at least one of maximum_packets or file_path is provided if applicable. + if ( + args.maximum_packets is None + and getattr(args, "file_path", None) is None + ): + base_parser.error( + "At least one of --maximum-packets or --file-path must be provided." + ) + + return args + + +def main(): + args = parse_arguments() + + # Create the root SimObject and system. + root = Root(full_system=False) + root.system = System() + + # Set up the clock and voltage domains. + root.system.clk_domain = SrcClockDomain() + root.system.clk_domain.clock = "1.4GHz" + root.system.clk_domain.voltage_domain = VoltageDomain() + + # Create the DataCells. + num_cells = args.num_cells + data_cells = [DataCell() for _ in range(num_cells)] + + # Create Layers for each dynamic range. + layers = [ + Layer( + dynamic_range=dr, + data_cells=data_cells, + max_packets=args.maximum_packets, + schedule_path=getattr(args, "file_path", None), + crosspoint_delay=NetworkDelays.CROSSPOINT_DELAY.value, + merger_delay=NetworkDelays.MERGER_DELAY.value, + splitter_delay=NetworkDelays.SPLITTER_DELAY.value, + circuit_variability=NetworkDelays.CIRCUIT_VARIABILITY.value, + variability_counting_network=NetworkDelays.VARIABILITY_COUNTING_NETWORK.value, + crosspoint_setup_time=NetworkDelays.CROSSPOINT_SETUP_TIME.value, + ) + for dr in args.dynamic_range + ] + + # Create the SuperNetwork and add the layers. + super_network = SuperNetwork() + super_network.layers = layers + root.system.super_network = super_network + + # Print test configuration. + print("SRNoC Test Configuration") + print("==============================") + print(f"Number of DataCells: {num_cells}") + print(f"Dynamic Range: {args.dynamic_range}") + print() + print("Power and Area Statistics") + print("==============================") + power_and_area = calculate_power_and_area(radix=(num_cells * 2)) + print() + + if args.maximum_packets: + print(f"Maximum Packets: {args.maximum_packets}") + if getattr(args, "file_path", None): + print(f"File Path: {args.file_path}") + print() + + # Instantiate the simulation. + m5.instantiate() + + # Set the traffic mode based on the chosen sub-command. + if args.traffic_mode == "hotspot": + for layer in layers: + layer.setHotspotTrafficMode( + args.hotspot_addr, args.hotspot_fraction + ) + else: # Random or file mode selected. + for layer in layers: + layer.setRandomTrafficMode() + + exit_event = m5.simulate() + print(f"Exiting @ tick {m5.curTick()} because {exit_event.getCause()}") + + +if __name__ == "__main__": + main() diff --git a/src/network/DataCell.py b/src/network/DataCell.py index 99efe333ad..081044e80b 100644 --- a/src/network/DataCell.py +++ b/src/network/DataCell.py @@ -31,5 +31,5 @@ class DataCell(ClockedObject): type = "DataCell" - cxx_header = "network/DataCell.hh" + cxx_header = "network/data_cell.hh" cxx_class = "gem5::DataCell" diff --git a/src/network/Layer.py b/src/network/Layer.py index f84409cc37..754dee1d02 100644 --- a/src/network/Layer.py +++ b/src/network/Layer.py @@ -31,7 +31,7 @@ class Layer(ClockedObject): type = "Layer" - cxx_header = "network/Layer.hh" + cxx_header = "network/layer.hh" cxx_class = "gem5::Layer" # Vector of data cells in the network diff --git a/src/network/SConscript b/src/network/SConscript index 02d1471745..bcacb6ba53 100644 --- a/src/network/SConscript +++ b/src/network/SConscript @@ -4,10 +4,10 @@ SimObject("DataCell.py", sim_objects=["DataCell"]) SimObject("SuperNetwork.py", sim_objects=["SuperNetwork"]) SimObject("Layer.py", sim_objects=["Layer"]) -Source("DataCell.cc") -Source("SuperNetwork.cc") -Source("Layer.cc") -Source('NetworkScheduler.cc') +Source("data_cell.cc") +Source("super_network.cc") +Source("layer.cc") +Source('network_scheduler.cc') DebugFlag("SuperNetwork") DebugFlag("DataCell") diff --git a/src/network/SuperNetwork.py b/src/network/SuperNetwork.py index edafc172e3..9280a9bf90 100644 --- a/src/network/SuperNetwork.py +++ b/src/network/SuperNetwork.py @@ -30,7 +30,7 @@ class SuperNetwork(ClockedObject): type = "SuperNetwork" - cxx_header = "network/SuperNetwork.hh" + cxx_header = "network/super_network.hh" cxx_class = "gem5::SuperNetwork" # Vector of layers in the network diff --git a/src/network/DataCell.cc b/src/network/data_cell.cc similarity index 99% rename from src/network/DataCell.cc rename to src/network/data_cell.cc index be5ddd9ded..0505f3bc2f 100644 --- a/src/network/DataCell.cc +++ b/src/network/data_cell.cc @@ -26,7 +26,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "network/DataCell.hh" +#include "network/data_cell.hh" #include "debug/DataCell.hh" #include "sim/sim_exit.hh" diff --git a/src/network/DataCell.hh b/src/network/data_cell.hh similarity index 100% rename from src/network/DataCell.hh rename to src/network/data_cell.hh diff --git a/src/network/Layer.cc b/src/network/layer.cc similarity index 84% rename from src/network/Layer.cc rename to src/network/layer.cc index ac43152cdd..667798e927 100644 --- a/src/network/Layer.cc +++ b/src/network/layer.cc @@ -26,7 +26,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "network/Layer.hh" +#include "network/layer.hh" #include #include @@ -35,8 +35,8 @@ #include #include "debug/Layer.hh" -#include "network/NetworkScheduler.hh" -#include "network/SuperNetwork.hh" +#include "network/network_scheduler.hh" +#include "network/super_network.hh" #include "sim/eventq.hh" #include "sim/sim_exit.hh" #include "sim/stats.hh" @@ -62,6 +62,7 @@ Layer::Layer(const LayerParams& params) : packetsDelivered(0), currentTimeSlotIndex(0), isFinished(false), + fileMode(false), // Event for processing the next network event nextNetworkEvent([this]{ processNextNetworkEvent(); }, name() + ".nextNetworkEvent"), @@ -78,7 +79,28 @@ Layer::Layer(const LayerParams& params) : initializeDataCells(params.data_cells); // Initialize the network scheduler - // scheduler.initialize(); + std::queue> + scheduleQueue = scheduler.initialize(); + + if (!scheduleQueue.empty()) { + fileMode = true; + maxPackets = scheduleQueue.size(); + while (!scheduleQueue.empty()) { + const auto& entry = scheduleQueue.front(); + + uint64_t srcAddr = entry.first; + uint64_t destAddr = entry.second; + + DataCell* cell = getDataCell(srcAddr); + if (cell != nullptr) { + cell->assignPacket(destAddr); + DPRINTF(Layer, + "DataCell %d: addr=%d, packet assigned to %d\n", + srcAddr, cell->getAddr(), destAddr); + } + scheduleQueue.pop(); + } + } // Assign packets from the predefined schedule // assignPacketsFromSchedule(); @@ -290,35 +312,48 @@ Layer::processPackets( { Tick payloadSpecificDelay = 0; // Determine if we are in infinite mode - bool infiniteMode = (maxPackets == static_cast(-1)); + bool infinite_mode = (maxPackets == static_cast(-1)); // Iterate through all data cells for (DataCell* cell : dataCells) { // Check if we've already reached the maximum packets - if (packetsDelivered >= maxPackets && !infiniteMode) { + if (packetsDelivered >= maxPackets && !infinite_mode) { break; // Exit the loop immediately if we've reached max packets } uint64_t srcAddr = cell->getAddr(); uint64_t allowedDest = staticSchedule.at(srcAddr); - uint64_t packetDest; + uint64_t packetDest = -1; // Check if there's already a packet in the buffer first if (cell->hasPackets()) { packetDest = cell->peekNextPacket(); } else { - if (trafficMode == TrafficMode::RANDOM) { - // Generate a random packet destination - packetDest = scheduler.generateRandomPacket(srcAddr); - } else if (trafficMode == TrafficMode::HOTSPOT) { - // Use the static schedule for the current time slot - packetDest = scheduler.generateHotspotPacket( - srcAddr, hotspotAddr, hotspotFraction + if (!fileMode) { + if (trafficMode == TrafficMode::RANDOM) { + // Generate a random packet destination + packetDest = scheduler.generateRandomPacket(srcAddr); + } else if (trafficMode == TrafficMode::HOTSPOT) { + // Use the static schedule for the current time slot + packetDest = scheduler.generateHotspotPacket( + srcAddr, hotspotAddr, hotspotFraction + ); + } + DPRINTF(Layer, + "DataCell %lu: generated packet for %lu\n", + srcAddr, packetDest + ); + // Only generate a new packet if there's nothing in the buffer + assert(packetDest != -1); + } else { + // In file mode, don't generate a new packet destination. + // Optionally, log that no new packet was generated. + DPRINTF(Layer, + "DataCell %lu: file mode active," + "skipping packet generation\n", + srcAddr ); } - // Only generate a new packet if there's nothing in the buffer - // packetDest = scheduler.generateRandomPacket(srcAddr); - assert(packetDest != -1); } // Check if packet can be sent in the current time slot @@ -352,39 +387,10 @@ Layer::processPackets( // Check if we've reached max packets after processing this one // If not in infinite mode, check for termination condition. - if (!infiniteMode && packetsDelivered >= maxPackets) { + if (!infinite_mode && packetsDelivered >= maxPackets) { break; } - // } else if (cell->hasPackets() && - // cell->peekNextPacket() == allowedDest) { - // cell->getNextPacket(); - // Above call should remove the packet from the queue - // uint64_t payload = cell->getData(); - - // // Calculate precise delivery time (as before) - // payloadSpecificDelay = ((payload + 1) % dynamicRange) * - // (getTimeSlot()) * clockPeriod() / 714; - - // DPRINTF(Layer, - // "Processing packet: src=%lu, dest=%lu, data=%lu, - // specific delay=%lu ps\n", - // srcAddr, allowedDest, payload, payloadSpecificDelay - // ); - - // packetsDelivered++; - // packetsProcessedThisWindow++; - - // // Schedule packet delivery with payload-specific timing - // schedule(new EventFunctionWrapper([this, - // srcAddr, allowedDest, payload]() { - // deliverPacket(srcAddr, allowedDest, payload); - // }, "deliverPacketEvent"), curTick() + payloadSpecificDelay); - - // // Check if we've reached max packets after processing this one - // if (packetsDelivered >= maxPackets) { - // break; - // } - } else { + } else if (!fileMode) { // Packet not allowed in the current time slot cell->assignPacket(packetDest); DPRINTF(Layer, @@ -401,7 +407,7 @@ Layer::processPackets( stats.pktsPerWindow.sample(packetsProcessedThisWindow); // Only exit simulation if not in infinite mode - if (!infiniteMode && packetsDelivered >= maxPackets) { + if (!infinite_mode && packetsDelivered >= maxPackets) { DPRINTF(Layer, "All packets processed in window %lu\n", currentTimeSlotIndex @@ -412,15 +418,14 @@ Layer::processPackets( ); isFinished = true; if (superNetwork != nullptr) { - superNetwork->notifyLayerFinished(this); + // Schedule the notification after the delay + schedule(new EventFunctionWrapper([this]() { + superNetwork->notifyLayerFinished(this); + }, "layerFinishedEvent"), curTick() + payloadSpecificDelay); } - // exitSimLoop("All packets processed", 0, - // curTick() + payloadSpecificDelay, 0, - // false - // ); } - return infiniteMode ? true : (packetsDelivered < maxPackets); + return infinite_mode ? true : (packetsDelivered < maxPackets); } // Deliver a packet to its destination data cell diff --git a/src/network/Layer.hh b/src/network/layer.hh similarity index 97% rename from src/network/Layer.hh rename to src/network/layer.hh index 5c6ac6af88..1d9667b185 100644 --- a/src/network/Layer.hh +++ b/src/network/layer.hh @@ -36,10 +36,10 @@ #include "base/statistics.hh" #include "base/stats/group.hh" -#include "network/DataCell.hh" -#include "network/Layer.hh" -#include "network/NetworkScheduler.hh" +#include "network/data_cell.hh" #include "network/enums.hh" +#include "network/layer.hh" +#include "network/network_scheduler.hh" #include "params/Layer.hh" #include "sim/clocked_object.hh" #include "sim/eventq.hh" @@ -73,8 +73,8 @@ private: int maxPackets; // Maximum number of packets, -1 means no limit int packetsDelivered; // Number of packet deliveries bool isFinished; // Flag to indicate if the layer has finished + bool fileMode; // Flag to indicate if a file is used for scheduling std::string schedulePath; // Path to the schedule file - std::queue> scheduleQueue; NetworkScheduler scheduler; // Scheduler for the network SuperNetwork* superNetwork; // Pointer to the super network TrafficMode trafficMode; // Traffic mode for the network diff --git a/src/network/NetworkScheduler.cc b/src/network/network_scheduler.cc similarity index 94% rename from src/network/NetworkScheduler.cc rename to src/network/network_scheduler.cc index 41e4a193bb..c7b08bdfac 100644 --- a/src/network/NetworkScheduler.cc +++ b/src/network/network_scheduler.cc @@ -26,7 +26,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "network/NetworkScheduler.hh" +#include "network/network_scheduler.hh" #include // For random number generation @@ -49,28 +49,17 @@ NetworkScheduler::NetworkScheduler( {} // Initializes the scheduler by either generating or loading a schedule -void +std::queue> NetworkScheduler::initialize() { if (maxPackets == 0 && schedulePath.empty()) { // Error: No packets and no schedule path specified fatal("Either max_packets or schedule_path must be provided.\n"); - } else if (maxPackets != 0 && schedulePath.empty()) { - // Generate a random schedule if no path is specified - generateRandomSchedule(); - } else if (maxPackets != 0 && !schedulePath.empty()) { - // If both max packets and schedule path are provided - if (fileExists(schedulePath)) { - // Warn if the schedule file already exists - warn("schedule_path %s exists; it will be overwritten.\n", - schedulePath); - } - generateRandomSchedule(); - saveSchedule(); } else if (maxPackets == 0 && !schedulePath.empty()) { // Load an existing schedule from the specified path loadSchedule(); } + return scheduleQueue; } void diff --git a/src/network/NetworkScheduler.hh b/src/network/network_scheduler.hh similarity index 97% rename from src/network/NetworkScheduler.hh rename to src/network/network_scheduler.hh index 71b922e574..9d57417e3b 100644 --- a/src/network/NetworkScheduler.hh +++ b/src/network/network_scheduler.hh @@ -38,7 +38,7 @@ #include #include "base/logging.hh" -#include "network/DataCell.hh" +#include "network/data_cell.hh" namespace gem5 { @@ -53,7 +53,7 @@ public: ); // Initializes the scheduler - void initialize(); + std::queue> initialize(); // Generates a random schedule for packets between DataCells void generateRandomSchedule(); diff --git a/src/network/SuperNetwork.cc b/src/network/super_network.cc similarity index 76% rename from src/network/SuperNetwork.cc rename to src/network/super_network.cc index 19de9f4542..c55e3f51f1 100644 --- a/src/network/SuperNetwork.cc +++ b/src/network/super_network.cc @@ -26,7 +26,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "network/SuperNetwork.hh" +#include "network/super_network.hh" #include #include @@ -35,8 +35,8 @@ #include #include "debug/SuperNetwork.hh" -#include "network/Layer.hh" -#include "network/NetworkScheduler.hh" +#include "network/layer.hh" +#include "network/network_scheduler.hh" #include "sim/eventq.hh" #include "sim/sim_exit.hh" #include "sim/stats.hh" @@ -49,44 +49,22 @@ namespace gem5 numLayers(params.layers.size()), finishedLayers(0) { - int layerIndex = 0; + int layer_index = 0; for (auto layer : params.layers) { layer->computeTimingParameters(); DPRINTF(SuperNetwork, "Layer %d: time slot = %d\n", - layerIndex, layer->getTimeSlot() + layer_index, layer->getTimeSlot() ); DPRINTF(SuperNetwork, "Layer %d: connection window = %d\n", - layerIndex, layer->getConnectionWindow() + layer_index, layer->getConnectionWindow() ); layer->scheduleNextNetworkEvent(curTick()); layer->registerSuperNetwork(this); managedLayers.push_back(layer); - layerIndex++; + layer_index++; } } - // Cycles - // SuperNetwork::calculateTimeSlot(uint64_t radix) - // { - // // Adjust setup time considering circuit variability - // double SE_adjusted = std::max(0.0, - // crosspointSetupTime - circuitVariability - // ); - - //// Calculate time slot considering delays of various network components - // double calculatedTimeSlot = circuitVariability * ( - // crosspointDelay + SE_adjusted + - // splitterDelay * (radix - 1) + - // mergerDelay * (radix - 1) + - // variabilityCountingNetwork - // ); - - // // Round up the calculated time slot - // this->timeSlot = Cycles(std::ceil(calculatedTimeSlot)); - // return this->timeSlot; - - // } - void SuperNetwork::notifyLayerFinished(Layer* layer) { @@ -120,7 +98,7 @@ namespace gem5 "All %d layers have finished processing.\n", numLayers ); - // Use exitSimLoop for a clean exit in event-driven simulation + // Exit the simulation loop exitSimLoop("SuperNetwork: \ All layers finished processing packets." ); diff --git a/src/network/SuperNetwork.hh b/src/network/super_network.hh similarity index 96% rename from src/network/SuperNetwork.hh rename to src/network/super_network.hh index 1c2f6ced15..7b337d0c5a 100644 --- a/src/network/SuperNetwork.hh +++ b/src/network/super_network.hh @@ -29,9 +29,9 @@ #ifndef __NETWORK_SUPERNETWORK_HH__ #define __NETWORK_SUPERNETWORK_HH__ -#include "network/DataCell.hh" -#include "network/Layer.hh" -#include "network/NetworkScheduler.hh" +#include "network/data_cell.hh" +#include "network/layer.hh" +#include "network/network_scheduler.hh" #include "params/SuperNetwork.hh" #include "sim/clocked_object.hh" #include "sim/eventq.hh" From da8c57439ff41d7cb9cef0b1332489343f24ff25 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Sat, 5 Apr 2025 10:10:50 -0700 Subject: [PATCH 19/47] misc: Fix argument parsers in SRNoC config script Made sure all arguments are being parsed correctly. Also, fixed if __name__=='__main__' to '__m5_main__'. --- configs/supernetwork/SRNoC.py | 85 ++++++++++++----------------------- 1 file changed, 29 insertions(+), 56 deletions(-) diff --git a/configs/supernetwork/SRNoC.py b/configs/supernetwork/SRNoC.py index 78d08343b8..145b2e65ca 100644 --- a/configs/supernetwork/SRNoC.py +++ b/configs/supernetwork/SRNoC.py @@ -129,44 +129,45 @@ def calculate_power_and_area(radix): } -def create_base_parser(): +def create_shared_parser(): """ - Create the base argument parser with common arguments. + Parser for arguments shared across all traffic modes. """ - parser = argparse.ArgumentParser(description="SuperNetwork Simulation") - # Global argument for number of cells is common to all modes - parser.add_argument( - "--num-cells", type=int, default=10, help="Number of DataCells" - ) - parser.add_argument( + shared_parser = argparse.ArgumentParser(add_help=False) + shared_parser.add_argument( "--dynamic-range", type=int, nargs="+", - default=[1000], + required=True, help="Dynamic range settings", ) - # Global maximum packets (optional) + return shared_parser + + +def create_base_parser(): + parser = argparse.ArgumentParser(description="SuperNetwork Simulation") + parser.add_argument( + "--num-cells", type=int, default=10, help="Number of DataCells" + ) parser.add_argument( "--maximum-packets", type=int, default=0, help="Maximum packets" ) return parser -def add_random_traffic_subparser(subparsers): - """ - Add the random traffic mode subparser. - """ - random_parser = subparsers.add_parser("random", help="Random traffic mode") - # Random mode uses global arguments; additional random-specific arguments can be added here if needed. - return random_parser +def parse_arguments(): + shared_parser = create_shared_parser() + base_parser = create_base_parser() + subparsers = base_parser.add_subparsers(dest="traffic_mode", required=True) + # random traffic + random_parser = subparsers.add_parser( + "random", parents=[shared_parser], help="Random traffic mode" + ) -def add_hotspot_traffic_subparser(subparsers): - """ - Add the hotspot traffic mode subparser. - """ + # hotspot traffic hotspot_parser = subparsers.add_parser( - "hotspot", help="Hotspot traffic mode" + "hotspot", parents=[shared_parser], help="Hotspot traffic mode" ) hotspot_parser.add_argument( "--hotspot-addr", type=int, required=True, help="Hotspot address" @@ -177,44 +178,16 @@ def add_hotspot_traffic_subparser(subparsers): required=True, help="Fraction of hotspot traffic", ) - return hotspot_parser - -def add_file_traffic_subparser(subparsers): - """ - Add the file-based traffic mode subparser. - """ - file_parser = subparsers.add_parser("file", help="File-based traffic mode") + # file traffic + file_parser = subparsers.add_parser( + "file", parents=[shared_parser], help="File-based traffic mode" + ) file_parser.add_argument( "--file-path", type=str, required=True, help="Path to the traffic file" ) - return file_parser - - -def parse_arguments(): - """ - Set up the main parser with subparsers and return the parsed arguments. - """ - base_parser = create_base_parser() - subparsers = base_parser.add_subparsers(dest="traffic_mode", required=True) - - # Add traffic mode subparsers - add_random_traffic_subparser(subparsers) - add_hotspot_traffic_subparser(subparsers) - add_file_traffic_subparser(subparsers) - - args = base_parser.parse_args() - - # Validate that at least one of maximum_packets or file_path is provided if applicable. - if ( - args.maximum_packets is None - and getattr(args, "file_path", None) is None - ): - base_parser.error( - "At least one of --maximum-packets or --file-path must be provided." - ) - return args + return base_parser.parse_args() def main(): @@ -289,5 +262,5 @@ def main(): print(f"Exiting @ tick {m5.curTick()} because {exit_event.getCause()}") -if __name__ == "__main__": +if __name__ == "__m5_main__": main() From 50c2070d0d5effb9310db8de4e3f71c96d7c1907 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Sat, 5 Apr 2025 14:27:14 -0700 Subject: [PATCH 20/47] misc: Code clean-up Cleaned code; removed unused functions. Renamed variables to follow gem5 naming conventions. --- src/network/data_cell.cc | 46 ++----- src/network/data_cell.hh | 28 +---- src/network/layer.cc | 187 ++++++++++------------------ src/network/layer.hh | 16 +-- src/network/network_scheduler.cc | 205 +++++-------------------------- src/network/network_scheduler.hh | 22 +--- 6 files changed, 117 insertions(+), 387 deletions(-) diff --git a/src/network/data_cell.cc b/src/network/data_cell.cc index 0505f3bc2f..0d80ed7cb7 100644 --- a/src/network/data_cell.cc +++ b/src/network/data_cell.cc @@ -37,12 +37,11 @@ namespace gem5 { // Constructor for DataCell class -// Initializes the cell with default values and links to the statistics group +// Initializes the cell with default values DataCell::DataCell(const DataCellParams& params) : ClockedObject(params), data(0), // Initialize data to 0 - addr(0), // Initialize address to 0 - stats(this) // Link the stats object to this cell + addr(0) // Initialize address to 0 { } @@ -76,11 +75,11 @@ DataCell::getAddr() // Assigns a packet to the cell by pushing the dest address into queue void -DataCell::assignPacket(uint64_t destAddr) +DataCell::assignPacket(uint64_t dest_addr) { - packetQueue.push(destAddr); // Queue the dest + packetQueue.push(dest_addr); // Queue the dest DPRINTF(DataCell, "DataCell %d assigned packet to destination %d\n", - addr, destAddr); + addr, dest_addr); } // Retrieves and removes the next packet from the queue @@ -92,7 +91,6 @@ DataCell::getNextPacket() // Get the next packet and remove it from the queue uint64_t nextPacket = packetQueue.front(); packetQueue.pop(); - stats.sentPackets++; return nextPacket; } return 0; // No packet available @@ -107,16 +105,13 @@ DataCell::hasPackets() const // Handles receiving data by updating the last received values and stats void -DataCell::receiveData(uint64_t receivedData, uint64_t srcAddr) +DataCell::receiveData(uint64_t received_data, uint64_t src_addr) { DPRINTF(DataCell, "DataCell %d received data %d from source %d\n", - addr, receivedData, srcAddr); + addr, received_data, src_addr); - lastReceivedData = receivedData; // Store the last received data - lastReceivedFrom = srcAddr; // Store the source of the data - - receivedPackets++; // Increment the local received counter - stats.receivedPackets++; // Increment the statistics counter + lastReceivedData = received_data; // Store the last received data + lastReceivedFrom = src_addr; // Store the source of the data } // Returns the next packet without removing it from the queue @@ -130,27 +125,4 @@ DataCell::peekNextPacket() const return -1; // No packet available } -// Constructor for the statistics group associated with the DataCell -DataCell::DataCellStats::DataCellStats(DataCell* dataCell) : - statistics::Group(dataCell), - ADD_STAT(sentPackets, statistics::units::Count::get(), - "Packets sent from this cell"), - ADD_STAT(receivedPackets, statistics::units::Count::get(), - "Packets received by this cell") -{ -} - -// Registers statistics for the DataCell -void -DataCell::DataCellStats::regStats() -{ - using namespace statistics; - - sentPackets.name("sentPackets") - .desc("Number of packets sent from this cell"); - - receivedPackets.name("receivedPackets") - .desc("Number of packets received by this cell"); -} - } // namespace gem5 diff --git a/src/network/data_cell.hh b/src/network/data_cell.hh index c2bda9bcd8..af2d3ad97f 100644 --- a/src/network/data_cell.hh +++ b/src/network/data_cell.hh @@ -52,30 +52,10 @@ class DataCell : public ClockedObject // Queue to hold packets (destination addresses) assigned to the cell std::queue packetQueue; - // Counters for the # of packets sent and received by the cell - uint64_t sentPackets = 0; - uint64_t receivedPackets = 0; - // Variables to store the most recent received data and source addr uint64_t lastReceivedData = 0; uint64_t lastReceivedFrom = 0; - // Statistics struct to track sent and received packets - struct DataCellStats : public statistics::Group - { - statistics::Scalar sentPackets; // # of packets sent - statistics::Scalar receivedPackets; // # of packets received - - // Constructor for the statistics group - DataCellStats(DataCell* dataCell); - - // Registers the statistics with gem5's statistics system - void regStats() override; - }; - - // Statistics instance associated with the current DataCell - DataCellStats stats; - public: // Constructor: Initializes the DataCell with parameters DataCell(const DataCellParams& params); @@ -93,11 +73,11 @@ class DataCell : public ClockedObject uint64_t getAddr(); // Assigns a packet to the queue with the given destination address - void assignPacket(uint64_t destAddr); + void assignPacket(uint64_t dest_addr); // Receives data from another cell // Stores the received value and source - void receiveData(uint64_t receivedData, uint64_t srcAddr); + void receiveData(uint64_t received_data, uint64_t src_addr); // Retrieves and removes the next packet from the queue uint64_t getNextPacket(); @@ -105,10 +85,6 @@ class DataCell : public ClockedObject // Checks if the cell has any packets in its queue bool hasPackets() const; - // Getters for tracking statistics - uint64_t getSentPackets() const { return sentPackets; } - uint64_t getReceivedPackets() const { return receivedPackets; } - // Getters for the last received data and source information uint64_t getLastReceivedData() const { return lastReceivedData; } uint64_t getLastReceivedFrom() const { return lastReceivedFrom; } diff --git a/src/network/layer.cc b/src/network/layer.cc index 667798e927..b4edba5e65 100644 --- a/src/network/layer.cc +++ b/src/network/layer.cc @@ -80,31 +80,28 @@ Layer::Layer(const LayerParams& params) : // Initialize the network scheduler std::queue> - scheduleQueue = scheduler.initialize(); + schedule_queue = scheduler.initialize(); - if (!scheduleQueue.empty()) { + if (!schedule_queue.empty()) { fileMode = true; - maxPackets = scheduleQueue.size(); - while (!scheduleQueue.empty()) { - const auto& entry = scheduleQueue.front(); + maxPackets = schedule_queue.size(); + while (!schedule_queue.empty()) { + const auto& entry = schedule_queue.front(); - uint64_t srcAddr = entry.first; - uint64_t destAddr = entry.second; + uint64_t src_addr = entry.first; + uint64_t dest_addr = entry.second; - DataCell* cell = getDataCell(srcAddr); + DataCell* cell = getDataCell(src_addr); if (cell != nullptr) { - cell->assignPacket(destAddr); + cell->assignPacket(dest_addr); DPRINTF(Layer, "DataCell %d: addr=%d, packet assigned to %d\n", - srcAddr, cell->getAddr(), destAddr); + src_addr, cell->getAddr(), dest_addr); } - scheduleQueue.pop(); + schedule_queue.pop(); } } - // Assign packets from the predefined schedule - // assignPacketsFromSchedule(); - // Compute network parameters like time slot and connection window // computeNetworkParameters(); @@ -122,7 +119,7 @@ Layer::initializeDataCells(const std::vector& cells) } // Set network radix - assignRadix(cells.size() * 2); + setRadix(cells.size() * 2); // Populate data cells with addresses and random data for (uint64_t i = 0; i < cells.size(); i++) { @@ -130,8 +127,8 @@ Layer::initializeDataCells(const std::vector& cells) cell->setAddr(i); // Generate random data within the dynamic range - uint64_t randomData = random() % dynamicRange; - cell->setData(randomData); + uint64_t random_data = random() % dynamicRange; + cell->setData(random_data); DPRINTF(Layer, "DataCell %d: addr=%d, data=%d\n", i, cell->getAddr(), cell->getData()); @@ -141,33 +138,6 @@ Layer::initializeDataCells(const std::vector& cells) } } -// Assign packets to data cells based on the predefined schedule -void -Layer::assignPacketsFromSchedule() -{ - uint64_t packetCount = 0; - - // Process all packets in the scheduler - while (scheduler.hasPackets()) { - // Get the next packet's source and destination addresses - auto [srcAddr, destAddr] = scheduler.getNextPacket(); - - // Find the source data cell - DataCell* cell = getDataCell(srcAddr); - if (cell != nullptr) { - DPRINTF(Layer, - "Assigning packet: src=%d, dest=%d\n", - srcAddr, destAddr - ); - // Assign the packet to the source cell - cell->assignPacket(destAddr); - packetCount++; - } - } - - DPRINTF(Layer, "Total packets assigned: %d\n", packetCount); -} - // Compute key network parameters like time slot and connection window void Layer::computeTimingParameters() @@ -189,47 +159,25 @@ Layer::computeTimingParameters() ); } -// Schedule the initial network event if there are packets to process -// void -// Layer::scheduleInitialEvent() -// { -// bool hasPackets = false; -// // Check if any data cell has packets -// for (DataCell* cell : dataCells) { -// if (cell->hasPackets()) { -// hasPackets = true; -// break; -// } -// } - -// // Schedule the first network event if packets exist -// if (!dataCells.empty() && hasPackets) { -// DPRINTF(Layer, "Scheduling first network event\n"); -// scheduleNextNetworkEvent(curTick()); // Start at this tick -// } else { -// DPRINTF(Layer, "No packets to process\n"); -// } -// } - // Calculate the time slot based on network component delays void Layer::assignTimeSlot() { // Adjust setup time considering circuit variability - double SE_adjusted = std::max(0.0, + double se_adjusted = std::max(0.0, crosspointSetupTime - circuitVariability ); // Calculate time slot considering delays of various network components - double calculatedTimeSlot = circuitVariability * ( - crosspointDelay + SE_adjusted + + double calculated_time_slot = circuitVariability * ( + crosspointDelay + se_adjusted + splitterDelay * (radix - 1) + mergerDelay * (radix - 1) + variabilityCountingNetwork ); // Round up the calculated time slot - this->timeSlot = Cycles(std::ceil(calculatedTimeSlot)); + this->timeSlot = Cycles(std::ceil(calculated_time_slot)); } // Add a data cell to the network's data cell collection @@ -256,16 +204,16 @@ Layer::processNextNetworkEvent() if (isFinished) { return; } - uint64_t packetsProcessedThisWindow = 0; + uint64_t packets_processed_this_window = 0; // Build a static schedule for the current time slot - std::unordered_map staticSchedule = + std::unordered_map static_schedule = buildStaticSchedule(); // Process packets according to the static schedule processPackets( - staticSchedule, - packetsProcessedThisWindow + static_schedule, + packets_processed_this_window ); stats.totalWindowsUsed++; @@ -286,31 +234,31 @@ Layer::processNextNetworkEvent() std::unordered_map Layer::buildStaticSchedule() { - std::unordered_map staticSchedule; + std::unordered_map static_schedule; // Determine allowed destination for each data cell for (DataCell* cell : dataCells) { - uint64_t srcAddr = cell->getAddr(); - uint64_t allowedDest = - (srcAddr + currentTimeSlotIndex) % dataCells.size(); - staticSchedule[srcAddr] = allowedDest; + uint64_t src_addr = cell->getAddr(); + uint64_t allowed_dest = + (src_addr + currentTimeSlotIndex) % dataCells.size(); + static_schedule[src_addr] = allowed_dest; DPRINTF(Layer, "Window %lu: allowed transmission from DataCell %lu to %lu\n", - currentTimeSlotIndex, srcAddr, allowedDest + currentTimeSlotIndex, src_addr, allowed_dest ); } - return staticSchedule; + return static_schedule; } // Process packets according to the static schedule bool Layer::processPackets( - const std::unordered_map& staticSchedule, - uint64_t& packetsProcessedThisWindow) + const std::unordered_map& static_schedule, + uint64_t& packets_processed_this_window) { - Tick payloadSpecificDelay = 0; + Tick payload_specific_delay = 0; // Determine if we are in infinite mode bool infinite_mode = (maxPackets == static_cast(-1)); @@ -321,43 +269,43 @@ Layer::processPackets( break; // Exit the loop immediately if we've reached max packets } - uint64_t srcAddr = cell->getAddr(); - uint64_t allowedDest = staticSchedule.at(srcAddr); + uint64_t src_addr = cell->getAddr(); + uint64_t allowed_dest = static_schedule.at(src_addr); - uint64_t packetDest = -1; + uint64_t packet_dest = -1; // Check if there's already a packet in the buffer first if (cell->hasPackets()) { - packetDest = cell->peekNextPacket(); + packet_dest = cell->peekNextPacket(); } else { if (!fileMode) { if (trafficMode == TrafficMode::RANDOM) { // Generate a random packet destination - packetDest = scheduler.generateRandomPacket(srcAddr); + packet_dest = scheduler.generateRandomPacket(src_addr); } else if (trafficMode == TrafficMode::HOTSPOT) { // Use the static schedule for the current time slot - packetDest = scheduler.generateHotspotPacket( - srcAddr, hotspotAddr, hotspotFraction + packet_dest = scheduler.generateHotspotPacket( + src_addr, hotspotAddr, hotspotFraction ); } DPRINTF(Layer, "DataCell %lu: generated packet for %lu\n", - srcAddr, packetDest + src_addr, packet_dest ); // Only generate a new packet if there's nothing in the buffer - assert(packetDest != -1); + assert(packet_dest != -1); } else { // In file mode, don't generate a new packet destination. // Optionally, log that no new packet was generated. DPRINTF(Layer, "DataCell %lu: file mode active," "skipping packet generation\n", - srcAddr + src_addr ); } } // Check if packet can be sent in the current time slot - if (packetDest == allowedDest) { + if (packet_dest == allowed_dest) { // Remove the packet if it was from the buffer if (cell->hasPackets()) { cell->getNextPacket(); @@ -367,23 +315,23 @@ Layer::processPackets( // Calculate precise delivery time // within the connection window // Use the payload value -> RACE LOGIC - payloadSpecificDelay = ((payload + 1)) * + payload_specific_delay = ((payload + 1)) * (getTimeSlot()) * clockPeriod()/714; DPRINTF(Layer, "Processing packet: src=%lu, dest=%lu, \ data=%lu, specific delay=%lu ps\n", - srcAddr, allowedDest, payload, payloadSpecificDelay + src_addr, allowed_dest, payload, payload_specific_delay ); stats.totalPacketsProcessed++; packetsDelivered++; - packetsProcessedThisWindow++; + packets_processed_this_window++; // Schedule packet delivery with payload-specific timing schedule(new EventFunctionWrapper([this, - srcAddr, allowedDest, payload]() { - deliverPacket(srcAddr, allowedDest, payload); - }, "deliverPacketEvent"), curTick() + payloadSpecificDelay); + src_addr, allowed_dest, payload]() { + deliverPacket(src_addr, allowed_dest, payload); + }, "deliverPacketEvent"), curTick() + payload_specific_delay); // Check if we've reached max packets after processing this one // If not in infinite mode, check for termination condition. @@ -392,19 +340,19 @@ Layer::processPackets( } } else if (!fileMode) { // Packet not allowed in the current time slot - cell->assignPacket(packetDest); + cell->assignPacket(packet_dest); DPRINTF(Layer, "DataCell %lu: packet for %lu not scheduled (allowed: %lu)\n", - srcAddr, packetDest, allowedDest + src_addr, packet_dest, allowed_dest ); DPRINTF(Layer, "DataCell %lu: packet for %lu assigned to buffer\n", - srcAddr, packetDest + src_addr, packet_dest ); } } - stats.pktsPerWindow.sample(packetsProcessedThisWindow); + stats.pktsPerWindow.sample(packets_processed_this_window); // Only exit simulation if not in infinite mode if (!infinite_mode && packetsDelivered >= maxPackets) { @@ -414,14 +362,14 @@ Layer::processPackets( ); DPRINTF(Layer, "Payload specific delay: %lu\n", - payloadSpecificDelay + payload_specific_delay ); isFinished = true; if (superNetwork != nullptr) { // Schedule the notification after the delay schedule(new EventFunctionWrapper([this]() { superNetwork->notifyLayerFinished(this); - }, "layerFinishedEvent"), curTick() + payloadSpecificDelay); + }, "layerFinishedEvent"), curTick() + payload_specific_delay); } } @@ -430,22 +378,22 @@ Layer::processPackets( // Deliver a packet to its destination data cell void -Layer::deliverPacket(uint64_t srcAddr, - uint64_t destAddr, uint64_t payload) +Layer::deliverPacket(uint64_t src_addr, + uint64_t dest_addr, uint64_t payload) { // Find the destination data cell - DataCell* destCell = getDataCell(destAddr); - if (destCell != nullptr) { + DataCell* dest_cell = getDataCell(dest_addr); + if (dest_cell != nullptr) { // Receive data at the destination cell - destCell->receiveData(payload, srcAddr); + dest_cell->receiveData(payload, src_addr); DPRINTF(Layer, "Packet delivered: src=%lu, dest=%lu, data=%lu\n", - srcAddr, destAddr, payload + src_addr, dest_addr, payload ); } else { DPRINTF(Layer, "Error: Destination cell %lu not found\n", - destAddr + dest_addr ); } } @@ -462,8 +410,8 @@ Layer::scheduleNextNetworkEvent(Tick when) // Constructor for Layer statistics Layer::LayerStats::LayerStats( - Layer* Layer - ) : statistics::Group(Layer), + Layer* layer + ) : statistics::Group(layer), ADD_STAT(totalPacketsProcessed, statistics::units::Count::get(), "Total packets processed"), ADD_STAT(totalWindowsUsed, statistics::units::Count::get(), @@ -487,13 +435,6 @@ Layer::LayerStats::regStats() totalWindowsUsed.name("totalWindowsUsed") .desc("Number of connection windows used"); - // Calculate average packets per window - // pktsPerWindow.name("pktsPerWindow") - // .desc("Average packets processed per window") - // .precision(2) - // .flags(nozero) - // = totalPacketsProcessed / totalWindowsUsed; - pktsPerWindow.init(64); } diff --git a/src/network/layer.hh b/src/network/layer.hh index 1d9667b185..efb1d81cf2 100644 --- a/src/network/layer.hh +++ b/src/network/layer.hh @@ -83,10 +83,8 @@ private: uint64_t hotspotAddr; // Address of the hotspot double hotspotFraction; // Fraction of packets targeting the hotspot - // Initialization methods to set up network layers and data cells - void initializeNetworkLayers(const std::vector& layers); + // Initialization methods to set up data cells void initializeDataCells(const std::vector& cells); - void assignPacketsFromSchedule(); // Method to calculate the time slot based on network parameters void assignTimeSlot(); @@ -95,11 +93,13 @@ private: // Builds a static schedule for the current time slot std::unordered_map buildStaticSchedule(); bool processPackets( - const std::unordered_map& staticSchedule, - uint64_t& packetsProcessedThisWindow + const std::unordered_map& static_schedule, + uint64_t& packets_processed_this_window ); // Method for delivering a packet to its destination - void deliverPacket(uint64_t srcAddr, uint64_t destAddr, uint64_t payload); + void deliverPacket(uint64_t src_addr, + uint64_t dest_addr, uint64_t payload + ); // Struct to hold statistics related to the Layer struct LayerStats: public statistics::Group @@ -115,7 +115,7 @@ private: statistics::Histogram pktsPerWindow; // Constructor that links stats to the Layer instance - LayerStats(Layer* Layer); + LayerStats(Layer* layer); // Registers the statistics with the simulator void regStats() override; @@ -140,7 +140,7 @@ public: // Methods for assigning and retrieving radix, // time slot, and connection window values - void assignRadix(uint64_t radix) { this->radix = radix; } + void setRadix(uint64_t radix) { this->radix = radix; } uint64_t getRadix() const { return radix; } Cycles getTimeSlot() const { return timeSlot; } diff --git a/src/network/network_scheduler.cc b/src/network/network_scheduler.cc index c7b08bdfac..1238465594 100644 --- a/src/network/network_scheduler.cc +++ b/src/network/network_scheduler.cc @@ -38,14 +38,14 @@ namespace gem5 { // Initializes the scheduler with maximum packets, // schedule path, and list of DataCells NetworkScheduler::NetworkScheduler( - uint64_t maxPackets, - const std::string& schedulePath, + uint64_t max_packets, + const std::string& schedule_path, const std::vector& cells ) -: maxPackets(maxPackets), - schedulePath(schedulePath), +: maxPackets(max_packets), + schedulePath(schedule_path), dataCells(cells), - infiniteMode(maxPackets == static_cast(-1)) + infiniteMode(max_packets == static_cast(-1)) {} // Initializes the scheduler by either generating or loading a schedule @@ -62,135 +62,6 @@ NetworkScheduler::initialize() return scheduleQueue; } -void -NetworkScheduler::generateAllToAllSchedule() -{ - clear(); - if (dataCells.empty()) { - warn("No DataCells available for scheduling.\n"); - return; - } - - // For each cell as a source, - // schedule packets to all other cells as destinations. - for (size_t i = 0; i < dataCells.size(); i++) { - for (size_t j = 0; j < dataCells.size(); j++) { - if (i != j) { - uint64_t srcAddr = dataCells[i]->getAddr(); - uint64_t destAddr = dataCells[j]->getAddr(); - scheduleQueue.push(std::make_pair(srcAddr, destAddr)); - } - } - } - DPRINTF(NetworkScheduler, - "All-to-All schedule generated with %d packets.\n", - scheduleQueue.size() - ); -} - -void -NetworkScheduler::generateHotspotSchedule( - uint64_t hotspotAddr, - double hotspotFraction -) -{ - clear(); - if (dataCells.empty()) { - warn("No DataCells available for scheduling.\n"); - return; - } - - // Calculate the number of hotspot packets based on hotspotFraction. - uint64_t hotspotPackets = maxPackets * hotspotFraction; - uint64_t otherPackets = maxPackets - hotspotPackets; - std::random_device rd; - std::mt19937 gen(rd()); - - // Generate packets targeting the hotspot. - for (uint64_t i = 0; i < hotspotPackets; i++) { - int srcIndex = gen() % dataCells.size(); - uint64_t srcAddr = dataCells[srcIndex]->getAddr(); - scheduleQueue.push(std::make_pair(srcAddr, hotspotAddr)); - } - - // Generate remaining random packets. - for (uint64_t i = 0; i < otherPackets; i++) { - int srcIndex = gen() % dataCells.size(); - int destIndex = gen() % dataCells.size(); - uint64_t srcAddr = dataCells[srcIndex]->getAddr(); - uint64_t destAddr = dataCells[destIndex]->getAddr(); - scheduleQueue.push(std::make_pair(srcAddr, destAddr)); - } - - DPRINTF(NetworkScheduler, - "Hotspot schedule generated: %d packets targeting hotspot %d.\n", - hotspotPackets, hotspotAddr - ); -} - - -// Generates a random schedule of packets -void -NetworkScheduler::generateRandomSchedule() -{ - // Clear any existing schedule before generating a new one - clear(); - - if (dataCells.empty()) { - // Warn if there are no DataCells available - warn("No DataCells available for scheduling.\n"); - return; - } - - // In infinite mode we do not pre-generate the schedule. - if (infiniteMode) { - DPRINTF(NetworkScheduler, - "Infinite mode active: schedule will \ - be generated on demand.\n" - ); - return; - } - - // Random number generator setup - std::random_device rd; // Random seed - std::mt19937 gen(rd()); // Mersenne Twister random generator - - // Generate random src-dest packet pairs - for (uint64_t i = 0; i < maxPackets; i++) { - int srcIndex = gen() % dataCells.size(); - int destIndex = gen() % dataCells.size(); - uint64_t srcAddr = dataCells[srcIndex]->getAddr(); - uint64_t destAddr = dataCells[destIndex]->getAddr(); - scheduleQueue.push(std::make_pair(srcAddr, destAddr)); - } - - DPRINTF(NetworkScheduler, - "Random schedule generated with %d packets.\n", - scheduleQueue.size()); -} - -// Saves the current schedule to a file -void -NetworkScheduler::saveSchedule() -{ - std::ofstream ofs(schedulePath); - if (!ofs.is_open()) { - // Fatal error if the file cannot be opened for writing - fatal("Failed to open schedule file %s for writing.\n", schedulePath); - } - - // Write each src-dest packet pair to the file - std::queue> tempQueue = scheduleQueue; - while (!tempQueue.empty()) { - auto entry = tempQueue.front(); - ofs << entry.first << " " << entry.second << "\n"; - tempQueue.pop(); - } - - ofs.close(); - DPRINTF(NetworkScheduler, "Schedule saved to %s.\n", schedulePath); -} - // Generates a random packet using the given src. // It picks a random destination from dataCells. uint64_t @@ -205,24 +76,24 @@ NetworkScheduler::generateRandomPacket(uint64_t src) std::random_device rd; std::mt19937 gen(rd()); - uint64_t destAddr = src; + uint64_t dest_addr = src; if (dataCells.size() > 1) { - int destIndex = gen() % dataCells.size(); - destAddr = dataCells[destIndex]->getAddr(); + int dest_index = gen() % dataCells.size(); + dest_addr = dataCells[dest_index]->getAddr(); } - return destAddr; + return dest_addr; } // Generates a hotspot packet using the -// given src, hotspotAddr and hotspotFraction. +// given src, hotspot_addr and hotspot_fraction. // It generates a packet targeting the hotspot with -// probability hotspotFraction. +// probability hotspot_fraction. uint64_t NetworkScheduler::generateHotspotPacket( uint64_t src, - uint64_t hotspotAddr, - double hotspotFraction + uint64_t hotspot_addr, + double hotspot_fraction ) { if (dataCells.empty()) { @@ -231,8 +102,8 @@ NetworkScheduler::generateHotspotPacket( } // Check if the hotspot address is valid - if (hotspotAddr >= dataCells.size()) { - fatal("Invalid hotspot address %lu.\n", hotspotAddr); + if (hotspot_addr >= dataCells.size()) { + fatal("Invalid hotspot address %lu.\n", hotspot_addr); return -1; } @@ -241,9 +112,9 @@ NetworkScheduler::generateHotspotPacket( std::mt19937 gen(rd()); // Generate a packet targeting the hotspot - // with probability hotspotFraction. - if (gen() % 100 < hotspotFraction * 100) { - return hotspotAddr; + // with probability hotspot_fraction. + if (gen() % 100 < hotspot_fraction * 100) { + return hotspot_addr; } // Generate a random packet targeting a random destination. @@ -270,27 +141,27 @@ NetworkScheduler::loadSchedule() // Clear any existing schedule clear(); - std::vector> fileEntries; + std::vector> file_entries; uint64_t src, dest; // Read src-dest pairs from the file while (ifs >> src >> dest) { - fileEntries.emplace_back(src, dest); + file_entries.emplace_back(src, dest); } // Load the read entries into the schedule queue - uint64_t packetCount = loadScheduleEntries(fileEntries); + uint64_t packet_count = loadScheduleEntries(file_entries); DPRINTF(NetworkScheduler, "Schedule loaded from %s with %d entries.\n", - schedulePath, packetCount); + schedulePath, packet_count); } // Adds schedule entries from the file into the queue uint64_t NetworkScheduler::loadScheduleEntries(const std::vector>& fileEntries) + uint64_t>>& file_entries) { - uint64_t packetCount = 0; + uint64_t packet_count = 0; if (maxPackets > 0) { // If maxPackets is specified, only load up to that limit @@ -299,24 +170,24 @@ NetworkScheduler::loadScheduleEntries(const std::vector 0) { uint64_t entriesThisRound = std::min(remaining, - (uint64_t)fileEntries.size()); + (uint64_t)file_entries.size()); for (uint64_t i = 0; i < entriesThisRound; i++) { - scheduleQueue.push(fileEntries[i]); - packetCount++; + scheduleQueue.push(file_entries[i]); + packet_count++; } remaining -= entriesThisRound; } } else { // If no maxPackets limit, load all entries - for (const auto& entry : fileEntries) { + for (const auto& entry : file_entries) { scheduleQueue.push(entry); - packetCount++; + packet_count++; } } - return packetCount; + return packet_count; } // Checks if the schedule file exists @@ -334,22 +205,6 @@ NetworkScheduler::hasPackets() const return infiniteMode ? true : (!scheduleQueue.empty()); } -// Retrieves the next packet in the schedule -std::pair -NetworkScheduler::getNextPacket() -{ - if (scheduleQueue.empty()) { - // Return a default packet with {-1, -1} - // if the queue is empty - return {-1, -1}; - } - - // Retrieve and remove the next packet from the queue - auto packet = scheduleQueue.front(); - scheduleQueue.pop(); - return packet; -} - // Clears the current schedule by swapping with an empty queue void NetworkScheduler::clear() diff --git a/src/network/network_scheduler.hh b/src/network/network_scheduler.hh index 9d57417e3b..5c7f74543e 100644 --- a/src/network/network_scheduler.hh +++ b/src/network/network_scheduler.hh @@ -55,25 +55,14 @@ public: // Initializes the scheduler std::queue> initialize(); - // Generates a random schedule for packets between DataCells - void generateRandomSchedule(); - // Generates a random packet using the given src uint64_t generateRandomPacket(uint64_t src); - // Generates an all-to-all schedule for packets between DataCells - void generateAllToAllSchedule(); - - // Generates a hotspot schedule for packets between DataCells - void generateHotspotSchedule(uint64_t hotspotAddr, - double hotspotFraction - ); - // Generates a hotspot packet - // using the given src, hotspotAddr and hotspotFraction + // using the given src, hotspot_addr and hotspot_fraction uint64_t generateHotspotPacket(uint64_t src, - uint64_t hotspotAddr, - double hotspotFraction + uint64_t hotspot_addr, + double hotspot_fraction ); // Saves the current schedule to a specified file @@ -84,15 +73,12 @@ public: // Loads schedule entries from a given list of source-destination pairs uint64_t loadScheduleEntries(const std::vector>& fileEntries + uint64_t>>& file_entries ); // Checks if there are any packets left in the schedule bool hasPackets() const; - // Returns the next packet in the schedule - std::pair getNextPacket(); - // Clears the current schedule, effectively resetting the scheduler void clear(); From 46c60aaa61ffc59122ca3718dce99e9cd86fdddd Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Mon, 7 Apr 2025 10:46:46 -0700 Subject: [PATCH 21/47] misc: Add hold time According to SRNoC paper, a connection window is setup time + RL time slots + hold time Updated scheduling to reflect the above. --- configs/supernetwork/SRNoC.py | 2 ++ src/network/Layer.py | 1 + src/network/layer.cc | 21 +++++++++++++++------ src/network/layer.hh | 1 + 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/configs/supernetwork/SRNoC.py b/configs/supernetwork/SRNoC.py index 145b2e65ca..0c17d88505 100644 --- a/configs/supernetwork/SRNoC.py +++ b/configs/supernetwork/SRNoC.py @@ -39,6 +39,7 @@ class NetworkDelays(PyEnum): CIRCUIT_VARIABILITY = 1.2 VARIABILITY_COUNTING_NETWORK = 4.38 CROSSPOINT_SETUP_TIME = 8.0 + CROSSPOINT_HOLD_TIME = 8.0 class ComponentPower(PyEnum): @@ -219,6 +220,7 @@ def main(): circuit_variability=NetworkDelays.CIRCUIT_VARIABILITY.value, variability_counting_network=NetworkDelays.VARIABILITY_COUNTING_NETWORK.value, crosspoint_setup_time=NetworkDelays.CROSSPOINT_SETUP_TIME.value, + hold_time=NetworkDelays.CROSSPOINT_HOLD_TIME.value, ) for dr in args.dynamic_range ] diff --git a/src/network/Layer.py b/src/network/Layer.py index 754dee1d02..93572fa339 100644 --- a/src/network/Layer.py +++ b/src/network/Layer.py @@ -59,6 +59,7 @@ class Layer(ClockedObject): crosspoint_setup_time = Param.Float( -1, "Crosspoint setup time in picoseconds" ) + hold_time = Param.Float(-1, "Hold time in picoseconds") cxx_exports = [ PyBindMethod("setRandomTrafficMode"), diff --git a/src/network/layer.cc b/src/network/layer.cc index b4edba5e65..65d0734281 100644 --- a/src/network/layer.cc +++ b/src/network/layer.cc @@ -59,6 +59,7 @@ Layer::Layer(const LayerParams& params) : circuitVariability(params.circuit_variability), variabilityCountingNetwork(params.variability_counting_network), crosspointSetupTime(params.crosspoint_setup_time), + holdTime(params.hold_time), packetsDelivered(0), currentTimeSlotIndex(0), isFinished(false), @@ -211,22 +212,30 @@ Layer::processNextNetworkEvent() buildStaticSchedule(); // Process packets according to the static schedule - processPackets( - static_schedule, - packets_processed_this_window - ); + // Add hold time before processing packets + schedule(new EventFunctionWrapper( + [this, static_schedule, &packets_processed_this_window]() { + processPackets(static_schedule, packets_processed_this_window); + }, "processPacketsEvent"), + curTick() + holdTime * clockPeriod() / 714); stats.totalWindowsUsed++; // Advance the time slot for the next event - currentTimeSlotIndex++; + // Add scheduled setup time + // currentTimeSlotIndex++; + schedule(new EventFunctionWrapper( + [this]() { + currentTimeSlotIndex++; + }, "advanceTimeSlotEvent"), + curTick() + crosspointSetupTime * clockPeriod() / 714); // Schedule next network event. // In infinite mode (maxPackets == -1) we always schedule the next event. if (maxPackets == static_cast(-1) || packetsDelivered < maxPackets) { scheduleNextNetworkEvent(curTick() + - connectionWindow * clockPeriod()/714); + ((connectionWindow + crosspointSetupTime) * clockPeriod()/714)); } } diff --git a/src/network/layer.hh b/src/network/layer.hh index efb1d81cf2..4c2042f056 100644 --- a/src/network/layer.hh +++ b/src/network/layer.hh @@ -63,6 +63,7 @@ private: double circuitVariability; double variabilityCountingNetwork; double crosspointSetupTime; + double holdTime; // Network configuration parameters uint64_t dynamicRange; // The dynamic range of the network From 35fa81afafdb31187ee69fef42ef229e06ecf7f8 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Sun, 13 Apr 2025 01:39:40 -0700 Subject: [PATCH 22/47] misc: Improve timing model Timing was made more accurate based on the SRNoC paper --- src/network/layer.cc | 23 ++++++++++++++++++----- src/network/layer.hh | 1 + src/network/network_scheduler.cc | 14 ++++++++------ 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/network/layer.cc b/src/network/layer.cc index 65d0734281..dc4fbcd0fd 100644 --- a/src/network/layer.cc +++ b/src/network/layer.cc @@ -64,6 +64,7 @@ Layer::Layer(const LayerParams& params) : currentTimeSlotIndex(0), isFinished(false), fileMode(false), + size(params.data_cells.size()), // Event for processing the next network event nextNetworkEvent([this]{ processNextNetworkEvent(); }, name() + ".nextNetworkEvent"), @@ -150,8 +151,14 @@ Layer::computeTimingParameters() getTimeSlot() * clockPeriod()/714 ); + // dynamic range increases due to circuit variability + // and the number of data cells + double expected_packets = std::round( + (dynamicRange * std::exp(1.0)) / (std::exp(1.0) - 1.0) + ); + // Calculate and assign the connection window - setConnectionWindow(Cycles(dynamicRange * getTimeSlot())); + setConnectionWindow(Cycles(expected_packets * getTimeSlot())); DPRINTF(Layer, "Connection window: %d Cycles\n", getConnectionWindow() ); @@ -214,9 +221,10 @@ Layer::processNextNetworkEvent() // Process packets according to the static schedule // Add hold time before processing packets schedule(new EventFunctionWrapper( - [this, static_schedule, &packets_processed_this_window]() { + [this, static_schedule, packets_processed_this_window]() mutable { processPackets(static_schedule, packets_processed_this_window); - }, "processPacketsEvent"), + }, + "processPacketsEvent"), curTick() + holdTime * clockPeriod() / 714); stats.totalWindowsUsed++; @@ -324,8 +332,13 @@ Layer::processPackets( // Calculate precise delivery time // within the connection window // Use the payload value -> RACE LOGIC - payload_specific_delay = ((payload + 1)) * - (getTimeSlot()) * clockPeriod()/714; + payload_specific_delay = + ((payload + 1) * getTimeSlot() * clockPeriod() / 714) + + splitterDelay * (packet_dest + 1) * clockPeriod() / 714 + + mergerDelay * (size - src_addr - 1) * clockPeriod() / 714 + + crosspointDelay * clockPeriod() / 714; + + DPRINTF(Layer, "Processing packet: src=%lu, dest=%lu, \ diff --git a/src/network/layer.hh b/src/network/layer.hh index 4c2042f056..dd1bbb641c 100644 --- a/src/network/layer.hh +++ b/src/network/layer.hh @@ -73,6 +73,7 @@ private: uint64_t currentTimeSlotIndex; // Current index for the time slot int maxPackets; // Maximum number of packets, -1 means no limit int packetsDelivered; // Number of packet deliveries + int size; // Size of the network bool isFinished; // Flag to indicate if the layer has finished bool fileMode; // Flag to indicate if a file is used for scheduling std::string schedulePath; // Path to the schedule file diff --git a/src/network/network_scheduler.cc b/src/network/network_scheduler.cc index 1238465594..63f643957d 100644 --- a/src/network/network_scheduler.cc +++ b/src/network/network_scheduler.cc @@ -52,12 +52,14 @@ NetworkScheduler::NetworkScheduler( std::queue> NetworkScheduler::initialize() { - if (maxPackets == 0 && schedulePath.empty()) { - // Error: No packets and no schedule path specified - fatal("Either max_packets or schedule_path must be provided.\n"); - } else if (maxPackets == 0 && !schedulePath.empty()) { - // Load an existing schedule from the specified path - loadSchedule(); + if (!maxPackets) { + if (schedulePath.empty()) { + fatal("Either max_packets or schedule_path must be provided.\n"); + } else { + loadSchedule(); + } + } else if (!schedulePath.empty()) { + fatal("Both max_packets and schedule_path are specified.\n"); } return scheduleQueue; } From 29eb7fe5a515537ee77c2341e7c39c33479e0603 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Sun, 13 Apr 2025 13:43:39 -0700 Subject: [PATCH 23/47] misc: Add All-to-All traffic mode One DataCell schedules to all other DataCells --- configs/supernetwork/SRNoC.py | 20 ++++++++++++++++++-- src/network/Layer.py | 1 + src/network/enums.cc | 3 ++- src/network/enums.hh | 1 + src/network/layer.cc | 15 +++++++++++++++ src/network/layer.hh | 5 +++++ 6 files changed, 42 insertions(+), 3 deletions(-) diff --git a/configs/supernetwork/SRNoC.py b/configs/supernetwork/SRNoC.py index 0c17d88505..59f6635491 100644 --- a/configs/supernetwork/SRNoC.py +++ b/configs/supernetwork/SRNoC.py @@ -166,6 +166,11 @@ def parse_arguments(): "random", parents=[shared_parser], help="Random traffic mode" ) + # all-to-all traffic + all_to_all_parser = subparsers.add_parser( + "all-to-all", parents=[shared_parser], help="All-to-all traffic mode" + ) + # hotspot traffic hotspot_parser = subparsers.add_parser( "hotspot", parents=[shared_parser], help="Hotspot traffic mode" @@ -207,13 +212,18 @@ def main(): num_cells = args.num_cells data_cells = [DataCell() for _ in range(num_cells)] + if args.traffic_mode != "file": + schedule_path = "" # Force schedule_path to be empty if not using file-based traffic mode. + else: + schedule_path = args.file_path + # Create Layers for each dynamic range. layers = [ Layer( dynamic_range=dr, data_cells=data_cells, max_packets=args.maximum_packets, - schedule_path=getattr(args, "file_path", None), + schedule_path=schedule_path, crosspoint_delay=NetworkDelays.CROSSPOINT_DELAY.value, merger_delay=NetworkDelays.MERGER_DELAY.value, splitter_delay=NetworkDelays.SPLITTER_DELAY.value, @@ -256,7 +266,13 @@ def main(): layer.setHotspotTrafficMode( args.hotspot_addr, args.hotspot_fraction ) - else: # Random or file mode selected. + elif args.traffic_mode == "all-to-all": + for layer in layers: + layer.setAllToAllTrafficMode() + elif args.traffic_mode == "random": + for layer in layers: + layer.setRandomTrafficMode() + else: # file mode selected. for layer in layers: layer.setRandomTrafficMode() diff --git a/src/network/Layer.py b/src/network/Layer.py index 93572fa339..d61b2690c1 100644 --- a/src/network/Layer.py +++ b/src/network/Layer.py @@ -64,4 +64,5 @@ class Layer(ClockedObject): cxx_exports = [ PyBindMethod("setRandomTrafficMode"), PyBindMethod("setHotspotTrafficMode"), + PyBindMethod("setAllToAllTrafficMode"), ] diff --git a/src/network/enums.cc b/src/network/enums.cc index 6b7fd52f67..82417cc53b 100644 --- a/src/network/enums.cc +++ b/src/network/enums.cc @@ -33,7 +33,8 @@ namespace gem5 const char* TrafficModeNames[NUM_TRAFFIC_MODES] = { "RANDOM", - "HOTSPOT" + "HOTSPOT", + "ALL_TO_ALL", }; } // namespace gem5 diff --git a/src/network/enums.hh b/src/network/enums.hh index 53f7ee17cb..7445f5fee7 100644 --- a/src/network/enums.hh +++ b/src/network/enums.hh @@ -36,6 +36,7 @@ enum TrafficMode { RANDOM, HOTSPOT, + ALL_TO_ALL, NUM_TRAFFIC_MODES }; extern const char* TrafficModeNames[NUM_TRAFFIC_MODES]; diff --git a/src/network/layer.cc b/src/network/layer.cc index dc4fbcd0fd..0db3d0f6d9 100644 --- a/src/network/layer.cc +++ b/src/network/layer.cc @@ -303,6 +303,21 @@ Layer::processPackets( packet_dest = scheduler.generateHotspotPacket( src_addr, hotspotAddr, hotspotFraction ); + } else if (trafficMode == TrafficMode::ALL_TO_ALL) { + // Check if the cell already has queued destinations. + if (!cell->hasPackets()) { + // For an all-to-all mode, enqueue each destination. + for (uint64_t dest = 0; dest < size; dest++) { + cell->assignPacket(dest); + DPRINTF(Layer, + "DataCell %lu: enqueued " + "all-to-all packet for destination %lu\n", + src_addr, dest + ); + } + } + // Peek the next destination from the cell’s queue. + packet_dest = cell->peekNextPacket(); } DPRINTF(Layer, "DataCell %lu: generated packet for %lu\n", diff --git a/src/network/layer.hh b/src/network/layer.hh index dd1bbb641c..3db660269c 100644 --- a/src/network/layer.hh +++ b/src/network/layer.hh @@ -167,6 +167,11 @@ public: trafficMode = TrafficMode::RANDOM; } + void setAllToAllTrafficMode() + { + trafficMode = TrafficMode::ALL_TO_ALL; + } + void setHotspotTrafficMode(uint64_t hotspotAddr, double hotspotFraction) { From a7c882ca85581c762a3524ee89666e853685c58b Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Sun, 13 Apr 2025 14:04:43 -0700 Subject: [PATCH 24/47] misc: Add tornado traffic pattern Stresses bisection bandwidth --- configs/supernetwork/SRNoC.py | 7 +++++++ src/network/Layer.py | 1 + src/network/enums.cc | 1 + src/network/enums.hh | 1 + src/network/layer.cc | 6 ++++++ src/network/layer.hh | 5 +++++ src/network/network_scheduler.cc | 25 +++++++++++++++++++++++++ src/network/network_scheduler.hh | 4 ++++ 8 files changed, 50 insertions(+) diff --git a/configs/supernetwork/SRNoC.py b/configs/supernetwork/SRNoC.py index 59f6635491..059d1dcae7 100644 --- a/configs/supernetwork/SRNoC.py +++ b/configs/supernetwork/SRNoC.py @@ -171,6 +171,10 @@ def parse_arguments(): "all-to-all", parents=[shared_parser], help="All-to-all traffic mode" ) + tornado_parser = subparsers.add_parser( + "tornado", parents=[shared_parser], help="Tornado traffic mode" + ) + # hotspot traffic hotspot_parser = subparsers.add_parser( "hotspot", parents=[shared_parser], help="Hotspot traffic mode" @@ -272,6 +276,9 @@ def main(): elif args.traffic_mode == "random": for layer in layers: layer.setRandomTrafficMode() + elif args.traffic_mode == "tornado": + for layer in layers: + layer.setTornadoTrafficMode() else: # file mode selected. for layer in layers: layer.setRandomTrafficMode() diff --git a/src/network/Layer.py b/src/network/Layer.py index d61b2690c1..d81dc03c7d 100644 --- a/src/network/Layer.py +++ b/src/network/Layer.py @@ -65,4 +65,5 @@ class Layer(ClockedObject): PyBindMethod("setRandomTrafficMode"), PyBindMethod("setHotspotTrafficMode"), PyBindMethod("setAllToAllTrafficMode"), + PyBindMethod("setTornadoTrafficMode"), ] diff --git a/src/network/enums.cc b/src/network/enums.cc index 82417cc53b..bbcbc4ecb9 100644 --- a/src/network/enums.cc +++ b/src/network/enums.cc @@ -35,6 +35,7 @@ const char* TrafficModeNames[NUM_TRAFFIC_MODES] = { "RANDOM", "HOTSPOT", "ALL_TO_ALL", + "TORNADO", }; } // namespace gem5 diff --git a/src/network/enums.hh b/src/network/enums.hh index 7445f5fee7..76eb09d06d 100644 --- a/src/network/enums.hh +++ b/src/network/enums.hh @@ -37,6 +37,7 @@ enum TrafficMode RANDOM, HOTSPOT, ALL_TO_ALL, + TORNADO, NUM_TRAFFIC_MODES }; extern const char* TrafficModeNames[NUM_TRAFFIC_MODES]; diff --git a/src/network/layer.cc b/src/network/layer.cc index 0db3d0f6d9..51347bb44d 100644 --- a/src/network/layer.cc +++ b/src/network/layer.cc @@ -318,6 +318,12 @@ Layer::processPackets( } // Peek the next destination from the cell’s queue. packet_dest = cell->peekNextPacket(); + } else if (trafficMode == TrafficMode::TORNADO) { + // Generate a tornado packet + packet_dest = scheduler.generateTornadoPacket(src_addr); + } else { + // Handle unknown traffic mode + fatal("Unknown traffic mode: %d\n", trafficMode); } DPRINTF(Layer, "DataCell %lu: generated packet for %lu\n", diff --git a/src/network/layer.hh b/src/network/layer.hh index 3db660269c..8a3d93ca99 100644 --- a/src/network/layer.hh +++ b/src/network/layer.hh @@ -172,6 +172,11 @@ public: trafficMode = TrafficMode::ALL_TO_ALL; } + void setTornadoTrafficMode() + { + trafficMode = TrafficMode::TORNADO; + } + void setHotspotTrafficMode(uint64_t hotspotAddr, double hotspotFraction) { diff --git a/src/network/network_scheduler.cc b/src/network/network_scheduler.cc index 63f643957d..2e94e8221a 100644 --- a/src/network/network_scheduler.cc +++ b/src/network/network_scheduler.cc @@ -87,6 +87,31 @@ NetworkScheduler::generateRandomPacket(uint64_t src) return dest_addr; } +// Generates a tornado packet using the given src. +// It generates a packet targeting the data cell +// roughly halfway around the network. +// stresses bisection bandwidth. +uint64_t +NetworkScheduler::generateTornadoPacket(uint64_t src) +{ + if (dataCells.empty()) { + warn("No DataCells available for scheduling.\n"); + return -1; + } + + // Check if the source address is valid + if (src >= dataCells.size()) { + fatal("Invalid source address %lu.\n", src); + return -1; + } + + // Generate a packet targeting the data cell + // roughly halfway around the network. + uint64_t dest_addr = (src + dataCells.size() / 2) % dataCells.size(); + + return dest_addr; +} + // Generates a hotspot packet using the // given src, hotspot_addr and hotspot_fraction. // It generates a packet targeting the hotspot with diff --git a/src/network/network_scheduler.hh b/src/network/network_scheduler.hh index 5c7f74543e..91cb39b580 100644 --- a/src/network/network_scheduler.hh +++ b/src/network/network_scheduler.hh @@ -58,6 +58,10 @@ public: // Generates a random packet using the given src uint64_t generateRandomPacket(uint64_t src); + // Generates a tornado packet + // using the given src + uint64_t generateTornadoPacket(uint64_t src); + // Generates a hotspot packet // using the given src, hotspot_addr and hotspot_fraction uint64_t generateHotspotPacket(uint64_t src, From 4488ca98eebb76aff62def92cc829716ccd04eea Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Sun, 13 Apr 2025 17:01:15 -0700 Subject: [PATCH 25/47] misc: Dynamic histogram bins --- src/network/layer.cc | 3 ++- src/network/layer.hh | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/network/layer.cc b/src/network/layer.cc index 51347bb44d..aa719faf8c 100644 --- a/src/network/layer.cc +++ b/src/network/layer.cc @@ -455,6 +455,7 @@ Layer::scheduleNextNetworkEvent(Tick when) Layer::LayerStats::LayerStats( Layer* layer ) : statistics::Group(layer), + parentLayer(layer), ADD_STAT(totalPacketsProcessed, statistics::units::Count::get(), "Total packets processed"), ADD_STAT(totalWindowsUsed, statistics::units::Count::get(), @@ -478,7 +479,7 @@ Layer::LayerStats::regStats() totalWindowsUsed.name("totalWindowsUsed") .desc("Number of connection windows used"); - pktsPerWindow.init(64); + pktsPerWindow.init(parentLayer->size + 1); } } // namespace gem5 diff --git a/src/network/layer.hh b/src/network/layer.hh index 8a3d93ca99..8ffe20412d 100644 --- a/src/network/layer.hh +++ b/src/network/layer.hh @@ -106,6 +106,8 @@ private: // Struct to hold statistics related to the Layer struct LayerStats: public statistics::Group { + // pointer to the Layer instance + Layer *parentLayer; // Statistics for round-robin scheduling From 6532ca248fac3dffcf4d3c6ddaedd3104a0ecc4a Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Tue, 15 Apr 2025 17:23:08 -0700 Subject: [PATCH 26/47] misc: Change timing delays and add new stat Stat tracks the missed packets per cell --- src/network/data_cell.cc | 10 ++++++++++ src/network/data_cell.hh | 7 +++++++ src/network/layer.cc | 33 +++++++++++++++++++++++---------- src/network/layer.hh | 2 ++ 4 files changed, 42 insertions(+), 10 deletions(-) diff --git a/src/network/data_cell.cc b/src/network/data_cell.cc index 0d80ed7cb7..e861bc15a5 100644 --- a/src/network/data_cell.cc +++ b/src/network/data_cell.cc @@ -103,6 +103,16 @@ DataCell::hasPackets() const return !packetQueue.empty(); } +// Increments the missed packet count +void +DataCell::incrementMissedPackets() +{ + missedPackets++; + DPRINTF(DataCell, "DataCell %d missed packets: %d\n", + addr, missedPackets + ); +} + // Handles receiving data by updating the last received values and stats void DataCell::receiveData(uint64_t received_data, uint64_t src_addr) diff --git a/src/network/data_cell.hh b/src/network/data_cell.hh index af2d3ad97f..32d79cb502 100644 --- a/src/network/data_cell.hh +++ b/src/network/data_cell.hh @@ -56,6 +56,8 @@ class DataCell : public ClockedObject uint64_t lastReceivedData = 0; uint64_t lastReceivedFrom = 0; + uint64_t missedPackets = 0; // Count of missed packets + public: // Constructor: Initializes the DataCell with parameters DataCell(const DataCellParams& params); @@ -89,6 +91,11 @@ class DataCell : public ClockedObject uint64_t getLastReceivedData() const { return lastReceivedData; } uint64_t getLastReceivedFrom() const { return lastReceivedFrom; } + // Getter for missed packets count + uint64_t getMissedPackets() const { return missedPackets; } + // Increments the missed packets count + void incrementMissedPackets(); + // Peeks at the next packet without removing it from the queue uint64_t peekNextPacket() const; }; diff --git a/src/network/layer.cc b/src/network/layer.cc index aa719faf8c..4c936ff88f 100644 --- a/src/network/layer.cc +++ b/src/network/layer.cc @@ -148,7 +148,7 @@ Layer::computeTimingParameters() assignTimeSlot(); DPRINTF(Layer, "Time slot: %d Cycles\n", getTimeSlot()); DPRINTF(Layer, "Time slot: %d ps\n", - getTimeSlot() * clockPeriod()/714 + getTimeSlot() * clockPeriod() ); // dynamic range increases due to circuit variability @@ -163,7 +163,7 @@ Layer::computeTimingParameters() getConnectionWindow() ); DPRINTF(Layer, "Connection window: %d ps\n", - getConnectionWindow() * clockPeriod()/714 + getConnectionWindow() * clockPeriod() ); } @@ -225,7 +225,7 @@ Layer::processNextNetworkEvent() processPackets(static_schedule, packets_processed_this_window); }, "processPacketsEvent"), - curTick() + holdTime * clockPeriod() / 714); + curTick() + holdTime * clockPeriod()); stats.totalWindowsUsed++; @@ -236,14 +236,14 @@ Layer::processNextNetworkEvent() [this]() { currentTimeSlotIndex++; }, "advanceTimeSlotEvent"), - curTick() + crosspointSetupTime * clockPeriod() / 714); + curTick() + crosspointSetupTime * clockPeriod()); // Schedule next network event. // In infinite mode (maxPackets == -1) we always schedule the next event. if (maxPackets == static_cast(-1) || packetsDelivered < maxPackets) { scheduleNextNetworkEvent(curTick() + - ((connectionWindow + crosspointSetupTime) * clockPeriod()/714)); + ((connectionWindow + crosspointSetupTime) * clockPeriod())); } } @@ -318,6 +318,10 @@ Layer::processPackets( } // Peek the next destination from the cell’s queue. packet_dest = cell->peekNextPacket(); + DPRINTF(Layer, + "DataCell %lu: all-to-all packet for %lu\n", + src_addr, packet_dest + ); } else if (trafficMode == TrafficMode::TORNADO) { // Generate a tornado packet packet_dest = scheduler.generateTornadoPacket(src_addr); @@ -354,10 +358,10 @@ Layer::processPackets( // within the connection window // Use the payload value -> RACE LOGIC payload_specific_delay = - ((payload + 1) * getTimeSlot() * clockPeriod() / 714) - + splitterDelay * (packet_dest + 1) * clockPeriod() / 714 - + mergerDelay * (size - src_addr - 1) * clockPeriod() / 714 - + crosspointDelay * clockPeriod() / 714; + ((payload + 1) * getTimeSlot() * clockPeriod()) + + splitterDelay * (packet_dest + 1) * clockPeriod() + + mergerDelay * (size - src_addr - 1) * clockPeriod() + + crosspointDelay * clockPeriod(); @@ -384,6 +388,11 @@ Layer::processPackets( } else if (!fileMode) { // Packet not allowed in the current time slot cell->assignPacket(packet_dest); + // Increment missed packets for the data cell + cell->incrementMissedPackets(); + stats.missedPacketsPerDataCell.sample( + cell->getMissedPackets() + ); DPRINTF(Layer, "DataCell %lu: packet for %lu not scheduled (allowed: %lu)\n", src_addr, packet_dest, allowed_dest @@ -461,7 +470,9 @@ Layer::LayerStats::LayerStats( ADD_STAT(totalWindowsUsed, statistics::units::Count::get(), "Number of connection windows used"), ADD_STAT(pktsPerWindow, statistics::units::Count::get(), - "Distribution of packets per window") + "Distribution of packets per window"), + ADD_STAT(missedPacketsPerDataCell, statistics::units::Count::get(), + "Distribution of missed packets per DataCell") { } @@ -480,6 +491,8 @@ Layer::LayerStats::regStats() .desc("Number of connection windows used"); pktsPerWindow.init(parentLayer->size + 1); + + missedPacketsPerDataCell.init(64); } } // namespace gem5 diff --git a/src/network/layer.hh b/src/network/layer.hh index 8ffe20412d..e4fc7827ef 100644 --- a/src/network/layer.hh +++ b/src/network/layer.hh @@ -117,6 +117,8 @@ private: statistics::Scalar totalWindowsUsed; // Distribution of packets processed per time window statistics::Histogram pktsPerWindow; + // Distribution of missed packets per DataCell + statistics::Histogram missedPacketsPerDataCell; // Constructor that links stats to the Layer instance LayerStats(Layer* layer); From c6cf554125d5f52ac06c785556cf45d689dc2c64 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Tue, 15 Apr 2025 17:24:56 -0700 Subject: [PATCH 27/47] misc: Small change in SConscript Apostrophe style changed for consistency --- src/network/SConscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/SConscript b/src/network/SConscript index bcacb6ba53..a10e7be865 100644 --- a/src/network/SConscript +++ b/src/network/SConscript @@ -7,7 +7,7 @@ SimObject("Layer.py", sim_objects=["Layer"]) Source("data_cell.cc") Source("super_network.cc") Source("layer.cc") -Source('network_scheduler.cc') +Source("network_scheduler.cc") DebugFlag("SuperNetwork") DebugFlag("DataCell") From 656363363e1751eb857437769362556f00294846 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Tue, 15 Apr 2025 17:48:33 -0700 Subject: [PATCH 28/47] misc: Move data generation to scheduler Random payload generation within range of values possible --- src/network/data_cell.cc | 15 --------------- src/network/data_cell.hh | 9 --------- src/network/layer.cc | 16 ++++++++-------- src/network/network_scheduler.cc | 17 +++++++++++++++-- src/network/network_scheduler.hh | 8 +++++++- 5 files changed, 30 insertions(+), 35 deletions(-) diff --git a/src/network/data_cell.cc b/src/network/data_cell.cc index e861bc15a5..38cfb51296 100644 --- a/src/network/data_cell.cc +++ b/src/network/data_cell.cc @@ -40,25 +40,10 @@ namespace gem5 // Initializes the cell with default values DataCell::DataCell(const DataCellParams& params) : ClockedObject(params), - data(0), // Initialize data to 0 addr(0) // Initialize address to 0 { } -// Sets the data value in the cell -void -DataCell::setData(uint64_t data) -{ - this->data = data; -} - -// Retrieves the current data value in the cell -uint64_t -DataCell::getData() -{ - return data; -} - // Sets the address of the cell void DataCell::setAddr(uint64_t addr) diff --git a/src/network/data_cell.hh b/src/network/data_cell.hh index 32d79cb502..04cc97996a 100644 --- a/src/network/data_cell.hh +++ b/src/network/data_cell.hh @@ -43,9 +43,6 @@ namespace gem5 class DataCell : public ClockedObject { private: - // The data value stored in the cell - uint64_t data; - // The address identifier of the cell uint64_t addr; @@ -62,12 +59,6 @@ class DataCell : public ClockedObject // Constructor: Initializes the DataCell with parameters DataCell(const DataCellParams& params); - // Sets the data value in the cell - void setData(uint64_t data); - - // Retrieves the current data value - uint64_t getData(); - // Sets the address of the cell void setAddr(uint64_t addr); diff --git a/src/network/layer.cc b/src/network/layer.cc index 4c936ff88f..60082113ba 100644 --- a/src/network/layer.cc +++ b/src/network/layer.cc @@ -51,7 +51,11 @@ Layer::Layer(const LayerParams& params) : ClockedObject(params), maxPackets(params.max_packets), schedulePath(params.schedule_path), - scheduler(params.max_packets, params.schedule_path, params.data_cells), + scheduler(params.max_packets, + params.schedule_path, + params.data_cells, + params.dynamic_range + ), dynamicRange(params.dynamic_range), crosspointDelay(params.crosspoint_delay), mergerDelay(params.merger_delay), @@ -128,12 +132,8 @@ Layer::initializeDataCells(const std::vector& cells) DataCell* cell = cells[i]; cell->setAddr(i); - // Generate random data within the dynamic range - uint64_t random_data = random() % dynamicRange; - cell->setData(random_data); - - DPRINTF(Layer, "DataCell %d: addr=%d, data=%d\n", - i, cell->getAddr(), cell->getData()); + DPRINTF(Layer, "DataCell %d: addr=%d\n", + i, cell->getAddr()); // Add the cell to the network addDataCell(cell); @@ -352,7 +352,7 @@ Layer::processPackets( if (cell->hasPackets()) { cell->getNextPacket(); } - uint64_t payload = cell->getData(); + uint64_t payload = scheduler.generateRandomPayload(); // Calculate precise delivery time // within the connection window diff --git a/src/network/network_scheduler.cc b/src/network/network_scheduler.cc index 2e94e8221a..b17449c0ca 100644 --- a/src/network/network_scheduler.cc +++ b/src/network/network_scheduler.cc @@ -40,12 +40,14 @@ namespace gem5 { NetworkScheduler::NetworkScheduler( uint64_t max_packets, const std::string& schedule_path, - const std::vector& cells + const std::vector& cells, + uint64_t dynamic_range ) : maxPackets(max_packets), schedulePath(schedule_path), dataCells(cells), - infiniteMode(max_packets == static_cast(-1)) + infiniteMode(max_packets == static_cast(-1)), + dynamicRange(dynamic_range) {} // Initializes the scheduler by either generating or loading a schedule @@ -64,6 +66,17 @@ NetworkScheduler::initialize() return scheduleQueue; } +uint64_t +NetworkScheduler::generateRandomPayload() { + // Create a random number generator. In production code, consider + // keeping a persistent generator for reproducibility. + static std::random_device rd; + static std::mt19937 gen(rd()); + std::uniform_int_distribution dist(0, dynamicRange - 1); + return dist(gen); +} + + // Generates a random packet using the given src. // It picks a random destination from dataCells. uint64_t diff --git a/src/network/network_scheduler.hh b/src/network/network_scheduler.hh index 91cb39b580..9ec8582e39 100644 --- a/src/network/network_scheduler.hh +++ b/src/network/network_scheduler.hh @@ -49,7 +49,8 @@ public: // Constructor that initializes the scheduler NetworkScheduler(uint64_t maxPackets, const std::string& schedulePath, - const std::vector& cells + const std::vector& cells, + uint64_t dynamic_range ); // Initializes the scheduler @@ -69,6 +70,9 @@ public: double hotspot_fraction ); + // Generates a random payload + uint64_t generateRandomPayload(); + // Saves the current schedule to a specified file void saveSchedule(); @@ -101,6 +105,8 @@ private: const std::vector& dataCells; // Scheduled packets (source-destination pairs) std::queue> scheduleQueue; + // Dynamic range of the layer + uint64_t dynamicRange; }; } // namespace gem5 From e562b2d911e92a686630a747b6f0a385731099fd Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Tue, 15 Apr 2025 23:53:38 -0700 Subject: [PATCH 29/47] misc: Add shuffling to all-to-all traffic --- configs/supernetwork/SRNoC.py | 7 +++++++ src/network/Layer.py | 1 + src/network/layer.cc | 29 +++++++++++++++++++++++++---- src/network/layer.hh | 3 +++ 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/configs/supernetwork/SRNoC.py b/configs/supernetwork/SRNoC.py index 059d1dcae7..34cb3c2313 100644 --- a/configs/supernetwork/SRNoC.py +++ b/configs/supernetwork/SRNoC.py @@ -170,6 +170,11 @@ def parse_arguments(): all_to_all_parser = subparsers.add_parser( "all-to-all", parents=[shared_parser], help="All-to-all traffic mode" ) + all_to_all_parser.add_argument( + "--shuffle", + action="store_true", + help="Shuffle the destinations for all-to-all mode", + ) tornado_parser = subparsers.add_parser( "tornado", parents=[shared_parser], help="Tornado traffic mode" @@ -272,6 +277,8 @@ def main(): ) elif args.traffic_mode == "all-to-all": for layer in layers: + if args.shuffle: + layer.setShuffle() layer.setAllToAllTrafficMode() elif args.traffic_mode == "random": for layer in layers: diff --git a/src/network/Layer.py b/src/network/Layer.py index d81dc03c7d..30d35d1ef3 100644 --- a/src/network/Layer.py +++ b/src/network/Layer.py @@ -66,4 +66,5 @@ class Layer(ClockedObject): PyBindMethod("setHotspotTrafficMode"), PyBindMethod("setAllToAllTrafficMode"), PyBindMethod("setTornadoTrafficMode"), + PyBindMethod("setShuffle"), ] diff --git a/src/network/layer.cc b/src/network/layer.cc index 60082113ba..a3fd681f35 100644 --- a/src/network/layer.cc +++ b/src/network/layer.cc @@ -33,6 +33,7 @@ #include #include #include +#include #include "debug/Layer.hh" #include "network/network_scheduler.hh" @@ -68,6 +69,7 @@ Layer::Layer(const LayerParams& params) : currentTimeSlotIndex(0), isFinished(false), fileMode(false), + shuffleEnabled(false), size(params.data_cells.size()), // Event for processing the next network event nextNetworkEvent([this]{ processNextNetworkEvent(); }, @@ -303,15 +305,34 @@ Layer::processPackets( packet_dest = scheduler.generateHotspotPacket( src_addr, hotspotAddr, hotspotFraction ); - } else if (trafficMode == TrafficMode::ALL_TO_ALL) { + } if (trafficMode == TrafficMode::ALL_TO_ALL) { // Check if the cell already has queued destinations. if (!cell->hasPackets()) { - // For an all-to-all mode, enqueue each destination. + // Create a vector to hold all destination indices. + std::vector destinations; + destinations.reserve(size); for (uint64_t dest = 0; dest < size; dest++) { + destinations.push_back(dest); + } + + // Conditionally shuffle the vector + if (shuffleEnabled) { + // Create a random number generator. + std::random_device rd; + std::mt19937 g(rd()); + // Shuffle the destinations. + std::shuffle(destinations.begin(), + destinations.end(), g + ); + } + + // Enqueue each destination from the vector. + // vector can be shuffled or not + for (auto dest : destinations) { cell->assignPacket(dest); DPRINTF(Layer, - "DataCell %lu: enqueued " - "all-to-all packet for destination %lu\n", + "DataCell %lu: enqueued all-to-all " + "packet for destination %lu\n", src_addr, dest ); } diff --git a/src/network/layer.hh b/src/network/layer.hh index e4fc7827ef..1e43f5fd0f 100644 --- a/src/network/layer.hh +++ b/src/network/layer.hh @@ -76,6 +76,7 @@ private: int size; // Size of the network bool isFinished; // Flag to indicate if the layer has finished bool fileMode; // Flag to indicate if a file is used for scheduling + bool shuffleEnabled; // Flag to indicate if shuffling is enabled std::string schedulePath; // Path to the schedule file NetworkScheduler scheduler; // Scheduler for the network SuperNetwork* superNetwork; // Pointer to the super network @@ -188,6 +189,8 @@ public: this->hotspotFraction = hotspotFraction; trafficMode = TrafficMode::HOTSPOT; } + + void setShuffle() { shuffleEnabled = true; } }; } // namespace gem5 From 1bd8267423e9af3750f33b717849000e519eea82 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Wed, 16 Apr 2025 16:53:56 -0700 Subject: [PATCH 30/47] misc: Update SRNoC params Dynamic range updated to RL Time Slots to reflect paper semantics Also, RL Time Slots also dictate maximum packets sent in a window, implemented that behavior --- configs/supernetwork/SRNoC.py | 17 +++++++++++------ src/network/Layer.py | 2 +- src/network/layer.cc | 20 +++++++++++--------- src/network/layer.hh | 14 ++++++++++++-- 4 files changed, 35 insertions(+), 18 deletions(-) diff --git a/configs/supernetwork/SRNoC.py b/configs/supernetwork/SRNoC.py index 34cb3c2313..381a6c4639 100644 --- a/configs/supernetwork/SRNoC.py +++ b/configs/supernetwork/SRNoC.py @@ -116,6 +116,11 @@ def calculate_power_and_area(radix): + num_mergers * ComponentJJ.MERGER.value ) + print(num_counting_networks * counting_network_jj) + print(num_crosspoints * ComponentJJ.CROSSPOINT.value) + print(num_splitters * ComponentJJ.SPLITTER.value) + print(num_mergers * ComponentJJ.MERGER.value) + # Log and store power and area statistics print(f"Active power: {active_power:.6f} W") print(f"Static power: {static_power:.6f} W") @@ -136,11 +141,11 @@ def create_shared_parser(): """ shared_parser = argparse.ArgumentParser(add_help=False) shared_parser.add_argument( - "--dynamic-range", + "--num-rl-time-slots", type=int, nargs="+", required=True, - help="Dynamic range settings", + help="Number of time slots per connection window", ) return shared_parser @@ -226,10 +231,10 @@ def main(): else: schedule_path = args.file_path - # Create Layers for each dynamic range. + # Create Layers layers = [ Layer( - dynamic_range=dr, + rl_time_slots=rl, data_cells=data_cells, max_packets=args.maximum_packets, schedule_path=schedule_path, @@ -241,7 +246,7 @@ def main(): crosspoint_setup_time=NetworkDelays.CROSSPOINT_SETUP_TIME.value, hold_time=NetworkDelays.CROSSPOINT_HOLD_TIME.value, ) - for dr in args.dynamic_range + for rl in args.num_rl_time_slots ] # Create the SuperNetwork and add the layers. @@ -253,7 +258,7 @@ def main(): print("SRNoC Test Configuration") print("==============================") print(f"Number of DataCells: {num_cells}") - print(f"Dynamic Range: {args.dynamic_range}") + print(f"RL Time Slots: {args.num_rl_time_slots}") print() print("Power and Area Statistics") print("==============================") diff --git a/src/network/Layer.py b/src/network/Layer.py index 30d35d1ef3..32ebfc5101 100644 --- a/src/network/Layer.py +++ b/src/network/Layer.py @@ -37,7 +37,7 @@ class Layer(ClockedObject): # Vector of data cells in the network data_cells = VectorParam.DataCell("Data cells in the layer") - dynamic_range = Param.UInt64("Range size of the layer (dynamic range)") + rl_time_slots = Param.UInt64("Number of time slots per connection window") # max_packets: 0 means not provided max_packets = Param.Int( diff --git a/src/network/layer.cc b/src/network/layer.cc index a3fd681f35..be333e4844 100644 --- a/src/network/layer.cc +++ b/src/network/layer.cc @@ -52,12 +52,14 @@ Layer::Layer(const LayerParams& params) : ClockedObject(params), maxPackets(params.max_packets), schedulePath(params.schedule_path), + rlTimeSlots(params.rl_time_slots), + maxPacketsPerWindow(std::floor(params.rl_time_slots - + (params.rl_time_slots / std::exp(1.0)))), scheduler(params.max_packets, params.schedule_path, params.data_cells, - params.dynamic_range + params.rl_time_slots ), - dynamicRange(params.dynamic_range), crosspointDelay(params.crosspoint_delay), mergerDelay(params.merger_delay), splitterDelay(params.splitter_delay), @@ -153,14 +155,8 @@ Layer::computeTimingParameters() getTimeSlot() * clockPeriod() ); - // dynamic range increases due to circuit variability - // and the number of data cells - double expected_packets = std::round( - (dynamicRange * std::exp(1.0)) / (std::exp(1.0) - 1.0) - ); - // Calculate and assign the connection window - setConnectionWindow(Cycles(expected_packets * getTimeSlot())); + setConnectionWindow(Cycles(rlTimeSlots * getTimeSlot())); DPRINTF(Layer, "Connection window: %d Cycles\n", getConnectionWindow() ); @@ -283,6 +279,12 @@ Layer::processPackets( // Iterate through all data cells for (DataCell* cell : dataCells) { + if (packets_processed_this_window >= maxPacketsPerWindow) { + DPRINTF(Layer, + "Window %lu: reached max packets (%lu), stopping.\n", + currentTimeSlotIndex, maxPacketsPerWindow); + break; + } // Check if we've already reached the maximum packets if (packetsDelivered >= maxPackets && !infinite_mode) { break; // Exit the loop immediately if we've reached max packets diff --git a/src/network/layer.hh b/src/network/layer.hh index 1e43f5fd0f..d82d28c0f8 100644 --- a/src/network/layer.hh +++ b/src/network/layer.hh @@ -66,8 +66,9 @@ private: double holdTime; // Network configuration parameters - uint64_t dynamicRange; // The dynamic range of the network + uint64_t maxPacketsPerWindow; // Maximum packets per window uint64_t radix; // Radix for the network, used in the topology + uint64_t rlTimeSlots; // Number of time slots per connection win. Cycles timeSlot; // Time slot for scheduling packets Cycles connectionWindow; // Connection window uint64_t currentTimeSlotIndex; // Current index for the time slot @@ -143,7 +144,16 @@ public: void addDataCell(DataCell* dataCell); DataCell* getDataCell(uint64_t addr); - uint64_t getDynamicRange() const { return dynamicRange; } + // Methods for getting certain network parameters + uint64_t getMaximumPacketsPerWindow() const + { + return maxPacketsPerWindow; + } + + uint64_t getRLTimeSlots() const + { + return rlTimeSlots; + } // Methods for assigning and retrieving radix, // time slot, and connection window values From 0495bcc3b5c0248a33ae2912cd0051bacc033048 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Wed, 16 Apr 2025 23:01:39 -0700 Subject: [PATCH 31/47] misc: Refactor out # of RL Time Slots as configurable Parameters like delays of components like crosspoint, splitter, merger, etc. are configurable. The above decide the length of a time slot. According to the paper, 8 time slots of 92 ps, make the frequency of the network 1.4 GHz. This makes sense, as 736 ps time period is roughly 1.4 GHz. So, given configurable frequencies, the Layer computes the max range of values and the max packets sent per window. Multiple frequencies can be defined to make multiple Layers. --- configs/supernetwork/SRNoC.py | 13 ++++-- src/network/Layer.py | 2 - src/network/layer.cc | 80 ++++++++++++++++++-------------- src/network/layer.hh | 10 ++-- src/network/network_scheduler.cc | 13 ++---- src/network/network_scheduler.hh | 5 +- 6 files changed, 64 insertions(+), 59 deletions(-) diff --git a/configs/supernetwork/SRNoC.py b/configs/supernetwork/SRNoC.py index 381a6c4639..6d9f096b0e 100644 --- a/configs/supernetwork/SRNoC.py +++ b/configs/supernetwork/SRNoC.py @@ -141,8 +141,8 @@ def create_shared_parser(): """ shared_parser = argparse.ArgumentParser(add_help=False) shared_parser.add_argument( - "--num-rl-time-slots", - type=int, + "--frequencies-per-layer", + type=str, nargs="+", required=True, help="Number of time slots per connection window", @@ -234,7 +234,6 @@ def main(): # Create Layers layers = [ Layer( - rl_time_slots=rl, data_cells=data_cells, max_packets=args.maximum_packets, schedule_path=schedule_path, @@ -245,8 +244,12 @@ def main(): variability_counting_network=NetworkDelays.VARIABILITY_COUNTING_NETWORK.value, crosspoint_setup_time=NetworkDelays.CROSSPOINT_SETUP_TIME.value, hold_time=NetworkDelays.CROSSPOINT_HOLD_TIME.value, + clk_domain=SrcClockDomain( + clock=frequency, + voltage_domain=VoltageDomain(), + ), ) - for rl in args.num_rl_time_slots + for frequency in args.frequencies_per_layer ] # Create the SuperNetwork and add the layers. @@ -258,7 +261,7 @@ def main(): print("SRNoC Test Configuration") print("==============================") print(f"Number of DataCells: {num_cells}") - print(f"RL Time Slots: {args.num_rl_time_slots}") + print(f"Frequencies per Layer: {args.frequencies_per_layer}") print() print("Power and Area Statistics") print("==============================") diff --git a/src/network/Layer.py b/src/network/Layer.py index 32ebfc5101..be3f1ffefb 100644 --- a/src/network/Layer.py +++ b/src/network/Layer.py @@ -37,8 +37,6 @@ class Layer(ClockedObject): # Vector of data cells in the network data_cells = VectorParam.DataCell("Data cells in the layer") - rl_time_slots = Param.UInt64("Number of time slots per connection window") - # max_packets: 0 means not provided max_packets = Param.Int( -1, "Maximum number of packets to schedule; -1 means infinite" diff --git a/src/network/layer.cc b/src/network/layer.cc index be333e4844..b2612eeb6c 100644 --- a/src/network/layer.cc +++ b/src/network/layer.cc @@ -52,13 +52,9 @@ Layer::Layer(const LayerParams& params) : ClockedObject(params), maxPackets(params.max_packets), schedulePath(params.schedule_path), - rlTimeSlots(params.rl_time_slots), - maxPacketsPerWindow(std::floor(params.rl_time_slots - - (params.rl_time_slots / std::exp(1.0)))), scheduler(params.max_packets, params.schedule_path, - params.data_cells, - params.rl_time_slots + params.data_cells ), crosspointDelay(params.crosspoint_delay), mergerDelay(params.merger_delay), @@ -111,12 +107,6 @@ Layer::Layer(const LayerParams& params) : schedule_queue.pop(); } } - - // Compute network parameters like time slot and connection window - // computeNetworkParameters(); - - // // Schedule the initial network event - // scheduleNextNetworkEvent(curTick()); } // Initialize data cells with random data and unique addresses @@ -150,18 +140,40 @@ Layer::computeTimingParameters() { // Calculate and assign the time slot assignTimeSlot(); - DPRINTF(Layer, "Time slot: %d Cycles\n", getTimeSlot()); DPRINTF(Layer, "Time slot: %d ps\n", - getTimeSlot() * clockPeriod() + getTimeSlot() ); - // Calculate and assign the connection window - setConnectionWindow(Cycles(rlTimeSlots * getTimeSlot())); - DPRINTF(Layer, "Connection window: %d Cycles\n", - getConnectionWindow() + DPRINTF(Layer, + "Clock period: %lu\n", + clockPeriod() + ); + + // Calculate the number of time slots possible + // given the clock period and time slot duration + // Round up to the nearest whole number + rlTimeSlots = std::ceil( + static_cast(clockPeriod()) / getTimeSlot() + ); + + // We can only use a fraction of the time slots + maxPacketsPerWindow = std::floor(rlTimeSlots - + (rlTimeSlots / std::exp(1.0))); + + DPRINTF(Layer, + "RL Time slots: %lu\n", + rlTimeSlots ); + + DPRINTF(Layer, + "Max packets per window: %lu\n", + maxPacketsPerWindow + ); + + // Calculate and assign the connection window + setConnectionWindow(rlTimeSlots * getTimeSlot()); DPRINTF(Layer, "Connection window: %d ps\n", - getConnectionWindow() * clockPeriod() + getConnectionWindow() ); } @@ -175,15 +187,15 @@ Layer::assignTimeSlot() ); // Calculate time slot considering delays of various network components - double calculated_time_slot = circuitVariability * ( + double calculated_time_slot = std::ceil(circuitVariability * ( crosspointDelay + se_adjusted + splitterDelay * (radix - 1) + mergerDelay * (radix - 1) + variabilityCountingNetwork - ); + ) + crosspointSetupTime); // Round up the calculated time slot - this->timeSlot = Cycles(std::ceil(calculated_time_slot)); + this->timeSlot = calculated_time_slot; } // Add a data cell to the network's data cell collection @@ -223,25 +235,19 @@ Layer::processNextNetworkEvent() processPackets(static_schedule, packets_processed_this_window); }, "processPacketsEvent"), - curTick() + holdTime * clockPeriod()); + curTick() + holdTime); stats.totalWindowsUsed++; // Advance the time slot for the next event - // Add scheduled setup time - // currentTimeSlotIndex++; - schedule(new EventFunctionWrapper( - [this]() { - currentTimeSlotIndex++; - }, "advanceTimeSlotEvent"), - curTick() + crosspointSetupTime * clockPeriod()); + currentTimeSlotIndex++; // Schedule next network event. // In infinite mode (maxPackets == -1) we always schedule the next event. if (maxPackets == static_cast(-1) || packetsDelivered < maxPackets) { scheduleNextNetworkEvent(curTick() + - ((connectionWindow + crosspointSetupTime) * clockPeriod())); + ((connectionWindow))); } } @@ -307,7 +313,7 @@ Layer::processPackets( packet_dest = scheduler.generateHotspotPacket( src_addr, hotspotAddr, hotspotFraction ); - } if (trafficMode == TrafficMode::ALL_TO_ALL) { + } else if (trafficMode == TrafficMode::ALL_TO_ALL) { // Check if the cell already has queued destinations. if (!cell->hasPackets()) { // Create a vector to hold all destination indices. @@ -375,16 +381,18 @@ Layer::processPackets( if (cell->hasPackets()) { cell->getNextPacket(); } - uint64_t payload = scheduler.generateRandomPayload(); + uint64_t payload = scheduler.generateRandomPayload( + rlTimeSlots + ); // Calculate precise delivery time // within the connection window // Use the payload value -> RACE LOGIC payload_specific_delay = - ((payload + 1) * getTimeSlot() * clockPeriod()) - + splitterDelay * (packet_dest + 1) * clockPeriod() - + mergerDelay * (size - src_addr - 1) * clockPeriod() - + crosspointDelay * clockPeriod(); + ((payload + 1) * getTimeSlot()) + + splitterDelay * (packet_dest + 1) + + mergerDelay * (size - src_addr - 1) + + crosspointDelay; diff --git a/src/network/layer.hh b/src/network/layer.hh index d82d28c0f8..7ed7c7c1db 100644 --- a/src/network/layer.hh +++ b/src/network/layer.hh @@ -69,8 +69,8 @@ private: uint64_t maxPacketsPerWindow; // Maximum packets per window uint64_t radix; // Radix for the network, used in the topology uint64_t rlTimeSlots; // Number of time slots per connection win. - Cycles timeSlot; // Time slot for scheduling packets - Cycles connectionWindow; // Connection window + uint64_t timeSlot; // Time slot for scheduling packets + uint64_t connectionWindow; // Connection window uint64_t currentTimeSlotIndex; // Current index for the time slot int maxPackets; // Maximum number of packets, -1 means no limit int packetsDelivered; // Number of packet deliveries @@ -160,10 +160,10 @@ public: void setRadix(uint64_t radix) { this->radix = radix; } uint64_t getRadix() const { return radix; } - Cycles getTimeSlot() const { return timeSlot; } - void setTimeSlot(Cycles timeSlot) { this->timeSlot = timeSlot; } + uint64_t getTimeSlot() const { return timeSlot; } + void setTimeSlot(uint64_t timeSlot) { this->timeSlot = timeSlot; } - void setConnectionWindow(Cycles window) { connectionWindow = window; } + void setConnectionWindow(uint64_t window) { connectionWindow = window; } int getConnectionWindow() const { return connectionWindow; } void scheduleNextNetworkEvent(Tick when); // Schedules the next event diff --git a/src/network/network_scheduler.cc b/src/network/network_scheduler.cc index b17449c0ca..b84c02cee8 100644 --- a/src/network/network_scheduler.cc +++ b/src/network/network_scheduler.cc @@ -40,14 +40,12 @@ namespace gem5 { NetworkScheduler::NetworkScheduler( uint64_t max_packets, const std::string& schedule_path, - const std::vector& cells, - uint64_t dynamic_range + const std::vector& cells ) : maxPackets(max_packets), schedulePath(schedule_path), dataCells(cells), - infiniteMode(max_packets == static_cast(-1)), - dynamicRange(dynamic_range) + infiniteMode(max_packets == static_cast(-1)) {} // Initializes the scheduler by either generating or loading a schedule @@ -67,12 +65,11 @@ NetworkScheduler::initialize() } uint64_t -NetworkScheduler::generateRandomPayload() { - // Create a random number generator. In production code, consider - // keeping a persistent generator for reproducibility. +NetworkScheduler::generateRandomPayload(uint64_t dynamic_range) { + // Create a random number generator. static std::random_device rd; static std::mt19937 gen(rd()); - std::uniform_int_distribution dist(0, dynamicRange - 1); + std::uniform_int_distribution dist(0, dynamic_range - 1); return dist(gen); } diff --git a/src/network/network_scheduler.hh b/src/network/network_scheduler.hh index 9ec8582e39..9e8c7f773c 100644 --- a/src/network/network_scheduler.hh +++ b/src/network/network_scheduler.hh @@ -49,8 +49,7 @@ public: // Constructor that initializes the scheduler NetworkScheduler(uint64_t maxPackets, const std::string& schedulePath, - const std::vector& cells, - uint64_t dynamic_range + const std::vector& cells ); // Initializes the scheduler @@ -71,7 +70,7 @@ public: ); // Generates a random payload - uint64_t generateRandomPayload(); + uint64_t generateRandomPayload(uint64_t dynamic_range); // Saves the current schedule to a specified file void saveSchedule(); From b86fc789c610464b8675854522822b9190686a5c Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Wed, 16 Apr 2025 23:51:08 -0700 Subject: [PATCH 32/47] misc: Rename DataCell to BufferedPort DataCell is no longer an accurate name, since data is generated by the scheduler. --- configs/supernetwork/SRNoC.py | 14 +- src/network/{DataCell.py => BufferedPort.py} | 8 +- src/network/Layer.py | 4 +- src/network/SConscript | 6 +- .../{data_cell.cc => buffered_port.cc} | 43 +++--- .../{data_cell.hh => buffered_port.hh} | 33 ++-- src/network/layer.cc | 143 +++++++++--------- src/network/layer.hh | 22 +-- src/network/network_scheduler.cc | 43 +++--- src/network/network_scheduler.hh | 14 +- src/network/super_network.hh | 2 +- 11 files changed, 170 insertions(+), 162 deletions(-) rename src/network/{DataCell.py => BufferedPort.py} (92%) rename src/network/{data_cell.cc => buffered_port.cc} (75%) rename src/network/{data_cell.hh => buffered_port.hh} (79%) diff --git a/configs/supernetwork/SRNoC.py b/configs/supernetwork/SRNoC.py index 6d9f096b0e..786b60901b 100644 --- a/configs/supernetwork/SRNoC.py +++ b/configs/supernetwork/SRNoC.py @@ -153,7 +153,7 @@ def create_shared_parser(): def create_base_parser(): parser = argparse.ArgumentParser(description="SuperNetwork Simulation") parser.add_argument( - "--num-cells", type=int, default=10, help="Number of DataCells" + "--num-ports", type=int, default=10, help="Number of BufferedPorts" ) parser.add_argument( "--maximum-packets", type=int, default=0, help="Maximum packets" @@ -222,9 +222,9 @@ def main(): root.system.clk_domain.clock = "1.4GHz" root.system.clk_domain.voltage_domain = VoltageDomain() - # Create the DataCells. - num_cells = args.num_cells - data_cells = [DataCell() for _ in range(num_cells)] + # Create the BufferedPorts. + num_ports = args.num_ports + buffered_ports = [BufferedPort() for _ in range(num_ports)] if args.traffic_mode != "file": schedule_path = "" # Force schedule_path to be empty if not using file-based traffic mode. @@ -234,7 +234,7 @@ def main(): # Create Layers layers = [ Layer( - data_cells=data_cells, + buffered_ports=buffered_ports, max_packets=args.maximum_packets, schedule_path=schedule_path, crosspoint_delay=NetworkDelays.CROSSPOINT_DELAY.value, @@ -260,12 +260,12 @@ def main(): # Print test configuration. print("SRNoC Test Configuration") print("==============================") - print(f"Number of DataCells: {num_cells}") + print(f"Number of BufferedPort: {num_ports}") print(f"Frequencies per Layer: {args.frequencies_per_layer}") print() print("Power and Area Statistics") print("==============================") - power_and_area = calculate_power_and_area(radix=(num_cells * 2)) + power_and_area = calculate_power_and_area(radix=(num_ports * 2)) print() if args.maximum_packets: diff --git a/src/network/DataCell.py b/src/network/BufferedPort.py similarity index 92% rename from src/network/DataCell.py rename to src/network/BufferedPort.py index 081044e80b..12615839d4 100644 --- a/src/network/DataCell.py +++ b/src/network/BufferedPort.py @@ -29,7 +29,7 @@ from m5.proxy import * -class DataCell(ClockedObject): - type = "DataCell" - cxx_header = "network/data_cell.hh" - cxx_class = "gem5::DataCell" +class BufferedPort(ClockedObject): + type = "BufferedPort" + cxx_header = "network/buffered_port.hh" + cxx_class = "gem5::BufferedPort" diff --git a/src/network/Layer.py b/src/network/Layer.py index be3f1ffefb..4396463c4e 100644 --- a/src/network/Layer.py +++ b/src/network/Layer.py @@ -34,8 +34,8 @@ class Layer(ClockedObject): cxx_header = "network/layer.hh" cxx_class = "gem5::Layer" - # Vector of data cells in the network - data_cells = VectorParam.DataCell("Data cells in the layer") + # Vector of ports in the network + buffered_ports = VectorParam.BufferedPort("I/O ports in the network") # max_packets: 0 means not provided max_packets = Param.Int( diff --git a/src/network/SConscript b/src/network/SConscript index a10e7be865..cee7b44a8e 100644 --- a/src/network/SConscript +++ b/src/network/SConscript @@ -1,15 +1,15 @@ Import("*") -SimObject("DataCell.py", sim_objects=["DataCell"]) +SimObject("BufferedPort.py", sim_objects=["BufferedPort"]) SimObject("SuperNetwork.py", sim_objects=["SuperNetwork"]) SimObject("Layer.py", sim_objects=["Layer"]) -Source("data_cell.cc") +Source("buffered_port.cc") Source("super_network.cc") Source("layer.cc") Source("network_scheduler.cc") DebugFlag("SuperNetwork") -DebugFlag("DataCell") +DebugFlag("BufferedPort") DebugFlag("NetworkScheduler") DebugFlag("Layer") diff --git a/src/network/data_cell.cc b/src/network/buffered_port.cc similarity index 75% rename from src/network/data_cell.cc rename to src/network/buffered_port.cc index 38cfb51296..9375516cda 100644 --- a/src/network/data_cell.cc +++ b/src/network/buffered_port.cc @@ -26,9 +26,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "network/data_cell.hh" +#include "network/buffered_port.hh" -#include "debug/DataCell.hh" +#include "debug/BufferedPort.hh" #include "sim/sim_exit.hh" #include "sim/stats.hh" #include "sim/system.hh" @@ -36,41 +36,44 @@ namespace gem5 { -// Constructor for DataCell class -// Initializes the cell with default values -DataCell::DataCell(const DataCellParams& params) : +// Constructor for BufferedPort class +// Initializes the port with default values +BufferedPort::BufferedPort(const BufferedPortParams& params) : ClockedObject(params), addr(0) // Initialize address to 0 { } -// Sets the address of the cell +// Sets the address of the port void -DataCell::setAddr(uint64_t addr) +BufferedPort::setAddr(uint64_t addr) { this->addr = addr; } -// Retrieves the address of the cell +// Retrieves the address of the port uint64_t -DataCell::getAddr() +BufferedPort::getAddr() { return addr; } -// Assigns a packet to the cell by pushing the dest address into queue +// Assigns a packet to the port by pushing the dest address into queue void -DataCell::assignPacket(uint64_t dest_addr) +BufferedPort::assignPacket(uint64_t dest_addr) { packetQueue.push(dest_addr); // Queue the dest - DPRINTF(DataCell, "DataCell %d assigned packet to destination %d\n", - addr, dest_addr); + DPRINTF(BufferedPort, + "BufferedPort %d assigned packet " + "to destination %d\n", + addr, dest_addr + ); } // Retrieves and removes the next packet from the queue // Returns 0 if no packets are available uint64_t -DataCell::getNextPacket() +BufferedPort::getNextPacket() { if (!packetQueue.empty()) { // Get the next packet and remove it from the queue @@ -83,26 +86,26 @@ DataCell::getNextPacket() // Checks if there are any packets in the queue bool -DataCell::hasPackets() const +BufferedPort::hasPackets() const { return !packetQueue.empty(); } // Increments the missed packet count void -DataCell::incrementMissedPackets() +BufferedPort::incrementMissedPackets() { missedPackets++; - DPRINTF(DataCell, "DataCell %d missed packets: %d\n", + DPRINTF(BufferedPort, "BufferedPort %d missed packets: %d\n", addr, missedPackets ); } // Handles receiving data by updating the last received values and stats void -DataCell::receiveData(uint64_t received_data, uint64_t src_addr) +BufferedPort::receiveData(uint64_t received_data, uint64_t src_addr) { - DPRINTF(DataCell, "DataCell %d received data %d from source %d\n", + DPRINTF(BufferedPort, "BufferedPort %d received data %d from source %d\n", addr, received_data, src_addr); lastReceivedData = received_data; // Store the last received data @@ -112,7 +115,7 @@ DataCell::receiveData(uint64_t received_data, uint64_t src_addr) // Returns the next packet without removing it from the queue // Returns -1 if no packets are available uint64_t -DataCell::peekNextPacket() const +BufferedPort::peekNextPacket() const { if (!packetQueue.empty()) { return packetQueue.front(); diff --git a/src/network/data_cell.hh b/src/network/buffered_port.hh similarity index 79% rename from src/network/data_cell.hh rename to src/network/buffered_port.hh index 04cc97996a..0885f4f714 100644 --- a/src/network/data_cell.hh +++ b/src/network/buffered_port.hh @@ -26,27 +26,28 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __NETWORK_DATACELL_HH__ -#define __NETWORK_DATACELL_HH__ +#ifndef __NETWORK_BUFFEREDPORT_HH__ +#define __NETWORK_BUFFEREDPORT_HH__ #include -#include "params/DataCell.hh" +#include "params/BufferedPort.hh" #include "sim/clocked_object.hh" namespace gem5 { -// The DataCell class represents a single node in the network responsible for -// storing, sending, and receiving packets. It tracks its data, address, -// and maintains statistics for sent and received packets. -class DataCell : public ClockedObject +// The BufferedPort class represents a single node in the network +// responsible for storing, sending, and receiving packets. +// It tracks its data, address, and maintains statistics for +// sent and received packets. +class BufferedPort : public ClockedObject { private: - // The address identifier of the cell + // The address identifier of the port uint64_t addr; - // Queue to hold packets (destination addresses) assigned to the cell + // Queue to hold packets (destination addresses) assigned to the port std::queue packetQueue; // Variables to store the most recent received data and source addr @@ -56,26 +57,26 @@ class DataCell : public ClockedObject uint64_t missedPackets = 0; // Count of missed packets public: - // Constructor: Initializes the DataCell with parameters - DataCell(const DataCellParams& params); + // Constructor: Initializes the BufferedPort with parameters + BufferedPort(const BufferedPortParams& params); - // Sets the address of the cell + // Sets the address of the port void setAddr(uint64_t addr); - // Retrieves the address of the cell + // Retrieves the address of the port uint64_t getAddr(); // Assigns a packet to the queue with the given destination address void assignPacket(uint64_t dest_addr); - // Receives data from another cell + // Receives data from another port // Stores the received value and source void receiveData(uint64_t received_data, uint64_t src_addr); // Retrieves and removes the next packet from the queue uint64_t getNextPacket(); - // Checks if the cell has any packets in its queue + // Checks if the port has any packets in its queue bool hasPackets() const; // Getters for the last received data and source information @@ -93,4 +94,4 @@ class DataCell : public ClockedObject } // namespace gem5 -#endif // __NETWORK_DATACELL_HH__ +#endif // __NETWORK_BUFFEREDPORT_HH__ diff --git a/src/network/layer.cc b/src/network/layer.cc index b2612eeb6c..3c8088e7c9 100644 --- a/src/network/layer.cc +++ b/src/network/layer.cc @@ -46,7 +46,7 @@ namespace gem5 { // Constructor for the Layer class -// Initializes the network with given parameters, sets up data cells, +// Initializes the network with given parameters, sets up ports, // and prepares for packet scheduling Layer::Layer(const LayerParams& params) : ClockedObject(params), @@ -54,7 +54,7 @@ Layer::Layer(const LayerParams& params) : schedulePath(params.schedule_path), scheduler(params.max_packets, params.schedule_path, - params.data_cells + params.buffered_ports ), crosspointDelay(params.crosspoint_delay), mergerDelay(params.merger_delay), @@ -68,7 +68,7 @@ Layer::Layer(const LayerParams& params) : isFinished(false), fileMode(false), shuffleEnabled(false), - size(params.data_cells.size()), + size(params.buffered_ports.size()), // Event for processing the next network event nextNetworkEvent([this]{ processNextNetworkEvent(); }, name() + ".nextNetworkEvent"), @@ -81,8 +81,8 @@ Layer::Layer(const LayerParams& params) : assert(params.variability_counting_network >= 0); assert(params.crosspoint_setup_time >= 0); - // Initialize data cells with random data - initializeDataCells(params.data_cells); + // Initialize ports + initializeBufferedPorts(params.buffered_ports); // Initialize the network scheduler std::queue> @@ -97,40 +97,40 @@ Layer::Layer(const LayerParams& params) : uint64_t src_addr = entry.first; uint64_t dest_addr = entry.second; - DataCell* cell = getDataCell(src_addr); - if (cell != nullptr) { - cell->assignPacket(dest_addr); + BufferedPort* port = getBufferedPort(src_addr); + if (port != nullptr) { + port->assignPacket(dest_addr); DPRINTF(Layer, - "DataCell %d: addr=%d, packet assigned to %d\n", - src_addr, cell->getAddr(), dest_addr); + "BufferedPort %d: addr=%d, packet assigned to %d\n", + src_addr, port->getAddr(), dest_addr); } schedule_queue.pop(); } } } -// Initialize data cells with random data and unique addresses +// Initialize ports with unique addresses void -Layer::initializeDataCells(const std::vector& cells) +Layer::initializeBufferedPorts(const std::vector& ports) { - // Skip if no data cells are provided - if (cells.empty()) { + // Skip if no ports are provided + if (ports.empty()) { return; } // Set network radix - setRadix(cells.size() * 2); + setRadix(ports.size() * 2); - // Populate data cells with addresses and random data - for (uint64_t i = 0; i < cells.size(); i++) { - DataCell* cell = cells[i]; - cell->setAddr(i); + // Populate ports with addresses + for (uint64_t i = 0; i < ports.size(); i++) { + BufferedPort* port = ports[i]; + port->setAddr(i); - DPRINTF(Layer, "DataCell %d: addr=%d\n", - i, cell->getAddr()); + DPRINTF(Layer, "BufferedPort %d: addr=%d\n", + i, port->getAddr()); - // Add the cell to the network - addDataCell(cell); + // Add the port to the network + addBufferedPort(port); } } @@ -198,21 +198,21 @@ Layer::assignTimeSlot() this->timeSlot = calculated_time_slot; } -// Add a data cell to the network's data cell collection +// Add a port to the network's port collection void -Layer::addDataCell(DataCell* dataCell) +Layer::addBufferedPort(BufferedPort* port) { - dataCells.push_back(dataCell); - uint64_t addr = dataCell->getAddr(); - dataCellMap[addr] = dataCell; + bufferedPorts.push_back(port); + uint64_t addr = port->getAddr(); + bufferedPortsMap[addr] = port; } -// Retrieve a data cell by its address -DataCell* -Layer::getDataCell(uint64_t addr) +// Retrieve a port by its address +BufferedPort* +Layer::getBufferedPort(uint64_t addr) { - auto it = dataCellMap.find(addr); - return (it != dataCellMap.end()) ? it->second : nullptr; + auto it = bufferedPortsMap.find(addr); + return (it != bufferedPortsMap.end()) ? it->second : nullptr; } // Process the next network event in the simulation @@ -257,15 +257,15 @@ Layer::buildStaticSchedule() { std::unordered_map static_schedule; - // Determine allowed destination for each data cell - for (DataCell* cell : dataCells) { - uint64_t src_addr = cell->getAddr(); + // Determine allowed destination for each port + for (BufferedPort* port : bufferedPorts) { + uint64_t src_addr = port->getAddr(); uint64_t allowed_dest = - (src_addr + currentTimeSlotIndex) % dataCells.size(); + (src_addr + currentTimeSlotIndex) % bufferedPorts.size(); static_schedule[src_addr] = allowed_dest; DPRINTF(Layer, - "Window %lu: allowed transmission from DataCell %lu to %lu\n", + "Window %lu: allowed transmission from BufferedPort %lu to %lu\n", currentTimeSlotIndex, src_addr, allowed_dest ); } @@ -283,8 +283,8 @@ Layer::processPackets( // Determine if we are in infinite mode bool infinite_mode = (maxPackets == static_cast(-1)); - // Iterate through all data cells - for (DataCell* cell : dataCells) { + // Iterate through all ports + for (BufferedPort* port : bufferedPorts) { if (packets_processed_this_window >= maxPacketsPerWindow) { DPRINTF(Layer, "Window %lu: reached max packets (%lu), stopping.\n", @@ -296,13 +296,13 @@ Layer::processPackets( break; // Exit the loop immediately if we've reached max packets } - uint64_t src_addr = cell->getAddr(); + uint64_t src_addr = port->getAddr(); uint64_t allowed_dest = static_schedule.at(src_addr); uint64_t packet_dest = -1; // Check if there's already a packet in the buffer first - if (cell->hasPackets()) { - packet_dest = cell->peekNextPacket(); + if (port->hasPackets()) { + packet_dest = port->peekNextPacket(); } else { if (!fileMode) { if (trafficMode == TrafficMode::RANDOM) { @@ -314,8 +314,8 @@ Layer::processPackets( src_addr, hotspotAddr, hotspotFraction ); } else if (trafficMode == TrafficMode::ALL_TO_ALL) { - // Check if the cell already has queued destinations. - if (!cell->hasPackets()) { + // Check if the port already has queued destinations. + if (!port->hasPackets()) { // Create a vector to hold all destination indices. std::vector destinations; destinations.reserve(size); @@ -337,18 +337,18 @@ Layer::processPackets( // Enqueue each destination from the vector. // vector can be shuffled or not for (auto dest : destinations) { - cell->assignPacket(dest); + port->assignPacket(dest); DPRINTF(Layer, - "DataCell %lu: enqueued all-to-all " + "BufferedPort %lu: enqueued all-to-all " "packet for destination %lu\n", src_addr, dest ); } } - // Peek the next destination from the cell’s queue. - packet_dest = cell->peekNextPacket(); + // Peek the next destination from the port's queue. + packet_dest = port->peekNextPacket(); DPRINTF(Layer, - "DataCell %lu: all-to-all packet for %lu\n", + "BufferedPort %lu: all-to-all packet for %lu\n", src_addr, packet_dest ); } else if (trafficMode == TrafficMode::TORNADO) { @@ -359,7 +359,7 @@ Layer::processPackets( fatal("Unknown traffic mode: %d\n", trafficMode); } DPRINTF(Layer, - "DataCell %lu: generated packet for %lu\n", + "BufferedPort %lu: generated packet for %lu\n", src_addr, packet_dest ); // Only generate a new packet if there's nothing in the buffer @@ -368,7 +368,7 @@ Layer::processPackets( // In file mode, don't generate a new packet destination. // Optionally, log that no new packet was generated. DPRINTF(Layer, - "DataCell %lu: file mode active," + "BufferedPort %lu: file mode active," "skipping packet generation\n", src_addr ); @@ -378,8 +378,8 @@ Layer::processPackets( // Check if packet can be sent in the current time slot if (packet_dest == allowed_dest) { // Remove the packet if it was from the buffer - if (cell->hasPackets()) { - cell->getNextPacket(); + if (port->hasPackets()) { + port->getNextPacket(); } uint64_t payload = scheduler.generateRandomPayload( rlTimeSlots @@ -418,18 +418,19 @@ Layer::processPackets( } } else if (!fileMode) { // Packet not allowed in the current time slot - cell->assignPacket(packet_dest); - // Increment missed packets for the data cell - cell->incrementMissedPackets(); - stats.missedPacketsPerDataCell.sample( - cell->getMissedPackets() + port->assignPacket(packet_dest); + // Increment missed packets for the BufferedPort + port->incrementMissedPackets(); + stats.missedPacketsPerBufferedPort.sample( + port->getMissedPackets() ); DPRINTF(Layer, - "DataCell %lu: packet for %lu not scheduled (allowed: %lu)\n", + "BufferedPort %lu: packet for %lu not " + "scheduled (allowed: %lu)\n", src_addr, packet_dest, allowed_dest ); DPRINTF(Layer, - "DataCell %lu: packet for %lu assigned to buffer\n", + "BufferedPort %lu: packet for %lu assigned to buffer\n", src_addr, packet_dest ); } @@ -459,23 +460,23 @@ Layer::processPackets( return infinite_mode ? true : (packetsDelivered < maxPackets); } -// Deliver a packet to its destination data cell +// Deliver a packet to its destination port void Layer::deliverPacket(uint64_t src_addr, uint64_t dest_addr, uint64_t payload) { - // Find the destination data cell - DataCell* dest_cell = getDataCell(dest_addr); - if (dest_cell != nullptr) { - // Receive data at the destination cell - dest_cell->receiveData(payload, src_addr); + // Find the destination port + BufferedPort* dest_port = getBufferedPort(dest_addr); + if (dest_port != nullptr) { + // Receive data at the destination port + dest_port->receiveData(payload, src_addr); DPRINTF(Layer, "Packet delivered: src=%lu, dest=%lu, data=%lu\n", src_addr, dest_addr, payload ); } else { DPRINTF(Layer, - "Error: Destination cell %lu not found\n", + "Error: Destination port %lu not found\n", dest_addr ); } @@ -502,8 +503,8 @@ Layer::LayerStats::LayerStats( "Number of connection windows used"), ADD_STAT(pktsPerWindow, statistics::units::Count::get(), "Distribution of packets per window"), - ADD_STAT(missedPacketsPerDataCell, statistics::units::Count::get(), - "Distribution of missed packets per DataCell") + ADD_STAT(missedPacketsPerBufferedPort, statistics::units::Count::get(), + "Distribution of missed packets per BufferedPort") { } @@ -523,7 +524,7 @@ Layer::LayerStats::regStats() pktsPerWindow.init(parentLayer->size + 1); - missedPacketsPerDataCell.init(64); + missedPacketsPerBufferedPort.init(64); } } // namespace gem5 diff --git a/src/network/layer.hh b/src/network/layer.hh index 7ed7c7c1db..57e0a5e5fd 100644 --- a/src/network/layer.hh +++ b/src/network/layer.hh @@ -36,7 +36,7 @@ #include "base/statistics.hh" #include "base/stats/group.hh" -#include "network/data_cell.hh" +#include "network/buffered_port.hh" #include "network/enums.hh" #include "network/layer.hh" #include "network/network_scheduler.hh" @@ -53,8 +53,8 @@ class SuperNetwork; class Layer : public ClockedObject { private: - std::vector dataCells; // Stores all data cells in the network - std::unordered_map dataCellMap; + std::vector bufferedPorts; // all ports in the network + std::unordered_map bufferedPortsMap; // network delay parameters double crosspointDelay; @@ -87,8 +87,10 @@ private: uint64_t hotspotAddr; // Address of the hotspot double hotspotFraction; // Fraction of packets targeting the hotspot - // Initialization methods to set up data cells - void initializeDataCells(const std::vector& cells); + // Initialization methods to set up buffered ports + void initializeBufferedPorts( + const std::vector& buffered_ports + ); // Method to calculate the time slot based on network parameters void assignTimeSlot(); @@ -119,8 +121,8 @@ private: statistics::Scalar totalWindowsUsed; // Distribution of packets processed per time window statistics::Histogram pktsPerWindow; - // Distribution of missed packets per DataCell - statistics::Histogram missedPacketsPerDataCell; + // Distribution of missed packets per BufferedPort + statistics::Histogram missedPacketsPerBufferedPort; // Constructor that links stats to the Layer instance LayerStats(Layer* layer); @@ -140,9 +142,9 @@ public: // Methods for computing layer timing parameters void computeTimingParameters(); - // Methods for adding and retrieving data cells in the network - void addDataCell(DataCell* dataCell); - DataCell* getDataCell(uint64_t addr); + // Methods for adding and retrieving ports in the network + void addBufferedPort(BufferedPort* buffered_port); + BufferedPort* getBufferedPort(uint64_t addr); // Methods for getting certain network parameters uint64_t getMaximumPacketsPerWindow() const diff --git a/src/network/network_scheduler.cc b/src/network/network_scheduler.cc index b84c02cee8..94dc7f6b25 100644 --- a/src/network/network_scheduler.cc +++ b/src/network/network_scheduler.cc @@ -36,15 +36,15 @@ namespace gem5 { // Constructor for NetworkScheduler // Initializes the scheduler with maximum packets, -// schedule path, and list of DataCells +// schedule path, and list of BufferedPorts NetworkScheduler::NetworkScheduler( uint64_t max_packets, const std::string& schedule_path, - const std::vector& cells + const std::vector& buffered_ports ) : maxPackets(max_packets), schedulePath(schedule_path), - dataCells(cells), + bufferedPorts(buffered_ports), infiniteMode(max_packets == static_cast(-1)) {} @@ -75,12 +75,12 @@ NetworkScheduler::generateRandomPayload(uint64_t dynamic_range) { // Generates a random packet using the given src. -// It picks a random destination from dataCells. +// It picks a random destination from BufferedPorts. uint64_t NetworkScheduler::generateRandomPacket(uint64_t src) { - if (dataCells.empty()) { - warn("No DataCells available for scheduling.\n"); + if (bufferedPorts.empty()) { + warn("No BufferedPorts available for scheduling.\n"); return -1; } @@ -89,35 +89,36 @@ NetworkScheduler::generateRandomPacket(uint64_t src) std::mt19937 gen(rd()); uint64_t dest_addr = src; - if (dataCells.size() > 1) { - int dest_index = gen() % dataCells.size(); - dest_addr = dataCells[dest_index]->getAddr(); + if (bufferedPorts.size() > 1) { + int dest_index = gen() % bufferedPorts.size(); + dest_addr = bufferedPorts[dest_index]->getAddr(); } return dest_addr; } // Generates a tornado packet using the given src. -// It generates a packet targeting the data cell +// It generates a packet targeting the port // roughly halfway around the network. // stresses bisection bandwidth. uint64_t NetworkScheduler::generateTornadoPacket(uint64_t src) { - if (dataCells.empty()) { - warn("No DataCells available for scheduling.\n"); + if (bufferedPorts.empty()) { + warn("No BufferedPorts available for scheduling.\n"); return -1; } // Check if the source address is valid - if (src >= dataCells.size()) { + if (src >= bufferedPorts.size()) { fatal("Invalid source address %lu.\n", src); return -1; } - // Generate a packet targeting the data cell + // Generate a packet targeting the port // roughly halfway around the network. - uint64_t dest_addr = (src + dataCells.size() / 2) % dataCells.size(); + uint64_t dest_addr = (src + bufferedPorts.size() / 2) + % bufferedPorts.size(); return dest_addr; } @@ -133,13 +134,13 @@ NetworkScheduler::generateHotspotPacket( double hotspot_fraction ) { - if (dataCells.empty()) { - warn("No DataCells available for scheduling.\n"); + if (bufferedPorts.empty()) { + warn("No BufferedPorts available for scheduling.\n"); return -1; } // Check if the hotspot address is valid - if (hotspot_addr >= dataCells.size()) { + if (hotspot_addr >= bufferedPorts.size()) { fatal("Invalid hotspot address %lu.\n", hotspot_addr); return -1; } @@ -156,9 +157,9 @@ NetworkScheduler::generateHotspotPacket( // Generate a random packet targeting a random destination. uint64_t destAddr = src; - if (dataCells.size() > 1) { - int destIndex = gen() % dataCells.size(); - destAddr = dataCells[destIndex]->getAddr(); + if (bufferedPorts.size() > 1) { + int destIndex = gen() % bufferedPorts.size(); + destAddr = bufferedPorts[destIndex]->getAddr(); } return destAddr; diff --git a/src/network/network_scheduler.hh b/src/network/network_scheduler.hh index 9e8c7f773c..774dd137ea 100644 --- a/src/network/network_scheduler.hh +++ b/src/network/network_scheduler.hh @@ -38,18 +38,18 @@ #include #include "base/logging.hh" -#include "network/data_cell.hh" +#include "network/buffered_port.hh" namespace gem5 { -// NetworkScheduler class handles scheduling packets between DataCells +// NetworkScheduler class handles scheduling packets between BufferedPorts class NetworkScheduler { public: // Constructor that initializes the scheduler - NetworkScheduler(uint64_t maxPackets, - const std::string& schedulePath, - const std::vector& cells + NetworkScheduler(uint64_t max_packets, + const std::string& schedule_path, + const std::vector& buffered_ports ); // Initializes the scheduler @@ -100,8 +100,8 @@ private: uint64_t maxPackets; // Path to the file where the schedule is saved/loaded std::string schedulePath; - // List of DataCells involved in the network - const std::vector& dataCells; + // List of BufferedPorts involved in the network + const std::vector& bufferedPorts; // Scheduled packets (source-destination pairs) std::queue> scheduleQueue; // Dynamic range of the layer diff --git a/src/network/super_network.hh b/src/network/super_network.hh index 7b337d0c5a..67265a13cd 100644 --- a/src/network/super_network.hh +++ b/src/network/super_network.hh @@ -29,7 +29,7 @@ #ifndef __NETWORK_SUPERNETWORK_HH__ #define __NETWORK_SUPERNETWORK_HH__ -#include "network/data_cell.hh" +#include "network/buffered_port.hh" #include "network/layer.hh" #include "network/network_scheduler.hh" #include "params/SuperNetwork.hh" From 9af8d57760b5411338968d76f75b446cadf8a016 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Thu, 17 Apr 2025 00:08:29 -0700 Subject: [PATCH 33/47] misc: Add some fatals If timeSlot is greater than clockPeriod, fatal because no values can be sent on that Layer --- src/network/layer.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/network/layer.cc b/src/network/layer.cc index 3c8088e7c9..54cb8b3428 100644 --- a/src/network/layer.cc +++ b/src/network/layer.cc @@ -149,6 +149,16 @@ Layer::computeTimingParameters() clockPeriod() ); + if (getTimeSlot() <= 0) { + fatal("Layer %s: Time slot (%lu) must be greater than 0!\n", + name(), getTimeSlot()); + } + if (getTimeSlot() > clockPeriod()) { + fatal("Layer %s: Time slot (%lu) is greater than ", + "clock period (%lu)!\n", + name(), getTimeSlot(), clockPeriod()); + } + // Calculate the number of time slots possible // given the clock period and time slot duration // Round up to the nearest whole number From 5fdfc19943e365bf2aa8919c080fdf60de771fd1 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Thu, 17 Apr 2025 21:09:53 -0700 Subject: [PATCH 34/47] misc: Payload specific delay formula changed More accurate; shows correct behavior from the paper as well --- src/network/layer.cc | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/network/layer.cc b/src/network/layer.cc index 54cb8b3428..40892b8da4 100644 --- a/src/network/layer.cc +++ b/src/network/layer.cc @@ -398,11 +398,28 @@ Layer::processPackets( // Calculate precise delivery time // within the connection window // Use the payload value -> RACE LOGIC + // - Payload: (payload + 1) time slots + // - Splitter delay: + // * 1 stage if dest == 0 + // * (dest + 1) stages if dest < size - 1 + // * dest stages if dest == size - 1 + // - Merger delay: + // * (size - 1) stages unless src == size - 1, + // in which case it's 1 stage + // - Crosspoint delay is constant payload_specific_delay = - ((payload + 1) * getTimeSlot()) - + splitterDelay * (packet_dest + 1) - + mergerDelay * (size - src_addr - 1) - + crosspointDelay; + ((payload + 1) * getTimeSlot()) + + splitterDelay * ( + (packet_dest == 0) ? 1 : + (packet_dest < size - 1) ? (packet_dest + 1) : + packet_dest + ) + + mergerDelay * ( + (src_addr == size - 1) ? 1 : + (size - 1) + ) + + crosspointDelay + + variabilityCountingNetwork; From 81c46e6bbcc37103f69c63410f67a0f3bab9e8c3 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Fri, 18 Apr 2025 00:10:50 -0700 Subject: [PATCH 35/47] misc: Add bit complement and nearest neighbor traffic patterns They were in the SRNoC paper. --- configs/supernetwork/SRNoC.py | 25 ++++++++++++++++++++ src/network/Layer.py | 2 ++ src/network/enums.cc | 2 ++ src/network/enums.hh | 2 ++ src/network/layer.cc | 39 ++++++++++++++++++++++++++++++++ src/network/layer.hh | 10 ++++++++ src/network/network_scheduler.cc | 28 +++++++++++++++++++++-- src/network/network_scheduler.hh | 4 ++++ 8 files changed, 110 insertions(+), 2 deletions(-) diff --git a/configs/supernetwork/SRNoC.py b/configs/supernetwork/SRNoC.py index 786b60901b..b6c791fc07 100644 --- a/configs/supernetwork/SRNoC.py +++ b/configs/supernetwork/SRNoC.py @@ -171,6 +171,23 @@ def parse_arguments(): "random", parents=[shared_parser], help="Random traffic mode" ) + bit_complement_parser = subparsers.add_parser( + "bit-complement", + parents=[shared_parser], + help="Bit-complement traffic mode", + ) + + nearest_neighbor_parser = subparsers.add_parser( + "nearest-neighbor", + parents=[shared_parser], + help="Nearest-neighbor traffic mode", + ) + nearest_neighbor_parser.add_argument( + "--shuffle", + action="store_true", + help="Shuffle the destinations for nearest-neighbor mode", + ) + # all-to-all traffic all_to_all_parser = subparsers.add_parser( "all-to-all", parents=[shared_parser], help="All-to-all traffic mode" @@ -294,6 +311,14 @@ def main(): elif args.traffic_mode == "tornado": for layer in layers: layer.setTornadoTrafficMode() + elif args.traffic_mode == "bit-complement": + for layer in layers: + layer.setBitComplementTrafficMode() + elif args.traffic_mode == "nearest-neighbor": + for layer in layers: + if args.shuffle: + layer.setShuffle() + layer.setNearestNeighborTrafficMode() else: # file mode selected. for layer in layers: layer.setRandomTrafficMode() diff --git a/src/network/Layer.py b/src/network/Layer.py index 4396463c4e..09716ff12b 100644 --- a/src/network/Layer.py +++ b/src/network/Layer.py @@ -64,5 +64,7 @@ class Layer(ClockedObject): PyBindMethod("setHotspotTrafficMode"), PyBindMethod("setAllToAllTrafficMode"), PyBindMethod("setTornadoTrafficMode"), + PyBindMethod("setBitComplementTrafficMode"), + PyBindMethod("setNearestNeighborTrafficMode"), PyBindMethod("setShuffle"), ] diff --git a/src/network/enums.cc b/src/network/enums.cc index bbcbc4ecb9..9b0a538f95 100644 --- a/src/network/enums.cc +++ b/src/network/enums.cc @@ -36,6 +36,8 @@ const char* TrafficModeNames[NUM_TRAFFIC_MODES] = { "HOTSPOT", "ALL_TO_ALL", "TORNADO", + "BIT_COMPLEMENT", + "NEAREST_NEIGHBOR" }; } // namespace gem5 diff --git a/src/network/enums.hh b/src/network/enums.hh index 76eb09d06d..8201f690dc 100644 --- a/src/network/enums.hh +++ b/src/network/enums.hh @@ -38,6 +38,8 @@ enum TrafficMode HOTSPOT, ALL_TO_ALL, TORNADO, + BIT_COMPLEMENT, + NEAREST_NEIGHBOR, NUM_TRAFFIC_MODES }; extern const char* TrafficModeNames[NUM_TRAFFIC_MODES]; diff --git a/src/network/layer.cc b/src/network/layer.cc index 40892b8da4..0a2764596a 100644 --- a/src/network/layer.cc +++ b/src/network/layer.cc @@ -323,6 +323,45 @@ Layer::processPackets( packet_dest = scheduler.generateHotspotPacket( src_addr, hotspotAddr, hotspotFraction ); + } else if (trafficMode == TrafficMode::BIT_COMPLEMENT) { + // Generate a bit complement packet + packet_dest = scheduler.generateBitComplementPacket( + src_addr + ); + } else if (trafficMode == TrafficMode::NEAREST_NEIGHBOR) { + // only generate once per port + if (!port->hasPackets()) { + // compute wrap‑around neighbors + uint64_t left = (src_addr + size - 1) % size; + uint64_t right = (src_addr + 1) % size; + + // pack them into a small vector + std::vector neighbors = { left, right }; + + // optionally randomize order + if (shuffleEnabled) { + std::random_device rd; + std::mt19937 g(rd()); + std::shuffle(neighbors.begin(), + neighbors.end(), g + ); + } + + // enqueue neighbor packets + for (auto dest : neighbors) { + port->assignPacket(dest); + DPRINTF(Layer, + "BufferedPort %lu: enqueued nearest-neighbor " + "packet for destination %lu\n", + src_addr, dest + ); + } + } + packet_dest = port->peekNextPacket(); + DPRINTF(Layer, + "BufferedPort %lu: nearest-neighbor packet for %lu\n", + src_addr, packet_dest + ); } else if (trafficMode == TrafficMode::ALL_TO_ALL) { // Check if the port already has queued destinations. if (!port->hasPackets()) { diff --git a/src/network/layer.hh b/src/network/layer.hh index 57e0a5e5fd..4f6a17bc79 100644 --- a/src/network/layer.hh +++ b/src/network/layer.hh @@ -194,6 +194,16 @@ public: trafficMode = TrafficMode::TORNADO; } + void setBitComplementTrafficMode() + { + trafficMode = TrafficMode::BIT_COMPLEMENT; + } + + void setNearestNeighborTrafficMode() + { + trafficMode = TrafficMode::NEAREST_NEIGHBOR; + } + void setHotspotTrafficMode(uint64_t hotspotAddr, double hotspotFraction) { diff --git a/src/network/network_scheduler.cc b/src/network/network_scheduler.cc index 94dc7f6b25..253948ec6e 100644 --- a/src/network/network_scheduler.cc +++ b/src/network/network_scheduler.cc @@ -81,7 +81,7 @@ NetworkScheduler::generateRandomPacket(uint64_t src) { if (bufferedPorts.empty()) { warn("No BufferedPorts available for scheduling.\n"); - return -1; + return static_cast(-1); } // Random number generator setup @@ -90,13 +90,37 @@ NetworkScheduler::generateRandomPacket(uint64_t src) uint64_t dest_addr = src; if (bufferedPorts.size() > 1) { - int dest_index = gen() % bufferedPorts.size(); + std::uniform_int_distribution<> dist(0, bufferedPorts.size() - 1); + int dest_index = dist(gen); dest_addr = bufferedPorts[dest_index]->getAddr(); } return dest_addr; } +// Generates a bit complement packet using the given src. +// It generates a packet targeting the port +// at the bit complement of the source address. +uint64_t +NetworkScheduler::generateBitComplementPacket(uint64_t src) +{ + if (bufferedPorts.empty()) { + warn("No BufferedPorts available for scheduling.\n"); + return -1; + } + + if (src >= bufferedPorts.size()) { + fatal("Invalid source address %lu.\n", src); + return -1; + } + + uint64_t dest_addr = ~src; + dest_addr %= bufferedPorts.size(); + + return dest_addr; +} + + // Generates a tornado packet using the given src. // It generates a packet targeting the port // roughly halfway around the network. diff --git a/src/network/network_scheduler.hh b/src/network/network_scheduler.hh index 774dd137ea..e0bfaf3877 100644 --- a/src/network/network_scheduler.hh +++ b/src/network/network_scheduler.hh @@ -69,6 +69,10 @@ public: double hotspot_fraction ); + // Generates a bit complement packet + // using the given src + uint64_t generateBitComplementPacket(uint64_t src); + // Generates a random payload uint64_t generateRandomPayload(uint64_t dynamic_range); From e6488b3a53a17773274aff5b70ffbf9f606662db Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Sun, 20 Apr 2025 20:58:49 -0700 Subject: [PATCH 36/47] misc: Multiple packets from 1 src to 1 dest in 1 window Paper indicates we can send more than 1 value in a window between a src and a dest. Only caveat being they need to be DISTINCT values. --- configs/supernetwork/SRNoC.py | 7 +++ src/network/Layer.py | 1 + src/network/layer.cc | 108 +++++++++++++++++++--------------- src/network/layer.hh | 1 + 4 files changed, 70 insertions(+), 47 deletions(-) diff --git a/configs/supernetwork/SRNoC.py b/configs/supernetwork/SRNoC.py index b6c791fc07..94080b5b32 100644 --- a/configs/supernetwork/SRNoC.py +++ b/configs/supernetwork/SRNoC.py @@ -158,6 +158,12 @@ def create_base_parser(): parser.add_argument( "--maximum-packets", type=int, default=0, help="Maximum packets" ) + parser.add_argument( + "--packets-per-port-per-window", + type=int, + default=1, + help="Packets per port per window", + ) return parser @@ -261,6 +267,7 @@ def main(): variability_counting_network=NetworkDelays.VARIABILITY_COUNTING_NETWORK.value, crosspoint_setup_time=NetworkDelays.CROSSPOINT_SETUP_TIME.value, hold_time=NetworkDelays.CROSSPOINT_HOLD_TIME.value, + packets_per_port_per_window=args.packets_per_port_per_window, clk_domain=SrcClockDomain( clock=frequency, voltage_domain=VoltageDomain(), diff --git a/src/network/Layer.py b/src/network/Layer.py index 09716ff12b..6c1a7901e6 100644 --- a/src/network/Layer.py +++ b/src/network/Layer.py @@ -58,6 +58,7 @@ class Layer(ClockedObject): -1, "Crosspoint setup time in picoseconds" ) hold_time = Param.Float(-1, "Hold time in picoseconds") + packets_per_port_per_window = Param.Int(1, "Packets per port per window") cxx_exports = [ PyBindMethod("setRandomTrafficMode"), diff --git a/src/network/layer.cc b/src/network/layer.cc index 0a2764596a..79a5418488 100644 --- a/src/network/layer.cc +++ b/src/network/layer.cc @@ -65,6 +65,7 @@ Layer::Layer(const LayerParams& params) : holdTime(params.hold_time), packetsDelivered(0), currentTimeSlotIndex(0), + packetsPerPortPerWindow(params.packets_per_port_per_window), isFinished(false), fileMode(false), shuffleEnabled(false), @@ -295,6 +296,7 @@ Layer::processPackets( // Iterate through all ports for (BufferedPort* port : bufferedPorts) { + std::vector used_payloads; if (packets_processed_this_window >= maxPacketsPerWindow) { DPRINTF(Layer, "Window %lu: reached max packets (%lu), stopping.\n", @@ -430,57 +432,69 @@ Layer::processPackets( if (port->hasPackets()) { port->getNextPacket(); } - uint64_t payload = scheduler.generateRandomPayload( - rlTimeSlots - ); + uint64_t payload; + used_payloads.reserve(packetsPerPortPerWindow); + while (used_payloads.size() < packetsPerPortPerWindow) { + uint64_t p = scheduler.generateRandomPayload(rlTimeSlots - 1); + if (std::find(used_payloads.begin(), + used_payloads.end(), + p) + == used_payloads.end()) { + used_payloads.push_back(p); + } + } - // Calculate precise delivery time - // within the connection window - // Use the payload value -> RACE LOGIC - // - Payload: (payload + 1) time slots - // - Splitter delay: - // * 1 stage if dest == 0 - // * (dest + 1) stages if dest < size - 1 - // * dest stages if dest == size - 1 - // - Merger delay: - // * (size - 1) stages unless src == size - 1, - // in which case it's 1 stage - // - Crosspoint delay is constant - payload_specific_delay = - ((payload + 1) * getTimeSlot()) + - splitterDelay * ( - (packet_dest == 0) ? 1 : - (packet_dest < size - 1) ? (packet_dest + 1) : - packet_dest - ) + - mergerDelay * ( - (src_addr == size - 1) ? 1 : - (size - 1) - ) + - crosspointDelay + - variabilityCountingNetwork; + for (auto p : used_payloads) { + // Calculate precise delivery time + // within the connection window + // Use the payload value -> RACE LOGIC + // - Payload: (payload + 1) time slots + // - Splitter delay: + // * 1 stage if dest == 0 + // * (dest + 1) stages if dest < size - 1 + // * dest stages if dest == size - 1 + // - Merger delay: + // * (size - 1) stages unless src == size - 1, + // in which case it's 1 stage + // - Crosspoint delay is constant + payload_specific_delay = + ((p + 1) * getTimeSlot()) + + splitterDelay * ( + (packet_dest == 0) ? 1 : + (packet_dest < size - 1) ? (packet_dest + 1) : + packet_dest + ) + + mergerDelay * ( + (src_addr == size - 1) ? 1 : + (size - 1) + ) + + crosspointDelay + + variabilityCountingNetwork; - DPRINTF(Layer, - "Processing packet: src=%lu, dest=%lu, \ - data=%lu, specific delay=%lu ps\n", - src_addr, allowed_dest, payload, payload_specific_delay - ); - stats.totalPacketsProcessed++; - packetsDelivered++; - packets_processed_this_window++; - - // Schedule packet delivery with payload-specific timing - schedule(new EventFunctionWrapper([this, - src_addr, allowed_dest, payload]() { - deliverPacket(src_addr, allowed_dest, payload); - }, "deliverPacketEvent"), curTick() + payload_specific_delay); - - // Check if we've reached max packets after processing this one - // If not in infinite mode, check for termination condition. - if (!infinite_mode && packetsDelivered >= maxPackets) { - break; + DPRINTF(Layer, + "Processing packet: src=%lu, dest=%lu, \ + data=%lu, specific delay=%lu ps\n", + src_addr, allowed_dest, p, payload_specific_delay + ); + + stats.totalPacketsProcessed++; + packetsDelivered++; + packets_processed_this_window++; + + + // Schedule packet delivery with payload-specific timing + schedule(new EventFunctionWrapper([this, + src_addr, allowed_dest, p]() { + deliverPacket(src_addr, allowed_dest, p); + }, "deliverPacketEvent"), curTick() + payload_specific_delay); + + // Check if we've reached max packets after processing this one + // If not in infinite mode, check for termination condition. + if (!infinite_mode && packetsDelivered >= maxPackets) { + break; + } } } else if (!fileMode) { // Packet not allowed in the current time slot diff --git a/src/network/layer.hh b/src/network/layer.hh index 4f6a17bc79..21e8f6b56b 100644 --- a/src/network/layer.hh +++ b/src/network/layer.hh @@ -74,6 +74,7 @@ private: uint64_t currentTimeSlotIndex; // Current index for the time slot int maxPackets; // Maximum number of packets, -1 means no limit int packetsDelivered; // Number of packet deliveries + uint32_t packetsPerPortPerWindow; // Packets per port per window int size; // Size of the network bool isFinished; // Flag to indicate if the layer has finished bool fileMode; // Flag to indicate if a file is used for scheduling From 39da8b7100355d794e72e17fe5c366169df7a0eb Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Sun, 20 Apr 2025 21:12:43 -0700 Subject: [PATCH 37/47] misc: Align area and power model with ground truth Closer to values seen in paper --- configs/supernetwork/SRNoC.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/configs/supernetwork/SRNoC.py b/configs/supernetwork/SRNoC.py index 94080b5b32..6f6de73a17 100644 --- a/configs/supernetwork/SRNoC.py +++ b/configs/supernetwork/SRNoC.py @@ -69,7 +69,8 @@ class ComponentJJ(PyEnum): def calculate_power_and_area(radix): # Scale counting network power based on network radix - counting_network_ratio = ((radix / 2) + 1) / 4.0 + counting_network_ratio = (radix / 2) // 4.0 + print(f"Counting network ratio: {counting_network_ratio}") counting_network_active_power = ( ComponentPower.COUNTING_NETWORK_ACTIVE.value * counting_network_ratio ) @@ -84,8 +85,8 @@ def calculate_power_and_area(radix): r = radix // 2 num_counting_networks = r num_crosspoints = r * r - num_splitters = r * (r * (r - 1) + 1) - num_mergers = r * (r * (r - 1) + 1) + num_splitters = r * (r - 1) + num_mergers = r * (r - 1) # Calculate active power consumption active_power = ( @@ -116,11 +117,6 @@ def calculate_power_and_area(radix): + num_mergers * ComponentJJ.MERGER.value ) - print(num_counting_networks * counting_network_jj) - print(num_crosspoints * ComponentJJ.CROSSPOINT.value) - print(num_splitters * ComponentJJ.SPLITTER.value) - print(num_mergers * ComponentJJ.MERGER.value) - # Log and store power and area statistics print(f"Active power: {active_power:.6f} W") print(f"Static power: {static_power:.6f} W") From a3832686053c22e5bbda3e7ab7e787ddbd093897 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Wed, 30 Apr 2025 20:39:43 -0700 Subject: [PATCH 38/47] misc: Minor changes Add stat to track the attempted communications and latency Fix bug with maximum communications possible in a window --- src/network/layer.cc | 24 ++++++++++++++++++------ src/network/layer.hh | 4 ++++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/network/layer.cc b/src/network/layer.cc index 79a5418488..ced12da0da 100644 --- a/src/network/layer.cc +++ b/src/network/layer.cc @@ -178,7 +178,7 @@ Layer::computeTimingParameters() DPRINTF(Layer, "Max packets per window: %lu\n", - maxPacketsPerWindow + maxPacketsPerWindow * size ); // Calculate and assign the connection window @@ -297,10 +297,11 @@ Layer::processPackets( // Iterate through all ports for (BufferedPort* port : bufferedPorts) { std::vector used_payloads; - if (packets_processed_this_window >= maxPacketsPerWindow) { + if (packets_processed_this_window >= (maxPacketsPerWindow * size)) { DPRINTF(Layer, "Window %lu: reached max packets (%lu), stopping.\n", - currentTimeSlotIndex, maxPacketsPerWindow); + currentTimeSlotIndex, packets_processed_this_window + ); break; } // Check if we've already reached the maximum packets @@ -425,7 +426,7 @@ Layer::processPackets( ); } } - + stats.totalPacketsAttempted++; // Check if packet can be sent in the current time slot if (packet_dest == allowed_dest) { // Remove the packet if it was from the buffer @@ -471,7 +472,8 @@ Layer::processPackets( crosspointDelay + variabilityCountingNetwork; - + // Log the packet processing details + stats.packetLatency.sample(payload_specific_delay); DPRINTF(Layer, "Processing packet: src=%lu, dest=%lu, \ @@ -584,7 +586,11 @@ Layer::LayerStats::LayerStats( ADD_STAT(pktsPerWindow, statistics::units::Count::get(), "Distribution of packets per window"), ADD_STAT(missedPacketsPerBufferedPort, statistics::units::Count::get(), - "Distribution of missed packets per BufferedPort") + "Distribution of missed packets per BufferedPort"), + ADD_STAT(packetLatency, statistics::units::Count::get(), + "Distribution of packet latency (ps)"), + ADD_STAT(totalPacketsAttempted, statistics::units::Count::get(), + "Total packets attempted to be sent") { } @@ -602,9 +608,15 @@ Layer::LayerStats::regStats() totalWindowsUsed.name("totalWindowsUsed") .desc("Number of connection windows used"); + totalPacketsAttempted.name("totalPacketsAttempted") + .desc("Total packets attempted to be sent"); + pktsPerWindow.init(parentLayer->size + 1); missedPacketsPerBufferedPort.init(64); + + packetLatency.init(64) + .name("packetLatency"); } } // namespace gem5 diff --git a/src/network/layer.hh b/src/network/layer.hh index 21e8f6b56b..1e3df4b56b 100644 --- a/src/network/layer.hh +++ b/src/network/layer.hh @@ -120,10 +120,14 @@ private: statistics::Scalar totalPacketsProcessed; // Number of scheduling windows used statistics::Scalar totalWindowsUsed; + // Number of packets attempted to be sent + statistics::Scalar totalPacketsAttempted; // Distribution of packets processed per time window statistics::Histogram pktsPerWindow; // Distribution of missed packets per BufferedPort statistics::Histogram missedPacketsPerBufferedPort; + // Packet latency distribution + statistics::Histogram packetLatency; // Constructor that links stats to the Layer instance LayerStats(Layer* layer); From 2c16f0b1a3d1e8bcdb3ed4866b6b8d682580df54 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Wed, 30 Apr 2025 21:30:51 -0700 Subject: [PATCH 39/47] misc: Replace packet with value Since communications in SRNoC do not have headers & flits, values is the more accurate term. --- src/network/Layer.py | 8 +- src/network/buffered_port.cc | 54 +++---- src/network/buffered_port.hh | 34 ++--- src/network/layer.cc | 234 +++++++++++++++---------------- src/network/layer.hh | 44 +++--- src/network/network_scheduler.cc | 68 ++++----- src/network/network_scheduler.hh | 30 ++-- src/network/super_network.cc | 2 +- 8 files changed, 237 insertions(+), 237 deletions(-) diff --git a/src/network/Layer.py b/src/network/Layer.py index 6c1a7901e6..566c97c88b 100644 --- a/src/network/Layer.py +++ b/src/network/Layer.py @@ -37,9 +37,9 @@ class Layer(ClockedObject): # Vector of ports in the network buffered_ports = VectorParam.BufferedPort("I/O ports in the network") - # max_packets: 0 means not provided - max_packets = Param.Int( - -1, "Maximum number of packets to schedule; -1 means infinite" + # max_values: 0 means not provided + max_values = Param.Int( + -1, "Maximum number of values to schedule; -1 means infinite" ) # schedule_path: empty string means not provided @@ -58,7 +58,7 @@ class Layer(ClockedObject): -1, "Crosspoint setup time in picoseconds" ) hold_time = Param.Float(-1, "Hold time in picoseconds") - packets_per_port_per_window = Param.Int(1, "Packets per port per window") + values_per_port_per_window = Param.Int(1, "Values per port per window") cxx_exports = [ PyBindMethod("setRandomTrafficMode"), diff --git a/src/network/buffered_port.cc b/src/network/buffered_port.cc index 9375516cda..fab3359772 100644 --- a/src/network/buffered_port.cc +++ b/src/network/buffered_port.cc @@ -58,46 +58,46 @@ BufferedPort::getAddr() return addr; } -// Assigns a packet to the port by pushing the dest address into queue +// Assigns a value to the port by pushing the dest address into queue void -BufferedPort::assignPacket(uint64_t dest_addr) +BufferedPort::assignValue(uint64_t dest_addr) { - packetQueue.push(dest_addr); // Queue the dest + valueQueue.push(dest_addr); // Queue the dest DPRINTF(BufferedPort, - "BufferedPort %d assigned packet " + "BufferedPort %d assigned value " "to destination %d\n", addr, dest_addr ); } -// Retrieves and removes the next packet from the queue -// Returns 0 if no packets are available +// Retrieves and removes the next value from the queue +// Returns 0 if no values are available uint64_t -BufferedPort::getNextPacket() +BufferedPort::getNextValue() { - if (!packetQueue.empty()) { - // Get the next packet and remove it from the queue - uint64_t nextPacket = packetQueue.front(); - packetQueue.pop(); - return nextPacket; + if (!valueQueue.empty()) { + // Get the next value and remove it from the queue + uint64_t nextValue = valueQueue.front(); + valueQueue.pop(); + return nextValue; } - return 0; // No packet available + return 0; // No value available } -// Checks if there are any packets in the queue +// Checks if there are any values in the queue bool -BufferedPort::hasPackets() const +BufferedPort::hasValues() const { - return !packetQueue.empty(); + return !valueQueue.empty(); } -// Increments the missed packet count +// Increments the missed value count void -BufferedPort::incrementMissedPackets() +BufferedPort::incrementMissedValues() { - missedPackets++; - DPRINTF(BufferedPort, "BufferedPort %d missed packets: %d\n", - addr, missedPackets + missedValues++; + DPRINTF(BufferedPort, "BufferedPort %d missed values: %d\n", + addr, missedValues ); } @@ -112,15 +112,15 @@ BufferedPort::receiveData(uint64_t received_data, uint64_t src_addr) lastReceivedFrom = src_addr; // Store the source of the data } -// Returns the next packet without removing it from the queue -// Returns -1 if no packets are available +// Returns the next value without removing it from the queue +// Returns -1 if no values are available uint64_t -BufferedPort::peekNextPacket() const +BufferedPort::peekNextValue() const { - if (!packetQueue.empty()) { - return packetQueue.front(); + if (!valueQueue.empty()) { + return valueQueue.front(); } - return -1; // No packet available + return -1; // No value available } } // namespace gem5 diff --git a/src/network/buffered_port.hh b/src/network/buffered_port.hh index 0885f4f714..84bc208fec 100644 --- a/src/network/buffered_port.hh +++ b/src/network/buffered_port.hh @@ -38,23 +38,23 @@ namespace gem5 { // The BufferedPort class represents a single node in the network -// responsible for storing, sending, and receiving packets. +// responsible for storing, sending, and receiving values. // It tracks its data, address, and maintains statistics for -// sent and received packets. +// sent and received values. class BufferedPort : public ClockedObject { private: // The address identifier of the port uint64_t addr; - // Queue to hold packets (destination addresses) assigned to the port - std::queue packetQueue; + // Queue to hold values (destination addresses) assigned to the port + std::queue valueQueue; // Variables to store the most recent received data and source addr uint64_t lastReceivedData = 0; uint64_t lastReceivedFrom = 0; - uint64_t missedPackets = 0; // Count of missed packets + uint64_t missedValues = 0; // Count of missed values public: // Constructor: Initializes the BufferedPort with parameters @@ -66,30 +66,30 @@ class BufferedPort : public ClockedObject // Retrieves the address of the port uint64_t getAddr(); - // Assigns a packet to the queue with the given destination address - void assignPacket(uint64_t dest_addr); + // Assigns a value to the queue with the given destination address + void assignValue(uint64_t dest_addr); // Receives data from another port // Stores the received value and source void receiveData(uint64_t received_data, uint64_t src_addr); - // Retrieves and removes the next packet from the queue - uint64_t getNextPacket(); + // Retrieves and removes the next value from the queue + uint64_t getNextValue(); - // Checks if the port has any packets in its queue - bool hasPackets() const; + // Checks if the port has any values in its queue + bool hasValues() const; // Getters for the last received data and source information uint64_t getLastReceivedData() const { return lastReceivedData; } uint64_t getLastReceivedFrom() const { return lastReceivedFrom; } - // Getter for missed packets count - uint64_t getMissedPackets() const { return missedPackets; } - // Increments the missed packets count - void incrementMissedPackets(); + // Getter for missed values count + uint64_t getMissedValues() const { return missedValues; } + // Increments the missed values count + void incrementMissedValues(); - // Peeks at the next packet without removing it from the queue - uint64_t peekNextPacket() const; + // Peeks at the next value without removing it from the queue + uint64_t peekNextValue() const; }; } // namespace gem5 diff --git a/src/network/layer.cc b/src/network/layer.cc index ced12da0da..8fd27d61d3 100644 --- a/src/network/layer.cc +++ b/src/network/layer.cc @@ -47,12 +47,12 @@ namespace gem5 { // Constructor for the Layer class // Initializes the network with given parameters, sets up ports, -// and prepares for packet scheduling +// and prepares for value scheduling Layer::Layer(const LayerParams& params) : ClockedObject(params), - maxPackets(params.max_packets), + maxValues(params.max_values), schedulePath(params.schedule_path), - scheduler(params.max_packets, + scheduler(params.max_values, params.schedule_path, params.buffered_ports ), @@ -63,9 +63,9 @@ Layer::Layer(const LayerParams& params) : variabilityCountingNetwork(params.variability_counting_network), crosspointSetupTime(params.crosspoint_setup_time), holdTime(params.hold_time), - packetsDelivered(0), + valuesDelivered(0), currentTimeSlotIndex(0), - packetsPerPortPerWindow(params.packets_per_port_per_window), + valuesPerPortPerWindow(params.values_per_port_per_window), isFinished(false), fileMode(false), shuffleEnabled(false), @@ -91,7 +91,7 @@ Layer::Layer(const LayerParams& params) : if (!schedule_queue.empty()) { fileMode = true; - maxPackets = schedule_queue.size(); + maxValues = schedule_queue.size(); while (!schedule_queue.empty()) { const auto& entry = schedule_queue.front(); @@ -100,9 +100,9 @@ Layer::Layer(const LayerParams& params) : BufferedPort* port = getBufferedPort(src_addr); if (port != nullptr) { - port->assignPacket(dest_addr); + port->assignValue(dest_addr); DPRINTF(Layer, - "BufferedPort %d: addr=%d, packet assigned to %d\n", + "BufferedPort %d: addr=%d, value assigned to %d\n", src_addr, port->getAddr(), dest_addr); } schedule_queue.pop(); @@ -168,7 +168,7 @@ Layer::computeTimingParameters() ); // We can only use a fraction of the time slots - maxPacketsPerWindow = std::floor(rlTimeSlots - + maxValuesPerWindow = std::floor(rlTimeSlots - (rlTimeSlots / std::exp(1.0))); DPRINTF(Layer, @@ -177,8 +177,8 @@ Layer::computeTimingParameters() ); DPRINTF(Layer, - "Max packets per window: %lu\n", - maxPacketsPerWindow * size + "Max values per window: %lu\n", + maxValuesPerWindow * size ); // Calculate and assign the connection window @@ -233,19 +233,19 @@ Layer::processNextNetworkEvent() if (isFinished) { return; } - uint64_t packets_processed_this_window = 0; + uint64_t values_processed_this_window = 0; // Build a static schedule for the current time slot std::unordered_map static_schedule = buildStaticSchedule(); - // Process packets according to the static schedule - // Add hold time before processing packets + // Process values according to the static schedule + // Add hold time before processing values schedule(new EventFunctionWrapper( - [this, static_schedule, packets_processed_this_window]() mutable { - processPackets(static_schedule, packets_processed_this_window); + [this, static_schedule, values_processed_this_window]() mutable { + processValues(static_schedule, values_processed_this_window); }, - "processPacketsEvent"), + "processValuesEvent"), curTick() + holdTime); stats.totalWindowsUsed++; @@ -254,15 +254,15 @@ Layer::processNextNetworkEvent() currentTimeSlotIndex++; // Schedule next network event. - // In infinite mode (maxPackets == -1) we always schedule the next event. - if (maxPackets == static_cast(-1) - || packetsDelivered < maxPackets) { + // In infinite mode (maxValues == -1) we always schedule the next event. + if (maxValues == static_cast(-1) + || valuesDelivered < maxValues) { scheduleNextNetworkEvent(curTick() + ((connectionWindow))); } } -// Build a static schedule for packet transmission in the current time slot +// Build a static schedule for value transmission in the current time slot std::unordered_map Layer::buildStaticSchedule() { @@ -284,56 +284,56 @@ Layer::buildStaticSchedule() return static_schedule; } -// Process packets according to the static schedule +// Process values according to the static schedule bool -Layer::processPackets( +Layer::processValues( const std::unordered_map& static_schedule, - uint64_t& packets_processed_this_window) + uint64_t& values_processed_this_window) { Tick payload_specific_delay = 0; // Determine if we are in infinite mode - bool infinite_mode = (maxPackets == static_cast(-1)); + bool infinite_mode = (maxValues == static_cast(-1)); // Iterate through all ports for (BufferedPort* port : bufferedPorts) { std::vector used_payloads; - if (packets_processed_this_window >= (maxPacketsPerWindow * size)) { + if (values_processed_this_window >= (maxValuesPerWindow * size)) { DPRINTF(Layer, - "Window %lu: reached max packets (%lu), stopping.\n", - currentTimeSlotIndex, packets_processed_this_window + "Window %lu: reached max values (%lu), stopping.\n", + currentTimeSlotIndex, values_processed_this_window ); break; } - // Check if we've already reached the maximum packets - if (packetsDelivered >= maxPackets && !infinite_mode) { - break; // Exit the loop immediately if we've reached max packets + // Check if we've already reached the maximum values + if (valuesDelivered >= maxValues && !infinite_mode) { + break; // Exit the loop immediately if we've reached max values } uint64_t src_addr = port->getAddr(); uint64_t allowed_dest = static_schedule.at(src_addr); - uint64_t packet_dest = -1; - // Check if there's already a packet in the buffer first - if (port->hasPackets()) { - packet_dest = port->peekNextPacket(); + uint64_t value_dest = -1; + // Check if there's already a value in the buffer first + if (port->hasValues()) { + value_dest = port->peekNextValue(); } else { if (!fileMode) { if (trafficMode == TrafficMode::RANDOM) { - // Generate a random packet destination - packet_dest = scheduler.generateRandomPacket(src_addr); + // Generate a random value destination + value_dest = scheduler.generateRandomValue(src_addr); } else if (trafficMode == TrafficMode::HOTSPOT) { // Use the static schedule for the current time slot - packet_dest = scheduler.generateHotspotPacket( + value_dest = scheduler.generateHotspotValue( src_addr, hotspotAddr, hotspotFraction ); } else if (trafficMode == TrafficMode::BIT_COMPLEMENT) { - // Generate a bit complement packet - packet_dest = scheduler.generateBitComplementPacket( + // Generate a bit complement value + value_dest = scheduler.generateBitComplementValue( src_addr ); } else if (trafficMode == TrafficMode::NEAREST_NEIGHBOR) { // only generate once per port - if (!port->hasPackets()) { + if (!port->hasValues()) { // compute wrap‑around neighbors uint64_t left = (src_addr + size - 1) % size; uint64_t right = (src_addr + 1) % size; @@ -350,24 +350,24 @@ Layer::processPackets( ); } - // enqueue neighbor packets + // enqueue neighbor values for (auto dest : neighbors) { - port->assignPacket(dest); + port->assignValue(dest); DPRINTF(Layer, "BufferedPort %lu: enqueued nearest-neighbor " - "packet for destination %lu\n", + "value for destination %lu\n", src_addr, dest ); } } - packet_dest = port->peekNextPacket(); + value_dest = port->peekNextValue(); DPRINTF(Layer, - "BufferedPort %lu: nearest-neighbor packet for %lu\n", - src_addr, packet_dest + "BufferedPort %lu: nearest-neighbor value for %lu\n", + src_addr, value_dest ); } else if (trafficMode == TrafficMode::ALL_TO_ALL) { // Check if the port already has queued destinations. - if (!port->hasPackets()) { + if (!port->hasValues()) { // Create a vector to hold all destination indices. std::vector destinations; destinations.reserve(size); @@ -389,53 +389,53 @@ Layer::processPackets( // Enqueue each destination from the vector. // vector can be shuffled or not for (auto dest : destinations) { - port->assignPacket(dest); + port->assignValue(dest); DPRINTF(Layer, "BufferedPort %lu: enqueued all-to-all " - "packet for destination %lu\n", + "value for destination %lu\n", src_addr, dest ); } } // Peek the next destination from the port's queue. - packet_dest = port->peekNextPacket(); + value_dest = port->peekNextValue(); DPRINTF(Layer, - "BufferedPort %lu: all-to-all packet for %lu\n", - src_addr, packet_dest + "BufferedPort %lu: all-to-all value for %lu\n", + src_addr, value_dest ); } else if (trafficMode == TrafficMode::TORNADO) { - // Generate a tornado packet - packet_dest = scheduler.generateTornadoPacket(src_addr); + // Generate a tornado value + value_dest = scheduler.generateTornadoValue(src_addr); } else { // Handle unknown traffic mode fatal("Unknown traffic mode: %d\n", trafficMode); } DPRINTF(Layer, - "BufferedPort %lu: generated packet for %lu\n", - src_addr, packet_dest + "BufferedPort %lu: generated value for %lu\n", + src_addr, value_dest ); - // Only generate a new packet if there's nothing in the buffer - assert(packet_dest != -1); + // Only generate a new value if there's nothing in the buffer + assert(value_dest != -1); } else { - // In file mode, don't generate a new packet destination. - // Optionally, log that no new packet was generated. + // In file mode, don't generate a new value destination. + // Optionally, log that no new value was generated. DPRINTF(Layer, "BufferedPort %lu: file mode active," - "skipping packet generation\n", + "skipping value generation\n", src_addr ); } } - stats.totalPacketsAttempted++; - // Check if packet can be sent in the current time slot - if (packet_dest == allowed_dest) { - // Remove the packet if it was from the buffer - if (port->hasPackets()) { - port->getNextPacket(); + stats.totalValuesAttempted++; + // Check if value can be sent in the current time slot + if (value_dest == allowed_dest) { + // Remove the value if it was from the buffer + if (port->hasValues()) { + port->getNextValue(); } uint64_t payload; - used_payloads.reserve(packetsPerPortPerWindow); - while (used_payloads.size() < packetsPerPortPerWindow) { + used_payloads.reserve(valuesPerPortPerWindow); + while (used_payloads.size() < valuesPerPortPerWindow) { uint64_t p = scheduler.generateRandomPayload(rlTimeSlots - 1); if (std::find(used_payloads.begin(), used_payloads.end(), @@ -461,9 +461,9 @@ Layer::processPackets( payload_specific_delay = ((p + 1) * getTimeSlot()) + splitterDelay * ( - (packet_dest == 0) ? 1 : - (packet_dest < size - 1) ? (packet_dest + 1) : - packet_dest + (value_dest == 0) ? 1 : + (value_dest < size - 1) ? (value_dest + 1) : + value_dest ) + mergerDelay * ( (src_addr == size - 1) ? 1 : @@ -472,58 +472,58 @@ Layer::processPackets( crosspointDelay + variabilityCountingNetwork; - // Log the packet processing details - stats.packetLatency.sample(payload_specific_delay); + // Log the value processing details + stats.valueLatency.sample(payload_specific_delay); DPRINTF(Layer, - "Processing packet: src=%lu, dest=%lu, \ + "Processing value: src=%lu, dest=%lu, \ data=%lu, specific delay=%lu ps\n", src_addr, allowed_dest, p, payload_specific_delay ); - stats.totalPacketsProcessed++; - packetsDelivered++; - packets_processed_this_window++; + stats.totalValuesProcessed++; + valuesDelivered++; + values_processed_this_window++; - // Schedule packet delivery with payload-specific timing + // Schedule value delivery with payload-specific timing schedule(new EventFunctionWrapper([this, src_addr, allowed_dest, p]() { - deliverPacket(src_addr, allowed_dest, p); - }, "deliverPacketEvent"), curTick() + payload_specific_delay); + deliverValue(src_addr, allowed_dest, p); + }, "deliverValueEvent"), curTick() + payload_specific_delay); - // Check if we've reached max packets after processing this one + // Check if we've reached max values after processing this one // If not in infinite mode, check for termination condition. - if (!infinite_mode && packetsDelivered >= maxPackets) { + if (!infinite_mode && valuesDelivered >= maxValues) { break; } } } else if (!fileMode) { - // Packet not allowed in the current time slot - port->assignPacket(packet_dest); - // Increment missed packets for the BufferedPort - port->incrementMissedPackets(); - stats.missedPacketsPerBufferedPort.sample( - port->getMissedPackets() + // Value not allowed in the current time slot + port->assignValue(value_dest); + // Increment missed values for the BufferedPort + port->incrementMissedValues(); + stats.missedValuesPerBufferedPort.sample( + port->getMissedValues() ); DPRINTF(Layer, - "BufferedPort %lu: packet for %lu not " + "BufferedPort %lu: value for %lu not " "scheduled (allowed: %lu)\n", - src_addr, packet_dest, allowed_dest + src_addr, value_dest, allowed_dest ); DPRINTF(Layer, - "BufferedPort %lu: packet for %lu assigned to buffer\n", - src_addr, packet_dest + "BufferedPort %lu: value for %lu assigned to buffer\n", + src_addr, value_dest ); } } - stats.pktsPerWindow.sample(packets_processed_this_window); + stats.pktsPerWindow.sample(values_processed_this_window); // Only exit simulation if not in infinite mode - if (!infinite_mode && packetsDelivered >= maxPackets) { + if (!infinite_mode && valuesDelivered >= maxValues) { DPRINTF(Layer, - "All packets processed in window %lu\n", + "All values processed in window %lu\n", currentTimeSlotIndex ); DPRINTF(Layer, @@ -539,12 +539,12 @@ Layer::processPackets( } } - return infinite_mode ? true : (packetsDelivered < maxPackets); + return infinite_mode ? true : (valuesDelivered < maxValues); } -// Deliver a packet to its destination port +// Deliver a value to its destination port void -Layer::deliverPacket(uint64_t src_addr, +Layer::deliverValue(uint64_t src_addr, uint64_t dest_addr, uint64_t payload) { // Find the destination port @@ -553,7 +553,7 @@ Layer::deliverPacket(uint64_t src_addr, // Receive data at the destination port dest_port->receiveData(payload, src_addr); DPRINTF(Layer, - "Packet delivered: src=%lu, dest=%lu, data=%lu\n", + "Value delivered: src=%lu, dest=%lu, data=%lu\n", src_addr, dest_addr, payload ); } else { @@ -579,18 +579,18 @@ Layer::LayerStats::LayerStats( Layer* layer ) : statistics::Group(layer), parentLayer(layer), - ADD_STAT(totalPacketsProcessed, statistics::units::Count::get(), - "Total packets processed"), + ADD_STAT(totalValuesProcessed, statistics::units::Count::get(), + "Total values processed"), ADD_STAT(totalWindowsUsed, statistics::units::Count::get(), "Number of connection windows used"), ADD_STAT(pktsPerWindow, statistics::units::Count::get(), - "Distribution of packets per window"), - ADD_STAT(missedPacketsPerBufferedPort, statistics::units::Count::get(), - "Distribution of missed packets per BufferedPort"), - ADD_STAT(packetLatency, statistics::units::Count::get(), - "Distribution of packet latency (ps)"), - ADD_STAT(totalPacketsAttempted, statistics::units::Count::get(), - "Total packets attempted to be sent") + "Distribution of values per window"), + ADD_STAT(missedValuesPerBufferedPort, statistics::units::Count::get(), + "Distribution of missed values per BufferedPort"), + ADD_STAT(valueLatency, statistics::units::Count::get(), + "Distribution of value latency (ps)"), + ADD_STAT(totalValuesAttempted, statistics::units::Count::get(), + "Total values attempted to be sent") { } @@ -602,21 +602,21 @@ Layer::LayerStats::regStats() // Configure statistics with names, descriptions, and formatting - totalPacketsProcessed.name("totalPacketsProcessed") - .desc("Total number of packets processed"); + totalValuesProcessed.name("totalValuesProcessed") + .desc("Total number of values processed"); totalWindowsUsed.name("totalWindowsUsed") .desc("Number of connection windows used"); - totalPacketsAttempted.name("totalPacketsAttempted") - .desc("Total packets attempted to be sent"); + totalValuesAttempted.name("totalValuesAttempted") + .desc("Total values attempted to be sent"); pktsPerWindow.init(parentLayer->size + 1); - missedPacketsPerBufferedPort.init(64); + missedValuesPerBufferedPort.init(64); - packetLatency.init(64) - .name("packetLatency"); + valueLatency.init(64) + .name("valueLatency"); } } // namespace gem5 diff --git a/src/network/layer.hh b/src/network/layer.hh index 1e3df4b56b..a0361f366c 100644 --- a/src/network/layer.hh +++ b/src/network/layer.hh @@ -66,15 +66,15 @@ private: double holdTime; // Network configuration parameters - uint64_t maxPacketsPerWindow; // Maximum packets per window + uint64_t maxValuesPerWindow; // Maximum values per window uint64_t radix; // Radix for the network, used in the topology uint64_t rlTimeSlots; // Number of time slots per connection win. - uint64_t timeSlot; // Time slot for scheduling packets + uint64_t timeSlot; // Time slot for scheduling values uint64_t connectionWindow; // Connection window uint64_t currentTimeSlotIndex; // Current index for the time slot - int maxPackets; // Maximum number of packets, -1 means no limit - int packetsDelivered; // Number of packet deliveries - uint32_t packetsPerPortPerWindow; // Packets per port per window + int maxValues; // Maximum number of values, -1 means no limit + int valuesDelivered; // Number of value deliveries + uint32_t valuesPerPortPerWindow; // Values per port per window int size; // Size of the network bool isFinished; // Flag to indicate if the layer has finished bool fileMode; // Flag to indicate if a file is used for scheduling @@ -86,7 +86,7 @@ private: // Hotspot parameters uint64_t hotspotAddr; // Address of the hotspot - double hotspotFraction; // Fraction of packets targeting the hotspot + double hotspotFraction; // Fraction of values targeting the hotspot // Initialization methods to set up buffered ports void initializeBufferedPorts( @@ -96,15 +96,15 @@ private: // Method to calculate the time slot based on network parameters void assignTimeSlot(); - // Methods for processing packets + // Methods for processing values // Builds a static schedule for the current time slot std::unordered_map buildStaticSchedule(); - bool processPackets( + bool processValues( const std::unordered_map& static_schedule, - uint64_t& packets_processed_this_window + uint64_t& values_processed_this_window ); - // Method for delivering a packet to its destination - void deliverPacket(uint64_t src_addr, + // Method for delivering a value to its destination + void deliverValue(uint64_t src_addr, uint64_t dest_addr, uint64_t payload ); @@ -116,18 +116,18 @@ private: // Statistics for round-robin scheduling - // Total number of packets processed - statistics::Scalar totalPacketsProcessed; + // Total number of values processed + statistics::Scalar totalValuesProcessed; // Number of scheduling windows used statistics::Scalar totalWindowsUsed; - // Number of packets attempted to be sent - statistics::Scalar totalPacketsAttempted; - // Distribution of packets processed per time window + // Number of values attempted to be sent + statistics::Scalar totalValuesAttempted; + // Distribution of values processed per time window statistics::Histogram pktsPerWindow; - // Distribution of missed packets per BufferedPort - statistics::Histogram missedPacketsPerBufferedPort; - // Packet latency distribution - statistics::Histogram packetLatency; + // Distribution of missed values per BufferedPort + statistics::Histogram missedValuesPerBufferedPort; + // Value latency distribution + statistics::Histogram valueLatency; // Constructor that links stats to the Layer instance LayerStats(Layer* layer); @@ -152,9 +152,9 @@ public: BufferedPort* getBufferedPort(uint64_t addr); // Methods for getting certain network parameters - uint64_t getMaximumPacketsPerWindow() const + uint64_t getMaximumValuesPerWindow() const { - return maxPacketsPerWindow; + return maxValuesPerWindow; } uint64_t getRLTimeSlots() const diff --git a/src/network/network_scheduler.cc b/src/network/network_scheduler.cc index 253948ec6e..59954422c6 100644 --- a/src/network/network_scheduler.cc +++ b/src/network/network_scheduler.cc @@ -35,31 +35,31 @@ namespace gem5 { // Constructor for NetworkScheduler -// Initializes the scheduler with maximum packets, +// Initializes the scheduler with maximum values, // schedule path, and list of BufferedPorts NetworkScheduler::NetworkScheduler( - uint64_t max_packets, + uint64_t max_values, const std::string& schedule_path, const std::vector& buffered_ports ) -: maxPackets(max_packets), +: maxValues(max_values), schedulePath(schedule_path), bufferedPorts(buffered_ports), - infiniteMode(max_packets == static_cast(-1)) + infiniteMode(max_values == static_cast(-1)) {} // Initializes the scheduler by either generating or loading a schedule std::queue> NetworkScheduler::initialize() { - if (!maxPackets) { + if (!maxValues) { if (schedulePath.empty()) { - fatal("Either max_packets or schedule_path must be provided.\n"); + fatal("Either max_values or schedule_path must be provided.\n"); } else { loadSchedule(); } } else if (!schedulePath.empty()) { - fatal("Both max_packets and schedule_path are specified.\n"); + fatal("Both max_values and schedule_path are specified.\n"); } return scheduleQueue; } @@ -74,10 +74,10 @@ NetworkScheduler::generateRandomPayload(uint64_t dynamic_range) { } -// Generates a random packet using the given src. +// Generates a random value using the given src. // It picks a random destination from BufferedPorts. uint64_t -NetworkScheduler::generateRandomPacket(uint64_t src) +NetworkScheduler::generateRandomValue(uint64_t src) { if (bufferedPorts.empty()) { warn("No BufferedPorts available for scheduling.\n"); @@ -98,11 +98,11 @@ NetworkScheduler::generateRandomPacket(uint64_t src) return dest_addr; } -// Generates a bit complement packet using the given src. -// It generates a packet targeting the port +// Generates a bit complement value using the given src. +// It generates a value targeting the port // at the bit complement of the source address. uint64_t -NetworkScheduler::generateBitComplementPacket(uint64_t src) +NetworkScheduler::generateBitComplementValue(uint64_t src) { if (bufferedPorts.empty()) { warn("No BufferedPorts available for scheduling.\n"); @@ -121,12 +121,12 @@ NetworkScheduler::generateBitComplementPacket(uint64_t src) } -// Generates a tornado packet using the given src. -// It generates a packet targeting the port +// Generates a tornado value using the given src. +// It generates a value targeting the port // roughly halfway around the network. // stresses bisection bandwidth. uint64_t -NetworkScheduler::generateTornadoPacket(uint64_t src) +NetworkScheduler::generateTornadoValue(uint64_t src) { if (bufferedPorts.empty()) { warn("No BufferedPorts available for scheduling.\n"); @@ -139,7 +139,7 @@ NetworkScheduler::generateTornadoPacket(uint64_t src) return -1; } - // Generate a packet targeting the port + // Generate a value targeting the port // roughly halfway around the network. uint64_t dest_addr = (src + bufferedPorts.size() / 2) % bufferedPorts.size(); @@ -147,12 +147,12 @@ NetworkScheduler::generateTornadoPacket(uint64_t src) return dest_addr; } -// Generates a hotspot packet using the +// Generates a hotspot value using the // given src, hotspot_addr and hotspot_fraction. -// It generates a packet targeting the hotspot with +// It generates a value targeting the hotspot with // probability hotspot_fraction. uint64_t -NetworkScheduler::generateHotspotPacket( +NetworkScheduler::generateHotspotValue( uint64_t src, uint64_t hotspot_addr, double hotspot_fraction @@ -173,13 +173,13 @@ NetworkScheduler::generateHotspotPacket( std::random_device rd; std::mt19937 gen(rd()); - // Generate a packet targeting the hotspot + // Generate a value targeting the hotspot // with probability hotspot_fraction. if (gen() % 100 < hotspot_fraction * 100) { return hotspot_addr; } - // Generate a random packet targeting a random destination. + // Generate a random value targeting a random destination. uint64_t destAddr = src; if (bufferedPorts.size() > 1) { int destIndex = gen() % bufferedPorts.size(); @@ -212,10 +212,10 @@ NetworkScheduler::loadSchedule() } // Load the read entries into the schedule queue - uint64_t packet_count = loadScheduleEntries(file_entries); + uint64_t value_count = loadScheduleEntries(file_entries); DPRINTF(NetworkScheduler, "Schedule loaded from %s with %d entries.\n", - schedulePath, packet_count); + schedulePath, value_count); } // Adds schedule entries from the file into the queue @@ -223,33 +223,33 @@ uint64_t NetworkScheduler::loadScheduleEntries(const std::vector>& file_entries) { - uint64_t packet_count = 0; + uint64_t value_count = 0; - if (maxPackets > 0) { - // If maxPackets is specified, only load up to that limit - uint64_t remaining = maxPackets; + if (maxValues > 0) { + // If maxValues is specified, only load up to that limit + uint64_t remaining = maxValues; - // Add entries in rounds until the maxPackets limit is reached + // Add entries in rounds until the maxValues limit is reached while (remaining > 0) { uint64_t entriesThisRound = std::min(remaining, (uint64_t)file_entries.size()); for (uint64_t i = 0; i < entriesThisRound; i++) { scheduleQueue.push(file_entries[i]); - packet_count++; + value_count++; } remaining -= entriesThisRound; } } else { - // If no maxPackets limit, load all entries + // If no maxValues limit, load all entries for (const auto& entry : file_entries) { scheduleQueue.push(entry); - packet_count++; + value_count++; } } - return packet_count; + return value_count; } // Checks if the schedule file exists @@ -260,9 +260,9 @@ NetworkScheduler::fileExists(const std::string& path) const return ifs.good(); } -// Checks if there are packets remaining in the schedule +// Checks if there are values remaining in the schedule bool -NetworkScheduler::hasPackets() const +NetworkScheduler::hasValues() const { return infiniteMode ? true : (!scheduleQueue.empty()); } diff --git a/src/network/network_scheduler.hh b/src/network/network_scheduler.hh index e0bfaf3877..facd77876b 100644 --- a/src/network/network_scheduler.hh +++ b/src/network/network_scheduler.hh @@ -42,12 +42,12 @@ namespace gem5 { -// NetworkScheduler class handles scheduling packets between BufferedPorts +// NetworkScheduler class handles scheduling values between BufferedPorts class NetworkScheduler { public: // Constructor that initializes the scheduler - NetworkScheduler(uint64_t max_packets, + NetworkScheduler(uint64_t max_values, const std::string& schedule_path, const std::vector& buffered_ports ); @@ -55,23 +55,23 @@ public: // Initializes the scheduler std::queue> initialize(); - // Generates a random packet using the given src - uint64_t generateRandomPacket(uint64_t src); + // Generates a random value using the given src + uint64_t generateRandomValue(uint64_t src); - // Generates a tornado packet + // Generates a tornado value // using the given src - uint64_t generateTornadoPacket(uint64_t src); + uint64_t generateTornadoValue(uint64_t src); - // Generates a hotspot packet + // Generates a hotspot value // using the given src, hotspot_addr and hotspot_fraction - uint64_t generateHotspotPacket(uint64_t src, + uint64_t generateHotspotValue(uint64_t src, uint64_t hotspot_addr, double hotspot_fraction ); - // Generates a bit complement packet + // Generates a bit complement value // using the given src - uint64_t generateBitComplementPacket(uint64_t src); + uint64_t generateBitComplementValue(uint64_t src); // Generates a random payload uint64_t generateRandomPayload(uint64_t dynamic_range); @@ -87,8 +87,8 @@ public: uint64_t>>& file_entries ); - // Checks if there are any packets left in the schedule - bool hasPackets() const; + // Checks if there are any values left in the schedule + bool hasValues() const; // Clears the current schedule, effectively resetting the scheduler void clear(); @@ -100,13 +100,13 @@ private: // Checks if a given file exists at the specified path bool fileExists(const std::string& path) const; - // Maximum number of packets to be scheduled - uint64_t maxPackets; + // Maximum number of values to be scheduled + uint64_t maxValues; // Path to the file where the schedule is saved/loaded std::string schedulePath; // List of BufferedPorts involved in the network const std::vector& bufferedPorts; - // Scheduled packets (source-destination pairs) + // Scheduled values (source-destination pairs) std::queue> scheduleQueue; // Dynamic range of the layer uint64_t dynamicRange; diff --git a/src/network/super_network.cc b/src/network/super_network.cc index c55e3f51f1..e83c920fb3 100644 --- a/src/network/super_network.cc +++ b/src/network/super_network.cc @@ -100,7 +100,7 @@ namespace gem5 ); // Exit the simulation loop exitSimLoop("SuperNetwork: \ - All layers finished processing packets." + All layers finished processing values." ); } } From ec287d3d300fe3dbbf19c6d4fd75d85c1a92574e Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Thu, 1 May 2025 09:23:44 -0700 Subject: [PATCH 40/47] misc: Replace packet with value in config script --- configs/supernetwork/SRNoC.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/configs/supernetwork/SRNoC.py b/configs/supernetwork/SRNoC.py index 6f6de73a17..0d6579858d 100644 --- a/configs/supernetwork/SRNoC.py +++ b/configs/supernetwork/SRNoC.py @@ -152,13 +152,13 @@ def create_base_parser(): "--num-ports", type=int, default=10, help="Number of BufferedPorts" ) parser.add_argument( - "--maximum-packets", type=int, default=0, help="Maximum packets" + "--maximum-values", type=int, default=0, help="Maximum values" ) parser.add_argument( - "--packets-per-port-per-window", + "--values-per-port-per-window", type=int, default=1, - help="Packets per port per window", + help="values per port per window", ) return parser @@ -254,7 +254,7 @@ def main(): layers = [ Layer( buffered_ports=buffered_ports, - max_packets=args.maximum_packets, + max_values=args.maximum_values, schedule_path=schedule_path, crosspoint_delay=NetworkDelays.CROSSPOINT_DELAY.value, merger_delay=NetworkDelays.MERGER_DELAY.value, @@ -263,7 +263,7 @@ def main(): variability_counting_network=NetworkDelays.VARIABILITY_COUNTING_NETWORK.value, crosspoint_setup_time=NetworkDelays.CROSSPOINT_SETUP_TIME.value, hold_time=NetworkDelays.CROSSPOINT_HOLD_TIME.value, - packets_per_port_per_window=args.packets_per_port_per_window, + values_per_port_per_window=args.values_per_port_per_window, clk_domain=SrcClockDomain( clock=frequency, voltage_domain=VoltageDomain(), @@ -288,8 +288,8 @@ def main(): power_and_area = calculate_power_and_area(radix=(num_ports * 2)) print() - if args.maximum_packets: - print(f"Maximum Packets: {args.maximum_packets}") + if args.maximum_values: + print(f"Maximum values: {args.maximum_values}") if getattr(args, "file_path", None): print(f"File Path: {args.file_path}") print() From 398bd5039f3520440146f2ec667750313269ad1b Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Sat, 17 May 2025 15:29:16 -0700 Subject: [PATCH 41/47] misc: Add latency tracking, no buffer mode Latency tracking (in buffer + network delay) No buffer mode; does not store in a buffer at all Config script accepts a --no-buffer arg --- configs/supernetwork/SRNoC.py | 10 +++++++++ src/network/Layer.py | 1 + src/network/buffered_port.cc | 21 +++++++++++++----- src/network/buffered_port.hh | 16 +++++++++---- src/network/layer.cc | 42 ++++++++++++++++++++++++++--------- src/network/layer.hh | 9 +++++++- 6 files changed, 78 insertions(+), 21 deletions(-) diff --git a/configs/supernetwork/SRNoC.py b/configs/supernetwork/SRNoC.py index 0d6579858d..d1bf72fc85 100644 --- a/configs/supernetwork/SRNoC.py +++ b/configs/supernetwork/SRNoC.py @@ -160,6 +160,11 @@ def create_base_parser(): default=1, help="values per port per window", ) + parser.add_argument( + "--no-buffer", + action="store_true", + help="Use no buffer mode (default is buffered mode)", + ) return parser @@ -326,6 +331,11 @@ def main(): for layer in layers: layer.setRandomTrafficMode() + # Set the no buffer mode if specified. + if args.no_buffer: + for layer in layers: + layer.setNoBufferMode() + exit_event = m5.simulate() print(f"Exiting @ tick {m5.curTick()} because {exit_event.getCause()}") diff --git a/src/network/Layer.py b/src/network/Layer.py index 566c97c88b..7cfc88e384 100644 --- a/src/network/Layer.py +++ b/src/network/Layer.py @@ -68,4 +68,5 @@ class Layer(ClockedObject): PyBindMethod("setBitComplementTrafficMode"), PyBindMethod("setNearestNeighborTrafficMode"), PyBindMethod("setShuffle"), + PyBindMethod("setNoBufferMode"), ] diff --git a/src/network/buffered_port.cc b/src/network/buffered_port.cc index fab3359772..b8aa89872e 100644 --- a/src/network/buffered_port.cc +++ b/src/network/buffered_port.cc @@ -62,7 +62,7 @@ BufferedPort::getAddr() void BufferedPort::assignValue(uint64_t dest_addr) { - valueQueue.push(dest_addr); // Queue the dest + valueQueue.emplace(ValueEntry{dest_addr, curTick()}); DPRINTF(BufferedPort, "BufferedPort %d assigned value " "to destination %d\n", @@ -70,18 +70,27 @@ BufferedPort::assignValue(uint64_t dest_addr) ); } +// Clear the queue of values +void +BufferedPort::clearQueue() +{ + while (!valueQueue.empty()) { + valueQueue.pop(); + } +} + // Retrieves and removes the next value from the queue // Returns 0 if no values are available -uint64_t +ValueEntry BufferedPort::getNextValue() { if (!valueQueue.empty()) { // Get the next value and remove it from the queue - uint64_t nextValue = valueQueue.front(); + ValueEntry nextValue = valueQueue.front(); valueQueue.pop(); return nextValue; } - return 0; // No value available + return ValueEntry{0, 0}; // No value available } // Checks if there are any values in the queue @@ -118,9 +127,9 @@ uint64_t BufferedPort::peekNextValue() const { if (!valueQueue.empty()) { - return valueQueue.front(); + return valueQueue.front().dest; } - return -1; // No value available + return -1; // No value available } } // namespace gem5 diff --git a/src/network/buffered_port.hh b/src/network/buffered_port.hh index 84bc208fec..c3d09c3385 100644 --- a/src/network/buffered_port.hh +++ b/src/network/buffered_port.hh @@ -36,7 +36,11 @@ namespace gem5 { - +struct ValueEntry +{ + uint64_t dest; + Tick enqueueTick; +}; // The BufferedPort class represents a single node in the network // responsible for storing, sending, and receiving values. // It tracks its data, address, and maintains statistics for @@ -48,7 +52,7 @@ class BufferedPort : public ClockedObject uint64_t addr; // Queue to hold values (destination addresses) assigned to the port - std::queue valueQueue; + std::queue valueQueue; // Variables to store the most recent received data and source addr uint64_t lastReceivedData = 0; @@ -67,14 +71,18 @@ class BufferedPort : public ClockedObject uint64_t getAddr(); // Assigns a value to the queue with the given destination address - void assignValue(uint64_t dest_addr); + // The value is stored with the current tick as the enqueue time + void assignValue(uint64_t dest); + + // Clears the queue of values + void clearQueue(); // Receives data from another port // Stores the received value and source void receiveData(uint64_t received_data, uint64_t src_addr); // Retrieves and removes the next value from the queue - uint64_t getNextValue(); + ValueEntry getNextValue(); // Checks if the port has any values in its queue bool hasValues() const; diff --git a/src/network/layer.cc b/src/network/layer.cc index 8fd27d61d3..8ecab571b3 100644 --- a/src/network/layer.cc +++ b/src/network/layer.cc @@ -69,6 +69,7 @@ Layer::Layer(const LayerParams& params) : isFinished(false), fileMode(false), shuffleEnabled(false), + noBufferMode(false), size(params.buffered_ports.size()), // Event for processing the next network event nextNetworkEvent([this]{ processNextNetworkEvent(); }, @@ -314,7 +315,8 @@ Layer::processValues( uint64_t value_dest = -1; // Check if there's already a value in the buffer first - if (port->hasValues()) { + if (port->hasValues() && !noBufferMode) { + // Peek the next value from the port's queue value_dest = port->peekNextValue(); } else { if (!fileMode) { @@ -430,9 +432,20 @@ Layer::processValues( // Check if value can be sent in the current time slot if (value_dest == allowed_dest) { // Remove the value if it was from the buffer + Tick enqueue_tick = 0; if (port->hasValues()) { - port->getNextValue(); + auto entry = port->getNextValue(); + value_dest = entry.dest; + enqueue_tick = entry.enqueueTick; + } else { + enqueue_tick = curTick(); + } + + // We can clear out the buffer + if (!noBufferMode) { + port->clearQueue(); } + uint64_t payload; used_payloads.reserve(valuesPerPortPerWindow); while (used_payloads.size() < valuesPerPortPerWindow) { @@ -472,9 +485,6 @@ Layer::processValues( crosspointDelay + variabilityCountingNetwork; - // Log the value processing details - stats.valueLatency.sample(payload_specific_delay); - DPRINTF(Layer, "Processing value: src=%lu, dest=%lu, \ data=%lu, specific delay=%lu ps\n", @@ -488,8 +498,8 @@ Layer::processValues( // Schedule value delivery with payload-specific timing schedule(new EventFunctionWrapper([this, - src_addr, allowed_dest, p]() { - deliverValue(src_addr, allowed_dest, p); + src_addr, allowed_dest, p, enqueue_tick]() { + deliverValue(src_addr, allowed_dest, p, enqueue_tick); }, "deliverValueEvent"), curTick() + payload_specific_delay); // Check if we've reached max values after processing this one @@ -500,7 +510,11 @@ Layer::processValues( } } else if (!fileMode) { // Value not allowed in the current time slot - port->assignValue(value_dest); + if (!noBufferMode){ + // If not in noBufferMode, + // assign the value to the buffer + port->assignValue(value_dest); + } // Increment missed values for the BufferedPort port->incrementMissedValues(); stats.missedValuesPerBufferedPort.sample( @@ -545,13 +559,20 @@ Layer::processValues( // Deliver a value to its destination port void Layer::deliverValue(uint64_t src_addr, - uint64_t dest_addr, uint64_t payload) + uint64_t dest_addr, uint64_t payload, + Tick enqueue_tick) { + Tick total_latency = curTick() - enqueue_tick; + DPRINTF(Layer, + "Value delivery: src=%lu, dest=%lu, data=%lu, latency=%lu\n", + src_addr, dest_addr, payload, total_latency + ); // Find the destination port BufferedPort* dest_port = getBufferedPort(dest_addr); if (dest_port != nullptr) { // Receive data at the destination port dest_port->receiveData(payload, src_addr); + stats.valueLatency.sample(total_latency); DPRINTF(Layer, "Value delivered: src=%lu, dest=%lu, data=%lu\n", src_addr, dest_addr, payload @@ -616,7 +637,8 @@ Layer::LayerStats::regStats() missedValuesPerBufferedPort.init(64); valueLatency.init(64) - .name("valueLatency"); + .name("valueLatency") + .desc("End-to-end latency (ps) = buffer delay + network"); } } // namespace gem5 diff --git a/src/network/layer.hh b/src/network/layer.hh index a0361f366c..57e43716c3 100644 --- a/src/network/layer.hh +++ b/src/network/layer.hh @@ -79,6 +79,7 @@ private: bool isFinished; // Flag to indicate if the layer has finished bool fileMode; // Flag to indicate if a file is used for scheduling bool shuffleEnabled; // Flag to indicate if shuffling is enabled + bool noBufferMode; // Flag to indicate if no buffering is used std::string schedulePath; // Path to the schedule file NetworkScheduler scheduler; // Scheduler for the network SuperNetwork* superNetwork; // Pointer to the super network @@ -105,7 +106,8 @@ private: ); // Method for delivering a value to its destination void deliverValue(uint64_t src_addr, - uint64_t dest_addr, uint64_t payload + uint64_t dest_addr, uint64_t payload, + Tick enqueue_tick ); // Struct to hold statistics related to the Layer @@ -218,6 +220,11 @@ public: } void setShuffle() { shuffleEnabled = true; } + + void setNoBufferMode() + { + noBufferMode = true; + } }; } // namespace gem5 From 7a9cdcf9263d9e291f6ed02d6720e18930878930 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Wed, 21 May 2025 14:18:52 -0700 Subject: [PATCH 42/47] misc: Add param to target messages per second, bug fixes Bug was with sending multiple values from one src to a dest. Fixed it to cap at number of rlTimeSlots in a connection window. Using the above concept, we can reach a target number of messages per second. --- configs/supernetwork/SRNoC.py | 19 +++++++-- src/network/Layer.py | 3 ++ src/network/layer.cc | 74 ++++++++++++++++++++++++++++++++++- src/network/layer.hh | 3 +- 4 files changed, 93 insertions(+), 6 deletions(-) diff --git a/configs/supernetwork/SRNoC.py b/configs/supernetwork/SRNoC.py index d1bf72fc85..d98e9a24f7 100644 --- a/configs/supernetwork/SRNoC.py +++ b/configs/supernetwork/SRNoC.py @@ -155,16 +155,26 @@ def create_base_parser(): "--maximum-values", type=int, default=0, help="Maximum values" ) parser.add_argument( + "--no-buffer", + action="store_true", + help="Use no buffer mode (default is buffered mode)", + ) + + # Mutually exclusive group for value rate config + group = parser.add_mutually_exclusive_group(required=False) + group.add_argument( "--values-per-port-per-window", type=int, default=1, help="values per port per window", ) - parser.add_argument( - "--no-buffer", - action="store_true", - help="Use no buffer mode (default is buffered mode)", + group.add_argument( + "--target-mps", + type=float, + default=-1.0, + help="Target million packets per second", ) + return parser @@ -269,6 +279,7 @@ def main(): crosspoint_setup_time=NetworkDelays.CROSSPOINT_SETUP_TIME.value, hold_time=NetworkDelays.CROSSPOINT_HOLD_TIME.value, values_per_port_per_window=args.values_per_port_per_window, + target_mps=args.target_mps, clk_domain=SrcClockDomain( clock=frequency, voltage_domain=VoltageDomain(), diff --git a/src/network/Layer.py b/src/network/Layer.py index 7cfc88e384..30d9a4a284 100644 --- a/src/network/Layer.py +++ b/src/network/Layer.py @@ -59,6 +59,9 @@ class Layer(ClockedObject): ) hold_time = Param.Float(-1, "Hold time in picoseconds") values_per_port_per_window = Param.Int(1, "Values per port per window") + target_mps = Param.Float( + -1, "Target million packets per second; -1 means not provided" + ) cxx_exports = [ PyBindMethod("setRandomTrafficMode"), diff --git a/src/network/layer.cc b/src/network/layer.cc index 8ecab571b3..55ec7a00d3 100644 --- a/src/network/layer.cc +++ b/src/network/layer.cc @@ -66,6 +66,7 @@ Layer::Layer(const LayerParams& params) : valuesDelivered(0), currentTimeSlotIndex(0), valuesPerPortPerWindow(params.values_per_port_per_window), + targetMMPS(params.target_mps), isFinished(false), fileMode(false), shuffleEnabled(false), @@ -187,6 +188,57 @@ Layer::computeTimingParameters() DPRINTF(Layer, "Connection window: %d ps\n", getConnectionWindow() ); + + if (targetMMPS >= 0) { + double values_this_window = + static_cast(targetMMPS) * 1e6 * + (static_cast(getConnectionWindow()) / 1e12); + + DPRINTF(Layer, + "Values this window: %f\n", + values_this_window + ); + + // spread them evenly across ports, round *up* + valuesPerPortPerWindow = + std::ceil(values_this_window / static_cast(size)); + + DPRINTF(Layer, + "Value per port per window: %lu\n", + valuesPerPortPerWindow + ); + + // safety: never let it exceed the hard structural cap + valuesPerPortPerWindow = + std::min(valuesPerPortPerWindow, + maxValuesPerWindow * size); + DPRINTF(Layer, + "Target MMPS: %f\n", + targetMMPS + ); + DPRINTF(Layer, + "Values per port per window: %lu\n", + valuesPerPortPerWindow + ); + if (valuesPerPortPerWindow == 0) { + fatal("Layer %s: Target MMPS (%f) is too low!\n", + name(), targetMMPS); + } + if (valuesPerPortPerWindow > (maxValuesPerWindow * size)) { + warn("Layer %s: Target MMPS (%f) is too high!\n", + name(), targetMMPS); + warn("Layer %s: Setting values per port per \ + window to %lu\n", + name(),(maxValuesPerWindow * size)); + } + } + + if (valuesPerPortPerWindow > maxValues) { + fatal("Values per port per window (%lu) \ + exceeds max values (%lu)\n", + name(), valuesPerPortPerWindow, maxValues); + } + } // Calculate the time slot based on network component delays @@ -305,6 +357,14 @@ Layer::processValues( ); break; } + if (valuesPerPortPerWindow > rlTimeSlots) { + warn("Layer %s: values per port per window (%lu) " + "exceeds RL time slots (%lu)\n", + name(), valuesPerPortPerWindow, rlTimeSlots); + warn("Layer %s: setting values per port per window to %lu\n", + name(), rlTimeSlots); + valuesPerPortPerWindow = rlTimeSlots; + } // Check if we've already reached the maximum values if (valuesDelivered >= maxValues && !infinite_mode) { break; // Exit the loop immediately if we've reached max values @@ -449,7 +509,7 @@ Layer::processValues( uint64_t payload; used_payloads.reserve(valuesPerPortPerWindow); while (used_payloads.size() < valuesPerPortPerWindow) { - uint64_t p = scheduler.generateRandomPayload(rlTimeSlots - 1); + uint64_t p = scheduler.generateRandomPayload(rlTimeSlots); if (std::find(used_payloads.begin(), used_payloads.end(), p) @@ -458,6 +518,18 @@ Layer::processValues( } } + // Sort the payloads in ascending order + std::sort(used_payloads.begin(), used_payloads.end()); + + // print the payloads + DPRINTF(Layer, + "BufferedPort %lu: payloads for %lu: ", + src_addr, value_dest + ); + for (auto p : used_payloads) { + DPRINTF(Layer, "%lu ", p); + } + for (auto p : used_payloads) { // Calculate precise delivery time // within the connection window diff --git a/src/network/layer.hh b/src/network/layer.hh index 57e43716c3..b7991255b0 100644 --- a/src/network/layer.hh +++ b/src/network/layer.hh @@ -74,7 +74,8 @@ private: uint64_t currentTimeSlotIndex; // Current index for the time slot int maxValues; // Maximum number of values, -1 means no limit int valuesDelivered; // Number of value deliveries - uint32_t valuesPerPortPerWindow; // Values per port per window + int valuesPerPortPerWindow; // Values per port per window + double targetMMPS; // Target million messages per second of the network int size; // Size of the network bool isFinished; // Flag to indicate if the layer has finished bool fileMode; // Flag to indicate if a file is used for scheduling From a387d9ca3a9629956a406bcfb1540c7c06b36950 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Thu, 22 May 2025 15:27:28 -0700 Subject: [PATCH 43/47] misc: Add buffer depth This is done as a param to control the injection rate for nearest neighbor and all-to-all --- src/network/Layer.py | 3 + src/network/buffered_port.hh | 22 +++ src/network/layer.cc | 288 ++++++++++++++++++++++------------- src/network/layer.hh | 4 + 4 files changed, 210 insertions(+), 107 deletions(-) diff --git a/src/network/Layer.py b/src/network/Layer.py index 7cfc88e384..5512b94bfe 100644 --- a/src/network/Layer.py +++ b/src/network/Layer.py @@ -59,6 +59,9 @@ class Layer(ClockedObject): ) hold_time = Param.Float(-1, "Hold time in picoseconds") values_per_port_per_window = Param.Int(1, "Values per port per window") + buffer_depth = Param.Int( + 1, "Buffer depth (number of values in the buffer)" + ) cxx_exports = [ PyBindMethod("setRandomTrafficMode"), diff --git a/src/network/buffered_port.hh b/src/network/buffered_port.hh index c3d09c3385..d50edcf24c 100644 --- a/src/network/buffered_port.hh +++ b/src/network/buffered_port.hh @@ -30,6 +30,7 @@ #define __NETWORK_BUFFEREDPORT_HH__ #include +#include #include "params/BufferedPort.hh" #include "sim/clocked_object.hh" @@ -91,6 +92,27 @@ class BufferedPort : public ClockedObject uint64_t getLastReceivedData() const { return lastReceivedData; } uint64_t getLastReceivedFrom() const { return lastReceivedFrom; } + // Getter for the size of the value queue + size_t queueSize() const { return valueQueue.size(); } + + uint64_t allToAllCursor = 0; // Cursor for all-to-all traffic mode + + void shuffleQueue() + { + if (valueQueue.size() < 2) return; + + std::vector tmp; + while (!valueQueue.empty()) { + tmp.push_back(valueQueue.front()); + valueQueue.pop(); + } + std::random_device rd; + std::mt19937 gen(rd()); + std::shuffle(tmp.begin(), tmp.end(), gen); + for (auto &e : tmp) valueQueue.push(e); + } + + // Getter for missed values count uint64_t getMissedValues() const { return missedValues; } // Increments the missed values count diff --git a/src/network/layer.cc b/src/network/layer.cc index 8ecab571b3..5c65d724a6 100644 --- a/src/network/layer.cc +++ b/src/network/layer.cc @@ -70,6 +70,7 @@ Layer::Layer(const LayerParams& params) : fileMode(false), shuffleEnabled(false), noBufferMode(false), + bufferDepth(params.buffer_depth), size(params.buffered_ports.size()), // Event for processing the next network event nextNetworkEvent([this]{ processNextNetworkEvent(); }, @@ -263,6 +264,67 @@ Layer::processNextNetworkEvent() } } +void +Layer::fillQueue(BufferedPort* port, TrafficMode mode) +{ + while (port->queueSize() < bufferDepth) { + uint64_t src = port->getAddr(); + uint64_t dest = 0; + + switch (mode) { + case TrafficMode::RANDOM: + dest = scheduler.generateRandomValue(src); + break; + + case TrafficMode::HOTSPOT: + dest = scheduler.generateHotspotValue(src, hotspotAddr, + hotspotFraction); + break; + + case TrafficMode::BIT_COMPLEMENT: + dest = scheduler.generateBitComplementValue(src); + break; + + case TrafficMode::TORNADO: + dest = scheduler.generateTornadoValue(src); + break; + + case TrafficMode::NEAREST_NEIGHBOR: { + /* pick left or right at random so we don’t exceed + injectionsPerPortPerWindow == 1 unintentionally */ + uint64_t neighbor = + (random() & 1) ? (src + 1) % size + : (src + size - 1) % size; + dest = neighbor; + break; + } + + case TrafficMode::ALL_TO_ALL: { + /* cycle through the permutation instead of enqueuing them all */ + uint64_t next = + (port->allToAllCursor + 1) % size; // store cursor in port + port->allToAllCursor = next; + dest = next; + break; + } + + default: + fatal("unknown traffic mode"); + } + port->assignValue(dest); + } + + // if shuffleEnabled is true, shuffle the queue + if (shuffleEnabled) { + port->shuffleQueue(); + DPRINTF(Layer, + "BufferedPort %lu: shuffled queue\n", + port->getAddr() + ); + } +} + + // Build a static schedule for value transmission in the current time slot std::unordered_map Layer::buildStaticSchedule() @@ -320,113 +382,115 @@ Layer::processValues( value_dest = port->peekNextValue(); } else { if (!fileMode) { - if (trafficMode == TrafficMode::RANDOM) { - // Generate a random value destination - value_dest = scheduler.generateRandomValue(src_addr); - } else if (trafficMode == TrafficMode::HOTSPOT) { - // Use the static schedule for the current time slot - value_dest = scheduler.generateHotspotValue( - src_addr, hotspotAddr, hotspotFraction - ); - } else if (trafficMode == TrafficMode::BIT_COMPLEMENT) { - // Generate a bit complement value - value_dest = scheduler.generateBitComplementValue( - src_addr - ); - } else if (trafficMode == TrafficMode::NEAREST_NEIGHBOR) { - // only generate once per port - if (!port->hasValues()) { - // compute wrap‑around neighbors - uint64_t left = (src_addr + size - 1) % size; - uint64_t right = (src_addr + 1) % size; - - // pack them into a small vector - std::vector neighbors = { left, right }; - - // optionally randomize order - if (shuffleEnabled) { - std::random_device rd; - std::mt19937 g(rd()); - std::shuffle(neighbors.begin(), - neighbors.end(), g - ); - } - - // enqueue neighbor values - for (auto dest : neighbors) { - port->assignValue(dest); - DPRINTF(Layer, - "BufferedPort %lu: enqueued nearest-neighbor " - "value for destination %lu\n", - src_addr, dest - ); - } - } - value_dest = port->peekNextValue(); - DPRINTF(Layer, - "BufferedPort %lu: nearest-neighbor value for %lu\n", - src_addr, value_dest - ); - } else if (trafficMode == TrafficMode::ALL_TO_ALL) { - // Check if the port already has queued destinations. - if (!port->hasValues()) { - // Create a vector to hold all destination indices. - std::vector destinations; - destinations.reserve(size); - for (uint64_t dest = 0; dest < size; dest++) { - destinations.push_back(dest); - } - - // Conditionally shuffle the vector - if (shuffleEnabled) { - // Create a random number generator. - std::random_device rd; - std::mt19937 g(rd()); - // Shuffle the destinations. - std::shuffle(destinations.begin(), - destinations.end(), g - ); - } - - // Enqueue each destination from the vector. - // vector can be shuffled or not - for (auto dest : destinations) { - port->assignValue(dest); - DPRINTF(Layer, - "BufferedPort %lu: enqueued all-to-all " - "value for destination %lu\n", - src_addr, dest - ); - } - } - // Peek the next destination from the port's queue. - value_dest = port->peekNextValue(); - DPRINTF(Layer, - "BufferedPort %lu: all-to-all value for %lu\n", - src_addr, value_dest - ); - } else if (trafficMode == TrafficMode::TORNADO) { - // Generate a tornado value - value_dest = scheduler.generateTornadoValue(src_addr); - } else { - // Handle unknown traffic mode - fatal("Unknown traffic mode: %d\n", trafficMode); - } - DPRINTF(Layer, - "BufferedPort %lu: generated value for %lu\n", - src_addr, value_dest - ); - // Only generate a new value if there's nothing in the buffer - assert(value_dest != -1); - } else { - // In file mode, don't generate a new value destination. - // Optionally, log that no new value was generated. - DPRINTF(Layer, - "BufferedPort %lu: file mode active," - "skipping value generation\n", - src_addr - ); + fillQueue(port, trafficMode); } + // if (trafficMode == TrafficMode::RANDOM) { + // // Generate a random value destination + // value_dest = scheduler.generateRandomValue(src_addr); + // } else if (trafficMode == TrafficMode::HOTSPOT) { + // // Use the static schedule for the current time slot + // value_dest = scheduler.generateHotspotValue( + // src_addr, hotspotAddr, hotspotFraction + // ); + // } else if (trafficMode == TrafficMode::BIT_COMPLEMENT) { + // // Generate a bit complement value + // value_dest = scheduler.generateBitComplementValue( + // src_addr + // ); + // } else if (trafficMode == TrafficMode::NEAREST_NEIGHBOR) { + // // only generate once per port + // if (!port->hasValues()) { + // // compute wrap‑around neighbors + // uint64_t left = (src_addr + size - 1) % size; + // uint64_t right = (src_addr + 1) % size; + + // // pack them into a small vector + // std::vector neighbors = { left, right }; + + // // optionally randomize order + // if (shuffleEnabled) { + // std::random_device rd; + // std::mt19937 g(rd()); + // std::shuffle(neighbors.begin(), + // neighbors.end(), g + // ); + // } + + // // enqueue neighbor values + // for (auto dest : neighbors) { + // port->assignValue(dest); + // DPRINTF(Layer, + // "BufferedPort %lu: enqueued nearest-neighbor " + // "value for destination %lu\n", + // src_addr, dest + // ); + // } + // } + // value_dest = port->peekNextValue(); + // DPRINTF(Layer, + // "BufferedPort %lu: nearest-neighbor value for %lu\n", + // src_addr, value_dest + // ); + // } else if (trafficMode == TrafficMode::ALL_TO_ALL) { + // // Check if the port already has queued destinations. + // if (!port->hasValues()) { + // // Create a vector to hold all destination indices. + // std::vector destinations; + // destinations.reserve(size); + // for (uint64_t dest = 0; dest < size; dest++) { + // destinations.push_back(dest); + // } + + // // Conditionally shuffle the vector + // if (shuffleEnabled) { + // // Create a random number generator. + // std::random_device rd; + // std::mt19937 g(rd()); + // // Shuffle the destinations. + // std::shuffle(destinations.begin(), + // destinations.end(), g + // ); + // } + + // // Enqueue each destination from the vector. + // // vector can be shuffled or not + // for (auto dest : destinations) { + // port->assignValue(dest); + // DPRINTF(Layer, + // "BufferedPort %lu: enqueued all-to-all " + // "value for destination %lu\n", + // src_addr, dest + // ); + // } + // } + // // Peek the next destination from the port's queue. + // value_dest = port->peekNextValue(); + // DPRINTF(Layer, + // "BufferedPort %lu: all-to-all value for %lu\n", + // src_addr, value_dest + // ); + // } else if (trafficMode == TrafficMode::TORNADO) { + // // Generate a tornado value + // value_dest = scheduler.generateTornadoValue(src_addr); + // } else { + // // Handle unknown traffic mode + // fatal("Unknown traffic mode: %d\n", trafficMode); + // } + // DPRINTF(Layer, + // "BufferedPort %lu: generated value for %lu\n", + // src_addr, value_dest + // ); + // + // assert(value_dest != -1); + // } else { + // // In file mode, don't generate a new value destination. + // // Optionally, log that no new value was generated. + // DPRINTF(Layer, + // "BufferedPort %lu: file mode active," + // "skipping value generation\n", + // src_addr + // ); + // } } stats.totalValuesAttempted++; // Check if value can be sent in the current time slot @@ -446,10 +510,20 @@ Layer::processValues( port->clearQueue(); } + if (valuesPerPortPerWindow > rlTimeSlots) { + // If the number of values per port per window + // is greater than the number of time slots, + // we need to generate unique payloads + warn("Layer %s: valuesPerPortPerWindow (%lu) is greater than " + "rlTimeSlots (%lu), using rlTimeSlots instead\n", + name(), valuesPerPortPerWindow, rlTimeSlots); + valuesPerPortPerWindow = rlTimeSlots; + } + uint64_t payload; used_payloads.reserve(valuesPerPortPerWindow); while (used_payloads.size() < valuesPerPortPerWindow) { - uint64_t p = scheduler.generateRandomPayload(rlTimeSlots - 1); + uint64_t p = scheduler.generateRandomPayload(rlTimeSlots); if (std::find(used_payloads.begin(), used_payloads.end(), p) diff --git a/src/network/layer.hh b/src/network/layer.hh index 57e43716c3..8c9d4ad3de 100644 --- a/src/network/layer.hh +++ b/src/network/layer.hh @@ -75,6 +75,7 @@ private: int maxValues; // Maximum number of values, -1 means no limit int valuesDelivered; // Number of value deliveries uint32_t valuesPerPortPerWindow; // Values per port per window + int bufferDepth; // Depth of the buffer int size; // Size of the network bool isFinished; // Flag to indicate if the layer has finished bool fileMode; // Flag to indicate if a file is used for scheduling @@ -149,6 +150,9 @@ public: // Methods for computing layer timing parameters void computeTimingParameters(); + // Method to fill the queue of a port with values + void fillQueue(BufferedPort* port, TrafficMode mode); + // Methods for adding and retrieving ports in the network void addBufferedPort(BufferedPort* buffered_port); BufferedPort* getBufferedPort(uint64_t addr); From d98525b07663bb6a82b6ec5e7c9e2088a043607f Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Thu, 22 May 2025 16:33:56 -0700 Subject: [PATCH 44/47] misc: Configurable buffer depth Removed no buffer mode bool and collapsed its functionality onto the buffer depth param --- configs/supernetwork/SRNoC.py | 10 -------- src/network/Layer.py | 1 - src/network/layer.cc | 47 ++++++++++++++++++++++++++++------- src/network/layer.hh | 8 +++--- 4 files changed, 41 insertions(+), 25 deletions(-) diff --git a/configs/supernetwork/SRNoC.py b/configs/supernetwork/SRNoC.py index d1bf72fc85..0d6579858d 100644 --- a/configs/supernetwork/SRNoC.py +++ b/configs/supernetwork/SRNoC.py @@ -160,11 +160,6 @@ def create_base_parser(): default=1, help="values per port per window", ) - parser.add_argument( - "--no-buffer", - action="store_true", - help="Use no buffer mode (default is buffered mode)", - ) return parser @@ -331,11 +326,6 @@ def main(): for layer in layers: layer.setRandomTrafficMode() - # Set the no buffer mode if specified. - if args.no_buffer: - for layer in layers: - layer.setNoBufferMode() - exit_event = m5.simulate() print(f"Exiting @ tick {m5.curTick()} because {exit_event.getCause()}") diff --git a/src/network/Layer.py b/src/network/Layer.py index 5512b94bfe..67474ce383 100644 --- a/src/network/Layer.py +++ b/src/network/Layer.py @@ -71,5 +71,4 @@ class Layer(ClockedObject): PyBindMethod("setBitComplementTrafficMode"), PyBindMethod("setNearestNeighborTrafficMode"), PyBindMethod("setShuffle"), - PyBindMethod("setNoBufferMode"), ] diff --git a/src/network/layer.cc b/src/network/layer.cc index 5c65d724a6..c2b6081d07 100644 --- a/src/network/layer.cc +++ b/src/network/layer.cc @@ -69,7 +69,6 @@ Layer::Layer(const LayerParams& params) : isFinished(false), fileMode(false), shuffleEnabled(false), - noBufferMode(false), bufferDepth(params.buffer_depth), size(params.buffered_ports.size()), // Event for processing the next network event @@ -264,29 +263,48 @@ Layer::processNextNetworkEvent() } } -void +uint64_t Layer::fillQueue(BufferedPort* port, TrafficMode mode) { - while (port->queueSize() < bufferDepth) { + int count = 0; + while (isBuffered() ? port->queueSize() < bufferDepth : count < 1) { + count++; uint64_t src = port->getAddr(); uint64_t dest = 0; switch (mode) { case TrafficMode::RANDOM: dest = scheduler.generateRandomValue(src); + DPRINTF(Layer, + "BufferedPort %lu: generated random value for %lu\n", + src, dest + ); break; case TrafficMode::HOTSPOT: dest = scheduler.generateHotspotValue(src, hotspotAddr, hotspotFraction); + DPRINTF(Layer, + "BufferedPort %lu: generated hotspot value for %lu\n", + src, dest + ); break; case TrafficMode::BIT_COMPLEMENT: dest = scheduler.generateBitComplementValue(src); + DPRINTF(Layer, + "BufferedPort %lu: generated bit complement value \ + for %lu\n", + src, dest + ); break; case TrafficMode::TORNADO: dest = scheduler.generateTornadoValue(src); + DPRINTF(Layer, + "BufferedPort %lu: generated tornado value for %lu\n", + src, dest + ); break; case TrafficMode::NEAREST_NEIGHBOR: { @@ -296,6 +314,11 @@ Layer::fillQueue(BufferedPort* port, TrafficMode mode) (random() & 1) ? (src + 1) % size : (src + size - 1) % size; dest = neighbor; + DPRINTF(Layer, + "BufferedPort %lu: generated nearest-neighbor value \ + for %lu\n", + src, dest + ); break; } @@ -305,6 +328,10 @@ Layer::fillQueue(BufferedPort* port, TrafficMode mode) (port->allToAllCursor + 1) % size; // store cursor in port port->allToAllCursor = next; dest = next; + DPRINTF(Layer, + "BufferedPort %lu: generated all-to-all value for %lu\n", + src, dest + ); break; } @@ -322,6 +349,8 @@ Layer::fillQueue(BufferedPort* port, TrafficMode mode) port->getAddr() ); } + + return port->peekNextValue(); } @@ -377,12 +406,12 @@ Layer::processValues( uint64_t value_dest = -1; // Check if there's already a value in the buffer first - if (port->hasValues() && !noBufferMode) { + if (port->hasValues() && isBuffered()) { // Peek the next value from the port's queue value_dest = port->peekNextValue(); } else { if (!fileMode) { - fillQueue(port, trafficMode); + value_dest = fillQueue(port, trafficMode); } // if (trafficMode == TrafficMode::RANDOM) { // // Generate a random value destination @@ -506,7 +535,7 @@ Layer::processValues( } // We can clear out the buffer - if (!noBufferMode) { + if (isBuffered()) { port->clearQueue(); } @@ -584,9 +613,9 @@ Layer::processValues( } } else if (!fileMode) { // Value not allowed in the current time slot - if (!noBufferMode){ - // If not in noBufferMode, - // assign the value to the buffer + if (isBuffered()) { + // If in buffered mode + // Assign the value to the buffer port->assignValue(value_dest); } // Increment missed values for the BufferedPort diff --git a/src/network/layer.hh b/src/network/layer.hh index 8c9d4ad3de..9c2461bb78 100644 --- a/src/network/layer.hh +++ b/src/network/layer.hh @@ -80,7 +80,6 @@ private: bool isFinished; // Flag to indicate if the layer has finished bool fileMode; // Flag to indicate if a file is used for scheduling bool shuffleEnabled; // Flag to indicate if shuffling is enabled - bool noBufferMode; // Flag to indicate if no buffering is used std::string schedulePath; // Path to the schedule file NetworkScheduler scheduler; // Scheduler for the network SuperNetwork* superNetwork; // Pointer to the super network @@ -151,7 +150,7 @@ public: void computeTimingParameters(); // Method to fill the queue of a port with values - void fillQueue(BufferedPort* port, TrafficMode mode); + uint64_t fillQueue(BufferedPort* port, TrafficMode mode); // Methods for adding and retrieving ports in the network void addBufferedPort(BufferedPort* buffered_port); @@ -225,9 +224,8 @@ public: void setShuffle() { shuffleEnabled = true; } - void setNoBufferMode() - { - noBufferMode = true; + bool isBuffered() { + return (bufferDepth > 0); } }; From 1bba2bb0f4537f699088977c72ff5865d1a76d84 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Tue, 27 May 2025 21:36:17 -0700 Subject: [PATCH 45/47] misc: Fixing bugs --- configs/supernetwork/SRNoC.py | 9 ++-- src/network/buffered_port.hh | 2 +- src/network/layer.cc | 88 +++++++++++++++++------------------ 3 files changed, 50 insertions(+), 49 deletions(-) diff --git a/configs/supernetwork/SRNoC.py b/configs/supernetwork/SRNoC.py index dd84efe335..843df36b0d 100644 --- a/configs/supernetwork/SRNoC.py +++ b/configs/supernetwork/SRNoC.py @@ -155,9 +155,10 @@ def create_base_parser(): "--maximum-values", type=int, default=0, help="Maximum values" ) parser.add_argument( - "--no-buffer", - action="store_true", - help="Use no buffer mode (default is buffered mode)", + "--buffer-depth", + type=int, + default=1, + help="Buffer depth (number of values in the buffer)", ) # Mutually exclusive group for value rate config @@ -272,7 +273,7 @@ def main(): crosspoint_setup_time=NetworkDelays.CROSSPOINT_SETUP_TIME.value, hold_time=NetworkDelays.CROSSPOINT_HOLD_TIME.value, values_per_port_per_window=args.values_per_port_per_window, - target_mps=args.target_mps, + buffer_depth=args.buffer_depth, clk_domain=SrcClockDomain( clock=frequency, voltage_domain=VoltageDomain(), diff --git a/src/network/buffered_port.hh b/src/network/buffered_port.hh index d50edcf24c..6d4229632f 100644 --- a/src/network/buffered_port.hh +++ b/src/network/buffered_port.hh @@ -95,7 +95,7 @@ class BufferedPort : public ClockedObject // Getter for the size of the value queue size_t queueSize() const { return valueQueue.size(); } - uint64_t allToAllCursor = 0; // Cursor for all-to-all traffic mode + uint64_t allToAllCursor = -1; // Cursor for all-to-all traffic mode void shuffleQueue() { diff --git a/src/network/layer.cc b/src/network/layer.cc index 3df4bb1b93..80a5038ab4 100644 --- a/src/network/layer.cc +++ b/src/network/layer.cc @@ -66,7 +66,7 @@ Layer::Layer(const LayerParams& params) : valuesDelivered(0), currentTimeSlotIndex(0), valuesPerPortPerWindow(params.values_per_port_per_window), - targetMMPS(params.target_mps), + // targetMMPS(params.target_mps), isFinished(false), fileMode(false), shuffleEnabled(false), @@ -189,49 +189,49 @@ Layer::computeTimingParameters() getConnectionWindow() ); - if (targetMMPS >= 0) { - double values_this_window = - static_cast(targetMMPS) * 1e6 * - (static_cast(getConnectionWindow()) / 1e12); - - DPRINTF(Layer, - "Values this window: %f\n", - values_this_window - ); - - // spread them evenly across ports, round *up* - valuesPerPortPerWindow = - std::ceil(values_this_window / static_cast(size)); - - DPRINTF(Layer, - "Value per port per window: %lu\n", - valuesPerPortPerWindow - ); - - // safety: never let it exceed the hard structural cap - valuesPerPortPerWindow = - std::min(valuesPerPortPerWindow, - maxValuesPerWindow * size); - DPRINTF(Layer, - "Target MMPS: %f\n", - targetMMPS - ); - DPRINTF(Layer, - "Values per port per window: %lu\n", - valuesPerPortPerWindow - ); - if (valuesPerPortPerWindow == 0) { - fatal("Layer %s: Target MMPS (%f) is too low!\n", - name(), targetMMPS); - } - if (valuesPerPortPerWindow > (maxValuesPerWindow * size)) { - warn("Layer %s: Target MMPS (%f) is too high!\n", - name(), targetMMPS); - warn("Layer %s: Setting values per port per \ - window to %lu\n", - name(),(maxValuesPerWindow * size)); - } - } + // if (targetMMPS >= 0) { + // double values_this_window = + // static_cast(targetMMPS) * 1e6 * + // (static_cast(getConnectionWindow()) / 1e12); + + // DPRINTF(Layer, + // "Values this window: %f\n", + // values_this_window + // ); + + // // spread them evenly across ports, round *up* + // valuesPerPortPerWindow = + // std::ceil(values_this_window / static_cast(size)); + + // DPRINTF(Layer, + // "Value per port per window: %lu\n", + // valuesPerPortPerWindow + // ); + + // // safety: never let it exceed the hard structural cap + // valuesPerPortPerWindow = + // std::min(valuesPerPortPerWindow, + // maxValuesPerWindow * size); + // DPRINTF(Layer, + // "Target MMPS: %f\n", + // targetMMPS + // ); + // DPRINTF(Layer, + // "Values per port per window: %lu\n", + // valuesPerPortPerWindow + // ); + // if (valuesPerPortPerWindow == 0) { + // fatal("Layer %s: Target MMPS (%f) is too low!\n", + // name(), targetMMPS); + // } + // if (valuesPerPortPerWindow > (maxValuesPerWindow * size)) { + // warn("Layer %s: Target MMPS (%f) is too high!\n", + // name(), targetMMPS); + // warn("Layer %s: Setting values per port per \ + // window to %lu\n", + // name(),(maxValuesPerWindow * size)); + // } + // } if (valuesPerPortPerWindow > maxValues) { fatal("Values per port per window (%lu) \ From 20247bbf63d922c13e63c0d541f2c80d74113e56 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Fri, 6 Jun 2025 21:33:09 -0700 Subject: [PATCH 46/47] misc: Add active sources Based on a parameter, we can either set a raw number or a fraction of the srcs to be active FOR SOURCE SENDING. Destinations are all still fully active. There is also a boolean that can determine if these active sources should be sequential or if they can be random. Also, right now I am using a hard-coded seed to make sure the random sources are the same. Perhaps might consider setting seed through a parameter later. --- configs/supernetwork/SRNoC.py | 28 +++++++++++++++++++---- src/network/Layer.py | 10 +++++++++ src/network/layer.cc | 42 +++++++++++++++++++++++++++++++++++ src/network/layer.hh | 11 +++++++++ 4 files changed, 87 insertions(+), 4 deletions(-) diff --git a/configs/supernetwork/SRNoC.py b/configs/supernetwork/SRNoC.py index 843df36b0d..4846ca7d05 100644 --- a/configs/supernetwork/SRNoC.py +++ b/configs/supernetwork/SRNoC.py @@ -160,15 +160,32 @@ def create_base_parser(): default=1, help="Buffer depth (number of values in the buffer)", ) - - # Mutually exclusive group for value rate config - group = parser.add_mutually_exclusive_group(required=False) - group.add_argument( + parser.add_argument( "--values-per-port-per-window", type=int, default=1, help="values per port per window", ) + + # add mutually exclusive group for active source selection + active_src_group = parser.add_mutually_exclusive_group() + active_src_group.add_argument( + "--active-src-count", + type=int, + default=-1, + help="Number of active sources in the network (-1 for all)", + ) + active_src_group.add_argument( + "--active-src-fraction", + type=float, + default=1.0, + help="Fraction of active sources in the network (default is 1 for all)", + ) + active_src_group.add_argument( + "--active-src-sequence", + action="store_true", + help="If true, active sources are selected in a sequence; otherwise, randomly", + ) return parser @@ -278,6 +295,9 @@ def main(): clock=frequency, voltage_domain=VoltageDomain(), ), + active_src_count=args.active_src_count, + active_src_frac=args.active_src_fraction, + active_src_seq=args.active_src_sequence, ) for frequency in args.frequencies_per_layer ] diff --git a/src/network/Layer.py b/src/network/Layer.py index 67474ce383..c4caea74de 100644 --- a/src/network/Layer.py +++ b/src/network/Layer.py @@ -62,6 +62,16 @@ class Layer(ClockedObject): buffer_depth = Param.Int( 1, "Buffer depth (number of values in the buffer)" ) + active_src_count = Param.Int( + -1, "Number of active sources in the network (default is -1 for all)" + ) + active_src_frac = Param.Float( + 1.0, "Fraction of active sources in the network (default is 1 for all)" + ) + active_src_seq = Param.Bool( + False, + "If true, active sources are selected in a sequence; otherwise, randomly", + ) cxx_exports = [ PyBindMethod("setRandomTrafficMode"), diff --git a/src/network/layer.cc b/src/network/layer.cc index 80a5038ab4..168d075521 100644 --- a/src/network/layer.cc +++ b/src/network/layer.cc @@ -72,6 +72,9 @@ Layer::Layer(const LayerParams& params) : shuffleEnabled(false), bufferDepth(params.buffer_depth), size(params.buffered_ports.size()), + activeSrcCount(params.active_src_count), + activeSrcFraction(params.active_src_frac), + activeSrcSeq(params.active_src_seq), // Event for processing the next network event nextNetworkEvent([this]{ processNextNetworkEvent(); }, name() + ".nextNetworkEvent"), @@ -110,6 +113,43 @@ Layer::Layer(const LayerParams& params) : schedule_queue.pop(); } } + + // for active source selection + uint64_t want; + if (params.active_src_frac < 0.0 || + params.active_src_frac > 1.0) { + fatal("Layer %s: active_src_frac (%f) must be in [0, 1]!\n", + name(), params.active_src_frac); + } + if (params.active_src_count <= 0 && + params.active_src_count != -1.0) { + fatal("Layer %s: active_src_count (%d) must be > 0!\n", + name(), params.active_src_count); + } + if (params.active_src_count > 0) { + want = std::min(params.active_src_count, size); + } else { + want = std::ceil(params.active_src_frac * size); + } + if (want >= size) // all active ⇒ keep set empty + ; + else if (params.active_src_seq) { // sequential + for (uint64_t i = 0; i < want; ++i) + activeSrc.insert(i); + } else { // random but repeatable + std::vector ids(size); + std::iota(ids.begin(), ids.end(), 0); + std::mt19937 rng(42); // fixed seed for repeatability + std::shuffle(ids.begin(), ids.end(), rng); + for (uint64_t i = 0; i < want; ++i) + activeSrc.insert(ids[i]); + } + + // debug output for active sources + DPRINTF(Layer, "Active sources: "); + for (const auto& src : activeSrc) { + DPRINTF(Layer, "%lu ", src); + } } // Initialize ports with unique addresses @@ -440,6 +480,8 @@ Layer::processValues( // Iterate through all ports for (BufferedPort* port : bufferedPorts) { + if (!isSrcActive(port->getAddr())) + continue; std::vector used_payloads; if (values_processed_this_window >= (maxValuesPerWindow * size)) { DPRINTF(Layer, diff --git a/src/network/layer.hh b/src/network/layer.hh index 9c2461bb78..e4cd51a1a2 100644 --- a/src/network/layer.hh +++ b/src/network/layer.hh @@ -55,6 +55,7 @@ class Layer : public ClockedObject private: std::vector bufferedPorts; // all ports in the network std::unordered_map bufferedPortsMap; + std::unordered_set activeSrc; // Set of active source addresses // network delay parameters double crosspointDelay; @@ -76,6 +77,9 @@ private: int valuesDelivered; // Number of value deliveries uint32_t valuesPerPortPerWindow; // Values per port per window int bufferDepth; // Depth of the buffer + int activeSrcCount; // Count of active source addresses + double activeSrcFraction; // Fraction of active source addresses + bool activeSrcSeq; // Flag for sequential active source addresses int size; // Size of the network bool isFinished; // Flag to indicate if the layer has finished bool fileMode; // Flag to indicate if a file is used for scheduling @@ -227,6 +231,13 @@ public: bool isBuffered() { return (bufferDepth > 0); } + + bool + isSrcActive(uint64_t id) const + { + /* empty set -> “all active” */ + return activeSrc.empty() || activeSrc.count(id); + } }; } // namespace gem5 From 0f606372d9376fba6f0d60c87d1699861b98ab49 Mon Sep 17 00:00:00 2001 From: KUNAL PAI Date: Tue, 10 Jun 2025 23:56:05 -0700 Subject: [PATCH 47/47] misc: Move seq/rand active ports bool Move it out of mutually exclusive parser --- configs/supernetwork/SRNoC.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/supernetwork/SRNoC.py b/configs/supernetwork/SRNoC.py index 4846ca7d05..86ffaa6e48 100644 --- a/configs/supernetwork/SRNoC.py +++ b/configs/supernetwork/SRNoC.py @@ -181,7 +181,7 @@ def create_base_parser(): default=1.0, help="Fraction of active sources in the network (default is 1 for all)", ) - active_src_group.add_argument( + parser.add_argument( "--active-src-sequence", action="store_true", help="If true, active sources are selected in a sequence; otherwise, randomly",