简介
更改gem5源代码后,有时候想看看改变有没有成功,效果怎么样,需要监控一下结果.有两种方式,debug模式下,命令行窗口打印出来,就像cpp的 cout或python的print一样,这是dprintf. 或者利用gem5自带的输出功能,本来它会有一个统计文件叫stat.txt,作为输出,我们可以复用add_stat功能,将我们需要打印的值,打印到stat.txt里
1 . dprintf
DPRINTF is a debugging trace facility that allows one to
- selectively enable tracing statements. To use DPRINTF, there must
- be a function or functor called name() that returns a const
- std::string & in the current scope.
2.1 GEM5传统的扁平化统计方式
非常直观,如果要添加一个统计量,直接定义一个新变量
Stats::Scalar totalReadLatency;
然后再需要给它赋值的时候写代码给它赋值就好了,比如每得到一个包的onePacketreadlatency,
totalReadLatency =totalReadLatency + onePacketreadlatency
2.2 新的结构化统计: 使用宏 ADD_STAT 添加到stats.txt
gem5之前统计太扁平了,所以新的方法支持更结构化的统计, 旨在在构造函数中使用Stats::Group来初始化Stats对象。
老的方法也支持. 个人评价是更复杂更华丽胡哨,初学者可以不用2.2的方法,只用2.1传统的统计方式就完全够用了.
定义
在 gem5/src/base/stats/group.hh 中
#define ADD_STAT(n, …) n(this, #n, VA_ARGS)
ADD_STAT 宏通常在 gem5 源代码的统计系统相关的头文件中定义。这些头文件位于 src/base/stats/ 目录中。
使用例子
2.1 传统统计方式的例子
我们以NI为例子, src/mem/ruby/network/garnet/NetworkInterface.cc这个CPP代码中,会调用一个increment_flit_network_latency函数:
NetworkInterface::incrementStats(flit *t_flit)
{
m_net_ptr->increment_flit_network_latency(network_delay, vnet);
m_net_ptr->increment_flit_queueing_latency(queueing_delay, vnet);
}
increment_flit_queueing_latency函数定义在 src/mem/ruby/network/garnet/GarnetNetwork.hh内,具体细节如下:
void
increment_flit_queueing_latency(Tick latency, int vnet)
{
m_flit_queueing_latency[vnet] += latency;
}
而 m_flit_queueing_latency就是一个很简单很清晰的统计变量: 定义在 src/mem/ruby/network/garnet/GarnetNetwork.hh内
statistics::Vector m_flit_queueing_latency;
它是一个vector,长度其实是3,因为garnet 只有3个vnet. 里面有三个scalar值,每个scalar值对应一个vn网络的这个变量(queueing_latency)的统计. 它的功能就是统计三个vn网络内,各自的网络delay和queueing_delay之和.
统计了怎么打印输出
刚刚的部分,cpp程序会计算 m_flit_queueing_latency的值,但是这个值很显然只在内存里,并不会通过io操作打印成stats.txt里的值.
打印的部分是在 src/mem/ruby/network/garnet/GarnetNetwork.cc的函数void
GarnetNetwork::regStats()里实现的
void
GarnetNetwork::regStats()
{
m_flit_queueing_latency
.init(m_virtual_networks)
.name(name() + ".flit_queueing_latency")
.flags(statistics::oneline)
;
}
这里的name()是自己的 “name()”,作为garnetwork.cc里的name(),他的值是system.ruby.network.
有点需要init有点不需要: 是否调用 init() 取决于统计变量的类型和所需的初始化方式。数组或列表类型的统计变量需要使用 init() 来设定其大小,而单一值类型的统计变量则不需要这样的初始化过程。
验证: m_flit_queueing_latency flit_queueing_latency
我们可以看到,stats.txt里是有下面两个量的截图的.
如果换用不启用ruby的network的结果,则搜不到这些flit的统计量.
这里的值为0,是因为m_demand_accesses也是0,也就是说这个统计里,并没有用网络传包.
2.2的例子
例如已经用的例子。
使用时我们先定义一个结构体
** Statistics */
struct TableWalkerStats : public statistics::Group
{
TableWalkerStats(statistics::Group *parent);
statistics::Scalar walks;
} stats;
然后调用
TableWalker::TableWalkerStats::TableWalkerStats(statistics::Group *parent)
: statistics::Group(parent),
ADD_STAT(walks, statistics::units::Count::get(),
"Table walker walks requested"),
{
}
另一个例子 GpuTLBStats是创建的结构体
GpuTLB::GpuTLBStats::GpuTLBStats(statistics::Group *parent)
: statistics::Group(parent),
ADD_STAT(localNumTLBAccesses, "Number of TLB accesses"),
{
}
其中 statistics来自与include的 statistics.hh
#include “base/statistics.hh”
我的实例
https://blog.csdn.net/weixin_37702021/article/details/124872704提到的,gatech课程里的extract_network_stats.sh
echo > network_stats.txt
grep "packets_injected::total" m5out/stats.txt | sed 's/system.ruby.network.packets_injected::total\s*/packets_injected = /' >> network_stats.txt
grep "packets_received::total" m5out/stats.txt | sed 's/system.ruby.network.packets_received::total\s*/packets_received = /' >> network_stats.txt
grep "average_packet_queueing_latency" m5out/stats.txt | sed 's/system.ruby.network.average_packet_queueing_latency\s*/average_packet_queueing_latency = /' >> network_stats.txt
grep "average_packet_network_latency" m5out/stats.txt | sed 's/system.ruby.network.average_packet_network_latency\s*/average_packet_network_latency = /' >> network_stats.txt
grep "average_packet_latency" m5out/stats.txt | sed 's/system.ruby.network.average_packet_latency\s*/average_packet_latency = /' >> network_stats.txt
grep "flits_injected::total" m5out/stats.txt | sed 's/system.ruby.network.flits_injected::total\s*/flits_injected = /' >> network_stats.txt
grep "flits_received::total" m5out/stats.txt | sed 's/system.ruby.network.flits_received::total\s*/flits_received = /' >> network_stats.txt
grep "average_flit_queueing_latency" m5out/stats.txt | sed 's/system.ruby.network.average_flit_queueing_latency\s*/average_flit_queueing_latency = /' >> network_stats.txt
grep "average_flit_network_latency" m5out/stats.txt | sed 's/system.ruby.network.average_flit_network_latency\s*/average_flit_network_latency = /' >> network_stats.txt
grep "average_flit_latency" m5out/stats.txt | sed 's/system.ruby.network.average_flit_latency\s*/average_flit_latency = /' >> network_stats.txt
grep "average_hops" m5out/stats.txt | sed 's/system.ruby.network.average_hops\s*/average_hops = /' >> network_stats.txt
但是这里很多的变量名在23.0版本已经变了.
我们运行10000cycle,命令行如下
./build/NULL/gem5.debug configs/example/garnet_synth_traffic.py
–num-cpus=16
–num-dirs=16
–network=garnet
–topology=Mesh_XY
–mesh-rows=4
–sim-cycles=10000 --inj-vnet=0
–synthetic=uniform_random
–injectionrate=1
stats.txt结果如下.可以看到发出了318flit 只有76个flit收到了
如果我们发出100万cycles
./build/NULL/gem5.debug configs/example/garnet_synth_traffic.py
–num-cpus=16
–num-dirs=16
–network=garnet
–topology=Mesh_XY
–mesh-rows=4
–sim-cycles=1000000 --inj-vnet=0
–synthetic=uniform_random
–injectionrate=1
inject注入了15972,收到了15897,说明还有100不到的flit没有收到.