From df2af9fd4f0161c707439810ac581921fe082af3 Mon Sep 17 00:00:00 2001 From: Pavel Ralnikov Date: Thu, 30 Apr 2026 16:27:11 +0300 Subject: [PATCH 01/10] Start RDMA realization --- configs/scenario-configs.txt | 1 + configs/simple/rdma_network.yml | 9 + configs/simple/rdma_scenario.yml | 8 + .../{mplb/rdma => rdma/dcqcn}/dcqcn.cpp | 0 .../{mplb/rdma => rdma/dcqcn}/dcqcn.hpp | 0 .../connection/rdma/rdma_connection.cpp | 246 ++++++++++++++++++ .../connection/rdma/rdma_connectrion.hpp | 98 +++++++ .../network/connection/connection_parser.cpp | 3 + .../network/connection/dcqcn_parser.cpp | 9 + .../network/connection/dcqcn_parser.hpp | 7 + .../connection/rdma_connection_parser.cpp | 33 +++ .../connection/rdma_connection_parser.hpp | 12 + test/connection/rdma/dcqcn_test.cpp | 2 +- 13 files changed, 427 insertions(+), 1 deletion(-) create mode 100644 configs/simple/rdma_network.yml create mode 100644 configs/simple/rdma_scenario.yml rename source/network/connection/{mplb/rdma => rdma/dcqcn}/dcqcn.cpp (100%) rename source/network/connection/{mplb/rdma => rdma/dcqcn}/dcqcn.hpp (100%) create mode 100644 source/network/connection/rdma/rdma_connection.cpp create mode 100644 source/network/connection/rdma/rdma_connectrion.hpp create mode 100644 source/parser/network/connection/dcqcn_parser.cpp create mode 100644 source/parser/network/connection/dcqcn_parser.hpp create mode 100644 source/parser/network/connection/rdma_connection_parser.cpp create mode 100644 source/parser/network/connection/rdma_connection_parser.hpp diff --git a/configs/scenario-configs.txt b/configs/scenario-configs.txt index e3cdef51aa..661d0a7236 100644 --- a/configs/scenario-configs.txt +++ b/configs/scenario-configs.txt @@ -2,4 +2,5 @@ fat-tree/scenario.yml incast/scenario.yml leaf-spine/scenario.yml simple/scenario.yml +simple/rdma_scenario.yml single-rack/scenario.yml diff --git a/configs/simple/rdma_network.yml b/configs/simple/rdma_network.yml new file mode 100644 index 0000000000..7f69cb8363 --- /dev/null +++ b/configs/simple/rdma_network.yml @@ -0,0 +1,9 @@ +topology_config_path: topology.yml +type: custom + +connections: + connection: + type: rdma + sender_id: sender + receiver_id: receiver + dcqcn: {} \ No newline at end of file diff --git a/configs/simple/rdma_scenario.yml b/configs/simple/rdma_scenario.yml new file mode 100644 index 0000000000..702e9b5181 --- /dev/null +++ b/configs/simple/rdma_scenario.yml @@ -0,0 +1,8 @@ +network_config_path: rdma_network.yml + +scenario: +- action: send_data + id: send + when: 0ns + size: 4500B + connections: connection diff --git a/source/network/connection/mplb/rdma/dcqcn.cpp b/source/network/connection/rdma/dcqcn/dcqcn.cpp similarity index 100% rename from source/network/connection/mplb/rdma/dcqcn.cpp rename to source/network/connection/rdma/dcqcn/dcqcn.cpp diff --git a/source/network/connection/mplb/rdma/dcqcn.hpp b/source/network/connection/rdma/dcqcn/dcqcn.hpp similarity index 100% rename from source/network/connection/mplb/rdma/dcqcn.hpp rename to source/network/connection/rdma/dcqcn/dcqcn.hpp diff --git a/source/network/connection/rdma/rdma_connection.cpp b/source/network/connection/rdma/rdma_connection.cpp new file mode 100644 index 0000000000..633ee62897 --- /dev/null +++ b/source/network/connection/rdma/rdma_connection.cpp @@ -0,0 +1,246 @@ +#include "rdma_connectrion.hpp" +#include "scheduler/scheduler.hpp" +#include "utils/defer.hpp" + +namespace sim { + +RdmaConnectionPtr RdmaConnection::create_shared(const Id& a_id, + const DCQCN& a_dcqcn, + const FlowFourTuple& a_ft) { + return RdmaConnectionPtr(new RdmaConnection(a_id, a_dcqcn, a_ft)); +} + +[[nodiscard]] utils::StrExpected RdmaConnection::send_data( + Data data, OnDeliveryCallback callback) { + DataId data_id = data.id; + if (m_data_context_table.contains(data_id)) { + return std::unexpected( + fmt::format("Connection {}: could not add data {}: data with given " + "id already sent", + m_id, data.to_string())); + } + if (m_ctx.first_send_data_time == std::nullopt) { + m_ctx.first_send_data_time = + Scheduler::get_instance().get_current_time(); + } + m_data_context_table[data_id] = + DataContext{data.size, SizeByte(0ul), SizeByte(0ul), callback}; + m_ctx.total_data_added += data.size; + + SizeByte total_size(0ul); + if (data.size == SizeByte(0ul)) { + return std::unexpected(fmt::format( + "Rdma connection {}: could not send data with zero size", m_id)); + } + bool was_sending_queue_empty = m_send_queue.empty(); + while (total_size < data.size) { + m_send_queue.emplace_back(create_data_packet(data)); + total_size += m_packet_size; + } + if (was_sending_queue_empty) { + start_data_sending(); + } + return {}; +} + +ConnectionContext RdmaConnection::get_context() const { return m_ctx; } + +MetricsTable RdmaConnection::get_metrics_table() const { + return MetricsTable(); +} + +void RdmaConnection::write_inner_metrics( + [[maybe_unused]] std::filesystem::path output_dir) const {} + +const Id& RdmaConnection::get_id() const { return m_id; } + +RdmaConnection::RdmaConnection(const Id& a_id, const DCQCN& a_dcqcn, + const FlowFourTuple& a_ft) + : m_id(a_id), + m_dcqcn(a_dcqcn), + m_sender(a_ft.sender), + m_sender_port(a_ft.sender_port), + m_receiver(a_ft.receiver), + m_receiver_port(a_ft.receiver_port) {} + +void RdmaConnection::start_data_sending() { + m_dcqcn.start(); + schedule_data_send(); +} + +void RdmaConnection::schedule_data_send() { + Scheduler& sched = Scheduler::get_instance(); + TimeNs now = sched.get_current_time(); + + SpeedGbps rate = m_dcqcn.get_rate(); + TimeNs delay = m_packet_size / rate; + RdmaConnectionPtr conn = shared_from_this(); + sched.add(now + delay, [conn]() { conn->send_next_data_packet(); }); +} + +void RdmaConnection::send_next_data_packet() { + uint32_t i = m_pcn - m_last_acked_pcn - 1; + if (i >= m_send_queue.size()) { + LOG_INFO( + fmt::format("RDMA connection {}: send all packet from sending " + "queue; send ack request packet", + m_id)); + send_ack_request(); + return; + } + m_pcn++; + const Packet& data = m_send_queue[i]; + m_sender->enqueue_packet(data); + schedule_data_send(); +} + +Packet RdmaConnection::create_data_packet(const Data& data) { + Packet packet; + packet.packet_num = m_next_packet_num++; + + packet.data_id = std::move(data.id); + packet.sender_id = m_sender->get_id(); + packet.sender_port = m_sender_port; + packet.receiver_port = m_receiver_port; + packet.receiver_id = m_receiver->get_id(); + packet.size = m_packet_size; + + RdmaConnectionPtr conn = shared_from_this(); + + packet.callback = [conn](const Packet& delivered_packet) { + conn->process_data_packet(delivered_packet); + }; + TimeNs now = Scheduler::get_instance().get_current_time(); + packet.generated_time = now; + + packet.ecn_capable_transport = true; + packet.congestion_experienced = false; + return packet; +} + +void RdmaConnection::process_data_packet(const Packet& packet) { + if (packet.packet_num != m_next_expected_packet_num) { + LOG_ERROR( + fmt::format("RDMA receiver got data packet {} with number that " + "differs from expected {}; ignored", + packet.to_string(), m_next_expected_packet_num)); + // TODO: correct implementation for such case + return; + } + m_next_expected_packet_num++; + if (++m_data_packets_on_receiver >= m_ack_threshold) { + m_data_packets_on_receiver = 0; + send_ack(); + } +} + +void RdmaConnection::send_ack() { + Packet ack; + if (m_next_expected_packet_num == 0) { + LOG_ERROR( + fmt::format("RDMA connection {}: cold not send ack: next expected " + "packet num = 0", + m_id)); + return; + } + ack.packet_num = m_next_expected_packet_num - 1; + + ack.sender_id = m_receiver->get_id(); + ack.sender_port = m_receiver_port; + ack.receiver_port = m_sender_port; + ack.receiver_id = m_sender->get_id(); + ack.size = M_ACK_SIZE; + + RdmaConnectionPtr conn = shared_from_this(); + + ack.callback = [conn](const Packet& delivered_packet) { + conn->process_ack(delivered_packet); + }; + TimeNs now = Scheduler::get_instance().get_current_time(); + ack.generated_time = now; + ack.sent_time = now; + + ack.ecn_capable_transport = true; + ack.congestion_experienced = false; + + m_receiver->enqueue_packet(ack); +} + +void RdmaConnection::process_ack(const Packet& ack) { + PacketNum ack_num = ack.packet_num; + if (ack_num < m_last_acked_pcn) { + LOG_ERROR( + fmt::format("RDMA connection {}: sender got ack with number " + "smaller than last acked PCN", + m_id)); + return; + } + while (m_last_acked_pcn < ack_num) { + m_last_acked_pcn++; + confirm_first_unconfirmed_packet(); + } +} + +void RdmaConnection::confirm_first_unconfirmed_packet() { + if (m_send_queue.empty()) { + LOG_ERROR( + fmt::format("RDMA connection {}: could not confirm packet with " + "empty send queue", + m_id)); + return; + } + const Packet& confirmed = m_send_queue.front(); + utils::Defer defer([this]() { + m_send_queue.pop_front(); + if (m_send_queue.empty()) { + m_dcqcn.stop(); + } + }); + + const DataId& data_id = confirmed.data_id; + auto it = m_data_context_table.find(data_id); + if (it == m_data_context_table.end()) { + LOG_ERROR( + fmt::format("RDMA connection {}: could not find context that " + "connresponds to data {}", + m_id, data_id.to_string())); + return; + } + DataContext& data_ctx = it->second; + data_ctx.delivered += m_packet_size; + if (data_ctx.delivered >= data_ctx.total_size) { + LOG_INFO( + fmt::format("RDMA connection {} delivered data {}; call callback", + m_id, data_id)); + data_ctx.callback(); + } +} + +void RdmaConnection::send_ack_request() { + Packet ack_request; + ack_request.packet_num = m_next_packet_num++; + + ack_request.sender_id = m_sender->get_id(); + ack_request.sender_port = m_sender_port; + ack_request.receiver_port = m_receiver_port; + ack_request.receiver_id = m_receiver->get_id(); + ack_request.size = ACK_REQUEST_SIZE; + + RdmaConnectionPtr conn = shared_from_this(); + + ack_request.callback = + [conn]([[maybe_unused]] const Packet& delivered_packet) { + conn->process_ack_request(); + }; + TimeNs now = Scheduler::get_instance().get_current_time(); + ack_request.generated_time = now; + ack_request.sent_time = now; + + ack_request.ecn_capable_transport = true; + ack_request.congestion_experienced = false; + m_sender->enqueue_packet(ack_request); +} + +void RdmaConnection::process_ack_request() { send_ack(); } + +} // namespace sim \ No newline at end of file diff --git a/source/network/connection/rdma/rdma_connectrion.hpp b/source/network/connection/rdma/rdma_connectrion.hpp new file mode 100644 index 0000000000..d506331222 --- /dev/null +++ b/source/network/connection/rdma/rdma_connectrion.hpp @@ -0,0 +1,98 @@ +#pragma once +#include + +#include "../i_connection.hpp" +#include "dcqcn/dcqcn.hpp" +#include "network/connection/flow/flow_four_tuple.hpp" +#include "network/connection/flow/packet.hpp" +#include "topology/device/host.hpp" + +namespace sim { + +class RdmaConnection; + +using RdmaConnectionPtr = std::shared_ptr; + +class RdmaConnection : public IConnection, + public std::enable_shared_from_this { +public: + static RdmaConnectionPtr create_shared(const Id& a_id, const DCQCN& a_dcqcn, + const FlowFourTuple& a_ft); + + [[nodiscard]] virtual utils::StrExpected send_data( + Data data, OnDeliveryCallback callback) final; + + ConnectionContext get_context() const final; + + virtual MetricsTable get_metrics_table() const final; + + virtual void write_inner_metrics( + std::filesystem::path output_dir) const final; + + virtual const Id& get_id() const final; + +private: + RdmaConnection(const Id& a_id, const DCQCN& a_dcqcn, + const FlowFourTuple& a_endpoints); + + void start_data_sending(); + + void schedule_data_send(); + + void send_next_data_packet(); + + Packet create_data_packet(const Data& data); + + void process_data_packet(const Packet& data); + + void send_ack(); + + void process_ack(const Packet& ack); + + void confirm_first_unconfirmed_packet(); + + void send_ack_request(); + + void process_ack_request(); + + ConnectionContext m_ctx; + Id m_id; + DCQCN m_dcqcn; + + // --------------------sender part-------------------- + static constexpr SizeByte ACK_REQUEST_SIZE = SizeByte(1ul); + std::shared_ptr m_sender; + Port m_sender_port; + // TODO: make custom + SizeByte m_packet_size = SizeByte(1500ul); + + // Invariant: packet_num of first packet in this queue is equal to + // m_last_acked_pcn + std::deque m_send_queue; + + uint32_t m_send_window; + + // number of first packet that was not send + PacketNum m_pcn = 1; + PacketNum m_last_acked_pcn = 0; + PacketNum m_next_packet_num = 1; + + struct DataContext { + SizeByte total_size; + SizeByte sent; + SizeByte delivered; + OnDeliveryCallback callback; + }; + std::map m_data_context_table; + + // --------------------receiver part-------------------- + std::shared_ptr m_receiver; + Port m_receiver_port; + uint32_t m_data_packets_on_receiver = 0; + // TODO: make custom + uint32_t m_ack_threshold = 32; + PacketNum m_next_expected_packet_num = 1; + static constexpr SizeByte M_ACK_SIZE = SizeByte(1ul); +}; + +} // namespace sim \ No newline at end of file diff --git a/source/parser/network/connection/connection_parser.cpp b/source/parser/network/connection/connection_parser.cpp index 95bacf711d..5a39a2780d 100644 --- a/source/parser/network/connection/connection_parser.cpp +++ b/source/parser/network/connection/connection_parser.cpp @@ -2,6 +2,7 @@ #include "mplb/mplb_parser.hpp" #include "network/connection/connection.hpp" +#include "rdma_connection_parser.hpp" #include "utils/identifiable.hpp" namespace sim { @@ -25,6 +26,8 @@ std::shared_ptr parse_i_connection( params["type"].value_or_throw().as_or_throw(); if (type == "mplb-connection") { return parse_mplb_connection(sender, receiver, params, connection_id); + } else if (type == "rdma") { + return parse_rdma_connection(sender, receiver, params, connection_id); } throw params.create_parsing_error( fmt::format("Unsupported connection type: {}", type)); diff --git a/source/parser/network/connection/dcqcn_parser.cpp b/source/parser/network/connection/dcqcn_parser.cpp new file mode 100644 index 0000000000..c8d9acf057 --- /dev/null +++ b/source/parser/network/connection/dcqcn_parser.cpp @@ -0,0 +1,9 @@ +#include "dcqcn_parser.hpp" + +namespace sim { +DCQCN parse_dcqcn([[maybe_unused]] const ConfigNodeWithPreset& node) { + // TODO: implement correctlty + ParamsDQCCN params; + return DCQCN(params); +} +} // namespace sim \ No newline at end of file diff --git a/source/parser/network/connection/dcqcn_parser.hpp b/source/parser/network/connection/dcqcn_parser.hpp new file mode 100644 index 0000000000..5f75f668e1 --- /dev/null +++ b/source/parser/network/connection/dcqcn_parser.hpp @@ -0,0 +1,7 @@ +#pragma once +#include "network/connection/rdma/dcqcn/dcqcn.hpp" +#include "parser/config_reader/config_node_with_preset.hpp" + +namespace sim { +DCQCN parse_dcqcn(const ConfigNodeWithPreset& node); +} \ No newline at end of file diff --git a/source/parser/network/connection/rdma_connection_parser.cpp b/source/parser/network/connection/rdma_connection_parser.cpp new file mode 100644 index 0000000000..0a6c732437 --- /dev/null +++ b/source/parser/network/connection/rdma_connection_parser.cpp @@ -0,0 +1,33 @@ +#include "rdma_connection_parser.hpp" + +#include + +#include "dcqcn_parser.hpp" + +namespace sim { + +static EndpointPorts generate_ports() { + static constexpr size_t RANDOM_SEED = 31; + static std::mt19937 rnd(RANDOM_SEED); + + static constexpr size_t MAX_PORT = 5000; + + static std::uniform_int_distribution range(0, MAX_PORT); + return EndpointPorts(range(rnd), range(rnd)); +} + +RdmaConnectionPtr parse_rdma_connection(std::shared_ptr sender, + std::shared_ptr receiver, + const ConfigNodeWithPreset& params, + const Id& connection_id) { + static const ConfigNodeWithPreset& dcqcn_node = + params["dcqcn"].value_or_throw(); + + DCQCN dcqcn = parse_dcqcn(dcqcn_node); + + FlowFourTuple ft(Endpoints(sender, receiver), generate_ports()); + + return RdmaConnection::create_shared(connection_id, dcqcn, ft); +} + +} // namespace sim \ No newline at end of file diff --git a/source/parser/network/connection/rdma_connection_parser.hpp b/source/parser/network/connection/rdma_connection_parser.hpp new file mode 100644 index 0000000000..e6b04223b7 --- /dev/null +++ b/source/parser/network/connection/rdma_connection_parser.hpp @@ -0,0 +1,12 @@ +#pragma once +#include "network/connection/rdma/rdma_connectrion.hpp" +#include "parser/config_reader/config_node_with_preset.hpp" + +namespace sim { + +RdmaConnectionPtr parse_rdma_connection(std::shared_ptr sender, + std::shared_ptr receiver, + const ConfigNodeWithPreset& params, + const Id& connection_id); + +} \ No newline at end of file diff --git a/test/connection/rdma/dcqcn_test.cpp b/test/connection/rdma/dcqcn_test.cpp index 12b6421f72..4064b27f99 100644 --- a/test/connection/rdma/dcqcn_test.cpp +++ b/test/connection/rdma/dcqcn_test.cpp @@ -1,4 +1,4 @@ -#include "network/connection/mplb/rdma/dcqcn.hpp" +#include "network/connection/rdma/dcqcn/dcqcn.hpp" #include From 1da3d5c38763fb93168d220d026975c38e77d033 Mon Sep 17 00:00:00 2001 From: Pavel Ralnikov Date: Sat, 2 May 2026 14:16:02 +0300 Subject: [PATCH 02/10] Reorder buffer --- .../connection/rdma/rdma_connection.cpp | 64 +++++++++++++------ .../connection/rdma/rdma_connectrion.hpp | 26 +++++--- .../network/connection/rdma/rdma_params.hpp | 16 +++++ .../connection/rdma_connection_parser.cpp | 6 +- 4 files changed, 81 insertions(+), 31 deletions(-) create mode 100644 source/network/connection/rdma/rdma_params.hpp diff --git a/source/network/connection/rdma/rdma_connection.cpp b/source/network/connection/rdma/rdma_connection.cpp index 633ee62897..b0491722f5 100644 --- a/source/network/connection/rdma/rdma_connection.cpp +++ b/source/network/connection/rdma/rdma_connection.cpp @@ -4,10 +4,8 @@ namespace sim { -RdmaConnectionPtr RdmaConnection::create_shared(const Id& a_id, - const DCQCN& a_dcqcn, - const FlowFourTuple& a_ft) { - return RdmaConnectionPtr(new RdmaConnection(a_id, a_dcqcn, a_ft)); +RdmaConnectionPtr RdmaConnection::create_shared(const RdmaParams& a_params) { + return RdmaConnectionPtr(new RdmaConnection(a_params)); } [[nodiscard]] utils::StrExpected RdmaConnection::send_data( @@ -54,14 +52,16 @@ void RdmaConnection::write_inner_metrics( const Id& RdmaConnection::get_id() const { return m_id; } -RdmaConnection::RdmaConnection(const Id& a_id, const DCQCN& a_dcqcn, - const FlowFourTuple& a_ft) - : m_id(a_id), - m_dcqcn(a_dcqcn), - m_sender(a_ft.sender), - m_sender_port(a_ft.sender_port), - m_receiver(a_ft.receiver), - m_receiver_port(a_ft.receiver_port) {} +RdmaConnection::RdmaConnection(const RdmaParams& a_params) + : m_id(a_params.id), + m_dcqcn(a_params.dcqcn), + m_sender(a_params.ft.sender), + m_sender_port(a_params.ft.sender_port), + m_packet_size(a_params.packet_size), + m_receiver(a_params.ft.receiver), + m_receiver_port(a_params.ft.receiver_port), + m_ack_threshold(a_params.ack_threshold), + m_max_reorder_buffer_size(a_params.reorder_buffer_size / m_packet_size) {} void RdmaConnection::start_data_sending() { m_dcqcn.start(); @@ -119,14 +119,40 @@ Packet RdmaConnection::create_data_packet(const Data& data) { } void RdmaConnection::process_data_packet(const Packet& packet) { - if (packet.packet_num != m_next_expected_packet_num) { + if (packet.packet_num < m_next_expected_packet_num) { LOG_ERROR( - fmt::format("RDMA receiver got data packet {} with number that " - "differs from expected {}; ignored", + fmt::format("RDMA receiver got data packet {} with number smaller " + "than expected {}; ignored", packet.to_string(), m_next_expected_packet_num)); - // TODO: correct implementation for such case - return; + } else if (packet.packet_num == m_next_expected_packet_num) { + process_expected_data_packet(); + while (!m_reorder_buffer.empty() && + m_reorder_buffer.front().has_value()) { + m_reorder_buffer.pop_front(); + process_expected_data_packet(); + } + } else { + uint32_t diff = packet.packet_num - m_next_expected_packet_num; + if (diff >= m_max_reorder_buffer_size) { + LOG_ERROR(fmt::format( + "RDMA receiver got data packet {} with number greater " + "than expected {}; could not put it to reorder buffer; ignored", + packet.to_string(), m_next_expected_packet_num)); + // TODO: send NAK + return; + } + while (m_reorder_buffer.size() <= diff) { + m_reorder_buffer.emplace_back(std::nullopt); + } + LOG_INFO( + fmt::format("RDMA receiver got data packet {} with number greater " + "than expected {}; put it to reorder buffer;", + m_id, packet)); + m_reorder_buffer[diff].emplace(packet); } +} + +void RdmaConnection::process_expected_data_packet() { m_next_expected_packet_num++; if (++m_data_packets_on_receiver >= m_ack_threshold) { m_data_packets_on_receiver = 0; @@ -211,7 +237,7 @@ void RdmaConnection::confirm_first_unconfirmed_packet() { if (data_ctx.delivered >= data_ctx.total_size) { LOG_INFO( fmt::format("RDMA connection {} delivered data {}; call callback", - m_id, data_id)); + m_id, data_id.to_string())); data_ctx.callback(); } } @@ -243,4 +269,4 @@ void RdmaConnection::send_ack_request() { void RdmaConnection::process_ack_request() { send_ack(); } -} // namespace sim \ No newline at end of file +} // namespace sim diff --git a/source/network/connection/rdma/rdma_connectrion.hpp b/source/network/connection/rdma/rdma_connectrion.hpp index d506331222..e0e6cbae6a 100644 --- a/source/network/connection/rdma/rdma_connectrion.hpp +++ b/source/network/connection/rdma/rdma_connectrion.hpp @@ -1,10 +1,11 @@ #pragma once #include +#include #include "../i_connection.hpp" -#include "dcqcn/dcqcn.hpp" #include "network/connection/flow/flow_four_tuple.hpp" #include "network/connection/flow/packet.hpp" +#include "rdma_params.hpp" #include "topology/device/host.hpp" namespace sim { @@ -16,8 +17,7 @@ using RdmaConnectionPtr = std::shared_ptr; class RdmaConnection : public IConnection, public std::enable_shared_from_this { public: - static RdmaConnectionPtr create_shared(const Id& a_id, const DCQCN& a_dcqcn, - const FlowFourTuple& a_ft); + static RdmaConnectionPtr create_shared(const RdmaParams& a_params); [[nodiscard]] virtual utils::StrExpected send_data( Data data, OnDeliveryCallback callback) final; @@ -32,8 +32,7 @@ class RdmaConnection : public IConnection, virtual const Id& get_id() const final; private: - RdmaConnection(const Id& a_id, const DCQCN& a_dcqcn, - const FlowFourTuple& a_endpoints); + RdmaConnection(const RdmaParams& a_params); void start_data_sending(); @@ -45,6 +44,8 @@ class RdmaConnection : public IConnection, void process_data_packet(const Packet& data); + void process_expected_data_packet(); + void send_ack(); void process_ack(const Packet& ack); @@ -63,8 +64,8 @@ class RdmaConnection : public IConnection, static constexpr SizeByte ACK_REQUEST_SIZE = SizeByte(1ul); std::shared_ptr m_sender; Port m_sender_port; - // TODO: make custom - SizeByte m_packet_size = SizeByte(1500ul); + + SizeByte m_packet_size; // Invariant: packet_num of first packet in this queue is equal to // m_last_acked_pcn @@ -89,10 +90,15 @@ class RdmaConnection : public IConnection, std::shared_ptr m_receiver; Port m_receiver_port; uint32_t m_data_packets_on_receiver = 0; - // TODO: make custom - uint32_t m_ack_threshold = 32; + + uint32_t m_ack_threshold; PacketNum m_next_expected_packet_num = 1; static constexpr SizeByte M_ACK_SIZE = SizeByte(1ul); + + // Invariant: if packet with number i > m_next_packet_num received, + // m_reorder_buffer[i - m_next_packet_num - 1] contains it + std::deque > m_reorder_buffer; + std::size_t m_max_reorder_buffer_size; }; -} // namespace sim \ No newline at end of file +} // namespace sim diff --git a/source/network/connection/rdma/rdma_params.hpp b/source/network/connection/rdma/rdma_params.hpp new file mode 100644 index 0000000000..d4b0360aa4 --- /dev/null +++ b/source/network/connection/rdma/rdma_params.hpp @@ -0,0 +1,16 @@ +#pragma once +#include "dcqcn/dcqcn.hpp" +#include "network/connection/flow/flow_four_tuple.hpp" + +namespace sim { + +struct RdmaParams { + Id id; + DCQCN dcqcn; + FlowFourTuple ft; + SizeByte packet_size = SizeByte(1500ul); + uint32_t send_window = 256; + uint32_t ack_threshold = 32; + SizeByte reorder_buffer_size = Size(64ul); +}; +} // namespace sim diff --git a/source/parser/network/connection/rdma_connection_parser.cpp b/source/parser/network/connection/rdma_connection_parser.cpp index 0a6c732437..bae4e538cd 100644 --- a/source/parser/network/connection/rdma_connection_parser.cpp +++ b/source/parser/network/connection/rdma_connection_parser.cpp @@ -27,7 +27,9 @@ RdmaConnectionPtr parse_rdma_connection(std::shared_ptr sender, FlowFourTuple ft(Endpoints(sender, receiver), generate_ports()); - return RdmaConnection::create_shared(connection_id, dcqcn, ft); + RdmaParams rdma_params{connection_id, dcqcn, ft}; + + return RdmaConnection::create_shared(rdma_params); } -} // namespace sim \ No newline at end of file +} // namespace sim From ef1abbec9b0faa3da0d4e911b41edd1ab32bff7b Mon Sep 17 00:00:00 2001 From: Pavel Ralnikov Date: Sat, 2 May 2026 14:42:06 +0300 Subject: [PATCH 03/10] Fix --- source/network/connection/rdma/rdma_connection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/network/connection/rdma/rdma_connection.cpp b/source/network/connection/rdma/rdma_connection.cpp index b0491722f5..abae573622 100644 --- a/source/network/connection/rdma/rdma_connection.cpp +++ b/source/network/connection/rdma/rdma_connection.cpp @@ -147,7 +147,7 @@ void RdmaConnection::process_data_packet(const Packet& packet) { LOG_INFO( fmt::format("RDMA receiver got data packet {} with number greater " "than expected {}; put it to reorder buffer;", - m_id, packet)); + m_id, packet.to_string())); m_reorder_buffer[diff].emplace(packet); } } From e64c166c80dd55bf269c3702c8ad8f2af5e0420d Mon Sep 17 00:00:00 2001 From: Pavel Ralnikov Date: Tue, 5 May 2026 17:50:14 +0300 Subject: [PATCH 04/10] Continut RDMA implementation --- configs/rdma_test/network.yml | 10 ++ configs/rdma_test/scenario.yml | 8 ++ configs/rdma_test/topology.yml | 83 ++++++++++++ configs/simple/rdma_network.yml | 3 +- configs/simple/rdma_scenario.yml | 2 +- .../network/connection/rdma/dcqcn/dcqcn.cpp | 4 +- .../network/connection/rdma/dcqcn/dcqcn.hpp | 3 +- .../connection/rdma/rdma_connection.cpp | 119 +++++++++++++++++- .../connection/rdma/rdma_connectrion.hpp | 19 +++ .../network/connection/dcqcn_parser.cpp | 70 ++++++++++- 10 files changed, 311 insertions(+), 10 deletions(-) create mode 100644 configs/rdma_test/network.yml create mode 100644 configs/rdma_test/scenario.yml create mode 100644 configs/rdma_test/topology.yml diff --git a/configs/rdma_test/network.yml b/configs/rdma_test/network.yml new file mode 100644 index 0000000000..b56be19013 --- /dev/null +++ b/configs/rdma_test/network.yml @@ -0,0 +1,10 @@ +topology_config_path: topology.yml +type: custom + +connections: + connection: + type: rdma + sender_id: sender + receiver_id: receiver + dcqcn: + start_target_rate: 18Gbps diff --git a/configs/rdma_test/scenario.yml b/configs/rdma_test/scenario.yml new file mode 100644 index 0000000000..2501cc1346 --- /dev/null +++ b/configs/rdma_test/scenario.yml @@ -0,0 +1,8 @@ +network_config_path: network.yml + +scenario: +- action: send_data + id: send + when: 0ns + size: 1MB + connections: connection diff --git a/configs/rdma_test/topology.yml b/configs/rdma_test/topology.yml new file mode 100644 index 0000000000..13d50f8535 --- /dev/null +++ b/configs/rdma_test/topology.yml @@ -0,0 +1,83 @@ +type: custom +presets: + default-switch: + ecn: + min: 0.3 + max: 0.5 + probability: 0.2 + default-link: + latency: 1000ns + throughput: 10Gbps + ingress_buffer_size: 64KB + egress_buffer_size: 64KB + +packet-spraying: + type: flowlet + threshold: 1000ns + +hosts: + sender: + receiver: + +switches: + switch-sender: + preset-name: default-switch + switch-1: + preset-name: default-switch + switch-2: + preset-name: default-switch + switch-receiver: + preset-name: default-switch +links: + link-0: + from: sender + to: switch-sender + preset-name: default-link + throughput: 20Gbps + back-0: + from: switch-sender + to: sender + preset-name: default-link + throughput: 20Gbps + link-1: + from: switch-sender + to: switch-1 + preset-name: default-link + link-2: + from: switch-1 + to: switch-sender + preset-name: default-link + link-3: + from: switch-sender + to: switch-2 + preset-name: default-link + link-4: + from: switch-2 + to: switch-sender + preset-name: default-link + link-5: + from: switch-receiver + to: switch-1 + preset-name: default-link + link-6: + from: switch-1 + to: switch-receiver + preset-name: default-link + link-7: + from: switch-receiver + to: switch-2 + preset-name: default-link + link-8: + from: switch-2 + to: switch-receiver + preset-name: default-link + link-9: + from: receiver + to: switch-receiver + preset-name: default-link + throughput: 20Gbps + back-9: + from: switch-receiver + to: receiver + preset-name: default-link + throughput: 20Gbps diff --git a/configs/simple/rdma_network.yml b/configs/simple/rdma_network.yml index 7f69cb8363..aac951938a 100644 --- a/configs/simple/rdma_network.yml +++ b/configs/simple/rdma_network.yml @@ -6,4 +6,5 @@ connections: type: rdma sender_id: sender receiver_id: receiver - dcqcn: {} \ No newline at end of file + dcqcn: + start_target_rate: 10Gbps diff --git a/configs/simple/rdma_scenario.yml b/configs/simple/rdma_scenario.yml index 702e9b5181..a22ab650d4 100644 --- a/configs/simple/rdma_scenario.yml +++ b/configs/simple/rdma_scenario.yml @@ -4,5 +4,5 @@ scenario: - action: send_data id: send when: 0ns - size: 4500B + size: 50KB connections: connection diff --git a/source/network/connection/rdma/dcqcn/dcqcn.cpp b/source/network/connection/rdma/dcqcn/dcqcn.cpp index 56c24818ba..2a94937d62 100644 --- a/source/network/connection/rdma/dcqcn/dcqcn.cpp +++ b/source/network/connection/rdma/dcqcn/dcqcn.cpp @@ -5,7 +5,7 @@ namespace sim { DCQCN::DCQCN(const ParamsDQCCN& a_params) : m_params(a_params), - m_current_rate(a_params.rpg_min_rate), + m_current_rate(a_params.start_target_rate), m_target_rate(m_current_rate), m_alpha(m_params.initial_alpha_value) {} @@ -145,4 +145,4 @@ void DCQCN::on_rate_increase_event() { m_current_rate = (m_current_rate + m_target_rate) / 2.0; } -} // namespace sim \ No newline at end of file +} // namespace sim diff --git a/source/network/connection/rdma/dcqcn/dcqcn.hpp b/source/network/connection/rdma/dcqcn/dcqcn.hpp index dd5cf62f13..a4e5289d17 100644 --- a/source/network/connection/rdma/dcqcn/dcqcn.hpp +++ b/source/network/connection/rdma/dcqcn/dcqcn.hpp @@ -11,6 +11,7 @@ namespace sim { // https://enterprise-support.nvidia.com/s/article/dcqcn-parameters struct ParamsDQCCN { + SpeedGbps start_target_rate; // -------------Rate increment------------- // The time period between rate increase events. @@ -108,4 +109,4 @@ class DCQCN { bool m_stop_request = false; }; -} // namespace sim \ No newline at end of file +} // namespace sim diff --git a/source/network/connection/rdma/rdma_connection.cpp b/source/network/connection/rdma/rdma_connection.cpp index abae573622..f10c574bf6 100644 --- a/source/network/connection/rdma/rdma_connection.cpp +++ b/source/network/connection/rdma/rdma_connection.cpp @@ -63,9 +63,71 @@ RdmaConnection::RdmaConnection(const RdmaParams& a_params) m_ack_threshold(a_params.ack_threshold), m_max_reorder_buffer_size(a_params.reorder_buffer_size / m_packet_size) {} +void RdmaConnection::schedule_ack_timer() { + Scheduler& sched = Scheduler::get_instance(); + TimeNs now = sched.get_current_time(); + auto conn = shared_from_this(); + sched.add(now + m_ack_receiver_timout, [conn]() { conn->on_ack_timer(); }); +} + +void RdmaConnection::on_ack_timer() { + Scheduler& sched = Scheduler::get_instance(); + TimeNs now = sched.get_current_time(); + // TODO: replacse with flag (send <> packet by sender) + if (m_send_queue.empty()) { + return; + } + + if (m_last_ack_send + m_ack_receiver_timout < now) { + LOG_ERROR(fmt::format("RDMA connection {}: ack timer; send ack", m_id)); + send_ack(); + } + + schedule_ack_timer(); +} + +void RdmaConnection::on_retry_timout() { + Scheduler& sched = Scheduler::get_instance(); + TimeNs now = sched.get_current_time(); + + if (m_send_queue.empty()) { + LOG_INFO( + fmt::format("RMDA connection {}: all packets confirmed; stop retry " + "events scheduling", + m_id)); + return; + } + + if (m_ctx.last_data_delivery_time.value_or(TimeNs(0)) + m_retry_timout < + now) { + LOG_ERROR(fmt::format( + "RDMA connection {}: retry timout expired; retrandsmit packets", + m_id)); + retransmit_packets(); + } + schedule_retry_timout(); +} + +void RdmaConnection::schedule_retry_timout() { + Scheduler& sched = Scheduler::get_instance(); + TimeNs now = sched.get_current_time(); + auto conn = shared_from_this(); + sched.add(now + m_retry_timout, [conn]() { conn->on_retry_timout(); }); +} + +void RdmaConnection::retransmit_packets() { + uint32_t i = m_pcn - m_last_acked_pcn - 1; + bool sending_stopped = (i >= m_send_queue.size()); + m_pcn = m_last_acked_pcn + 1; + if (sending_stopped) { + send_next_data_packet(); + } +} + void RdmaConnection::start_data_sending() { m_dcqcn.start(); - schedule_data_send(); + send_next_data_packet(); + schedule_retry_timout(); } void RdmaConnection::schedule_data_send() { @@ -119,6 +181,10 @@ Packet RdmaConnection::create_data_packet(const Data& data) { } void RdmaConnection::process_data_packet(const Packet& packet) { + if (!m_receiver_started) { + m_receiver_started = true; + schedule_ack_timer(); + } if (packet.packet_num < m_next_expected_packet_num) { LOG_ERROR( fmt::format("RDMA receiver got data packet {} with number smaller " @@ -138,7 +204,7 @@ void RdmaConnection::process_data_packet(const Packet& packet) { "RDMA receiver got data packet {} with number greater " "than expected {}; could not put it to reorder buffer; ignored", packet.to_string(), m_next_expected_packet_num)); - // TODO: send NAK + send_nak(); return; } while (m_reorder_buffer.size() <= diff) { @@ -160,7 +226,42 @@ void RdmaConnection::process_expected_data_packet() { } } +void RdmaConnection::send_nak() { + Packet nak; + if (m_next_expected_packet_num == 0) { + LOG_ERROR( + fmt::format("RDMA connection {}: cold not send nak: next expected " + "packet num = 0", + m_id)); + return; + } + nak.packet_num = m_next_expected_packet_num - 1; + + nak.sender_id = m_receiver->get_id(); + nak.sender_port = m_receiver_port; + nak.receiver_port = m_sender_port; + nak.receiver_id = m_sender->get_id(); + nak.size = M_ACK_SIZE; + + RdmaConnectionPtr conn = shared_from_this(); + + nak.callback = [conn](const Packet& nak) { conn->process_nak(nak); }; + TimeNs now = Scheduler::get_instance().get_current_time(); + nak.generated_time = now; + nak.sent_time = now; + + nak.ecn_capable_transport = true; + nak.congestion_experienced = false; + + m_receiver->enqueue_packet(nak); +} + +void RdmaConnection::process_nak([[maybe_unused]] const Packet& nak) { + retransmit_packets(); +} + void RdmaConnection::send_ack() { + m_last_ack_send = Scheduler::get_instance().get_current_time(); Packet ack; if (m_next_expected_packet_num == 0) { LOG_ERROR( @@ -201,6 +302,19 @@ void RdmaConnection::process_ack(const Packet& ack) { m_id)); return; } + SizeByte total_data_confirmed = + (ack_num - m_last_acked_pcn) * m_packet_size; + TimeNs now = Scheduler::get_instance().get_current_time(); + + if (m_ctx.last_data_delivery_time.has_value()) { + TimeNs time_from_last_delivery = + now - m_ctx.last_data_delivery_time.value(); + SpeedGbps delivery_rate = + total_data_confirmed / time_from_last_delivery; + m_ctx.delivery_rate_statistics.add_record(delivery_rate); + } + + m_ctx.last_data_delivery_time = now; while (m_last_acked_pcn < ack_num) { m_last_acked_pcn++; confirm_first_unconfirmed_packet(); @@ -208,6 +322,7 @@ void RdmaConnection::process_ack(const Packet& ack) { } void RdmaConnection::confirm_first_unconfirmed_packet() { + m_ctx.total_data_delivered += m_packet_size; if (m_send_queue.empty()) { LOG_ERROR( fmt::format("RDMA connection {}: could not confirm packet with " diff --git a/source/network/connection/rdma/rdma_connectrion.hpp b/source/network/connection/rdma/rdma_connectrion.hpp index e0e6cbae6a..c2a6f5a654 100644 --- a/source/network/connection/rdma/rdma_connectrion.hpp +++ b/source/network/connection/rdma/rdma_connectrion.hpp @@ -34,6 +34,16 @@ class RdmaConnection : public IConnection, private: RdmaConnection(const RdmaParams& a_params); + void schedule_ack_timer(); + + void on_ack_timer(); + + void on_retry_timout(); + + void schedule_retry_timout(); + + void retransmit_packets(); + void start_data_sending(); void schedule_data_send(); @@ -46,6 +56,10 @@ class RdmaConnection : public IConnection, void process_expected_data_packet(); + void send_nak(); + + void process_nak(const Packet& nak); + void send_ack(); void process_ack(const Packet& ack); @@ -66,6 +80,7 @@ class RdmaConnection : public IConnection, Port m_sender_port; SizeByte m_packet_size; + TimeNs m_retry_timout = TimeNs(50000); // Invariant: packet_num of first packet in this queue is equal to // m_last_acked_pcn @@ -94,11 +109,15 @@ class RdmaConnection : public IConnection, uint32_t m_ack_threshold; PacketNum m_next_expected_packet_num = 1; static constexpr SizeByte M_ACK_SIZE = SizeByte(1ul); + static constexpr SizeByte M_NAK_SIZE = M_ACK_SIZE; // Invariant: if packet with number i > m_next_packet_num received, // m_reorder_buffer[i - m_next_packet_num - 1] contains it std::deque > m_reorder_buffer; std::size_t m_max_reorder_buffer_size; + TimeNs m_ack_receiver_timout = TimeNs(50000); + TimeNs m_last_ack_send = TimeNs(0); + bool m_receiver_started = false; }; } // namespace sim diff --git a/source/parser/network/connection/dcqcn_parser.cpp b/source/parser/network/connection/dcqcn_parser.cpp index c8d9acf057..9fc8cee148 100644 --- a/source/parser/network/connection/dcqcn_parser.cpp +++ b/source/parser/network/connection/dcqcn_parser.cpp @@ -1,9 +1,73 @@ #include "dcqcn_parser.hpp" +#include "parser/parse_utils.hpp" namespace sim { -DCQCN parse_dcqcn([[maybe_unused]] const ConfigNodeWithPreset& node) { - // TODO: implement correctlty +DCQCN parse_dcqcn(const ConfigNodeWithPreset& node) { ParamsDQCCN params; + + if (auto start_rate_node = node["start_target_rate"]) { + params.start_target_rate = parse_speed(start_rate_node->get_node()); + } + + // -------- Rate increment -------- + if (auto rpg_time_reset_node = node["rpg_time_reset"]) { + params.rpg_time_reset = parse_time(rpg_time_reset_node->get_node()); + } + + if (auto rpg_byte_reset_node = node["rpg_byte_reset"]) { + params.rpg_byte_reset = parse_size(rpg_byte_reset_node->get_node()); + } + + if (auto rpg_threshold_node = node["rpg_threshold"]) { + params.rpg_threshold = rpg_threshold_node->as_or_throw(); + } + + if (auto rpg_ai_rate_node = node["rpg_ai_rate"]) { + params.rpg_ai_rate = parse_speed(rpg_ai_rate_node->get_node()); + } + + if (auto rpg_hai_rate_node = node["rpg_hai_rate"]) { + params.rpg_hai_rate = parse_speed(rpg_hai_rate_node->get_node()); + } + + // -------- Alpha update -------- + if (auto initial_alpha_node = node["initial_alpha_value"]) { + params.initial_alpha_value = initial_alpha_node->as_or_throw(); + } + + if (auto dce_tcp_g_node = node["dce_tcp_g"]) { + params.dce_tcp_g = dce_tcp_g_node->as_or_throw(); + } + + if (auto dce_tcp_rtt_node = node["dce_tcp_rtt"]) { + params.dce_tcp_rtt = parse_time(dce_tcp_rtt_node->get_node()); + } + + // -------- Rate decrement -------- + if (auto rate_reduce_period_node = node["rate_reduce_monitor_period"]) { + params.rate_reduce_monitor_period = parse_time(rate_reduce_period_node->get_node()); + } + + if (auto first_cnp_rate_node = node["rate_to_set_on_first_cnp"]) { + params.rate_to_set_on_first_cnp = parse_speed(first_cnp_rate_node->get_node()); + } + + if (auto clamp_tgt_rate_node = node["clamp_tgt_rate"]) { + params.clamp_tgt_rate = clamp_tgt_rate_node->as_or_throw(); + } + + if (auto rpg_gd_node = node["rpg_gd"]) { + params.rpg_gd = rpg_gd_node->as_or_throw(); + } + + if (auto rpg_min_rate_node = node["rpg_min_rate"]) { + params.rpg_min_rate = parse_speed(rpg_min_rate_node->get_node()); + } + + if (auto rpg_min_dec_fac_node = node["rpg_min_dec_fac"]) { + params.rpg_min_dec_fac = rpg_min_dec_fac_node->as_or_throw(); + } + return DCQCN(params); } -} // namespace sim \ No newline at end of file +} // namespace sim From 5e20dd8e10ea6603619eaf4aa627b0f0ba3d6f76 Mon Sep 17 00:00:00 2001 From: Pavel Ralnikov Date: Wed, 6 May 2026 09:04:51 +0300 Subject: [PATCH 05/10] Fix some bugs & add some scenarios --- configs/fat-tree/network.yml | 31 +++------- configs/fat-tree/topology.yml | 5 +- configs/leaf-spine/network.yml | 59 ++++--------------- configs/leaf-spine/network_sw_based.yml | 40 +++++++++++++ configs/leaf-spine/scenario.yml | 4 +- configs/leaf-spine/scenario_sw_based.yml | 23 ++++++++ configs/leaf-spine/topology.yml | 21 +++++-- configs/rdma_test/network.yml | 5 +- configs/rdma_test/topology.yml | 6 +- .../simple_packet_reordering.cpp | 8 ++- .../simple_packet_reordering.hpp | 5 +- .../network/connection/rdma/dcqcn/dcqcn.cpp | 5 +- .../connection/rdma/rdma_connection.cpp | 33 ++++++++++- .../connection/rdma/rdma_connectrion.hpp | 4 ++ .../connection/rdma_connection_parser.cpp | 6 ++ .../topology/leaf_spine_topology_parser.cpp | 4 +- source/topology/device/host.cpp | 6 +- source/topology/device/switch.cpp | 6 +- 18 files changed, 171 insertions(+), 100 deletions(-) create mode 100644 configs/leaf-spine/network_sw_based.yml create mode 100644 configs/leaf-spine/scenario_sw_based.yml diff --git a/configs/fat-tree/network.yml b/configs/fat-tree/network.yml index b3c4feaec2..438a1acab4 100644 --- a/configs/fat-tree/network.yml +++ b/configs/fat-tree/network.yml @@ -32,31 +32,16 @@ presets: type: tcp preset-name: default-flow - flow-2: - type: tcp - preset-name: default-flow + # flow-2: + # type: tcp + # preset-name: default-flow - flow-3: - type: tcp - preset-name: default-flow + # flow-3: + # type: tcp + # preset-name: default-flow connections: - connection-pod1_host1--pod2_host1: - preset-name: default-connection - sender_id: pod-1_edge-1_host-1 - receiver_id: pod-2_edge-1_host-1 - - connection-pod1_host1--pod2_host2: - preset-name: default-connection - sender_id: pod-1_edge-1_host-1 - receiver_id: pod-2_edge-1_host-2 - - connection-pod1_host1--pod2_host3: - preset-name: default-connection - sender_id: pod-1_edge-1_host-1 - receiver_id: pod-2_edge-2_host-1 - - connection-pod1_host1--pod2_host4: + connection-pod1_edge-1_host1--edge-2_host1: preset-name: default-connection sender_id: pod-1_edge-1_host-1 - receiver_id: pod-2_edge-2_host-2 + receiver_id: pod-1_edge-2_host-1 diff --git a/configs/fat-tree/topology.yml b/configs/fat-tree/topology.yml index 45f35c4d3d..fd65f02ec6 100644 --- a/configs/fat-tree/topology.yml +++ b/configs/fat-tree/topology.yml @@ -25,7 +25,7 @@ switches: min: 0.2 max: 0.3 probability: 0.7 - + edge: ecn: min: 0.2 @@ -41,4 +41,5 @@ links: aggr-edge: preset-name: link edge-host: - preset-name: link \ No newline at end of file + preset-name: link + throughput: 20Gbps diff --git a/configs/leaf-spine/network.yml b/configs/leaf-spine/network.yml index 6a1b97ba56..fe4aec2520 100644 --- a/configs/leaf-spine/network.yml +++ b/configs/leaf-spine/network.yml @@ -8,59 +8,24 @@ presets: type: single-cc packet-size: 1500B cc: - type: tahoe + type: swift + base_target: 12500ns path-chooser: type: round-robin flows: - flow: + flow-1: + type: tcp + flow-2: + type: tcp + flow-3: + type: tcp + flow-4: + type: tcp + flow-5: type: tcp connections: - conn_1--2: - sender_id: host-1 - receiver_id: host-2 + conn: preset-name: default-connection - conn_1--3: - sender_id: host-1 - receiver_id: host-3 - preset-name: default-connection - conn_1--4: sender_id: host-1 receiver_id: host-4 - preset-name: default-connection - conn_2--1: - sender_id: host-2 - receiver_id: host-1 - preset-name: default-connection - conn_2--3: - sender_id: host-2 - receiver_id: host-3 - preset-name: default-connection - conn_2--4: - sender_id: host-2 - receiver_id: host-4 - preset-name: default-connection - conn_3--1: - sender_id: host-3 - receiver_id: host-1 - preset-name: default-connection - conn_3--2: - sender_id: host-3 - receiver_id: host-2 - preset-name: default-connection - conn_3--4: - sender_id: host-3 - receiver_id: host-4 - preset-name: default-connection - conn_4--1: - sender_id: host-4 - receiver_id: host-1 - preset-name: default-connection - conn_4--2: - sender_id: host-4 - receiver_id: host-2 - preset-name: default-connection - conn_4--3: - sender_id: host-4 - receiver_id: host-3 - preset-name: default-connection diff --git a/configs/leaf-spine/network_sw_based.yml b/configs/leaf-spine/network_sw_based.yml new file mode 100644 index 0000000000..b7169cd748 --- /dev/null +++ b/configs/leaf-spine/network_sw_based.yml @@ -0,0 +1,40 @@ +type: custom +topology_config_path: topology.yml + +presets: + default-connection: + type: mplb-connection + mplb: + type: single-cc + packet-size: 1500B + cc: + type: swift + base_target: 12500ns + path-chooser: + type: round-robin + flows: + flow: + type: tcp + +connections: + conn-1: + preset-name: default-connection + sender_id: host-1 + receiver_id: host-4 + conn-2: + preset-name: default-connection + sender_id: host-2 + receiver_id: host-4 + conn-3: + preset-name: default-connection + sender_id: host-3 + receiver_id: host-4 + conn-rdma: + type: rdma + sender_id: host-1 + receiver_id: host-4 + dcqcn: + start_target_rate: 10Gbps + rpg_time_reset: 1000ns + rate_reduce_monitor_period: 10000ns + rpg_min_rate: 1Gbps diff --git a/configs/leaf-spine/scenario.yml b/configs/leaf-spine/scenario.yml index 6aebfbeb5d..d9490425c0 100644 --- a/configs/leaf-spine/scenario.yml +++ b/configs/leaf-spine/scenario.yml @@ -4,7 +4,5 @@ scenario: - action: send_data id: send-1 when: 0ns - size: 256KB - repeat_count: 1 + size: 1MB connections: ^conn.* - repeat_interval: 500000ns diff --git a/configs/leaf-spine/scenario_sw_based.yml b/configs/leaf-spine/scenario_sw_based.yml new file mode 100644 index 0000000000..5a76fc7427 --- /dev/null +++ b/configs/leaf-spine/scenario_sw_based.yml @@ -0,0 +1,23 @@ +network_config_path: network_sw_based.yml + +scenario: +# - action: send_data +# id: send-1 +# when: 0ns +# size: 1MB +# connections: conn-1 +- action: send_data + id: send-rdma + when: 0ns + size: 1MB + connections: conn-rdma +# - action: send_data +# id: send-2 +# when: 0ns +# size: 1MB +# connections: conn-2 +# - action: send_data +# id: send-3 +# when: 0ns +# size: 1MB +# connections: conn-3 diff --git a/configs/leaf-spine/topology.yml b/configs/leaf-spine/topology.yml index 396b1d6be3..311bf90185 100644 --- a/configs/leaf-spine/topology.yml +++ b/configs/leaf-spine/topology.yml @@ -2,20 +2,30 @@ type: leaf-spine presets: link: - latency: 0ns - throughput: 100Gbps - ingress_buffer_size: 64KB - egress_buffer_size: 64KB + latency: 1000ns + throughput: 10Gbps + ingress_buffer_size: 1MB + egress_buffer_size: 1MB metrics_filters: queue_sizes: false packet-spraying: type: random + # type: flowlet + # threshold: 0ns switches: spine: count: 2 + ecn: + min: 0.3 + max: 0.5 + probability: 0.2 leaf: + ecn: + min: 0.3 + max: 0.5 + probability: 0.2 count: 4 hosts: @@ -24,4 +34,5 @@ links: leaf-spine: preset-name: link host-leaf: - preset-name: link \ No newline at end of file + preset-name: link + throughput: 20Gbps diff --git a/configs/rdma_test/network.yml b/configs/rdma_test/network.yml index b56be19013..382a756beb 100644 --- a/configs/rdma_test/network.yml +++ b/configs/rdma_test/network.yml @@ -7,4 +7,7 @@ connections: sender_id: sender receiver_id: receiver dcqcn: - start_target_rate: 18Gbps + start_target_rate: 10Gbps + rpg_time_reset: 1000ns + rate_reduce_monitor_period: 10000ns + rpg_min_rate: 1Gbps diff --git a/configs/rdma_test/topology.yml b/configs/rdma_test/topology.yml index 13d50f8535..981a8dc4f5 100644 --- a/configs/rdma_test/topology.yml +++ b/configs/rdma_test/topology.yml @@ -8,11 +8,11 @@ presets: default-link: latency: 1000ns throughput: 10Gbps - ingress_buffer_size: 64KB - egress_buffer_size: 64KB + ingress_buffer_size: 1MB + egress_buffer_size: 1MB packet-spraying: - type: flowlet + type: ecmp threshold: 1000ns hosts: diff --git a/source/metrics/packet_reordering/simple_packet_reordering.cpp b/source/metrics/packet_reordering/simple_packet_reordering.cpp index d206a9c951..1d15f22ed6 100644 --- a/source/metrics/packet_reordering/simple_packet_reordering.cpp +++ b/source/metrics/packet_reordering/simple_packet_reordering.cpp @@ -8,11 +8,17 @@ SimplePacketReordering::SimplePacketReordering() void SimplePacketReordering::add_record(PacketNum packet_num) { if (packet_num == m_next_packet_num) { m_next_packet_num++; + while (!m_packet_num_set.empty() && + *m_packet_num_set.begin() == m_next_packet_num) { + m_packet_num_set.erase(m_packet_num_set.begin()); + m_next_packet_num++; + } } else { + m_packet_num_set.insert(packet_num); m_reordering++; } } PacketReordering SimplePacketReordering::value() const { return m_reordering; } -}; // namespace sim \ No newline at end of file +}; // namespace sim diff --git a/source/metrics/packet_reordering/simple_packet_reordering.hpp b/source/metrics/packet_reordering/simple_packet_reordering.hpp index 2fa097f8cd..a933fcc089 100644 --- a/source/metrics/packet_reordering/simple_packet_reordering.hpp +++ b/source/metrics/packet_reordering/simple_packet_reordering.hpp @@ -1,4 +1,6 @@ #pragma once +#include + #include "i_packet_reordering.hpp" #include "utils/statistics.hpp" @@ -17,5 +19,6 @@ class SimplePacketReordering : public IPacketReordering { // When m_packet_num_set.size() growth up it, the smallest element deletes std::size_t m_next_packet_num; PacketReordering m_reordering; + std::set m_packet_num_set; }; -} // namespace sim \ No newline at end of file +} // namespace sim diff --git a/source/network/connection/rdma/dcqcn/dcqcn.cpp b/source/network/connection/rdma/dcqcn/dcqcn.cpp index 2a94937d62..aeb149c16d 100644 --- a/source/network/connection/rdma/dcqcn/dcqcn.cpp +++ b/source/network/connection/rdma/dcqcn/dcqcn.cpp @@ -81,9 +81,8 @@ void DCQCN::on_rate_reduce_monitor_period() { m_time_counter = 0; } - sched.add(now + m_params.rpg_time_reset, [this, last_cnp = m_last_cnp]() { - on_rate_increase_timer(last_cnp); - }); + sched.add(now + m_params.rate_reduce_monitor_period, + [this]() { on_rate_reduce_monitor_period(); }); } void DCQCN::on_alpha_timer() { diff --git a/source/network/connection/rdma/rdma_connection.cpp b/source/network/connection/rdma/rdma_connection.cpp index f10c574bf6..378db1e5cb 100644 --- a/source/network/connection/rdma/rdma_connection.cpp +++ b/source/network/connection/rdma/rdma_connection.cpp @@ -181,6 +181,7 @@ Packet RdmaConnection::create_data_packet(const Data& data) { } void RdmaConnection::process_data_packet(const Packet& packet) { + if (packet.num > 160) if (!m_receiver_started) { m_receiver_started = true; schedule_ack_timer(); @@ -216,6 +217,9 @@ void RdmaConnection::process_data_packet(const Packet& packet) { m_id, packet.to_string())); m_reorder_buffer[diff].emplace(packet); } + if (packet.congestion_experienced) { + send_cnp(); + } } void RdmaConnection::process_expected_data_packet() { @@ -313,7 +317,7 @@ void RdmaConnection::process_ack(const Packet& ack) { total_data_confirmed / time_from_last_delivery; m_ctx.delivery_rate_statistics.add_record(delivery_rate); } - + m_ctx.last_data_delivery_time = now; while (m_last_acked_pcn < ack_num) { m_last_acked_pcn++; @@ -321,6 +325,33 @@ void RdmaConnection::process_ack(const Packet& ack) { } } +void RdmaConnection::send_cnp() { + Packet cnp; + cnp.packet_num = m_next_expected_packet_num - 1; + + cnp.sender_id = m_receiver->get_id(); + cnp.sender_port = m_receiver_port; + cnp.receiver_port = m_sender_port; + cnp.receiver_id = m_sender->get_id(); + cnp.size = M_ACK_SIZE; + + RdmaConnectionPtr conn = shared_from_this(); + + cnp.callback = [conn](const Packet& cnp) { conn->process_cnp(cnp); }; + TimeNs now = Scheduler::get_instance().get_current_time(); + cnp.generated_time = now; + cnp.sent_time = now; + + cnp.ecn_capable_transport = true; + cnp.congestion_experienced = true; + + m_receiver->enqueue_packet(cnp); +} + +void RdmaConnection::process_cnp([[maybe_unused]] const Packet& cnp) { + m_dcqcn.on_cnp(); +} + void RdmaConnection::confirm_first_unconfirmed_packet() { m_ctx.total_data_delivered += m_packet_size; if (m_send_queue.empty()) { diff --git a/source/network/connection/rdma/rdma_connectrion.hpp b/source/network/connection/rdma/rdma_connectrion.hpp index c2a6f5a654..c388a3efd7 100644 --- a/source/network/connection/rdma/rdma_connectrion.hpp +++ b/source/network/connection/rdma/rdma_connectrion.hpp @@ -64,6 +64,10 @@ class RdmaConnection : public IConnection, void process_ack(const Packet& ack); + void send_cnp(); + + void process_cnp(const Packet& cnp); + void confirm_first_unconfirmed_packet(); void send_ack_request(); diff --git a/source/parser/network/connection/rdma_connection_parser.cpp b/source/parser/network/connection/rdma_connection_parser.cpp index bae4e538cd..3904fe8191 100644 --- a/source/parser/network/connection/rdma_connection_parser.cpp +++ b/source/parser/network/connection/rdma_connection_parser.cpp @@ -3,6 +3,7 @@ #include #include "dcqcn_parser.hpp" +#include "parser/parse_utils.hpp" namespace sim { @@ -29,6 +30,11 @@ RdmaConnectionPtr parse_rdma_connection(std::shared_ptr sender, RdmaParams rdma_params{connection_id, dcqcn, ft}; + if (auto reorder_buffer_size_node = params["reorder_buffer_size"]) { + rdma_params.reorder_buffer_size = + parse_size(reorder_buffer_size_node.value().get_node()); + } + return RdmaConnection::create_shared(rdma_params); } diff --git a/source/parser/topology/leaf_spine_topology_parser.cpp b/source/parser/topology/leaf_spine_topology_parser.cpp index 6ce76569af..e848bc8178 100644 --- a/source/parser/topology/leaf_spine_topology_parser.cpp +++ b/source/parser/topology/leaf_spine_topology_parser.cpp @@ -47,7 +47,7 @@ LeafSpineTopologyContext parse_leaf_spine_topology_context( const ConfigNodeWithPreset& leaf_spine_links = links["leaf-spine"].value_or_throw(); const ConfigNodeWithPreset& host_leaf_links = - links["leaf-spine"].value_or_throw(); + links["host-leaf"].value_or_throw(); LeafSpineParams params{packet_spraying, spine_switches, leaf_switches, hosts, leaf_spine_links, host_leaf_links}; @@ -147,4 +147,4 @@ LeafSpineTopologyContext create_leaf_spine_topology_context( return ctx; } -} // namespace sim \ No newline at end of file +} // namespace sim diff --git a/source/topology/device/host.cpp b/source/topology/device/host.cpp index 56a5e59731..af99b1b935 100644 --- a/source/topology/device/host.cpp +++ b/source/topology/device/host.cpp @@ -67,7 +67,7 @@ void Host::process() { if (packet.receiver_id == get_id()) { packet.callback(packet); } else { - LOG_WARN( + LOG_ERROR( "Host {}: arrived packet {} which destination differs from this " "host; use routing " "table to send it further"); @@ -88,8 +88,6 @@ void Host::process() { next_link->schedule_arrival(packet); } - - return; } void Host::send_packet() { @@ -115,7 +113,7 @@ void Host::send_packet() { auto next_link = get_link_to_destination(data_packet); if (next_link == nullptr) { - LOG_WARN("Link to send data packet does not exist"); + LOG_ERROR("Link to send data packet does not exist"); return; } diff --git a/source/topology/device/switch.cpp b/source/topology/device/switch.cpp index a27b5bb47c..5441cfad0f 100644 --- a/source/topology/device/switch.cpp +++ b/source/topology/device/switch.cpp @@ -26,7 +26,7 @@ void Switch::process() { std::shared_ptr link = next_inlink(); if (link == nullptr) { - LOG_WARN("No next inlink"); + LOG_ERROR("No next inlink"); return; } @@ -48,7 +48,7 @@ void Switch::process() { std::shared_ptr next_link = get_link_to_destination(packet); if (next_link == nullptr) { - LOG_WARN(fmt::format( + LOG_ERROR(fmt::format( "Switch {}: no link corresponds to destination device for packet " "{}", get_id(), packet.to_string())); @@ -84,8 +84,6 @@ void Switch::process() { // TODO: increase total_processing_time correctly next_link->schedule_arrival(packet); - - return; } } // namespace sim From 8ac13662841c3637cad8dea4ffeb89e86a17ff66 Mon Sep 17 00:00:00 2001 From: Pavel Ralnikov Date: Wed, 6 May 2026 15:27:03 +0300 Subject: [PATCH 06/10] Fix bugs --- configs/leaf-spine/network_sw_based.yml | 20 +++++++++- configs/leaf-spine/scenario_sw_based.yml | 7 +++- configs/leaf-spine/topology.yml | 3 +- .../connection/rdma/rdma_connection.cpp | 38 ++++++------------- .../connection/rdma/rdma_connectrion.hpp | 8 +--- .../network/connection/rdma/rdma_params.hpp | 1 - .../connection/rdma_connection_parser.cpp | 16 +++----- .../topology/device/hashers/ecmp_hasher.cpp | 4 +- 8 files changed, 49 insertions(+), 48 deletions(-) diff --git a/configs/leaf-spine/network_sw_based.yml b/configs/leaf-spine/network_sw_based.yml index b7169cd748..bf87245f6e 100644 --- a/configs/leaf-spine/network_sw_based.yml +++ b/configs/leaf-spine/network_sw_based.yml @@ -35,6 +35,22 @@ connections: receiver_id: host-4 dcqcn: start_target_rate: 10Gbps - rpg_time_reset: 1000ns - rate_reduce_monitor_period: 10000ns + rpg_time_reset: 10000ns + rate_reduce_monitor_period: 500ns rpg_min_rate: 1Gbps + rpg_ai_rate: 1Mbps + rpg_hai_rate: 2Gbps + conn-tahoe: + type: mplb-connection + sender_id: host-2 + receiver_id: host-4 + mplb: + type: single-cc + packet-size: 1500B + cc: + type: tahoe + path-chooser: + type: round-robin + flows: + flow: + type: tcp diff --git a/configs/leaf-spine/scenario_sw_based.yml b/configs/leaf-spine/scenario_sw_based.yml index 5a76fc7427..c0ac27f863 100644 --- a/configs/leaf-spine/scenario_sw_based.yml +++ b/configs/leaf-spine/scenario_sw_based.yml @@ -9,8 +9,13 @@ scenario: - action: send_data id: send-rdma when: 0ns - size: 1MB + size: 10MB connections: conn-rdma +- action: send_data + id: send-tahoe + when: 0ns + size: 10MB + connections: conn-tahoe # - action: send_data # id: send-2 # when: 0ns diff --git a/configs/leaf-spine/topology.yml b/configs/leaf-spine/topology.yml index 311bf90185..34a24e70cb 100644 --- a/configs/leaf-spine/topology.yml +++ b/configs/leaf-spine/topology.yml @@ -10,9 +10,10 @@ presets: queue_sizes: false packet-spraying: + # type: ecmp type: random # type: flowlet - # threshold: 0ns + # threshold: 200000ns switches: spine: diff --git a/source/network/connection/rdma/rdma_connection.cpp b/source/network/connection/rdma/rdma_connection.cpp index 378db1e5cb..c8a0d74822 100644 --- a/source/network/connection/rdma/rdma_connection.cpp +++ b/source/network/connection/rdma/rdma_connection.cpp @@ -60,8 +60,7 @@ RdmaConnection::RdmaConnection(const RdmaParams& a_params) m_packet_size(a_params.packet_size), m_receiver(a_params.ft.receiver), m_receiver_port(a_params.ft.receiver_port), - m_ack_threshold(a_params.ack_threshold), - m_max_reorder_buffer_size(a_params.reorder_buffer_size / m_packet_size) {} + m_ack_threshold(a_params.ack_threshold) {} void RdmaConnection::schedule_ack_timer() { Scheduler& sched = Scheduler::get_instance(); @@ -181,7 +180,6 @@ Packet RdmaConnection::create_data_packet(const Data& data) { } void RdmaConnection::process_data_packet(const Packet& packet) { - if (packet.num > 160) if (!m_receiver_started) { m_receiver_started = true; schedule_ack_timer(); @@ -193,29 +191,13 @@ void RdmaConnection::process_data_packet(const Packet& packet) { packet.to_string(), m_next_expected_packet_num)); } else if (packet.packet_num == m_next_expected_packet_num) { process_expected_data_packet(); - while (!m_reorder_buffer.empty() && - m_reorder_buffer.front().has_value()) { - m_reorder_buffer.pop_front(); - process_expected_data_packet(); - } } else { - uint32_t diff = packet.packet_num - m_next_expected_packet_num; - if (diff >= m_max_reorder_buffer_size) { - LOG_ERROR(fmt::format( - "RDMA receiver got data packet {} with number greater " - "than expected {}; could not put it to reorder buffer; ignored", - packet.to_string(), m_next_expected_packet_num)); - send_nak(); - return; - } - while (m_reorder_buffer.size() <= diff) { - m_reorder_buffer.emplace_back(std::nullopt); - } - LOG_INFO( - fmt::format("RDMA receiver got data packet {} with number greater " - "than expected {}; put it to reorder buffer;", - m_id, packet.to_string())); - m_reorder_buffer[diff].emplace(packet); + LOG_ERROR(fmt::format( + "RDMA receiver got data packet {} with number greater " + "than expected {}; could not put it to reorder buffer; ignored", + packet.to_string(), m_next_expected_packet_num)); + send_nak(); + return; } if (packet.congestion_experienced) { send_cnp(); @@ -260,7 +242,11 @@ void RdmaConnection::send_nak() { m_receiver->enqueue_packet(nak); } -void RdmaConnection::process_nak([[maybe_unused]] const Packet& nak) { +void RdmaConnection::process_nak(const Packet& nak) { + while (m_last_acked_pcn < nak.packet_num) { + m_last_acked_pcn++; + confirm_first_unconfirmed_packet(); + } retransmit_packets(); } diff --git a/source/network/connection/rdma/rdma_connectrion.hpp b/source/network/connection/rdma/rdma_connectrion.hpp index c388a3efd7..8f7718874d 100644 --- a/source/network/connection/rdma/rdma_connectrion.hpp +++ b/source/network/connection/rdma/rdma_connectrion.hpp @@ -84,7 +84,7 @@ class RdmaConnection : public IConnection, Port m_sender_port; SizeByte m_packet_size; - TimeNs m_retry_timout = TimeNs(50000); + TimeNs m_retry_timout = TimeNs(500000); // Invariant: packet_num of first packet in this queue is equal to // m_last_acked_pcn @@ -115,11 +115,7 @@ class RdmaConnection : public IConnection, static constexpr SizeByte M_ACK_SIZE = SizeByte(1ul); static constexpr SizeByte M_NAK_SIZE = M_ACK_SIZE; - // Invariant: if packet with number i > m_next_packet_num received, - // m_reorder_buffer[i - m_next_packet_num - 1] contains it - std::deque > m_reorder_buffer; - std::size_t m_max_reorder_buffer_size; - TimeNs m_ack_receiver_timout = TimeNs(50000); + TimeNs m_ack_receiver_timout = TimeNs(500000); TimeNs m_last_ack_send = TimeNs(0); bool m_receiver_started = false; }; diff --git a/source/network/connection/rdma/rdma_params.hpp b/source/network/connection/rdma/rdma_params.hpp index d4b0360aa4..c8c8a972a0 100644 --- a/source/network/connection/rdma/rdma_params.hpp +++ b/source/network/connection/rdma/rdma_params.hpp @@ -11,6 +11,5 @@ struct RdmaParams { SizeByte packet_size = SizeByte(1500ul); uint32_t send_window = 256; uint32_t ack_threshold = 32; - SizeByte reorder_buffer_size = Size(64ul); }; } // namespace sim diff --git a/source/parser/network/connection/rdma_connection_parser.cpp b/source/parser/network/connection/rdma_connection_parser.cpp index 3904fe8191..8da351e9ca 100644 --- a/source/parser/network/connection/rdma_connection_parser.cpp +++ b/source/parser/network/connection/rdma_connection_parser.cpp @@ -8,13 +8,14 @@ namespace sim { static EndpointPorts generate_ports() { - static constexpr size_t RANDOM_SEED = 31; - static std::mt19937 rnd(RANDOM_SEED); + // static constexpr size_t RANDOM_SEED = 42; + // static std::mt19937 rnd(RANDOM_SEED); - static constexpr size_t MAX_PORT = 5000; + // static constexpr size_t MAX_PORT = 5000; - static std::uniform_int_distribution range(0, MAX_PORT); - return EndpointPorts(range(rnd), range(rnd)); + // static std::uniform_int_distribution range(0, MAX_PORT); + // return EndpointPorts(range(rnd), range(rnd)); + return EndpointPorts{0, 1}; } RdmaConnectionPtr parse_rdma_connection(std::shared_ptr sender, @@ -30,11 +31,6 @@ RdmaConnectionPtr parse_rdma_connection(std::shared_ptr sender, RdmaParams rdma_params{connection_id, dcqcn, ft}; - if (auto reorder_buffer_size_node = params["reorder_buffer_size"]) { - rdma_params.reorder_buffer_size = - parse_size(reorder_buffer_size_node.value().get_node()); - } - return RdmaConnection::create_shared(rdma_params); } diff --git a/source/topology/device/hashers/ecmp_hasher.cpp b/source/topology/device/hashers/ecmp_hasher.cpp index e491a726dc..03b56a5429 100644 --- a/source/topology/device/hashers/ecmp_hasher.cpp +++ b/source/topology/device/hashers/ecmp_hasher.cpp @@ -13,7 +13,9 @@ static inline std::size_t mix(std::size_t h) { } static inline void hash_combine(std::size_t& seed, std::size_t value) { - seed ^= mix(value) + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2); + static constexpr std::size_t BIT_MASK = 0x99999989; + seed ^= (mix(value) ^ BIT_MASK) + 0x9e3779b97f4a7c15ULL + (seed << 6) + + (seed >> 2); } std::uint32_t ECMPHasher::get_hash(const Packet& packet) { From e1abd879ef2b81c2dab442e775f509cee53cf329 Mon Sep 17 00:00:00 2001 From: Pavel Ralnikov Date: Wed, 6 May 2026 16:59:59 +0300 Subject: [PATCH 07/10] Add sw-based configs for tcp --- configs/leaf-spine-sw_based/network.yml | 90 +++++++++++++++++++ configs/leaf-spine-sw_based/scenario.yml | 28 ++++++ configs/leaf-spine-sw_based/topology.yml | 39 ++++++++ .../mplb/path-chooser/flow/flow_parser.cpp | 10 ++- 4 files changed, 165 insertions(+), 2 deletions(-) create mode 100644 configs/leaf-spine-sw_based/network.yml create mode 100644 configs/leaf-spine-sw_based/scenario.yml create mode 100644 configs/leaf-spine-sw_based/topology.yml diff --git a/configs/leaf-spine-sw_based/network.yml b/configs/leaf-spine-sw_based/network.yml new file mode 100644 index 0000000000..9f1e8dbc42 --- /dev/null +++ b/configs/leaf-spine-sw_based/network.yml @@ -0,0 +1,90 @@ +type: custom +topology_config_path: topology.yml + +connections: + host-1--host-6: + type: mplb-connection + sender_id: host-1 + receiver_id: host-6 + mplb: + type: single-cc + packet-size: 1500B + cc: + type: tahoe + path-chooser: + type: round-robin + flows: + flow: + type: tcp + ports: + sender: 1 + receiver: 1 + host-2--host-6: + type: mplb-connection + sender_id: host-2 + receiver_id: host-6 + mplb: + type: single-cc + packet-size: 1500B + cc: + type: tahoe + path-chooser: + type: round-robin + flows: + flow: + type: tcp + ports: + sender: 1 + receiver: 2 + host-3--host-6: + type: mplb-connection + sender_id: host-3 + receiver_id: host-6 + mplb: + type: single-cc + packet-size: 1500B + cc: + type: tahoe + path-chooser: + type: round-robin + flows: + flow: + type: tcp + ports: + sender: 1 + receiver: 3 + host-4--host-6: + type: mplb-connection + sender_id: host-4 + receiver_id: host-6 + mplb: + type: single-cc + packet-size: 1500B + cc: + type: tahoe + path-chooser: + type: round-robin + flows: + flow: + type: tcp + ports: + sender: 1 + receiver: 4 + host-5--host-6: + type: mplb-connection + sender_id: host-5 + receiver_id: host-6 + mplb: + type: single-cc + packet-size: 1500B + cc: + type: tahoe + path-chooser: + type: round-robin + flows: + flow: + type: tcp + ports: + sender: 1 + receiver: 5 + \ No newline at end of file diff --git a/configs/leaf-spine-sw_based/scenario.yml b/configs/leaf-spine-sw_based/scenario.yml new file mode 100644 index 0000000000..7e96a824a2 --- /dev/null +++ b/configs/leaf-spine-sw_based/scenario.yml @@ -0,0 +1,28 @@ +network_config_path: network.yml + +scenario: +- action: send_data + id: huge-send_1--10 + when: 0ns + size: 10MB + connections: host-1--host-6 +- action: send_data + id: small_2--10 + when: 100000ns + size: 256KB + connections: host-2--host-6 +- action: send_data + id: small_3--10 + when: 100000ns + size: 256KB + connections: host-3--host-6 +- action: send_data + id: small_4--10 + when: 100000ns + size: 256KB + connections: host-4--host-6 +- action: send_data + id: small_5--10 + when: 100000ns + size: 256KB + connections: host-5--host-6 \ No newline at end of file diff --git a/configs/leaf-spine-sw_based/topology.yml b/configs/leaf-spine-sw_based/topology.yml new file mode 100644 index 0000000000..4c3c1890e3 --- /dev/null +++ b/configs/leaf-spine-sw_based/topology.yml @@ -0,0 +1,39 @@ +type: leaf-spine + +presets: + link: + latency: 1000ns + throughput: 10Gbps + ingress_buffer_size: 1MB + egress_buffer_size: 1MB + metrics_filters: + queue_sizes: false + +packet-spraying: + # type: ecmp + type: random + # type: flowlet + # threshold: 500ns + +switches: + spine: + count: 4 + ecn: + min: 0.3 + max: 0.5 + probability: 0.2 + leaf: + ecn: + min: 0.3 + max: 0.5 + probability: 0.2 + count: 6 + +hosts: + +links: + leaf-spine: + preset-name: link + host-leaf: + preset-name: link + throughput: 50Gbps diff --git a/source/parser/network/connection/mplb/path-chooser/flow/flow_parser.cpp b/source/parser/network/connection/mplb/path-chooser/flow/flow_parser.cpp index 3de667899e..f03323b267 100644 --- a/source/parser/network/connection/mplb/path-chooser/flow/flow_parser.cpp +++ b/source/parser/network/connection/mplb/path-chooser/flow/flow_parser.cpp @@ -67,8 +67,14 @@ std::shared_ptr parse_tcp_flow(const ConfigNodeWithPreset& flow_node, TcpFlowMetricsFilters metrics_flags = (metrics_flags_node ? parse_metrics_flags(metrics_flags_node.value()) : TcpFlow::DEFAULT_METRICS_FLAGS); - - EndpointPorts ports = generate_ports(); + EndpointPorts ports; + if (auto exp_ports_nod = flow_node["ports"]) { + auto ports_node = exp_ports_nod.value(); + ports.sender_port = ports_node["sender"].as().value_or_throw(); + ports.sender_port = ports_node["receiver"].as().value_or_throw(); + } else { + ports = generate_ports(); + } return TcpFlow::create_shared(flow_node.get_name_or_throw(), FlowFourTuple(endpoints, ports), ecn_capable, From 7154d5ed4e52bad3b0637b4a9a1acab8ec3ce982 Mon Sep 17 00:00:00 2001 From: Pavel Ralnikov Date: Wed, 6 May 2026 18:52:29 +0300 Subject: [PATCH 08/10] Some configs & results --- configs/leaf-spine-sw_based rdma/network.yml | 76 +++++++++++++++++++ configs/leaf-spine-sw_based rdma/scenario.yml | 28 +++++++ configs/leaf-spine-sw_based rdma/topology.yml | 39 ++++++++++ rdma_results/actions_summary.csv | 5 ++ rdma_results/ecmp_summary.csv | 5 ++ .../connection/rdma/rdma_connection.cpp | 12 +-- .../mplb/path-chooser/flow/flow_parser.cpp | 3 +- .../connection/rdma_connection_parser.cpp | 11 ++- 8 files changed, 171 insertions(+), 8 deletions(-) create mode 100644 configs/leaf-spine-sw_based rdma/network.yml create mode 100644 configs/leaf-spine-sw_based rdma/scenario.yml create mode 100644 configs/leaf-spine-sw_based rdma/topology.yml create mode 100644 rdma_results/actions_summary.csv create mode 100644 rdma_results/ecmp_summary.csv diff --git a/configs/leaf-spine-sw_based rdma/network.yml b/configs/leaf-spine-sw_based rdma/network.yml new file mode 100644 index 0000000000..349e722fc3 --- /dev/null +++ b/configs/leaf-spine-sw_based rdma/network.yml @@ -0,0 +1,76 @@ +type: custom +topology_config_path: topology.yml + +connections: + host-1--host-6: + type: rdma + sender_id: host-1 + receiver_id: host-6 + ports: + sender: 1 + receiver: 1 + dcqcn: + initial_alpha_value: 200 + start_target_rate: 10Gbps + rpg_time_reset: 10000ns + rate_reduce_monitor_period: 500ns + rpg_min_rate: 1Gbps + rpg_ai_rate: 1Mbps + rpg_hai_rate: 2Gbps + host-2--host-6: + type: rdma + sender_id: host-2 + receiver_id: host-6 + ports: + sender: 1 + receiver: 2 + dcqcn: + start_target_rate: 10Gbps + rpg_time_reset: 10000ns + rate_reduce_monitor_period: 500ns + rpg_min_rate: 1Gbps + rpg_ai_rate: 1Mbps + rpg_hai_rate: 2Gbps + host-3--host-6: + type: rdma + sender_id: host-3 + receiver_id: host-6 + ports: + sender: 1 + receiver: 3 + dcqcn: + start_target_rate: 10Gbps + rpg_time_reset: 10000ns + rate_reduce_monitor_period: 500ns + rpg_min_rate: 1Gbps + rpg_ai_rate: 1Mbps + rpg_hai_rate: 2Gbps + host-4--host-6: + type: rdma + sender_id: host-4 + receiver_id: host-6 + ports: + sender: 11 + receiver: 4 + dcqcn: + start_target_rate: 10Gbps + rpg_time_reset: 10000ns + rate_reduce_monitor_period: 500ns + rpg_min_rate: 1Gbps + rpg_ai_rate: 1Mbps + rpg_hai_rate: 2Gbps + host-5--host-6: + type: rdma + sender_id: host-5 + receiver_id: host-6 + ports: + sender: 1 + receiver: 5 + dcqcn: + start_target_rate: 10Gbps + rpg_time_reset: 10000ns + rate_reduce_monitor_period: 500ns + rpg_min_rate: 1Gbps + rpg_ai_rate: 1Mbps + rpg_hai_rate: 2Gbps + \ No newline at end of file diff --git a/configs/leaf-spine-sw_based rdma/scenario.yml b/configs/leaf-spine-sw_based rdma/scenario.yml new file mode 100644 index 0000000000..72b7bed3e6 --- /dev/null +++ b/configs/leaf-spine-sw_based rdma/scenario.yml @@ -0,0 +1,28 @@ +network_config_path: network.yml + +scenario: +- action: send_data + id: huge-send_1--6 + when: 0ns + size: 10MB + connections: host-1--host-6 +- action: send_data + id: small_2--6 + when: 100000ns + size: 256KB + connections: host-2--host-6 +- action: send_data + id: small_3--6 + when: 100000ns + size: 256KB + connections: host-3--host-6 +- action: send_data + id: small_4--6 + when: 100000ns + size: 256KB + connections: host-4--host-6 +# - action: send_data +# id: small_5--6 +# when: 100000ns +# size: 256KB +# connections: host-5--host-6 \ No newline at end of file diff --git a/configs/leaf-spine-sw_based rdma/topology.yml b/configs/leaf-spine-sw_based rdma/topology.yml new file mode 100644 index 0000000000..3296ffdad9 --- /dev/null +++ b/configs/leaf-spine-sw_based rdma/topology.yml @@ -0,0 +1,39 @@ +type: leaf-spine + +presets: + link: + latency: 1000ns + throughput: 10Gbps + ingress_buffer_size: 1MB + egress_buffer_size: 1MB + metrics_filters: + queue_sizes: false + +packet-spraying: + # type: ecmp + # type: random + type: flowlet + threshold: 9000ns + +switches: + spine: + count: 4 + ecn: + min: 0.3 + max: 0.5 + probability: 0.2 + leaf: + ecn: + min: 0.3 + max: 0.5 + probability: 0.2 + count: 6 + +hosts: + +links: + leaf-spine: + preset-name: link + host-leaf: + preset-name: link + throughput: 50Gbps diff --git a/rdma_results/actions_summary.csv b/rdma_results/actions_summary.csv new file mode 100644 index 0000000000..eabe2f87e4 --- /dev/null +++ b/rdma_results/actions_summary.csv @@ -0,0 +1,5 @@ +Data Id, Connection Ids, Data Size (bytes), Time Spent (ns), Throughput (Gbps), Start time (ns), Finish time (ns) +huge-send_1--6, host-1--host-6, 10485760, 1.5055e+07, 5.18931, 0, 1.5055e+07 +small_2--6, host-2--host-6, 262144, 2.32548e+06, 0.839881, 100000, 2.42548e+06 +small_3--6, host-3--host-6, 262144, 2.03506e+06, 0.959739, 100000, 2.13506e+06 +small_4--6, host-4--host-6, 262144, 2.15228e+06, 0.90747, 100000, 2.25228e+06 diff --git a/rdma_results/ecmp_summary.csv b/rdma_results/ecmp_summary.csv new file mode 100644 index 0000000000..085382d9cb --- /dev/null +++ b/rdma_results/ecmp_summary.csv @@ -0,0 +1,5 @@ +Data Id, Connection Ids, Data Size (bytes), Time Spent (ns), Throughput (Gbps), Start time (ns), Finish time (ns) +huge-send_1--6, host-1--host-6, 10485760, 7.82551e+06, 9.98338, 0, 7.82551e+06 +small_2--6, host-2--host-6, 262144, 205666, 9.49659, 100000, 305666 +small_3--6, host-3--host-6, 262144, 205667, 9.49654, 100000, 305667 +small_4--6, host-4--host-6, 262144, 205666, 9.49659, 100000, 305666 diff --git a/source/network/connection/rdma/rdma_connection.cpp b/source/network/connection/rdma/rdma_connection.cpp index c8a0d74822..ca143fbcf7 100644 --- a/source/network/connection/rdma/rdma_connection.cpp +++ b/source/network/connection/rdma/rdma_connection.cpp @@ -185,17 +185,17 @@ void RdmaConnection::process_data_packet(const Packet& packet) { schedule_ack_timer(); } if (packet.packet_num < m_next_expected_packet_num) { - LOG_ERROR( - fmt::format("RDMA receiver got data packet {} with number smaller " - "than expected {}; ignored", - packet.to_string(), m_next_expected_packet_num)); + LOG_ERROR(fmt::format( + "RDMA {}: receiver got data packet {} with number smaller " + "than expected {}; ignored", + m_id, packet.to_string(), m_next_expected_packet_num)); } else if (packet.packet_num == m_next_expected_packet_num) { process_expected_data_packet(); } else { LOG_ERROR(fmt::format( - "RDMA receiver got data packet {} with number greater " + "RDMA {}: receiver got data packet {} with number greater " "than expected {}; could not put it to reorder buffer; ignored", - packet.to_string(), m_next_expected_packet_num)); + m_id, packet.to_string(), m_next_expected_packet_num)); send_nak(); return; } diff --git a/source/parser/network/connection/mplb/path-chooser/flow/flow_parser.cpp b/source/parser/network/connection/mplb/path-chooser/flow/flow_parser.cpp index f03323b267..513bd2b7eb 100644 --- a/source/parser/network/connection/mplb/path-chooser/flow/flow_parser.cpp +++ b/source/parser/network/connection/mplb/path-chooser/flow/flow_parser.cpp @@ -71,7 +71,8 @@ std::shared_ptr parse_tcp_flow(const ConfigNodeWithPreset& flow_node, if (auto exp_ports_nod = flow_node["ports"]) { auto ports_node = exp_ports_nod.value(); ports.sender_port = ports_node["sender"].as().value_or_throw(); - ports.sender_port = ports_node["receiver"].as().value_or_throw(); + ports.receiver_port = + ports_node["receiver"].as().value_or_throw(); } else { ports = generate_ports(); } diff --git a/source/parser/network/connection/rdma_connection_parser.cpp b/source/parser/network/connection/rdma_connection_parser.cpp index 8da351e9ca..10d540a35f 100644 --- a/source/parser/network/connection/rdma_connection_parser.cpp +++ b/source/parser/network/connection/rdma_connection_parser.cpp @@ -27,7 +27,16 @@ RdmaConnectionPtr parse_rdma_connection(std::shared_ptr sender, DCQCN dcqcn = parse_dcqcn(dcqcn_node); - FlowFourTuple ft(Endpoints(sender, receiver), generate_ports()); + EndpointPorts ports; + if (auto exp_ports_node = params["ports"]) { + auto ports_node = exp_ports_node.value(); + ports.sender_port = ports_node["sender"].as().value_or_throw(); + ports.receiver_port = ports_node["receiver"].as().value_or_throw(); + } else { + ports = generate_ports(); + } + + FlowFourTuple ft(Endpoints(sender, receiver), ports); RdmaParams rdma_params{connection_id, dcqcn, ft}; From 4083eff628b6126ccac223fef27f43110889eca1 Mon Sep 17 00:00:00 2001 From: Pavel Ralnikov Date: Thu, 14 May 2026 12:18:54 +0300 Subject: [PATCH 09/10] Fix CI --- source/network/connection/rdma/dcqcn/dcqcn.cpp | 3 ++- source/parser/network/connection/dcqcn_parser.cpp | 7 +++++-- .../parser/network/connection/rdma_connection_parser.cpp | 3 ++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/source/network/connection/rdma/dcqcn/dcqcn.cpp b/source/network/connection/rdma/dcqcn/dcqcn.cpp index aeb149c16d..1dae312b57 100644 --- a/source/network/connection/rdma/dcqcn/dcqcn.cpp +++ b/source/network/connection/rdma/dcqcn/dcqcn.cpp @@ -5,7 +5,8 @@ namespace sim { DCQCN::DCQCN(const ParamsDQCCN& a_params) : m_params(a_params), - m_current_rate(a_params.start_target_rate), + m_current_rate( + std::max(SpeedMbps(m_params.start_target_rate), m_params.rpg_min_rate)), m_target_rate(m_current_rate), m_alpha(m_params.initial_alpha_value) {} diff --git a/source/parser/network/connection/dcqcn_parser.cpp b/source/parser/network/connection/dcqcn_parser.cpp index 9fc8cee148..a13e92fc87 100644 --- a/source/parser/network/connection/dcqcn_parser.cpp +++ b/source/parser/network/connection/dcqcn_parser.cpp @@ -1,4 +1,5 @@ #include "dcqcn_parser.hpp" + #include "parser/parse_utils.hpp" namespace sim { @@ -45,11 +46,13 @@ DCQCN parse_dcqcn(const ConfigNodeWithPreset& node) { // -------- Rate decrement -------- if (auto rate_reduce_period_node = node["rate_reduce_monitor_period"]) { - params.rate_reduce_monitor_period = parse_time(rate_reduce_period_node->get_node()); + params.rate_reduce_monitor_period = + parse_time(rate_reduce_period_node->get_node()); } if (auto first_cnp_rate_node = node["rate_to_set_on_first_cnp"]) { - params.rate_to_set_on_first_cnp = parse_speed(first_cnp_rate_node->get_node()); + params.rate_to_set_on_first_cnp = + parse_speed(first_cnp_rate_node->get_node()); } if (auto clamp_tgt_rate_node = node["clamp_tgt_rate"]) { diff --git a/source/parser/network/connection/rdma_connection_parser.cpp b/source/parser/network/connection/rdma_connection_parser.cpp index 10d540a35f..3267f1407a 100644 --- a/source/parser/network/connection/rdma_connection_parser.cpp +++ b/source/parser/network/connection/rdma_connection_parser.cpp @@ -31,7 +31,8 @@ RdmaConnectionPtr parse_rdma_connection(std::shared_ptr sender, if (auto exp_ports_node = params["ports"]) { auto ports_node = exp_ports_node.value(); ports.sender_port = ports_node["sender"].as().value_or_throw(); - ports.receiver_port = ports_node["receiver"].as().value_or_throw(); + ports.receiver_port = + ports_node["receiver"].as().value_or_throw(); } else { ports = generate_ports(); } From 8365c249607eb99ff3e18138aca4ae130cca2703 Mon Sep 17 00:00:00 2001 From: Pavel Ralnikov Date: Thu, 14 May 2026 12:22:53 +0300 Subject: [PATCH 10/10] Fix --- .../network.yml | 0 .../scenario.yml | 0 .../topology.yml | 0 .../network.yml | 0 .../scenario.yml | 0 .../topology.yml | 0 configs/scenario-configs.txt | 2 ++ rdma_results/actions_summary.csv | 5 ----- rdma_results/ecmp_summary.csv | 5 ----- source/network/connection/rdma/dcqcn/dcqcn.cpp | 4 ++-- 10 files changed, 4 insertions(+), 12 deletions(-) rename configs/{leaf-spine-sw_based rdma => leaf-spine-sw_based_rdma}/network.yml (100%) rename configs/{leaf-spine-sw_based rdma => leaf-spine-sw_based_rdma}/scenario.yml (100%) rename configs/{leaf-spine-sw_based rdma => leaf-spine-sw_based_rdma}/topology.yml (100%) rename configs/{leaf-spine-sw_based => leaf-spine-sw_based_tcp}/network.yml (100%) rename configs/{leaf-spine-sw_based => leaf-spine-sw_based_tcp}/scenario.yml (100%) rename configs/{leaf-spine-sw_based => leaf-spine-sw_based_tcp}/topology.yml (100%) delete mode 100644 rdma_results/actions_summary.csv delete mode 100644 rdma_results/ecmp_summary.csv diff --git a/configs/leaf-spine-sw_based rdma/network.yml b/configs/leaf-spine-sw_based_rdma/network.yml similarity index 100% rename from configs/leaf-spine-sw_based rdma/network.yml rename to configs/leaf-spine-sw_based_rdma/network.yml diff --git a/configs/leaf-spine-sw_based rdma/scenario.yml b/configs/leaf-spine-sw_based_rdma/scenario.yml similarity index 100% rename from configs/leaf-spine-sw_based rdma/scenario.yml rename to configs/leaf-spine-sw_based_rdma/scenario.yml diff --git a/configs/leaf-spine-sw_based rdma/topology.yml b/configs/leaf-spine-sw_based_rdma/topology.yml similarity index 100% rename from configs/leaf-spine-sw_based rdma/topology.yml rename to configs/leaf-spine-sw_based_rdma/topology.yml diff --git a/configs/leaf-spine-sw_based/network.yml b/configs/leaf-spine-sw_based_tcp/network.yml similarity index 100% rename from configs/leaf-spine-sw_based/network.yml rename to configs/leaf-spine-sw_based_tcp/network.yml diff --git a/configs/leaf-spine-sw_based/scenario.yml b/configs/leaf-spine-sw_based_tcp/scenario.yml similarity index 100% rename from configs/leaf-spine-sw_based/scenario.yml rename to configs/leaf-spine-sw_based_tcp/scenario.yml diff --git a/configs/leaf-spine-sw_based/topology.yml b/configs/leaf-spine-sw_based_tcp/topology.yml similarity index 100% rename from configs/leaf-spine-sw_based/topology.yml rename to configs/leaf-spine-sw_based_tcp/topology.yml diff --git a/configs/scenario-configs.txt b/configs/scenario-configs.txt index 661d0a7236..cfc963a97a 100644 --- a/configs/scenario-configs.txt +++ b/configs/scenario-configs.txt @@ -4,3 +4,5 @@ leaf-spine/scenario.yml simple/scenario.yml simple/rdma_scenario.yml single-rack/scenario.yml +leaf-spine-sw_based_tcp/scenario.yml +leaf-spine-sw_based_rdma/scenario.yml diff --git a/rdma_results/actions_summary.csv b/rdma_results/actions_summary.csv deleted file mode 100644 index eabe2f87e4..0000000000 --- a/rdma_results/actions_summary.csv +++ /dev/null @@ -1,5 +0,0 @@ -Data Id, Connection Ids, Data Size (bytes), Time Spent (ns), Throughput (Gbps), Start time (ns), Finish time (ns) -huge-send_1--6, host-1--host-6, 10485760, 1.5055e+07, 5.18931, 0, 1.5055e+07 -small_2--6, host-2--host-6, 262144, 2.32548e+06, 0.839881, 100000, 2.42548e+06 -small_3--6, host-3--host-6, 262144, 2.03506e+06, 0.959739, 100000, 2.13506e+06 -small_4--6, host-4--host-6, 262144, 2.15228e+06, 0.90747, 100000, 2.25228e+06 diff --git a/rdma_results/ecmp_summary.csv b/rdma_results/ecmp_summary.csv deleted file mode 100644 index 085382d9cb..0000000000 --- a/rdma_results/ecmp_summary.csv +++ /dev/null @@ -1,5 +0,0 @@ -Data Id, Connection Ids, Data Size (bytes), Time Spent (ns), Throughput (Gbps), Start time (ns), Finish time (ns) -huge-send_1--6, host-1--host-6, 10485760, 7.82551e+06, 9.98338, 0, 7.82551e+06 -small_2--6, host-2--host-6, 262144, 205666, 9.49659, 100000, 305666 -small_3--6, host-3--host-6, 262144, 205667, 9.49654, 100000, 305667 -small_4--6, host-4--host-6, 262144, 205666, 9.49659, 100000, 305666 diff --git a/source/network/connection/rdma/dcqcn/dcqcn.cpp b/source/network/connection/rdma/dcqcn/dcqcn.cpp index 1dae312b57..c1d5875dcf 100644 --- a/source/network/connection/rdma/dcqcn/dcqcn.cpp +++ b/source/network/connection/rdma/dcqcn/dcqcn.cpp @@ -5,8 +5,8 @@ namespace sim { DCQCN::DCQCN(const ParamsDQCCN& a_params) : m_params(a_params), - m_current_rate( - std::max(SpeedMbps(m_params.start_target_rate), m_params.rpg_min_rate)), + m_current_rate(std::max(SpeedMbps(m_params.start_target_rate), + m_params.rpg_min_rate)), m_target_rate(m_current_rate), m_alpha(m_params.initial_alpha_value) {}