Probe system in gem5 (Simpoint example)
本节介绍 gem5 中的 Probe System,也就是监测系统,这个监测系统是用来监测 SimObject 的,也就是说在 SimObject 满足某些条件的情况下,会除法监测系统进行工作。
关键概念和架构图
有关监测系统的基本定义全部定义在了 src/sim/probe/probe.hh 下,这之中有几个最基本的概念,以及针对这些概念衍生出的定义。
监测系统的基本概念如下:
- ProbePoint:即探测点,探测点依附在探测的对象中。探测对象在某些条件满足的时候会通知探测点,进而探测点通知监听器进行函数回调
ProbePoint:给出了最基本的探测点的定义。将addListener和removeListener作为纯虚函数供子类去做实现。ProbePointArg:给出了最基本的探测点的实现。传入的模板参数Arg,同样被用作后续监听器的模板参数。
- ProbeListener:即监听器,监听器主要用来监听探测点,在某些探测点被触发的时候,监听器中的回调函数被调用。监听器和探测点之间是多对多的关系,一个监听器能够用到多个探测点上,一个探测点也能够触发多个监听器。它们之间的关系是靠探测点的
name变量来维护的,在添加监听的时候要指定探测点的name才能建立监听。ProbeListener:给出了最基本的监听器的实现。ProbeListenerArgBase:拓展了ProbeListener,接收模板参数Arg,是后续回调函数接受的参数类型。ProbeListenerArg:进一步拓展了ProbeListenerArgBase,对回调函数进行了通用的实现。ProbeListenerArgFunc:和ProbeListenerArg原理类似,只是可以通过 lambda 的方式轻松创建监听器。ProbeListenerObject:可以简单的理解成他维护了一堆ProbeListener,同时它本身也是一个 Simobject。
- ProbeManager:即管理器,实际上用来维护多个探测点和监听器,方便探测点和监听器之间建立联系,同时解耦探测点和监听器。
ProbeManager:管理器实现。
通过以上的基本概念,可以得到监测系统的架构图:

以 SimPoint 为例
已经了解了整体架构之后,这整个过程是怎么建立的又是一个关键的问题。以下以 SimPoint 为例讲述建立的过程,SimPoint 是一个加快仿真速度的工具,其就是通过监测系统进行 cpu 相关的检测,获取相关的信息,最后导出 SimPoint 需要的 BB 格式的信息。
在 gem5 中 SimPoint 只支持 AtomicSimpleCPU,在 python 脚本中,为了在一次执行的过程中导出 BB 格式分析文件,AtomicSimpleCPU 需要调用其方法 addSimPointProbe(src/cpu/simple/BaseAtomicSimpleCPU.py):
def addSimPointProbe(self, interval):
simpoint = SimPoint()
simpoint.interval = interval
self.probeListener = simpoint这个方法很简单,重点关注其中的 simpoint = SimPoint(),进入到 SimPoint(src/cpu/simple/probes/SimPoint.py) 的定义中,我们能够发现:
class SimPoint(ProbeListenerObject):
"""Probe for collecting SimPoint Basic Block Vectors (BBVs)."""
type = "SimPoint"
cxx_header = "cpu/simple/probes/simpoint.hh"
cxx_class = "gem5::SimPoint"
interval = Param.UInt64(100000000, "Interval Size (insts)")
profile_file = Param.String("simpoint.bb.gz", "BBV (output) file")这个类定义平平无奇,重点在于其继承自 ProbeListenerObject,查看其源码 src/sim/probe/Probe.py:
class ProbeListenerObject(SimObject):
type = "ProbeListenerObject"
cxx_header = "sim/probe/probe.hh"
cxx_class = "gem5::ProbeListenerObject"
manager = Param.SimObject(Parent.any, "ProbeManager")可以看到 manager 指向了当前对象的父对象,也就是说,只要调用了 addSimPointProbe 方法,SimPoint 作为一个 ProbeListenerObject 会在后续与 manager 建立联系。
instantiate阶段
在 instantiate(src/python/m5/simulate.py)方法中,Simobject对象创建和监测系统创建顺序如下:
# Create the C++ sim objects and connect ports
for obj in root.descendants():
obj.createCCObject()
for obj in root.descendants():
obj.connectPorts()
# Do a second pass to finish initializing the sim objects
# ...
# Do a third pass to initialize statistics
# ...
# Do a fourth pass to initialize probe points
for obj in root.descendants():
obj.regProbePoints()
# Do a fifth pass to connect probe listeners
for obj in root.descendants():
obj.regProbeListeners()可以看到顺序先进行 SimObject 的 cpp 对象的创建,然后再进行监测系统相关的对象的创建。在 SimObject 的源代码(src/sim/sim_object.cc)中我们可以看到:
SimObject::SimObject(const Params &p)
: EventManager(getEventQueue(p.eventq_index)),
statistics::Group(nullptr), Named(p.name),
_params(p)
{
simObjectList.push_back(this);
probeManager = new ProbeManager(this);
}可以看到每个 SimObject 的内部都隐含了一个 ProbeManager,从抽象意义上说,每个 SimObject 我们认为其都具有管理监控点和监听器的能力。
重新回到 AtomicSimpleCPU 和 SimPoint,这之中 AtomicSimpleCPU 应该担任监控点的角色,在合适的时机通知监听器 SimPoint 进行相关的回调操作。可以大胆的猜测 AtomicSimpleCPU 在 regProbePoints 要有所作为,而 SimPoint 要在 regProbeListeners 中有所作为。
不出所料:
在 AtomicSimpleCPU(src/cpu/simple/atomic.cc) 中
void
AtomicSimpleCPU::regProbePoints()
{
BaseCPU::regProbePoints();
ppCommit = new ProbePointArg<std::pair<SimpleThread*, const StaticInstPtr>>
(getProbeManager(), "Commit");
}在 SimPoint(src/cpu/simple/probes/simpoint.cc) 中
void
SimPoint::regProbeListeners()
{
typedef ProbeListenerArg<SimPoint, std::pair<SimpleThread*,StaticInstPtr>>
SimPointListener;
listeners.push_back(new SimPointListener(this, "Commit",
&SimPoint::profile));
}两者很巧妙的建立了联系。更多有关 gem5 中的 SimPoint 支持可以查看这篇文章。
以上就是监测系统建立的过程。