DRAMSim2 icon indicating copy to clipboard operation
DRAMSim2 copied to clipboard

Row Buffer Miss

Open SunnyBeike opened this issue 12 years ago • 8 comments

Hi All, I used MARSSx86+DramSim2 to got the row buffer miss rate of test suites in PARSEC. But the result is too low to be true. I first added my code the these following methods. void MemoryController::update() void Rank::receiveFromBus(BusPacket *packet) The above two methos all update bankStates in a "switch" branch. But I think the update in Rank::receiveFromBus is not appropriate. Because in the real DRAM, it is the memory controller sends the essential commands, and only one time. So, why not do some optimization to " class Rank "? While, the bankStates updated in the MemoryController::update() method seems invalid... Finally, I collect the row buffer miss information in the Rank::receiveFromBus method like this:


####################################################################
    switch (packet->busPacketType)
    {
    case READ:
    /*
        Added by SunnyBeike
    */
            #ifdef SunnyBeike
                ++bankStates[packet->bank].READ_times[privilegeState];
                if(packet->row == bankStates[packet->bank].lastOpenRowAddress) 
                    ++bankStates[packet->bank].rowBufferHitTimes[privilegeState];
                else 
                    ++bankStates[packet->bank].rowBufferMissTimes[privilegeState];
                bankStates[packet->bank].lastOpenRowAddress = packet->row;

                    #endif
    /*
        The End
    */
        ...
      }
####################################################################

The lastOpenRowAddress is a new member I added to class BankState to record the last row that was active in the row buffer. I had also added some other members to class BankState, like rowBufferHitTimes , READ_times, WRITE_times... The code listed above was adde to busPacketType that is READ or RED_P or WRITE or WRITE_P.

So, can I get the right rowbuffer miss rate in the above way? Thanks for your attention!

SunnyBeike avatar Jan 10 '13 13:01 SunnyBeike

Are you using git? If so, would you mind posting a diff instead of freeform code? The github markup screwed up all the formatting in your post.

dramninjasUMD avatar Jan 11 '13 16:01 dramninjasUMD

Thanks for your reply. Sorry, I am not using git, but I think I can if necessary. While, I have to make sure that the optimization point I have proposed is correct. Because the reulst of my lab was quite different from my prediction.

SunnyBeike avatar Jan 14 '13 13:01 SunnyBeike

I actually realized that github let me edit your post and I added three backticks to mark your code as a code block so now it is much easier to read.

Just one question -- are you setting lastOpenRowAddress only after the first time a request (READ/WRITE) is issued to that row? Because if you set it immediately upon an activate, the first request will always be a row buffer hit, but I wouldn't really call that a row buffer hit since you haven't really saved anything by issuing the first request to the open row buffer. You may also try increasing your queue sizes to see if you can capture more locality to the row buffers in open page to see if your optimization does better in that case? (I'm just suggesting things blindly since I don't know what your proposed optimization is)

dramninjasUMD avatar Jan 14 '13 17:01 dramninjasUMD

Thanks. According to the DramSim2, before any READ/WRITE commands, an ACTIVE command will be handled. So, when the ACTIVE is handled, the lastOpenRowAddress will be updated:


void Rank::receiveFromBus(BusPacket *packet)
{
    switch (packet->busPacketType)
    {
    case READ:
    /*
        Added by SunnyBeike
    */
            #ifdef SunnyBeike
                ++bankStates[packet->bank].READ_times[privilegeState];
                if(packet->row == bankStates[packet->bank].lastOpenRowAddress) {
                    ++bankStates[packet->bank].rowBufferHitTimes[privilegeState];
                    ++bankStates[packet->bank].READ_hitTimes[privilegeState];
                }
                else {
                    ++bankStates[packet->bank].rowBufferMissTimes[privilegeState];
                }
                bankStates[packet->bank].lastOpenRowAddress = packet->row;

            #endif
    /*
        The End
    */
        //make sure a read is allowed
        ...
    case ACTIVATE:
        ...
        bankStates[packet->bank].currentBankState = RowActive;
        bankStates[packet->bank].nextActivate = currentClockCycle + tRC;
        /*
        *   Added by SunnyBeike
        * */
        #ifdef SunnyBeike
            ++bankStates[packet->bank].ACTIVE_times[privilegeState];
            bankStates[packet->bank].lastOpenRowAddress = bankStates[packet->bank].openRowAddress;
        #endif
        /*
         *  The End
         * */

        bankStates[packet->bank].openRowAddress = packet->row;

        ...
}

The row buffer hit information is collected in ACTIVE/ACTIVE_P/WRITE/WRITE_P command.

SunnyBeike avatar Jan 15 '13 00:01 SunnyBeike

But don't you think that will cause your "hit rate" to be artificially high since you're counting regular old transactions to open rows as row buffer hits?

dramninjasUMD avatar Jan 15 '13 00:01 dramninjasUMD

Thanks. The "old transactions" ? Sorry, but I can not understand.

//memory controller update
void MemoryController::update(){

            //now that we know there is room in the command queue, we can remove from the transaction queue
            transactionQueue.erase(transactionQueue.begin()+i);

            /*
                Modified by SunnyBeike
            */
            //create activate command to the row we just translated

            BusPacket *ACTcommand = new BusPacket(ACTIVATE, transaction->address,
                    newTransactionColumn, newTransactionRow, newTransactionRank,
                    newTransactionBank, 0, dramsim_log);

            //create read or write command and enqueue it
            BusPacketType bpType = transaction->getBusPacketType();

            BusPacket *command = new BusPacket(bpType, transaction->address,
                    newTransactionColumn, newTransactionRow, newTransactionRank,
                    newTransactionBank, transaction->data, dramsim_log);

            commandQueue.enqueue(ACTcommand);
            commandQueue.enqueue(command);
}

This code shows that after translating the requested row, the top transaction from the queue will be removed, and handled by two following BusPacket, one to ACTIVE the corresponding row, and the other is to READ/WRITE. And the BusPacket will also be in a queue. So, how does the "old transaction" come?

SunnyBeike avatar Jan 15 '13 00:01 SunnyBeike

Sorry, "regular old" doesn't mean "old" it just means like ... "plain".

Anyways, what I'm trying to say is that in your scheme every single request will count as a row buffer hit. In my mind the first request that goes to a row should not count as a row buffer hit since the row was opened specifically for that request.

in other words, this line: if(packet->row == bankStates[packet->bank].lastOpenRowAddress) will always be true.

What you really want to know is how many requests except the original request were sent to a row before it closed. Does that make sense?

dramninjasUMD avatar Jan 15 '13 01:01 dramninjasUMD

Thanks

if(packet->row == bankStates[packet->bank].lastOpenRowAddress)

This line will not always be true. After the ACTIVE command was processed, the lastOpenRowAddress had been set to the row address latest opened:

    case ACTIVATE:
        ...
        bankStates[packet->bank].currentBankState = RowActive;
        bankStates[packet->bank].nextActivate = currentClockCycle + tRC;
        /*
        *   Added by SunnyBeike
        * */
        #ifdef SunnyBeike
            ++bankStates[packet->bank].ACTIVE_times[privilegeState];
            bankStates[packet->bank].lastOpenRowAddress = bankStates[packet->bank].openRowAddress;  //THIS LINE WORKS
        #endif
        /*
         *  The End
         * */

        bankStates[packet->bank].openRowAddress = packet->row;

When the READ/WRITE BusPacket comes, this lastOpenRowAddress will be compared with the row this packet want to access:

    case READ:
    /*
        Added by SunnyBeike
    */
            #ifdef SunnyBeike
                ++bankStates[packet->bank].READ_times[privilegeState];
                if(packet->row == bankStates[packet->bank].lastOpenRowAddress) {
                    ++bankStates[packet->bank].rowBufferHitTimes[privilegeState];
                    ++bankStates[packet->bank].READ_hitTimes[privilegeState];
                }
                else {
                    ++bankStates[packet->bank].rowBufferMissTimes[privilegeState];
                }
                bankStates[packet->bank].lastOpenRowAddress = packet->row;

            #endif
    /*
        The End
    */

The result of my lab shows about 30%~80% row buffer hit rate, that depends on the bencmark I used. And I do want to know how many requests except the original request were sent to a row before it closed.

SunnyBeike avatar Jan 15 '13 01:01 SunnyBeike