FlipNwrite代碼解析

#include "DataEncoders/FlipNWrite/FlipNWrite.h"

#include <iostream>

using namespace NVM;

FlipNWrite::FlipNWrite( )
{
    flippedAddresses.clear( );

    /* Clear statistics */
    bitsFlipped = 0;
    bitCompareSwapWrites = 0;
}

FlipNWrite::~FlipNWrite( )
{
    /*
     *  Nothing to do here. We do not own the *config pointer, so
     *  don't delete that.
     */
}

void FlipNWrite::SetConfig( Config *config, bool /*createChildren*/ )
{
    Params *params = new Params( );
    params->SetParams( config );
    SetParams( params );

    /* Cache granularity size. */
    fpSize = config->GetValue( "FlipNWriteGranularity" );
//設置flipNWrite的粒度,論文中默認設置的就是一個word爲32bit
    /* Some default size if the parameter is not specified */
    if( fpSize == -1 )
        fpSize = 32; 
}

void FlipNWrite::RegisterStats( )
{
    AddStat(bitsFlipped);
    AddStat(bitCompareSwapWrites);
    AddUnitStat(flipNWriteReduction, "%");
}
//用來把一個byte前後翻轉且01翻轉
void FlipNWrite::InvertData( NVMDataBlock& data, uint64_t startBit, uint64_t endBit )
{
    uint64_t wordSize;
    int startByte, endByte;

    wordSize = p->BusWidth;
    wordSize *= p->tBURST * p->RATE;
    wordSize /= 8;
//wordSize以Byte爲單位,表示一次burst的數據量
    startByte = (int)(startBit / 8);
    endByte = (int)((endBit - 1) / 8);

    for( int i = startByte; i <= endByte; i++ )
    {
    //對於每個byte來說
        uint8_t originalByte = data.GetByte( i );
        uint8_t shiftByte = originalByte;
        uint8_t newByte = 0;

        for( int j = 0; j < 8; j++ )
        {
            uint64_t currentBit = i * 8 + j;
           
            if( currentBit < startBit || currentBit >= endBit )
            {
                shiftByte = static_cast<uint8_t>(shiftByte >> 1);
                continue;
            }
//如果shiftbyte第7-j個bit爲0,newbyte第j個bit爲1
            if( !(shiftByte & 0x1) )
            {
                newByte = static_cast<uint8_t>(newByte | (1 << (7-j)));
            }

            shiftByte = static_cast<uint8_t>(shiftByte >> 1);
        }

        data.SetByte( i, newByte );
    }
}

ncycle_t FlipNWrite::Read( NVMainRequest* /*request*/ )
{
    ncycle_t rv = 0;

    // TODO: Add some energy here

    return rv;
}

ncycle_t FlipNWrite::Write( NVMainRequest *request ) 
{
    NVMDataBlock& newData = request->data;
    NVMDataBlock& oldData = request->oldData;
    NVMAddress address = request->address;

    /*
     *  The default life map is an stl map< uint64_t, uint64_t >. 
     *  You may map row and col to this map_key however you want.
     *  It is up to you to ensure there are no collisions here.
     */
    uint64_t row;
    uint64_t col;
    ncycle_t rv = 0;

    request->address.GetTranslatedAddress( &row, &col, NULL, NULL, NULL, NULL );

    /*
     *  If using the default life map, we can call the DecrementLife
     *  function which will check if the map_key already exists. If so,
     *  the life value is decremented (write count incremented). Otherwise 
     *  the map_key is inserted with a write count of 1.
     */
    uint64_t rowSize;
    uint64_t wordSize;
    uint64_t currentBit;
    uint64_t flipPartitions;
    uint64_t rowPartitions;
    int *modifyCount;

    wordSize = p->BusWidth;
    wordSize *= p->tBURST * p->RATE;
    wordSize /= 8;
//一次會來總線寬度*burst*rate/8 個byte
//rowsize是一行的byte數
    rowSize = p->COLS * wordSize;
    rowPartitions = ( rowSize * 8 ) / fpSize;
    //flipPartitions即爲可以分爲多少個fpSize大小的word
    //也就是一個wordsize可以分爲幾個fpsize
    flipPartitions = ( wordSize * 8 ) / fpSize; 

    modifyCount = new int[ flipPartitions ];

    /*
     *  Count the number of bits that are modified. If it is more than
     *  half, then we will invert the data then write.
     */
    for( uint64_t i = 0; i < flipPartitions; i++ )
        modifyCount[i] = 0;

    currentBit = 0;

    /* Get what is currently in the memory (i.e., if it was previously flipped, get the flipped data. */
    for( uint64_t i = 0; i < flipPartitions; i++ )
    {
    //實際情況是這樣的 我們一個req,會有wordsize個byte等待處理,fpsize處理一個,總共處理flippartition個
        uint64_t curAddr = row * rowPartitions + col * flipPartitions + i;
//如果在翻轉地址中找到了當前地址,翻轉回來
        if( flippedAddresses.count( curAddr ) )
        {
            InvertData( oldData, i*fpSize, (i+1)*fpSize );
        }
    }

    /* Check each byte to see if it was modified */
    for( uint64_t i = 0; i < wordSize; ++i )
    {
        /*
         *  If no bytes have changed we can just continue. Yes, I know this
         *  will check the byte 8 times, but i'd rather not change the iter.
         */
        uint8_t oldByte, newByte;

        oldByte = oldData.GetByte( i );
        newByte = newData.GetByte( i );
//對於某個byte,如果新舊一樣,currentbit+8
        if( oldByte == newByte )
        {
            currentBit += 8;
            continue;
        }

        /*
         *  If the bytes are different, then at least one bit has changed.
         *  check each bit individually.
         */
        for( int j = 0; j < 8; j++ )
        {
            uint8_t oldBit, newBit;

            oldBit = ( oldByte >> j ) & 0x1;
            newBit = ( newByte >> j ) & 0x1;
//由於這個modifycount數組有wordsize*8/fpsize (也就是flippatrion個)
//若有不相等則對應modify++,代表這個fpsize是修改過的
            if( oldBit != newBit )
            {
                modifyCount[(int)(currentBit/fpSize)]++;
            }

            currentBit++;
        }
    }

    /*
     *  Flip any partitions as needed and mark them as inverted or not.
     */
    for( uint64_t i = 0; i < flipPartitions; i++ )
    {
        bitCompareSwapWrites += modifyCount[i];
//bitCompareSwapWrites 是所有需要改變的bit的數量總和
        uint64_t curAddr = row * rowPartitions + col * flipPartitions + i;

        /* Invert if more than half of the bits are modified. */
        //對於每個fpsize來說,如果其中改變位數超過一半就翻轉
        if( modifyCount[i] > (fpSize / 2) )
        {
            InvertData( newData, i*fpSize, (i+1)*fpSize );

            bitsFlipped += (fpSize - modifyCount[i]);
//bitsFlipped 代表實際翻轉的位數
            /*
             *  Mark this address as flipped. If the data was already inverted, it
             *  should remain as inverted for the new data.
             */
            if( !flippedAddresses.count( curAddr ) )
            {
                flippedAddresses.insert( curAddr );
            }
        }
        else
        {
            /*
             *  This data is not inverted and should not be marked as such.
             */
             //如果不到一半,就正常寫
            if( flippedAddresses.count( curAddr ) )
            {
                flippedAddresses.erase( curAddr );
            }

            bitsFlipped += modifyCount[i];
        }
    }

    delete modifyCount;
    
    return rv;
}

void FlipNWrite::CalculateStats( )
{
    if( bitCompareSwapWrites != 0 )
        flipNWriteReduction = (((double)bitsFlipped / (double)bitCompareSwapWrites)*100.0);
    else
        flipNWriteReduction = 100.0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章