7
|
1 \subsection{Task}
|
|
2 Task の定義は以下のようになる。
|
|
3
|
|
4 {\small
|
|
5 \begin{verbatim}
|
|
6
|
|
7 class Task {
|
|
8 public:
|
|
9 int command; // 実行するタスクID
|
|
10 int size; // in_addr で取得するデータのバイト数
|
|
11 unsigned int in_addr; // 入力データ元アドレス
|
|
12 unsigned int out_addr; // 出力データ先アドレス
|
|
13
|
|
14 TaskQueue *wait_me;
|
|
15 TaskQueue *wait_i;
|
|
16
|
|
17 CPU_TYPE cpu_type; // PPE or SPE
|
|
18
|
|
19 void spawn(void);
|
|
20 void set_depend(Task*);
|
|
21 void set_cpu(Task*);
|
|
22 };
|
|
23
|
|
24 \end{verbatim}
|
|
25 }
|
|
26
|
|
27 command, size, in\_addr, out\_addr は
|
|
28 create\_task() で引数で登録する。
|
|
29
|
|
30 \subsection{Dependency} \label{sec:task}
|
|
31 「Task1 は Task2, Task3 が終わるまで実行されてはいけない」といった、
|
|
32 Task 同士での依存関係を指定するには、API の set\_depend() を使う。
|
|
33
|
|
34 {\small
|
|
35 \begin{verbatim}
|
|
36
|
|
37 // task2 は task1 が終了してから開始する
|
|
38 task2->set_depend(task1);
|
|
39
|
|
40 \end{verbatim}
|
|
41 }
|
|
42
|
|
43 set\_depend の実装を以下に示す。
|
|
44
|
|
45 {\small
|
|
46 \begin{verbatim}
|
|
47
|
|
48 void
|
|
49 Task::set_depend(Task* master)
|
|
50 {
|
|
51 Task *slave = this;
|
|
52
|
|
53 master->wait_me
|
|
54 = append_queue(master_wait_me, slave)
|
|
55 slave->wait_i
|
|
56 = append_queue(slave_wait_i, master);
|
|
57 }
|
|
58
|
|
59 \end{verbatim}
|
|
60 }
|
|
61
|
|
62 各 Task が持つ wait\_me は、「自分を待っている Task」のキューで、
|
|
63 wait\_i は、「自分が待っている Task 」のキューとなる。
|
|
64
|
|
65 Task が spawn された時、wait\_i が空であれば 実行 Queue へ、
|
|
66 あれば WaitQueue へ追加される。
|
|
67
|
|
68 Task が終わる毎に、SPE から Task が終了したことを PPE に知らせる。
|
|
69 PPE は、Task が終了したことを、WaitQueue にある Task に知らせる。
|
|
70 WaitQueue の Task は、終了した Task が、自分が待っている Task であれば
|
|
71 自分の wait\_i からその Task を削除していく。
|
|
72 自分の wait\_i が空になれば、Task 依存を満たしたので ActiveQueue に追加される。
|
|
73 以上の記述を以下に示す。
|
|
74
|
|
75 {\small
|
|
76 \begin{verbatim}
|
|
77
|
|
78 /**
|
|
79 * master : 終了した Task
|
|
80 * list : master->wait_me
|
|
81 */
|
|
82 void
|
|
83 notify_waitQueue(Task *master,TaskQueue *list)
|
|
84 {
|
|
85 Task* slave;
|
|
86
|
|
87 while (list) {
|
|
88 slave = list->task;
|
|
89 slave->wait_i
|
|
90 = remove_taskQueue(slave->wait_i, master);
|
|
91 if (slave->wait_i == NULL) {
|
|
92 append_activeTask(slave);
|
|
93 }
|
|
94 list = list->next;
|
|
95 }
|
|
96 }
|
|
97
|
|
98 \end{verbatim}
|
|
99 }
|
|
100
|
|
101 \subsection{Mail}
|
|
102 \ref{sec:task} で述べたように、SPE から Task の終了を
|
|
103 PPE に伝える必要があるが、その際の待ち合わせは避けるべきである。
|
|
104
|
|
105 Cell では、PPE と SPE 間のメッセージのやりとりには
|
|
106 Mail box という FIFO メッセージキューを用いる。
|
|
107 メッセージ交換なので待ち合わせを避けることが可能である。
|
|
108
|
|
109 SPE $\rightarrow$ PPE だけでなく、PPE Kernel 内部でも
|
|
110 Mailbox と同じ方式でメッセージ交換をしている。
|
|
111 Task は SPE だけでなく、PPE でも実行されているためである。
|
|
112
|
|
113 メールチェックをする関数 mail\_check() を以下に示す。
|
|
114 この関数は、現在 PPE 側の ActiveQueue にある Task が
|
|
115 全て終わった後、次の ActiveQueue を取得する前に呼ばれる。
|
|
116
|
|
117 {\small
|
|
118 \begin{verbatim}
|
|
119
|
|
120 MailQueuePtr
|
|
121 SpeTaskManager::mail_check(MailQueue *mail_list)
|
|
122 {
|
|
123 MailQueue *list;
|
|
124 unsigned int data;
|
|
125
|
|
126 // mail_list には、
|
|
127 // 「PPE側」で終了した Task に関するメールがある
|
|
128 // list には、次の Task に関するメールがある
|
|
129 list = ppeTaskManager->mail_check(mail_list);
|
|
130
|
|
131 do {
|
|
132 for (id = 0; id < SPE_NUM; id++) {
|
|
133 while (1) {
|
|
134 // data には、
|
|
135 // 「SPE側」で終了した Task がある。
|
|
136 // data がマイナスの場合、Mail box は空
|
|
137 data = speThreads->get_mail(id);
|
|
138 if (data < 0) break;
|
|
139 check_task_finish(data);
|
|
140 }
|
|
141 }
|
|
142 } while (list == NULL && waitTaskQueue
|
|
143 && !activeTaskQueue);
|
|
144
|
|
145 return list;
|
|
146 }
|
|
147
|
|
148 \end{verbatim}
|
|
149 }
|
|
150
|
|
151 PPE が SPE からメールを受け取る場合、
|
|
152 spe\_out\_mbox\_read() という、SPE Runtime Management Library \cite{libspe2} を
|
|
153 用いる。しかし、spe\_out\_mbox\_read() は Non-blocking function のため、
|
|
154 busy-wait なメールの待ち方は避けるべきである。
|
|
155 今回は、PPE 側でメールチェックを行う際に、SPE からのメールをチェックする。
|
|
156
|
|
157 PPE と SPE のメールチェックを分離させたい場合、
|
|
158 メールをチェックする Blocking Function を作る必要がある。
|
|
159
|
|
160 もしくは SPE Event Handling を用いる手法もある。
|
|
161 これは、メールが来たら event を起こすことを Event Handler に登録する。
|
|
162 この場合、通常の Mailbox ではない、割り込み用の interrupting Mailbox を
|
|
163 使用しなくてはならない。
|
|
164 interrupting Mailbox を使用する spe\_out\_intr\_mbox\_read() は、
|
|
165 Event が起きたときに呼ばれるため Blocking Function である。
|
|
166 SPE のどれかからメッセージが来たらポーリングによってメールチェックを行う。
|
|
167
|
|
168 今回は、PPE と SPE のメールチェックは分離しない実装をした。
|