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