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 */