GEM5 是事件驱动的仿真器。本节将研究如何创建和调度事件,我们从hello-simobject-chapter简单的HelloObject进行构建(building)。
创建简单的事件回调
在gem5的事件驱动模型中,每个事件都有一个回调函数用于处理事件。
这个函数一般是从:cppEvent继承而来的一个类,但是,gem5提供了一个封装函数,用于创建简单的事件。
在HelloObject的头文件中,我们只需要声明需要在每次事件触发时(processEvent)执行的一个新函数,同时这个函数必须不带任何参数并做空返回。
然后,添加一个事件(Event)的实例。在本例中,我们使用一个事件函数封装(EventFunctionWrapper),因为它可以用于执行任意函数,我们还添加了一个Startup功能,这个功能我们将在后面解释。
class HelloObject : public SimObject
{
private:
void processEvent();
EventFunctionWrapper event;
public:
HelloObject(const HelloObjectParams &p);
void startup() override;
};
接下来,必须在HelloObject的构造函数中构造这个事件。EventFuntionWrapper需要两个参数:一个函数用于执行外加一个名字。这个名字通常是拥有这个事件的SimObject的名字,当这个名字打印时,字符串 “.wrapped_function_event”会自动附加到名称的尾部。
第一个参数只是一个不带参数且没有返回值的函数(std::function<void(void)>),通常是调用成员函数的简单Lambda函数,它实现用户想要的任何功能。下面,这段代码主要是通过调用SimObject的构造函数实现了HelloObject 的构造函数,同时使用lambda ([this])捕获了this指针,使得用户可以调用类的实例的成员函数。
HelloObject::HelloObject(const HelloObjectParams ¶ms) :
SimObject(params), event([this]{processEvent();}, name())
{
DPRINTF(HelloExample, "Created the hello object\n");
}
此外,用户还需要定义进程(process)函数的实现。本例中,我们只需要在调试时简单地打印一些内容。
void
HelloObject::processEvent()
{
DPRINTF(HelloExample, "Hello world! Processing the event!\n");
}
调度事件
最后,要处理的事件,必须先进行调度。gem5使用cppschedule函数将某个实例调度到未来的某个时间执行(事件驱动的仿真禁止将事件调度到过去执行)。
我们往HelloObject类中添加的startup()函数首先进行调度,startup()函数能够调度SimObject的内部事件。它只在仿真首次启动时执行(即从Python配置文件调用simulate()函数)。
void
HelloObject::startup()
{
schedule(event, 100);
}
本例中,我们只简单地将事件调度到tick=100时执行。通常用户可以使用当前tick的相对偏移量进行调度,这里因为我们知道startup()函数在当前时间为0时被调用,我们可以使用显式的tick值。
这里运行“HelloExample”时,输出调试标志是当前时刻。
gem5 Simulator System. http://gem5.org
gem5 is copyrighted software; use the --copyright option for details.
gem5 compiled Jan 4 2017 11:01:46
gem5 started Jan 4 2017 13:41:38
gem5 executing on chinook, pid 1834
command line: build/X86/gem5.opt --debug-flags=Hello configs/learning_gem5/part2/run_hello.py
Global frequency set at 1000000000000 ticks per second
0: hello: Created the hello object
Beginning simulation!
info: Entering event queue @ 0. Starting simulation...
100: hello: Hello world! Processing the event!
Exiting @ tick 18446744073709551615 because simulate() limit reached
更多事件调度
用户还可以在事件处理进程(process)的行为中调度新的事件。例如,我们将向HelloObject添加一个延迟参数以及一个记录事件(event)触发次数的参数,下一节中,我们还将使用Python配置文件获取这些参数。
这里,在HelloObject类声明中为延迟latency和触发次数timesLeft分别增加成员变量。
class HelloObject : public SimObject
{
private:
void processEvent();
EventFunctionWrapper event;
const Tick latency;
int timesLeft;
public:
HelloObject(const HelloObjectParams &p);
void startup() override;
};
然后,在构造函数中添加latency和timesLeft的默认值。
HelloObject::HelloObject(const HelloObjectParams ¶ms) :
SimObject(params), event([this]{processEvent();}, name()),
latency(100), timesLeft(10)
{
DPRINTF(HelloExample, "Created the hello object\n");
}
最后,更新startup()函数和processEvent()函数
void
HelloObject::startup()
{
schedule(event, latency);
}
void
HelloObject::processEvent()
{
timesLeft--;
DPRINTF(HelloExample, "Hello world! Processing the event! %d left\n", timesLeft);
if (timesLeft <= 0) {
DPRINTF(HelloExample, "Done firing!\n");
} else {
schedule(event, curTick() + latency);
}
}
这时候运行gem5,事件应该被触发 10 次,同时仿真在1000个tick后结束,具体输出如下所示:
gem5 Simulator System. http://gem5.org
gem5 is copyrighted software; use the --copyright option for details.
gem5 compiled Jan 4 2017 13:53:35
gem5 started Jan 4 2017 13:54:11
gem5 executing on chinook, pid 2326
command line: build/X86/gem5.opt --debug-flags=Hello configs/learning_gem5/part2/run_hello.py
Global frequency set at 1000000000000 ticks per second
0: hello: Created the hello object
Beginning simulation!
info: Entering event queue @ 0. Starting simulation...
100: hello: Hello world! Processing the event! 9 left
200: hello: Hello world! Processing the event! 8 left
300: hello: Hello world! Processing the event! 7 left
400: hello: Hello world! Processing the event! 6 left
500: hello: Hello world! Processing the event! 5 left
600: hello: Hello world! Processing the event! 4 left
700: hello: Hello world! Processing the event! 3 left
800: hello: Hello world! Processing the event! 2 left
900: hello: Hello world! Processing the event! 1 left
1000: hello: Hello world! Processing the event! 0 left
1000: hello: Done firing!
Exiting @ tick 18446744073709551615 because simulate() limit reached