diff --git a/.vscode/launch.json b/.vscode/launch.json index d570bd0a31..e87b5c5d87 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -100,7 +100,7 @@ "request": "launch", "program": "${workspaceFolder}/build/scratch/ns3.40-rdma-simulator-debug", "args": [ - "config/demos/cc-tree4/cc-swift.json" + "config/demos/leaky-bucket.json" ], "stopAtEntry": false, "cwd": "${workspaceFolder}", @@ -118,9 +118,36 @@ "description": "Enable pretty-printing for gdb", "text": "-enable-pretty-printing", "ignoreFailures": true - }, + } + ] + }, + { + "name": "(gdb) Launch rdma-simulator with config selection", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/scratch/ns3.40-rdma-simulator-debug", + "args": [ + "${input:configFile}" ], - } + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "preLaunchTask": "Build", + "environment": [ + { + "name": "LD_LIBRARY_PATH", + "value": "${workspaceFolder}/build/lib/" + } + ], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + }, ], "inputs": [ { @@ -135,6 +162,18 @@ "minsizerel" ], "default": "default" + }, + { + "type": "pickString", + "id": "configFile", + "description": "Select configuration file", + "options": [ + "config/demos/cc-tree4/cc-dcqcn.json", + "config/demos/cc-tree4/cc-swift.json", + "config/demos/cc-tree4/cc-ledbat.json", + "config/demos/cc-tree4/cc-harvest.json" + ], + "default": "config/demos/cc-tree4/cc-dcqcn.json" } ] } \ No newline at end of file diff --git a/config/demos/cc-tree4/cc-dcqcn.json b/config/demos/cc-tree4/cc-dcqcn.json index 043c6cad3c..fd8c205436 100644 --- a/config/demos/cc-tree4/cc-dcqcn.json +++ b/config/demos/cc-tree4/cc-dcqcn.json @@ -115,7 +115,7 @@ "CongestionType": "ns3::RoCEv2Dcqcn", "SendEnabled": true, "TrafficPattern": "SendOnce", - "TrafficSizeBytes": 10000000, + "TrafficSizeBytes": 1000000, "TrafficLoad": 0.0, "DestFixed": true, "DestinationNode": 4 diff --git a/config/demos/leaky-bucket.json b/config/demos/leaky-bucket.json new file mode 100644 index 0000000000..c46c9a18aa --- /dev/null +++ b/config/demos/leaky-bucket.json @@ -0,0 +1,154 @@ +{ + "inputFile": { + "topo": "config/topo/1to1.txt" + }, + "outputFile": { + "resultFile": "output/*.json" + }, + "runtimeConfig": { + "seed": 5, + "runningTime": "1s", + "stopTime": "10s" + }, + "defaultConfig": { + "TcpL4Protocol": { + "SocketType": "ns3::TcpNewReno" + }, + "TcpSocket": { + "DelAckCount": 1, + "InitialCwnd": 1, + "SndBufSize": 1073741823, + "RcvBufSize": 1073741823, + "SegmentSize": 1500 + }, + "TcpSocketBase": { + "Timestamp": false + }, + "RoCEv2Timely": { + "Tlow": "32us", + "Thigh": "16us" + }, + "RoCEv2Socket": { + "RetxMode": "GBN" + }, + "RoCEv2SocketState": { + "MinRateRatio": 0.01 + } + }, + "globalConfig": { + "detailedSenderStats": false, + "detailedRetxStats": false, + "detailedQlengthStats": false, + "qlengthRecordInterval": "1000us", + "detailedThroughputStats": false, + "deviceThroughputRecordInterval": "10us" + }, + "topologyConfig": { + "flowControlConfig": [ + { + "nodes": "host", + "trafficControlLayer": "ns3::TrafficControlLayer", + "trafficControlLayerConfig": {}, + "flowControlPort": "ns3::DcbPfcPort", + "flowControlPortConfig": { + "EnableIngressControl": true, + "EnableEgressControl": true, + "EnableVec": 255 + }, + "outerQueueDisc": "ns3::PausableQueueDisc", + "outerQueueDiscConfig": { + "FcEnabled": true + }, + "innerQueueDisc": "ns3::FifoQueueDiscEcn", + "innerQueueDiscConfig": { + "MaxSize": "10MiB" + } + }, + { + "nodes": "switch", + "bufferSize": "32MiB", + "bufferPerPort": "0.675MiB", + "numQueuePerPort": 8, + "numLosslessQueue": 2, + "trafficControlLayer": "ns3::DcbTrafficControl", + "trafficControlLayerConfig": {}, + "flowControlPort": "ns3::DcbHpccPort", + "flowControlPortConfig": { + "EnableIngressControl": true, + "EnableEgressControl": true, + "EnableVec": 255 + }, + "flowControlMmuQueue": "ns3::DcbPfcMmuQueue", + "flowControlMmuQueueConfig": { + "ReserveSize": "4KiB", + "ResumeOffset": "3KiB", + "IsDynamicThreshold": true, + "DtShift": 2 + }, + "outerQueueDisc": "ns3::PausableQueueDisc", + "outerQueueDiscConfig": { + "FcEnabled": true + }, + "innerQueueDisc": "ns3::FifoQueueDiscEcn", + "innerQueueDiscConfig": { + "EcnKMin": "400KiB", + "EcnKMax": "1600KiB", + "EcnPMax": 0.2 + }, + "prioRateLimits" :[ + {"priority": 0, "rate": "5Gbps", "burstSize": 10000}, + {"priority": 1, "rate": "5Gbps", "burstSize": 10000}, + {"priority": 2, "rate": "5Gbps", "burstSize": 10000}, + {"priority": 3, "rate": "5Gbps", "burstSize": 10000}, + {"priority": 4, "rate": "5Gbps", "burstSize": 10000}, + {"priority": 5, "rate": "5Gbps", "burstSize": 10000}, {"priority": 6, "rate": "5Gbps", "burstSize": 10000}, + {"priority": 7, "rate": "5Gbps", "burstSize": 10000} + ] + } + ], + "linkConfig": [ + { + "links": "0", + "rate": "10Gbps", + "delay": "3us" + } + ] + }, + "applicationConfig": [ + { + "appType": "ns3::DcbTrafficGenApplication", + "nodes": "[0]", + "protocolGroup": "RoCEv2", + "applicationConfig":{ + "CongestionType": "ns3::RoCEv2Dcqcn", + "SendEnabled": true, + "TrafficPattern": "SendOnce", + "TrafficSizeBytes": 10000000, + "FixedFlowArrive": true, + "DestFixed": true, + "DestinationNode": 1 + }, + "cdf": { + "cdfFile": "config/trace/WebSearch_distribution.txt", + "avgSize": 0, + "scaleFactor": 0 + }, + "socketConfig": { + "InnerPriority": 0 + }, + "startTime": "0.100s", + "stopTime": "0.11s", + "flowInterval": "0.0000s" + }, + { + "NOTE": "Recevier side applciation", + "appType": "ns3::DcbTrafficGenApplication", + "nodes": "[1]", + "protocolGroup": "RoCEv2", + "applicationConfig":{ + "SendEnabled": false + }, + "startTime": "0.1s" + } + ] +} \ No newline at end of file diff --git a/config/demos/symmetric-hashing.json b/config/demos/symmetric-hashing.json new file mode 100644 index 0000000000..d8da1541f6 --- /dev/null +++ b/config/demos/symmetric-hashing.json @@ -0,0 +1,145 @@ +{ + "inputFile": { + "topo": "config/topo/1-1-4-1-1multipath.txt" + }, + "outputFile": { + "resultFile": "output/*.json" + }, + "runtimeConfig": { + "seed": 5, + "runningTime": "1s", + "stopTime": "10s" + }, + "defaultConfig": { + "TcpL4Protocol": { + "SocketType": "ns3::TcpNewReno" + }, + "TcpSocket": { + "DelAckCount": 1, + "InitialCwnd": 1, + "SndBufSize": 1073741823, + "RcvBufSize": 1073741823, + "SegmentSize": 1500 + }, + "TcpSocketBase": { + "Timestamp": false + }, + "RoCEv2Timely": { + "Tlow": "32us", + "Thigh": "16us" + }, + "RoCEv2Socket": { + "RetxMode": "GBN" + }, + "RoCEv2SocketState": { + "MinRateRatio": 0.01 + } + }, + "globalConfig": { + "detailedSenderStats": false, + "detailedRetxStats": false, + "detailedQlengthStats": false, + "qlengthRecordInterval": "1000us", + "detailedThroughputStats": true, + "deviceThroughputRecordInterval": "10us" + }, + "topologyConfig": { + "flowControlConfig": [ + { + "nodes": "host", + "trafficControlLayer": "ns3::TrafficControlLayer", + "trafficControlLayerConfig": {}, + "flowControlPort": "ns3::DcbPfcPort", + "flowControlPortConfig": { + "EnableIngressControl": true, + "EnableEgressControl": true, + "EnableVec": 255 + }, + "outerQueueDisc": "ns3::PausableQueueDisc", + "outerQueueDiscConfig": { + "FcEnabled": true + }, + "innerQueueDisc": "ns3::FifoQueueDiscEcn", + "innerQueueDiscConfig": { + "MaxSize": "10MiB" + } + }, + { + "nodes": "switch", + "bufferSize": "32MiB", + "bufferPerPort": "0.675MiB", + "numQueuePerPort": 8, + "numLosslessQueue": 2, + "trafficControlLayer": "ns3::DcbTrafficControl", + "trafficControlLayerConfig": {}, + "flowControlPort": "ns3::DcbHpccPort", + "flowControlPortConfig": { + "EnableIngressControl": true, + "EnableEgressControl": true, + "EnableVec": 255 + }, + "flowControlMmuQueue": "ns3::DcbPfcMmuQueue", + "flowControlMmuQueueConfig": { + "ReserveSize": "4KiB", + "ResumeOffset": "3KiB", + "IsDynamicThreshold": true, + "DtShift": 2 + }, + "outerQueueDisc": "ns3::PausableQueueDisc", + "outerQueueDiscConfig": { + "FcEnabled": true + }, + "innerQueueDisc": "ns3::FifoQueueDiscEcn", + "innerQueueDiscConfig": { + "EcnKMin": "400KiB", + "EcnKMax": "1600KiB", + "EcnPMax": 0.2 + } + } + ], + "linkConfig": [ + { + "links": "0", + "rate": "10Gbps", + "delay": "3us" + } + ] + }, + "applicationConfig": [ + { + "appType": "ns3::DcbTrafficGenApplication", + "nodes": "[0]", + "protocolGroup": "RoCEv2", + "applicationConfig":{ + "CongestionType": "ns3::RoCEv2CreditSpary", + "SendEnabled": true, + "TrafficPattern": "SendOnce", + "TrafficSizeBytes": 1000000, + "FixedFlowArrive": true, + "DestFixed": true, + "DestinationNode": 7 + }, + "cdf": { + "cdfFile": "config/trace/WebSearch_distribution.txt", + "avgSize": 0, + "scaleFactor": 0 + }, + "socketConfig": { + "InnerPriority": 0 + }, + "startTime": "0.100s", + "stopTime": "0.11s", + "flowInterval": "0.0000s" + }, + { + "NOTE": "Recevier side applciation", + "appType": "ns3::DcbTrafficGenApplication", + "nodes": "[7]", + "protocolGroup": "RoCEv2", + "applicationConfig":{ + "SendEnabled": false + }, + "startTime": "0.1s" + } + ] +} \ No newline at end of file diff --git a/config/topo/1-1-4-1-1multipath.txt b/config/topo/1-1-4-1-1multipath.txt new file mode 100644 index 0000000000..d8b2c11362 --- /dev/null +++ b/config/topo/1-1-4-1-1multipath.txt @@ -0,0 +1,12 @@ +8 6 10 +1 2 3 4 5 6 +0 1 0 +1 2 0 +1 3 0 +1 4 0 +1 5 0 +2 6 0 +3 6 0 +4 6 0 +5 6 0 +6 7 0 \ No newline at end of file diff --git a/ns3 b/ns3 index 26a75a9668..6e6af6d6dd 100755 --- a/ns3 +++ b/ns3 @@ -322,7 +322,7 @@ def parse_args(argv): dest='verbose', default_value=False) - # Try to split -- separated arguments into two lists for ns3 and for the runnable target +# Try to split -- separated arguments into two lists for ns3 and for the runnable target try: args_separator_index = argv.index('--') ns3_args = argv[:args_separator_index] @@ -652,6 +652,9 @@ def configure_cmake(cmake, args, current_cmake_cache_folder, current_cmake_gener ) cmake_args.append("-DNS3_NATIVE_OPTIMIZATIONS=%s" % on_off((args.build_profile == "optimized"))) + # Add compile commands database for IDE support + cmake_args.append("-DCMAKE_EXPORT_COMPILE_COMMANDS=ON") + options = (("ASSERT", "asserts"), ("CLANG_TIDY", "clang_tidy"), ("COVERAGE", "gcov"), @@ -920,8 +923,6 @@ def cmake_build(current_cmake_cache_folder, output, jobs, target=None, dry_run=F # In case of failure, exit prematurely with the return code from the build if ret.returncode != 0: exit(ret.returncode) - - def extract_cmakecache_settings(current_cmake_cache_folder): try: with open(current_cmake_cache_folder + os.sep + "CMakeCache.txt", "r", encoding="utf-8") as f: @@ -1627,4 +1628,4 @@ def main(): return -main() +main() \ No newline at end of file diff --git a/scratch/rdma-simulator.cc b/scratch/rdma-simulator.cc index 9e035071b2..7a8e0c67a3 100644 --- a/scratch/rdma-simulator.cc +++ b/scratch/rdma-simulator.cc @@ -156,9 +156,9 @@ main(int argc, char* argv[]) // port.GetFC()->TraceConnectWithoutContext("PfcReceived", MakeCallback(&PfcReceived)); // } // } - + // Simulator::ScheduleDestroy(); Simulator::Run(); - + std::cout<< "time: " << Simulator::Now().GetNanoSeconds() << "ns" << std::endl; json_util::OutputStats(configObj, apps, topology, config_file); tEnd = std::chrono::system_clock::now(); diff --git a/src/dcb/CMakeLists.txt b/src/dcb/CMakeLists.txt index ec8a478f5e..3184afddff 100644 --- a/src/dcb/CMakeLists.txt +++ b/src/dcb/CMakeLists.txt @@ -38,7 +38,9 @@ build_lib( model/rocev2-poseidon.cc model/rocev2-d2tcp.cc model/rocev2-nocc.cc + model/rocev2-credit-spary.cc model/switch-node.cc + model/leaky-bucket.cc utils/hpcc-header.cc utils/poseidon-header.cc utils/pfc-frame.cc @@ -82,6 +84,8 @@ build_lib( model/rocev2-d2tcp.h model/rocev2-nocc.h model/switch-node.h + model/rocev2-credit-spary.h + model/leaky-bucket.h utils/hpcc-header.h utils/poseidon-header.h utils/pfc-frame.h diff --git a/src/dcb/helper/dcb-fc-helper.cc b/src/dcb/helper/dcb-fc-helper.cc index e73fbb0739..02b415e8ad 100644 --- a/src/dcb/helper/dcb-fc-helper.cc +++ b/src/dcb/helper/dcb-fc-helper.cc @@ -336,6 +336,12 @@ DcbFcHelper::Install(Ptr node) { qDisc->SetDefaultStrictPriority(); } + + // Set priority rate limits, if have + if (m_prioRateLimits.size() > 0) + { + qDisc->SetPriorityRateLimits(m_prioRateLimits); + } } if (dcbTc != nullptr) @@ -522,4 +528,10 @@ DcbFcHelper::SetMaxCredit(uint32_t maxCredit) m_maxCredit = maxCredit; } -} // namespace ns3 +void +DcbFcHelper::SetPrioRateLimit(const std::vector>& rateLimits) +{ + m_prioRateLimits = rateLimits; +} + +} // namespace ns3 \ No newline at end of file diff --git a/src/dcb/helper/dcb-fc-helper.h b/src/dcb/helper/dcb-fc-helper.h index 636f10ec29..55e3cdeffd 100644 --- a/src/dcb/helper/dcb-fc-helper.h +++ b/src/dcb/helper/dcb-fc-helper.h @@ -80,6 +80,8 @@ class DcbFcHelper void SetQuantum(std::vector&& quantum); void SetMaxCredit(uint32_t maxCredit); + void SetPrioRateLimit(const std::vector>& rateLimits); + private: ObjectFactory m_tcFactory; ObjectFactory m_fcpFactory; @@ -96,8 +98,10 @@ class DcbFcHelper std::vector m_priorities; std::vector m_quantum; // in KB uint32_t m_maxCredit; // in KB + + std::vector> m_prioRateLimits; }; // class DcbFcHelper } // namespace ns3 -#endif +#endif \ No newline at end of file diff --git a/src/dcb/model/leaky-bucket.cc b/src/dcb/model/leaky-bucket.cc new file mode 100644 index 0000000000..bd13fd4c2d --- /dev/null +++ b/src/dcb/model/leaky-bucket.cc @@ -0,0 +1,107 @@ +#include "leaky-bucket.h" + +#include "ns3/log.h" +#include "ns3/simulator.h" +#include +#include +NS_LOG_COMPONENT_DEFINE("LeakyBucket"); + +namespace ns3 +{ + TypeId + LeakyBucket::GetTypeId() + { + static TypeId tid = TypeId("ns3::LeakyBucket") + .SetParent() + .AddConstructor(); + return tid; + } + + LeakyBucket::LeakyBucket() + { + NS_LOG_FUNCTION(this); + } + LeakyBucket::LeakyBucket(DataRate rate, uint32_t capacity,Callback cb) + : m_rate(rate), + m_capacity(capacity), + m_availableTokens(capacity), + m_RefillInterval(MicroSeconds(10)), + m_RefillCallback(cb) + { + NS_LOG_FUNCTION(this << rate << capacity); + m_RefillAmount = static_cast(m_rate.GetBitRate() * m_RefillInterval.GetSeconds() / 8); + m_refillEvent = Simulator::Schedule(m_RefillInterval, &LeakyBucket::Refill, this); + //m_refillEvent = Simulator::ScheduleNow(&LeakyBucket::Refill, this); + //Refill(); + } + + LeakyBucket::~LeakyBucket() + { + NS_LOG_FUNCTION(this); + if (!m_refillEvent.IsExpired()) + { + m_refillEvent.Cancel(); + } + } + + void LeakyBucket::SetRefillCallback(Callback cb) + { + m_RefillCallback = cb; + } + + void LeakyBucket::Refill() + { + NS_LOG_FUNCTION(this); + //std::cout << "Refill called, available tokens: " << m_availableTokens << std::endl; + m_availableTokens = std::min(m_availableTokens + m_RefillAmount, m_capacity); + if (m_refillEvent.IsExpired()&&!isFull()) + { + m_refillEvent = Simulator::Schedule(m_RefillInterval, &LeakyBucket::Refill, this); + } + if (!m_RefillCallback.IsNull()) + { + m_RefillCallback(); + } + + } + + bool LeakyBucket::CanConsume(uint32_t bytes) + { + if(m_refillEvent.IsExpired()&&!isFull()) + m_refillEvent = Simulator::Schedule(m_RefillInterval,&LeakyBucket::Refill, this); + NS_LOG_FUNCTION(this << bytes); + return m_availableTokens >= bytes; + } + + // must call CanConsume(bytes) to make sure it returns true before Consume(bytes) + void LeakyBucket::Consume(uint32_t bytes) + { + NS_LOG_FUNCTION(this << bytes); + NS_ABORT_IF(!CanConsume(bytes)); + m_availableTokens -= bytes; + return; + } + + void LeakyBucket::Pause() + { + NS_LOG_FUNCTION(this); + if (!m_refillEvent.IsExpired()) + { + m_refillEvent.Cancel(); + } + } + void LeakyBucket::Resume() + { + NS_LOG_FUNCTION(this); + if (m_refillEvent.IsExpired()) + { + m_refillEvent = Simulator::Schedule(m_RefillInterval, &LeakyBucket::Refill, this); + } + } + + bool LeakyBucket::isFull() + { + NS_LOG_FUNCTION(this); + return m_availableTokens == m_capacity; + } +} \ No newline at end of file diff --git a/src/dcb/model/leaky-bucket.h b/src/dcb/model/leaky-bucket.h new file mode 100644 index 0000000000..bc17d7d08a --- /dev/null +++ b/src/dcb/model/leaky-bucket.h @@ -0,0 +1,41 @@ +#ifndef LEAKY_BUCKET_H +#define LEAKY_BUCKET_H + +#include "ns3/data-rate.h" +#include "ns3/event-id.h" +#include "ns3/nstime.h" +#include "ns3/object.h" + +namespace ns3 +{ + +class LeakyBucket : public Object +{ + public: + static TypeId GetTypeId(); + LeakyBucket(); + LeakyBucket(DataRate rate, uint32_t capacity,Callback cb); + + virtual ~LeakyBucket(); + + void Pause(); + void Resume(); + bool isFull(); + + void Consume(uint32_t bytes); + bool CanConsume(uint32_t bytes); + void SetRefillCallback(Callback cb); + private: + DataRate m_rate; + uint32_t m_capacity; // in bytes + uint32_t m_availableTokens; // in bytes + + Time m_RefillInterval; + uint32_t m_RefillAmount; // in bytes + EventId m_refillEvent; + + Callback m_RefillCallback; + void Refill(); +}; +} +#endif diff --git a/src/dcb/model/pausable-queue-disc.cc b/src/dcb/model/pausable-queue-disc.cc index e92d14e1b4..3521e14d42 100644 --- a/src/dcb/model/pausable-queue-disc.cc +++ b/src/dcb/model/pausable-queue-disc.cc @@ -244,7 +244,7 @@ PausableQueueDisc::DoEnqueue(Ptr item) priority = RoCEv2Socket::IpTos2Priority(ipv4Qdi->GetHeader().GetTos()); } NS_ASSERT_MSG(priority < DcbTrafficControl::PRIORITY_NUMBER, - "Priority should be 0~" << DcbTrafficControl::PRIORITY_NUMBER - 1 +"Priority should be 0~" << DcbTrafficControl::PRIORITY_NUMBER - 1 << " but here we have " << priority); Ptr qdiscClass = GetQueueDiscClass(priority); @@ -300,7 +300,31 @@ PausableQueueDisc::DoDequeue() // for (uint32_t i = m_priorityToInnerQueue.size() - 1; i-- > 0;) for (auto it = m_priorityToInnerQueue.rbegin(); it != m_priorityToInnerQueue.rend(); ++it) { - // std::cout << "Try priority: " << it->first << std::endl; + //find the minimum packet size among all queues in this priority + // if the minimum packet size is larger than the available tokens in the leaky bucket, + // we skip this priority + uint32_t consume_size=INT32_MAX; + uint32_t prio=it->first; + for(uint32_t i=0;i qdclass = GetQueueDiscClass(innerQueueIndex); + if((!m_fcEnabled || !qdclass->IsPaused())){ + if (qdclass->GetQueueDisc()->GetNBytes()>0){ + consume_size=std::min(consume_size,qdclass->GetQueueDisc()->Peek()->GetPacket()->GetSize()); + } + } + } + + // 检查该优先级是否有leaky bucket + auto leakyBucketIt = m_priorityToLeakyBucket.find(prio); + if(leakyBucketIt != m_priorityToLeakyBucket.end()){ + NS_ASSERT(leakyBucketIt->second != nullptr); + if(leakyBucketIt->second->CanConsume(consume_size)==false){ + //This prio is rate limited now, skip it + continue; + } + } + for (uint32_t j = 0; j < it->second.size(); j++) { uint32_t innerQueueIndex = it->second[j]; @@ -374,7 +398,15 @@ PausableQueueDisc::DoDequeue() } qdclass->DecrementCredit(item->GetPacket()->GetSize()); - if (!m_tcEgress.IsNull()) + + + auto leakyBucketIt = m_priorityToLeakyBucket.find(selectedPriority); + if(leakyBucketIt != m_priorityToLeakyBucket.end()){ + NS_ASSERT(leakyBucketIt->second != nullptr); + leakyBucketIt->second->Consume(item->GetPacket()->GetSize()); + } + + if(!m_tcEgress.IsNull()) m_tcEgress(m_portIndex, selectedPriority, item->GetPacket()); return item; } @@ -491,26 +523,12 @@ PausableQueueDisc::SetWdrrParameters(std::vector priorities, // Constuct the m_priorityToInnerQueue for (uint32_t i = 0; i < priorities.size(); i++) { + // 去掉硬编码的leaky bucket创建逻辑 + // m_priorityToLeakyBucket[priorities[i]] = LeakyBucket(DataRate("5Gbps"), 10000,MakeCallback(&PausableQueueDisc::Run,this)); m_priorityToInnerQueue[priorities[i]].push_back(i); Ptr qdclass = GetQueueDiscClass(i); qdclass->SetWdrrParameters(quantum[i] * 1000, maxCredit * 1000); } - - // cout the priorities and quantum - // for (uint32_t i = 0; i < GetNQueueDiscClasses(); i++) - // { - // std::cout << "Priority: " << priorities[i] << ", Quantum: " << quantum[i] << std::endl; - // } - // cout the m_priorityToInnerQueue - // for (auto it = m_priorityToInnerQueue.begin(); it != m_priorityToInnerQueue.end(); ++it) - // { - // std::cout << "Priority: " << it->first << ", Inner queues: "; - // for (uint32_t i = 0; i < it->second.size(); i++) - // { - // std::cout << it->second[i] << " "; - // } - // std::cout << std::endl; - // } } void @@ -520,7 +538,34 @@ PausableQueueDisc::SetDefaultStrictPriority() for (uint32_t i = 0; i < GetNQueueDiscClasses(); i++) { m_priorityToInnerQueue[i].push_back(i); + // 去掉硬编码的leaky bucket创建逻辑 + // m_priorityToLeakyBucket[i] = LeakyBucket(DataRate("5Gbps"), 10000,MakeCallback(&PausableQueueDisc::Run,this)); + } +} + +// 添加设置优先级限速的方法 +void +PausableQueueDisc::SetPriorityRateLimits(const std::vector>& rateLimits) +{ + NS_LOG_FUNCTION(this); + + // 首先清空现有的限速配置 + m_priorityToLeakyBucket.clear(); + + // 根据传入的配置设置限速 + for (const auto& rateLimit : rateLimits) + { + uint32_t priority = std::get<0>(rateLimit); + std::string rate = std::get<1>(rateLimit); + uint32_t burstSize = std::get<2>(rateLimit); + + // 创建新的leaky bucket + DataRate dataRate(rate); + Ptr leakyBucket = CreateObject(dataRate, burstSize, MakeCallback(&PausableQueueDisc::Run, this)); + m_priorityToLeakyBucket[priority] = leakyBucket; } + + // 没设置ratelimit的优先级对应的ptr自动为null(因为不在map中) } std::shared_ptr @@ -585,7 +630,6 @@ PausableQueueDisc::Stats::CollectAndCheck() vQueueStats.emplace_back(qd->GetStats()); } } - TypeId PausableQueueDiscClass::GetTypeId() { @@ -648,4 +692,4 @@ PausableQueueDiscClass::HasCredit() const return m_credit >= 0; } -} // namespace ns3 +} // namespace ns3 \ No newline at end of file diff --git a/src/dcb/model/pausable-queue-disc.h b/src/dcb/model/pausable-queue-disc.h index 2fcdf3f126..b6072a5900 100644 --- a/src/dcb/model/pausable-queue-disc.h +++ b/src/dcb/model/pausable-queue-disc.h @@ -26,7 +26,9 @@ #include "ns3/queue-disc.h" #include "ns3/queue-item.h" #include "ns3/type-id.h" +#include "leaky-bucket.h" +class LeakyBucket; namespace ns3 { @@ -163,7 +165,7 @@ class PausableQueueDisc : public QueueDisc * \brief Default configuration, construct a strict priority m_priorityToInnerQueue. */ void SetDefaultStrictPriority(); - + void SetPriorityRateLimits(const std::vector>& rateLimits); protected: Ptr m_node; //!< Node owning this NetDevice @@ -197,8 +199,11 @@ class PausableQueueDisc : public QueueDisc /***** Members for WDRR *****/ std::map> m_priorityToInnerQueue; //> + m_priorityToLeakyBucket; //() + .SetGroupName("Dcb") + .AddConstructor(); + return tid; +} +RoCEv2CreditSpary::RoCEv2CreditSpary() +{ + NS_LOG_FUNCTION(this); + RegisterCongestionType(GetTypeId()); +} + +RoCEv2CreditSpary::~RoCEv2CreditSpary() +{ + NS_LOG_FUNCTION(this); +} + +void RoCEv2CreditSpary::UpdateStateWithGenACK(Ptr packet, Ptr ackPacket) +{ + NS_LOG_FUNCTION(this << packet << ackPacket); + PathTag pathTag; + NS_ASSERT(packet->PeekPacketTag(pathTag)); + pathTag.forward=false; + ackPacket->AddPacketTag(pathTag); +} +} \ No newline at end of file diff --git a/src/dcb/model/rocev2-credit-spary.h b/src/dcb/model/rocev2-credit-spary.h new file mode 100644 index 0000000000..9ec41ccb85 --- /dev/null +++ b/src/dcb/model/rocev2-credit-spary.h @@ -0,0 +1,28 @@ +#ifndef ROCERV2_CREDIT_SPARY_H +#define ROCERV2_CREDIT_SPARY_H + +#include "rocev2-nocc.h" + +namespace ns3 +{ + +class RoCEv2SocketState; + +class RoCEv2CreditSpary : public RoCEv2Nocc +{ + public: + /** + * Get the type ID. + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId(); + + RoCEv2CreditSpary(); + + ~RoCEv2CreditSpary() override; + + void UpdateStateWithGenACK(Ptr packet, Ptr ackPacket) override; +}; +} // namespace ns3 +#endif // ROCERV2_CREDIT_SPARY_H \ No newline at end of file diff --git a/src/dcb/model/rocev2-nocc.cc b/src/dcb/model/rocev2-nocc.cc index be1bc2e0ca..2922a9383f 100644 --- a/src/dcb/model/rocev2-nocc.cc +++ b/src/dcb/model/rocev2-nocc.cc @@ -30,6 +30,53 @@ NS_LOG_COMPONENT_DEFINE("RoCEv2Nocc"); NS_OBJECT_ENSURE_REGISTERED(RoCEv2Nocc); +TypeId +RoCEv2Nocc::GetTypeId(void) +{ + static TypeId tid = TypeId("ns3::RoCEv2Nocc") + .SetParent() + .AddConstructor() + .SetGroupName("Dcb") + .AddAttribute("FairShare", + "Set the rate to the fair share", + BooleanValue(false), + MakeBooleanAccessor(&RoCEv2Nocc::m_fairShare), + MakeBooleanChecker()) + .AddAttribute("TargetInflight", + "Set the target inflight", + DoubleValue(1.0), + MakeDoubleAccessor(&RoCEv2Nocc::m_targetInflight), + MakeDoubleChecker()); + return tid; +} + +RoCEv2Nocc::RoCEv2Nocc() + : RoCEv2CongestionOps(std::make_shared()), + m_stats(std::dynamic_pointer_cast(RoCEv2CongestionOps::m_stats)) +{ + Init(); +} + +RoCEv2Nocc::RoCEv2Nocc(Ptr sockState) + : RoCEv2CongestionOps(sockState, std::make_shared()), + m_stats(std::dynamic_pointer_cast(RoCEv2CongestionOps::m_stats)) +{ + Init(); +} + +std::string +RoCEv2Nocc::GetName() const +{ + return "NoCC"; +} + +void +RoCEv2Nocc::Init() +{ + m_fairShare = false; + RegisterCongestionType(GetTypeId()); +} + void RoCEv2Nocc::SetReady() { @@ -56,4 +103,4 @@ RoCEv2Nocc::SetReady() } } -} // namespace ns3 +} // namespace ns3 \ No newline at end of file diff --git a/src/dcb/model/rocev2-nocc.h b/src/dcb/model/rocev2-nocc.h index de20e86394..bdad735b13 100644 --- a/src/dcb/model/rocev2-nocc.h +++ b/src/dcb/model/rocev2-nocc.h @@ -38,43 +38,13 @@ class RoCEv2Nocc : public RoCEv2CongestionOps * \brief Get the type ID. * \return the object TypeId */ - static TypeId GetTypeId(void) - { - static TypeId tid = TypeId("ns3::RoCEv2Nocc") - .SetParent() - .AddConstructor() - .SetGroupName("Dcb") - .AddAttribute("FairShare", - "Set the rate to the fair share", - BooleanValue(false), - MakeBooleanAccessor(&RoCEv2Nocc::m_fairShare), - MakeBooleanChecker()) - .AddAttribute("TargetInflight", - "Set the target inflight", - DoubleValue(1.0), - MakeDoubleAccessor(&RoCEv2Nocc::m_targetInflight), - MakeDoubleChecker()); - return tid; - } + static TypeId GetTypeId(void); - RoCEv2Nocc() - : RoCEv2CongestionOps(std::make_shared()), - m_stats(std::dynamic_pointer_cast(RoCEv2CongestionOps::m_stats)) - { - Init(); - } + RoCEv2Nocc(); - RoCEv2Nocc(Ptr sockState) - : RoCEv2CongestionOps(sockState, std::make_shared()), - m_stats(std::dynamic_pointer_cast(RoCEv2CongestionOps::m_stats)) - { - Init(); - } + RoCEv2Nocc(Ptr sockState); - std::string GetName() const override - { - return "NoCC"; - } + std::string GetName() const override; inline std::shared_ptr GetStats() const { @@ -82,11 +52,7 @@ class RoCEv2Nocc : public RoCEv2CongestionOps return nullptr; } - void Init() - { - m_fairShare = false; - RegisterCongestionType(GetTypeId()); - } + void Init(); virtual void SetReady() override; @@ -99,4 +65,4 @@ class RoCEv2Nocc : public RoCEv2CongestionOps } // namespace ns3 -#endif // NOCC_H +#endif // NOCC_H \ No newline at end of file diff --git a/src/dcb/model/rocev2-prioplus-swift.cc b/src/dcb/model/rocev2-prioplus-swift.cc index 265cffd141..25a236fd99 100644 --- a/src/dcb/model/rocev2-prioplus-swift.cc +++ b/src/dcb/model/rocev2-prioplus-swift.cc @@ -897,7 +897,7 @@ RoCEv2PrioplusSwift::SetPriorityConfig() std::vector> linearStartRatioArray; for (auto& [key, value] : configJsonObj["LinearStartRateRatio"].as_object()) { - linearStartRatioArray.push_back(std::make_pair(std::stod(key), value.as_double())); + linearStartRatioArray.push_back(std::make_pair(std::stod(std::string(key)), value.as_double())); } // Set the linear start ratio accoding priority ratio for (auto& [linearStartRatio, priorityRatio] : linearStartRatioArray) diff --git a/src/dcb/model/switch-node.cc b/src/dcb/model/switch-node.cc index f78d2db343..d0ba3abc94 100644 --- a/src/dcb/model/switch-node.cc +++ b/src/dcb/model/switch-node.cc @@ -5,6 +5,7 @@ #include "ns3/ipv4-global-routing.h" #include "ns3/point-to-point-net-device.h" #include "ns3/traffic-control-layer.h" +#include "ns3/ipv4-global-routing.h" namespace ns3 { @@ -122,11 +123,28 @@ SwitchNode::GetEgressDevIndex(Ptr packet) } void -SwitchNode::SendIpv4Packet(Ptr packet) +SwitchNode::SendIpv4Packet(Ptr inDev, Ptr packet) { uint32_t devIdx = GetEgressDevIndex(packet); + PathTag pathTag; + if(packet->PeekPacketTag(pathTag)) + { + if(pathTag.forward){ + pathTag.AppendInterfaceIndex(inDev->GetIfIndex()); + packet->ReplacePacketTag(pathTag); + } + else{ + devIdx=pathTag.PopInterfaceIndex(); + packet->ReplacePacketTag(pathTag); + } + } + else{ + pathTag.forward=true; + pathTag.AppendInterfaceIndex(inDev->GetIfIndex()); + packet->AddPacketTag(pathTag); + }//first hop auto dev = GetDevice(devIdx); - + Ipv4Header ipv4H; packet->RemoveHeader(ipv4H); ipv4H.SetTtl(ipv4H.GetTtl() - 1); @@ -172,7 +190,7 @@ SwitchNode::ReceiveFromDevice(Ptr device, void SwitchNode::ReceiveIpv4Packet(Ptr inDev, Ptr packet) { - SendIpv4Packet(packet->Copy()); + SendIpv4Packet(inDev,packet->Copy()); } void @@ -184,7 +202,7 @@ SwitchNode::ReceivePacketAfterTc(Ptr dev, NetDevice::PacketType packetType) { NS_LOG_FUNCTION(this << dev << protocol << from << to); - SendIpv4Packet(packet->Copy()); + SendIpv4Packet(dev,packet->Copy()); } } // namespace ns3 diff --git a/src/dcb/model/switch-node.h b/src/dcb/model/switch-node.h index d0ba54eb88..9774e815c3 100644 --- a/src/dcb/model/switch-node.h +++ b/src/dcb/model/switch-node.h @@ -7,7 +7,7 @@ #include "ns3/packet.h" #include "ns3/tcp-header.h" #include "ns3/udp-header.h" - +#include namespace ns3 { @@ -30,7 +30,7 @@ class SwitchNode : public Node protected: void DoInitialize() override; uint32_t GetEgressDevIndex(Ptr packet); // returns ECMP calculated egress port - void SendIpv4Packet(Ptr packet); + void SendIpv4Packet(Ptr inDev, Ptr packet); virtual void ReceiveIpv4Packet(Ptr inDev, Ptr packet); private: diff --git a/src/internet/CMakeLists.txt b/src/internet/CMakeLists.txt index c3e8e83781..e85b4b2f3a 100644 --- a/src/internet/CMakeLists.txt +++ b/src/internet/CMakeLists.txt @@ -349,4 +349,4 @@ build_lib( ${libbridge} ${libtraffic-control} TEST_SOURCES ${test_sources} -) +) \ No newline at end of file diff --git a/src/internet/model/ipv4-global-routing.cc b/src/internet/model/ipv4-global-routing.cc index ecfc3a84c9..86a60b75cd 100644 --- a/src/internet/model/ipv4-global-routing.cc +++ b/src/internet/model/ipv4-global-routing.cc @@ -41,6 +41,7 @@ #include "udp-header.h" #include "ns3/uinteger.h" +#include "ns3/rocev2-credit-spary.h" namespace ns3 { @@ -57,10 +58,10 @@ Ipv4GlobalRouting::GetTypeId() .SetParent() .SetGroupName("Internet") .AddAttribute("RandomEcmpRouting", - "Set according to EcmpMode (NONE, PER_PACKET_ECMP, PER_FLOW_ECMP)", + "Set according to EcmpMode (NONE, PER_PACKET_ECMP, PER_FLOW_ECMP, PER_PACKET_SYMMETRIC_ECMP) ", UintegerValue(0), MakeUintegerAccessor(&Ipv4GlobalRouting::m_randomEcmpRouting), - MakeUintegerChecker(0, 2)) + MakeUintegerChecker(0, 3)) .AddAttribute("RespondToInterfaceEvents", "Set to true if you want to dynamically recompute the global routes upon " "Interface notification events (up/down, or add/remove address)", @@ -239,6 +240,38 @@ Ipv4GlobalRouting::LookupGlobal(Ipv4Header header, Ptr p, PtrGetInteger(0, allRoutes.size() - 1); + // }//for init topo build + // else{ + // Ptr p_modify_tag=ConstCast(p); + // PathTag tag; + // if (p_modify_tag->PeekPacketTag(tag)) { + // if (tag.forward) { + // uint32_t interfaceIndex=oif->GetIfIndex(); + // selectIndex=m_rand->GetInteger(0, allRoutes.size() - 1); + // tag.AppendInterfaceIndex(interfaceIndex); + // p_modify_tag->ReplacePacketTag(tag); + // } + // else{ + // uint32_t interfaceIndex=tag.PopInterfaceIndex(); + // p_modify_tag->ReplacePacketTag(tag); + // for (uint32_t i=0;iGetInterface()==interfaceIndex){ + // selectIndex=i; + // break; + // } + // } + // } + // } + // else{ + // selectIndex = m_rand->GetInteger(0, allRoutes.size() - 1); + // tag.forward=true; + // tag.AppendInterfaceIndex(oif->GetIfIndex()); + // p_modify_tag->AddPacketTag(tag); + // }} + // }break; } } @@ -659,4 +692,74 @@ Ipv4GlobalRouting::UdpEcmp(const Ipv4Header& header, return Hash32(buf._b, HASH_BUF_SIZE) % totalRoutes; } +PathTag::PathTag() +{ +} + +PathTag::~PathTag() +{ +} + +TypeId +PathTag::GetTypeId(){ + static TypeId tid = TypeId("ns3::PathTag") + .SetParent() + .SetGroupName("Dcb") + .AddConstructor(); + return tid; +} + +TypeId +PathTag::GetInstanceTypeId() const{ + return PathTag::GetTypeId(); +} + +uint32_t +PathTag::GetSerializedSize() const{ + return m_path_device_interface_indexes.size() * sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint8_t); +} + +void +PathTag::Serialize(TagBuffer i) const{ + i.WriteU8(static_cast(forward)); + i.WriteU32(m_path_length); + for (auto index : m_path_device_interface_indexes) + { + i.WriteU32(index); + } +} + +void +PathTag::Deserialize(TagBuffer i){ + m_path_device_interface_indexes.clear(); + forward = i.ReadU8() != 0; + m_path_length = i.ReadU32(); + for (uint32_t j = 0; j < m_path_length; j++) + { + m_path_device_interface_indexes.push_back(i.ReadU32()); + } +} + +void +PathTag::Print(std::ostream& os) const{ + os << "PathTag: "; + for (auto index : m_path_device_interface_indexes) + { + os << index << " "; + } +} + +void +PathTag::AppendInterfaceIndex(uint32_t index){ + m_path_device_interface_indexes.push_back(index); + m_path_length= m_path_device_interface_indexes.size(); +} + +uint32_t PathTag::PopInterfaceIndex(){ + NS_ASSERT(!m_path_device_interface_indexes.empty()); + uint32_t index = m_path_device_interface_indexes.back(); + m_path_device_interface_indexes.pop_back(); + m_path_length= m_path_device_interface_indexes.size(); + return index; +} } // namespace ns3 \ No newline at end of file diff --git a/src/internet/model/ipv4-global-routing.h b/src/internet/model/ipv4-global-routing.h index d7d21907ed..3dda625552 100644 --- a/src/internet/model/ipv4-global-routing.h +++ b/src/internet/model/ipv4-global-routing.h @@ -26,6 +26,7 @@ #include "ns3/ipv4-address.h" #include "ns3/ptr.h" #include "ns3/random-variable-stream.h" +#include "ns3/rocev2-credit-spary.h" #include #include @@ -237,6 +238,7 @@ class Ipv4GlobalRouting : public Ipv4RoutingProtocol NONE, PER_PACKET_ECMP, PER_FLOW_ECMP, + //PER_PACKET_SYMMETRIC_ECMP }; protected: @@ -308,6 +310,26 @@ class Ipv4GlobalRouting : public Ipv4RoutingProtocol Ptr m_ipv4; //!< associated IPv4 instance }; +class PathTag: public Tag +{ + public: + PathTag(); + ~PathTag() override; + static TypeId GetTypeId(); + virtual TypeId GetInstanceTypeId() const override; + virtual uint32_t GetSerializedSize() const override; + virtual void Serialize(TagBuffer i) const override; + virtual void Deserialize(TagBuffer i) override; + virtual void Print(std::ostream& os) const override; + + void AppendInterfaceIndex(uint32_t index); + uint32_t PopInterfaceIndex(); + bool forward;//switch append path when forward, otherwise, pop path to select next hop + private: + std::vector m_path_device_interface_indexes; + uint32_t m_path_length; +}; + } // Namespace ns3 #endif /* IPV4_GLOBAL_ROUTING_H */ \ No newline at end of file diff --git a/src/json-util/helper/json-application-helper.cc b/src/json-util/helper/json-application-helper.cc index c96b4cca6a..fe62d6b549 100644 --- a/src/json-util/helper/json-application-helper.cc +++ b/src/json-util/helper/json-application-helper.cc @@ -312,7 +312,7 @@ SetGroupAttributes(const boost::json::object& gConf, // Iterate over the attributes in the group for (auto kvPair : gConf) { - std::string name = kvPair.key(); + std::string name(kvPair.key()); if (name == "groupSize" || name == "applicationNumber") { continue; diff --git a/src/json-util/helper/json-topology-helper.cc b/src/json-util/helper/json-topology-helper.cc index 5c7b843b4e..4a5825b272 100644 --- a/src/json-util/helper/json-topology-helper.cc +++ b/src/json-util/helper/json-topology-helper.cc @@ -116,11 +116,30 @@ ConstructFcHelper(const boost::json::object& fcConfig) JsonCallIfExistsString(fcConfig, "quantumVec", [fcHelper](std::string quantumVec) { fcHelper->SetQuantum(ConvertRangeToVector(quantumVec.c_str(), fcHelper->GetNumQueuePerPort())); }); + JsonCallIfExistsInt( fcConfig, "maxCredit", [fcHelper](uint32_t maxCredit) { fcHelper->SetMaxCredit(maxCredit); }); + // Parse and set priority rate limits if they exist + JsonCallIfExistsArray(fcConfig, "prioRateLimits", [fcHelper](const boost::json::array& rateLimitsArray) { + std::vector> rateLimits; + for (const auto& rateLimitObj : rateLimitsArray) + { + if (!rateLimitObj.is_object()) + { + NS_FATAL_ERROR("prioRateLimits array element must be an object"); + } + const auto& obj = rateLimitObj.get_object(); + uint32_t priority = JsonGetInt64OrRaise(obj, "priority", "priority is required in prioRateLimits"); + std::string rate = JsonGetStringOrRaise(obj, "rate", "rate is required in prioRateLimits"); + uint32_t burstSize = JsonGetInt64OrRaise(obj, "burstSize", "burstSize is required in prioRateLimits"); + rateLimits.emplace_back(priority, rate, burstSize); + } + fcHelper->SetPrioRateLimit(rateLimits); + }); + return fcHelper; } @@ -503,4 +522,4 @@ BuildTopology(boost::json::object& configObj) } // namespace json_util -} // namespace ns3 +} // namespace ns3 \ No newline at end of file diff --git a/src/json-util/model/json-configs.cc b/src/json-util/model/json-configs.cc index 9d83abdfbc..78b449fad4 100644 --- a/src/json-util/model/json-configs.cc +++ b/src/json-util/model/json-configs.cc @@ -59,11 +59,11 @@ SetDefault(boost::json::object& defaultObj) { // kvPair is the first level pair // kvPair contains {Class: {Attribute: Value}} - std::string className = kvPair.key(); + std::string className(kvPair.key()); boost::json::object subObj = kvPair.value().get_object(); for (auto subKvPair : subObj) { - std::string attributeName = subKvPair.key(); + std::string attributeName(subKvPair.key()); boost::json::value value = subKvPair.value(); switch (value.kind()) { @@ -101,7 +101,7 @@ SetGlobal(boost::json::object& globalObj) for (auto kvPair : globalObj) { // kvPair are {Name: Value} - std::string name = kvPair.key(); + std::string name(kvPair.key()); boost::json::value value = kvPair.value(); switch (value.kind()) { diff --git a/src/json-util/utils/json-utils.cc b/src/json-util/utils/json-utils.cc index 193ae86c89..d5a7877814 100644 --- a/src/json-util/utils/json-utils.cc +++ b/src/json-util/utils/json-utils.cc @@ -264,7 +264,7 @@ ConstructConfigVector(const boost::json::object& configObj) // Each value is .Copy() to get Ptr as it is forbidden to construct directly for (auto kvPair : configObj) { - std::string name = kvPair.key(); + std::string name(kvPair.key()); boost::json::value value = kvPair.value(); switch (value.kind()) { diff --git a/src/json-util/utils/json-utils.h b/src/json-util/utils/json-utils.h index ead9e00418..e65f4d43bf 100644 --- a/src/json-util/utils/json-utils.h +++ b/src/json-util/utils/json-utils.h @@ -220,8 +220,29 @@ JsonCallIfExistsBool(const boost::json::object& obj, return true; } +inline bool +JsonCallIfExistsArray(const boost::json::object& obj, + std::string field, + std::function callback) +{ + boost::json::object::const_iterator subobj = obj.find(field); + if (subobj == obj.end()) + { + return false; + } + try + { + callback(subobj->value().get_array()); + return true; + } + catch (const std::exception& err) + { + return false; + } +} + } // namespace json_util } // namespace ns3 -#endif /* JSON_UTILS_H */ +#endif /* JSON_UTILS_H */ \ No newline at end of file diff --git a/throughput_results.json b/throughput_results.json new file mode 100644 index 0000000000..9e71954e9f --- /dev/null +++ b/throughput_results.json @@ -0,0 +1,86 @@ +{ + "1": { + "1": { + "throughput_bitps_sum": 51200000000.0, + "throughput_gb_sum": 6.4 + }, + "2": { + "throughput_bitps_sum": 843200000000.0, + "throughput_gb_sum": 105.4 + }, + "3": { + "throughput_bitps_sum": 0.0, + "throughput_gb_sum": 0.0 + }, + "4": { + "throughput_bitps_sum": 0.0, + "throughput_gb_sum": 0.0 + }, + "5": { + "throughput_bitps_sum": 0.0, + "throughput_gb_sum": 0.0 + } + }, + "2": { + "1": { + "throughput_bitps_sum": 51200000000.0, + "throughput_gb_sum": 6.4 + }, + "2": { + "throughput_bitps_sum": 843200000000.0, + "throughput_gb_sum": 105.4 + } + }, + "3": { + "1": { + "throughput_bitps_sum": 0.0, + "throughput_gb_sum": 0.0 + }, + "2": { + "throughput_bitps_sum": 0.0, + "throughput_gb_sum": 0.0 + } + }, + "4": { + "1": { + "throughput_bitps_sum": 0.0, + "throughput_gb_sum": 0.0 + }, + "2": { + "throughput_bitps_sum": 0.0, + "throughput_gb_sum": 0.0 + } + }, + "5": { + "1": { + "throughput_bitps_sum": 0.0, + "throughput_gb_sum": 0.0 + }, + "2": { + "throughput_bitps_sum": 0.0, + "throughput_gb_sum": 0.0 + } + }, + "6": { + "1": { + "throughput_bitps_sum": 51200000000.0, + "throughput_gb_sum": 6.4 + }, + "2": { + "throughput_bitps_sum": 0.0, + "throughput_gb_sum": 0.0 + }, + "3": { + "throughput_bitps_sum": 0.0, + "throughput_gb_sum": 0.0 + }, + "4": { + "throughput_bitps_sum": 0.0, + "throughput_gb_sum": 0.0 + }, + "5": { + "throughput_bitps_sum": 843200000000.0, + "throughput_gb_sum": 105.4 + } + } +} \ No newline at end of file