Mercurial > hg > Game > Cerium
view TaskManager/kernel/ppe/TaskManagerImpl.cc @ 2000:ac16a57f5dd7 draft
fix get_nextTaskArea
author | kkb |
---|---|
date | Fri, 02 May 2014 19:30:48 +0900 |
parents | f4c16bdddee0 |
children |
line wrap: on
line source
//#include <stdio.h> #include "TaskManagerImpl.h" #include "types.h" #include "error.h" #include "SchedTask.h" #include "Scheduler.h" #include "SysTask.h" #include "SysFunc.h" #include "rdtsc.h" #include <string.h> // singleton QueueInfo<TaskQueue> *taskQueuePool = new QueueInfo<TaskQueue>() ; QueueInfo<HTask> *htaskPool = new QueueInfo<HTask>() ; QueueInfo<TaskList> *taskListPool = new QueueInfo<TaskList>() ; QueueInfo<TaskLog> *taskLogQueue = new QueueInfo<TaskLog>(); static HTaskPtr systask_start; static HTaskPtr systask_finish; static void noaction(SchedTask *s, void *read, void *write) { } TaskManagerImpl::TaskManagerImpl(int num) : machineNum(num) ,_export_task_log(0){ // 実行可能なHTaskのリスト activeTaskQueue = new QueueInfo<HTask>(htaskPool); // wait_forで止まっているHTaskのリスト。必要ないが、Dead lock detection に使う waitTaskQueue = new QueueInfo<HTask>(htaskPool); // HTask の factory. QueueInfo<HTask> ならなんでもいい。 htaskImpl = waitTaskQueue ; // any QueueInfo<HTask> // Task の dependency を表現する double linked list. QueueInfo<HTask> とは別に必要。 taskQueueImpl = new QueueInfo<TaskQueue>(taskQueuePool); } /** * 一番最初に PPE で実行される systask_start */ void TaskManagerImpl::systask_init() { systask_register(); systask_start = create_task(StartTask,0,0,0,0,__builtin_return_address(0)); systask_finish = create_task(FinishTask,0,0,0,0,__builtin_return_address(0)); systask_start->spawn(); // すべての Task が FinishTask を wait_for すると、 // あらゆる Task が FinishTask の waiting task queue を操作する // ことになる。それは、重すぎる。PPE/SPE Task が終了した時点で、 // TaskManager が実行する方が安い。 // append_waitTask(systask_finish); } /** * Create Simple Task */ HTaskPtr TaskManagerImpl::create_task(int cmd,memaddr rbuf, long r_size, memaddr wbuf, long w_size, void *from) { HTaskPtr new_task = htaskImpl->create(); new_task->init(cmd, rbuf, r_size, wbuf, w_size); // この引数はもう意味がない new_task->mimpl = this; new_task->command = TaskArray1; new_task->create_task_array(cmd, 1, 8, 8, 8) ; // この引数はもう意味がない new_task->post_func = noaction; new_task->from = (memaddr)from; Task *t = new_task->next_task_array(cmd,0,8,1,1); t->set_inData(0,rbuf,r_size); t->set_outData(0,wbuf,w_size); if (_export_task_log) { tasklog = new TaskLog(); tasklog->set_cmd(cmd); taskLogQueue->addLast(tasklog); } #ifdef EARLY_TOUCH if (rbuf) { if ((unsigned long)rbuf&0xf) { printf("Data is not aligned. command = %d, addr = 0x%lx, size = %ld\n", cmd, (unsigned long)rbuf, r_size); } char *p = (char *)rbuf; char b = *p; // これはコンパイラが落としてしまうのではないか... p = (char *)(rbuf+r_size-1); b += *p; } if (wbuf) { if ((unsigned long)wbuf&0xf) { printf("Data is not aligned. command = %d, addr = 0x%lx, size = %ld\n", cmd, (unsigned long)wbuf, w_size); } char *p = (char *)wbuf; char b = *p; p = (char *)(wbuf+w_size-1); b += *p; } #endif return new_task; } /** * Create Compatible Task (TaskArray1) */ HTaskPtr TaskManagerImpl::create_task(int cmd,void *from) { HTaskPtr new_task = create_task(TaskArray,0,0,0,0, from); new_task->post_func = noaction; new_task->mimpl = this; new_task->create_task_array(cmd,1,8,8,8); // rbuf, r_size were set new_task->command = TaskArray1; new_task->from = (memaddr)from; new_task->next_task_array(cmd,0,8,8,8); if (_export_task_log) { tasklog = new TaskLog(); tasklog->set_cmd(cmd); taskLogQueue->addLast(tasklog); } return new_task; } /** * Create Task Array */ HTaskPtr TaskManagerImpl::create_task_array(int id, int num_task, int num_param, int num_inData, int num_outData, void *from) { HTaskPtr ta = create_task(TaskArray,0,0,0,0, from); ta->create_task_array(id, num_task, num_param, num_inData, num_outData) ; return ta; } TaskListPtr TaskManagerImpl::createTaskList() { return NULL; } /* call get_task_name from ppu only */ const char * TaskManagerImpl::get_task_name(int cmd) { if (0 <= cmd && cmd < MAX_TASK_OBJECT) { return task_list[cmd].name; } else { return NULL; } } const char * TaskManagerImpl::get_task_name(TaskPtr task) { return task != NULL ? get_task_name(task->command) : NULL; } const char * TaskManagerImpl::get_task_name(SimpleTaskPtr simple_task) { return simple_task != NULL ? get_task_name(simple_task->command) : NULL; } const char * TaskManagerImpl::get_task_name(SchedTaskBase *sched_task) { if (sched_task == NULL) return NULL; if (sched_task->atask != NULL) { return get_task_name(sched_task->atask->command); } return NULL; } const char * TaskManagerImpl::get_task_name(HTaskPtr htask) { return get_task_name(htask, 0); } const char * TaskManagerImpl::get_task_name(HTaskPtr htask, int index) { if (!htask) return NULL; switch (htask->command) { case TaskArray1: return get_task_name((TaskPtr)htask->rbuf); break; case TaskArray: { TaskPtr tmp = (TaskPtr)htask->rbuf; return get_task_name(tmp[0].command); } default: return get_task_name(htask->command); } return NULL; } /** * task の依存関係を設定 * master task が終わってから、slave task を実行するように * master->wait_for(slave); */ void TaskManagerImpl::set_task_depend(HTaskPtr master, HTaskPtr slave) { if (_export_task_log) { waitTask* wait_task = new waitTask; wait_task->task_id = tasklog->mtask_id; wait_task->cmd = tasklog->cmd; tasklog->wait_for_list.addLast(wait_task); } TaskQueuePtr m, s; if (!master->self) return; m = taskQueueImpl->create(); m->init(master); s = taskQueueImpl->create(); s->init(slave); master->wait_me->addLast(s); slave->wait_i->addLast(m); s->waiter = m; } /** * タスクを実行可能キューまたは待機キューへ追加する。 * 依存関係が満たされていれば active, まだだったら wait へ。 * task->spawn(); */ void TaskManagerImpl::spawn_task(HTaskPtr task) { if (_export_task_log) tasklog->create_time = rdtsc(); // waiter // master // waitee // slave if (task->wait_i->empty()) { append_activeTask(task); } else { append_waitTask(task); } } /** * Task を実行可能キューに追加する */ void TaskManagerImpl::append_activeTask(HTaskPtr q) { activeTaskQueue->addLast(q); } /** * タスクが実行する CPU を選択する * * 現在は CPU_PPE, CPU_SPE, SPE_ANY, SPE_0, SPE_1, ..., SPE_5 * types.h に書いてます。 */ void TaskManagerImpl::set_task_cpu(HTaskPtr task, CPU_TYPE type) { task_list->cpu_type = type; if (machineNum==0) task->cpu_type = CPU_PPE ; else task->cpu_type = type; } #if 0 static void check_wait(TaskManagerImpl *tm, QueueInfo<TaskQueue> *wait_i) { for(TaskQueue *t = wait_i->getFirst(); t; t = wait_i->getNext(t)) { if (!tm->waitTaskQueue->find(t->task)) { //this->printf("stray waiting task%d %lx\n",t->task->command, (long)t->task); printf("stray waiting task%d %lx\n",t->task->command, (long)t->task); } else if (tm->activeTaskQueue->find(t->task)) { //this->printf(" active task%d in waiting queue %lx\n",t->task->command, (long)t->task); printf(" active task%d in waiting queue %lx\n",t->task->command, (long)t->task); } else printf("."); } } #endif /** * @brief 終了したタスクから依存の処理とか * post_func() はこのタスクが終了したら実行する関数。 * * @param [task] 終了したタスク */ void TaskManagerImpl::check_task_finish(HTaskPtr me, QueueInfo<HTask> *wait_queue) { if (_export_task_log) tasklog->finish_time = rdtsc(); while(TaskQueue *p = me->wait_me->poll()) { HTaskPtr you = p->task; QueueInfo<TaskQueue> *wait_i = you->wait_i; // 相手の wait queue から自分(を指しているTaskQueue)を削除 wait_i->remove(p->waiter); // queue を free する wait_i->free_(p->waiter); if (wait_i->empty()) { wait_queue->remove(you); append_activeTask(you); } wait_i->free_(p); // p->wait_i, p->wait_me は再利用される } // このTaskList は終わったので、今 free して良いが、TaskListInfo に入っているので、 // MY_SPE_STATUS_READY 時に、まとめてfree する。FifoTaskManager/CellTaskManager // me を誰かが持っていて、me が finish した後に、 // me->wait_for(i) とか、やられると気まずい。 // 特に、me が他人に再利用されていると。そういう時には、 // このfreeをコメントアウトしてみる。 // id かななんかでチェックした方が良いが... me->self = 0; if (!me->flag.no_auto_free) htaskImpl->free_(me); } /** * @brief 終了したタスクリストの依存の処理 * @param [task] 終了したタスク */ void TaskManagerImpl::check_task_list_finish(SchedTask *s, TaskListPtr list, QueueInfo<HTask> *wait_queue) { HTask *me = list->self; if (me) { me->post_func(s, me->post_arg1, me->post_arg2); check_task_finish(me, wait_queue); } } /** * @brief waitTaskqueue への挿入 。必須ではない。 * 現状では、dead lock 検出にしか使ってない * * @param [task] 終了したタスク */ void TaskManagerImpl::append_waitTask(HTaskPtr q) { waitTaskQueue ->addLast(q); } /** @brief htask のTaskListを DMA でCPUに渡すための TaskListQueue に入れる @param htask @param taskList */ void TaskManagerImpl::set_taskList(HTaskPtr htask, QueueInfo<TaskList> * taskList) { if (_export_task_log) tasklog->execute_time = rdtsc(); TaskListPtr tl = (TaskList*)htask->rbuf; while(tl->prev) tl=tl->prev; while(tl) { TaskListPtr next = tl->next; taskList->addLast(tl); tl = next; } } void error(const char *error_message) { fprintf(stderr,"%s \n",error_message); exit(1); } /* end */