From e141d9e4d0bf4d9845cf1ce8a5d955363219bb87 Mon Sep 17 00:00:00 2001 From: Minje Jun Date: Sun, 21 Jan 2024 16:14:53 +0900 Subject: [PATCH 1/4] mem-ruby: Writeback CHI UD_RU line at local evict In Ruby CHI protocol UD_RU state means the line is in UD state in the local cache and the upstream may have it in UD or UC state. In the previous implementation UD_RU line was just dropped without WriteBack which can cause loss of dirty data when the upstream has it in UC state. This commit fixes it by performing WriteBack when evciting UD_RU line. Change-Id: I1db9b4f95cc576e71dcef38b01de24775df514ba --- src/mem/ruby/protocol/chi/CHI-cache-funcs.sm | 8 ++++---- src/mem/ruby/protocol/chi/CHI-cache-transitions.sm | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/mem/ruby/protocol/chi/CHI-cache-funcs.sm b/src/mem/ruby/protocol/chi/CHI-cache-funcs.sm index fbafda61cd..ccef1d8deb 100644 --- a/src/mem/ruby/protocol/chi/CHI-cache-funcs.sm +++ b/src/mem/ruby/protocol/chi/CHI-cache-funcs.sm @@ -892,10 +892,10 @@ void copyCacheAndDir(CacheEntry cache_entry, DirEntry dir_entry, if (is_valid(cache_entry) && ((initialState == State:UD) || (initialState == State:SD) || (initialState == State:UC) || (initialState == State:SC) || - (initialState == State:UD_RSC) || (initialState == State:SD_RSC) || - (initialState == State:UC_RSC) || (initialState == State:SC_RSC) || - (initialState == State:UD_RSD) || (initialState == State:SD_RSD) || - (initialState == State:UD_T))) { + (initialState == State:UD_RU) || (initialState == State:UD_RSC) || + (initialState == State:SD_RSC) || (initialState == State:UC_RSC) || + (initialState == State:SC_RSC) || (initialState == State:UD_RSD) || + (initialState == State:SD_RSD) || (initialState == State:UD_T))) { tbe.dataBlk := cache_entry.DataBlk; tbe.dataBlkValid.fillMask(); tbe.dataValid := true; diff --git a/src/mem/ruby/protocol/chi/CHI-cache-transitions.sm b/src/mem/ruby/protocol/chi/CHI-cache-transitions.sm index 31b5b0914a..b2cb419833 100644 --- a/src/mem/ruby/protocol/chi/CHI-cache-transitions.sm +++ b/src/mem/ruby/protocol/chi/CHI-cache-transitions.sm @@ -710,10 +710,10 @@ transition({UD_RSC, UC_RSC, SC_RSC, SD_RSC, UD, RU, RSD, RUSD, RUSC, UD_RSD, SD_ // Cache Replacement -// When in UD_RU,UC_RU,UD_RSD,SD_RSD we also just drop the line since an upstream +// When in UC_RU,UD_RSD,SD_RSD we also just drop the line since an upstream // cache has an up-to-data line that it will either WriteBack or WriteEvict transition({SC,UC,SC_RSC,UC_RSC, - UD_RU,UC_RU,UD_RSD,SD_RSD}, LocalHN_Eviction, BUSY_BLKD) {ReplTBEAvailable} { + UC_RU,UD_RSD,SD_RSD}, LocalHN_Eviction, BUSY_BLKD) {ReplTBEAvailable} { Initiate_Replacement; Initiate_Replacement_JustDrop; Profile_Eviction; @@ -722,7 +722,7 @@ transition({SC,UC,SC_RSC,UC_RSC, ProcessNextState; } -transition({UD,SD,UD_RSC,SD_RSC}, LocalHN_Eviction, BUSY_BLKD) {ReplTBEAvailable} { +transition({UD,SD,UD_RU,UD_RSC,SD_RSC}, LocalHN_Eviction, BUSY_BLKD) {ReplTBEAvailable} { Initiate_Replacement; Initiate_Replacement_WB; Profile_Eviction; @@ -749,7 +749,7 @@ transition({UD,SD,UC}, Local_Eviction, BUSY_BLKD) {ReplTBEAvailable} { ProcessNextState; } -transition({UD_RU,UC_RU,UD_RSD,SD_RSD,SC_RSC,UC_RSC}, Local_Eviction, BUSY_BLKD) {ReplTBEAvailable} { +transition({UC_RU,UD_RSD,SD_RSD,SC_RSC,UC_RSC}, Local_Eviction, BUSY_BLKD) {ReplTBEAvailable} { Initiate_Replacement; Initiate_Replacement_JustDrop; Profile_Eviction; @@ -758,7 +758,7 @@ transition({UD_RU,UC_RU,UD_RSD,SD_RSD,SC_RSC,UC_RSC}, Local_Eviction, BUSY_BLKD) ProcessNextState; } -transition({UD_RSC,SD_RSC}, Local_Eviction, BUSY_BLKD) {ReplTBEAvailable} { +transition({UD_RU,UD_RSC,SD_RSC}, Local_Eviction, BUSY_BLKD) {ReplTBEAvailable} { Initiate_Replacement; Initiate_Replacement_WB; Profile_Eviction; From 1b5d92ee9c00ed4efd4e3d098b316bc1aa30d4b2 Mon Sep 17 00:00:00 2001 From: Minje Jun Date: Wed, 31 Jan 2024 13:42:32 +0900 Subject: [PATCH 2/4] mem-ruby: Revert Writeback CHI UD_RU line at local evict This reverts commit d613d814a431525e122552a667eed653a057f2be. Change-Id: I50e218b7debf3a2836ce12515d8fcb6c0b38df53 --- src/mem/ruby/protocol/chi/CHI-cache-funcs.sm | 8 ++++---- src/mem/ruby/protocol/chi/CHI-cache-transitions.sm | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/mem/ruby/protocol/chi/CHI-cache-funcs.sm b/src/mem/ruby/protocol/chi/CHI-cache-funcs.sm index ccef1d8deb..fbafda61cd 100644 --- a/src/mem/ruby/protocol/chi/CHI-cache-funcs.sm +++ b/src/mem/ruby/protocol/chi/CHI-cache-funcs.sm @@ -892,10 +892,10 @@ void copyCacheAndDir(CacheEntry cache_entry, DirEntry dir_entry, if (is_valid(cache_entry) && ((initialState == State:UD) || (initialState == State:SD) || (initialState == State:UC) || (initialState == State:SC) || - (initialState == State:UD_RU) || (initialState == State:UD_RSC) || - (initialState == State:SD_RSC) || (initialState == State:UC_RSC) || - (initialState == State:SC_RSC) || (initialState == State:UD_RSD) || - (initialState == State:SD_RSD) || (initialState == State:UD_T))) { + (initialState == State:UD_RSC) || (initialState == State:SD_RSC) || + (initialState == State:UC_RSC) || (initialState == State:SC_RSC) || + (initialState == State:UD_RSD) || (initialState == State:SD_RSD) || + (initialState == State:UD_T))) { tbe.dataBlk := cache_entry.DataBlk; tbe.dataBlkValid.fillMask(); tbe.dataValid := true; diff --git a/src/mem/ruby/protocol/chi/CHI-cache-transitions.sm b/src/mem/ruby/protocol/chi/CHI-cache-transitions.sm index b2cb419833..31b5b0914a 100644 --- a/src/mem/ruby/protocol/chi/CHI-cache-transitions.sm +++ b/src/mem/ruby/protocol/chi/CHI-cache-transitions.sm @@ -710,10 +710,10 @@ transition({UD_RSC, UC_RSC, SC_RSC, SD_RSC, UD, RU, RSD, RUSD, RUSC, UD_RSD, SD_ // Cache Replacement -// When in UC_RU,UD_RSD,SD_RSD we also just drop the line since an upstream +// When in UD_RU,UC_RU,UD_RSD,SD_RSD we also just drop the line since an upstream // cache has an up-to-data line that it will either WriteBack or WriteEvict transition({SC,UC,SC_RSC,UC_RSC, - UC_RU,UD_RSD,SD_RSD}, LocalHN_Eviction, BUSY_BLKD) {ReplTBEAvailable} { + UD_RU,UC_RU,UD_RSD,SD_RSD}, LocalHN_Eviction, BUSY_BLKD) {ReplTBEAvailable} { Initiate_Replacement; Initiate_Replacement_JustDrop; Profile_Eviction; @@ -722,7 +722,7 @@ transition({SC,UC,SC_RSC,UC_RSC, ProcessNextState; } -transition({UD,SD,UD_RU,UD_RSC,SD_RSC}, LocalHN_Eviction, BUSY_BLKD) {ReplTBEAvailable} { +transition({UD,SD,UD_RSC,SD_RSC}, LocalHN_Eviction, BUSY_BLKD) {ReplTBEAvailable} { Initiate_Replacement; Initiate_Replacement_WB; Profile_Eviction; @@ -749,7 +749,7 @@ transition({UD,SD,UC}, Local_Eviction, BUSY_BLKD) {ReplTBEAvailable} { ProcessNextState; } -transition({UC_RU,UD_RSD,SD_RSD,SC_RSC,UC_RSC}, Local_Eviction, BUSY_BLKD) {ReplTBEAvailable} { +transition({UD_RU,UC_RU,UD_RSD,SD_RSD,SC_RSC,UC_RSC}, Local_Eviction, BUSY_BLKD) {ReplTBEAvailable} { Initiate_Replacement; Initiate_Replacement_JustDrop; Profile_Eviction; @@ -758,7 +758,7 @@ transition({UC_RU,UD_RSD,SD_RSD,SC_RSC,UC_RSC}, Local_Eviction, BUSY_BLKD) {Repl ProcessNextState; } -transition({UD_RU,UD_RSC,SD_RSC}, Local_Eviction, BUSY_BLKD) {ReplTBEAvailable} { +transition({UD_RSC,SD_RSC}, Local_Eviction, BUSY_BLKD) {ReplTBEAvailable} { Initiate_Replacement; Initiate_Replacement_WB; Profile_Eviction; From 628be390a0c52efbae3d8a3cc1c84be6184c6d44 Mon Sep 17 00:00:00 2001 From: Minje Jun Date: Wed, 31 Jan 2024 17:48:29 +0900 Subject: [PATCH 3/4] mem-ruby: Fix ReadShared hit handling on UD line In case ReadShared hit on a UD line and there's no sharers, this chage makes the downstream respond with Unique even though it doesn't deallocate the line. This will make the requestor to UD and the downstream to UD_RU. In the previous implementation, loosely exclusive intermediate cache can cause loss of dirty data. Example sequence 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. Change-Id: Ic9bee27f2ec8906dd5df8bd3be60e5a9a76c782f --- src/mem/ruby/protocol/chi/CHI-cache-actions.sm | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/mem/ruby/protocol/chi/CHI-cache-actions.sm b/src/mem/ruby/protocol/chi/CHI-cache-actions.sm index 34358050cf..eb54d01053 100644 --- a/src/mem/ruby/protocol/chi/CHI-cache-actions.sm +++ b/src/mem/ruby/protocol/chi/CHI-cache-actions.sm @@ -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) + // if the request type allows SD + bool snd_dirty_on_rs := is_rd_shared && !is_rd_nsd; + + // 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 + bool snd_unique_on_rs := (fwd_unique_on_readshared || + tbe.dataToBeInvalid || + snd_dirty_on_rs) && 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; if (is_rd_once) { tbe.snd_msgType := CHIDataType:CompData_I; From db5c71a919a67ff97c996a5b398828a407550bf2 Mon Sep 17 00:00:00 2001 From: Minje Jun Date: Tue, 6 Feb 2024 16:03:11 +0900 Subject: [PATCH 4/4] mem-ruby: Pass UD on ReadShared hit only if SD is not allowed This commit allows CompData_SD be sent when ReadShared hits on UD line and the local cache keeps the line, unless the request doesn't allow SD. Change-Id: I337f24c871cc4c19c5b5fb11f9b35c0a8eb7911c --- src/mem/ruby/protocol/chi/CHI-cache-actions.sm | 10 +++++----- src/mem/ruby/protocol/chi/CHI-cache-transitions.sm | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mem/ruby/protocol/chi/CHI-cache-actions.sm b/src/mem/ruby/protocol/chi/CHI-cache-actions.sm index eb54d01053..6123a6c70d 100644 --- a/src/mem/ruby/protocol/chi/CHI-cache-actions.sm +++ b/src/mem/ruby/protocol/chi/CHI-cache-actions.sm @@ -2600,18 +2600,18 @@ action(Send_CompData, desc="") { bool is_rd_nsd := tbe.reqType == CHIRequestType:ReadNotSharedDirty; bool is_rd_unique := tbe.reqType == CHIRequestType:ReadUnique; - // if the request type allows SD - bool snd_dirty_on_rs := is_rd_shared && !is_rd_nsd; - // 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 + // 3) Dirty will be passed but the request doesn't allow SD bool snd_unique_on_rs := (fwd_unique_on_readshared || tbe.dataToBeInvalid || - snd_dirty_on_rs) + (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.dir_ownerExists; if (is_rd_once) { tbe.snd_msgType := CHIDataType:CompData_I; diff --git a/src/mem/ruby/protocol/chi/CHI-cache-transitions.sm b/src/mem/ruby/protocol/chi/CHI-cache-transitions.sm index 31b5b0914a..9aaee236ac 100644 --- a/src/mem/ruby/protocol/chi/CHI-cache-transitions.sm +++ b/src/mem/ruby/protocol/chi/CHI-cache-transitions.sm @@ -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;