57
|
1 #include <stdio.h>
|
|
2 #include <stdlib.h>
|
|
3 #include <string.h>
|
|
4 #include "CellTaskManagerImpl.h"
|
61
|
5 #include "CellBufferManager.h"
|
109
|
6 #include "PpeScheduler.h"
|
57
|
7 #include "types.h"
|
65
|
8 #include "error.h"
|
57
|
9
|
109
|
10 CellTaskManagerImpl::~CellTaskManagerImpl(void)
|
67
|
11 {
|
109
|
12 delete speThreads;
|
|
13 delete [] speTaskList;
|
|
14 delete [] speTaskList_bg;
|
|
15 /**
|
|
16 * bufferManager は
|
|
17 * ppeManager のなかで delete してもらう
|
|
18 */
|
|
19 // delete bufferManager;
|
|
20 delete [] flag_sendTaskList;
|
|
21
|
|
22 delete ppeManager;
|
67
|
23 }
|
|
24
|
57
|
25 void
|
|
26 CellTaskManagerImpl::init(void)
|
|
27 {
|
109
|
28 bufferManager = new CellBufferManager(machineNum);
|
57
|
29 bufferManager->init();
|
65
|
30
|
|
31 speThreads = new SpeThreads(machineNum);
|
|
32 speThreads->init();
|
109
|
33
|
|
34 speTaskList = new TaskListPtr[machineNum];
|
|
35 speTaskList_bg = new TaskListPtr[machineNum];
|
|
36 for (int i = 0; i < machineNum; i++) {
|
|
37 speTaskList[i] = bufferManager->create_taskList();
|
|
38 speTaskList_bg[i] = bufferManager->create_taskList();
|
|
39 }
|
|
40
|
|
41 flag_sendTaskList = new int[machineNum];
|
|
42 for (int i = 0; i < machineNum; i++) {
|
|
43 flag_sendTaskList[i] = 1;
|
|
44 }
|
|
45
|
|
46 // PPE 側の管理をする Manager
|
|
47 ppeManager = new FifoTaskManagerImpl(machineNum);
|
|
48 ppeManager->init(new PpeScheduler, bufferManager);
|
57
|
49 }
|
|
50
|
109
|
51 void
|
|
52 CellTaskManagerImpl::append_activeTask(HTaskPtr task)
|
|
53 {
|
|
54 TaskQueuePtr q;
|
|
55
|
|
56 q = bufferManager->create_taskQueue(task);
|
|
57 if (task->cpu_type == CPU_PPE) {
|
|
58 ppeManager->append_activeTask(task);
|
|
59 } else {
|
|
60 activeTaskQueue = TaskQueue::append(activeTaskQueue, q);
|
|
61 }
|
|
62 }
|
|
63
|
|
64 // SPE_ANY が指定されていた時に
|
|
65 // これをインクリメントしつつ呼ぶことにする。
|
|
66 // 乱数使ってもいいけどさ。
|
|
67 int cur_anySpeid = 0;
|
|
68
|
|
69 /**
|
|
70 * ActiveTaskQueue から Task を
|
|
71 * 各 SPE に渡す TaskList に入れる
|
|
72 *
|
|
73 * ここの activeTaskQueue は FifoTaskManagerImpl のと意味が違い、
|
|
74 * spe に渡される Task だけ入っている
|
|
75 */
|
|
76 void
|
|
77 CellTaskManagerImpl::set_runTaskList(void)
|
70
|
78 {
|
|
79 // ここ...直すかな
|
|
80 TaskListPtr list;
|
|
81 TaskQueuePtr queue;
|
|
82 TaskQueuePtr d;
|
|
83 HTaskPtr htask;
|
|
84 TaskPtr task;
|
109
|
85 int speid;
|
70
|
86
|
109
|
87 queue = activeTaskQueue;
|
70
|
88 if (queue == NULL) {
|
109
|
89 return ;
|
70
|
90 }
|
|
91
|
|
92 while (queue) {
|
109
|
93 htask = (HTaskPtr)queue->task;
|
70
|
94 d = queue;
|
|
95 queue = queue->next;
|
|
96
|
109
|
97 if (htask->cpu_type == SPE_ANY) {
|
|
98 speid = cur_anySpeid++;
|
|
99 cur_anySpeid = (cur_anySpeid < machineNum)
|
|
100 ? cur_anySpeid : 0;
|
70
|
101 } else {
|
109
|
102 // -1 してるのは
|
|
103 // htask->cpu_type - CPU_SPE で
|
|
104 // SPE0 = 1, SPE1 = 2, ... SPE5 = 6 ってなってるので
|
|
105 // 配列的 (SPE0 = arr[0], SPE1 = arr[1]) にするため
|
|
106 speid = htask->cpu_type - CPU_SPE - 1;
|
|
107
|
|
108 // SPU の数以上が指定されていれば
|
|
109 // とりあえず MAX_USE_SPE_NUM (実際に動く SPE の最大数) で
|
|
110 // あまり求めてそれを使うことにする。
|
|
111 // ここで判定するもんでもないか?
|
|
112 if (speid >= machineNum) {
|
|
113 speid %= machineNum;
|
|
114 }
|
70
|
115 }
|
109
|
116
|
|
117 list = speTaskList_bg[speid];
|
|
118
|
|
119 if (list->length >= TASK_MAX_SIZE) {
|
|
120 TaskListPtr newList = bufferManager->create_taskList();
|
|
121 newList = TaskListInfo::append(newList, speTaskList_bg[speid]);
|
|
122 speTaskList_bg[speid] = newList;
|
|
123 list = newList;
|
|
124 }
|
|
125
|
|
126 task = &list->tasks[list->length++];
|
|
127 #if 0
|
|
128 task->command = htask->command;
|
|
129 task->inData = htask->inData;
|
|
130 task->outData = htask->outData;
|
|
131 task->self = (unsigned int)htask;
|
79
|
132 #else
|
109
|
133 memcpy(task, htask, sizeof(Task));
|
79
|
134 #endif
|
70
|
135
|
|
136 bufferManager->free_taskQueue(d);
|
|
137 }
|
|
138
|
109
|
139 activeTaskQueue = NULL;
|
|
140 }
|
|
141
|
|
142 void
|
|
143 CellTaskManagerImpl::run(void)
|
|
144 {
|
|
145 TaskListPtr ppeTaskList = NULL;
|
|
146 MailQueuePtr ppeMail = NULL;
|
70
|
147
|
109
|
148 // PPE 側で動く TaskList です
|
|
149 // FifoTaskManagerImpl::run と上手く合うように
|
|
150 // こんなことやってますよ
|
|
151 ppeTaskList = ppeManager->get_runTaskList();
|
|
152 if (!ppeTaskList) {
|
|
153 goto cont;
|
|
154 }
|
70
|
155
|
109
|
156 // SPE からの Mailbox Check は
|
|
157 // PPE 側の schedule から抜けて来たときに行う
|
|
158 // (speThreads で Blocking Mailbox read と
|
|
159 // セマフォとか使ってやってもいいが、今はこの方式で)
|
|
160 do {
|
|
161 ppeMail = ppeManager->schedule(ppeTaskList);
|
|
162 cont:
|
|
163 ppeTaskList = mail_check(ppeMail);
|
|
164 } while (ppeTaskList);
|
70
|
165 }
|
|
166
|
65
|
167 /**
|
109
|
168 * SPE からのメールをチェックする
|
|
169 *
|
|
170 * @param [mail_list]
|
|
171 * PPE 側で動く Scheduler からのメールリスト
|
|
172 * この中で PPE 側の mail check も行う
|
|
173 *
|
|
174 * @return PPE Scheduler に対してのメール。
|
|
175 * 次に実行する TaskList のアドレスや、終了コマンドを送る
|
|
176 */TaskListPtr
|
65
|
177 CellTaskManagerImpl::mail_check(MailQueuePtr mail_list)
|
57
|
178 {
|
109
|
179 // PPE Scheduler からの mail check
|
|
180 ppeManager->mail_check(mail_list, &waitTaskQueue);
|
65
|
181
|
70
|
182 do {
|
244
|
183 unsigned int data;
|
109
|
184
|
|
185 // SPE Scheduler からの mail check
|
244
|
186 for (int id = 0; id < machineNum; id++) {
|
|
187 while (speThreads->check_mail(id, 1, &data)) {
|
70
|
188
|
109
|
189 /**
|
|
190 * MY_SPE_STATUS_READY: SPE が持ってた Task 全て終了
|
|
191 * MY_SPE_NOP: 特に意味のないコマンド
|
|
192 * それ以外:終了したタスク(PPEにあるのでアドレス
|
|
193 *
|
|
194 * MY_SPE_NOP が 0 なので、
|
|
195 * 下のように data > MY_SPE_NOP とかしています。
|
|
196 * 一目でよくわからない書き方なんで、直したいところですが。。。
|
|
197 */
|
70
|
198 // 名前あとでちゃんと決めよう => MY_SPE_... とかじゃなくて
|
|
199 if (data == MY_SPE_STATUS_READY) {
|
|
200 __debug_ppe("[SPE %d] finish\n", id);
|
109
|
201 flag_sendTaskList[id] = 1;
|
|
202 } else if (data == MY_SPE_COMMAND_MALLOC) {
|
|
203 __debug_ppe("[PPE] MALLOC COMMAND from [SPE %d]\n", id);
|
|
204
|
|
205 /**
|
|
206 * info[0] = alloc_id; (CellScheduler::mainMem_alloc 参照)
|
|
207 * info[1] = alloc_addr;
|
|
208 */
|
244
|
209 unsigned int alloc_info[3];
|
109
|
210 int alloc_size;
|
244
|
211 int command;
|
109
|
212
|
244
|
213 speThreads->get_mail(id, 2, alloc_info);
|
|
214 command = alloc_info[0];
|
|
215 allock_size = alloc_info[1];
|
|
216
|
109
|
217
|
|
218 alloc_info[1] = (unsigned int)allocate(alloc_size);
|
244
|
219 /*
|
|
220 * allocate された領域は今の SPE buffer にリンクとして接続する
|
|
221 * ここでは TaskList を allocate(new) して登録してやろうか
|
|
222 */
|
109
|
223
|
244
|
224 speThreads->add_output_tasklist(command, alloc_info[1], alloc_size);
|
|
225
|
|
226 speThreads->send_mail(id, 2, alloc_info);
|
109
|
227 } else if (data > MY_SPE_NOP) {
|
70
|
228 __debug_ppe("[PPE] recv from [SPE %d] : 0x%x\n", id, data);
|
109
|
229 check_task_finish((HTaskPtr)data);
|
70
|
230 }
|
65
|
231 }
|
|
232 }
|
109
|
233
|
|
234 // 依存関係を満たしたタスクをアクティブに
|
|
235 wakeup_waitTask();
|
|
236
|
|
237 // SPE に送る TaskList の準備
|
|
238 set_runTaskList();
|
|
239
|
|
240 // TaskList 待ちの SPE に TaskList を送る
|
|
241 for (int i = 0; i < machineNum; i++) {
|
|
242 if (flag_sendTaskList[i] == 1 && speTaskList_bg[i]->length >= 1 ) {
|
|
243 send_taskList(i);
|
|
244 }
|
|
245 }
|
70
|
246
|
109
|
247 // 現在の FifoTaskManager の仕様では
|
|
248 // ・PPE で実行するタスクが無くなれば終了する
|
|
249 // であり、この場合もし SPE にタスクが残っていても
|
|
250 // メインループから抜けてプログラム終了となってしまうので
|
|
251 // ここでストップかけてます。
|
|
252 } while (!ppeManager->activeTaskQueue && waitTaskQueue);
|
|
253
|
|
254 return ppeManager->get_runTaskList();
|
|
255 }
|
66
|
256
|
109
|
257 /**
|
|
258 * 条件を満たしたら SPE に TaskList を送信する
|
|
259 * 条件1. SPE が持ってた TaskList を終了して、次の TaskList を待ってる
|
|
260 * 条件2. SPE に送る TaskList に Task がある
|
|
261 *
|
|
262 * SPE で実行終了した TaskList [speTaskList] と
|
|
263 * これから実行する TaskList [speTaskList_bg] のバッファを入れ替える
|
|
264 * ついでに実行終了したやつは clear しておく。
|
|
265 */
|
|
266 void
|
|
267 CellTaskManagerImpl::send_taskList(int id)
|
|
268 {
|
|
269 TaskListPtr tmp;
|
|
270
|
|
271 tmp = speTaskList[id];
|
|
272 speTaskList[id] = speTaskList_bg[id];
|
|
273 speTaskList_bg[id] = tmp;
|
|
274
|
|
275 bufferManager->clear_taskList(speTaskList_bg[id]);
|
|
276
|
244
|
277 speThreads->send_mail(id, 1, (unsigned int *)&speTaskList[id]);
|
109
|
278 flag_sendTaskList[id] = 0;
|
57
|
279 }
|
|
280
|
65
|
281
|
109
|
282 void*
|
|
283 CellTaskManagerImpl::allocate(int size)
|
|
284 {
|
|
285 void *buff;
|
|
286
|
|
287 posix_memalign(&buff, DEFAULT_ALIGNMENT, size);
|
244
|
288
|
|
289 // bzero はコストが高いのでやりたくない
|
109
|
290 bzero(buff, size);
|
|
291
|
|
292 return buff;
|
|
293 }
|
|
294
|
|
295 #ifdef __CERIUM_CELL__
|
57
|
296 TaskManagerImpl*
|
|
297 create_impl(int num)
|
|
298 {
|
67
|
299 return new CellTaskManagerImpl(num);
|
57
|
300 }
|
109
|
301 #endif // __CERIUM_CELL
|