Mercurial > hg > Papers > 2008 > gongo-sigos
view manager-task.tex @ 7:bd8574dedd1b
*** empty log message ***
author | gongo |
---|---|
date | Tue, 25 Mar 2008 15:51:53 +0900 |
parents | |
children | b70a62630a57 |
line wrap: on
line source
\subsection{Task} Task の定義は以下のようになる。 {\small \begin{verbatim} class Task { public: int command; // 実行するタスクID int size; // in_addr で取得するデータのバイト数 unsigned int in_addr; // 入力データ元アドレス unsigned int out_addr; // 出力データ先アドレス TaskQueue *wait_me; TaskQueue *wait_i; CPU_TYPE cpu_type; // PPE or SPE void spawn(void); void set_depend(Task*); void set_cpu(Task*); }; \end{verbatim} } command, size, in\_addr, out\_addr は create\_task() で引数で登録する。 \subsection{Dependency} \label{sec:task} 「Task1 は Task2, Task3 が終わるまで実行されてはいけない」といった、 Task 同士での依存関係を指定するには、API の set\_depend() を使う。 {\small \begin{verbatim} // task2 は task1 が終了してから開始する task2->set_depend(task1); \end{verbatim} } set\_depend の実装を以下に示す。 {\small \begin{verbatim} void Task::set_depend(Task* master) { Task *slave = this; master->wait_me = append_queue(master_wait_me, slave) slave->wait_i = append_queue(slave_wait_i, master); } \end{verbatim} } 各 Task が持つ wait\_me は、「自分を待っている Task」のキューで、 wait\_i は、「自分が待っている Task 」のキューとなる。 Task が spawn された時、wait\_i が空であれば 実行 Queue へ、 あれば WaitQueue へ追加される。 Task が終わる毎に、SPE から Task が終了したことを PPE に知らせる。 PPE は、Task が終了したことを、WaitQueue にある Task に知らせる。 WaitQueue の Task は、終了した Task が、自分が待っている Task であれば 自分の wait\_i からその Task を削除していく。 自分の wait\_i が空になれば、Task 依存を満たしたので ActiveQueue に追加される。 以上の記述を以下に示す。 {\small \begin{verbatim} /** * master : 終了した Task * list : master->wait_me */ void notify_waitQueue(Task *master,TaskQueue *list) { Task* slave; while (list) { slave = list->task; slave->wait_i = remove_taskQueue(slave->wait_i, master); if (slave->wait_i == NULL) { append_activeTask(slave); } list = list->next; } } \end{verbatim} } \subsection{Mail} \ref{sec:task} で述べたように、SPE から Task の終了を PPE に伝える必要があるが、その際の待ち合わせは避けるべきである。 Cell では、PPE と SPE 間のメッセージのやりとりには Mail box という FIFO メッセージキューを用いる。 メッセージ交換なので待ち合わせを避けることが可能である。 SPE $\rightarrow$ PPE だけでなく、PPE Kernel 内部でも Mailbox と同じ方式でメッセージ交換をしている。 Task は SPE だけでなく、PPE でも実行されているためである。 メールチェックをする関数 mail\_check() を以下に示す。 この関数は、現在 PPE 側の ActiveQueue にある Task が 全て終わった後、次の ActiveQueue を取得する前に呼ばれる。 {\small \begin{verbatim} MailQueuePtr SpeTaskManager::mail_check(MailQueue *mail_list) { MailQueue *list; unsigned int data; // mail_list には、 // 「PPE側」で終了した Task に関するメールがある // list には、次の Task に関するメールがある list = ppeTaskManager->mail_check(mail_list); do { for (id = 0; id < SPE_NUM; id++) { while (1) { // data には、 // 「SPE側」で終了した Task がある。 // data がマイナスの場合、Mail box は空 data = speThreads->get_mail(id); if (data < 0) break; check_task_finish(data); } } } while (list == NULL && waitTaskQueue && !activeTaskQueue); return list; } \end{verbatim} } PPE が SPE からメールを受け取る場合、 spe\_out\_mbox\_read() という、SPE Runtime Management Library \cite{libspe2} を 用いる。しかし、spe\_out\_mbox\_read() は Non-blocking function のため、 busy-wait なメールの待ち方は避けるべきである。 今回は、PPE 側でメールチェックを行う際に、SPE からのメールをチェックする。 PPE と SPE のメールチェックを分離させたい場合、 メールをチェックする Blocking Function を作る必要がある。 もしくは SPE Event Handling を用いる手法もある。 これは、メールが来たら event を起こすことを Event Handler に登録する。 この場合、通常の Mailbox ではない、割り込み用の interrupting Mailbox を 使用しなくてはならない。 interrupting Mailbox を使用する spe\_out\_intr\_mbox\_read() は、 Event が起きたときに呼ばれるため Blocking Function である。 SPE のどれかからメッセージが来たらポーリングによってメールチェックを行う。 今回は、PPE と SPE のメールチェックは分離しない実装をした。