view TaskManager/kernel/schedule/Scheduler.cc @ 1724:d6f18ee58e0e draft

use the method of opencl
author Yuhi TOMARI <yuhi@cr.ie.u-ryukyu.ac.jp>
date Wed, 30 Oct 2013 17:28:20 +0900
parents a0014faececa
children e99dc86d39e2
line wrap: on
line source

//#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "Scheduler.h"
#include "SchedTask.h"
#include "SchedNop.h"
#include "SysFunc.h"
#include "error.h"
#include <assert.h>
#include "TaskManagerImpl.h"

/*
 * Edit kernel/schedule/xx.cc, Cell/spe/xx.cc will be over writen by this.
 * Do not edit Cell/spe/xx.cc unless there is no kernel/schedule/xx.cc files.
 */

TaskObject task_list[MAX_TASK_OBJECT];

#ifndef NOT_CHECK
int entry_cmd[MAX_TASK_OBJECT];
int task_count = 0;
#endif

Scheduler::~Scheduler()
{
    delete connector;
}

int
null_run(SchedTask* smanager, void* r, void *w)
{
    smanager->printf("Calling Undefined Task %d\n", smanager->atask->command);
    return 0;
}

void null_loader(Scheduler *m, int task_id);

/*! @brief speTaskの入出力のパイプラインバッファを確保する
 */

void
init_task_list(TaskObject* task_list) {
  for (int i = 0; i< MAX_TASK_OBJECT; i++) {
    task_list[i].run = null_run;
    task_list[i].load = null_loader;
    task_list[i].wait = null_loader;
    task_list[i].gputask = new GpuTaskObject();
    
#ifndef NOT_CHECK
    entry_cmd[i] = NULL;
#endif

    }
}

//useRefDmaは、0という初期値が設定されている。
void
Scheduler::init(TaskManagerImpl *m, int useRefDma, int export_task_log)
{
    hash = 0;

#ifndef NOT_CHECK
    task_count = 0;
#endif

    set_manager(m);
    init_impl(useRefDma);

    for (int i = 0; i < 2; i++) {
        buff_taskList[i]    = (TaskListPtr)m->allocate(sizeof(TaskList));
    }

    buffFlag_taskList = 0;

    // bzero でもいいけど
    for (int i = 0; i < MAX_GLOBAL_AREA; i++) {
        globalList[i] = NULL;
    }

    for (int i = 0; i < MAX_MAINMEM_AREA; i++) {
        mainMemList[i] = (memaddr)NULL;
    }

}

void
Scheduler::run(SchedTaskBase* task1)
{

    // Pipeline Stage
    SchedTaskBase* task2 = new SchedNop();
    SchedTaskBase* task3 = new SchedNop();
    // main loop
    do {

        task1->read();
        task2->exec();
        task3->write();

        delete task3;

        task3 = task2;
        task2 = task1;
        //SchedMailの場合、Mailの待ちが入る
        task1 = task1->next(this, 0);

    } while (task1);

    delete task3;
    delete task2;
}


void
Scheduler::finish()
{
    free(buff_taskList[0]);
    free(buff_taskList[1]);
}

/**
 * あらかじめ memory allocte してある TaskList の領域を
 * パイプラインの各処理が交代して使う。
 */
TaskListPtr
Scheduler::get_curListBuf()
{
    buffFlag_taskList ^= 1;

    return buff_taskList[buffFlag_taskList];
}


/*
  ここから下は、memory 以下にあるべき
*/

void*
Scheduler::global_alloc(int id, int size)
{

    globalList[id] = manager->allocate(size);

    return globalList[id];
}

void*
Scheduler::global_get(int id)
{
    return globalList[id];
}

void
Scheduler::global_set(int id, void *addr)
{
    globalList[id] = addr;
}

void
Scheduler::global_free(int id)
{
    free(globalList[id]);
    globalList[id] = NULL;
}

/**
 * mainMem_alloc で確保したメインメモリの領域アドレスを返す。
 * これは Fifo, Cell で共通
 */
memaddr
Scheduler::mainMem_get(int id)
{
    return mainMemList[id];
}

/**
 *  Task load API
 */
void
Scheduler::allocate_code_segment(int size, int count, struct tbl *table)
{
    // 既に overlay 領域があるので、それを追加する必要がある...
    code_segment_pool = createMemList(size, count);
    if (table) {
        MemorySegment* here = (MemorySegment*)(
                                               manager->allocate(sizeof(MemorySegment)));
        here->data = &table->vma;
        here->size = size;
        here->address = (memaddr)here;
        code_segment_pool->addLast(here);
    }
}

static void
load_task(Scheduler *m, int task_id)
{
    MemorySegment *s = m->get_segment(
                                      task_list[task_id].location,
                                      m->code_segment_pool,
                                      task_list[task_id].end-task_list[task_id].location);
    task_list[task_id].segment = s;
    // calcurate call address
    TaskObjectRun run =
        (TaskObjectRun)(
                        (char*)task_list[task_id].segment->data +
                        task_list[task_id].entry_offset);
    task_list[task_id].run = run;
#if 0
    m->printf("loadng task id %d at 0x%x entry 0x%x location 0x%x\n",task_id,
              (unsigned int)(task_list[task_id].segment->data ),
              (unsigned int)(
                             (char*)task_list[task_id].segment->data +
                             task_list[task_id].entry_offset),
              task_list[task_id].location);
#endif
}

void
null_loader(Scheduler *m, int task_id)
{
}

static void
wait_load(Scheduler *m, int task_id)
{
#if 0
    MemorySegment *s = task_list[task_id].segment;
    if (s)
        m->printf("wait load task id %d 0x%x\n",task_id,(int)s->data);
    else
        m->printf("wait load task id %d 000000\n",task_id);
#endif
    // wait for code segment load
    m->wait_segment(task_list[task_id].segment);
#if 0
    m->printf("wait load task id %d done. creator = 0x%x entry_offset = 0x%x\n",task_id,
              (unsigned int)(task_list[task_id].run),
              task_list[task_id].entry_offset);
#endif
}

static void
null_waiter(Scheduler *m, int task_id)
{
}

extern void
register_task(int cmd, TaskObjectRun run, const char *str)
{
    task_list[cmd].run = run;
    task_list[cmd].load = null_loader;
    task_list[cmd].wait = null_waiter;
    task_list[cmd].name = str;

#ifndef NOT_CHECK
    entry_cmd[task_count++] = cmd;
#endif

}

extern void
register_dynamic_task(int cmd,
                      memaddr start, int size,
                      TaskObjectRun run, int entry_offset,
                      const char *str)
{
    task_list[cmd].run = run;
    task_list[cmd].location = start;
    size &= 0xfffffffe;
    task_list[cmd].end = start+size;
    task_list[cmd].entry_offset = entry_offset;
    task_list[cmd].load = load_task;
    task_list[cmd].wait = wait_load;
    task_list[cmd].name = str;

#ifndef NOT_CHECK
    entry_cmd[task_count++] = cmd;
#endif

#if 0
    this->printf("cmd        = %d\n",cmd);
    this->printf("locatation = 0x%x\n",start);
    this->printf("end        = 0x%x\n",start+size);
    this->printf("size       = 0x%x\n",size);
    this->printf("entry      = 0x%x\n",entry_offset);
#endif

}


/*!

  size 単位のMemory Segment を count 個作る

  @param [size] リストの要素1つのサイズ
  @param [count] 要素数
  @return allocate した領域のポインタ

*/
MemList*
Scheduler::createMemList(int size, int count)
{
    uint32 head_size = round_up16(sizeof(MemorySegment));
    uint32 seg_size = round_up16(head_size+size);
    char* mseg = (char*)manager->allocate(seg_size*count);
    MemList* mlist = new MemList((MemorySegment*)mseg);

    if (!hash) {
        hash = new MemHash();
    }

    for(int i = 0; i < count; i++) {
        MemorySegment* next = (MemorySegment*)(mseg+seg_size*i);
        char* data = (char*)next+head_size;
        next->data = (void*)data;
        next->size = size;
        next->address = (memaddr)next;
        mlist->addLast(next);
    }

    return mlist;
}

/*!

  Main Memory のSegmentを取得する

  @param [addr] Main Memory のアドレス
  @param [m]    Mem List
  @return allocate した領域のポインタ
  memory directory にあるべきだが...

*/
MemorySegment *
Scheduler::get_segment(memaddr addr, MemList *m)
{
#ifdef USE_CACHE

    MemorySegment *s = m->getFirst();
    return get_segment(addr, m, s->size);

#else

    //addr が空だった場合はどうなるか
    //こうすると単純にFIFOか
    //  そうじゃなくて、単にbufferを余計に取って毎回DMAしているだけだよね。

    MemorySegment *s = m->getLast();
    m->moveToFirst(s);
    s->tag = connector->get_tag();
    s->address = addr;
    s->data = connector->dma_load1(s->data, addr, s->size, s->tag);

    return s;

#endif

}

/*!

  free な Segmentを取得する(SPEのLSから)
  書き込み専用の場合、dma_loadは必要ないので
  こういう感じになるのかな.

  @param [addr] Main Memory のアドレス
  @param [m]    Mem List
  @return allocate した領域のポインタ
  memory directory にあるべきだが...

*/

MemorySegment *
Scheduler::get_free_segment(memaddr addr, MemList *m)
{


    if(addr == NULL) {
        return NULL;
    }

    MemorySegment *s = m->getLast();
    m->moveToFirst(s);
    s->tag = connector->get_tag();
    s->address = addr;

    return s;

}

/*!

  指定した MemorySegment を上書きする

  @param [s]     上書きするMemorySegment
  @param [addr]  上書きするdataへのアドレス

*/

void
Scheduler::overwrite_segment(MemorySegment *s, memaddr addr)
{

    if(addr == NULL) {
        return;
    }

    s->address = addr;
    s->data = connector->dma_load1(s->data, addr, s->size, s->tag);

}


int
Scheduler::max_cpu()
{ // todo
    return maxcpu-1;
}

int
Scheduler::min_cpu()
{ // todo
    return mincpu;
}

MemorySegment *
Scheduler::get_segment(memaddr addr, MemList *m, int size)
{

    // memory segment のsizeをoverride する場合がある
    MemorySegment *s = hash->get(addr);

    if (s) {

        /* 既に load されている */
        // this->printf("get_segement loaded %llx 0x%x size 0x%d\n",addr,s->data,size);
        m->moveToFirst(s);
        return s;
    }


    /* LRU なので、もっとも使われてない segment を上書きする */
    s = m->getLast();
    m->moveToFirst(s);

    memaddr old_addr = s->address;
    s->tag = connector->get_tag();
    s->data = connector->dma_load1(s->data, addr, size, s->tag);
    /* 前のをhashから削除 */
    hash->remove(old_addr);
    /* 新しいaddress を登録 */
    s->address = addr;
    hash->put(s->address, s);

    // this->printf("get_segement %llx 0x%x size 0x%d\n",addr, s->data,size);

    return s;
}



/*!

  Main Memory のSegmentを書き出す
  Segment は get_segement されていて、
  追い出されていてはいけない。
  それを保証するのは難しい?

  @param [addr] Main Memory のアドレス
  @param [m]    Mem List
  @return allocate した領域のポインタ

*/
void
Scheduler::put_segment(MemorySegment *s)
{

    if (s == NULL) return;
    s->tag = connector->get_tag();
    connector->dma_store(s->data, s->address, s->size, s->tag);
}

/*!

  Main Memory のSegmentを読込、書き出しを待つ

  @param [id]    MemorySegment のid

*/
void
Scheduler::wait_segment(MemorySegment *s)
{
    if (s == NULL) return;
    if (s->tag) connector->dma_wait(s->tag);
    s->tag = 0;
}

long Scheduler::get_random() {
#if defined(__SPU__)
    return 0;
#else
    return random();
#endif

}

int
Scheduler::printf(const char * format, ...)
{
#if !defined(__SPU__) || 1
    va_list ap;
    va_start(ap,format);
    int ret= vprintf0(format, ap);
    va_end(ap);
    return ret;
#else
    return 0;
#endif
}

int
Scheduler::vprintf0(const char * format, va_list ap)
{
#if !defined(__SPU__) || 1
    int ret= vprintf(format, ap);
    return ret;
#else
    return 0;
#endif
}

/* end */