前言
事实上ns3的官方手册很全,相关书籍也是有的,官网先贴在这里:
ns-3.35_wifi-he-network.cc_ns-3网络仿真工具wifi脚本解析_wifi脚本网络拓扑_ns-3wifi6吞吐脚本关键注释_吞吐部分_基础ns-3_ns3.35-优快云博客
ns-3-model-library wifi 浅析_ns-3wifi部分解析_ns-3网络模拟器wifi部分文档分析_Part1_ns3 wifiphy物理层冲突-优快云博客
ns-3-model-library wifi 浅析_ns-3wifi部分解析_ns-3网络模拟器wifi部分文档分析_Part2_yansphy-优快云博客
不过现有的要么版本老旧,要么过于现象化,不够本质,正好我最近分析了下官方手册,在这里分享给大家——需要更加完整的内容,可以直接去官网。
Logging 日志记录
ns-3 日志记录工具可用于监视或调试模拟程序的进度。可以通过 main() 程序中的 program 语句或使用 NS_LOG 环境变量来启用日志记录输出。 日志记录语句未编译为 ns-3 的optimized 版本。要使用日志记录,必须使用 ns-3 的默认或debug 构建配置文件。该项目不保证日志记录输出是否会随着时间的推移而保持不变。警告用户不要在日志记录代码之上构建仿真输出框架,因为输出和启用输出的方式可能会随着时间的推移而变化。
概述
NS-3 日志记录语句通常用于记录各种程序执行事件,例如模拟事件的发生或特定函数的使用。例如,此代码片段来自 TcpSocketBase::EnterCwr() 并通知用户模型正在减少拥塞窗口并更改状态:
NS_LOG_INFO("Enter CWR recovery mode; set cwnd to " << m_tcb->m_cWnd << ", ssthresh to "
<< m_tcb->m_ssThresh << ", recover to "
<< m_recover);
如果已为 Ipv4L3Protocol 组件启用了严重性为 INFO 或更高的日志记录(请参阅下面的日志严重性),则该语句将被打印出来;否则,它将被抑制。日志记录实现在 debug 和 default 版本中启用,但在所有其他构建配置文件中禁用,因此它不会影响更优化的配置文件的执行速度。您可以尝试 src/core/example 中的示例程序 log-example.cc,其中包含 NS_LOG 环境变量的各种值,以查看下面讨论的选项的效果。
启用输出
用户通常有两种方式来控制日志输出。第一种是通过设置 NS_LOG 环境变量;例如:
$ NS_LOG="*" ./ns3 run first
将运行first 包含所有日志记录输出的教程程序。(NS_LOG 格式的细节将在下面讨论。这可以通过选择单个组件来更加精细:
$ NS_LOG="Ipv4L3Protocol" ./ns3 run first
可以使用 prefix 选项进一步定制输出。启用日志记录的第二种方法是在程序中使用显式语句,例如在first 教程程序中:
int
main(int argc, char *argv[])
{
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);
...
(LOG_LEVEL_INFO 的含义和其他可能的值将在下面讨论。
NS_LOG 语法
NS_LOG 环境变量包含日志组件和选项的列表。日志组件由 ':' 字符分隔:
$ NS_LOG="<log-component>:<log-component>..."
每个 log 组件的选项在每个 log 组件之后作为标志给出:
$ NS_LOG="<log-component>=<option>|<option>...:<log-component>..."
选项控制该组件的严重性和级别,以及是否应包含可选信息,例如模拟时间、模拟节点、函数名称和符号严重性。
日志组件
通常,日志组件引用单个源代码 .cc 文件,并包含整个文件。一些 helpers 有特殊的方法来启用模块中所有组件的日志记录,跨越不同的编译单元,但在逻辑上组合在一起,例如 ns-3 wifi 代码:
WifiHelper wifiHelper;
wifiHelper.EnableLogComponents();
NS_LOG log 组件通配符 '*' 将启用所有组件。
要查看定义了哪些日志组件,以下任何一个都可以:
$ NS_LOG="print-list" ./ns3 run ...
$ NS_LOG="foo" # a token not matching any log-component
第一种表单将打印链接的所有日志组件的名称和启用标志;用 scratch-simulator 试试。第二个表单打印所有已注册的日志组件,然后退出并显示错误。
Severity and Level Options
单个消息属于单个 “严重性类”,由创建消息的宏设置。在上面的示例中,NS_LOG_INFO(..) 在 LOG_INFO 严重性类中创建消息。以下严重性类定义为枚举常量:
通常,人们希望看到给定严重性等级和更高级别的消息。这是通过定义包含日志记录 “levels” 来完成的:
severity class 和 level 选项可以通过以下令牌在 NS_LOG 环境变量中给出:
使用严重性类令牌仅启用该严重性的日志消息。例如,NS_LOG=“*=warn” 不会输出严重性为 error 的消息。NS_LOG=“*=level_debug” 将输出严重性级别为 debug 及以上的消息。
严重性等级和级别可以与 '|' 运算符组合使用:NS_LOG=“*=level_warn|debug” 将输出严重性级别 error、warn 和 debug 的消息,但不会输出 info、function 或 logic。NS_LOG 严重性级别通配符 '*' 和 all 都是 level_all 的同义词。对于仅在 NS_LOG 中提及的日志组件
$ NS_LOG="<log-component>:..."
默认严重性为 LOG_LEVEL_ALL。
Prefix Options
许多前缀可以帮助识别消息的来源和时间以及严重性。可用的 prefix 选项(作为枚举常量)包括
下面简要介绍了 prefix 选项。这些选项可以通过以下令牌在 NS_LOG 环境变量中给出:
对于仅在 NS_LOG 中提及的日志组件默认前缀选项为 LOG_PREFIX_ALL。
Severity Prefix¶
消息的严重性类可以包含在选项 prefix_level 或 level 中。例如,此值 NS_LOG 启用所有日志组件 ('*') 和所有严重性类 (=all) 的日志记录,并在消息前面加上严重性类 (|prefix_level)。
$ NS_LOG="*=all|prefix_level" ./ns3 run scratch-simulator Scratch Simulator [ERROR] error message [WARN] warn message [INFO] info message [FUNCT] function message [LOGIC] logic message [DEBUG] debug message
Time Prefix
模拟时间可以包含在 prefix_time 或 time 选项中。这将以秒为单位打印模拟时间。
Node Prefix
模拟节点 ID 可以包含在选项 prefix_node 或 node 中。
Function Prefix
调用函数的名称可以包含在选项 prefix_func 或 func 中。
NS_LOG Wildcards
日志组件通配符 '*' 将启用所有组件。要启用特定严重性级别的所有组件,请使用 *=<severity>。严重性级别选项通配符 '*' 是 all 的同义词。这必须发生在分隔选项的任何 '|' 字符之前。要启用所有严重性等级,请使用 <log-component>=* 或 <log-component>=*|<options>。
后面暂时没有需求
如何向代码添加日志记录
将日志记录添加到您的代码中非常简单:
调用 NS_LOG_COMPONENT_DEFINE(...); 内部 namespace ns3 的宏。创建唯一的字符串标识符(通常基于文件名称和/或文件中定义的类)并使用宏调用注册它,如下所示:
namespace ns3 {
NS_LOG_COMPONENT_DEFINE("Ipv4L3Protocol");
这会将 Ipv4L3Protocol 注册为日志组件。(该宏经过精心编写,允许在命名空间 ns3 内部或外部包含,并且用法会因代码库而异,但最初的目的是在命名空间 ns3 之外的文件全局范围内注册它。
将日志记录语句(宏调用)添加到您的函数和函数体中。
如果要将日志记录语句添加到模板类的方法(在头文件中定义):
在类声明的 private 部分中调用 NS_LOG_TEMPLATE_DECLARE; 宏。例如:
template <typename Item>
class Queue : public QueueBase
{
...
private:
std::list<Ptr<Item>> m_packets; //!< the items in the queue
NS_LOG_TEMPLATE_DECLARE; //!< the log component
};
这要求您对类的所有子类执行这些步骤。
通过提供通过在某些模块中调用 NS_LOG_TEMPLATE_DEFINE NS_LOG_COMPONENT_DEFINE(...;) 宏注册的日志组件的名称,在类的构造函数中调用 (...); 宏。例如:
template <typename Item>
Queue<Item>::Queue()
: NS_LOG_TEMPLATE_DEFINE("Queue")
{
}
将日志记录语句(宏调用)添加到类的方法中。
如果要将日志记录语句添加到静态成员模板(在头文件中定义):
通过提供通过在某些模块中调用 NS_LOG_COMPONENT_DEFINE(...;宏而注册的日志组件的名称),在静态方法中调用 NS_LOG_STATIC_TEMPLATE_DEFINE
(...); 宏。例如:
template <typename Item>
void
NetDeviceQueue::PacketEnqueued(Ptr<Queue<Item>> queue,
Ptr<NetDeviceQueueInterface> ndqi,
uint8_t txq, Ptr<const Item> item)
{
NS_LOG_STATIC_TEMPLATE_DEFINE("NetDeviceQueueInterface");
...
将日志记录语句(宏调用)添加到静态方法中。
后面的注意事项没有需求
控制时间戳精度
时间戳以秒为单位打印出来。当与默认的 ns-3 时间分辨率(纳秒)一起使用时,默认时间戳精度为 9 位数字,采用固定格式,以允许将 9 位数字一致地打印到小数点右侧。例:
+0.000123456s RandomVariableStream:SetAntithetic(0x805040, 0)
当 ns-3 模拟使用更高的时间分辨率(如皮秒或飞秒)时,精度会相应扩展;例如,对于 PicoSecond:
+0.000123456789s RandomVariableStream:SetAntithetic(0x805040, 0)
当 ns-3 模拟使用低于微秒的时间分辨率时,将使用默认的 C++ 精度。上的 src/core/examples/sample-log-time-format.cc 示例程序演示了如何更改时间戳格式。最大有用精度为 20 位十进制数字,因为 Time 是 64 位的符号。
Asserts 断言
ns-3 断言工具可用于验证在执行过程中是否满足不变条件。如果不满足条件,则给出错误消息,程序停止,打印失败断言的位置。assert 实现在 debug 和 default 版本中启用,但在所有其他 build 配置文件中禁用,以提高执行速度。
如何向代码添加断言
只有一个宏应该使用:
NS_ASSERT_MSG(condition, message);
condition应该是你想要测试的不变量,作为一个布尔表达式。该消息应说明条件的含义和/或错误的可能来源。有一个不带消息的变体 NS_ASSERT(condition),但我们建议在 ns-3 库代码中使用消息变体,因为精心设计的消息可以帮助用户弄清楚如何解决其脚本的根本问题。在任何一种情况下,如果条件的计算结果为 false,则 assert 都会向 std::cerr 打印一条错误消息,其中包含以下信息:
- 错误消息:“NS_ASSERT失败,”
- 表达式 condition :“cond=” condition ”
- 的 message : “msg=” message ”
- 模拟时间和节点,如 logging 打印的那样。这些是独立于任何日志记录组件上设置的标志或前缀打印的。
- 包含断言的文件和行: “file=''file'', line=''line''
下面是一个没有断言的示例:
$ ./ns3 run assert-example
[0/2] Re-checking globbed directories... ninja: no work to do. NS_ASSERT_MSG example if an argument is given this example will assert.
下面是一个可以做到的:
$ ./ns3 run assert-example -- foo [0/2] Re-checking globbed directories... ninja: no work to do. NS_ASSERT_MSG example if an argument is given this example will assert. NS_ASSERT failed, cond="argc == 1", msg="An argument was given, so we assert", file=/Users/barnes26/Code/netsim/ns3/repos/ns-3-dev/src/core/examples/assert-example.cc, line=44 NS_FATAL, terminating terminate called without an active exception Command 'build/debug/src/core/examples/ns3-dev-assert-example-debug foo' died with <Signals.SIGABRT: 6>.
你可以尝试 src/core/example 中 assert-example.cc 的示例程序,带或不带参数来查看 NS_ASSERT_MSG 的作。