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 のメールチェックは分離しない実装をした。