#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;
}
FlipNwrite代碼解析
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.