view TaskManager/Fifo/FifoTaskManagerImpl.cc @ 2041:363b7c401c79 draft

Make Rendefing Engine
author Shin,ichi Uehara
date Mon, 23 Mar 2015 17:47:12 +0900
parents f82bb7393c4d
children
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, int export_task_log)
{
    // TaskManager から呼ばれるので、かなりの部分は初期化されている。

    mainScheduler = new MainScheduler();
    init_task_list(task_list);
    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,mainScheduler,0);

    _export_task_log = export_task_log;

}

/**
 * これは 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(this->scheduler, "mail_check(): Task List finish\n");
            ppeTaskList->freeAll(); 
        } else if (data == (memaddr)MY_SPE_COMMAND_EXIT) {
            __debug_ppe(this->scheduler, "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(this->scheduler, "mail_check(): recv from 0x%x\n", data);
            // post_func を先に実行しないと、systask_finish が active_queue
            // 移されてから、wait_for されるという事態が起きることがある。
            TaskListPtr list = (TaskListPtr)data;
            check_task_list_finish(schedTaskManager, list, waitTaskQueue);
        }
    }
}

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::show_profile() {
	for (int id = 0; id < machineNum; id++) {
		HTaskPtr t = schedTaskManager->create_task(ShowTime, 0, 0, 0, 0);
		t->set_cpu((CPU_TYPE) (id + 2));
		t->spawn();
	}
}

void FifoTaskManagerImpl::start_profile() {
	for (int id = 0; id < machineNum; id++) {
            HTaskPtr t = schedTaskManager->create_task(StartProfile, 0, 0, 0, 0);
            t->set_cpu((CPU_TYPE) (id + 2));
            t->spawn();
	}
}

void FifoTaskManagerImpl::export_task_log() {
}

void
FifoTaskManagerImpl::print_arch()
{
    printf("FifoTaskManagerImpl\n");
}

TaskListPtr FifoTaskManagerImpl::createTaskList()
{
    TaskListPtr tl = taskListInfo->create();
    bzero(tl->tasks,sizeof(Task)*TASK_MAX_SIZE);
    return tl;
}