gem5を構成するSimObjectを追加するためのチュートリアルをやってみる。
- gem5記事一覧インデックス
gem5はイベントドリブンのシミュレータである。本章では、イベントの作成とスケジューリングの方法を探る。hello-simobject-chapter
のシンプルなHelloObjectを元に作っていく。
単純なイベントコールバックの作成
gem5のイベントドリブンモデルでは、各イベントにイベントが処理されるコールバック関数がある。一般的に、これは :cppEvent を継承したクラスである。しかし、gem5には単純なイベントを作成するためのラッパー関数が用意されている。
HelloObject
のヘッダーファイルで、イベントが発生するたびに実行する新しい関数(processEvent()
)を宣言する必要がある。この関数はパラメーターを取らず、何も返さない。
次に、Event
インスタンスを追加する。今回は、任意の関数を実行できるEventFunctionWrapper
を使用する。
また、以下で説明するstartup()
関数も追加する。
class HelloObject : public SimObject { private: void processEvent(); EventFunctionWrapper event; public: HelloObject(HelloObjectParams *p); void startup(); };
次に、HelloObject
のコンストラクタでこのイベントを構築しなければならない。EventFuntionWrapper
は、実行する関数と名前の2つのパラメータを取る。名前は通常、イベントを所有するSimObject
の名前である。名前を表示する際には、自動的に".wrapped_function_event "が名前の最後に付加される。
最初のパラメータは、パラメータを取らず戻り値を持たない関数(std::function<void(void)>
)である。通常、これはメンバ関数を呼び出す単純なラムダ関数である。しかし、どんな関数でも構わない。以下では、this
をラムダ([this]
)に取り込んで、クラスのインスタンスのメンバ関数を呼び出せるようにしている。
HelloObject::HelloObject(HelloObjectParams *params) : SimObject(params), event([this]{processEvent();}, name()) { DPRINTF(HelloExample, "Created the hello object\n"); }
プロセス関数の実装も定義しなければならない。この場合、デバッグをするのであれば、単純に何かを表示することになる。
void HelloObject::processEvent() { DPRINTF(HelloExample, "Hello world! Processing the event!\n"); }
イベントのスケジューリング
最後に、イベントを処理するために、まずイベントをスケジュールする必要がある。そのために :cppschedule 関数を使用する。イベント・ドリブン・シミュレーションでは、イベントを過去に実行することはできない)。
最初は、HelloObjectクラスに追加したstartup()
関数でイベントをスケジュールする。startup()
関数は、SimObjectが内部イベントをスケジュールするための関数である。この関数は、シミュレーションが初めて開始されるまで実行されない(すなわち、Python設定ファイルからsimulate()
関数が呼び出される)。
void HelloObject::startup() { schedule(event, 100); }
ここでは、単純に100tickでイベントが実行されるようにスケジュールする。通常はcurTick()
からのオフセットを使用するが、startup()
関数は現在時刻が0のときに呼び出されることがわかっているので、明示的なtick値を使用することができる。
“HelloExample
"デバッグフラグを付けてgem5を実行したときの出力は以下のようになる。
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=HelloExample 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
より多くのイベントスケジューリング
イベント・プロセス・アクションの中で新しいイベントをスケジュールすることもできる。例えば、HelloObject
にレイテンシ・パラメーターを追加し、イベントを何回発生させるかのパラメーターを追加する。次の章では、これらのパラメータをPythonの設定ファイルからアクセスできるようにする。
HelloObject
クラスの宣言に、レイテンシとイベント発生回数のメンバ変数を追加する。
class HelloObject : public SimObject { private: void processEvent(); EventFunctionWrapper event; const Tick latency; int timesLeft; public: HelloObject(const HelloObjectParams &p); void startup(); };
次に、コンストラクタでlatency
とtimesLeft
の値を設定する。
HelloObject::HelloObject(HelloObjectParams *params) : 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=HelloExample 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