mem-ruby: Fix possible dirty line loss in CHI when ReadShared hit on UD line (#791)
In case ReadShared hit on a UD line and there's no sharers, this chage
makes the downstream passes Dirty to the requestor whenever possible
even though it doesn't deallocate the line. This will make the requestor
to SD and the downstream to UD_RSD.
In the previous implementation, loosely exclusive intermediate cache can
cause loss of dirty data. Example error condition is as below.
Configurations
L2 cache: Roughly inclusive to L1 without back-invalidation
- dealloc_on_* = false
- dealloc_backinv_* = false
L3 cache: Roughly exclusive to L2 without back-invalidation
- alloc_on_readshared = tue
- alloc_on_readunique = false
- dealloc_on_shared = false
- dealloc_on_unique = true
- dealloc_backinv_* = false
- is_HN = false
LLC: Same clusivity as L3 except is_HN = true
For all caches, allow_SD = true and fwd_unique_on_readshared = false
Example problem sequence:
1. L1 sends ReadUnique then becomes UD. L2 is UC_RU. L3 and LLC are RU.
2. L1 evicts the line to L2 by WriteBackFull (UD_PD). L2 becomes UD.
3. L2 evicts the line to L3 using WriteBackFull (UD_PD). L3 becomes UD.
4. L1 reads the line with ReadShared which misses on L2.
5. L2 reads the line with ReadShared which hits on L3. L3 becomes UD_RSC
because it doesn't deallocate the line (dataToBeInvalid=false)
6. L3 evicts the line to LLC by WriteCleanFull (UD_PD) because L3
doesn't back-invalidate and still has sharer. The local cache line is
invalidated by Deallocate_CacheBlock. L3 becomes RUSC and LLC becomes
UD_RU.
7. When UD_RU is evicted at LLC, the UD_RU line is dropped expecting the
upstream to writeback, causing loss of dirty data
This commit is contained in:
@@ -2600,11 +2600,18 @@ action(Send_CompData, desc="") {
|
||||
bool is_rd_nsd := tbe.reqType == CHIRequestType:ReadNotSharedDirty;
|
||||
bool is_rd_unique := tbe.reqType == CHIRequestType:ReadUnique;
|
||||
|
||||
// if the config allows (or not caching the data) and line has no sharers
|
||||
bool snd_unique_on_rs := (fwd_unique_on_readshared || tbe.dataToBeInvalid)
|
||||
// Send UC/UD on ReadShared or ReadNotSharedDirty if the line has no sharers
|
||||
// and one of the followings are met
|
||||
// 1) the config allows or
|
||||
// 2) local cache won't have the line or
|
||||
// 3) Dirty will be passed but the request doesn't allow SD
|
||||
bool snd_unique_on_rs := (fwd_unique_on_readshared ||
|
||||
tbe.dataToBeInvalid ||
|
||||
(tbe.dataDirty && is_rd_nsd))
|
||||
&& tbe.dataUnique && tbe.dir_sharers.isEmpty();
|
||||
// if the request type allows and we won't be caching the data
|
||||
bool snd_dirty_on_rs := is_rd_shared && !is_rd_nsd && tbe.dataToBeInvalid;
|
||||
bool snd_dirty_on_rs := (is_rd_shared && !is_rd_nsd) &&
|
||||
!tbe.dir_ownerExists;
|
||||
|
||||
if (is_rd_once) {
|
||||
tbe.snd_msgType := CHIDataType:CompData_I;
|
||||
|
||||
@@ -767,7 +767,7 @@ transition({UD_RSC,SD_RSC}, Local_Eviction, BUSY_BLKD) {ReplTBEAvailable} {
|
||||
ProcessNextState;
|
||||
}
|
||||
|
||||
transition({UD_RSC,SD_RSC,UC_RSC,UD_RU,UC_RU,UD_RSD}, Global_Eviction, BUSY_BLKD) {ReplTBEAvailable} {
|
||||
transition({UD_RSC,SD_RSC,UC_RSC,UD_RU,UC_RU,UD_RSD,SD_RSD}, Global_Eviction, BUSY_BLKD) {ReplTBEAvailable} {
|
||||
Initiate_Replacement;
|
||||
Initiate_Replacement_WB_BackInvalidate;
|
||||
Profile_Eviction;
|
||||
|
||||
Reference in New Issue
Block a user