Skip to content

Commit 5a16b6d

Browse files
Fixes for TX HDS and added to main HDS config (#1236)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Fixed packet segment chaining in scatter-gather transmit paths, improving transmission reliability. * **New Features** * Added a large CPU-side TX memory region with many small buffers to increase transmit capacity. * **Improvements** * Converted header/data split to a boolean flag across TX configs for clearer behavior. * Refined GPU-direct, header and payload handling for more consistent transmission. * **Chores** * Minor config formatting and comment updates. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Cliff Burdick <[email protected]> Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
1 parent f0e97ca commit 5a16b6d

File tree

6 files changed

+34
-22
lines changed

6 files changed

+34
-22
lines changed

applications/adv_networking_bench/adv_networking_bench_default_sw_loopback.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ bench_rx:
7777
bench_tx:
7878
interface_name: "loopback_ports" # Name of the TX port from the advanced_network config
7979
gpu_direct: true # Set to true if using a GPU region for the Tx queues.
80-
split_boundary: 0 # Byte boundary where header and data is split, 0 if no split
80+
split_boundary: false # True if header-data split is enabled
8181
batch_size: 10240
8282
payload_size: 1000
8383
header_size: 64

applications/adv_networking_bench/adv_networking_bench_default_tx_rx.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ bench_rx:
8888
bench_tx:
8989
interface_name: "tx_port" # Name of the TX port from the advanced_network config
9090
gpu_direct: true # Set to true if using a GPU region for the Tx queues.
91-
split_boundary: 0 # Byte boundary where header and data is split, 0 if no split
91+
split_boundary: false # True if header-data split is enabled
9292
batch_size: 10240
9393
payload_size: 1000
9494
header_size: 64

applications/adv_networking_bench/adv_networking_bench_default_tx_rx_hds.yaml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ advanced_network:
3131
loopback: ""
3232

3333
memory_regions:
34+
- name: "Data_TX_CPU"
35+
kind: "huge"
36+
affinity: 0
37+
num_bufs: 51200
38+
buf_size: 64
3439
- name: "Data_TX_GPU"
3540
kind: "device"
3641
affinity: 0
@@ -57,11 +62,12 @@ advanced_network:
5762
batch_size: 10240
5863
cpu_core: 11
5964
memory_regions:
65+
- "Data_TX_CPU"
6066
- "Data_TX_GPU"
6167
offloads:
6268
- "tx_eth_src"
6369
- name: "rx_port"
64-
address: <0000:00:00.0> # The BUS address of the interface doing Rx
70+
address: <0000:00:00.0> # The BUS address of the interface doing Rx
6571
rx:
6672
flow_isolation: true
6773
queues:
@@ -94,7 +100,7 @@ bench_rx:
94100
bench_tx:
95101
interface_name: "tx_port" # Name of the TX port from the advanced_network config
96102
gpu_direct: true # Set to true if using a GPU region for the Tx queues.
97-
split_boundary: 0 # Byte boundary where header and data is split, 0 if no split
103+
split_boundary: true # Whether header and data is split (Header to CPU, payload to GPU)
98104
batch_size: 10240
99105
payload_size: 1000
100106
header_size: 64

applications/adv_networking_bench/adv_networking_bench_default_tx_rx_multi_q_hds.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ bench_rx:
340340
bench_tx:
341341
interface_name: tx_port
342342
gpu_direct: false
343-
split_boundary: 0
343+
split_boundary: false
344344
batch_size: 10240
345345
payload_size: 1000
346346
header_size: 64

applications/adv_networking_bench/cpp/default_bench_op_tx.h

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
33
* SPDX-License-Identifier: Apache-2.0
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -144,7 +144,7 @@ class AdvNetworkingBenchDefaultTxOp : public Operator {
144144
// This section simply serves as an example to get an Eth+IP+UDP header onto the GPU,
145145
// but this header will not be correct without modification of the IP and MAC. In a
146146
// real situation the header would likely be constructed on the GPU
147-
if (gpu_direct_.get() && hds_.get() == 0) {
147+
if (gpu_direct_.get() && !hds_.get()) {
148148
cudaMalloc(&gds_header_, header_size_.get());
149149
cudaMemset(gds_header_, 0, header_size_.get());
150150

@@ -168,15 +168,15 @@ class AdvNetworkingBenchDefaultTxOp : public Operator {
168168
"Payload size",
169169
"Payload size to send including HDS portion",
170170
1400);
171-
spec.param<int>(hds_,
172-
"split_boundary",
173-
"Header-data split boundary",
174-
"Byte boundary where header and data is split",
175-
0);
171+
spec.param<bool>(hds_,
172+
"split_boundary",
173+
"Header-data split boundary",
174+
"Whether header and data is split (Header to CPU, payload to GPU)",
175+
false);
176176
spec.param<bool>(gpu_direct_,
177177
"gpu_direct",
178178
"GPUDirect enabled",
179-
"Byte boundary where header and data is split",
179+
"Whether GPUDirect is enabled",
180180
false);
181181
spec.param<std::string>(udp_src_port_str_,
182182
"udp_src_port", "UDP source port",
@@ -212,7 +212,11 @@ class AdvNetworkingBenchDefaultTxOp : public Operator {
212212
}
213213

214214
auto msg = create_tx_burst_params();
215-
set_header(msg, port_id_, queue_id, batch_size_.get(), hds_.get() > 0 ? 2 : 1);
215+
set_header(msg,
216+
port_id_,
217+
queue_id,
218+
batch_size_.get(),
219+
(gpu_direct_.get() && hds_.get()) ? 2 : 1);
216220

217221
/**
218222
* Spin waiting until a buffer is free. This can be stalled by sending faster than the NIC can
@@ -242,7 +246,7 @@ class AdvNetworkingBenchDefaultTxOp : public Operator {
242246

243247
// For HDS mode or CPU mode populate the packet headers
244248
for (int num_pkt = 0; num_pkt < get_num_packets(msg); num_pkt++) {
245-
if (!gpu_direct_.get() || hds_.get() > 0) {
249+
if (!gpu_direct_.get() || hds_.get()) {
246250
if ((ret = set_eth_header(msg, num_pkt, eth_dst_)) != Status::SUCCESS) {
247251
HOLOSCAN_LOG_ERROR("Failed to set Ethernet header for packet {}", num_pkt);
248252
free_all_packets_and_burst_tx(msg);
@@ -273,7 +277,7 @@ class AdvNetworkingBenchDefaultTxOp : public Operator {
273277
udp_dst_idx_ = (++udp_dst_idx_ % udp_dst_ports_.size());
274278

275279
// Only set payload on CPU buffer if we're not in HDS mode
276-
if (hds_.get() == 0) {
280+
if (!hds_.get()) {
277281
if ((ret = set_udp_payload(
278282
msg,
279283
num_pkt,
@@ -287,10 +291,10 @@ class AdvNetworkingBenchDefaultTxOp : public Operator {
287291
}
288292

289293
// Figure out the CPU and GPU length portions for advanced_network
290-
if (gpu_direct_.get() && hds_.get() > 0) {
294+
if (gpu_direct_.get() && hds_.get()) {
291295
gpu_bufs[cur_idx][num_pkt] =
292296
reinterpret_cast<uint8_t*>(get_segment_packet_ptr(msg, 1, num_pkt));
293-
if ((ret = set_packet_lengths(msg, num_pkt, {hds_.get(), payload_size_.get()})) !=
297+
if ((ret = set_packet_lengths(msg, num_pkt, {header_size_.get(), payload_size_.get()})) !=
294298
Status::SUCCESS) {
295299
HOLOSCAN_LOG_ERROR("Failed to set lengths for packet {}", num_pkt);
296300
free_all_packets_and_burst_tx(msg);
@@ -313,7 +317,7 @@ class AdvNetworkingBenchDefaultTxOp : public Operator {
313317
}
314318

315319
// In GPU-only mode copy the header
316-
if (gpu_direct_.get() && hds_.get() == 0) {
320+
if (gpu_direct_.get() && !hds_.get()) {
317321
copy_headers(gpu_bufs[cur_idx],
318322
gds_header_,
319323
header_size_.get(),
@@ -323,7 +327,7 @@ class AdvNetworkingBenchDefaultTxOp : public Operator {
323327

324328
// Populate packets with 16-bit numbers of {0,0}, {1,1}, ...
325329
if (gpu_direct_.get()) {
326-
const auto offset = (hds_.get() > 0) ? 0 : header_size_.get();
330+
const auto offset = hds_.get() ? 0 : header_size_.get();
327331
populate_packets(gpu_bufs[cur_idx],
328332
payload_size_.get(),
329333
get_num_packets(msg),
@@ -371,7 +375,7 @@ class AdvNetworkingBenchDefaultTxOp : public Operator {
371375
size_t udp_dst_idx_ = 0;
372376
std::vector<uint16_t> udp_src_ports_;
373377
std::vector<uint16_t> udp_dst_ports_;
374-
Parameter<int> hds_; // Header-data split point
378+
Parameter<bool> hds_; // Header-data split enabled
375379
Parameter<bool> gpu_direct_; // GPUDirect enabled
376380
Parameter<uint32_t> batch_size_;
377381
Parameter<uint16_t> header_size_; // Header size of packet

operators/advanced_network/advanced_network/managers/dpdk/adv_network_dpdk_mgr.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2220,11 +2220,13 @@ int DpdkMgr::tx_core_worker(void* arg) {
22202220
// Scatter mode needs to chain all the buffers
22212221
if (msg->hdr.hdr.num_segs > 1) {
22222222
for (size_t p = 0; p < msg->hdr.hdr.num_pkts; p++) {
2223-
for (int seg = 0; seg < msg->hdr.hdr.num_segs; seg++) {
2223+
for (int seg = 0; seg < msg->hdr.hdr.num_segs - 1; seg++) {
22242224
auto* mbuf = reinterpret_cast<struct rte_mbuf*>(msg->pkts[seg][p]);
22252225
mbuf->next = reinterpret_cast<struct rte_mbuf*>(msg->pkts[seg + 1][p]);
22262226
}
22272227

2228+
// The next pointer of the last segment should be nullptr
2229+
reinterpret_cast<struct rte_mbuf*>(msg->pkts[msg->hdr.hdr.num_segs - 1][p])->next = nullptr;
22282230
reinterpret_cast<struct rte_mbuf*>(msg->pkts[0][p])->nb_segs = msg->hdr.hdr.num_segs;
22292231
}
22302232
}

0 commit comments

Comments
 (0)