Mercurial > hg > Game > Cerium
view TaskManager/Fifo/FifoTaskManagerImpl.cc @ 1229:424c1f16e704 draft
add args useRefDma
author | Daichi TOMA <e085740@ie.u-ryukyu.ac.jp> |
---|---|
date | Wed, 24 Aug 2011 07:45:27 +0900 |
parents | 17508bef43be |
children | 26c155523861 |
line wrap: on
line source
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "FifoTaskManagerImpl.h" #include "CellTaskManagerImpl.h" #include "QueueInfo.h" #include "TaskList.h" #include "Scheduler.h" #include "SchedTask.h" #include "types.h" #include "error.h" #include "SchedNop.h" #include "SysFunc.h" extern QueueInfo<TaskList> *taskListPool; static void send_alloc_reply(FifoTaskManagerImpl *tm, int id, MainScheduler *s); FifoTaskManagerImpl::~FifoTaskManagerImpl() { delete mainScheduler; delete taskQueueImpl ; delete htaskImpl ; } /** * FifoTaskManager 単独で走るときの初期化 * MailManager は PPE スケジューラとのメール交換、 * FifoScheduler は PPE 側のスケジューラ */ void FifoTaskManagerImpl::init(int spuIdle_, int useRefDma) { // TaskManager から呼ばれるので、かなりの部分は初期化されている。 mainScheduler = new MainScheduler(); mainScheduler->init(this,useRefDma); mainScheduler->id = 0; set_scheduler(mainScheduler); taskListInfo = new QueueInfo<TaskList>(taskListPool); ppeTaskList = new QueueInfo<TaskList>(taskListPool); schedTaskManager = new SchedTask(); others = 0; schedTaskManager->init(0,0,0,mainScheduler,0); } /** * これは CellTaskManagerImpl から呼ばれる。 * TaskList等 は共用で使うので引数に。 * CellTaskManagerImpl と FifoTaskManagerImpl が同時に * 上のデータにアクセスする事は(今は)ないのでこれでおk */ void FifoTaskManagerImpl::init(MainScheduler *_sched, TaskManagerImpl *tm, int useRefDma) { mainScheduler = _sched; mainScheduler->init(this,useRefDma); set_scheduler(mainScheduler); taskQueueImpl = tm-> taskQueueImpl ; htaskImpl = tm-> htaskImpl ; waitTaskQueue = tm->waitTaskQueue; activeTaskQueue = tm->activeTaskQueue; taskListInfo = new QueueInfo<TaskList>(taskListPool); ppeTaskList = new QueueInfo<TaskList>(taskListPool); // schedTaskManager = new SchedTask(); others = tm; // schedTaskManager->init(0,0,0,mainScheduler); } // void FifoTaskManagerImpl::show_profile() {} // void FifoTaskManagerImpl::start_profile() {} /** * スケジューラに渡す TaskList を取得する。 * * @return 実行タスクリスト * * ActiveTaskQueue (依存条件は満たし済み) のタスクを * 実行タスクリストに入れる * CPU_PPE */ void FifoTaskManagerImpl::set_runTaskList(QueueInfo<HTask> *activeTaskQueue) { // printf("active task queue length = %d\n",activeTaskQueue->length()); HTaskPtr htask = activeTaskQueue->getFirst(); while (htask != NULL) { if (htask->cpu_type == CPU_PPE) { set_taskList(htask, taskListInfo ); HTaskPtr next = activeTaskQueue->getNext(htask); activeTaskQueue->remove(htask); htask = next; } else { htask = activeTaskQueue->getNext(htask); } } } /** * exec all cpu type as simulation */ void FifoTaskManagerImpl::set_runTaskList1(QueueInfo<HTask> *activeTaskQueue) { // printf("active task queue length = %d\n",activeTaskQueue->length()); HTaskPtr htask = activeTaskQueue->getFirst(); while (htask != NULL) { set_taskList(htask, taskListInfo ); HTaskPtr next = activeTaskQueue->getNext(htask); activeTaskQueue->remove(htask); htask = next; } } /** * called from CellTaskManagerImpl */ void FifoTaskManagerImpl::poll() { set_runTaskList(activeTaskQueue); // list を実行する sendTaskList(); // ppe scheduler からの mail を調べる mail_check(); } /** * single CPU run */ void FifoTaskManagerImpl::poll1() { set_runTaskList1(activeTaskQueue); // list を実行する sendTaskList(); // ppe scheduler からの mail を調べる mail_check(); } /** * single CPU run */ void FifoTaskManagerImpl::run() { do { poll1(); } while(!activeTaskQueue->empty()) ; if (!waitTaskQueue->empty()) { get_scheduler()->printf("Dead lock detected\n"); } } /** * @param [list] 実行タスクリスト * @return FifoScheduler からのメール * * [Tasklist] -> [番兵] -> scheduler->run を抜ける */ void FifoTaskManagerImpl::sendTaskList() { if (taskListInfo->empty()) return; // ppeTaskList は走り終わった ppe の Task の List. // taskListInfo はこれから走る Task の List. // 交換して実行する QueueInfo<TaskList>* tmp = ppeTaskList; ppeTaskList = taskListInfo; taskListInfo = tmp; // ppeTaskList は本来は循環リストなのだけど、実行中は線形リストである。 // なので、最後に 0 を代入する. 後でなおす。 ppeTaskList->getLast()->next = 0; // TaskList のアドレスを送る mainScheduler->mail_write_from_host((memaddr)ppeTaskList->getFirst()); // EXIT_COMMAND (番兵的な意味で) // これを読むと、mainScheduler->run() から抜けて来る。 mainScheduler->mail_write_from_host((memaddr)MY_SPE_COMMAND_EXIT); // scheduler は受け取ったメールを元に実行する mainScheduler->run(new SchedNop()); // すべてのlistを実行するまで戻らない ppeTaskList->getLast()->next = ppeTaskList; } /** * PPE Scheduler からのメールをチェックする * * @param [mail_list] * PPE 側で動く Scheduler からのメールリスト * 終了した Task や、その他(今はまだ実装してないけど)の情報が入ってる * * @return Scheduler が次に実行する Task List * NULL なら全てのタスクが実行終了したということ */ void FifoTaskManagerImpl::mail_check() { while (mainScheduler->has_mail_from_host()) { memaddr data = mainScheduler->mail_read_from_host(); if (data == (memaddr)MY_SPE_STATUS_READY) { __debug_ppe("mail_check(): Task List finish\n"); ppeTaskList->freeAll(); } else if (data == (memaddr)MY_SPE_COMMAND_EXIT) { __debug_ppe("mail_check(): Task List finish COMMAND\n"); } else if (data == (memaddr)MY_SPE_COMMAND_MALLOC) { send_alloc_reply(this, 0, mainScheduler); } else if (data != (memaddr)MY_SPE_NOP) { __debug_ppe("mail_check(): recv from 0x%x\n", data); // post_func を先に実行しないと、systask_finish が active_queue // 移されてから、wait_for されるという事態が起きることがある。 #ifdef TASK_LIST_MAIL TaskListPtr list = (TaskListPtr)data; check_task_list_finish(schedTaskManager, list, waitTaskQueue); #else HTaskPtr task = (HTaskPtr)data; #if 0 if (task->cpu_type != CPU_PPE) { const char *name = get_task_name(task); if (name != NULL) { printf("[PPE] "); printf("Task id : %d, ", task->command); printf("Task name : %s\n", name); } } #endif #ifndef NOT_CHECK if (task != NULL) { //PPE で処理された Task が返ってくるはず。 if (task->cpu_type != CPU_PPE) { printf("attention : SPE task run on PPE\n"); printf("Task id : %d\n", task->command); const char *name = get_task_name(task); if (name != NULL) { printf("Task name : %s\n", name); } } } #endif task->post_func(schedTaskManager, task->post_arg1, task->post_arg2); check_task_finish(task, waitTaskQueue); #endif } } } void FifoTaskManagerImpl::polling() { if (others!=0) others->polling(); } static void send_alloc_reply(FifoTaskManagerImpl *tm, int id, MainScheduler *s) { /** * info[0] = alloc_id; (CellScheduler::mainMem_alloc 参照) * info[1] = alloc_addr; */ memaddr alloc_info[2]; long alloc_size; long command; alloc_info[0] = s->mail_read_from_host(); alloc_info[1] = s->mail_read_from_host(); command = (long)alloc_info[0]; alloc_size = (long)alloc_info[1]; alloc_info[1] = (memaddr)tm->allocate(alloc_size); //__debug_ppe("[PPE] MALLOCED 0x%lx from [SPE %d]\n", alloc_info[1],id); // 今のところ何もしてない。どうも、この allocate を free // するのは、SPE task が返した値を見て行うらしい。それは、 // 忘れやすいのではないか? // s->add_output_tasklist(command, alloc_info[1], alloc_size); s->mail_write_from_host(alloc_info[0]); s->mail_write_from_host(alloc_info[1]); } void FifoTaskManagerImpl::print_arch() { printf("FifoTaskManagerImpl\n"); } /** * # # # # # # # # * Abstract Factory Pattern * # # # # # # # */ #ifdef __CERIUM_FIFO__ TaskManagerImpl* create_impl(int num, int useRefDma) { #ifdef __CERIUM_PARALLEL__ //マルチコアverでコンパイルしたのにかかわらず、 //CPU数が0だと、FifoTaskManagerが呼ばれてしまうので //0の場合は1を入れて、CellTaskManagerが呼ばれるようにする。 if (num == 0) num = 1; #else num = 0; #endif if (num == 0) { return new FifoTaskManagerImpl(num); } else { Threads *cpus = new CpuThreads(num,useRefDma); cpus->init(); return new CellTaskManagerImpl(num,cpus); } } #endif // __CERIUM_FIFO__