Hello All, I was running some experiments and I ran into a problem with ruby where a functional read was failing. After some investigation I found that the reason was that the functional read was trying to read a line that was in a MaybeStale state (no ReadOnly or ReadWrite versions).
I implemented a fix which so far seems to be working fine but I am not sure if there is a deeper problem that needs fixing or if my fix could present future problems. I am running Full System simulations with ARM ISA and MESI_Three_Level. Here is my fix (I have marked new lines with //------NEW------//): Basically what this fix does is perform the functional read from the controller that has the line in the MaybeStale state if no ReadOnly or ReadWrite versions in any controller. bool RubySystem::functionalRead(PacketPtr pkt) { Addr address(pkt->getAddr()); Addr line_address = makeLineAddress(address); AccessPermission access_perm = AccessPermission_NotPresent; int num_controllers = m_abs_cntrl_vec.size(); DPRINTF(RubySystem, "Functional Read request for %#x\n", address); unsigned int num_ro = 0; unsigned int num_rw = 0; unsigned int num_busy = 0; unsigned int num_backing_store = 0; unsigned int num_invalid = 0; unsigned int num_maybe_stale = 0; //------NEW------// // In this loop we count the number of controllers that have the given // address in read only, read write and busy states. for (unsigned int i = 0; i < num_controllers; ++i) { // Ignore ATD controllers for functional reads if (m_abs_cntrl_vec[i]->getType() == MachineType_ATD) { continue; } access_perm = m_abs_cntrl_vec[i]-> getAccessPermission(line_address); if (access_perm == AccessPermission_Read_Only) num_ro++; else if (access_perm == AccessPermission_Read_Write) num_rw++; else if (access_perm == AccessPermission_Busy) num_busy++; else if (access_perm == AccessPermission_Backing_Store) // See RubySlicc_Exports.sm for details, but Backing_Store is meant // to represent blocks in memory *for Broadcast/Snooping protocols*, // where memory has no idea whether it has an exclusive copy of data // or not. num_backing_store++; else if (access_perm == AccessPermission_Invalid || access_perm == AccessPermission_NotPresent) num_invalid++; else if (access_perm == AccessPermission_Maybe_Stale) //------NEW------// num_maybe_stale++; //------NEW------// } // This if case is meant to capture what happens in a Broadcast/Snoop // protocol where the block does not exist in the cache hierarchy. You // only want to read from the Backing_Store memory if there is no copy in // the cache hierarchy, otherwise you want to try to read the RO or RW // copies existing in the cache hierarchy (covered by the else statement). // The reason is because the Backing_Store memory could easily be stale, if // there are copies floating around the cache hierarchy, so you want to read // it only if it's not in the cache hierarchy at all. if (num_invalid == (num_controllers - 1) && num_backing_store == 1) { DPRINTF(RubySystem, "only copy in Backing_Store memory, read from it\n"); for (unsigned int i = 0; i < num_controllers; ++i) { access_perm = m_abs_cntrl_vec[i]->getAccessPermission(line_address); if (access_perm == AccessPermission_Backing_Store) { m_abs_cntrl_vec[i]->functionalRead(line_address, pkt); return true; } } } else if (num_ro > 0 || num_rw >= 1 || num_maybe_stale > 0) { //------NEW------// if (num_rw > 1) { // We iterate over the vector of abstract controllers, and return // the first copy found. If we have more than one cache with block // in writable permission, the first one found would be returned. warn("More than one Abstract Controller with RW permission for " "addr: %#x on cacheline: %#x.", address, line_address); } // In Broadcast/Snoop protocols, this covers if you know the block // exists somewhere in the caching hierarchy, then you want to read any // valid RO or RW block. In directory protocols, same thing, you want // to read any valid readable copy of the block. DPRINTF(RubySystem, "num_busy = %d, num_ro = %d, num_rw = %d\n", num_busy, num_ro, num_rw); // In this loop, we try to figure which controller has a read only or // a read write copy of the given address. Any valid copy would suffice // for a functional read. // Sometimes the functional read is to a line that has recently // transitioned to MaybeStale state and no other controller has it in // a ReadOnly or ReadWrite stat yet. // For example in MESI_Three_Level a modified block in the L2 goes into // a MaybeStale state when requested by the L1. If the functional read // occurs at that specific time when the block in L2 became MaybeStale // but still hasn't made it to ReadOnly on ReadWrite state in the L1, // the request should then be fulfilled from the L2 controller. // (I think so) // In case no ReadOnly or ReadWrite controller was found, this will // point to the MaybeStale controller AbstractController* func_read_cntrl = NULL; //------NEW------// for (unsigned int i = 0;i < num_controllers;++i) { access_perm = m_abs_cntrl_vec[i]-> getAccessPermission(line_address); if (access_perm == AccessPermission_Read_Only || access_perm == AccessPermission_Read_Write) { m_abs_cntrl_vec[i]->functionalRead(line_address, pkt); return true; } // Record the first MaybeStale controller in case no ReadOnly or // ReadWrite controller was found if (access_perm == AccessPermission_Maybe_Stale && //------NEW------// func_read_cntrl == NULL) { //------NEW------// func_read_cntrl = m_abs_cntrl_vec[i]; //------NEW------// } //------NEW------// } // At this point no RO or RW controller was found, read from the // MaybeStale one if (func_read_cntrl != NULL) { //------NEW------// func_read_cntrl->functionalRead(line_address, pkt); //------NEW------// return true; //------NEW------// } //------NEW------// } return false; }
_______________________________________________ gem5-users mailing list gem5-users@gem5.org http://m5sim.org/cgi-bin/mailman/listinfo/gem5-users