2023-09-16基于 ns-3 的
Unison 网络仿真器
本文介绍一款面向 ns-3
的快速、对用户透明的并行仿真器实现——Unison。
Unison
采用细粒度划分与负载自适应调度,用户无需额外配置,即可轻松对模型进行多线程并行仿真。
同时,细粒度划分降低了缓存缺失,负载自适应调度最小化了线程间的相互等待时间,从而实现高效并行。
有关 Unison 的更多信息可参见我们的 EuroSys
’24 论文。
支持的 ns-3 版本:≥ 3.36.1。 我们会持续让 Unison 适配
ns-3 的最新版本。 你可以通过 unison-*
标签找到各个支持 Unison 的 ns-3 版本。
快速开始
最快的上手方式是执行命令:
./ns3 configure --enable-mtp --enable-examples
此时编译配置为默认模式(使用 -O2 -g
编译选项)。 若希望使用 -O3
优化编译并关闭所有日志输出,请添加
-d optimized 参数。
--enable-mtp 选项将启用多线程并行。
你可以在可选功能列表中查看是否出现
Multithreaded Simulation : ON,以确认
Unison 已启用。
现在,我们分别编译并运行默认串行仿真与并行仿真(使用
4 线程)的 DCTCP 示例:
./ns3 build dctcp-example dctcp-example-mtp
time ./ns3 run dctcp-example
time ./ns3 run dctcp-example-mtp
dctcp-example 仿真通常需要 4–5
分钟,dctcp-example-mtp 只需 1–2
分钟,具体取决于硬件与编译配置。 *.dat
文件中的输出应与源文件中的注释一致。
拓扑规模越大、流量越大,Unison 的加速效果越显著。
如果你希望用它仿真胖树(fat-tree)、BCube、二维环网(2D-torus)等拓扑,请参考运行评估。
为现有代码加速
为了理解 Unison
如何作用于你的模型代码,我们对比上述示例的两个版本源文件:
diff examples/tcp/dctcp-example.cc examples/mtp/dctcp-example-mtp.cc
可以看到,只需在现有模型代码中引入头文件
ns3/mtp-interface.h,并在 main
函数开头添加一行:
MtpInterface::Enable(numberOfThreads);
即可启用 Unison。
参数 numberOfThreads 是可选的。
若省略,线程数将自动选择,且不超过系统可用硬件线程的最大值。
若希望在现有 MPI 程序上启用 Unison
进行分布式仿真以进一步加速,请将上述代码放在 MPI
初始化之前,且不要在代码中显式指定仿真器实现。
对于这种与 MPI 混合的仿真,配置 ns-3 时还需要添加
--enable-mpi 选项。
Unison 解决了 ns-3 架构中大量线程安全问题。
大多数情况下你无需自行处理这些问题,除非你使用了内置流量监控(flow-monitor)之外的自定义全局统计量。
对于后者,如果多个节点可能访问你的全局统计量,可以用
std::atomic<> 将其替换为原子变量。
在采集 Pcap
等追踪数据时,强烈建议为每个节点生成独立输出文件,而非单一追踪文件。
对于复杂的自定义数据结构,可在方法开头添加:
MtpInterface::CriticalSection cs;
来创建临界区。
示例
除 DCTCP 示例外,你还可以在 examples/mtp
中找到其他适配示例。 同时,Unison
也支持手动划分,最简示例位于
src/mtp/examples/simple-mtp.cc。 对于与 MPI
混合的仿真,最简示例位于
src/mpi/examples/simple-hybrid.cc。
我们还为 Unison、传统 MPI
并行仿真与混合仿真提供了三个详细的胖树示例:
| fat-tree-mtp | src/mtp/examples/fat-tree-mtp.cc | --enable-mtp --enable-examples(不含
--enable-mpi) | ./ns3 run "fat-tree-mtp --thread=4" |
| fat-tree-mpi | src/mpi/examples/fat-tree-mpi.cc | --enable-mpi --enable-examples(不含
--enable-mtp) | ./ns3 run fat-tree-mpi --command-template "mpirun -np 4 %s" |
| fat-tree-hybrid | src/mpi/examples/fat-tree-hybrid.cc | --enable-mtp --enable-mpi --enable-examples | ./ns3 run fat-tree-hybrid --command-template "mpirun -np 2 %s --thread=2" |
你可以自由探索这些示例,对比代码改动,并调整
-np 与 --thread 参数。
运行评估
若要评估 Unison,请切换到 unison-evaluations
分支,该分支基于 ns-3.36.1。
在该分支中,scratch
文件夹下包含多种拓扑模型。 每个拓扑都有大量可配置参数。
我们提供了工具脚本 exp.py
用于对比不同仿真器与参数, 同时提供
process.py 将原始实验数据转换为适合绘图的
CSV 文件。 更多细节请参见 该分支的
README。
本次评估制品(基于 ns-3.36.1)的永久 DOI 索引为:10.5281/zenodo.10077300。
模块文档
1. 概述
适用于 ns-3 的 Unison 主要在 mtp
模块中实现(位于 src/mtp/*),mtp
即多线程并行(multi-threaded parallelization)。
该模块包含三部分:并行仿真器实现
multithreaded-simulator-impl、面向用户的接口
mtp-interface,以及用于表示并行仿真中逻辑进程(LP)的
logical-process。
所有逻辑进程(LP)与线程均存储在
mtp-interface 中。 它控制仿真进度、将 LP
调度到线程、并管理 LP 与线程的生命周期。
该接口还提供了一些方法与选项供用户调整仿真行为。
每个 LP 的逻辑在 logical-process
中实现。
它包含默认串行仿真器的大部分方法,以及一些用于并行仿真的辅助方法。
仿真器实现 multithreaded-simulator-impl
继承自基础仿真器。
它根据当前线程上下文,将对基础仿真器的调用转发到对应逻辑进程。
同时提供了用于拓扑自动细粒度划分的划分方法。
对于基于 MPI 的分布式仿真,我们在 mpi
模块中新增了 hybrid-simulator-impl(位于
src/mpi/model/hybrid-simulator-impl*)。
该仿真器同时使用 mtp-interface 与
mpi-interface 协调本地 LP 与全局 MPI 通信。
我们还对模块进行了修改,使其在本地具备线程安全性。
2. 对 ns-3 架构的修改
除 mtp 与 mpi
模块外,我们还对 ns-3
架构的以下部分进行了线程安全改造,并修复了部分 ns-3
漏洞。 你可以通过 git diff unison-* ns-*
查看每个支持 Unison 的 ns-3 版本的具体改动。
对构建系统的修改,用于提供 --enable-mtp
选项以启用/禁用 Unison:
ns3 | 2 +
CMakeLists.txt | 1 +
build-support/custom-modules/ns3-configtable.cmake | 3 +
build-support/macros-and-definitions.cmake | 10 +
对 core
模块的修改,使引用计数具备线程安全性:
src/core/CMakeLists.txt | 1 +
src/core/model/atomic-counter.h | 50 +
src/core/model/hash.h | 16 +
src/core/model/object.cc | 2 +
src/core/model/simple-ref-count.h | 11 +-
对 network
模块的修改,使数据包具备线程安全性:
src/network/model/buffer.cc | 15 +-
src/network/model/buffer.h | 7 +
src/network/model/byte-tag-list.cc | 14 +-
src/network/model/node.cc | 7 +
src/network/model/node.h | 7 +
src/network/model/packet-metadata.cc | 26 +-
src/network/model/packet-metadata.h | 14 +-
src/network/model/packet-tag-list.h | 11 +-
src/network/model/socket.cc | 6 +
对 internet
模块的修改,使其线程安全并增加逐流 ECMP 路由:
src/internet/model/global-route-manager-impl.cc | 2 +
src/internet/model/ipv4-global-routing.cc | 32 +-
src/internet/model/ipv4-global-routing.h | 8 +-
src/internet/model/ipv4-packet-info-tag.cc | 2 +
src/internet/model/ipv6-packet-info-tag.cc | 2 +
src/internet/model/tcp-option.cc | 2 +-
对 flow-monitor
模块的修改,使其线程安全:
src/flow-monitor/model/flow-monitor.cc | 48 +
src/flow-monitor/model/flow-monitor.h | 4 +
src/flow-monitor/model/ipv4-flow-classifier.cc | 12 +
src/flow-monitor/model/ipv4-flow-classifier.h | 5 +
src/flow-monitor/model/ipv4-flow-probe.cc | 2 +
src/flow-monitor/model/ipv6-flow-classifier.cc | 12 +
src/flow-monitor/model/ipv6-flow-classifier.h | 5 +
src/flow-monitor/model/ipv6-flow-probe.cc | 2 +
对 nix-vector-routing
模块的修改,使其线程安全:
src/nix-vector-routing/model/nix-vector-routing.cc | 92 ++
src/nix-vector-routing/model/nix-vector-routing.h | 8 +
对 mpi
模块的修改,使其在混合仿真器下线程安全:
src/mpi/model/granted-time-window-mpi-interface.cc | 25 +
src/mpi/model/granted-time-window-mpi-interface.h | 7 +
src/mpi/model/mpi-interface.cc | 3 +-
3. 日志
Unison
速度快的原因在于:它将网络以细粒度划分为多个逻辑进程(LP),并对其进行动态调度。
如需了解该流程的更多细节,可以启用以下日志组件:
LogComponentEnable("LogicalProcess", LOG_LEVEL_INFO);
LogComponentEnable("MultithreadedSimulatorImpl", LOG_LEVEL_INFO);
4. 高级选项
这些选项可以在 main 函数开头使用 ns-3
原生配置语法修改。
你也可以通过以下方式修改默认最大线程数:
Config::SetDefault("ns3::MultithreadedSimulatorImpl::MaxThreads", UintegerValue(8));
Config::SetDefault("ns3::HybridSimulatorImpl::MaxThreads", UintegerValue(8));
自动划分会切断延迟高于阈值的无状态链路。
该阈值基于所有链路的延迟自动计算。
若对划分结果不满意,可自定义阈值:
Config::SetDefault("ns3::MultithreadedSimulatorImpl::MinLookahead", TimeValue(NanoSeconds(500)));
Config::SetDefault("ns3::HybridSimulatorImpl::MinLookahead", TimeValue(NanoSeconds(500)));
调度方式决定每个逻辑进程的优先级(下一轮预估完成时间)。
共有五种可选策略:
ByExecutionTime:上一轮执行时间更长的
LP 优先级更高。ByPendingEventCount:本轮待处理事件更多的
LP 优先级更高。ByEventCount:与
ByPendingEventCount 含义相同。BySimulationTime:当前仿真时钟更大的 LP
优先级更高。None:不进行调度,按划分 ID
决定优先级。
大量实验表明,第一种通常性能更好。
你也可以根据需要选择:
GlobalValue::Bind("PartitionSchedulingMethod", StringValue("ByExecutionTime"));
默认情况下,划分数小于 16 时调度周期为 2,小于 256
时为 3,小于 4096 时为 4,依此类推。
因为划分越多,调度开销越大。
你也可以手动设置调度频率:
GlobalValue::Bind("PartitionSchedulingPeriod", UintegerValue(4));
引用与链接
如果你觉得代码有用,请考虑引用 我们的论文。
@inproceedings{10.1145/3627703.3629574,
author = {Bai, Songyuan and Zheng, Hao and Tian, Chen and Wang, Xiaoliang and Liu, Chang and Jin, Xin and Xiao, Fu and Xiang, Qiao and Dou, Wanchun and Chen, Guihai},
title = {Unison: A Parallel-Efficient and User-Transparent Network Simulation Kernel},
year = {2024},
isbn = {9798400704376},
publisher = {Association for Computing Machinery},
address = {New York, NY, USA},
url = {https://doi.org/10.1145/3627703.3629574},
doi = {10.1145/3627703.3629574},
abstract = {Discrete-event simulation (DES) is a prevalent tool for evaluating network designs. Although DES offers full fidelity and generality, its slow performance limits its application. To speed up DES, many network simulators employ parallel discrete-event simulation (PDES). However, adapting existing network simulation models to PDES requires complex reconfigurations and often yields limited performance improvement. In this paper, we address this gap by proposing a parallel-efficient and user-transparent network simulation kernel, Unison, that adopts fine-grained partition and load-adaptive scheduling optimized for network scenarios. We prototype Unison based on ns-3. Existing network simulation models of ns-3 can be seamlessly transitioned to Unison. Testbed experiments on commodity servers demonstrate that Unison can achieve a 40\texttimes{} speedup over DES using 24 CPU cores, and a 10\texttimes{} speedup compared with existing PDES algorithms under the same CPU cores.},
booktitle = {Proceedings of the Nineteenth European Conference on Computer Systems},
pages = {115–131},
numpages = {17},
keywords = {Data center networks, Network simulation, Parallel discrete-event simulation},
location = {Athens, Greece},
series = {EuroSys '24}
}
以下链接可能对你有帮助: