nvmain源码阅读记录4

关于迁移

其他人的介绍:http://www.voidcn.com/article/p-txgoagur-xp.html

在每次IssueCommand的时候,都会在之前执行preHooks,之后执行postHooks。

【注意】

在GetChild( request )->IssueCommand( request );中,GetChild函数返回的是一个NVMObject_hook,而不是NVMObject;所以其实是先调用的NVMObjest.cpp的bool NVMObject_hook::IssueCommand( NVMainRequest *req )函数,该函数中先调用了preohooks,然后调用rv = trampoline->IssueCommand( req ); (trampoline即为该hook链接的对应NVMObject)这才调用了NVMObject的IssueCommand函数

 

CoinMigrator是一个回调类。而且既是prehooks也是posthooks.

首先会检查CoinMigrator的parent是不是nvmain。然后检查translator是Migrator。

1. 如果是prehook而且migratorTranslator->IsBuffered( request->address )也就是说【请求的这个块】已经存在buffer中。那么此时返回false.

在回到NVMObject_hook::IssueCommand中时,就【不会将命令发射下去】,也就是这个命令在这里停止了,不再Issue,直接返回buffer的结果。

bool NVMObject_hook::IssueCommand( NVMainRequest *req )
{
    bool rv = true, dropRequest = false;
    std::vector<NVMObject *>& preHooks  = trampoline->GetHooks( NVMHOOK_PREISSUE );
    std::vector<NVMObject *>& postHooks = trampoline->GetHooks( NVMHOOK_POSTISSUE );
    std::vector<NVMObject *>::iterator it;

    /* Call pre-issue hooks */
    for( it = preHooks.begin(); it != preHooks.end(); it++ )
    {
        (*it)->SetParent( trampoline );
        (*it)->SetCurrentHookType( NVMHOOK_PREISSUE );
        dropRequest = !(*it)->IssueCommand( req );
        (*it)->UnsetParent( );
    }

    /* Call IssueCommand. */
    if( !dropRequest )
        rv = trampoline->IssueCommand( req );

    /* Call post-issue hooks. */
    for( it = postHooks.begin(); it != postHooks.end(); it++ )
    {
        (*it)->SetParent( trampoline );
        (*it)->SetCurrentHookType( NVMHOOK_POSTISSUE );
        (*it)->IssueCommand( req );
        (*it)->UnsetParent( );
    }

    return rv;
}

2. 如果是prehook但是请求的块没有被缓冲,则返回true。正常继续执行。

        /* Migrations in progress must be served from the buffers during migration. */
        if( GetCurrentHookType( ) == NVMHOOK_PREISSUE && migratorTranslator->IsBuffered( request->address ) )
        {
            /* Short circuit this request so it is not queued. */
            rv = false;

            /* Complete the request, adding some buffer read latency. */
            GetEventQueue( )->InsertEvent( EventResponse, parent->GetTrampoline( ), request,
                              GetEventQueue()->GetCurrentCycle()+bufferReadLatency );

            bufferedReads++;

            return rv;
        }

        /* Don't inject results before the original is issued to prevent deadlock */
        if( GetCurrentHookType( ) != NVMHOOK_POSTISSUE )
        {
            return rv;
        }

3. 如果是posthook的情况,首先检查是否能够实现migrate, 这里首先要用到Migrator类,这是一个做地址变换的类,它里面存储了一些迁移相关的信息,先检查是否正在迁移,然后检查当前请求是否已经被迁移过了。然后保证请求的地址的通道不是promotionChannel【promotionChannel在配置文件中静态设置了】。

如果满足以上条件,则首先按照概率【决定是否迁移】,

首先promotee的地址是请求的地址,然后通过ChooseVictim函数【选择要替换的行】。

然后检查如果选择出的地址和要替换的地址都没有被迁移过,并且可以发射【CheckIssuable】,

 

具体的迁移由Migrator::StartMigration( NVMAddress& promotee, NVMAddress& demotee )完成,这个函数有两个输入,一个是promotee,另一个是demotee,迁移的目的是将内存行从慢速内存移动到快速内存中,promotee是在慢速内存中要迁移的地址,demotee是在快速内存中要被替换的地址。

 

添加hook,在CreateHook中,确认是哪个hook(配置文件最后AddHook配置为CoinMigrator)

NVMObject *HookFactory::CreateHook( std::string hookName )
{
    NVMObject *hook = NULL;

    if( hookName == "Visualizer" ) hook = new Visualizer( );
    else if( hookName == "PostTrace" ) hook = new PostTrace( );
    else if( hookName == "CoinMigrator" ) hook = new CoinMigrator( );
    //else if( hookName == "MyHook" ) hook = new MyHook( );

    if( hook != NULL )
        hook->StatName( hookName );

    return hook;
}

Migrator.cpp中函数进行一些迁移状态的判断(在CoinMigrator中被调用),还有地址翻译(迁移之后改变了,需要重新translate)

注意迁移不是立即迁移过去,而是需要IssueCommand进行读写,同时只可以有一个迁移操作在进行

CoinMigrator中两个重要函数:

TryMigration决定是否进行迁移以及被替换的page,若确认要迁移,对要交换的两个page发出读指令;

RequestComplete确认两个page都已经在交换buffer中后,发出写指令

以上两个函数均会调用Migrator.cpp中函数【确认/修改迁移状态】

先初始化查找牺牲页的一些信息(可替换的总数,如注释,可得到page count,再通过循环遍历所有fast memory的page依次进行替换) totalPromotionPages = p->RANKS * p->BANKS * p->ROWS;为重点;已获取后,每次需要选择victim page就直接选当前的,并指向下一个page,下次选下一个

void CoinMigrator::ChooseVictim( Migrator *at, NVMAddress& /*promotee*/, NVMAddress& victim )
{
    /*
     *  Since this is no method called after every module in the system is 
     *  initialized, we check here to see if we have queried the memory system
     *  about the information we need.
     */
    if( !queriedMemory )
    {
        /*
         *  Our naive replacement policy will simply circle through all the pages
         *  in the fast memory. In order to count the pages we need to count the
         *  number of rows in the fast memory channel. We do this by creating a
         *  dummy request which would route to the fast memory channel. From this
         *  we can grab it's config pointer and calculate the page count.
         */
        NVMainRequest queryRequest;

        queryRequest.address.SetTranslatedAddress( 0, 0, 0, 0, promotionChannel, 0 );
        queryRequest.address.SetPhysicalAddress( 0 );
        queryRequest.type = READ;
        queryRequest.owner = this;

        NVMObject *curObject = NULL;
        FindModuleChildType( &queryRequest, SubArray, curObject, parent->GetTrampoline( ) );

        SubArray *promotionChannelSubarray = NULL;
        promotionChannelSubarray = dynamic_cast<SubArray *>( curObject );

        assert( promotionChannelSubarray != NULL );
        Params *p = promotionChannelSubarray->GetParams( );
        promotionChannelParams = p;

        totalPromotionPages = p->RANKS * p->BANKS * p->ROWS;
        currentPromotionPage = 0;

        if( p->COLS != numCols )
        {
            std::cout << "Warning: Page size of fast and slow memory differs." << std::endl;
        }

        queriedMemory = true;
    }

    /*
     *  From the current promotion page, simply craft some translated address together
     *  as the victim address.
     */
    uint64_t victimRank, victimBank, victimRow, victimSubarray, subarrayCount;
    ncounter_t promoPage = currentPromotionPage;

    victimRank = promoPage % promotionChannelParams->RANKS;
    promoPage >>= NVM::mlog2( promotionChannelParams->RANKS );

    victimBank = promoPage % promotionChannelParams->BANKS;
    promoPage >>= NVM::mlog2( promotionChannelParams->BANKS );

    subarrayCount = promotionChannelParams->ROWS / promotionChannelParams->MATHeight;
    victimSubarray = promoPage % subarrayCount;
    promoPage >>= NVM::mlog2( subarrayCount );

    victimRow = promoPage;

    victim.SetTranslatedAddress( victimRow, 0, victimBank, victimRank, promotionChannel, victimSubarray );
    uint64_t victimAddress = at->ReverseTranslate( victimRow, 0, victimBank, victimRank, promotionChannel, victimSubarray );
    victim.SetPhysicalAddress( victimAddress );

    currentPromotionPage = (currentPromotionPage + 1) % totalPromotionPages;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值