Mercurial > hg > Members > kono > Cerium
view TaskManager/kernel/ppe/TaskManagerImpl.cc @ 1048:40cde8c1a6cd default tip
add ScaleXY (not for allExecute...)
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Wed, 08 Dec 2010 06:22:15 +0900 (2010-12-07) |
parents | 9989dd7b9ac2 |
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 <string.h> // singleton QueueInfo<TaskQueue> *taskQueuePool = new QueueInfo<TaskQueue>() ; QueueInfo<HTask> *htaskPool = new QueueInfo<HTask>() ; QueueInfo<TaskList> *taskListPool = new QueueInfo<TaskList>() ; static HTaskPtr systask_start; static HTaskPtr systask_finish; static void noaction(SchedTask *s, void *read, void *write) { } TaskManagerImpl::TaskManagerImpl(int num) : machineNum(num){ // 実行可能な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; new_task = htaskImpl->create(); new_task->init(cmd, rbuf, r_size, wbuf, w_size); new_task->post_func = noaction; new_task->mimpl = this; new_task->from = (memaddr)from; #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; // for compatibility new_task = htaskImpl->create(); new_task->init(TaskArray1); 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; 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; } /** * task の依存関係を設定 * master task が終わってから、slave task を実行するように * master->wait_for(slave); */ void TaskManagerImpl::set_task_depend(HTaskPtr master, HTaskPtr slave) { 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) { // 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) { 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)) { printf("stray waiting task%d %lx\n",t->task->command, (long)t->task); } else if (tm->activeTaskQueue->find(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) { 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 は再利用される } // 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) { for(int i = 0;i<list->length;i++) { SimpleTaskPtr task = &list->tasks[i]; HTask *me = (HTask*)task->self; me->post_func(s, me->post_arg1, me->post_arg2); if (task->command==TaskArray1) { int next = ((task->r_size)/sizeof(SimpleTask))+1; // assert(next<list->length); i+=next; } s->polling(); check_task_finish(me, wait_queue); } } /** * @brief waitTaskqueue への挿入 。必須ではない。 * 現状では、dead lock 検出にしか使ってない * * @param [task] 終了したタスク */ void TaskManagerImpl::append_waitTask(HTaskPtr q) { waitTaskQueue ->addLast(q); } /** @brief htask を DMA でCPUに渡すための TaskList に入れる (copy) @param htask @param taskList TaskList は自動的に延長される */ void TaskManagerImpl::set_taskList(HTaskPtr htask, QueueInfo<TaskList> * taskList) { TaskListPtr list ; if ( taskList->empty() ) { list = taskList->create(); taskList->addLast(list); } else list = taskList->getLast(); SimpleTaskPtr task = &list->tasks[list->length++]; if (htask->command==TaskArray1) { // compatibility int next = ((htask->r_size)/sizeof(SimpleTask))+1; if (list->length+next>=TASK_MAX_SIZE) { list->length--; TaskListPtr newList = taskList->create(); taskList->addLast(newList); list = newList; task = &list->tasks[list->length++]; } Task *array = (Task*)&list->tasks[list->length]; list->length += next; if (list->length>=TASK_MAX_SIZE) { perror("task array1 overflow\n"); } memcpy(array, htask->rbuf, htask->r_size); free(htask->rbuf); // htask->rbuf = 0; htask->r_size = 0; we need this... *task = *(SimpleTask*)htask; } else { *task = *(SimpleTask*)htask; } if (list->length >= TASK_MAX_SIZE) { TaskListPtr newList = taskList->create(); taskList->addLast(newList); list = newList; } } /* end */