view TaskManager/kernel/schedule/Scheduler.cc @ 1015:80b18af207c2

debug mail timing.
author yutaka@localhost.localdomain
date Fri, 05 Nov 2010 22:25:33 +0900
parents c67379f9d411
children 19a57960c436
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];

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

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

static void null_loader(Scheduler *m, int task_id);

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

void
Scheduler::init(TaskManagerImpl *m)
{
    hash = 0;

    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;
    }

    set_manager(m);
    init_impl();

    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];
}

void
Scheduler::dma_load(void *buf, memaddr addr, uint32 size, uint32 mask)
{
    connector->dma_load(buf, addr, size, mask);
}

void
Scheduler::dma_store(void *buf, memaddr addr, uint32 size, uint32 mask)
{
    connector->dma_store(buf, addr, size, mask);
}

void
Scheduler::dma_wait(uint32 mask)
{
  //printf("%d\n",mask);
    connector->dma_wait(mask);
}

void
Scheduler::dma_wait(uint32 mask, int cmd)
{
    connector->dma_wait(mask,cmd);
}

void
Scheduler::dma_loadList(ListDataPtr list, void *buff, uint32 mask)
{
    connector->dma_loadList(list, buff, mask);
}


void
Scheduler::dma_storeList(ListDataPtr list, void *buff, uint32 mask)
{
    return connector->dma_storeList(list, buff, mask);
}

void
Scheduler::mail_write(memaddr data)
{
    connector->mail_write(data);
}

void
Scheduler::mail_write_queue(memaddr data)
{
    connector->mail_write_queue(data);
}

void
Scheduler::mail_write_finish_list(memaddr data)
{
    connector->mail_write_finish_list(data);
}

memaddr
Scheduler::mail_read()
{
    return connector->mail_read();
}



/*
    ここから下は、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 = (void*)(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
}

static 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)
{
    task_list[cmd].run = run;
    task_list[cmd].load = null_loader;
    task_list[cmd].wait = null_waiter;
}

extern void 
register_dynamic_task(int cmd, 
    memaddr start, int size,
    TaskObjectRun run, int entry_offset)
{
    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;
#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) 
{
    MemorySegment *s = m->getFirst();
    return get_segment(addr, m, s->size); 
}

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 = get_tag();
    dma_load(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;
}


uint32
Scheduler::get_tag()
{
    static int tag = 16;
    tag ++;
    tag &= 0x0f;
    return tag+16;
}

/*!

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

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

 */
void
Scheduler::put_segment(MemorySegment *s)
{
    dma_store(s->data, s->address,
                       s->size, s->tag);
}

/*!

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

  @param [id]    MemorySegment のid

 */
void
Scheduler::wait_segment(MemorySegment *s)
{
    // えーと、dma してない時には、skip しないとだめなんじゃないの?

    if (s->tag) 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 */