Mercurial > hg > Members > kono > Cerium
view TaskManager/Cell/CellTaskManagerImpl.cc @ 300:0691f38195f6
remove TaskManager/Fifo/MainScheduler.o TaskManeger/Test/test_render/test_nogl
author | tkaito@localhost.localdomain |
---|---|
date | Sun, 07 Jun 2009 17:44:08 +0900 |
parents | 58fd16298954 |
children | c9f8cfcdc5c2 |
line wrap: on
line source
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "CellTaskManagerImpl.h" #include "CellBufferManager.h" #include "PpeScheduler.h" #include "types.h" #include "error.h" CellTaskManagerImpl::~CellTaskManagerImpl(void) { delete speThreads; delete [] speTaskList; delete [] speTaskList_bg; /** * bufferManager は * ppeManager のなかで delete してもらう */ // delete bufferManager; delete [] flag_sendTaskList; delete ppeManager; } void CellTaskManagerImpl::init(void) { bufferManager = new CellBufferManager(machineNum); bufferManager->init(); speThreads = new SpeThreads(machineNum); speThreads->init(); speTaskList = new TaskListPtr[machineNum]; speTaskList_bg = new TaskListPtr[machineNum]; for (int i = 0; i < machineNum; i++) { speTaskList[i] = bufferManager->create_taskList(); speTaskList_bg[i] = bufferManager->create_taskList(); } flag_sendTaskList = new int[machineNum]; for (int i = 0; i < machineNum; i++) { flag_sendTaskList[i] = 1; } // PPE 側の管理をする Manager ppeManager = new FifoTaskManagerImpl(machineNum); ppeManager->init(new PpeScheduler, bufferManager); } void CellTaskManagerImpl::append_activeTask(HTaskPtr task) { TaskQueuePtr q; q = bufferManager->create_taskQueue(task); if (task->cpu_type == CPU_PPE) { ppeManager->append_activeTask(task); } else { activeTaskQueue = TaskQueue::append(activeTaskQueue, q); } } // SPE_ANY が指定されていた時に // これをインクリメントしつつ呼ぶことにする。 // 乱数使ってもいいけどさ。 int cur_anySpeid = 0; /** * ActiveTaskQueue から Task を * 各 SPE に渡す TaskList に入れる * * ここの activeTaskQueue は FifoTaskManagerImpl のと意味が違い、 * spe に渡される Task だけ入っている */ void CellTaskManagerImpl::set_runTaskList(void) { // ここ...直すかな TaskListPtr list; TaskQueuePtr queue; TaskQueuePtr d; HTaskPtr htask; TaskPtr task; int speid; queue = activeTaskQueue; if (queue == NULL) { return ; } while (queue) { htask = (HTaskPtr)queue->task; d = queue; queue = queue->next; if (htask->cpu_type == SPE_ANY) { speid = cur_anySpeid++; cur_anySpeid = (cur_anySpeid < machineNum) ? cur_anySpeid : 0; } else { // -1 してるのは // htask->cpu_type - CPU_SPE で // SPE0 = 1, SPE1 = 2, ... SPE5 = 6 ってなってるので // 配列的 (SPE0 = arr[0], SPE1 = arr[1]) にするため speid = htask->cpu_type - CPU_SPE - 1; // SPU の数以上が指定されていれば // とりあえず MAX_USE_SPE_NUM (実際に動く SPE の最大数) で // あまり求めてそれを使うことにする。 // ここで判定するもんでもないか? if (speid >= machineNum) { speid %= machineNum; } } list = speTaskList_bg[speid]; if (list->length >= TASK_MAX_SIZE) { TaskListPtr newList = bufferManager->create_taskList(); newList = TaskListInfo::append(newList, speTaskList_bg[speid]); speTaskList_bg[speid] = newList; list = newList; } task = &list->tasks[list->length++]; #if 0 task->command = htask->command; task->inData = htask->inData; task->outData = htask->outData; task->self = (unsigned int)htask; #else memcpy(task, htask, sizeof(Task)); #endif bufferManager->free_taskQueue(d); } activeTaskQueue = NULL; } void CellTaskManagerImpl::run(void) { TaskListPtr ppeTaskList = NULL; MailQueuePtr ppeMail = NULL; // PPE 側で動く TaskList です // FifoTaskManagerImpl::run と上手く合うように // こんなことやってますよ ppeTaskList = ppeManager->get_runTaskList(); if (!ppeTaskList) { goto cont; } // SPE からの Mailbox Check は // PPE 側の schedule から抜けて来たときに行う // (speThreads で Blocking Mailbox read と // セマフォとか使ってやってもいいが、今はこの方式で) do { ppeMail = ppeManager->schedule(ppeTaskList); cont: ppeTaskList = mail_check(ppeMail); } while (ppeTaskList); } /** * SPE からのメールをチェックする * * @param [mail_list] * PPE 側で動く Scheduler からのメールリスト * この中で PPE 側の mail check も行う * * @return PPE Scheduler に対してのメール。 * 次に実行する TaskList のアドレスや、終了コマンドを送る */TaskListPtr CellTaskManagerImpl::mail_check(MailQueuePtr mail_list) { // PPE Scheduler からの mail check ppeManager->mail_check(mail_list, &waitTaskQueue); do { unsigned int data; // SPE Scheduler からの mail check for (int id = 0; id < machineNum; id++) { while (speThreads->check_mail(id, 1, &data)) { /** * MY_SPE_STATUS_READY: SPE が持ってた Task 全て終了 * MY_SPE_NOP: 特に意味のないコマンド * それ以外:終了したタスク(PPEにあるのでアドレス * * MY_SPE_NOP が 0 なので、 * 下のように data > MY_SPE_NOP とかしています。 * 一目でよくわからない書き方なんで、直したいところですが。。。 */ // 名前あとでちゃんと決めよう => MY_SPE_... とかじゃなくて if (data == MY_SPE_STATUS_READY) { __debug_ppe("[SPE %d] finish\n", id); flag_sendTaskList[id] = 1; } else if (data == MY_SPE_COMMAND_MALLOC) { __debug_ppe("[PPE] MALLOC COMMAND from [SPE %d]\n", id); /** * info[0] = alloc_id; (CellScheduler::mainMem_alloc 参照) * info[1] = alloc_addr; */ unsigned int alloc_info[3]; int alloc_size; int command; speThreads->get_mail(id, 2, alloc_info); command = alloc_info[0]; alloc_size = alloc_info[1]; alloc_info[1] = (unsigned int)allocate(alloc_size); /* * allocate された領域は今の SPE buffer にリンクとして接続する * ここでは TaskList を allocate(new) して登録してやろうか */ speThreads->add_output_tasklist(command, alloc_info[1], alloc_size); speThreads->send_mail(id, 2, alloc_info); } else if (data > MY_SPE_NOP) { __debug_ppe("[PPE] recv from [SPE %d] : 0x%x\n", id, data); check_task_finish((HTaskPtr)data); } } } // 依存関係を満たしたタスクをアクティブに wakeup_waitTask(); // SPE に送る TaskList の準備 set_runTaskList(); // TaskList 待ちの SPE に TaskList を送る for (int i = 0; i < machineNum; i++) { if (flag_sendTaskList[i] == 1 && speTaskList_bg[i]->length >= 1 ) { send_taskList(i); } } // 現在の FifoTaskManager の仕様では // ・PPE で実行するタスクが無くなれば終了する // であり、この場合もし SPE にタスクが残っていても // メインループから抜けてプログラム終了となってしまうので // ここでストップかけてます。 } while (!ppeManager->activeTaskQueue && waitTaskQueue); return ppeManager->get_runTaskList(); } /** * 条件を満たしたら SPE に TaskList を送信する * 条件1. SPE が持ってた TaskList を終了して、次の TaskList を待ってる * 条件2. SPE に送る TaskList に Task がある * * SPE で実行終了した TaskList [speTaskList] と * これから実行する TaskList [speTaskList_bg] のバッファを入れ替える * ついでに実行終了したやつは clear しておく。 */ void CellTaskManagerImpl::send_taskList(int id) { TaskListPtr tmp; tmp = speTaskList[id]; speTaskList[id] = speTaskList_bg[id]; speTaskList_bg[id] = tmp; bufferManager->clear_taskList(speTaskList_bg[id]); speThreads->send_mail(id, 1, (unsigned int *)&speTaskList[id]); flag_sendTaskList[id] = 0; } void* CellTaskManagerImpl::allocate(int size) { void *buff; posix_memalign(&buff, DEFAULT_ALIGNMENT, size); // bzero はコストが高いのでやりたくない bzero(buff, size); return buff; } #ifdef __CERIUM_CELL__ TaskManagerImpl* create_impl(int num) { return new CellTaskManagerImpl(num); } #endif // __CERIUM_CELL