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__