From 7c3a719cabd6266ee826d4ad04eb4f3b59d21596 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Thu, 20 Feb 2025 13:28:57 +0000 Subject: [PATCH 01/42] i7291: support large pages in TLB Changed `block_size` to `long int` in order to allow larger pages in TLB. Also added two minor fixes that came up while working on the feature: - Argument name mismatches in `cache_lru_t` and `cache_fifo_t` between the header and body. - Clearer error messages in `tlb_simulator_t`, so you can know exactly what failed to build. Fixes #7291 --- clients/drcachesim/common/utils.h | 17 ++++++-------- clients/drcachesim/simulator/cache.cpp | 8 +++---- clients/drcachesim/simulator/cache.h | 2 +- clients/drcachesim/simulator/cache_fifo.cpp | 2 +- clients/drcachesim/simulator/cache_fifo.h | 5 ++--- clients/drcachesim/simulator/cache_lru.cpp | 2 +- clients/drcachesim/simulator/cache_lru.h | 5 ++--- .../drcachesim/simulator/caching_device.cpp | 4 ++-- clients/drcachesim/simulator/caching_device.h | 14 +++++++----- .../drcachesim/simulator/tlb_simulator.cpp | 22 ++++++++++++++----- 10 files changed, 46 insertions(+), 35 deletions(-) diff --git a/clients/drcachesim/common/utils.h b/clients/drcachesim/common/utils.h index df5670703bd..02a6d2953f6 100644 --- a/clients/drcachesim/common/utils.h +++ b/clients/drcachesim/common/utils.h @@ -146,16 +146,13 @@ namespace drmemtrace { # define IF_UNIX(x) x #endif -static inline int -compute_log2(int value) -{ - int i; - for (i = 0; i < 31; i++) { - if (value == 1 << i) - return i; - } - // returns -1 if value is not a power of 2. - return -1; +static inline int compute_log2(long int value) { + int i; + for (i = 0; i < 63; i++) { + if (value == 1l << i) return i; + } + // returns -1 if value is not a power of 2. + return -1; } template diff --git a/clients/drcachesim/simulator/cache.cpp b/clients/drcachesim/simulator/cache.cpp index bf453412c58..268410ddefa 100644 --- a/clients/drcachesim/simulator/cache.cpp +++ b/clients/drcachesim/simulator/cache.cpp @@ -52,10 +52,10 @@ namespace drmemtrace { class snoop_filter_t; bool -cache_t::init(int associativity, int line_size, int total_size, caching_device_t *parent, - caching_device_stats_t *stats, prefetcher_t *prefetcher, - cache_inclusion_policy_t inclusion_policy, bool coherent_cache, int id, - snoop_filter_t *snoop_filter, +cache_t::init(int associativity, long int line_size, int total_size, + caching_device_t *parent, caching_device_stats_t *stats, + prefetcher_t *prefetcher, cache_inclusion_policy_t inclusion_policy, + bool coherent_cache, int id, snoop_filter_t *snoop_filter, const std::vector &children) { // Check line_size to avoid divide-by-0. diff --git a/clients/drcachesim/simulator/cache.h b/clients/drcachesim/simulator/cache.h index 10a79038654..ecfe08b4b9a 100644 --- a/clients/drcachesim/simulator/cache.h +++ b/clients/drcachesim/simulator/cache.h @@ -61,7 +61,7 @@ class cache_t : public caching_device_t { // The id is an index into the snoop filter's array of caches for coherent caches. // If this is a coherent cache, id should be in the range [0,num_snooped_caches). bool - init(int associativity, int line_size, int total_size, caching_device_t *parent, + init(int associativity, long int line_size, int total_size, caching_device_t *parent, caching_device_stats_t *stats, prefetcher_t *prefetcher = nullptr, cache_inclusion_policy_t inclusion_policy = cache_inclusion_policy_t::NON_INC_NON_EXC, diff --git a/clients/drcachesim/simulator/cache_fifo.cpp b/clients/drcachesim/simulator/cache_fifo.cpp index 0ee070e4f9c..d172be47c9c 100644 --- a/clients/drcachesim/simulator/cache_fifo.cpp +++ b/clients/drcachesim/simulator/cache_fifo.cpp @@ -53,7 +53,7 @@ namespace drmemtrace { // be cleared. The counter of the next block will be set to 1. bool -cache_fifo_t::init(int associativity, int block_size, int total_size, +cache_fifo_t::init(int associativity, long int block_size, int total_size, caching_device_t *parent, caching_device_stats_t *stats, prefetcher_t *prefetcher, cache_inclusion_policy_t inclusion_policy, bool coherent_cache, int id, snoop_filter_t *snoop_filter, diff --git a/clients/drcachesim/simulator/cache_fifo.h b/clients/drcachesim/simulator/cache_fifo.h index b8e293c00d7..62939846bdd 100644 --- a/clients/drcachesim/simulator/cache_fifo.h +++ b/clients/drcachesim/simulator/cache_fifo.h @@ -54,12 +54,11 @@ class cache_fifo_t : public cache_t { { } bool - init(int associativity, int line_size, int total_size, caching_device_t *parent, + init(int associativity, long int block_size, int total_size, caching_device_t *parent, caching_device_stats_t *stats, prefetcher_t *prefetcher = nullptr, cache_inclusion_policy_t inclusion_policy = cache_inclusion_policy_t::NON_INC_NON_EXC, - bool coherent_cache = false, int id_ = -1, - snoop_filter_t *snoop_filter_ = nullptr, + bool coherent_cache = false, int id = -1, snoop_filter_t *snoop_filter = nullptr, const std::vector &children = {}) override; std::string diff --git a/clients/drcachesim/simulator/cache_lru.cpp b/clients/drcachesim/simulator/cache_lru.cpp index dcefb0016f0..6280874fe87 100644 --- a/clients/drcachesim/simulator/cache_lru.cpp +++ b/clients/drcachesim/simulator/cache_lru.cpp @@ -50,7 +50,7 @@ namespace drmemtrace { // highest counter value will be picked for replacement in replace_which_way. bool -cache_lru_t::init(int associativity, int block_size, int total_size, +cache_lru_t::init(int associativity, long int block_size, int total_size, caching_device_t *parent, caching_device_stats_t *stats, prefetcher_t *prefetcher, cache_inclusion_policy_t inclusion_policy, bool coherent_cache, int id, snoop_filter_t *snoop_filter, diff --git a/clients/drcachesim/simulator/cache_lru.h b/clients/drcachesim/simulator/cache_lru.h index e01b0f89888..2156c5c8e4a 100644 --- a/clients/drcachesim/simulator/cache_lru.h +++ b/clients/drcachesim/simulator/cache_lru.h @@ -53,12 +53,11 @@ class cache_lru_t : public cache_t { { } bool - init(int associativity, int line_size, int total_size, caching_device_t *parent, + init(int associativity, long int block_size, int total_size, caching_device_t *parent, caching_device_stats_t *stats, prefetcher_t *prefetcher = nullptr, cache_inclusion_policy_t inclusion_policy = cache_inclusion_policy_t::NON_INC_NON_EXC, - bool coherent_cache = false, int id_ = -1, - snoop_filter_t *snoop_filter_ = nullptr, + bool coherent_cache = false, int id = -1, snoop_filter_t *snoop_filter = nullptr, const std::vector &children = {}) override; std::string get_replace_policy() const override diff --git a/clients/drcachesim/simulator/caching_device.cpp b/clients/drcachesim/simulator/caching_device.cpp index 08482bd0f0b..309cd20a12c 100644 --- a/clients/drcachesim/simulator/caching_device.cpp +++ b/clients/drcachesim/simulator/caching_device.cpp @@ -41,9 +41,9 @@ #include #include -#include "memref.h" #include "caching_device_block.h" #include "caching_device_stats.h" +#include "memref.h" #include "prefetcher.h" #include "snoop_filter.h" #include "trace_entry.h" @@ -74,7 +74,7 @@ caching_device_t::~caching_device_t() } bool -caching_device_t::init(int associativity, int block_size, int num_blocks, +caching_device_t::init(int associativity, long int block_size, int num_blocks, caching_device_t *parent, caching_device_stats_t *stats, prefetcher_t *prefetcher, cache_inclusion_policy_t inclusion_policy, bool coherent_cache, diff --git a/clients/drcachesim/simulator/caching_device.h b/clients/drcachesim/simulator/caching_device.h index 876f9809c4f..462dcfbaf2c 100644 --- a/clients/drcachesim/simulator/caching_device.h +++ b/clients/drcachesim/simulator/caching_device.h @@ -63,12 +63,11 @@ class prefetcher_t; // NON_INC_NON_EXC = Non-Inclusive Non-Exclusive, aka NINE. enum class cache_inclusion_policy_t { NON_INC_NON_EXC, INCLUSIVE, EXCLUSIVE }; - class caching_device_t { public: explicit caching_device_t(const std::string &name = "caching_device"); virtual bool - init(int associativity, int block_size, int num_blocks, caching_device_t *parent, + init(int associativity, long int block_size, int num_blocks, caching_device_t *parent, caching_device_stats_t *stats, prefetcher_t *prefetcher = nullptr, cache_inclusion_policy_t inclusion_policy = cache_inclusion_policy_t::NON_INC_NON_EXC, @@ -110,6 +109,11 @@ class caching_device_t { { return parent_; } + void + set_parent(caching_device_t *parent) + { + parent_ = parent; + } inline double get_loaded_fraction() const { @@ -143,7 +147,7 @@ class caching_device_t { { return associativity_; } - virtual int + virtual long int get_block_size() const { return block_size_; @@ -245,8 +249,8 @@ class caching_device_t { init_blocks() = 0; int associativity_; - int block_size_; // Also known as line length. - int num_blocks_; // Total number of lines in cache = size / block_size. + long int block_size_; // Also known as line length. + int num_blocks_; // Total number of lines in cache = size / block_size. bool coherent_cache_; // This is an index into snoop filter's array of caches. int id_; diff --git a/clients/drcachesim/simulator/tlb_simulator.cpp b/clients/drcachesim/simulator/tlb_simulator.cpp index dc363896551..9566a75139a 100644 --- a/clients/drcachesim/simulator/tlb_simulator.cpp +++ b/clients/drcachesim/simulator/tlb_simulator.cpp @@ -115,15 +115,27 @@ tlb_simulator_t::tlb_simulator_t(const tlb_simulator_knobs_t &knobs) if (!itlbs_[i]->init(knobs_.TLB_L1I_assoc, (int)knobs_.page_size, knobs_.TLB_L1I_entries, lltlbs_[i], - new tlb_stats_t((int)knobs_.page_size)) || - !dtlbs_[i]->init(knobs_.TLB_L1D_assoc, (int)knobs_.page_size, + new tlb_stats_t((int)knobs_.page_size))) { + error_string_ = + "Usage error: failed to initialize itlbs_. Ensure entry number, " + "page size and associativity are powers of 2."; + success_ = false; + return; + } + if (!dtlbs_[i]->init(knobs_.TLB_L1D_assoc, (int)knobs_.page_size, knobs_.TLB_L1D_entries, lltlbs_[i], - new tlb_stats_t((int)knobs_.page_size)) || - !lltlbs_[i]->init(knobs_.TLB_L2_assoc, (int)knobs_.page_size, + new tlb_stats_t((int)knobs_.page_size))) { + error_string_ = + "Usage error: failed to initialize dtlbs_. Ensure entry number, " + "page size and associativity are powers of 2."; + success_ = false; + return; + } + if (!lltlbs_[i]->init(knobs_.TLB_L2_assoc, (int)knobs_.page_size, knobs_.TLB_L2_entries, NULL, new tlb_stats_t((int)knobs_.page_size))) { error_string_ = - "Usage error: failed to initialize TLbs_. Ensure entry number, " + "Usage error: failed to initialize lltlbs_. Ensure entry number, " "page size and associativity are powers of 2."; success_ = false; return; From a83b0bc18771a312d9bb41b213f41391bbe2d559 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Thu, 20 Feb 2025 13:36:04 +0000 Subject: [PATCH 02/42] fix format in utils.h --- clients/drcachesim/common/utils.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/clients/drcachesim/common/utils.h b/clients/drcachesim/common/utils.h index 02a6d2953f6..610c648d823 100644 --- a/clients/drcachesim/common/utils.h +++ b/clients/drcachesim/common/utils.h @@ -146,13 +146,16 @@ namespace drmemtrace { # define IF_UNIX(x) x #endif -static inline int compute_log2(long int value) { - int i; - for (i = 0; i < 63; i++) { - if (value == 1l << i) return i; - } - // returns -1 if value is not a power of 2. - return -1; +static inline int +compute_log2(long int value) +{ + int i; + for (i = 0; i < 63; i++) { + if (value == 1l << i) + return i; + } + // returns -1 if value is not a power of 2. + return -1; } template From f33094e81feee9b495c9a120965740fb81a92a9b Mon Sep 17 00:00:00 2001 From: Or Almer Date: Sun, 23 Feb 2025 15:29:24 +0000 Subject: [PATCH 03/42] CR fixes - change to int64_t and add release dox --- api/docs/release.dox | 2 ++ clients/drcachesim/common/utils.h | 2 +- clients/drcachesim/simulator/cache.cpp | 2 +- clients/drcachesim/simulator/cache.h | 2 +- clients/drcachesim/simulator/cache_fifo.cpp | 2 +- clients/drcachesim/simulator/cache_fifo.h | 2 +- clients/drcachesim/simulator/cache_lru.cpp | 2 +- clients/drcachesim/simulator/cache_lru.h | 2 +- clients/drcachesim/simulator/caching_device.cpp | 2 +- clients/drcachesim/simulator/caching_device.h | 6 +++--- 10 files changed, 13 insertions(+), 11 deletions(-) diff --git a/api/docs/release.dox b/api/docs/release.dox index 56760ee2b59..f421163c7fd 100644 --- a/api/docs/release.dox +++ b/api/docs/release.dox @@ -126,6 +126,8 @@ clients. The changes between version \DR_VERSION and 11.3.0 include the following compatibility changes: + - Changed the type of `block_size` to `int64_t` in `caching_device_t` and it's + deriving classes. - On 32-bit Arm the size of #dr_mcontext_t has been increased by 4 and the struct is now required to be 8-byte aligned. The offset of the field "simd" has changed. diff --git a/clients/drcachesim/common/utils.h b/clients/drcachesim/common/utils.h index 610c648d823..1be06dec810 100644 --- a/clients/drcachesim/common/utils.h +++ b/clients/drcachesim/common/utils.h @@ -147,7 +147,7 @@ namespace drmemtrace { #endif static inline int -compute_log2(long int value) +compute_log2(int64_t value) { int i; for (i = 0; i < 63; i++) { diff --git a/clients/drcachesim/simulator/cache.cpp b/clients/drcachesim/simulator/cache.cpp index 268410ddefa..bfefdef7cce 100644 --- a/clients/drcachesim/simulator/cache.cpp +++ b/clients/drcachesim/simulator/cache.cpp @@ -52,7 +52,7 @@ namespace drmemtrace { class snoop_filter_t; bool -cache_t::init(int associativity, long int line_size, int total_size, +cache_t::init(int associativity, int64_t line_size, int total_size, caching_device_t *parent, caching_device_stats_t *stats, prefetcher_t *prefetcher, cache_inclusion_policy_t inclusion_policy, bool coherent_cache, int id, snoop_filter_t *snoop_filter, diff --git a/clients/drcachesim/simulator/cache.h b/clients/drcachesim/simulator/cache.h index ecfe08b4b9a..659926f15cf 100644 --- a/clients/drcachesim/simulator/cache.h +++ b/clients/drcachesim/simulator/cache.h @@ -61,7 +61,7 @@ class cache_t : public caching_device_t { // The id is an index into the snoop filter's array of caches for coherent caches. // If this is a coherent cache, id should be in the range [0,num_snooped_caches). bool - init(int associativity, long int line_size, int total_size, caching_device_t *parent, + init(int associativity, int64_t line_size, int total_size, caching_device_t *parent, caching_device_stats_t *stats, prefetcher_t *prefetcher = nullptr, cache_inclusion_policy_t inclusion_policy = cache_inclusion_policy_t::NON_INC_NON_EXC, diff --git a/clients/drcachesim/simulator/cache_fifo.cpp b/clients/drcachesim/simulator/cache_fifo.cpp index d172be47c9c..72b2fa45061 100644 --- a/clients/drcachesim/simulator/cache_fifo.cpp +++ b/clients/drcachesim/simulator/cache_fifo.cpp @@ -53,7 +53,7 @@ namespace drmemtrace { // be cleared. The counter of the next block will be set to 1. bool -cache_fifo_t::init(int associativity, long int block_size, int total_size, +cache_fifo_t::init(int associativity, int64_t block_size, int total_size, caching_device_t *parent, caching_device_stats_t *stats, prefetcher_t *prefetcher, cache_inclusion_policy_t inclusion_policy, bool coherent_cache, int id, snoop_filter_t *snoop_filter, diff --git a/clients/drcachesim/simulator/cache_fifo.h b/clients/drcachesim/simulator/cache_fifo.h index 62939846bdd..d532f78d827 100644 --- a/clients/drcachesim/simulator/cache_fifo.h +++ b/clients/drcachesim/simulator/cache_fifo.h @@ -54,7 +54,7 @@ class cache_fifo_t : public cache_t { { } bool - init(int associativity, long int block_size, int total_size, caching_device_t *parent, + init(int associativity, int64_t block_size, int total_size, caching_device_t *parent, caching_device_stats_t *stats, prefetcher_t *prefetcher = nullptr, cache_inclusion_policy_t inclusion_policy = cache_inclusion_policy_t::NON_INC_NON_EXC, diff --git a/clients/drcachesim/simulator/cache_lru.cpp b/clients/drcachesim/simulator/cache_lru.cpp index 6280874fe87..4f259e0dcd3 100644 --- a/clients/drcachesim/simulator/cache_lru.cpp +++ b/clients/drcachesim/simulator/cache_lru.cpp @@ -50,7 +50,7 @@ namespace drmemtrace { // highest counter value will be picked for replacement in replace_which_way. bool -cache_lru_t::init(int associativity, long int block_size, int total_size, +cache_lru_t::init(int associativity, int64_t block_size, int total_size, caching_device_t *parent, caching_device_stats_t *stats, prefetcher_t *prefetcher, cache_inclusion_policy_t inclusion_policy, bool coherent_cache, int id, snoop_filter_t *snoop_filter, diff --git a/clients/drcachesim/simulator/cache_lru.h b/clients/drcachesim/simulator/cache_lru.h index 2156c5c8e4a..87bd429d657 100644 --- a/clients/drcachesim/simulator/cache_lru.h +++ b/clients/drcachesim/simulator/cache_lru.h @@ -53,7 +53,7 @@ class cache_lru_t : public cache_t { { } bool - init(int associativity, long int block_size, int total_size, caching_device_t *parent, + init(int associativity, int64_t block_size, int total_size, caching_device_t *parent, caching_device_stats_t *stats, prefetcher_t *prefetcher = nullptr, cache_inclusion_policy_t inclusion_policy = cache_inclusion_policy_t::NON_INC_NON_EXC, diff --git a/clients/drcachesim/simulator/caching_device.cpp b/clients/drcachesim/simulator/caching_device.cpp index 309cd20a12c..2ce0387eb02 100644 --- a/clients/drcachesim/simulator/caching_device.cpp +++ b/clients/drcachesim/simulator/caching_device.cpp @@ -74,7 +74,7 @@ caching_device_t::~caching_device_t() } bool -caching_device_t::init(int associativity, long int block_size, int num_blocks, +caching_device_t::init(int associativity, int64_t block_size, int num_blocks, caching_device_t *parent, caching_device_stats_t *stats, prefetcher_t *prefetcher, cache_inclusion_policy_t inclusion_policy, bool coherent_cache, diff --git a/clients/drcachesim/simulator/caching_device.h b/clients/drcachesim/simulator/caching_device.h index 462dcfbaf2c..ce7d156d440 100644 --- a/clients/drcachesim/simulator/caching_device.h +++ b/clients/drcachesim/simulator/caching_device.h @@ -67,7 +67,7 @@ class caching_device_t { public: explicit caching_device_t(const std::string &name = "caching_device"); virtual bool - init(int associativity, long int block_size, int num_blocks, caching_device_t *parent, + init(int associativity, int64_t block_size, int num_blocks, caching_device_t *parent, caching_device_stats_t *stats, prefetcher_t *prefetcher = nullptr, cache_inclusion_policy_t inclusion_policy = cache_inclusion_policy_t::NON_INC_NON_EXC, @@ -147,7 +147,7 @@ class caching_device_t { { return associativity_; } - virtual long int + virtual int64_t get_block_size() const { return block_size_; @@ -249,7 +249,7 @@ class caching_device_t { init_blocks() = 0; int associativity_; - long int block_size_; // Also known as line length. + int64_t block_size_; // Also known as line length. int num_blocks_; // Total number of lines in cache = size / block_size. bool coherent_cache_; // This is an index into snoop filter's array of caches. From bf265f785fcff9fc3cf572cbe2cb2ef52471b729 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Mon, 24 Feb 2025 14:22:39 +0000 Subject: [PATCH 04/42] fix base type for shift --- clients/drcachesim/common/utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/drcachesim/common/utils.h b/clients/drcachesim/common/utils.h index 1be06dec810..e53a42696fe 100644 --- a/clients/drcachesim/common/utils.h +++ b/clients/drcachesim/common/utils.h @@ -151,7 +151,7 @@ compute_log2(int64_t value) { int i; for (i = 0; i < 63; i++) { - if (value == 1l << i) + if (value == int64_t(1) << i) return i; } // returns -1 if value is not a power of 2. From 145b0ec46cdfcea96ca9990b19b9de517815904f Mon Sep 17 00:00:00 2001 From: Or Almer Date: Mon, 24 Feb 2025 15:17:00 +0000 Subject: [PATCH 05/42] fix format --- clients/drcachesim/simulator/caching_device.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/drcachesim/simulator/caching_device.h b/clients/drcachesim/simulator/caching_device.h index ce7d156d440..0d5e3600fce 100644 --- a/clients/drcachesim/simulator/caching_device.h +++ b/clients/drcachesim/simulator/caching_device.h @@ -250,7 +250,7 @@ class caching_device_t { int associativity_; int64_t block_size_; // Also known as line length. - int num_blocks_; // Total number of lines in cache = size / block_size. + int num_blocks_; // Total number of lines in cache = size / block_size. bool coherent_cache_; // This is an index into snoop filter's array of caches. int id_; From 2ef1000475e7c9a5c4a1f7b85cc207317c1fd758 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Mon, 24 Feb 2025 15:29:04 +0000 Subject: [PATCH 06/42] Fixed return type - CI --- clients/drcachesim/simulator/caching_device.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clients/drcachesim/simulator/caching_device.h b/clients/drcachesim/simulator/caching_device.h index 0d5e3600fce..6f57f3e230b 100644 --- a/clients/drcachesim/simulator/caching_device.h +++ b/clients/drcachesim/simulator/caching_device.h @@ -36,6 +36,7 @@ #ifndef _CACHING_DEVICE_H_ #define _CACHING_DEVICE_H_ 1 +#include #include #include #include @@ -172,7 +173,7 @@ class caching_device_t { { return coherent_cache_; } - virtual int + virtual int64_t get_size_bytes() const { return num_blocks_ * block_size_; From 42862d7261e016b060b24aa1d4c20d7b0f44efd8 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Mon, 24 Feb 2025 15:41:29 +0000 Subject: [PATCH 07/42] Fixed return type - CI --- clients/drcachesim/simulator/cache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/drcachesim/simulator/cache.cpp b/clients/drcachesim/simulator/cache.cpp index bfefdef7cce..14abbe58025 100644 --- a/clients/drcachesim/simulator/cache.cpp +++ b/clients/drcachesim/simulator/cache.cpp @@ -62,7 +62,7 @@ cache_t::init(int associativity, int64_t line_size, int total_size, if (line_size < 1) return false; // convert total_size to num_blocks to fit for caching_device_t::init - int num_lines = total_size / line_size; + int num_lines = total_size / static_cast(line_size); return caching_device_t::init(associativity, line_size, num_lines, parent, stats, prefetcher, inclusion_policy, coherent_cache, id, From bb2c4864d94f66c3c33ef7c7cc1daaa8d4cad8da Mon Sep 17 00:00:00 2001 From: Or Almer Date: Tue, 25 Feb 2025 10:47:30 +0000 Subject: [PATCH 08/42] CR Fixes - grammer and link in release doc --- api/docs/release.dox | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/docs/release.dox b/api/docs/release.dox index f421163c7fd..a3b49e78e2b 100644 --- a/api/docs/release.dox +++ b/api/docs/release.dox @@ -126,8 +126,8 @@ clients. The changes between version \DR_VERSION and 11.3.0 include the following compatibility changes: - - Changed the type of `block_size` to `int64_t` in `caching_device_t` and it's - deriving classes. + - Changed the type of `block_size` to `int64_t` in + #dynamorio::drmemtrace::caching_device_t and its deriving classes. - On 32-bit Arm the size of #dr_mcontext_t has been increased by 4 and the struct is now required to be 8-byte aligned. The offset of the field "simd" has changed. From 3ec1a3641db164e2ee2e36626231a07f6a575822 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Tue, 25 Feb 2025 16:00:20 +0000 Subject: [PATCH 09/42] remove link since this file cannot be accessed by doxygen --- api/docs/release.dox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/docs/release.dox b/api/docs/release.dox index a3b49e78e2b..e24edc70d68 100644 --- a/api/docs/release.dox +++ b/api/docs/release.dox @@ -127,7 +127,7 @@ clients. The changes between version \DR_VERSION and 11.3.0 include the following compatibility changes: - Changed the type of `block_size` to `int64_t` in - #dynamorio::drmemtrace::caching_device_t and its deriving classes. + dynamorio::drmemtrace::caching_device_t and its deriving classes. - On 32-bit Arm the size of #dr_mcontext_t has been increased by 4 and the struct is now required to be 8-byte aligned. The offset of the field "simd" has changed. From aa1438a024872d0769377653b02fbbeb2381742f Mon Sep 17 00:00:00 2001 From: Or Almer Date: Wed, 26 Feb 2025 07:25:17 +0000 Subject: [PATCH 10/42] ix: Small Fixes - Consistent Naming, Error Printing, and `add_parent`. Samll fixes which were not enough to justify a seperate issue. - Fixed inconsistent argument names in cache_fifo and cach_lru - header vs implementation. - Improved error printing in tlb_t so you can know what actually failed - Added and `add_parent` method to `caching_device_t` --- clients/drcachesim/simulator/cache_fifo.h | 5 ++--- clients/drcachesim/simulator/cache_lru.h | 5 ++--- .../drcachesim/simulator/caching_device.cpp | 2 +- clients/drcachesim/simulator/caching_device.h | 6 +++++ .../drcachesim/simulator/tlb_simulator.cpp | 22 ++++++++++++++----- 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/clients/drcachesim/simulator/cache_fifo.h b/clients/drcachesim/simulator/cache_fifo.h index b8e293c00d7..f49f993d434 100644 --- a/clients/drcachesim/simulator/cache_fifo.h +++ b/clients/drcachesim/simulator/cache_fifo.h @@ -54,12 +54,11 @@ class cache_fifo_t : public cache_t { { } bool - init(int associativity, int line_size, int total_size, caching_device_t *parent, + init(int associativity, int block_size, int total_size, caching_device_t *parent, caching_device_stats_t *stats, prefetcher_t *prefetcher = nullptr, cache_inclusion_policy_t inclusion_policy = cache_inclusion_policy_t::NON_INC_NON_EXC, - bool coherent_cache = false, int id_ = -1, - snoop_filter_t *snoop_filter_ = nullptr, + bool coherent_cache = false, int id = -1, snoop_filter_t *snoop_filter = nullptr, const std::vector &children = {}) override; std::string diff --git a/clients/drcachesim/simulator/cache_lru.h b/clients/drcachesim/simulator/cache_lru.h index e01b0f89888..61268187fbf 100644 --- a/clients/drcachesim/simulator/cache_lru.h +++ b/clients/drcachesim/simulator/cache_lru.h @@ -53,12 +53,11 @@ class cache_lru_t : public cache_t { { } bool - init(int associativity, int line_size, int total_size, caching_device_t *parent, + init(int associativity, int block_size, int total_size, caching_device_t *parent, caching_device_stats_t *stats, prefetcher_t *prefetcher = nullptr, cache_inclusion_policy_t inclusion_policy = cache_inclusion_policy_t::NON_INC_NON_EXC, - bool coherent_cache = false, int id_ = -1, - snoop_filter_t *snoop_filter_ = nullptr, + bool coherent_cache = false, int id = -1, snoop_filter_t *snoop_filter = nullptr, const std::vector &children = {}) override; std::string get_replace_policy() const override diff --git a/clients/drcachesim/simulator/caching_device.cpp b/clients/drcachesim/simulator/caching_device.cpp index 08482bd0f0b..68cee324bcf 100644 --- a/clients/drcachesim/simulator/caching_device.cpp +++ b/clients/drcachesim/simulator/caching_device.cpp @@ -41,9 +41,9 @@ #include #include -#include "memref.h" #include "caching_device_block.h" #include "caching_device_stats.h" +#include "memref.h" #include "prefetcher.h" #include "snoop_filter.h" #include "trace_entry.h" diff --git a/clients/drcachesim/simulator/caching_device.h b/clients/drcachesim/simulator/caching_device.h index 876f9809c4f..4da7cf01a6e 100644 --- a/clients/drcachesim/simulator/caching_device.h +++ b/clients/drcachesim/simulator/caching_device.h @@ -110,6 +110,12 @@ class caching_device_t { { return parent_; } + void + set_parent(caching_device_t *parent) + { + parent_ = parent; + parent_->children_.push_back(this); + } inline double get_loaded_fraction() const { diff --git a/clients/drcachesim/simulator/tlb_simulator.cpp b/clients/drcachesim/simulator/tlb_simulator.cpp index dc363896551..9566a75139a 100644 --- a/clients/drcachesim/simulator/tlb_simulator.cpp +++ b/clients/drcachesim/simulator/tlb_simulator.cpp @@ -115,15 +115,27 @@ tlb_simulator_t::tlb_simulator_t(const tlb_simulator_knobs_t &knobs) if (!itlbs_[i]->init(knobs_.TLB_L1I_assoc, (int)knobs_.page_size, knobs_.TLB_L1I_entries, lltlbs_[i], - new tlb_stats_t((int)knobs_.page_size)) || - !dtlbs_[i]->init(knobs_.TLB_L1D_assoc, (int)knobs_.page_size, + new tlb_stats_t((int)knobs_.page_size))) { + error_string_ = + "Usage error: failed to initialize itlbs_. Ensure entry number, " + "page size and associativity are powers of 2."; + success_ = false; + return; + } + if (!dtlbs_[i]->init(knobs_.TLB_L1D_assoc, (int)knobs_.page_size, knobs_.TLB_L1D_entries, lltlbs_[i], - new tlb_stats_t((int)knobs_.page_size)) || - !lltlbs_[i]->init(knobs_.TLB_L2_assoc, (int)knobs_.page_size, + new tlb_stats_t((int)knobs_.page_size))) { + error_string_ = + "Usage error: failed to initialize dtlbs_. Ensure entry number, " + "page size and associativity are powers of 2."; + success_ = false; + return; + } + if (!lltlbs_[i]->init(knobs_.TLB_L2_assoc, (int)knobs_.page_size, knobs_.TLB_L2_entries, NULL, new tlb_stats_t((int)knobs_.page_size))) { error_string_ = - "Usage error: failed to initialize TLbs_. Ensure entry number, " + "Usage error: failed to initialize lltlbs_. Ensure entry number, " "page size and associativity are powers of 2."; success_ = false; return; From 06adc5251ba956c6701abeaf1f89fa4d1a8f0b94 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Wed, 26 Feb 2025 08:27:48 +0000 Subject: [PATCH 11/42] CR - check int size --- clients/drcachesim/simulator/cache.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/clients/drcachesim/simulator/cache.cpp b/clients/drcachesim/simulator/cache.cpp index 14abbe58025..23eb7b4440f 100644 --- a/clients/drcachesim/simulator/cache.cpp +++ b/clients/drcachesim/simulator/cache.cpp @@ -61,6 +61,11 @@ cache_t::init(int associativity, int64_t line_size, int total_size, // Check line_size to avoid divide-by-0. if (line_size < 1) return false; + // Check that line_size fits in int - we don't expect actual huge line sizes in + // cache. Support for 64-bit line/block size exists for pages in TLBs, which + // don't actually hold the pages, just reference them. + if (line_size > std::numeric_limits::max()) + return false; // convert total_size to num_blocks to fit for caching_device_t::init int num_lines = total_size / static_cast(line_size); From a8a3d2f891f6e8ff13132ce1355cb96f0b9a6f69 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Sun, 2 Mar 2025 12:34:00 +0000 Subject: [PATCH 12/42] i#7287: Decouple Cache Replacement Policies. Add `cache_replacement_policy_t` - An interface that allows defining a cache replacement policy used by `caching_device_t` We now no longer need to re-implement a cache for each replacement policy, instead passing a `unique_ptr` to a policy. The policies themselves can implement the replacement procedures with the appropriate data structures. Any user can add his own replacement policies and pass them to any caching device. Fixed all relevant uses and tests. Removed all subclasses re-implementing policies. Had to implement a small functionality change in `fifo` - Previously, the fifo cache policy in `cache_fifo_t` ignored invalidations, but now that invalidations are handled by the caching device and replacement by the policy, we can't completely ignore them. There don't seem to be any uses that depend on it, and I think this design makes more sense, but it does constitute a functionality change. Should we make an effort to support it? We can move the valid bits into the policy, for instance, but I personally think this is cleaner - Now it actually implements FIFO, rather than round robin. There is a cache policy test in `unit_test_cache_replacement_policy`, but I can add another that looks directly at the cache policies if you prefer. Fixes #7287 --- clients/drcachesim/CMakeLists.txt | 7 +- clients/drcachesim/common/options.cpp | 3 +- clients/drcachesim/simulator/bit_plru.cpp | 105 +++++++++++ .../simulator/{cache_lru.h => bit_plru.h} | 51 +++--- clients/drcachesim/simulator/cache.cpp | 16 +- clients/drcachesim/simulator/cache.h | 8 +- clients/drcachesim/simulator/cache_fifo.cpp | 120 ------------- .../simulator/cache_replacement_policy.h | 86 +++++++++ .../drcachesim/simulator/cache_simulator.cpp | 65 ++----- .../drcachesim/simulator/cache_simulator.h | 3 - .../drcachesim/simulator/caching_device.cpp | 49 +++--- clients/drcachesim/simulator/caching_device.h | 25 ++- .../create_cache_replacement_policy.cpp | 64 +++++++ .../create_cache_replacement_policy.h | 52 ++++++ clients/drcachesim/simulator/fifo.cpp | 84 +++++++++ .../simulator/{cache_fifo.h => fifo.h} | 51 ++---- clients/drcachesim/simulator/lfu.cpp | 88 ++++++++++ clients/drcachesim/simulator/lfu.h | 65 +++++++ .../simulator/{cache_lru.cpp => lru.cpp} | 77 +++----- clients/drcachesim/simulator/lru.h | 67 +++++++ clients/drcachesim/simulator/tlb.cpp | 63 +------ clients/drcachesim/simulator/tlb.h | 51 ------ .../drcachesim/simulator/tlb_simulator.cpp | 50 +++--- clients/drcachesim/simulator/tlb_simulator.h | 5 +- .../cache_replacement_policy_unit_test.cpp | 166 +++++++----------- .../tests/drcachesim_unit_tests.cpp | 79 ++++++--- .../drcachesim/tools/filter/cache_filter.cpp | 10 +- 27 files changed, 909 insertions(+), 601 deletions(-) create mode 100644 clients/drcachesim/simulator/bit_plru.cpp rename clients/drcachesim/simulator/{cache_lru.h => bit_plru.h} (65%) delete mode 100644 clients/drcachesim/simulator/cache_fifo.cpp create mode 100644 clients/drcachesim/simulator/cache_replacement_policy.h create mode 100644 clients/drcachesim/simulator/create_cache_replacement_policy.cpp create mode 100644 clients/drcachesim/simulator/create_cache_replacement_policy.h create mode 100644 clients/drcachesim/simulator/fifo.cpp rename clients/drcachesim/simulator/{cache_fifo.h => fifo.h} (65%) create mode 100644 clients/drcachesim/simulator/lfu.cpp create mode 100644 clients/drcachesim/simulator/lfu.h rename clients/drcachesim/simulator/{cache_lru.cpp => lru.cpp} (50%) create mode 100644 clients/drcachesim/simulator/lru.h diff --git a/clients/drcachesim/CMakeLists.txt b/clients/drcachesim/CMakeLists.txt index 6b24cb3b43c..3a4b206097f 100644 --- a/clients/drcachesim/CMakeLists.txt +++ b/clients/drcachesim/CMakeLists.txt @@ -193,8 +193,6 @@ configure_DynamoRIO_standalone(drmemtrace_invariant_checker) add_exported_library(drmemtrace_simulator STATIC simulator/simulator.cpp simulator/cache.cpp - simulator/cache_lru.cpp - simulator/cache_fifo.cpp simulator/cache_miss_analyzer.cpp simulator/caching_device.cpp simulator/caching_device_stats.cpp @@ -204,6 +202,11 @@ add_exported_library(drmemtrace_simulator STATIC simulator/snoop_filter.cpp simulator/tlb.cpp simulator/tlb_simulator.cpp + simulator/bit_plru.cpp + simulator/create_cache_replacement_policy.cpp + simulator/fifo.cpp + simulator/lfu.cpp + simulator/lru.cpp ) add_exported_library(drmemtrace_record_filter STATIC diff --git a/clients/drcachesim/common/options.cpp b/clients/drcachesim/common/options.cpp index bfbe43a07af..6d111ccedd2 100644 --- a/clients/drcachesim/common/options.cpp +++ b/clients/drcachesim/common/options.cpp @@ -502,7 +502,8 @@ droption_t "Specifies the replacement policy for TLBs. " "Supported policies: " REPLACE_POLICY_LFU " (Least Frequently Used), " REPLACE_POLICY_BIT_PLRU - " (Pseudo Least Recently Used)."); + " (Pseudo Least Recently Used) " REPLACE_POLICY_LRU + " (Least Recently Used)"); droption_t op_tool(DROPTION_SCOPE_FRONTEND, diff --git a/clients/drcachesim/simulator/bit_plru.cpp b/clients/drcachesim/simulator/bit_plru.cpp new file mode 100644 index 00000000000..d296d2d0550 --- /dev/null +++ b/clients/drcachesim/simulator/bit_plru.cpp @@ -0,0 +1,105 @@ +/* ********************************************************** + * Copyright (c) 2015-2023 Google, Inc. All rights reserved. + * **********************************************************/ + +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Google, Inc. nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#include "bit_plru.h" + +#include +#include + +namespace dynamorio { +namespace drmemtrace { + +bit_plru_t::bit_plru_t(int num_blocks, int associativity, int seed) + : cache_replacement_policy_t(num_blocks, associativity) + , block_set_counts_(num_blocks, 0) + , gen_(seed == -1 ? std::random_device()() : seed) +{ + // Initialize the bit vector for each block. + block_bits_.reserve(num_blocks); + for (int i = 0; i < num_blocks; ++i) { + block_bits_.emplace_back(associativity, false); + } +} + +void +bit_plru_t::access_update(int block_idx, int way) +{ + block_idx = get_block_index(block_idx); + // Set the bit for the accessed way. + if (!block_bits_[block_idx][way]) { + block_bits_[block_idx][way] = true; + block_set_counts_[block_idx]++; + } + if (block_set_counts_[block_idx] < associativity_) { + // Finished. + return; + } + // If all bits are set, reset them. + for (int i = 0; i < associativity_; ++i) { + block_bits_[block_idx][i] = false; + } + block_set_counts_[block_idx] = 1; + block_bits_[block_idx][way] = true; +} + +void +bit_plru_t::eviction_update(int block_idx, int way) +{ + // Nothing to update, when the way is accessed we will update it. +} + +int +bit_plru_t::get_next_way_to_replace(int block_idx) +{ + block_idx = get_block_index(block_idx); + std::vector unset_bits; + for (int i = 0; i < associativity_; ++i) { + if (block_bits_[block_idx][i] == 0) { + unset_bits.push_back(i); + } + } + + if (unset_bits.empty()) { + // Should not reach here. + return -1; + } + return unset_bits[gen_() % unset_bits.size()]; +} + +std::string +bit_plru_t::get_name() const +{ + return "BIT_PLRU"; +} + +} // namespace drmemtrace +} // namespace dynamorio diff --git a/clients/drcachesim/simulator/cache_lru.h b/clients/drcachesim/simulator/bit_plru.h similarity index 65% rename from clients/drcachesim/simulator/cache_lru.h rename to clients/drcachesim/simulator/bit_plru.h index 61268187fbf..c335dfca822 100644 --- a/clients/drcachesim/simulator/cache_lru.h +++ b/clients/drcachesim/simulator/bit_plru.h @@ -30,51 +30,40 @@ * DAMAGE. */ -/* cache_lru: represents a single hardware cache with LRU algo. - */ - -#ifndef _CACHE_LRU_H_ -#define _CACHE_LRU_H_ 1 +#ifndef _BIT_PLRU_H_ +#define _BIT_PLRU_H_ +#include #include #include -#include "cache.h" -#include "prefetcher.h" -#include "snoop_filter.h" +#include "cache_replacement_policy.h" namespace dynamorio { namespace drmemtrace { -class cache_lru_t : public cache_t { +class bit_plru_t : public cache_replacement_policy_t { public: - explicit cache_lru_t(const std::string &name = "cache_lru") - : cache_t(name) - { - } - bool - init(int associativity, int block_size, int total_size, caching_device_t *parent, - caching_device_stats_t *stats, prefetcher_t *prefetcher = nullptr, - cache_inclusion_policy_t inclusion_policy = - cache_inclusion_policy_t::NON_INC_NON_EXC, - bool coherent_cache = false, int id = -1, snoop_filter_t *snoop_filter = nullptr, - const std::vector &children = {}) override; - std::string - get_replace_policy() const override - { - return "LRU"; - } - -protected: + /// If seed is -1, a random seed will be used. + bit_plru_t(int num_blocks, int associativity, int seed = -1); void access_update(int block_idx, int way) override; + void + eviction_update(int block_idx, int way) override; int - replace_which_way(int block_idx) override; - int - get_next_way_to_replace(const int block_idx) const override; + get_next_way_to_replace(int block_idx) override; + std::string + get_name() const override; + + ~bit_plru_t() override = default; + +private: + std::vector> block_bits_; + std::vector block_set_counts_; + std::mt19937 gen_; }; } // namespace drmemtrace } // namespace dynamorio -#endif /* _CACHE_LRU_H_ */ +#endif // _BIT_PLRU_H_ diff --git a/clients/drcachesim/simulator/cache.cpp b/clients/drcachesim/simulator/cache.cpp index bf453412c58..e30c86872f9 100644 --- a/clients/drcachesim/simulator/cache.cpp +++ b/clients/drcachesim/simulator/cache.cpp @@ -33,7 +33,6 @@ #include "cache.h" #include - #include #include @@ -52,10 +51,11 @@ namespace drmemtrace { class snoop_filter_t; bool -cache_t::init(int associativity, int line_size, int total_size, caching_device_t *parent, - caching_device_stats_t *stats, prefetcher_t *prefetcher, - cache_inclusion_policy_t inclusion_policy, bool coherent_cache, int id, - snoop_filter_t *snoop_filter, +cache_t::init(int associativity, int64_t line_size, int total_size, + caching_device_t *parent, caching_device_stats_t *stats, + std::unique_ptr replacement_policy, + prefetcher_t *prefetcher, cache_inclusion_policy_t inclusion_policy, + bool coherent_cache, int id, snoop_filter_t *snoop_filter, const std::vector &children) { // Check line_size to avoid divide-by-0. @@ -64,9 +64,9 @@ cache_t::init(int associativity, int line_size, int total_size, caching_device_t // convert total_size to num_blocks to fit for caching_device_t::init int num_lines = total_size / line_size; - return caching_device_t::init(associativity, line_size, num_lines, parent, stats, - prefetcher, inclusion_policy, coherent_cache, id, - snoop_filter, children); + return caching_device_t::init( + associativity, line_size, num_lines, parent, stats, std::move(replacement_policy), + prefetcher, inclusion_policy, coherent_cache, id, snoop_filter, children); } void diff --git a/clients/drcachesim/simulator/cache.h b/clients/drcachesim/simulator/cache.h index 10a79038654..065d90e8863 100644 --- a/clients/drcachesim/simulator/cache.h +++ b/clients/drcachesim/simulator/cache.h @@ -38,8 +38,10 @@ #include #include +#include #include "cache_line.h" +#include "cache_replacement_policy.h" #include "cache_stats.h" #include "caching_device.h" #include "memref.h" @@ -61,8 +63,10 @@ class cache_t : public caching_device_t { // The id is an index into the snoop filter's array of caches for coherent caches. // If this is a coherent cache, id should be in the range [0,num_snooped_caches). bool - init(int associativity, int line_size, int total_size, caching_device_t *parent, - caching_device_stats_t *stats, prefetcher_t *prefetcher = nullptr, + init(int associativity, int64_t line_size, int total_size, caching_device_t *parent, + caching_device_stats_t *stats, + std::unique_ptr replacement_policy, + prefetcher_t *prefetcher = nullptr, cache_inclusion_policy_t inclusion_policy = cache_inclusion_policy_t::NON_INC_NON_EXC, bool coherent_cache = false, int id_ = -1, diff --git a/clients/drcachesim/simulator/cache_fifo.cpp b/clients/drcachesim/simulator/cache_fifo.cpp deleted file mode 100644 index 0ee070e4f9c..00000000000 --- a/clients/drcachesim/simulator/cache_fifo.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* ********************************************************** - * Copyright (c) 2015-2023 Google, Inc. All rights reserved. - * **********************************************************/ - -/* - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of Google, Inc. nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - */ - -#include "cache_fifo.h" - -#include - -#include - -#include "cache.h" -#include "caching_device.h" -#include "caching_device_block.h" -#include "caching_device_stats.h" -#include "prefetcher.h" -#include "snoop_filter.h" - -namespace dynamorio { -namespace drmemtrace { - -// For the FIFO/Round-Robin implementation, all the cache blocks in a set are organized -// as a FIFO. The counters of a set of blocks simulate the replacement pointer. -// The counter of the victim block is 1, and others are 0. -// While replacing happens, the victim block will be replaced and its counter will -// be cleared. The counter of the next block will be set to 1. - -bool -cache_fifo_t::init(int associativity, int block_size, int total_size, - caching_device_t *parent, caching_device_stats_t *stats, - prefetcher_t *prefetcher, cache_inclusion_policy_t inclusion_policy, - bool coherent_cache, int id, snoop_filter_t *snoop_filter, - const std::vector &children) -{ - // Works in the same way as the base class, - // except that the counters are initialized in a different way. - - bool ret_val = - cache_t::init(associativity, block_size, total_size, parent, stats, prefetcher, - inclusion_policy, coherent_cache, id, snoop_filter, children); - if (ret_val == false) - return false; - - // Create a replacement pointer for each set, and - // initialize it to point to the first block. - for (int i = 0; i < blocks_per_way_; i++) { - get_caching_device_block(i * associativity_, 0).counter_ = 1; - } - return true; -} - -void -cache_fifo_t::access_update(int block_idx, int way) -{ - // Since the FIFO replacement policy is independent of cache hit, - // we do not need to do anything here. - return; -} - -// This method replaces the current victim way and returns the next victim way -// to be replaced. As opposed to get_next_way_to_replace() which just returns the -// next way to be replaced without updating the cache state, replace_which_way() -// updates the cache state. -int -cache_fifo_t::replace_which_way(int block_idx) -{ - int victim_way = get_next_way_to_replace(block_idx); - // clear the counter of the victim block - get_caching_device_block(block_idx, victim_way).counter_ = 0; - // set the next block as victim - get_caching_device_block(block_idx, (victim_way + 1) & (associativity_ - 1)) - .counter_ = 1; - return victim_way; -} - -// This method just returns the next way to be replaced without actually -// replacing it, hence doesn't have a side-effect. -int -cache_fifo_t::get_next_way_to_replace(const int block_idx) const -{ - for (int i = 0; i < associativity_; i++) { - // We return the block whose counter is 1. - if (get_caching_device_block(block_idx, i).counter_ == 1) { - return i; - } - } - - assert(false); - return 0; -} - -} // namespace drmemtrace -} // namespace dynamorio diff --git a/clients/drcachesim/simulator/cache_replacement_policy.h b/clients/drcachesim/simulator/cache_replacement_policy.h new file mode 100644 index 00000000000..288a68d82ff --- /dev/null +++ b/clients/drcachesim/simulator/cache_replacement_policy.h @@ -0,0 +1,86 @@ +/* ********************************************************** + * Copyright (c) 2015-2023 Google, Inc. All rights reserved. + * **********************************************************/ + +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Google, Inc. nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#ifndef _CACHE_REPLACEMENT_POLICY_H_ +#define _CACHE_REPLACEMENT_POLICY_H_ 1 + +#include + +namespace dynamorio { +namespace drmemtrace { + +/** + * An interface for cache replacement policies. + * + * Holds the necassary information to implement a cache replacement policy, + * And provides an interface for caching_device_t find which way to replace + * in a block upon eviction. + */ +class cache_replacement_policy_t { +public: + cache_replacement_policy_t(int num_blocks, int associativity) + : associativity_(associativity) + , num_blocks_(num_blocks) + { + } + /// Informs the replacement policy that an access has occurred. + virtual void + access_update(int block_idx, int way) = 0; + /// Informs the replacement policy that an eviction has occurred. + virtual void + eviction_update(int block_idx, int way) = 0; + /// Returns the next way to replace in the block. + virtual int + get_next_way_to_replace(int block_idx) = 0; + /// Returns the name of the replacement policy. + virtual std::string + get_name() const = 0; + + virtual ~cache_replacement_policy_t() = default; + +protected: + virtual int + get_block_index(int block_idx) + { + // The block index points to the first way in the block, and the ways are stored + // in a contiguous array, so we divide by the associativity to get the block + // index. + return block_idx / associativity_; + } + int associativity_; + int num_blocks_; +}; + +} // namespace drmemtrace +} // namespace dynamorio + +#endif /* _CACHE_REPLACEMENT_POLICY_H_ */ diff --git a/clients/drcachesim/simulator/cache_simulator.cpp b/clients/drcachesim/simulator/cache_simulator.cpp index f3d0f358f61..097135a8613 100644 --- a/clients/drcachesim/simulator/cache_simulator.cpp +++ b/clients/drcachesim/simulator/cache_simulator.cpp @@ -51,12 +51,11 @@ #include "file_reader.h" #include "ipc_reader.h" #include "cache.h" -#include "cache_fifo.h" -#include "cache_lru.h" #include "cache_simulator_create.h" #include "cache_stats.h" #include "caching_device.h" #include "caching_device_stats.h" +#include "create_cache_replacement_policy.h" #include "prefetcher.h" #include "simulator.h" #include "snoop_filter.h" @@ -100,12 +99,7 @@ cache_simulator_t::cache_simulator_t(const cache_simulator_knobs_t &knobs, // This configuration allows for one shared LLC only. std::string cache_name = "LL"; - cache_t *llc = create_cache(cache_name, knobs_.replace_policy); - if (llc == NULL) { - error_string_ = "create_cache failed for the LLC"; - success_ = false; - return; - } + cache_t *llc = new cache_t(cache_name); all_caches_[cache_name] = llc; llcaches_[cache_name] = llc; @@ -131,7 +125,10 @@ cache_simulator_t::cache_simulator_t(const cache_simulator_knobs_t &knobs, if (!llc->init(knobs_.LL_assoc, (int)knobs_.line_size, (int)knobs_.LL_size, NULL, new cache_stats_t((int)knobs_.line_size, knobs_.LL_miss_file, - warmup_enabled_))) { + warmup_enabled_), + create_cache_replacement_policy( + knobs_.replace_policy, (int)knobs_.LL_size / (int)knobs_.LL_assoc, + (int)knobs_.LL_assoc))) { error_string_ = "Usage error: failed to initialize LL cache. Ensure size divided by " "associativity is a power of 2, that the total size is a multiple " @@ -150,32 +147,28 @@ cache_simulator_t::cache_simulator_t(const cache_simulator_knobs_t &knobs, for (unsigned int i = 0; i < knobs_.num_cores; i++) { cache_name = "L1I" + (knobs_.num_cores > 0 ? std::to_string(i) : ""); - l1_icaches_[i] = create_cache(cache_name, knobs_.replace_policy); - if (l1_icaches_[i] == NULL) { - error_string_ = "create_cache failed for an l1_icache"; - success_ = false; - return; - } + l1_icaches_[i] = new cache_t(cache_name); snooped_caches_[2 * i] = l1_icaches_[i]; cache_name = "L1D" + (knobs_.num_cores > 0 ? std::to_string(i) : ""); - l1_dcaches_[i] = create_cache(cache_name, knobs_.replace_policy); - if (l1_dcaches_[i] == NULL) { - error_string_ = "create_cache failed for an l1_dcache"; - success_ = false; - return; - } + l1_dcaches_[i] = new cache_t(cache_name); snooped_caches_[(2 * i) + 1] = l1_dcaches_[i]; if (!l1_icaches_[i]->init( knobs_.L1I_assoc, (int)knobs_.line_size, (int)knobs_.L1I_size, llc, new cache_stats_t((int)knobs_.line_size, "", warmup_enabled_, knobs_.model_coherence), + create_cache_replacement_policy( + knobs_.replace_policy, (int)knobs_.L1I_size / (int)knobs_.L1I_assoc, + (int)knobs_.L1I_assoc) /*replacement_policy*/, nullptr /*prefetcher*/, cache_inclusion_policy_t::NON_INC_NON_EXC, knobs_.model_coherence, 2 * i, snoop_filter_) || !l1_dcaches_[i]->init( knobs_.L1D_assoc, (int)knobs_.line_size, (int)knobs_.L1D_size, llc, new cache_stats_t((int)knobs_.line_size, "", warmup_enabled_, knobs_.model_coherence), + create_cache_replacement_policy( + knobs_.replace_policy, (int)knobs_.L1D_size / (int)knobs_.L1D_assoc, + (int)knobs_.L1D_assoc) /*replacement_policy*/, get_prefetcher(knobs_.data_prefetcher), cache_inclusion_policy_t::NON_INC_NON_EXC, knobs_.model_coherence, (2 * i) + 1, snoop_filter_)) { @@ -245,14 +238,7 @@ cache_simulator_t::cache_simulator_t(std::istream *config_file, // Create all the caches in the hierarchy. for (const auto &cache_params_it : cache_params) { std::string cache_name = cache_params_it.first; - const auto &cache_config = cache_params_it.second; - - cache_t *cache = create_cache(cache_name, cache_config.replace_policy); - if (cache == NULL) { - success_ = false; - return; - } - + cache_t *cache = new cache_t(cache_name); all_caches_[cache_name] = cache; } @@ -358,6 +344,10 @@ cache_simulator_t::cache_simulator_t(std::istream *config_file, (int)cache_config.size, parent_, new cache_stats_t((int)knobs_.line_size, cache_config.miss_file, warmup_enabled_, is_coherent_), + create_cache_replacement_policy(cache_config.replace_policy, + (int)cache_config.size / + (int)cache_config.assoc, + (int)cache_config.assoc), get_prefetcher(cache_config.prefetcher), inclusion_policy, is_coherent_, is_snooped ? snoop_id : -1, is_snooped ? snoop_filter_ : nullptr, children)) { @@ -714,23 +704,6 @@ cache_simulator_t::get_knobs() const return knobs_; } -cache_t * -cache_simulator_t::create_cache(const std::string &name, const std::string &policy) -{ - if (policy == REPLACE_POLICY_NON_SPECIFIED || // default LRU - policy == REPLACE_POLICY_LRU) // set to LRU - return new cache_lru_t(name); - if (policy == REPLACE_POLICY_LFU) // set to LFU - return new cache_t(name); - if (policy == REPLACE_POLICY_FIFO) // set to FIFO - return new cache_fifo_t(name); - - // undefined replacement policy - ERRMSG("Usage error: undefined replacement policy. " - "Please choose " REPLACE_POLICY_LRU " or " REPLACE_POLICY_LFU ".\n"); - return NULL; -} - // Access snoop filter stats. int64_t cache_simulator_t::get_num_snooped_caches(void) diff --git a/clients/drcachesim/simulator/cache_simulator.h b/clients/drcachesim/simulator/cache_simulator.h index a4540cf9116..116c2486455 100644 --- a/clients/drcachesim/simulator/cache_simulator.h +++ b/clients/drcachesim/simulator/cache_simulator.h @@ -110,9 +110,6 @@ class cache_simulator_t : public simulator_t { get_knobs() const; protected: - // Create a cache_t object with a specific replacement policy. - virtual cache_t * - create_cache(const std::string &name, const std::string &policy); prefetcher_t * get_prefetcher(std::string prefetcher_name); diff --git a/clients/drcachesim/simulator/caching_device.cpp b/clients/drcachesim/simulator/caching_device.cpp index 68cee324bcf..01e873c664a 100644 --- a/clients/drcachesim/simulator/caching_device.cpp +++ b/clients/drcachesim/simulator/caching_device.cpp @@ -74,23 +74,30 @@ caching_device_t::~caching_device_t() } bool -caching_device_t::init(int associativity, int block_size, int num_blocks, +caching_device_t::init(int associativity, int64_t block_size, int num_blocks, caching_device_t *parent, caching_device_stats_t *stats, + std::unique_ptr replacement_policy, prefetcher_t *prefetcher, cache_inclusion_policy_t inclusion_policy, bool coherent_cache, int id, snoop_filter_t *snoop_filter, const std::vector &children) { // Assume cache has nonzero capacity. - if (associativity < 1 || num_blocks < 1) + if (associativity < 1 || num_blocks < 1) { return false; + } // Assume caching device block size is at least 4 bytes. - if (!IS_POWER_OF_2(block_size) || block_size < 4) + if (!IS_POWER_OF_2(block_size) || block_size < 4) { return false; - if (stats == NULL) + } + if (stats == NULL) { return false; // A stats must be provided for perf: avoid conditional code - else if (!*stats) + } else if (!*stats) { + return false; + } + if (replacement_policy == NULL) { return false; + } associativity_ = associativity; block_size_ = block_size; num_blocks_ = num_blocks; @@ -120,6 +127,8 @@ caching_device_t::init(int associativity, int block_size, int num_blocks, inclusion_policy_ = inclusion_policy; children_ = children; + replacement_policy_ = std::move(replacement_policy); + return true; } @@ -201,7 +210,8 @@ caching_device_t::request(const memref_t &memref_in) snoop_filter_->snoop(tag, id_, (memref.data.type == TRACE_TYPE_WRITE)); } else if (parent_ != NULL) { - // On a miss, the parent access will inherently propagate the write. + // On a miss, the parent access will inherently propagate the + // write. parent_->propagate_write(tag, this); } } @@ -259,38 +269,25 @@ caching_device_t::request(const memref_t &memref_in) void caching_device_t::access_update(int block_idx, int way) { - // We just inc the counter for LFU. We live with any blip on overflow. - get_caching_device_block(block_idx, way).counter_++; + replacement_policy_->access_update(block_idx, way); } int caching_device_t::replace_which_way(int block_idx) { - int min_way = get_next_way_to_replace(block_idx); - // Clear the counter for LFU. - get_caching_device_block(block_idx, min_way).counter_ = 0; - return min_way; + int way_to_replace = get_next_way_to_replace(block_idx); + replacement_policy_->eviction_update(block_idx, way_to_replace); + return way_to_replace; } int caching_device_t::get_next_way_to_replace(const int block_idx) const { - // The base caching device class only implements LFU. - // A subclass can override this and access_update() to implement - // some other scheme. - int min_counter = 0; /* avoid "may be used uninitialized" with GCC 4.4.7 */ - int min_way = 0; for (int way = 0; way < associativity_; ++way) { - if (get_caching_device_block(block_idx, way).tag_ == TAG_INVALID) { - min_way = way; - break; - } - if (way == 0 || get_caching_device_block(block_idx, way).counter_ < min_counter) { - min_counter = get_caching_device_block(block_idx, way).counter_; - min_way = way; - } + if (get_caching_device_block(block_idx, way).tag_ == TAG_INVALID) + return way; } - return min_way; + return replacement_policy_->get_next_way_to_replace(block_idx); } void diff --git a/clients/drcachesim/simulator/caching_device.h b/clients/drcachesim/simulator/caching_device.h index 876f9809c4f..8d8cc43572f 100644 --- a/clients/drcachesim/simulator/caching_device.h +++ b/clients/drcachesim/simulator/caching_device.h @@ -37,6 +37,7 @@ #define _CACHING_DEVICE_H_ 1 #include +#include #include #include #include @@ -46,6 +47,7 @@ #include "caching_device_stats.h" #include "memref.h" #include "trace_entry.h" +#include "cache_replacement_policy.h" namespace dynamorio { namespace drmemtrace { @@ -63,13 +65,14 @@ class prefetcher_t; // NON_INC_NON_EXC = Non-Inclusive Non-Exclusive, aka NINE. enum class cache_inclusion_policy_t { NON_INC_NON_EXC, INCLUSIVE, EXCLUSIVE }; - class caching_device_t { public: explicit caching_device_t(const std::string &name = "caching_device"); virtual bool - init(int associativity, int block_size, int num_blocks, caching_device_t *parent, - caching_device_stats_t *stats, prefetcher_t *prefetcher = nullptr, + init(int associativity, int64_t block_size, int num_blocks, caching_device_t *parent, + caching_device_stats_t *stats, + std::unique_ptr replacement_policy, + prefetcher_t *prefetcher = nullptr, cache_inclusion_policy_t inclusion_policy = cache_inclusion_policy_t::NON_INC_NON_EXC, bool coherent_cache = false, int id_ = -1, @@ -110,6 +113,12 @@ class caching_device_t { { return parent_; } + void + set_parent(caching_device_t *parent) + { + parent_ = parent; + parent_->children_.push_back(this); + } inline double get_loaded_fraction() const { @@ -143,7 +152,7 @@ class caching_device_t { { return associativity_; } - virtual int + virtual int64_t get_block_size() const { return block_size_; @@ -176,7 +185,7 @@ class caching_device_t { virtual std::string get_replace_policy() const { - return "LFU"; + return replacement_policy_->get_name(); } virtual const std::string & get_name() const @@ -245,8 +254,8 @@ class caching_device_t { init_blocks() = 0; int associativity_; - int block_size_; // Also known as line length. - int num_blocks_; // Total number of lines in cache = size / block_size. + int64_t block_size_; // Also known as line length. + int num_blocks_; // Total number of lines in cache = size / block_size. bool coherent_cache_; // This is an index into snoop filter's array of caches. int id_; @@ -291,6 +300,8 @@ class caching_device_t { tag2block; bool use_tag2block_table_ = false; + mutable std::unique_ptr replacement_policy_; + // Name for this cache. const std::string name_; }; diff --git a/clients/drcachesim/simulator/create_cache_replacement_policy.cpp b/clients/drcachesim/simulator/create_cache_replacement_policy.cpp new file mode 100644 index 00000000000..1249baf8449 --- /dev/null +++ b/clients/drcachesim/simulator/create_cache_replacement_policy.cpp @@ -0,0 +1,64 @@ +/* ********************************************************** + * Copyright (c) 2015-2025 Google, Inc. All rights reserved. + * **********************************************************/ + +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Google, Inc. nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#include "create_cache_replacement_policy.h" + +#include +#include + +#include "bit_plru.h" +#include "fifo.h" +#include "lfu.h" +#include "lru.h" +#include "options.h" + +namespace dynamorio { +namespace drmemtrace { + +std::unique_ptr +create_cache_replacement_policy(const std::string &policy, int num_blocks, + int associativity) +{ + if (policy == REPLACE_POLICY_NON_SPECIFIED || // default LRU + policy == REPLACE_POLICY_LRU) // set to LRU + return std::unique_ptr(new lru_t(num_blocks, associativity)); + if (policy == REPLACE_POLICY_LFU) + return std::unique_ptr(new lfu_t(num_blocks, associativity)); + if (policy == REPLACE_POLICY_FIFO) + return std::unique_ptr(new fifo_t(num_blocks, associativity)); + if (policy == REPLACE_POLICY_BIT_PLRU) + return std::unique_ptr(new bit_plru_t(num_blocks, associativity)); + return nullptr; +} + +} // namespace drmemtrace +} // namespace dynamorio diff --git a/clients/drcachesim/simulator/create_cache_replacement_policy.h b/clients/drcachesim/simulator/create_cache_replacement_policy.h new file mode 100644 index 00000000000..f6de68b952c --- /dev/null +++ b/clients/drcachesim/simulator/create_cache_replacement_policy.h @@ -0,0 +1,52 @@ +/* ********************************************************** + * Copyright (c) 2015-2023 Google, Inc. All rights reserved. + * **********************************************************/ + +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Google, Inc. nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#ifndef _CREATE_CACHE_REPLACEMENT_POLICY_H_ +#define _CREATE_CACHE_REPLACEMENT_POLICY_H_ 1 + +#include +#include + +#include "cache_replacement_policy.h" + +namespace dynamorio { +namespace drmemtrace { + +/// Initializes and returns a specific replacement policy. +std::unique_ptr +create_cache_replacement_policy(const std::string &policy, int num_blocks, + int associativity); + +} // namespace drmemtrace +} // namespace dynamorio + +#endif /* _CREATE_CACHE_REPLACEMENT_POLICY_H_ */ diff --git a/clients/drcachesim/simulator/fifo.cpp b/clients/drcachesim/simulator/fifo.cpp new file mode 100644 index 00000000000..b4ea0f70cdc --- /dev/null +++ b/clients/drcachesim/simulator/fifo.cpp @@ -0,0 +1,84 @@ +#/* ********************************************************** + * Copyright (c) 2015-2023 Google, Inc. All rights reserved. + * **********************************************************/ + +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Google, Inc. nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#include "fifo.h" + +#include + +namespace dynamorio { +namespace drmemtrace { + +fifo_t::fifo_t(int num_blocks, int associativity) + : cache_replacement_policy_t(num_blocks, associativity) +{ + // Initialize the FIFO list for each block. + queues_.reserve(num_blocks); + for (int i = 0; i < num_blocks; ++i) { + queues_.push_back(std::list()); + for (int j = 0; j < associativity; ++j) { + queues_[i].push_back(j); + } + } +} + +void +fifo_t::access_update(int block_idx, int way) +{ + // Nothing to update, FIFO does not change on access. +} + +void +fifo_t::eviction_update(int block_idx, int way) +{ + block_idx = get_block_index(block_idx); + // Move the evicted way to the back of the queue. + auto &fifo_block = queues_[block_idx]; + fifo_block.remove(way); + fifo_block.push_back(way); +} + +int +fifo_t::get_next_way_to_replace(int block_idx) +{ + block_idx = get_block_index(block_idx); + // The next way to replace is at the front of the FIFO list. + return queues_[block_idx].front(); +} + +std::string +fifo_t::get_name() const +{ + return "FIFO"; +} + +} // namespace drmemtrace +} // namespace dynamorio diff --git a/clients/drcachesim/simulator/cache_fifo.h b/clients/drcachesim/simulator/fifo.h similarity index 65% rename from clients/drcachesim/simulator/cache_fifo.h rename to clients/drcachesim/simulator/fifo.h index f49f993d434..52bca2c512a 100644 --- a/clients/drcachesim/simulator/cache_fifo.h +++ b/clients/drcachesim/simulator/fifo.h @@ -30,53 +30,38 @@ * DAMAGE. */ -/* cache_fifo: represents a single hardware cache with FIFO algo. - */ - -#ifndef _CACHE_FIFO_H_ -#define _CACHE_FIFO_H_ 1 +#ifndef _FIFO_H_ +#define _FIFO_H_ +#include #include #include -#include "cache.h" -#include "prefetcher.h" +#include "cache_replacement_policy.h" namespace dynamorio { namespace drmemtrace { -class snoop_filter_t; - -class cache_fifo_t : public cache_t { +class fifo_t : public cache_replacement_policy_t { public: - explicit cache_fifo_t(const std::string &name = "cache_fifo") - : cache_t(name) - { - } - bool - init(int associativity, int block_size, int total_size, caching_device_t *parent, - caching_device_stats_t *stats, prefetcher_t *prefetcher = nullptr, - cache_inclusion_policy_t inclusion_policy = - cache_inclusion_policy_t::NON_INC_NON_EXC, - bool coherent_cache = false, int id = -1, snoop_filter_t *snoop_filter = nullptr, - const std::vector &children = {}) override; - - std::string - get_replace_policy() const override - { - return "FIFO"; - } - -protected: + fifo_t(int num_blocks, int associativity); void access_update(int block_idx, int way) override; + void + eviction_update(int block_idx, int way) override; int - replace_which_way(int block_idx) override; - int - get_next_way_to_replace(const int block_idx) const override; + get_next_way_to_replace(int block_idx) override; + std::string + get_name() const override; + + ~fifo_t() override = default; + +private: + // FIFO queue for each block. + std::vector> queues_; }; } // namespace drmemtrace } // namespace dynamorio -#endif /* _CACHE_FIFO_H_ */ +#endif // _FIFO_H_ diff --git a/clients/drcachesim/simulator/lfu.cpp b/clients/drcachesim/simulator/lfu.cpp new file mode 100644 index 00000000000..6ed1165440a --- /dev/null +++ b/clients/drcachesim/simulator/lfu.cpp @@ -0,0 +1,88 @@ +/* ********************************************************** + * Copyright (c) 2015-2023 Google, Inc. All rights reserved. + * **********************************************************/ + +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Google, Inc. nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#include "lfu.h" + +#include +#include +#include + +namespace dynamorio { +namespace drmemtrace { + +lfu_t::lfu_t(int num_blocks, int associativity) + : cache_replacement_policy_t(num_blocks, associativity) +{ + access_counts_.reserve(num_blocks); + for (int i = 0; i < num_blocks; ++i) { + access_counts_.emplace_back(associativity, 0); + } +} + +void +lfu_t::access_update(int block_idx, int way) +{ + block_idx = get_block_index(block_idx); + access_counts_[block_idx][way]++; +} + +void +lfu_t::eviction_update(int block_idx, int way) +{ + block_idx = get_block_index(block_idx); + access_counts_[block_idx][way] = 0; +} + +int +lfu_t::get_next_way_to_replace(int block_idx) +{ + // Find the way with the minimum frequency counter. + block_idx = get_block_index(block_idx); + int min_freq = access_counts_[block_idx][0]; + int min_way = 0; + for (int i = 1; i < associativity_; ++i) { + if (access_counts_[block_idx][i] < min_freq) { + min_freq = access_counts_[block_idx][i]; + min_way = i; + } + } + return min_way; +} + +std::string +lfu_t::get_name() const +{ + return "LFU"; +} + +} // namespace drmemtrace +} // namespace dynamorio diff --git a/clients/drcachesim/simulator/lfu.h b/clients/drcachesim/simulator/lfu.h new file mode 100644 index 00000000000..756b4310508 --- /dev/null +++ b/clients/drcachesim/simulator/lfu.h @@ -0,0 +1,65 @@ +/* ********************************************************** + * Copyright (c) 2015-2023 Google, Inc. All rights reserved. + * **********************************************************/ + +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Google, Inc. nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#ifndef _LFU_H_ +#define _LFU_H_ + +#include + +#include "cache_replacement_policy.h" + +namespace dynamorio { +namespace drmemtrace { + +class lfu_t : public cache_replacement_policy_t { +public: + lfu_t(int num_blocks, int associativity); + void + access_update(int block_idx, int way) override; + void + eviction_update(int block_idx, int way) override; + int + get_next_way_to_replace(int block_idx) override; + std::string + get_name() const override; + + ~lfu_t() override = default; + +private: + // Frequency counters for each way in each block. + std::vector> access_counts_; +}; + +} // namespace drmemtrace +} // namespace dynamorio + +#endif // _LFU_H_ diff --git a/clients/drcachesim/simulator/cache_lru.cpp b/clients/drcachesim/simulator/lru.cpp similarity index 50% rename from clients/drcachesim/simulator/cache_lru.cpp rename to clients/drcachesim/simulator/lru.cpp index dcefb0016f0..fb7928fbd55 100644 --- a/clients/drcachesim/simulator/cache_lru.cpp +++ b/clients/drcachesim/simulator/lru.cpp @@ -30,90 +30,67 @@ * DAMAGE. */ -#include "cache_lru.h" +#include "lru.h" -#include - -#include "cache.h" -#include "caching_device.h" -#include "caching_device_block.h" -#include "caching_device_stats.h" -#include "prefetcher.h" -#include "snoop_filter.h" +#include namespace dynamorio { namespace drmemtrace { -// For LRU implementation, we use the cache line counter to represent -// how recently a cache line is accessed. -// The count value 0 means the most recent access, and the cache line with the -// highest counter value will be picked for replacement in replace_which_way. - -bool -cache_lru_t::init(int associativity, int block_size, int total_size, - caching_device_t *parent, caching_device_stats_t *stats, - prefetcher_t *prefetcher, cache_inclusion_policy_t inclusion_policy, - bool coherent_cache, int id, snoop_filter_t *snoop_filter, - const std::vector &children) +lru_t::lru_t(int num_blocks, int associativity) + : cache_replacement_policy_t(num_blocks, associativity) { - // Works in the same way as the base class, - // except that the counters are initialized in a different way. - - bool ret_val = - cache_t::init(associativity, block_size, total_size, parent, stats, prefetcher, - inclusion_policy, coherent_cache, id, snoop_filter, children); - if (ret_val == false) - return false; - - // Initialize line counters with 0, 1, 2, ..., associativity - 1. - for (int i = 0; i < blocks_per_way_; i++) { - for (int way = 0; way < associativity_; ++way) { - get_caching_device_block(i * associativity_, way).counter_ = way; - } + // Initialize the LRU list for each block. + lru_counters_.reserve(num_blocks); + for (int i = 0; i < num_blocks; ++i) { + lru_counters_.emplace_back(associativity, 1); } - return true; } void -cache_lru_t::access_update(int block_idx, int way) +lru_t::access_update(int block_idx, int way) { - int cnt = get_caching_device_block(block_idx, way).counter_; + block_idx = get_block_index(block_idx); + int cnt = lru_counters_[block_idx][way]; // Optimization: return early if it is a repeated access. if (cnt == 0) return; // We inc all the counters that are not larger than cnt for LRU. for (int i = 0; i < associativity_; ++i) { - if (i != way && get_caching_device_block(block_idx, i).counter_ <= cnt) - get_caching_device_block(block_idx, i).counter_++; + if (i != way && lru_counters_[block_idx][i] <= cnt) + lru_counters_[block_idx][i]++; } // Clear the counter for LRU. - get_caching_device_block(block_idx, way).counter_ = 0; + lru_counters_[block_idx][way] = 0; } -int -cache_lru_t::replace_which_way(int block_idx) +void +lru_t::eviction_update(int block_idx, int way) { - return get_next_way_to_replace(block_idx); + // Nothing to update, when the way is accessed we will update it. } int -cache_lru_t::get_next_way_to_replace(int block_idx) const +lru_t::get_next_way_to_replace(int block_idx) { + block_idx = get_block_index(block_idx); // We implement LRU by picking the slot with the largest counter value. int max_counter = 0; int max_way = 0; for (int way = 0; way < associativity_; ++way) { - if (get_caching_device_block(block_idx, way).tag_ == TAG_INVALID) { - max_way = way; - break; - } - if (get_caching_device_block(block_idx, way).counter_ > max_counter) { - max_counter = get_caching_device_block(block_idx, way).counter_; + if (lru_counters_[block_idx][way] > max_counter) { + max_counter = lru_counters_[block_idx][way]; max_way = way; } } return max_way; } +std::string +lru_t::get_name() const +{ + return "LRU"; +} + } // namespace drmemtrace } // namespace dynamorio diff --git a/clients/drcachesim/simulator/lru.h b/clients/drcachesim/simulator/lru.h new file mode 100644 index 00000000000..d58c5326fa8 --- /dev/null +++ b/clients/drcachesim/simulator/lru.h @@ -0,0 +1,67 @@ +/* ********************************************************** + * Copyright (c) 2015-2023 Google, Inc. All rights reserved. + * **********************************************************/ + +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Google, Inc. nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#ifndef _LRU_H_ +#define _LRU_H_ + +#include +#include +#include + +#include "cache_replacement_policy.h" + +namespace dynamorio { +namespace drmemtrace { + +class lru_t : public cache_replacement_policy_t { +public: + lru_t(int num_blocks, int associativity); + void + access_update(int block_idx, int way) override; + void + eviction_update(int block_idx, int way) override; + int + get_next_way_to_replace(int block_idx) override; + std::string + get_name() const override; + + ~lru_t() override = default; + +private: + // LRU list for each block. + std::vector> lru_counters_; +}; + +} // namespace drmemtrace +} // namespace dynamorio + +#endif // _LRU_H_ diff --git a/clients/drcachesim/simulator/tlb.cpp b/clients/drcachesim/simulator/tlb.cpp index cade0536f93..3f672e2c171 100644 --- a/clients/drcachesim/simulator/tlb.cpp +++ b/clients/drcachesim/simulator/tlb.cpp @@ -35,11 +35,7 @@ #include #include -#include -#include -#include -#include - +#include "memref.h" #include "caching_device.h" #include "caching_device_block.h" #include "memref.h" @@ -143,62 +139,5 @@ tlb_t::request(const memref_t &memref_in) } } -tlb_lfu_t::tlb_lfu_t(const std::string &name) - : tlb_t(name) -{ -} - -std::string -tlb_lfu_t::get_replace_policy() const -{ - return REPLACE_POLICY_LFU; -} - -tlb_bit_plru_t::tlb_bit_plru_t(const std::string &name, int seed) - : tlb_t(name) - , gen_(seed == -1 ? std::random_device()() : seed) -{ -} - -void -tlb_bit_plru_t::access_update(int block_idx, int way) -{ - get_caching_device_block(block_idx, way).counter_ = 1; - for (int curr_way = 0; curr_way < associativity_; ++curr_way) { - if (get_caching_device_block(block_idx, curr_way).counter_ == 0) { - return; - } - } - for (int curr_way = 0; curr_way < associativity_; ++curr_way) { - get_caching_device_block(block_idx, curr_way).counter_ = 0; - } - get_caching_device_block(block_idx, way).counter_ = 1; -} - -int -tlb_bit_plru_t::get_next_way_to_replace(int block_idx) const -{ - std::vector zero_counter_ways; - for (int way = 0; way < associativity_; ++way) { - caching_device_block_t &curr_block = get_caching_device_block(block_idx, way); - if (curr_block.tag_ == TAG_INVALID) { - return way; - } - if (curr_block.counter_ == 0) { - zero_counter_ways.push_back(way); - } - } - if (!zero_counter_ways.empty()) { - return zero_counter_ways[gen_() % zero_counter_ways.size()]; - } - return -1; -} - -std::string -tlb_bit_plru_t::get_replace_policy() const -{ - return REPLACE_POLICY_BIT_PLRU; -} - } // namespace drmemtrace } // namespace dynamorio diff --git a/clients/drcachesim/simulator/tlb.h b/clients/drcachesim/simulator/tlb.h index e7cfdc76aa5..1b3b46d42ea 100644 --- a/clients/drcachesim/simulator/tlb.h +++ b/clients/drcachesim/simulator/tlb.h @@ -58,12 +58,6 @@ class tlb_t : public caching_device_t { // needs to be imposed on the parent methods invalidate(), contains_tag(), and // propagate_eviction() by overriding them. - // Returns the replacement policy used by this TLB. - // XXX: i#7287: This class currently has two subclasses by replacenent policy. - // We eventually want to decouple the policies from the classes. - std::string - get_replace_policy() const override = 0; - protected: void init_blocks() override; @@ -71,51 +65,6 @@ class tlb_t : public caching_device_t { memref_pid_t last_pid_; }; -/** - * TLB with least frequently used replacement policy. - * - * LFU has us hold a counter per way in the TLB entry. - * The counter is incremented when the way is accessed. - * When evicting, we choose the way with the least frequent access count. - * - * Note that the LFU logic itself is implemented - * in the parent class caching_device_t. - */ -class tlb_lfu_t : public tlb_t { -public: - tlb_lfu_t(const std::string &name = "tlb_lfu"); - - std::string - get_replace_policy() const override; -}; - -/** - * TLB with a bit-based PLRU replacement policy. - * - * Bit pseudo-LRU has us hold one bit per way in the TLB entry. - * The bit is set when the way is accessed. - * Once all bits for a block are set, we reset them all to 0. - * When evicting, we choose a random way with a zero bit to evict. - * - * When seed is -1, a seed is chosen with std::random_device(). - * XXX: Once we update our toolchains to guarantee C++17 support we - * could use std::optional here. - */ -class tlb_bit_plru_t : public tlb_t { -public: - tlb_bit_plru_t(const std::string &name = "tlb_bit_plru", int seed = -1); - - std::string - get_replace_policy() const override; - -protected: - void - access_update(int block_idx, int way) override; - int - get_next_way_to_replace(int block_idx) const override; - mutable std::mt19937 gen_; -}; - } // namespace drmemtrace } // namespace dynamorio diff --git a/clients/drcachesim/simulator/tlb_simulator.cpp b/clients/drcachesim/simulator/tlb_simulator.cpp index 45e78607471..41dbe35adb9 100644 --- a/clients/drcachesim/simulator/tlb_simulator.cpp +++ b/clients/drcachesim/simulator/tlb_simulator.cpp @@ -37,13 +37,14 @@ #include #include #include -#include +#include #include "analysis_tool.h" +#include "create_cache_replacement_policy.h" #include "memref.h" -#include "options.h" #include "utils.h" #include "caching_device_stats.h" +#include "create_cache_replacement_policy.h" #include "simulator.h" #include "tlb.h" #include "tlb_simulator_create.h" @@ -94,46 +95,56 @@ tlb_simulator_t::tlb_simulator_t(const tlb_simulator_knobs_t &knobs) lltlbs_[i] = NULL; } for (unsigned int i = 0; i < knobs_.num_cores; i++) { - itlbs_[i] = create_tlb(knobs_.TLB_replace_policy); + itlbs_[i] = new tlb_t("itlb"); if (itlbs_[i] == NULL) { error_string_ = "Failed to create itlbs_"; success_ = false; return; } - dtlbs_[i] = create_tlb(knobs_.TLB_replace_policy); + dtlbs_[i] = new tlb_t("dtlb"); if (dtlbs_[i] == NULL) { error_string_ = "Failed to create dtlbs_"; success_ = false; return; } - lltlbs_[i] = create_tlb(knobs_.TLB_replace_policy); + lltlbs_[i] = new tlb_t("lltlb"); if (lltlbs_[i] == NULL) { error_string_ = "Failed to create lltlbs_"; success_ = false; return; } - + auto replace_policy = create_cache_replacement_policy( + knobs_.TLB_replace_policy, knobs_.TLB_L1I_entries / knobs_.TLB_L1I_assoc, + knobs_.TLB_L1I_assoc); if (!itlbs_[i]->init(knobs_.TLB_L1I_assoc, (int)knobs_.page_size, knobs_.TLB_L1I_entries, lltlbs_[i], - new tlb_stats_t((int)knobs_.page_size))) { + new tlb_stats_t((int)knobs_.page_size), + std::move(replace_policy))) { error_string_ = "Usage error: failed to initialize itlbs_. Ensure (entry number / " "associativity) is a power of 2."; success_ = false; return; } + replace_policy = create_cache_replacement_policy( + knobs_.TLB_replace_policy, knobs_.TLB_L1D_entries / knobs_.TLB_L1D_assoc, + knobs_.TLB_L1D_assoc); if (!dtlbs_[i]->init(knobs_.TLB_L1D_assoc, (int)knobs_.page_size, knobs_.TLB_L1D_entries, lltlbs_[i], - new tlb_stats_t((int)knobs_.page_size))) { + new tlb_stats_t((int)knobs_.page_size), + std::move(replace_policy))) { error_string_ = "Usage error: failed to initialize dtlbs_. Ensure (entry number / " "associativity) is a power of 2."; success_ = false; return; } - if (!lltlbs_[i]->init(knobs_.TLB_L2_assoc, (int)knobs_.page_size, - knobs_.TLB_L2_entries, NULL, - new tlb_stats_t((int)knobs_.page_size))) { + replace_policy = create_cache_replacement_policy( + knobs_.TLB_replace_policy, knobs_.TLB_L2_entries / knobs_.TLB_L2_assoc, + knobs_.TLB_L2_assoc); + if (!lltlbs_[i]->init( + knobs_.TLB_L2_assoc, (int)knobs_.page_size, knobs_.TLB_L2_entries, NULL, + new tlb_stats_t((int)knobs_.page_size), std::move(replace_policy))) { error_string_ = "Usage error: failed to initialize lltlbs_. Ensure (entry number / " "associativity) is a power of 2."; @@ -292,22 +303,5 @@ tlb_simulator_t::print_results() return true; } -tlb_t * -tlb_simulator_t::create_tlb(std::string policy) -{ - // XXX: i#7287: Eventually we want to decouple the replacement policies from the cache - // classes. Once this happens, we will need to build the policies here and pass them - // to the TLB class. We have implemented this as a temporary solution. - if (policy == REPLACE_POLICY_NON_SPECIFIED || // default LFU - policy == REPLACE_POLICY_LFU) // set to LFU - return new tlb_lfu_t; - else if (policy == REPLACE_POLICY_BIT_PLRU) - return new tlb_bit_plru_t; - // undefined replacement policy - ERRMSG("Usage error: undefined replacement policy. " - "Please choose " REPLACE_POLICY_LFU " or " REPLACE_POLICY_BIT_PLRU ".\n"); - return NULL; -} - } // namespace drmemtrace } // namespace dynamorio diff --git a/clients/drcachesim/simulator/tlb_simulator.h b/clients/drcachesim/simulator/tlb_simulator.h index b8a82499da9..e8f8f9b133e 100644 --- a/clients/drcachesim/simulator/tlb_simulator.h +++ b/clients/drcachesim/simulator/tlb_simulator.h @@ -39,6 +39,7 @@ #include #include +#include "cache_replacement_policy.h" #include "memref.h" #include "simulator.h" #include "tlb.h" @@ -60,10 +61,6 @@ class tlb_simulator_t : public simulator_t { create_v2p_from_file(std::istream &v2p_file) override; protected: - // Create a tlb_t object with a specific replacement policy. - virtual tlb_t * - create_tlb(std::string policy); - tlb_simulator_knobs_t knobs_; // Each CPU core contains a L1 ITLB, L1 DTLB and L2 TLB. diff --git a/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp b/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp index a78ec720cff..e3bb6bef94c 100644 --- a/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp +++ b/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp @@ -34,10 +34,14 @@ #include #undef NDEBUG #include +#include #include #include "cache_replacement_policy_unit_test.h" -#include "simulator/cache_fifo.h" -#include "simulator/cache_lru.h" +#include "simulator/bit_plru.h" +#include "simulator/cache.h" +#include "simulator/fifo.h" +#include "simulator/lfu.h" +#include "simulator/lru.h" #include "simulator/tlb.h" namespace dynamorio { @@ -86,8 +90,7 @@ template class caching_device_policy_test_t : public T { ref.data.addr = addr; ref.data.pid = 1; this->request(ref); - assert(this->get_next_way_to_replace(this->get_block_index(addr)) == - expected_replacement_way_after_access); + assert(this->get_next_way_to_replace(this->get_block_index(addr)) == expected_replacement_way_after_access); } void @@ -127,72 +130,32 @@ template class caching_device_policy_test_t : public T { } return true; } -}; - -template class cache_policy_test_t : public caching_device_policy_test_t { - int total_size_; - -public: - cache_policy_test_t(int associativity, int line_size, int total_size) - : caching_device_policy_test_t(associativity, line_size) - , total_size_(total_size) - { - } + // Note that caches expect size as total size, while TLBs expect size as + // number of entries. void - initialize_cache() + initialize_cache(std::unique_ptr replacement_policy, + int size) { caching_device_stats_t *stats = new cache_stats_t(this->line_size_, /*miss_file=*/"", /*warmup_enabled=*/true); - if (!this->init(this->associativity_, this->line_size_, total_size_, nullptr, - stats, nullptr)) { + if (!this->init(this->associativity_, this->line_size_, size, nullptr, stats, + std::move(replacement_policy), nullptr)) { std::cerr << this->get_replace_policy() << " cache failed to initialize\n"; exit(1); } } }; -template class tlb_policy_test_t : public caching_device_policy_test_t { - int entries_; - -public: - tlb_policy_test_t(int associativity, int line_size, int entries) - : caching_device_policy_test_t(associativity, line_size) - , entries_(entries) - { - } - - void - initialize_cache() - { - caching_device_stats_t *stats = - new cache_stats_t(this->line_size_, /*miss_file=*/"", - /*warmup_enabled=*/true); - if (!this->init(this->associativity_, this->line_size_, entries_, nullptr, - stats)) { - std::cerr << this->get_replace_policy() << " tlb failed to initialize\n"; - exit(1); - } - } -}; - -template class seeded_tlb_policy_test_t : public tlb_policy_test_t { -public: - seeded_tlb_policy_test_t(int associativity, int line_size, int entries) - : tlb_policy_test_t(associativity, line_size, entries) - { - this->gen_ = std::mt19937(0); - } -}; - void unit_test_cache_lru_four_way() { - cache_policy_test_t cache_lru_test(/*associativity=*/4, - /*line_size=*/32, - /*total_size=*/256); - cache_lru_test.initialize_cache(); + caching_device_policy_test_t cache_lru_test(/*associativity=*/4, + /*line_size=*/32); + cache_lru_test.initialize_cache( + std::unique_ptr(new lru_t(/*num_blocks=*/256 / 4, /*associativity=*/4)), + 256); assert(cache_lru_test.get_replace_policy() == "LRU"); assert(cache_lru_test.block_indices_are_identical(addr_vec)); @@ -228,10 +191,11 @@ unit_test_cache_lru_four_way() void unit_test_cache_lru_eight_way() { - cache_policy_test_t cache_lru_test(/*associativity=*/8, - /*line_size=*/64, - /*total_size=*/1024); - cache_lru_test.initialize_cache(); + caching_device_policy_test_t cache_lru_test(/*associativity=*/8, + /*line_size=*/64); + cache_lru_test.initialize_cache( + std::unique_ptr(new lru_t(/*num_blocks=*/1024 / 8, /*associativity=*/8)), + 1024); assert(cache_lru_test.get_replace_policy() == "LRU"); assert(cache_lru_test.block_indices_are_identical(addr_vec)); @@ -274,10 +238,11 @@ unit_test_cache_lru_eight_way() void unit_test_cache_fifo_four_way() { - cache_policy_test_t cache_fifo_test(/*associativity=*/4, - /*line_size=*/32, - /*total_size=*/256); - cache_fifo_test.initialize_cache(); + caching_device_policy_test_t cache_fifo_test(/*associativity=*/4, + /*line_size=*/32); + cache_fifo_test.initialize_cache( + std::unique_ptr(new fifo_t(/*num_blocks=*/256 / 4, /*associativity=*/4)), + 256); assert(cache_fifo_test.get_replace_policy() == "FIFO"); assert(cache_fifo_test.block_indices_are_identical(addr_vec)); @@ -299,27 +264,28 @@ unit_test_cache_fifo_four_way() cache_fifo_test.access_and_check(addr_vec[ADDR_H], 0); // e F G H cache_fifo_test.access_and_check(addr_vec[ADDR_A], 1); // A f G H - cache_fifo_test.invalidate_and_check(addr_vec[ADDR_G], 1); // A f X H + cache_fifo_test.invalidate_and_check(addr_vec[ADDR_G], 2); // A F x H - cache_fifo_test.access_and_check(addr_vec[ADDR_G], 2); // A G x H - cache_fifo_test.access_and_check(addr_vec[ADDR_B], 3); // A G B h + cache_fifo_test.access_and_check(addr_vec[ADDR_G], 1); // A f G H + cache_fifo_test.access_and_check(addr_vec[ADDR_B], 3); // A B G h - cache_fifo_test.invalidate_and_check(addr_vec[ADDR_H], 3); // A G B x - cache_fifo_test.invalidate_and_check(addr_vec[ADDR_A], 3); // X G B x + cache_fifo_test.invalidate_and_check(addr_vec[ADDR_H], 3); // A B G x + cache_fifo_test.invalidate_and_check(addr_vec[ADDR_A], 0); // x B G X - cache_fifo_test.access_and_check(addr_vec[ADDR_A], 0); // x G B A - cache_fifo_test.access_and_check(addr_vec[ADDR_B], 0); // x G B A - cache_fifo_test.access_and_check(addr_vec[ADDR_C], 1); // C g B A - cache_fifo_test.access_and_check(addr_vec[ADDR_D], 2); // C D B A + cache_fifo_test.access_and_check(addr_vec[ADDR_A], 3); // A B G x + cache_fifo_test.access_and_check(addr_vec[ADDR_B], 3); // A B G x + cache_fifo_test.access_and_check(addr_vec[ADDR_C], 2); // A B g C + cache_fifo_test.access_and_check(addr_vec[ADDR_D], 1); // A b D C } void unit_test_cache_fifo_eight_way() { - cache_policy_test_t cache_fifo_test(/*associativity=*/8, - /*line_size=*/64, - /*total_size=*/1024); - cache_fifo_test.initialize_cache(); + caching_device_policy_test_t cache_fifo_test(/*associativity=*/8, + /*line_size=*/64); + cache_fifo_test.initialize_cache( + std::unique_ptr(new fifo_t(/*num_blocks=*/1024 / 8, /*associativity=*/8)), + 1024); assert(cache_fifo_test.get_replace_policy() == "FIFO"); assert(cache_fifo_test.block_indices_are_identical(addr_vec)); @@ -344,22 +310,23 @@ unit_test_cache_fifo_eight_way() cache_fifo_test.access_and_check(addr_vec[ADDR_L], 4); // I J K L e F G H cache_fifo_test.access_and_check(addr_vec[ADDR_L], 4); // I J K L e F G H - cache_fifo_test.invalidate_and_check(addr_vec[ADDR_G], 4); // I J K L e F X H - cache_fifo_test.invalidate_and_check(addr_vec[ADDR_K], 4); // I J X L e F X H + cache_fifo_test.invalidate_and_check(addr_vec[ADDR_G], 6); // I J K L R F x H + cache_fifo_test.invalidate_and_check(addr_vec[ADDR_K], 2); // I J x L E F X H - cache_fifo_test.access_and_check(addr_vec[ADDR_A], 5); // I J K L A f G H - cache_fifo_test.access_and_check(addr_vec[ADDR_B], 6); // I J K L A B g H - cache_fifo_test.access_and_check(addr_vec[ADDR_C], 7); // I J K L A B C h - cache_fifo_test.access_and_check(addr_vec[ADDR_D], 0); // i J K L A B C D + cache_fifo_test.access_and_check(addr_vec[ADDR_A], 6); // I J A L E F x H + cache_fifo_test.access_and_check(addr_vec[ADDR_B], 4); // I J K L e F B H + cache_fifo_test.access_and_check(addr_vec[ADDR_C], 5); // i J K L C f B H + cache_fifo_test.access_and_check(addr_vec[ADDR_D], 7); // I j K L C D b H } void unit_test_cache_lfu_four_way() { - cache_policy_test_t cache_lfu_test(/*associativity=*/4, - /*line_size=*/32, - /*total_size=*/256); - cache_lfu_test.initialize_cache(); + caching_device_policy_test_t cache_lfu_test(/*associativity=*/4, + /*line_size=*/32); + cache_lfu_test.initialize_cache( + std::unique_ptr(new lfu_t(/*num_blocks=*/256 / 4, /*associativity=*/4)), + 256); assert(cache_lfu_test.get_replace_policy() == "LFU"); assert(cache_lfu_test.block_indices_are_identical(addr_vec)); @@ -396,10 +363,11 @@ unit_test_cache_lfu_four_way() void unit_test_cache_lfu_eight_way() { - cache_policy_test_t cache_lfu_test(/*associativity=*/8, - /*line_size=*/64, - /*total_size=*/1024); - cache_lfu_test.initialize_cache(); + caching_device_policy_test_t cache_lfu_test(/*associativity=*/8, + /*line_size=*/64); + cache_lfu_test.initialize_cache( + std::unique_ptr(new lfu_t(/*num_blocks=*/1024 / 8, /*associativity=*/8)), + 1024); assert(cache_lfu_test.get_replace_policy() == "LFU"); assert(cache_lfu_test.block_indices_are_identical(addr_vec)); @@ -443,10 +411,12 @@ unit_test_cache_lfu_eight_way() void unit_test_tlb_plru_four_way() { - seeded_tlb_policy_test_t tlb_plru_test(/*associativity=*/4, - /*line_size=*/64, - /*entries=*/4); - tlb_plru_test.initialize_cache(); + caching_device_policy_test_t tlb_plru_test(/*associativity=*/4, + /*line_size=*/64); + tlb_plru_test.initialize_cache( + std::unique_ptr( + new bit_plru_t(4 /*num_blocks*/, 4 /*associativity*/, 0 /*seed*/)), + 4); assert(tlb_plru_test.get_replace_policy() == "BIT_PLRU"); assert(tlb_plru_test.block_indices_are_identical(addr_vec)); assert(tlb_plru_test.tags_are_different(addr_vec)); @@ -465,10 +435,10 @@ unit_test_tlb_plru_four_way() void unit_test_tlb_lfu_four_way() { - tlb_policy_test_t tlb_lfu_test(/*associativity=*/4, - /*line_size=*/64, - /*entries=*/4); - tlb_lfu_test.initialize_cache(); + caching_device_policy_test_t tlb_lfu_test(/*associativity=*/4, + /*line_size=*/64); + tlb_lfu_test.initialize_cache( + std::unique_ptr(new lfu_t(4 /*num_blocks*/, 4 /*associativity*/)), 4); assert(tlb_lfu_test.get_replace_policy() == "LFU"); assert(tlb_lfu_test.block_indices_are_identical(addr_vec)); assert(tlb_lfu_test.tags_are_different(addr_vec)); diff --git a/clients/drcachesim/tests/drcachesim_unit_tests.cpp b/clients/drcachesim/tests/drcachesim_unit_tests.cpp index a0b8878f1cd..9d2642f7f30 100644 --- a/clients/drcachesim/tests/drcachesim_unit_tests.cpp +++ b/clients/drcachesim/tests/drcachesim_unit_tests.cpp @@ -43,8 +43,9 @@ #include "tlb_simulator_unit_test.h" #include "cache_replacement_policy_unit_test.h" #include "simulator/cache.h" -#include "simulator/cache_lru.h" #include "simulator/cache_simulator.h" +#include "simulator/lfu.h" +#include "simulator/lru.h" #include "simulator/prefetcher.h" #include "../common/memref.h" #include "../common/utils.h" @@ -446,9 +447,9 @@ LLC { class test_cache_simulator_t : public cache_simulator_t { public: test_cache_simulator_t(const cache_simulator_knobs_t &knobs) - : cache_simulator_t(knobs) {}; + : cache_simulator_t(knobs) { }; test_cache_simulator_t(std::istream *config_file) - : cache_simulator_t(config_file) {}; + : cache_simulator_t(config_file) { }; // Returns cache_t* for named cache if it exists, else faults. cache_t * get_named_cache(std::string name) @@ -575,7 +576,6 @@ LLC { TEST_EQ(new_l2_misses - l2_misses, NUM_LOOPS * MORE_CONFLICTING_ADDRESSES - CONFLICTING_ADDRESSES); TEST_EQ(new_l2_hits - l2_hits, CONFLICTING_ADDRESSES); - TEST_EQ(new_llc_misses - llc_misses, MORE_CONFLICTING_ADDRESSES - CONFLICTING_ADDRESSES); TEST_EQ(new_llc_hits - llc_hits, (NUM_LOOPS - 1) * MORE_CONFLICTING_ADDRESSES); @@ -652,10 +652,11 @@ unit_test_cache_associativity() int total_size = LINE_SIZE * BLOCKS_PER_WAY * assoc; // Test access patterns that stress increasing associativity. for (uint32_t test_assoc = 1; test_assoc <= 2 * assoc; ++test_assoc) { - cache_lru_t cache; + cache_t cache; caching_device_stats_t stats(/*miss_file=*/"", LINE_SIZE); bool initialized = - cache.init(assoc, LINE_SIZE, total_size, /*parent=*/nullptr, &stats); + cache.init(assoc, LINE_SIZE, total_size, /*parent=*/nullptr, &stats, + std::unique_ptr(new lru_t(total_size / assoc, assoc))); assert(initialized); assert(cache.get_associativity() == assoc); // Test start address is arbitrary. @@ -701,10 +702,13 @@ unit_test_cache_size() // Access a buffer of increasing size, make sure hits + misses are expected. for (int buffer_size = cache_size / 2; buffer_size < cache_size * 2; buffer_size *= 2) { - cache_lru_t cache; + cache_t cache; caching_device_stats_t stats(/*miss_file=*/"", LINE_SIZE); - bool initialized = cache.init(associativity, LINE_SIZE, cache_size, - /*parent=*/nullptr, &stats); + bool initialized = + cache.init(associativity, LINE_SIZE, cache_size, + /*parent=*/nullptr, &stats, + std::unique_ptr( + new lru_t(cache_size / associativity, associativity))); assert(initialized); assert(cache.get_size_bytes() == cache_size); static constexpr int NUM_LOOPS = 3; // Anything >=2 should work. @@ -753,8 +757,11 @@ unit_test_cache_line_size() int total_cache_size = line_size * cache_line_count; cache_t cache; caching_device_stats_t stats(/*miss_file=*/"", line_size); - bool initialized = cache.init(ASSOCIATIVITY, line_size, total_cache_size, - /*parent=*/nullptr, &stats); + bool initialized = + cache.init(ASSOCIATIVITY, line_size, total_cache_size, + /*parent=*/nullptr, &stats, + std::unique_ptr(new lfu_t( + total_cache_size / ASSOCIATIVITY, ASSOCIATIVITY))); assert(initialized); auto read_count = generate_1D_accesses(cache, 0, stride, total_cache_size / stride); @@ -794,16 +801,33 @@ unit_test_cache_bad_configs() // 0 values are bad for any of these parameters. std::cerr << "Testing 0 parameters.\n"; - assert(!cache.init(0, SAFE_LINE_SIZE, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats)); - assert(!cache.init(SAFE_ASSOC, 0, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats)); - assert(!cache.init(SAFE_ASSOC, SAFE_LINE_SIZE, 0, /*parent=*/nullptr, &stats)); + + assert(!cache.init( + 0, SAFE_LINE_SIZE, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, + std::unique_ptr(new lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); + assert(!cache.init( + SAFE_ASSOC, 0, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, + std::unique_ptr(new lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); + assert(!cache.init( + SAFE_ASSOC, SAFE_LINE_SIZE, 0, /*parent=*/nullptr, &stats, + std::unique_ptr(new lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); + assert(!cache.init(SAFE_ASSOC, SAFE_LINE_SIZE, SAFE_CACHE_SIZE, /*parent=*/nullptr, + &stats, nullptr)); // Test other bad line sizes: <4 and/or non-power-of-two. std::cerr << "Testing bad line size parameters.\n"; - assert(!cache.init(SAFE_ASSOC, 1, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats)); - assert(!cache.init(SAFE_ASSOC, 2, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats)); - assert(!cache.init(SAFE_ASSOC, 7, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats)); - assert(!cache.init(SAFE_ASSOC, 65, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats)); + assert(!cache.init( + SAFE_ASSOC, 1, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, + std::unique_ptr(new lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); + assert(!cache.init( + SAFE_ASSOC, 2, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, + std::unique_ptr(new lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); + assert(!cache.init( + SAFE_ASSOC, 7, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, + std::unique_ptr(new lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); + assert(!cache.init( + SAFE_ASSOC, 65, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, + std::unique_ptr(new lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); // Size, associativity, and line_size are related. The requirement is that // size/associativity is a power-of-two, and >= line_size, so try some @@ -816,8 +840,9 @@ unit_test_cache_bad_configs() { 3, 1024 }, { 4, 768 }, { 64, 64 }, { 16, 8 * SAFE_LINE_SIZE } }; for (const auto &combo : bad_combinations) { - assert(!cache.init(combo.assoc, SAFE_LINE_SIZE, combo.size, /*parent=*/nullptr, - &stats)); + assert(!cache.init( + combo.assoc, SAFE_LINE_SIZE, combo.size, /*parent=*/nullptr, &stats, + std::unique_ptr(new lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); } } @@ -848,10 +873,14 @@ unit_test_cache_accessors() caching_device_stats_t stats(/*miss_file=*/"", line_size); // Only test LRU here. Other replacement policy accessors are // tested in the cache_replacement_policy_unit_test. - cache_lru_t cache(cache_name); - bool initialized = cache.init(associativity, line_size, total_size, - /*parent=*/nullptr, &stats, - /*prefetcher=*/nullptr, policy, coherent); + cache_t cache(cache_name); + bool initialized = + cache.init(associativity, line_size, total_size, + /*parent=*/nullptr, &stats, + /*replacement_policy=*/ + std::unique_ptr( + new lru_t(total_size / associativity, associativity)), + /*prefetcher=*/nullptr, policy, coherent); assert(initialized); assert(cache.get_stats() == &stats); assert(stats.get_caching_device() == &cache); @@ -941,6 +970,7 @@ test_main(int argc, const char *argv[]) // Takes in a path to the tests/ src dir. assert(argc == 2); + unit_test_cache_replacement_policy(); unit_test_exclusive_cache(); unit_test_cache_accessors(); unit_test_config_reader(std::string(argv[1])); @@ -956,7 +986,6 @@ test_main(int argc, const char *argv[]) unit_test_warmup_refs(); unit_test_sim_refs(); unit_test_child_hits(); - unit_test_cache_replacement_policy(); unit_test_core_sharded(); unit_test_nextline_prefetcher(); unit_test_custom_prefetcher(); diff --git a/clients/drcachesim/tools/filter/cache_filter.cpp b/clients/drcachesim/tools/filter/cache_filter.cpp index 470bc3b958f..62fc41fba8d 100644 --- a/clients/drcachesim/tools/filter/cache_filter.cpp +++ b/clients/drcachesim/tools/filter/cache_filter.cpp @@ -34,12 +34,13 @@ #include -#include "cache_lru.h" -#include "memref.h" -#include "memtrace_stream.h" +#include "cache.h" #include "cache_stats.h" #include "caching_device_block.h" #include "caching_device_stats.h" +#include "lru.h" +#include "memref.h" +#include "memtrace_stream.h" #include "trace_entry.h" namespace dynamorio { @@ -70,7 +71,7 @@ class cache_filter_stats_t : public cache_stats_t { }; struct per_shard_t { - cache_lru_t cache; + cache_t cache; }; void * @@ -80,6 +81,7 @@ cache_filter_t::parallel_shard_init(memtrace_stream_t *shard_stream, per_shard_t *per_shard = new per_shard_t; if (!(per_shard->cache.init(cache_associativity_, cache_line_size_, cache_size_, nullptr, new cache_filter_stats_t(cache_line_size_), + std::unique_ptr(new lru_t(cache_size_ / cache_associativity_, cache_associativity_)), nullptr))) { error_string_ = "Failed to initialize cache."; return nullptr; From 90afe0daf1c948929e3e808272fff868bbcd2764 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Sun, 2 Mar 2025 13:20:38 +0000 Subject: [PATCH 13/42] Self CR fixes --- clients/drcachesim/common/options.cpp | 3 ++- clients/drcachesim/simulator/bit_plru.cpp | 2 +- clients/drcachesim/simulator/caching_device.cpp | 3 +-- clients/drcachesim/simulator/caching_device.h | 6 ------ clients/drcachesim/simulator/lru.cpp | 6 +++--- .../drcachesim/tests/cache_replacement_policy_unit_test.cpp | 4 ++-- clients/drcachesim/tests/drcachesim_unit_tests.cpp | 2 +- 7 files changed, 10 insertions(+), 16 deletions(-) diff --git a/clients/drcachesim/common/options.cpp b/clients/drcachesim/common/options.cpp index 6d111ccedd2..55e1b9bf846 100644 --- a/clients/drcachesim/common/options.cpp +++ b/clients/drcachesim/common/options.cpp @@ -503,7 +503,8 @@ droption_t "Supported policies: " REPLACE_POLICY_LFU " (Least Frequently Used), " REPLACE_POLICY_BIT_PLRU " (Pseudo Least Recently Used) " REPLACE_POLICY_LRU - " (Least Recently Used)"); + " (Least Recently Used) " REPLACE_POLICY_FIFO + " (First-In-First-Out)"); droption_t op_tool(DROPTION_SCOPE_FRONTEND, diff --git a/clients/drcachesim/simulator/bit_plru.cpp b/clients/drcachesim/simulator/bit_plru.cpp index d296d2d0550..d71cfb31daf 100644 --- a/clients/drcachesim/simulator/bit_plru.cpp +++ b/clients/drcachesim/simulator/bit_plru.cpp @@ -83,7 +83,7 @@ bit_plru_t::get_next_way_to_replace(int block_idx) block_idx = get_block_index(block_idx); std::vector unset_bits; for (int i = 0; i < associativity_; ++i) { - if (block_bits_[block_idx][i] == 0) { + if (!block_bits_[block_idx][i]) { unset_bits.push_back(i); } } diff --git a/clients/drcachesim/simulator/caching_device.cpp b/clients/drcachesim/simulator/caching_device.cpp index 01e873c664a..56d1835ba3e 100644 --- a/clients/drcachesim/simulator/caching_device.cpp +++ b/clients/drcachesim/simulator/caching_device.cpp @@ -210,8 +210,7 @@ caching_device_t::request(const memref_t &memref_in) snoop_filter_->snoop(tag, id_, (memref.data.type == TRACE_TYPE_WRITE)); } else if (parent_ != NULL) { - // On a miss, the parent access will inherently propagate the - // write. + // On a miss, the parent access will inherently propagate the write. parent_->propagate_write(tag, this); } } diff --git a/clients/drcachesim/simulator/caching_device.h b/clients/drcachesim/simulator/caching_device.h index 8d8cc43572f..a8ddead7ee5 100644 --- a/clients/drcachesim/simulator/caching_device.h +++ b/clients/drcachesim/simulator/caching_device.h @@ -113,12 +113,6 @@ class caching_device_t { { return parent_; } - void - set_parent(caching_device_t *parent) - { - parent_ = parent; - parent_->children_.push_back(this); - } inline double get_loaded_fraction() const { diff --git a/clients/drcachesim/simulator/lru.cpp b/clients/drcachesim/simulator/lru.cpp index fb7928fbd55..bd7b608d1c5 100644 --- a/clients/drcachesim/simulator/lru.cpp +++ b/clients/drcachesim/simulator/lru.cpp @@ -51,13 +51,13 @@ void lru_t::access_update(int block_idx, int way) { block_idx = get_block_index(block_idx); - int cnt = lru_counters_[block_idx][way]; + int count = lru_counters_[block_idx][way]; // Optimization: return early if it is a repeated access. - if (cnt == 0) + if (count == 0) return; // We inc all the counters that are not larger than cnt for LRU. for (int i = 0; i < associativity_; ++i) { - if (i != way && lru_counters_[block_idx][i] <= cnt) + if (i != way && lru_counters_[block_idx][i] <= count) lru_counters_[block_idx][i]++; } // Clear the counter for LRU. diff --git a/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp b/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp index e3bb6bef94c..084cb00ecbd 100644 --- a/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp +++ b/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp @@ -415,7 +415,7 @@ unit_test_tlb_plru_four_way() /*line_size=*/64); tlb_plru_test.initialize_cache( std::unique_ptr( - new bit_plru_t(4 /*num_blocks*/, 4 /*associativity*/, 0 /*seed*/)), + new bit_plru_t(1 /*num_blocks*/, 4 /*associativity*/, 0 /*seed*/)), 4); assert(tlb_plru_test.get_replace_policy() == "BIT_PLRU"); assert(tlb_plru_test.block_indices_are_identical(addr_vec)); @@ -438,7 +438,7 @@ unit_test_tlb_lfu_four_way() caching_device_policy_test_t tlb_lfu_test(/*associativity=*/4, /*line_size=*/64); tlb_lfu_test.initialize_cache( - std::unique_ptr(new lfu_t(4 /*num_blocks*/, 4 /*associativity*/)), 4); + std::unique_ptr(new lfu_t(1 /*num_blocks*/, 4 /*associativity*/)), 4); assert(tlb_lfu_test.get_replace_policy() == "LFU"); assert(tlb_lfu_test.block_indices_are_identical(addr_vec)); assert(tlb_lfu_test.tags_are_different(addr_vec)); diff --git a/clients/drcachesim/tests/drcachesim_unit_tests.cpp b/clients/drcachesim/tests/drcachesim_unit_tests.cpp index 9d2642f7f30..6cedd442699 100644 --- a/clients/drcachesim/tests/drcachesim_unit_tests.cpp +++ b/clients/drcachesim/tests/drcachesim_unit_tests.cpp @@ -970,7 +970,6 @@ test_main(int argc, const char *argv[]) // Takes in a path to the tests/ src dir. assert(argc == 2); - unit_test_cache_replacement_policy(); unit_test_exclusive_cache(); unit_test_cache_accessors(); unit_test_config_reader(std::string(argv[1])); @@ -986,6 +985,7 @@ test_main(int argc, const char *argv[]) unit_test_warmup_refs(); unit_test_sim_refs(); unit_test_child_hits(); + unit_test_cache_replacement_policy(); unit_test_core_sharded(); unit_test_nextline_prefetcher(); unit_test_custom_prefetcher(); From c613e38f4e4bd844c5cb012070e46e9386c60dff Mon Sep 17 00:00:00 2001 From: Or Almer Date: Sun, 2 Mar 2025 13:30:28 +0000 Subject: [PATCH 14/42] remove get parent --- clients/drcachesim/simulator/caching_device.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/clients/drcachesim/simulator/caching_device.h b/clients/drcachesim/simulator/caching_device.h index 6476e958c2b..e0ba9ae733b 100644 --- a/clients/drcachesim/simulator/caching_device.h +++ b/clients/drcachesim/simulator/caching_device.h @@ -110,12 +110,6 @@ class caching_device_t { { return parent_; } - void - set_parent(caching_device_t *parent) - { - parent_ = parent; - parent_->children_.push_back(this); - } inline double get_loaded_fraction() const { From 36ff2d8ecf4a9651f49c318912e2d2143f777a83 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Sun, 2 Mar 2025 14:04:08 +0000 Subject: [PATCH 15/42] formatting --- clients/drcachesim/simulator/bit_plru.h | 2 +- clients/drcachesim/simulator/fifo.h | 2 +- clients/drcachesim/simulator/lfu.h | 2 +- clients/drcachesim/simulator/lru.h | 2 +- .../drcachesim/tests/cache_replacement_policy_unit_test.cpp | 3 ++- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/clients/drcachesim/simulator/bit_plru.h b/clients/drcachesim/simulator/bit_plru.h index c335dfca822..b8e2087e65e 100644 --- a/clients/drcachesim/simulator/bit_plru.h +++ b/clients/drcachesim/simulator/bit_plru.h @@ -66,4 +66,4 @@ class bit_plru_t : public cache_replacement_policy_t { } // namespace drmemtrace } // namespace dynamorio -#endif // _BIT_PLRU_H_ +#endif /* _BIT_PLRU_H_ */ diff --git a/clients/drcachesim/simulator/fifo.h b/clients/drcachesim/simulator/fifo.h index 52bca2c512a..73f31d5e373 100644 --- a/clients/drcachesim/simulator/fifo.h +++ b/clients/drcachesim/simulator/fifo.h @@ -64,4 +64,4 @@ class fifo_t : public cache_replacement_policy_t { } // namespace drmemtrace } // namespace dynamorio -#endif // _FIFO_H_ +#endif /* _FIFO_H_ */ diff --git a/clients/drcachesim/simulator/lfu.h b/clients/drcachesim/simulator/lfu.h index 756b4310508..c7c18eefb31 100644 --- a/clients/drcachesim/simulator/lfu.h +++ b/clients/drcachesim/simulator/lfu.h @@ -62,4 +62,4 @@ class lfu_t : public cache_replacement_policy_t { } // namespace drmemtrace } // namespace dynamorio -#endif // _LFU_H_ +#endif /* _LFU_H_ */ diff --git a/clients/drcachesim/simulator/lru.h b/clients/drcachesim/simulator/lru.h index d58c5326fa8..6a5e500f0b9 100644 --- a/clients/drcachesim/simulator/lru.h +++ b/clients/drcachesim/simulator/lru.h @@ -64,4 +64,4 @@ class lru_t : public cache_replacement_policy_t { } // namespace drmemtrace } // namespace dynamorio -#endif // _LRU_H_ +#endif /* _LRU_H_ */ diff --git a/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp b/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp index 084cb00ecbd..57ce4932af6 100644 --- a/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp +++ b/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp @@ -90,7 +90,8 @@ template class caching_device_policy_test_t : public T { ref.data.addr = addr; ref.data.pid = 1; this->request(ref); - assert(this->get_next_way_to_replace(this->get_block_index(addr)) == expected_replacement_way_after_access); + assert(this->get_next_way_to_replace(this->get_block_index(addr)) == + expected_replacement_way_after_access); } void From a61e2515254678ca3b90ce810135389574f61cd5 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Sun, 2 Mar 2025 14:06:17 +0000 Subject: [PATCH 16/42] formatting --- clients/drcachesim/tools/filter/cache_filter.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/clients/drcachesim/tools/filter/cache_filter.cpp b/clients/drcachesim/tools/filter/cache_filter.cpp index 62fc41fba8d..764d559170b 100644 --- a/clients/drcachesim/tools/filter/cache_filter.cpp +++ b/clients/drcachesim/tools/filter/cache_filter.cpp @@ -79,10 +79,12 @@ cache_filter_t::parallel_shard_init(memtrace_stream_t *shard_stream, bool partial_trace_filter) { per_shard_t *per_shard = new per_shard_t; - if (!(per_shard->cache.init(cache_associativity_, cache_line_size_, cache_size_, - nullptr, new cache_filter_stats_t(cache_line_size_), - std::unique_ptr(new lru_t(cache_size_ / cache_associativity_, cache_associativity_)), - nullptr))) { + if (!(per_shard->cache.init( + cache_associativity_, cache_line_size_, cache_size_, nullptr, + new cache_filter_stats_t(cache_line_size_), + std::unique_ptr( + new lru_t(cache_size_ / cache_associativity_, cache_associativity_)), + nullptr))) { error_string_ = "Failed to initialize cache."; return nullptr; } From 4cec4df7ab008909875b74eb4030dcc18c438d5b Mon Sep 17 00:00:00 2001 From: Or Almer Date: Sun, 2 Mar 2025 14:12:36 +0000 Subject: [PATCH 17/42] formatting --- clients/drcachesim/tests/drcachesim_unit_tests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clients/drcachesim/tests/drcachesim_unit_tests.cpp b/clients/drcachesim/tests/drcachesim_unit_tests.cpp index 6cedd442699..9ebb2ac1cbe 100644 --- a/clients/drcachesim/tests/drcachesim_unit_tests.cpp +++ b/clients/drcachesim/tests/drcachesim_unit_tests.cpp @@ -447,9 +447,9 @@ LLC { class test_cache_simulator_t : public cache_simulator_t { public: test_cache_simulator_t(const cache_simulator_knobs_t &knobs) - : cache_simulator_t(knobs) { }; + : cache_simulator_t(knobs) {}; test_cache_simulator_t(std::istream *config_file) - : cache_simulator_t(config_file) { }; + : cache_simulator_t(config_file) {}; // Returns cache_t* for named cache if it exists, else faults. cache_t * get_named_cache(std::string name) From dce8dfe147808331130b8d090df5614d5135f152 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Mon, 3 Mar 2025 06:54:47 +0000 Subject: [PATCH 18/42] Update total_size and num_lines types to int64_t --- api/docs/release.dox | 4 ++-- clients/drcachesim/simulator/cache.cpp | 9 ++------- clients/drcachesim/simulator/cache.h | 5 +++-- clients/drcachesim/simulator/cache_fifo.cpp | 2 +- clients/drcachesim/simulator/cache_fifo.h | 5 +++-- clients/drcachesim/simulator/cache_lru.cpp | 2 +- clients/drcachesim/simulator/cache_lru.h | 5 +++-- clients/drcachesim/simulator/caching_device.cpp | 2 +- clients/drcachesim/simulator/caching_device.h | 15 ++++++++------- 9 files changed, 24 insertions(+), 25 deletions(-) diff --git a/api/docs/release.dox b/api/docs/release.dox index 33167c035bd..419a533bf7d 100644 --- a/api/docs/release.dox +++ b/api/docs/release.dox @@ -126,8 +126,8 @@ clients. The changes between version \DR_VERSION and 11.3.0 include the following compatibility changes: - - Changed the type of `block_size` to `int64_t` in - dynamorio::drmemtrace::caching_device_t and its deriving classes. + - Changed the types of `block_size`, `num_lines`, `blocks_per_way_mask_` to `int64_t` + in dynamorio::drmemtrace::caching_device_t and its deriving classes. - On 32-bit Arm the size of #dr_mcontext_t has been increased by 4 and the struct is now required to be 8-byte aligned. The offset of the field "simd" has changed. diff --git a/clients/drcachesim/simulator/cache.cpp b/clients/drcachesim/simulator/cache.cpp index 23eb7b4440f..450ce592947 100644 --- a/clients/drcachesim/simulator/cache.cpp +++ b/clients/drcachesim/simulator/cache.cpp @@ -52,7 +52,7 @@ namespace drmemtrace { class snoop_filter_t; bool -cache_t::init(int associativity, int64_t line_size, int total_size, +cache_t::init(int associativity, int64_t line_size, int64_t total_size, caching_device_t *parent, caching_device_stats_t *stats, prefetcher_t *prefetcher, cache_inclusion_policy_t inclusion_policy, bool coherent_cache, int id, snoop_filter_t *snoop_filter, @@ -61,13 +61,8 @@ cache_t::init(int associativity, int64_t line_size, int total_size, // Check line_size to avoid divide-by-0. if (line_size < 1) return false; - // Check that line_size fits in int - we don't expect actual huge line sizes in - // cache. Support for 64-bit line/block size exists for pages in TLBs, which - // don't actually hold the pages, just reference them. - if (line_size > std::numeric_limits::max()) - return false; // convert total_size to num_blocks to fit for caching_device_t::init - int num_lines = total_size / static_cast(line_size); + int64_t num_lines = total_size / line_size; return caching_device_t::init(associativity, line_size, num_lines, parent, stats, prefetcher, inclusion_policy, coherent_cache, id, diff --git a/clients/drcachesim/simulator/cache.h b/clients/drcachesim/simulator/cache.h index 659926f15cf..d977cefc528 100644 --- a/clients/drcachesim/simulator/cache.h +++ b/clients/drcachesim/simulator/cache.h @@ -61,8 +61,9 @@ class cache_t : public caching_device_t { // The id is an index into the snoop filter's array of caches for coherent caches. // If this is a coherent cache, id should be in the range [0,num_snooped_caches). bool - init(int associativity, int64_t line_size, int total_size, caching_device_t *parent, - caching_device_stats_t *stats, prefetcher_t *prefetcher = nullptr, + init(int associativity, int64_t line_size, int64_t total_size, + caching_device_t *parent, caching_device_stats_t *stats, + prefetcher_t *prefetcher = nullptr, cache_inclusion_policy_t inclusion_policy = cache_inclusion_policy_t::NON_INC_NON_EXC, bool coherent_cache = false, int id_ = -1, diff --git a/clients/drcachesim/simulator/cache_fifo.cpp b/clients/drcachesim/simulator/cache_fifo.cpp index 72b2fa45061..e341f7d61a1 100644 --- a/clients/drcachesim/simulator/cache_fifo.cpp +++ b/clients/drcachesim/simulator/cache_fifo.cpp @@ -53,7 +53,7 @@ namespace drmemtrace { // be cleared. The counter of the next block will be set to 1. bool -cache_fifo_t::init(int associativity, int64_t block_size, int total_size, +cache_fifo_t::init(int associativity, int64_t block_size, int64_t total_size, caching_device_t *parent, caching_device_stats_t *stats, prefetcher_t *prefetcher, cache_inclusion_policy_t inclusion_policy, bool coherent_cache, int id, snoop_filter_t *snoop_filter, diff --git a/clients/drcachesim/simulator/cache_fifo.h b/clients/drcachesim/simulator/cache_fifo.h index d532f78d827..504e4ba2467 100644 --- a/clients/drcachesim/simulator/cache_fifo.h +++ b/clients/drcachesim/simulator/cache_fifo.h @@ -54,8 +54,9 @@ class cache_fifo_t : public cache_t { { } bool - init(int associativity, int64_t block_size, int total_size, caching_device_t *parent, - caching_device_stats_t *stats, prefetcher_t *prefetcher = nullptr, + init(int associativity, int64_t block_size, int64_t total_size, + caching_device_t *parent, caching_device_stats_t *stats, + prefetcher_t *prefetcher = nullptr, cache_inclusion_policy_t inclusion_policy = cache_inclusion_policy_t::NON_INC_NON_EXC, bool coherent_cache = false, int id = -1, snoop_filter_t *snoop_filter = nullptr, diff --git a/clients/drcachesim/simulator/cache_lru.cpp b/clients/drcachesim/simulator/cache_lru.cpp index 4f259e0dcd3..ef5a66498a1 100644 --- a/clients/drcachesim/simulator/cache_lru.cpp +++ b/clients/drcachesim/simulator/cache_lru.cpp @@ -50,7 +50,7 @@ namespace drmemtrace { // highest counter value will be picked for replacement in replace_which_way. bool -cache_lru_t::init(int associativity, int64_t block_size, int total_size, +cache_lru_t::init(int associativity, int64_t block_size, int64_t total_size, caching_device_t *parent, caching_device_stats_t *stats, prefetcher_t *prefetcher, cache_inclusion_policy_t inclusion_policy, bool coherent_cache, int id, snoop_filter_t *snoop_filter, diff --git a/clients/drcachesim/simulator/cache_lru.h b/clients/drcachesim/simulator/cache_lru.h index 87bd429d657..dfbdd38e87d 100644 --- a/clients/drcachesim/simulator/cache_lru.h +++ b/clients/drcachesim/simulator/cache_lru.h @@ -53,8 +53,9 @@ class cache_lru_t : public cache_t { { } bool - init(int associativity, int64_t block_size, int total_size, caching_device_t *parent, - caching_device_stats_t *stats, prefetcher_t *prefetcher = nullptr, + init(int associativity, int64_t block_size, int64_t total_size, + caching_device_t *parent, caching_device_stats_t *stats, + prefetcher_t *prefetcher = nullptr, cache_inclusion_policy_t inclusion_policy = cache_inclusion_policy_t::NON_INC_NON_EXC, bool coherent_cache = false, int id = -1, snoop_filter_t *snoop_filter = nullptr, diff --git a/clients/drcachesim/simulator/caching_device.cpp b/clients/drcachesim/simulator/caching_device.cpp index 2ce0387eb02..e1e7c82b393 100644 --- a/clients/drcachesim/simulator/caching_device.cpp +++ b/clients/drcachesim/simulator/caching_device.cpp @@ -74,7 +74,7 @@ caching_device_t::~caching_device_t() } bool -caching_device_t::init(int associativity, int64_t block_size, int num_blocks, +caching_device_t::init(int associativity, int64_t block_size, int64_t num_blocks, caching_device_t *parent, caching_device_stats_t *stats, prefetcher_t *prefetcher, cache_inclusion_policy_t inclusion_policy, bool coherent_cache, diff --git a/clients/drcachesim/simulator/caching_device.h b/clients/drcachesim/simulator/caching_device.h index e0ba9ae733b..e7fc65dfff1 100644 --- a/clients/drcachesim/simulator/caching_device.h +++ b/clients/drcachesim/simulator/caching_device.h @@ -68,8 +68,9 @@ class caching_device_t { public: explicit caching_device_t(const std::string &name = "caching_device"); virtual bool - init(int associativity, int64_t block_size, int num_blocks, caching_device_t *parent, - caching_device_stats_t *stats, prefetcher_t *prefetcher = nullptr, + init(int associativity, int64_t block_size, int64_t num_blocks, + caching_device_t *parent, caching_device_stats_t *stats, + prefetcher_t *prefetcher = nullptr, cache_inclusion_policy_t inclusion_policy = cache_inclusion_policy_t::NON_INC_NON_EXC, bool coherent_cache = false, int id_ = -1, @@ -148,7 +149,7 @@ class caching_device_t { { return block_size_; } - virtual int + virtual int64_t get_num_blocks() const { return num_blocks_; @@ -205,7 +206,7 @@ class caching_device_t { { return addr >> block_size_bits_; } - inline int + inline int64_t compute_block_idx(addr_t tag) const { return (tag & blocks_per_way_mask_) * associativity_; @@ -246,7 +247,7 @@ class caching_device_t { int associativity_; int64_t block_size_; // Also known as line length. - int num_blocks_; // Total number of lines in cache = size / block_size. + int64_t num_blocks_; // Total number of lines in cache = size / block_size. bool coherent_cache_; // This is an index into snoop filter's array of caches. int id_; @@ -267,9 +268,9 @@ class caching_device_t { // an extended block class which has its own member variables cannot be indexed // correctly by base class pointers. caching_device_block_t **blocks_; - int blocks_per_way_; + int64_t blocks_per_way_; // Optimization fields for fast bit operations - int blocks_per_way_mask_; + int64_t blocks_per_way_mask_; int block_size_bits_; caching_device_stats_t *stats_; From f977681dbe90ddb19b6f49ff5a5276e38afbce9c Mon Sep 17 00:00:00 2001 From: Or Almer Date: Mon, 3 Mar 2025 07:05:20 +0000 Subject: [PATCH 19/42] Update return type int64_t --- clients/drcachesim/simulator/caching_device.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/drcachesim/simulator/caching_device.h b/clients/drcachesim/simulator/caching_device.h index e7fc65dfff1..7657022ee84 100644 --- a/clients/drcachesim/simulator/caching_device.h +++ b/clients/drcachesim/simulator/caching_device.h @@ -130,7 +130,7 @@ class caching_device_t { } use_tag2block_table_ = use_hashtable; } - int + int64_t get_block_index(const addr_t addr) const { addr_t tag = compute_tag(addr); From e10e3e71ac940eca9e64051a40dedb9d6f662f5e Mon Sep 17 00:00:00 2001 From: Or Almer Date: Mon, 3 Mar 2025 07:39:22 +0000 Subject: [PATCH 20/42] Update return type int64_t --- clients/drcachesim/simulator/caching_device.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clients/drcachesim/simulator/caching_device.h b/clients/drcachesim/simulator/caching_device.h index 7657022ee84..00dec050433 100644 --- a/clients/drcachesim/simulator/caching_device.h +++ b/clients/drcachesim/simulator/caching_device.h @@ -134,8 +134,7 @@ class caching_device_t { get_block_index(const addr_t addr) const { addr_t tag = compute_tag(addr); - int block_idx = compute_block_idx(tag); - return block_idx; + return compute_block_idx(tag); } // Accessors for cache parameters. From a4b9328e277699c886f5a2f94eb9d564ee57bf1a Mon Sep 17 00:00:00 2001 From: Or Almer Date: Mon, 3 Mar 2025 08:15:21 +0000 Subject: [PATCH 21/42] CR fixes - docs and rename to policy_* --- clients/drcachesim/CMakeLists.txt | 8 ++--- clients/drcachesim/simulator/cache.cpp | 9 ++--- clients/drcachesim/simulator/cache.h | 4 +-- .../simulator/cache_replacement_policy.h | 6 ++-- .../drcachesim/simulator/caching_device.cpp | 2 +- clients/drcachesim/simulator/caching_device.h | 27 ++++++++------ .../create_cache_replacement_policy.cpp | 16 ++++----- .../{bit_plru.cpp => policy_bit_plru.cpp} | 12 +++---- .../{bit_plru.h => policy_bit_plru.h} | 14 +++++--- .../simulator/{fifo.cpp => policy_fifo.cpp} | 12 +++---- .../simulator/{fifo.h => policy_fifo.h} | 13 ++++--- .../simulator/{lfu.cpp => policy_lfu.cpp} | 12 +++---- .../simulator/{lfu.h => policy_lfu.h} | 13 ++++--- .../simulator/{lru.cpp => policy_lru.cpp} | 12 +++---- .../simulator/{lru.h => policy_lru.h} | 13 ++++--- .../cache_replacement_policy_unit_test.cpp | 29 ++++++++------- .../tests/drcachesim_unit_tests.cpp | 36 +++++++++---------- .../drcachesim/tools/filter/cache_filter.cpp | 12 +++---- 18 files changed, 134 insertions(+), 116 deletions(-) rename clients/drcachesim/simulator/{bit_plru.cpp => policy_bit_plru.cpp} (90%) rename clients/drcachesim/simulator/{bit_plru.h => policy_bit_plru.h} (84%) rename clients/drcachesim/simulator/{fifo.cpp => policy_fifo.cpp} (90%) rename clients/drcachesim/simulator/{fifo.h => policy_fifo.h} (88%) rename clients/drcachesim/simulator/{lfu.cpp => policy_lfu.cpp} (90%) rename clients/drcachesim/simulator/{lfu.h => policy_lfu.h} (87%) rename clients/drcachesim/simulator/{lru.cpp => policy_lru.cpp} (91%) rename clients/drcachesim/simulator/{lru.h => policy_lru.h} (88%) diff --git a/clients/drcachesim/CMakeLists.txt b/clients/drcachesim/CMakeLists.txt index 3a4b206097f..2f3374f102f 100644 --- a/clients/drcachesim/CMakeLists.txt +++ b/clients/drcachesim/CMakeLists.txt @@ -202,11 +202,11 @@ add_exported_library(drmemtrace_simulator STATIC simulator/snoop_filter.cpp simulator/tlb.cpp simulator/tlb_simulator.cpp - simulator/bit_plru.cpp simulator/create_cache_replacement_policy.cpp - simulator/fifo.cpp - simulator/lfu.cpp - simulator/lru.cpp + simulator/policy_bit_plru.cpp + simulator/policy_fifo.cpp + simulator/policy_lfu.cpp + simulator/policy_lru.cpp ) add_exported_library(drmemtrace_record_filter STATIC diff --git a/clients/drcachesim/simulator/cache.cpp b/clients/drcachesim/simulator/cache.cpp index a138c8a6586..80ddb49741c 100644 --- a/clients/drcachesim/simulator/cache.cpp +++ b/clients/drcachesim/simulator/cache.cpp @@ -51,7 +51,7 @@ namespace drmemtrace { class snoop_filter_t; bool -cache_t::init(int associativity, int64_t line_size, int total_size, +cache_t::init(int associativity, int64_t line_size, int64_t total_size, caching_device_t *parent, caching_device_stats_t *stats, std::unique_ptr replacement_policy, prefetcher_t *prefetcher, cache_inclusion_policy_t inclusion_policy, @@ -61,13 +61,8 @@ cache_t::init(int associativity, int64_t line_size, int total_size, // Check line_size to avoid divide-by-0. if (line_size < 1) return false; - // Check that line_size fits in int - we don't expect actual huge line sizes in - // cache. Support for 64-bit line/block size exists for pages in TLBs, which - // don't actually hold the pages, just reference them. - if (line_size > std::numeric_limits::max()) - return false; // convert total_size to num_blocks to fit for caching_device_t::init - int num_lines = total_size / static_cast(line_size); + int64_t num_lines = total_size / line_size; return caching_device_t::init( associativity, line_size, num_lines, parent, stats, std::move(replacement_policy), diff --git a/clients/drcachesim/simulator/cache.h b/clients/drcachesim/simulator/cache.h index 065d90e8863..86cba097e16 100644 --- a/clients/drcachesim/simulator/cache.h +++ b/clients/drcachesim/simulator/cache.h @@ -63,8 +63,8 @@ class cache_t : public caching_device_t { // The id is an index into the snoop filter's array of caches for coherent caches. // If this is a coherent cache, id should be in the range [0,num_snooped_caches). bool - init(int associativity, int64_t line_size, int total_size, caching_device_t *parent, - caching_device_stats_t *stats, + init(int associativity, int64_t line_size, int64_t total_size, + caching_device_t *parent, caching_device_stats_t *stats, std::unique_ptr replacement_policy, prefetcher_t *prefetcher = nullptr, cache_inclusion_policy_t inclusion_policy = diff --git a/clients/drcachesim/simulator/cache_replacement_policy.h b/clients/drcachesim/simulator/cache_replacement_policy.h index 288a68d82ff..30b7d2920dd 100644 --- a/clients/drcachesim/simulator/cache_replacement_policy.h +++ b/clients/drcachesim/simulator/cache_replacement_policy.h @@ -41,9 +41,9 @@ namespace drmemtrace { /** * An interface for cache replacement policies. * - * Holds the necassary information to implement a cache replacement policy, - * And provides an interface for caching_device_t find which way to replace - * in a block upon eviction. + * Holds the necessary information to implement a cache replacement policy, + * and provides a replacement-specific get_next_way_to_replace() method for + * `caching_device_t`. */ class cache_replacement_policy_t { public: diff --git a/clients/drcachesim/simulator/caching_device.cpp b/clients/drcachesim/simulator/caching_device.cpp index 56d1835ba3e..d8d73bd3eab 100644 --- a/clients/drcachesim/simulator/caching_device.cpp +++ b/clients/drcachesim/simulator/caching_device.cpp @@ -74,7 +74,7 @@ caching_device_t::~caching_device_t() } bool -caching_device_t::init(int associativity, int64_t block_size, int num_blocks, +caching_device_t::init(int associativity, int64_t block_size, int64_t num_blocks, caching_device_t *parent, caching_device_stats_t *stats, std::unique_ptr replacement_policy, prefetcher_t *prefetcher, diff --git a/clients/drcachesim/simulator/caching_device.h b/clients/drcachesim/simulator/caching_device.h index 41ded1b0ca8..ff6232873a2 100644 --- a/clients/drcachesim/simulator/caching_device.h +++ b/clients/drcachesim/simulator/caching_device.h @@ -33,10 +33,10 @@ /* caching_device: represents a hardware caching device. */ +#include #ifndef _CACHING_DEVICE_H_ #define _CACHING_DEVICE_H_ 1 -#include #include #include #include @@ -70,8 +70,8 @@ class caching_device_t { public: explicit caching_device_t(const std::string &name = "caching_device"); virtual bool - init(int associativity, int64_t block_size, int num_blocks, caching_device_t *parent, - caching_device_stats_t *stats, + init(int associativity, int64_t block_size, int64_t num_blocks, + caching_device_t *parent, caching_device_stats_t *stats, std::unique_ptr replacement_policy, prefetcher_t *prefetcher = nullptr, cache_inclusion_policy_t inclusion_policy = @@ -114,6 +114,12 @@ class caching_device_t { { return parent_; } + void + set_parent(caching_device_t *parent) + { + parent_ = parent; + parent_->children_.push_back(this); + } inline double get_loaded_fraction() const { @@ -133,12 +139,11 @@ class caching_device_t { } use_tag2block_table_ = use_hashtable; } - int + int64_t get_block_index(const addr_t addr) const { addr_t tag = compute_tag(addr); - int block_idx = compute_block_idx(tag); - return block_idx; + return compute_block_idx(tag); } // Accessors for cache parameters. @@ -152,7 +157,7 @@ class caching_device_t { { return block_size_; } - virtual int + virtual int64_t get_num_blocks() const { return num_blocks_; @@ -209,7 +214,7 @@ class caching_device_t { { return addr >> block_size_bits_; } - inline int + inline int64_t compute_block_idx(addr_t tag) const { return (tag & blocks_per_way_mask_) * associativity_; @@ -250,7 +255,7 @@ class caching_device_t { int associativity_; int64_t block_size_; // Also known as line length. - int num_blocks_; // Total number of lines in cache = size / block_size. + int64_t num_blocks_; // Total number of lines in cache = size / block_size. bool coherent_cache_; // This is an index into snoop filter's array of caches. int id_; @@ -271,9 +276,9 @@ class caching_device_t { // an extended block class which has its own member variables cannot be indexed // correctly by base class pointers. caching_device_block_t **blocks_; - int blocks_per_way_; + int64_t blocks_per_way_; // Optimization fields for fast bit operations - int blocks_per_way_mask_; + int64_t blocks_per_way_mask_; int block_size_bits_; caching_device_stats_t *stats_; diff --git a/clients/drcachesim/simulator/create_cache_replacement_policy.cpp b/clients/drcachesim/simulator/create_cache_replacement_policy.cpp index 1249baf8449..71d205b1a6a 100644 --- a/clients/drcachesim/simulator/create_cache_replacement_policy.cpp +++ b/clients/drcachesim/simulator/create_cache_replacement_policy.cpp @@ -35,10 +35,10 @@ #include #include -#include "bit_plru.h" -#include "fifo.h" -#include "lfu.h" -#include "lru.h" +#include "policy_bit_plru.h" +#include "policy_fifo.h" +#include "policy_lfu.h" +#include "policy_lru.h" #include "options.h" namespace dynamorio { @@ -50,13 +50,13 @@ create_cache_replacement_policy(const std::string &policy, int num_blocks, { if (policy == REPLACE_POLICY_NON_SPECIFIED || // default LRU policy == REPLACE_POLICY_LRU) // set to LRU - return std::unique_ptr(new lru_t(num_blocks, associativity)); + return std::unique_ptr(new policy_lru_t(num_blocks, associativity)); if (policy == REPLACE_POLICY_LFU) - return std::unique_ptr(new lfu_t(num_blocks, associativity)); + return std::unique_ptr(new policy_lfu_t(num_blocks, associativity)); if (policy == REPLACE_POLICY_FIFO) - return std::unique_ptr(new fifo_t(num_blocks, associativity)); + return std::unique_ptr(new policy_fifo_t(num_blocks, associativity)); if (policy == REPLACE_POLICY_BIT_PLRU) - return std::unique_ptr(new bit_plru_t(num_blocks, associativity)); + return std::unique_ptr(new policy_bit_plru_t(num_blocks, associativity)); return nullptr; } diff --git a/clients/drcachesim/simulator/bit_plru.cpp b/clients/drcachesim/simulator/policy_bit_plru.cpp similarity index 90% rename from clients/drcachesim/simulator/bit_plru.cpp rename to clients/drcachesim/simulator/policy_bit_plru.cpp index d71cfb31daf..24495ba04d6 100644 --- a/clients/drcachesim/simulator/bit_plru.cpp +++ b/clients/drcachesim/simulator/policy_bit_plru.cpp @@ -30,7 +30,7 @@ * DAMAGE. */ -#include "bit_plru.h" +#include "policy_bit_plru.h" #include #include @@ -38,7 +38,7 @@ namespace dynamorio { namespace drmemtrace { -bit_plru_t::bit_plru_t(int num_blocks, int associativity, int seed) +policy_bit_plru_t::policy_bit_plru_t(int num_blocks, int associativity, int seed) : cache_replacement_policy_t(num_blocks, associativity) , block_set_counts_(num_blocks, 0) , gen_(seed == -1 ? std::random_device()() : seed) @@ -51,7 +51,7 @@ bit_plru_t::bit_plru_t(int num_blocks, int associativity, int seed) } void -bit_plru_t::access_update(int block_idx, int way) +policy_bit_plru_t::access_update(int block_idx, int way) { block_idx = get_block_index(block_idx); // Set the bit for the accessed way. @@ -72,13 +72,13 @@ bit_plru_t::access_update(int block_idx, int way) } void -bit_plru_t::eviction_update(int block_idx, int way) +policy_bit_plru_t::eviction_update(int block_idx, int way) { // Nothing to update, when the way is accessed we will update it. } int -bit_plru_t::get_next_way_to_replace(int block_idx) +policy_bit_plru_t::get_next_way_to_replace(int block_idx) { block_idx = get_block_index(block_idx); std::vector unset_bits; @@ -96,7 +96,7 @@ bit_plru_t::get_next_way_to_replace(int block_idx) } std::string -bit_plru_t::get_name() const +policy_bit_plru_t::get_name() const { return "BIT_PLRU"; } diff --git a/clients/drcachesim/simulator/bit_plru.h b/clients/drcachesim/simulator/policy_bit_plru.h similarity index 84% rename from clients/drcachesim/simulator/bit_plru.h rename to clients/drcachesim/simulator/policy_bit_plru.h index b8e2087e65e..f9ffc1d246a 100644 --- a/clients/drcachesim/simulator/bit_plru.h +++ b/clients/drcachesim/simulator/policy_bit_plru.h @@ -42,10 +42,16 @@ namespace dynamorio { namespace drmemtrace { -class bit_plru_t : public cache_replacement_policy_t { +/** + * A replacement policy that uses a bit per wat to track access frequency. + * + * On access, a way's bit is set to 1. Once all bits are set, the whole block's bits + * are set to 0. A random way with a 0 bit is chosen for replacement. + */ +class policy_bit_plru_t : public cache_replacement_policy_t { public: /// If seed is -1, a random seed will be used. - bit_plru_t(int num_blocks, int associativity, int seed = -1); + policy_bit_plru_t(int num_blocks, int associativity, int seed = -1); void access_update(int block_idx, int way) override; void @@ -55,7 +61,7 @@ class bit_plru_t : public cache_replacement_policy_t { std::string get_name() const override; - ~bit_plru_t() override = default; + ~policy_bit_plru_t() override = default; private: std::vector> block_bits_; @@ -66,4 +72,4 @@ class bit_plru_t : public cache_replacement_policy_t { } // namespace drmemtrace } // namespace dynamorio -#endif /* _BIT_PLRU_H_ */ +#endif // _BIT_PLRU_H_ diff --git a/clients/drcachesim/simulator/fifo.cpp b/clients/drcachesim/simulator/policy_fifo.cpp similarity index 90% rename from clients/drcachesim/simulator/fifo.cpp rename to clients/drcachesim/simulator/policy_fifo.cpp index b4ea0f70cdc..c33f0bff845 100644 --- a/clients/drcachesim/simulator/fifo.cpp +++ b/clients/drcachesim/simulator/policy_fifo.cpp @@ -30,14 +30,14 @@ * DAMAGE. */ -#include "fifo.h" +#include "policy_fifo.h" #include namespace dynamorio { namespace drmemtrace { -fifo_t::fifo_t(int num_blocks, int associativity) +policy_fifo_t::policy_fifo_t(int num_blocks, int associativity) : cache_replacement_policy_t(num_blocks, associativity) { // Initialize the FIFO list for each block. @@ -51,13 +51,13 @@ fifo_t::fifo_t(int num_blocks, int associativity) } void -fifo_t::access_update(int block_idx, int way) +policy_fifo_t::access_update(int block_idx, int way) { // Nothing to update, FIFO does not change on access. } void -fifo_t::eviction_update(int block_idx, int way) +policy_fifo_t::eviction_update(int block_idx, int way) { block_idx = get_block_index(block_idx); // Move the evicted way to the back of the queue. @@ -67,7 +67,7 @@ fifo_t::eviction_update(int block_idx, int way) } int -fifo_t::get_next_way_to_replace(int block_idx) +policy_fifo_t::get_next_way_to_replace(int block_idx) { block_idx = get_block_index(block_idx); // The next way to replace is at the front of the FIFO list. @@ -75,7 +75,7 @@ fifo_t::get_next_way_to_replace(int block_idx) } std::string -fifo_t::get_name() const +policy_fifo_t::get_name() const { return "FIFO"; } diff --git a/clients/drcachesim/simulator/fifo.h b/clients/drcachesim/simulator/policy_fifo.h similarity index 88% rename from clients/drcachesim/simulator/fifo.h rename to clients/drcachesim/simulator/policy_fifo.h index 73f31d5e373..a14dc99fefa 100644 --- a/clients/drcachesim/simulator/fifo.h +++ b/clients/drcachesim/simulator/policy_fifo.h @@ -42,9 +42,14 @@ namespace dynamorio { namespace drmemtrace { -class fifo_t : public cache_replacement_policy_t { +/** + * A FIFO cache replacement policy. + * + * The way wich was added (not accessed) first is replaced first. + */ +class policy_fifo_t : public cache_replacement_policy_t { public: - fifo_t(int num_blocks, int associativity); + policy_fifo_t(int num_blocks, int associativity); void access_update(int block_idx, int way) override; void @@ -54,7 +59,7 @@ class fifo_t : public cache_replacement_policy_t { std::string get_name() const override; - ~fifo_t() override = default; + ~policy_fifo_t() override = default; private: // FIFO queue for each block. @@ -64,4 +69,4 @@ class fifo_t : public cache_replacement_policy_t { } // namespace drmemtrace } // namespace dynamorio -#endif /* _FIFO_H_ */ +#endif // _FIFO_H_ diff --git a/clients/drcachesim/simulator/lfu.cpp b/clients/drcachesim/simulator/policy_lfu.cpp similarity index 90% rename from clients/drcachesim/simulator/lfu.cpp rename to clients/drcachesim/simulator/policy_lfu.cpp index 6ed1165440a..78add9335df 100644 --- a/clients/drcachesim/simulator/lfu.cpp +++ b/clients/drcachesim/simulator/policy_lfu.cpp @@ -30,7 +30,7 @@ * DAMAGE. */ -#include "lfu.h" +#include "policy_lfu.h" #include #include @@ -39,7 +39,7 @@ namespace dynamorio { namespace drmemtrace { -lfu_t::lfu_t(int num_blocks, int associativity) +policy_lfu_t::policy_lfu_t(int num_blocks, int associativity) : cache_replacement_policy_t(num_blocks, associativity) { access_counts_.reserve(num_blocks); @@ -49,21 +49,21 @@ lfu_t::lfu_t(int num_blocks, int associativity) } void -lfu_t::access_update(int block_idx, int way) +policy_lfu_t::access_update(int block_idx, int way) { block_idx = get_block_index(block_idx); access_counts_[block_idx][way]++; } void -lfu_t::eviction_update(int block_idx, int way) +policy_lfu_t::eviction_update(int block_idx, int way) { block_idx = get_block_index(block_idx); access_counts_[block_idx][way] = 0; } int -lfu_t::get_next_way_to_replace(int block_idx) +policy_lfu_t::get_next_way_to_replace(int block_idx) { // Find the way with the minimum frequency counter. block_idx = get_block_index(block_idx); @@ -79,7 +79,7 @@ lfu_t::get_next_way_to_replace(int block_idx) } std::string -lfu_t::get_name() const +policy_lfu_t::get_name() const { return "LFU"; } diff --git a/clients/drcachesim/simulator/lfu.h b/clients/drcachesim/simulator/policy_lfu.h similarity index 87% rename from clients/drcachesim/simulator/lfu.h rename to clients/drcachesim/simulator/policy_lfu.h index c7c18eefb31..a7a17883025 100644 --- a/clients/drcachesim/simulator/lfu.h +++ b/clients/drcachesim/simulator/policy_lfu.h @@ -40,9 +40,14 @@ namespace dynamorio { namespace drmemtrace { -class lfu_t : public cache_replacement_policy_t { +/** + * A Least-Frequently-Used (LFU) cache replacement policy. + * + * Count all access to each way, the way with the least accesses is evicted. + */ +class policy_lfu_t : public cache_replacement_policy_t { public: - lfu_t(int num_blocks, int associativity); + policy_lfu_t(int num_blocks, int associativity); void access_update(int block_idx, int way) override; void @@ -52,7 +57,7 @@ class lfu_t : public cache_replacement_policy_t { std::string get_name() const override; - ~lfu_t() override = default; + ~policy_lfu_t() override = default; private: // Frequency counters for each way in each block. @@ -62,4 +67,4 @@ class lfu_t : public cache_replacement_policy_t { } // namespace drmemtrace } // namespace dynamorio -#endif /* _LFU_H_ */ +#endif // _LFU_H_ diff --git a/clients/drcachesim/simulator/lru.cpp b/clients/drcachesim/simulator/policy_lru.cpp similarity index 91% rename from clients/drcachesim/simulator/lru.cpp rename to clients/drcachesim/simulator/policy_lru.cpp index bd7b608d1c5..73b0846f5e1 100644 --- a/clients/drcachesim/simulator/lru.cpp +++ b/clients/drcachesim/simulator/policy_lru.cpp @@ -30,14 +30,14 @@ * DAMAGE. */ -#include "lru.h" +#include "policy_lru.h" #include namespace dynamorio { namespace drmemtrace { -lru_t::lru_t(int num_blocks, int associativity) +policy_lru_t::policy_lru_t(int num_blocks, int associativity) : cache_replacement_policy_t(num_blocks, associativity) { // Initialize the LRU list for each block. @@ -48,7 +48,7 @@ lru_t::lru_t(int num_blocks, int associativity) } void -lru_t::access_update(int block_idx, int way) +policy_lru_t::access_update(int block_idx, int way) { block_idx = get_block_index(block_idx); int count = lru_counters_[block_idx][way]; @@ -65,13 +65,13 @@ lru_t::access_update(int block_idx, int way) } void -lru_t::eviction_update(int block_idx, int way) +policy_lru_t::eviction_update(int block_idx, int way) { // Nothing to update, when the way is accessed we will update it. } int -lru_t::get_next_way_to_replace(int block_idx) +policy_lru_t::get_next_way_to_replace(int block_idx) { block_idx = get_block_index(block_idx); // We implement LRU by picking the slot with the largest counter value. @@ -87,7 +87,7 @@ lru_t::get_next_way_to_replace(int block_idx) } std::string -lru_t::get_name() const +policy_lru_t::get_name() const { return "LRU"; } diff --git a/clients/drcachesim/simulator/lru.h b/clients/drcachesim/simulator/policy_lru.h similarity index 88% rename from clients/drcachesim/simulator/lru.h rename to clients/drcachesim/simulator/policy_lru.h index 6a5e500f0b9..60719945d26 100644 --- a/clients/drcachesim/simulator/lru.h +++ b/clients/drcachesim/simulator/policy_lru.h @@ -42,9 +42,14 @@ namespace dynamorio { namespace drmemtrace { -class lru_t : public cache_replacement_policy_t { +/** + * An LRU cache replacement policy. + * + * The way which was accessed the longest time ago is evicted. + */ +class policy_lru_t : public cache_replacement_policy_t { public: - lru_t(int num_blocks, int associativity); + policy_lru_t(int num_blocks, int associativity); void access_update(int block_idx, int way) override; void @@ -54,7 +59,7 @@ class lru_t : public cache_replacement_policy_t { std::string get_name() const override; - ~lru_t() override = default; + ~policy_lru_t() override = default; private: // LRU list for each block. @@ -64,4 +69,4 @@ class lru_t : public cache_replacement_policy_t { } // namespace drmemtrace } // namespace dynamorio -#endif /* _LRU_H_ */ +#endif // _LRU_H_ diff --git a/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp b/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp index 57ce4932af6..2cbcef47331 100644 --- a/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp +++ b/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp @@ -37,11 +37,11 @@ #include #include #include "cache_replacement_policy_unit_test.h" -#include "simulator/bit_plru.h" +#include "simulator/policy_bit_plru.h" #include "simulator/cache.h" -#include "simulator/fifo.h" -#include "simulator/lfu.h" -#include "simulator/lru.h" +#include "simulator/policy_fifo.h" +#include "simulator/policy_lfu.h" +#include "simulator/policy_lru.h" #include "simulator/tlb.h" namespace dynamorio { @@ -90,8 +90,7 @@ template class caching_device_policy_test_t : public T { ref.data.addr = addr; ref.data.pid = 1; this->request(ref); - assert(this->get_next_way_to_replace(this->get_block_index(addr)) == - expected_replacement_way_after_access); + assert(this->get_next_way_to_replace(this->get_block_index(addr)) == expected_replacement_way_after_access); } void @@ -155,7 +154,7 @@ unit_test_cache_lru_four_way() caching_device_policy_test_t cache_lru_test(/*associativity=*/4, /*line_size=*/32); cache_lru_test.initialize_cache( - std::unique_ptr(new lru_t(/*num_blocks=*/256 / 4, /*associativity=*/4)), + std::unique_ptr(new policy_lru_t(/*num_blocks=*/256 / 4, /*associativity=*/4)), 256); assert(cache_lru_test.get_replace_policy() == "LRU"); @@ -195,7 +194,7 @@ unit_test_cache_lru_eight_way() caching_device_policy_test_t cache_lru_test(/*associativity=*/8, /*line_size=*/64); cache_lru_test.initialize_cache( - std::unique_ptr(new lru_t(/*num_blocks=*/1024 / 8, /*associativity=*/8)), + std::unique_ptr(new policy_lru_t(/*num_blocks=*/1024 / 8, /*associativity=*/8)), 1024); assert(cache_lru_test.get_replace_policy() == "LRU"); @@ -242,7 +241,7 @@ unit_test_cache_fifo_four_way() caching_device_policy_test_t cache_fifo_test(/*associativity=*/4, /*line_size=*/32); cache_fifo_test.initialize_cache( - std::unique_ptr(new fifo_t(/*num_blocks=*/256 / 4, /*associativity=*/4)), + std::unique_ptr(new policy_fifo_t(/*num_blocks=*/256 / 4, /*associativity=*/4)), 256); assert(cache_fifo_test.get_replace_policy() == "FIFO"); @@ -285,7 +284,7 @@ unit_test_cache_fifo_eight_way() caching_device_policy_test_t cache_fifo_test(/*associativity=*/8, /*line_size=*/64); cache_fifo_test.initialize_cache( - std::unique_ptr(new fifo_t(/*num_blocks=*/1024 / 8, /*associativity=*/8)), + std::unique_ptr(new policy_fifo_t(/*num_blocks=*/1024 / 8, /*associativity=*/8)), 1024); assert(cache_fifo_test.get_replace_policy() == "FIFO"); @@ -326,7 +325,7 @@ unit_test_cache_lfu_four_way() caching_device_policy_test_t cache_lfu_test(/*associativity=*/4, /*line_size=*/32); cache_lfu_test.initialize_cache( - std::unique_ptr(new lfu_t(/*num_blocks=*/256 / 4, /*associativity=*/4)), + std::unique_ptr(new policy_lfu_t(/*num_blocks=*/256 / 4, /*associativity=*/4)), 256); assert(cache_lfu_test.get_replace_policy() == "LFU"); @@ -367,7 +366,7 @@ unit_test_cache_lfu_eight_way() caching_device_policy_test_t cache_lfu_test(/*associativity=*/8, /*line_size=*/64); cache_lfu_test.initialize_cache( - std::unique_ptr(new lfu_t(/*num_blocks=*/1024 / 8, /*associativity=*/8)), + std::unique_ptr(new policy_lfu_t(/*num_blocks=*/1024 / 8, /*associativity=*/8)), 1024); assert(cache_lfu_test.get_replace_policy() == "LFU"); @@ -415,8 +414,8 @@ unit_test_tlb_plru_four_way() caching_device_policy_test_t tlb_plru_test(/*associativity=*/4, /*line_size=*/64); tlb_plru_test.initialize_cache( - std::unique_ptr( - new bit_plru_t(1 /*num_blocks*/, 4 /*associativity*/, 0 /*seed*/)), + std::unique_ptr( + new policy_bit_plru_t(1 /*num_blocks*/, 4 /*associativity*/, 0 /*seed*/)), 4); assert(tlb_plru_test.get_replace_policy() == "BIT_PLRU"); assert(tlb_plru_test.block_indices_are_identical(addr_vec)); @@ -439,7 +438,7 @@ unit_test_tlb_lfu_four_way() caching_device_policy_test_t tlb_lfu_test(/*associativity=*/4, /*line_size=*/64); tlb_lfu_test.initialize_cache( - std::unique_ptr(new lfu_t(1 /*num_blocks*/, 4 /*associativity*/)), 4); + std::unique_ptr(new policy_lfu_t(1 /*num_blocks*/, 4 /*associativity*/)), 4); assert(tlb_lfu_test.get_replace_policy() == "LFU"); assert(tlb_lfu_test.block_indices_are_identical(addr_vec)); assert(tlb_lfu_test.tags_are_different(addr_vec)); diff --git a/clients/drcachesim/tests/drcachesim_unit_tests.cpp b/clients/drcachesim/tests/drcachesim_unit_tests.cpp index 9ebb2ac1cbe..51df5d33a6c 100644 --- a/clients/drcachesim/tests/drcachesim_unit_tests.cpp +++ b/clients/drcachesim/tests/drcachesim_unit_tests.cpp @@ -44,8 +44,8 @@ #include "cache_replacement_policy_unit_test.h" #include "simulator/cache.h" #include "simulator/cache_simulator.h" -#include "simulator/lfu.h" -#include "simulator/lru.h" +#include "simulator/policy_lfu.h" +#include "simulator/policy_lru.h" #include "simulator/prefetcher.h" #include "../common/memref.h" #include "../common/utils.h" @@ -447,9 +447,9 @@ LLC { class test_cache_simulator_t : public cache_simulator_t { public: test_cache_simulator_t(const cache_simulator_knobs_t &knobs) - : cache_simulator_t(knobs) {}; + : cache_simulator_t(knobs) { }; test_cache_simulator_t(std::istream *config_file) - : cache_simulator_t(config_file) {}; + : cache_simulator_t(config_file) { }; // Returns cache_t* for named cache if it exists, else faults. cache_t * get_named_cache(std::string name) @@ -656,7 +656,7 @@ unit_test_cache_associativity() caching_device_stats_t stats(/*miss_file=*/"", LINE_SIZE); bool initialized = cache.init(assoc, LINE_SIZE, total_size, /*parent=*/nullptr, &stats, - std::unique_ptr(new lru_t(total_size / assoc, assoc))); + std::unique_ptr(new policy_lru_t(total_size / assoc, assoc))); assert(initialized); assert(cache.get_associativity() == assoc); // Test start address is arbitrary. @@ -707,8 +707,8 @@ unit_test_cache_size() bool initialized = cache.init(associativity, LINE_SIZE, cache_size, /*parent=*/nullptr, &stats, - std::unique_ptr( - new lru_t(cache_size / associativity, associativity))); + std::unique_ptr( + new policy_lru_t(cache_size / associativity, associativity))); assert(initialized); assert(cache.get_size_bytes() == cache_size); static constexpr int NUM_LOOPS = 3; // Anything >=2 should work. @@ -760,7 +760,7 @@ unit_test_cache_line_size() bool initialized = cache.init(ASSOCIATIVITY, line_size, total_cache_size, /*parent=*/nullptr, &stats, - std::unique_ptr(new lfu_t( + std::unique_ptr(new policy_lfu_t( total_cache_size / ASSOCIATIVITY, ASSOCIATIVITY))); assert(initialized); auto read_count = @@ -804,13 +804,13 @@ unit_test_cache_bad_configs() assert(!cache.init( 0, SAFE_LINE_SIZE, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, - std::unique_ptr(new lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); + std::unique_ptr(new policy_lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); assert(!cache.init( SAFE_ASSOC, 0, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, - std::unique_ptr(new lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); + std::unique_ptr(new policy_lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); assert(!cache.init( SAFE_ASSOC, SAFE_LINE_SIZE, 0, /*parent=*/nullptr, &stats, - std::unique_ptr(new lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); + std::unique_ptr(new policy_lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); assert(!cache.init(SAFE_ASSOC, SAFE_LINE_SIZE, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, nullptr)); @@ -818,16 +818,16 @@ unit_test_cache_bad_configs() std::cerr << "Testing bad line size parameters.\n"; assert(!cache.init( SAFE_ASSOC, 1, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, - std::unique_ptr(new lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); + std::unique_ptr(new policy_lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); assert(!cache.init( SAFE_ASSOC, 2, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, - std::unique_ptr(new lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); + std::unique_ptr(new policy_lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); assert(!cache.init( SAFE_ASSOC, 7, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, - std::unique_ptr(new lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); + std::unique_ptr(new policy_lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); assert(!cache.init( SAFE_ASSOC, 65, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, - std::unique_ptr(new lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); + std::unique_ptr(new policy_lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); // Size, associativity, and line_size are related. The requirement is that // size/associativity is a power-of-two, and >= line_size, so try some @@ -842,7 +842,7 @@ unit_test_cache_bad_configs() for (const auto &combo : bad_combinations) { assert(!cache.init( combo.assoc, SAFE_LINE_SIZE, combo.size, /*parent=*/nullptr, &stats, - std::unique_ptr(new lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); + std::unique_ptr(new policy_lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); } } @@ -878,8 +878,8 @@ unit_test_cache_accessors() cache.init(associativity, line_size, total_size, /*parent=*/nullptr, &stats, /*replacement_policy=*/ - std::unique_ptr( - new lru_t(total_size / associativity, associativity)), + std::unique_ptr( + new policy_lru_t(total_size / associativity, associativity)), /*prefetcher=*/nullptr, policy, coherent); assert(initialized); assert(cache.get_stats() == &stats); diff --git a/clients/drcachesim/tools/filter/cache_filter.cpp b/clients/drcachesim/tools/filter/cache_filter.cpp index 764d559170b..2b4983e324c 100644 --- a/clients/drcachesim/tools/filter/cache_filter.cpp +++ b/clients/drcachesim/tools/filter/cache_filter.cpp @@ -38,7 +38,7 @@ #include "cache_stats.h" #include "caching_device_block.h" #include "caching_device_stats.h" -#include "lru.h" +#include "policy_lru.h" #include "memref.h" #include "memtrace_stream.h" #include "trace_entry.h" @@ -79,12 +79,10 @@ cache_filter_t::parallel_shard_init(memtrace_stream_t *shard_stream, bool partial_trace_filter) { per_shard_t *per_shard = new per_shard_t; - if (!(per_shard->cache.init( - cache_associativity_, cache_line_size_, cache_size_, nullptr, - new cache_filter_stats_t(cache_line_size_), - std::unique_ptr( - new lru_t(cache_size_ / cache_associativity_, cache_associativity_)), - nullptr))) { + if (!(per_shard->cache.init(cache_associativity_, cache_line_size_, cache_size_, + nullptr, new cache_filter_stats_t(cache_line_size_), + std::unique_ptr(new policy_lru_t(cache_size_ / cache_associativity_, cache_associativity_)), + nullptr))) { error_string_ = "Failed to initialize cache."; return nullptr; } From 55f322378dd7c8e360ee7c92a9198b75b5e47c85 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Mon, 3 Mar 2025 08:16:13 +0000 Subject: [PATCH 22/42] CR fixes - docs and rename to policy_* --- clients/drcachesim/simulator/caching_device.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/clients/drcachesim/simulator/caching_device.h b/clients/drcachesim/simulator/caching_device.h index ff6232873a2..52422d4036c 100644 --- a/clients/drcachesim/simulator/caching_device.h +++ b/clients/drcachesim/simulator/caching_device.h @@ -114,12 +114,6 @@ class caching_device_t { { return parent_; } - void - set_parent(caching_device_t *parent) - { - parent_ = parent; - parent_->children_.push_back(this); - } inline double get_loaded_fraction() const { From e92350833c33ff71c6c2232a8e0bd9d4e0258770 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Mon, 3 Mar 2025 08:17:35 +0000 Subject: [PATCH 23/42] CR fixes - docs and rename to policy_* --- clients/drcachesim/simulator/caching_device.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/drcachesim/simulator/caching_device.h b/clients/drcachesim/simulator/caching_device.h index 52422d4036c..1b461ada154 100644 --- a/clients/drcachesim/simulator/caching_device.h +++ b/clients/drcachesim/simulator/caching_device.h @@ -33,10 +33,10 @@ /* caching_device: represents a hardware caching device. */ -#include #ifndef _CACHING_DEVICE_H_ #define _CACHING_DEVICE_H_ 1 +#include #include #include #include From 2727ca1c278041dce30504e3adde9c22b9958ce1 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Mon, 3 Mar 2025 08:35:19 +0000 Subject: [PATCH 24/42] cast to size_t --- clients/drcachesim/simulator/caching_device.cpp | 5 ++--- clients/drcachesim/simulator/caching_device.h | 5 +++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clients/drcachesim/simulator/caching_device.cpp b/clients/drcachesim/simulator/caching_device.cpp index e1e7c82b393..fff2f45e7e8 100644 --- a/clients/drcachesim/simulator/caching_device.cpp +++ b/clients/drcachesim/simulator/caching_device.cpp @@ -111,8 +111,7 @@ caching_device_t::init(int associativity, int64_t block_size, int64_t num_blocks id_ = id; snoop_filter_ = snoop_filter; coherent_cache_ = coherent_cache; - - blocks_ = new caching_device_block_t *[num_blocks_]; + blocks_ = new caching_device_block_t *[static_cast(num_blocks_)]; init_blocks(); last_tag_ = TAG_INVALID; // sentinel @@ -146,7 +145,7 @@ caching_device_t::find_caching_device_block(addr_t tag) assert(it->second.first->tag_ == tag); return it->second; } - int block_idx = compute_block_idx(tag); + int64_t block_idx = compute_block_idx(tag); for (int way = 0; way < associativity_; ++way) { caching_device_block_t &block = get_caching_device_block(block_idx, way); if (block.tag_ == tag) diff --git a/clients/drcachesim/simulator/caching_device.h b/clients/drcachesim/simulator/caching_device.h index 00dec050433..e4150536192 100644 --- a/clients/drcachesim/simulator/caching_device.h +++ b/clients/drcachesim/simulator/caching_device.h @@ -211,9 +211,10 @@ class caching_device_t { return (tag & blocks_per_way_mask_) * associativity_; } inline caching_device_block_t & - get_caching_device_block(int block_idx, int way) const + get_caching_device_block(int64_t block_idx, int way) const { - return *(blocks_[block_idx + way]); + size_t block_idx_offset = static_cast(block_idx + way); + return *(blocks_[block_idx_offset]); } inline void From 0e09b82457b8e79ebe346f4158911b0bbe72bec9 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Mon, 3 Mar 2025 09:09:13 +0000 Subject: [PATCH 25/42] undo cast to size_t --- clients/drcachesim/simulator/caching_device.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/clients/drcachesim/simulator/caching_device.cpp b/clients/drcachesim/simulator/caching_device.cpp index fff2f45e7e8..8626c004f11 100644 --- a/clients/drcachesim/simulator/caching_device.cpp +++ b/clients/drcachesim/simulator/caching_device.cpp @@ -99,7 +99,10 @@ caching_device_t::init(int associativity, int64_t block_size, int64_t num_blocks // Make sure num_blocks_ is evenly divisible by associativity if (blocks_per_way_ * associativity_ != num_blocks_) return false; - blocks_per_way_mask_ = blocks_per_way_ - 1; + // Make sure blocks_per_way_ fits in the mask and can be used as an index. + if (blocks_per_way_ > std::numeric_limits::max()) + return false; + blocks_per_way_mask_ = static_cast(blocks_per_way_ - 1); block_size_bits_ = compute_log2(block_size); // Non-power-of-two associativities and total cache sizes are allowed, so // long as the number blocks per cache way is a power of two. @@ -145,7 +148,7 @@ caching_device_t::find_caching_device_block(addr_t tag) assert(it->second.first->tag_ == tag); return it->second; } - int64_t block_idx = compute_block_idx(tag); + int block_idx = compute_block_idx(tag); for (int way = 0; way < associativity_; ++way) { caching_device_block_t &block = get_caching_device_block(block_idx, way); if (block.tag_ == tag) From 9168c9aedbc54f4539046a001f163a750b220521 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Mon, 3 Mar 2025 09:14:14 +0000 Subject: [PATCH 26/42] undo cast to size_t --- clients/drcachesim/simulator/caching_device.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/clients/drcachesim/simulator/caching_device.h b/clients/drcachesim/simulator/caching_device.h index e4150536192..c76afaaea76 100644 --- a/clients/drcachesim/simulator/caching_device.h +++ b/clients/drcachesim/simulator/caching_device.h @@ -130,7 +130,7 @@ class caching_device_t { } use_tag2block_table_ = use_hashtable; } - int64_t + int get_block_index(const addr_t addr) const { addr_t tag = compute_tag(addr); @@ -205,16 +205,15 @@ class caching_device_t { { return addr >> block_size_bits_; } - inline int64_t + inline int compute_block_idx(addr_t tag) const { return (tag & blocks_per_way_mask_) * associativity_; } inline caching_device_block_t & - get_caching_device_block(int64_t block_idx, int way) const + get_caching_device_block(int block_idx, int way) const { - size_t block_idx_offset = static_cast(block_idx + way); - return *(blocks_[block_idx_offset]); + return *(blocks_[block_idx + way]); } inline void @@ -270,7 +269,7 @@ class caching_device_t { caching_device_block_t **blocks_; int64_t blocks_per_way_; // Optimization fields for fast bit operations - int64_t blocks_per_way_mask_; + int blocks_per_way_mask_; int block_size_bits_; caching_device_stats_t *stats_; From dd96e6176009dfce2a365aba2be218399934ef4c Mon Sep 17 00:00:00 2001 From: Or Almer Date: Mon, 3 Mar 2025 09:38:24 +0000 Subject: [PATCH 27/42] auto format --- .../create_cache_replacement_policy.cpp | 6 +- .../cache_replacement_policy_unit_test.cpp | 44 +++++++------- .../tests/drcachesim_unit_tests.cpp | 60 ++++++++++--------- 3 files changed, 58 insertions(+), 52 deletions(-) diff --git a/clients/drcachesim/simulator/create_cache_replacement_policy.cpp b/clients/drcachesim/simulator/create_cache_replacement_policy.cpp index 71d205b1a6a..9c9f45bbacc 100644 --- a/clients/drcachesim/simulator/create_cache_replacement_policy.cpp +++ b/clients/drcachesim/simulator/create_cache_replacement_policy.cpp @@ -54,9 +54,11 @@ create_cache_replacement_policy(const std::string &policy, int num_blocks, if (policy == REPLACE_POLICY_LFU) return std::unique_ptr(new policy_lfu_t(num_blocks, associativity)); if (policy == REPLACE_POLICY_FIFO) - return std::unique_ptr(new policy_fifo_t(num_blocks, associativity)); + return std::unique_ptr( + new policy_fifo_t(num_blocks, associativity)); if (policy == REPLACE_POLICY_BIT_PLRU) - return std::unique_ptr(new policy_bit_plru_t(num_blocks, associativity)); + return std::unique_ptr( + new policy_bit_plru_t(num_blocks, associativity)); return nullptr; } diff --git a/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp b/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp index 2cbcef47331..3d9ab8a2a2f 100644 --- a/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp +++ b/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp @@ -90,7 +90,8 @@ template class caching_device_policy_test_t : public T { ref.data.addr = addr; ref.data.pid = 1; this->request(ref); - assert(this->get_next_way_to_replace(this->get_block_index(addr)) == expected_replacement_way_after_access); + assert(this->get_next_way_to_replace(this->get_block_index(addr)) == + expected_replacement_way_after_access); } void @@ -153,9 +154,9 @@ unit_test_cache_lru_four_way() { caching_device_policy_test_t cache_lru_test(/*associativity=*/4, /*line_size=*/32); - cache_lru_test.initialize_cache( - std::unique_ptr(new policy_lru_t(/*num_blocks=*/256 / 4, /*associativity=*/4)), - 256); + cache_lru_test.initialize_cache(std::unique_ptr(new policy_lru_t( + /*num_blocks=*/256 / 4, /*associativity=*/4)), + 256); assert(cache_lru_test.get_replace_policy() == "LRU"); assert(cache_lru_test.block_indices_are_identical(addr_vec)); @@ -193,9 +194,9 @@ unit_test_cache_lru_eight_way() { caching_device_policy_test_t cache_lru_test(/*associativity=*/8, /*line_size=*/64); - cache_lru_test.initialize_cache( - std::unique_ptr(new policy_lru_t(/*num_blocks=*/1024 / 8, /*associativity=*/8)), - 1024); + cache_lru_test.initialize_cache(std::unique_ptr(new policy_lru_t( + /*num_blocks=*/1024 / 8, /*associativity=*/8)), + 1024); assert(cache_lru_test.get_replace_policy() == "LRU"); assert(cache_lru_test.block_indices_are_identical(addr_vec)); @@ -240,9 +241,9 @@ unit_test_cache_fifo_four_way() { caching_device_policy_test_t cache_fifo_test(/*associativity=*/4, /*line_size=*/32); - cache_fifo_test.initialize_cache( - std::unique_ptr(new policy_fifo_t(/*num_blocks=*/256 / 4, /*associativity=*/4)), - 256); + cache_fifo_test.initialize_cache(std::unique_ptr(new policy_fifo_t( + /*num_blocks=*/256 / 4, /*associativity=*/4)), + 256); assert(cache_fifo_test.get_replace_policy() == "FIFO"); assert(cache_fifo_test.block_indices_are_identical(addr_vec)); @@ -283,9 +284,9 @@ unit_test_cache_fifo_eight_way() { caching_device_policy_test_t cache_fifo_test(/*associativity=*/8, /*line_size=*/64); - cache_fifo_test.initialize_cache( - std::unique_ptr(new policy_fifo_t(/*num_blocks=*/1024 / 8, /*associativity=*/8)), - 1024); + cache_fifo_test.initialize_cache(std::unique_ptr(new policy_fifo_t( + /*num_blocks=*/1024 / 8, /*associativity=*/8)), + 1024); assert(cache_fifo_test.get_replace_policy() == "FIFO"); assert(cache_fifo_test.block_indices_are_identical(addr_vec)); @@ -324,9 +325,9 @@ unit_test_cache_lfu_four_way() { caching_device_policy_test_t cache_lfu_test(/*associativity=*/4, /*line_size=*/32); - cache_lfu_test.initialize_cache( - std::unique_ptr(new policy_lfu_t(/*num_blocks=*/256 / 4, /*associativity=*/4)), - 256); + cache_lfu_test.initialize_cache(std::unique_ptr(new policy_lfu_t( + /*num_blocks=*/256 / 4, /*associativity=*/4)), + 256); assert(cache_lfu_test.get_replace_policy() == "LFU"); assert(cache_lfu_test.block_indices_are_identical(addr_vec)); @@ -365,9 +366,9 @@ unit_test_cache_lfu_eight_way() { caching_device_policy_test_t cache_lfu_test(/*associativity=*/8, /*line_size=*/64); - cache_lfu_test.initialize_cache( - std::unique_ptr(new policy_lfu_t(/*num_blocks=*/1024 / 8, /*associativity=*/8)), - 1024); + cache_lfu_test.initialize_cache(std::unique_ptr(new policy_lfu_t( + /*num_blocks=*/1024 / 8, /*associativity=*/8)), + 1024); assert(cache_lfu_test.get_replace_policy() == "LFU"); assert(cache_lfu_test.block_indices_are_identical(addr_vec)); @@ -437,8 +438,9 @@ unit_test_tlb_lfu_four_way() { caching_device_policy_test_t tlb_lfu_test(/*associativity=*/4, /*line_size=*/64); - tlb_lfu_test.initialize_cache( - std::unique_ptr(new policy_lfu_t(1 /*num_blocks*/, 4 /*associativity*/)), 4); + tlb_lfu_test.initialize_cache(std::unique_ptr(new policy_lfu_t( + 1 /*num_blocks*/, 4 /*associativity*/)), + 4); assert(tlb_lfu_test.get_replace_policy() == "LFU"); assert(tlb_lfu_test.block_indices_are_identical(addr_vec)); assert(tlb_lfu_test.tags_are_different(addr_vec)); diff --git a/clients/drcachesim/tests/drcachesim_unit_tests.cpp b/clients/drcachesim/tests/drcachesim_unit_tests.cpp index 51df5d33a6c..0f16be451b2 100644 --- a/clients/drcachesim/tests/drcachesim_unit_tests.cpp +++ b/clients/drcachesim/tests/drcachesim_unit_tests.cpp @@ -656,7 +656,8 @@ unit_test_cache_associativity() caching_device_stats_t stats(/*miss_file=*/"", LINE_SIZE); bool initialized = cache.init(assoc, LINE_SIZE, total_size, /*parent=*/nullptr, &stats, - std::unique_ptr(new policy_lru_t(total_size / assoc, assoc))); + std::unique_ptr( + new policy_lru_t(total_size / assoc, assoc))); assert(initialized); assert(cache.get_associativity() == assoc); // Test start address is arbitrary. @@ -707,8 +708,8 @@ unit_test_cache_size() bool initialized = cache.init(associativity, LINE_SIZE, cache_size, /*parent=*/nullptr, &stats, - std::unique_ptr( - new policy_lru_t(cache_size / associativity, associativity))); + std::unique_ptr(new policy_lru_t( + cache_size / associativity, associativity))); assert(initialized); assert(cache.get_size_bytes() == cache_size); static constexpr int NUM_LOOPS = 3; // Anything >=2 should work. @@ -802,32 +803,32 @@ unit_test_cache_bad_configs() // 0 values are bad for any of these parameters. std::cerr << "Testing 0 parameters.\n"; - assert(!cache.init( - 0, SAFE_LINE_SIZE, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, - std::unique_ptr(new policy_lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); - assert(!cache.init( - SAFE_ASSOC, 0, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, - std::unique_ptr(new policy_lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); - assert(!cache.init( - SAFE_ASSOC, SAFE_LINE_SIZE, 0, /*parent=*/nullptr, &stats, - std::unique_ptr(new policy_lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); + assert(!cache.init(0, SAFE_LINE_SIZE, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, + std::unique_ptr( + new policy_lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); + assert(!cache.init(SAFE_ASSOC, 0, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, + std::unique_ptr( + new policy_lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); + assert(!cache.init(SAFE_ASSOC, SAFE_LINE_SIZE, 0, /*parent=*/nullptr, &stats, + std::unique_ptr( + new policy_lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); assert(!cache.init(SAFE_ASSOC, SAFE_LINE_SIZE, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, nullptr)); // Test other bad line sizes: <4 and/or non-power-of-two. std::cerr << "Testing bad line size parameters.\n"; - assert(!cache.init( - SAFE_ASSOC, 1, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, - std::unique_ptr(new policy_lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); - assert(!cache.init( - SAFE_ASSOC, 2, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, - std::unique_ptr(new policy_lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); - assert(!cache.init( - SAFE_ASSOC, 7, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, - std::unique_ptr(new policy_lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); - assert(!cache.init( - SAFE_ASSOC, 65, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, - std::unique_ptr(new policy_lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); + assert(!cache.init(SAFE_ASSOC, 1, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, + std::unique_ptr( + new policy_lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); + assert(!cache.init(SAFE_ASSOC, 2, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, + std::unique_ptr( + new policy_lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); + assert(!cache.init(SAFE_ASSOC, 7, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, + std::unique_ptr( + new policy_lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); + assert(!cache.init(SAFE_ASSOC, 65, SAFE_CACHE_SIZE, /*parent=*/nullptr, &stats, + std::unique_ptr( + new policy_lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); // Size, associativity, and line_size are related. The requirement is that // size/associativity is a power-of-two, and >= line_size, so try some @@ -840,9 +841,10 @@ unit_test_cache_bad_configs() { 3, 1024 }, { 4, 768 }, { 64, 64 }, { 16, 8 * SAFE_LINE_SIZE } }; for (const auto &combo : bad_combinations) { - assert(!cache.init( - combo.assoc, SAFE_LINE_SIZE, combo.size, /*parent=*/nullptr, &stats, - std::unique_ptr(new policy_lru_t(SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); + assert(!cache.init(combo.assoc, SAFE_LINE_SIZE, combo.size, /*parent=*/nullptr, + &stats, + std::unique_ptr(new policy_lru_t( + SAFE_CACHE_SIZE / SAFE_ASSOC, SAFE_ASSOC)))); } } @@ -878,8 +880,8 @@ unit_test_cache_accessors() cache.init(associativity, line_size, total_size, /*parent=*/nullptr, &stats, /*replacement_policy=*/ - std::unique_ptr( - new policy_lru_t(total_size / associativity, associativity)), + std::unique_ptr(new policy_lru_t( + total_size / associativity, associativity)), /*prefetcher=*/nullptr, policy, coherent); assert(initialized); assert(cache.get_stats() == &stats); From c33d782c7238200aaa473d612b8471709a8d9e94 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Mon, 3 Mar 2025 09:42:12 +0000 Subject: [PATCH 28/42] auto format --- .../simulator/create_cache_replacement_policy.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/clients/drcachesim/simulator/create_cache_replacement_policy.cpp b/clients/drcachesim/simulator/create_cache_replacement_policy.cpp index 9c9f45bbacc..fa4cf4afdd5 100644 --- a/clients/drcachesim/simulator/create_cache_replacement_policy.cpp +++ b/clients/drcachesim/simulator/create_cache_replacement_policy.cpp @@ -49,16 +49,20 @@ create_cache_replacement_policy(const std::string &policy, int num_blocks, int associativity) { if (policy == REPLACE_POLICY_NON_SPECIFIED || // default LRU - policy == REPLACE_POLICY_LRU) // set to LRU + policy == REPLACE_POLICY_LRU) { // set to LRU return std::unique_ptr(new policy_lru_t(num_blocks, associativity)); - if (policy == REPLACE_POLICY_LFU) + } + if (policy == REPLACE_POLICY_LFU) { return std::unique_ptr(new policy_lfu_t(num_blocks, associativity)); - if (policy == REPLACE_POLICY_FIFO) + } + if (policy == REPLACE_POLICY_FIFO) { return std::unique_ptr( new policy_fifo_t(num_blocks, associativity)); - if (policy == REPLACE_POLICY_BIT_PLRU) + } + if (policy == REPLACE_POLICY_BIT_PLRU) { return std::unique_ptr( new policy_bit_plru_t(num_blocks, associativity)); + } return nullptr; } From fd0ce67685588b96ee402884c100d9804dcd113b Mon Sep 17 00:00:00 2001 From: Or Almer Date: Mon, 3 Mar 2025 09:43:54 +0000 Subject: [PATCH 29/42] auto format --- clients/drcachesim/tools/filter/cache_filter.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/clients/drcachesim/tools/filter/cache_filter.cpp b/clients/drcachesim/tools/filter/cache_filter.cpp index 2b4983e324c..188a8b2d193 100644 --- a/clients/drcachesim/tools/filter/cache_filter.cpp +++ b/clients/drcachesim/tools/filter/cache_filter.cpp @@ -79,10 +79,12 @@ cache_filter_t::parallel_shard_init(memtrace_stream_t *shard_stream, bool partial_trace_filter) { per_shard_t *per_shard = new per_shard_t; - if (!(per_shard->cache.init(cache_associativity_, cache_line_size_, cache_size_, - nullptr, new cache_filter_stats_t(cache_line_size_), - std::unique_ptr(new policy_lru_t(cache_size_ / cache_associativity_, cache_associativity_)), - nullptr))) { + if (!(per_shard->cache.init( + cache_associativity_, cache_line_size_, cache_size_, nullptr, + new cache_filter_stats_t(cache_line_size_), + std::unique_ptr(new policy_lru_t( + cache_size_ / cache_associativity_, cache_associativity_)), + nullptr))) { error_string_ = "Failed to initialize cache."; return nullptr; } From 3274cb3dd5f4c0a5e16f7ea6baab968c3f3129e4 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Mon, 3 Mar 2025 09:55:24 +0000 Subject: [PATCH 30/42] auto format --- clients/drcachesim/simulator/caching_device.h | 7 +++---- .../simulator/create_cache_replacement_policy.cpp | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/clients/drcachesim/simulator/caching_device.h b/clients/drcachesim/simulator/caching_device.h index 1b461ada154..ce97a83bcb7 100644 --- a/clients/drcachesim/simulator/caching_device.h +++ b/clients/drcachesim/simulator/caching_device.h @@ -36,7 +36,6 @@ #ifndef _CACHING_DEVICE_H_ #define _CACHING_DEVICE_H_ 1 -#include #include #include #include @@ -133,7 +132,7 @@ class caching_device_t { } use_tag2block_table_ = use_hashtable; } - int64_t + int get_block_index(const addr_t addr) const { addr_t tag = compute_tag(addr); @@ -208,7 +207,7 @@ class caching_device_t { { return addr >> block_size_bits_; } - inline int64_t + inline int compute_block_idx(addr_t tag) const { return (tag & blocks_per_way_mask_) * associativity_; @@ -272,7 +271,7 @@ class caching_device_t { caching_device_block_t **blocks_; int64_t blocks_per_way_; // Optimization fields for fast bit operations - int64_t blocks_per_way_mask_; + int blocks_per_way_mask_; int block_size_bits_; caching_device_stats_t *stats_; diff --git a/clients/drcachesim/simulator/create_cache_replacement_policy.cpp b/clients/drcachesim/simulator/create_cache_replacement_policy.cpp index fa4cf4afdd5..d3b381b2753 100644 --- a/clients/drcachesim/simulator/create_cache_replacement_policy.cpp +++ b/clients/drcachesim/simulator/create_cache_replacement_policy.cpp @@ -48,8 +48,8 @@ std::unique_ptr create_cache_replacement_policy(const std::string &policy, int num_blocks, int associativity) { - if (policy == REPLACE_POLICY_NON_SPECIFIED || // default LRU - policy == REPLACE_POLICY_LRU) { // set to LRU + // default LRU + if (policy == REPLACE_POLICY_NON_SPECIFIED || policy == REPLACE_POLICY_LRU) { return std::unique_ptr(new policy_lru_t(num_blocks, associativity)); } if (policy == REPLACE_POLICY_LFU) { From ef4a09d275fa293f99686aad059da83bf2d82113 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Mon, 3 Mar 2025 10:00:26 +0000 Subject: [PATCH 31/42] auto format --- clients/drcachesim/tests/drcachesim_unit_tests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clients/drcachesim/tests/drcachesim_unit_tests.cpp b/clients/drcachesim/tests/drcachesim_unit_tests.cpp index 0f16be451b2..2bba954cc7c 100644 --- a/clients/drcachesim/tests/drcachesim_unit_tests.cpp +++ b/clients/drcachesim/tests/drcachesim_unit_tests.cpp @@ -447,9 +447,9 @@ LLC { class test_cache_simulator_t : public cache_simulator_t { public: test_cache_simulator_t(const cache_simulator_knobs_t &knobs) - : cache_simulator_t(knobs) { }; + : cache_simulator_t(knobs) {}; test_cache_simulator_t(std::istream *config_file) - : cache_simulator_t(config_file) { }; + : cache_simulator_t(config_file) {}; // Returns cache_t* for named cache if it exists, else faults. cache_t * get_named_cache(std::string name) From d601accbf1d1fa1e71988c5e4033ed07afcc3af7 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Mon, 3 Mar 2025 14:18:55 +0000 Subject: [PATCH 32/42] Add set replace policy --- clients/drcachesim/simulator/caching_device.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/clients/drcachesim/simulator/caching_device.h b/clients/drcachesim/simulator/caching_device.h index ce97a83bcb7..a76d7af9c24 100644 --- a/clients/drcachesim/simulator/caching_device.h +++ b/clients/drcachesim/simulator/caching_device.h @@ -180,6 +180,11 @@ class caching_device_t { { return replacement_policy_->get_name(); } + virtual void + set_replace_policy(std::unique_ptr replacement_policy) + { + replacement_policy_ = std::move(replacement_policy); + } virtual const std::string & get_name() const { From 37f5302b25be32769beba2d23c50f2d93052db8d Mon Sep 17 00:00:00 2001 From: Or Almer Date: Mon, 3 Mar 2025 15:48:12 +0000 Subject: [PATCH 33/42] Add includes --- clients/drcachesim/simulator/cache.cpp | 1 + clients/drcachesim/simulator/cache_fifo.cpp | 1 + clients/drcachesim/simulator/cache_lru.cpp | 1 + clients/drcachesim/simulator/caching_device.cpp | 2 ++ clients/drcachesim/simulator/caching_device.h | 1 + 5 files changed, 6 insertions(+) diff --git a/clients/drcachesim/simulator/cache.cpp b/clients/drcachesim/simulator/cache.cpp index 450ce592947..a98255154e7 100644 --- a/clients/drcachesim/simulator/cache.cpp +++ b/clients/drcachesim/simulator/cache.cpp @@ -34,6 +34,7 @@ #include +#include #include #include diff --git a/clients/drcachesim/simulator/cache_fifo.cpp b/clients/drcachesim/simulator/cache_fifo.cpp index e341f7d61a1..cd4903f6d8f 100644 --- a/clients/drcachesim/simulator/cache_fifo.cpp +++ b/clients/drcachesim/simulator/cache_fifo.cpp @@ -34,6 +34,7 @@ #include +#include #include #include "cache.h" diff --git a/clients/drcachesim/simulator/cache_lru.cpp b/clients/drcachesim/simulator/cache_lru.cpp index ef5a66498a1..7f023de5a6b 100644 --- a/clients/drcachesim/simulator/cache_lru.cpp +++ b/clients/drcachesim/simulator/cache_lru.cpp @@ -32,6 +32,7 @@ #include "cache_lru.h" +#include #include #include "cache.h" diff --git a/clients/drcachesim/simulator/caching_device.cpp b/clients/drcachesim/simulator/caching_device.cpp index 8626c004f11..05ab7d2abd9 100644 --- a/clients/drcachesim/simulator/caching_device.cpp +++ b/clients/drcachesim/simulator/caching_device.cpp @@ -35,7 +35,9 @@ #include #include +#include #include +#include #include #include #include diff --git a/clients/drcachesim/simulator/caching_device.h b/clients/drcachesim/simulator/caching_device.h index c76afaaea76..afd660728b4 100644 --- a/clients/drcachesim/simulator/caching_device.h +++ b/clients/drcachesim/simulator/caching_device.h @@ -37,6 +37,7 @@ #define _CACHING_DEVICE_H_ 1 #include +#include #include #include #include From b108ea70aff89345ccb3dd84ae6e2d7aa7d31a54 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Tue, 4 Mar 2025 07:13:44 +0000 Subject: [PATCH 34/42] CR fixes - format and release doc --- api/docs/release.dox | 4 ++-- clients/drcachesim/simulator/caching_device.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/api/docs/release.dox b/api/docs/release.dox index 419a533bf7d..8f08ade79b4 100644 --- a/api/docs/release.dox +++ b/api/docs/release.dox @@ -126,8 +126,6 @@ clients. The changes between version \DR_VERSION and 11.3.0 include the following compatibility changes: - - Changed the types of `block_size`, `num_lines`, `blocks_per_way_mask_` to `int64_t` - in dynamorio::drmemtrace::caching_device_t and its deriving classes. - On 32-bit Arm the size of #dr_mcontext_t has been increased by 4 and the struct is now required to be 8-byte aligned. The offset of the field "simd" has changed. @@ -136,6 +134,8 @@ changes: written with the path to the memory dump file. Further non-compatibility-affecting changes include: + - Changed the types of `block_size`, `total_size`, `num_blocks`, to `int64_t` + in dynamorio::drmemtrace::caching_device_t and its deriving classes. - Added support for reading a single drmemtrace trace file from stdin via "-infile -". - Added the #dynamorio::drmemtrace::decode_cache_t library to make it easier and more diff --git a/clients/drcachesim/simulator/caching_device.h b/clients/drcachesim/simulator/caching_device.h index afd660728b4..7ae3bf485ab 100644 --- a/clients/drcachesim/simulator/caching_device.h +++ b/clients/drcachesim/simulator/caching_device.h @@ -65,6 +65,7 @@ class prefetcher_t; // NON_INC_NON_EXC = Non-Inclusive Non-Exclusive, aka NINE. enum class cache_inclusion_policy_t { NON_INC_NON_EXC, INCLUSIVE, EXCLUSIVE }; + class caching_device_t { public: explicit caching_device_t(const std::string &name = "caching_device"); From a7aa74dd70addf306f7d0ffde2f1b3412a1b6bd7 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Tue, 4 Mar 2025 08:53:27 +0000 Subject: [PATCH 35/42] CR fixes - sort includes, add comments, name changes --- clients/drcachesim/simulator/cache.h | 2 +- .../drcachesim/simulator/caching_device.cpp | 1 + clients/drcachesim/simulator/caching_device.h | 2 +- .../drcachesim/simulator/policy_bit_plru.cpp | 8 +++--- .../drcachesim/simulator/policy_bit_plru.h | 6 ++-- clients/drcachesim/simulator/policy_lru.cpp | 2 +- .../drcachesim/simulator/tlb_simulator.cpp | 28 +++++++------------ 7 files changed, 22 insertions(+), 27 deletions(-) diff --git a/clients/drcachesim/simulator/cache.h b/clients/drcachesim/simulator/cache.h index 86cba097e16..ff26b0a32a2 100644 --- a/clients/drcachesim/simulator/cache.h +++ b/clients/drcachesim/simulator/cache.h @@ -37,8 +37,8 @@ #define _CACHE_H_ 1 #include -#include #include +#include #include "cache_line.h" #include "cache_replacement_policy.h" diff --git a/clients/drcachesim/simulator/caching_device.cpp b/clients/drcachesim/simulator/caching_device.cpp index 596331ac491..5d1ffcf94b4 100644 --- a/clients/drcachesim/simulator/caching_device.cpp +++ b/clients/drcachesim/simulator/caching_device.cpp @@ -123,6 +123,7 @@ caching_device_t::init(int associativity, int64_t block_size, int64_t num_blocks id_ = id; snoop_filter_ = snoop_filter; coherent_cache_ = coherent_cache; + blocks_ = new caching_device_block_t *[static_cast(num_blocks_)]; init_blocks(); diff --git a/clients/drcachesim/simulator/caching_device.h b/clients/drcachesim/simulator/caching_device.h index 4483846fd08..88061cb91fa 100644 --- a/clients/drcachesim/simulator/caching_device.h +++ b/clients/drcachesim/simulator/caching_device.h @@ -45,11 +45,11 @@ #include #include +#include "cache_replacement_policy.h" #include "caching_device_block.h" #include "caching_device_stats.h" #include "memref.h" #include "trace_entry.h" -#include "cache_replacement_policy.h" namespace dynamorio { namespace drmemtrace { diff --git a/clients/drcachesim/simulator/policy_bit_plru.cpp b/clients/drcachesim/simulator/policy_bit_plru.cpp index 24495ba04d6..02ac08c4b5b 100644 --- a/clients/drcachesim/simulator/policy_bit_plru.cpp +++ b/clients/drcachesim/simulator/policy_bit_plru.cpp @@ -40,7 +40,7 @@ namespace drmemtrace { policy_bit_plru_t::policy_bit_plru_t(int num_blocks, int associativity, int seed) : cache_replacement_policy_t(num_blocks, associativity) - , block_set_counts_(num_blocks, 0) + , block_num_ones_(num_blocks, 0) , gen_(seed == -1 ? std::random_device()() : seed) { // Initialize the bit vector for each block. @@ -57,9 +57,9 @@ policy_bit_plru_t::access_update(int block_idx, int way) // Set the bit for the accessed way. if (!block_bits_[block_idx][way]) { block_bits_[block_idx][way] = true; - block_set_counts_[block_idx]++; + block_num_ones_[block_idx]++; } - if (block_set_counts_[block_idx] < associativity_) { + if (block_num_ones_[block_idx] < associativity_) { // Finished. return; } @@ -67,7 +67,7 @@ policy_bit_plru_t::access_update(int block_idx, int way) for (int i = 0; i < associativity_; ++i) { block_bits_[block_idx][i] = false; } - block_set_counts_[block_idx] = 1; + block_num_ones_[block_idx] = 1; block_bits_[block_idx][way] = true; } diff --git a/clients/drcachesim/simulator/policy_bit_plru.h b/clients/drcachesim/simulator/policy_bit_plru.h index f9ffc1d246a..d142088ec40 100644 --- a/clients/drcachesim/simulator/policy_bit_plru.h +++ b/clients/drcachesim/simulator/policy_bit_plru.h @@ -43,7 +43,7 @@ namespace dynamorio { namespace drmemtrace { /** - * A replacement policy that uses a bit per wat to track access frequency. + * A replacement policy that uses a bit per way to track access frequency. * * On access, a way's bit is set to 1. Once all bits are set, the whole block's bits * are set to 0. A random way with a 0 bit is chosen for replacement. @@ -64,8 +64,10 @@ class policy_bit_plru_t : public cache_replacement_policy_t { ~policy_bit_plru_t() override = default; private: + // A bit per way for each block. std::vector> block_bits_; - std::vector block_set_counts_; + // The amount of bits set to 1 for each block. + std::vector block_num_ones_; std::mt19937 gen_; }; diff --git a/clients/drcachesim/simulator/policy_lru.cpp b/clients/drcachesim/simulator/policy_lru.cpp index e06ec814aa5..0d09778f900 100644 --- a/clients/drcachesim/simulator/policy_lru.cpp +++ b/clients/drcachesim/simulator/policy_lru.cpp @@ -53,7 +53,7 @@ policy_lru_t::access_update(int block_idx, int way) // Optimization: return early if it is a repeated access. if (count == 0) return; - // We inc all the counters that are not larger than cnt for LRU. + // We inc all the counters that are not larger than count for LRU. for (int i = 0; i < associativity_; ++i) { if (i != way && lru_counters_[block_idx][i] <= count) lru_counters_[block_idx][i]++; diff --git a/clients/drcachesim/simulator/tlb_simulator.cpp b/clients/drcachesim/simulator/tlb_simulator.cpp index 41dbe35adb9..c538421eb81 100644 --- a/clients/drcachesim/simulator/tlb_simulator.cpp +++ b/clients/drcachesim/simulator/tlb_simulator.cpp @@ -36,6 +36,7 @@ #include #include +#include #include #include @@ -95,24 +96,15 @@ tlb_simulator_t::tlb_simulator_t(const tlb_simulator_knobs_t &knobs) lltlbs_[i] = NULL; } for (unsigned int i = 0; i < knobs_.num_cores; i++) { - itlbs_[i] = new tlb_t("itlb"); - if (itlbs_[i] == NULL) { - error_string_ = "Failed to create itlbs_"; - success_ = false; - return; - } - dtlbs_[i] = new tlb_t("dtlb"); - if (dtlbs_[i] == NULL) { - error_string_ = "Failed to create dtlbs_"; - success_ = false; - return; - } - lltlbs_[i] = new tlb_t("lltlb"); - if (lltlbs_[i] == NULL) { - error_string_ = "Failed to create lltlbs_"; - success_ = false; - return; - } + std::stringstream ss_itlb; + ss_itlb << "itlb " << i; + itlbs_[i] = new tlb_t(ss_itlb.str()); + std::stringstream ss_dtlb; + ss_dtlb << "dtlb " << i; + dtlbs_[i] = new tlb_t(ss_dtlb.str()); + std::stringstream ss_lltlb; + ss_lltlb << "lltlb " << i; + lltlbs_[i] = new tlb_t(ss_lltlb.str()); auto replace_policy = create_cache_replacement_policy( knobs_.TLB_replace_policy, knobs_.TLB_L1I_entries / knobs_.TLB_L1I_assoc, knobs_.TLB_L1I_assoc); From 322b40c9366bcda7d890d5a55da371c10a6f54a2 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Sun, 9 Mar 2025 15:34:28 +0000 Subject: [PATCH 36/42] CR fixes - added valid bits vector --- .../simulator/cache_replacement_policy.h | 33 +++++++++++++++++-- .../drcachesim/simulator/caching_device.cpp | 6 ++-- .../drcachesim/simulator/policy_bit_plru.cpp | 7 +++- .../drcachesim/simulator/policy_bit_plru.h | 5 +-- clients/drcachesim/simulator/policy_fifo.cpp | 3 +- clients/drcachesim/simulator/policy_fifo.h | 6 ++-- clients/drcachesim/simulator/policy_lfu.cpp | 7 +++- clients/drcachesim/simulator/policy_lfu.h | 3 +- clients/drcachesim/simulator/policy_lru.cpp | 7 +++- clients/drcachesim/simulator/policy_lru.h | 3 +- .../drcachesim/simulator/tlb_simulator.cpp | 13 +++----- .../cache_replacement_policy_unit_test.cpp | 30 ++++++++--------- 12 files changed, 83 insertions(+), 40 deletions(-) diff --git a/clients/drcachesim/simulator/cache_replacement_policy.h b/clients/drcachesim/simulator/cache_replacement_policy.h index 30b7d2920dd..335ab97a2e2 100644 --- a/clients/drcachesim/simulator/cache_replacement_policy.h +++ b/clients/drcachesim/simulator/cache_replacement_policy.h @@ -34,6 +34,7 @@ #define _CACHE_REPLACEMENT_POLICY_H_ 1 #include +#include namespace dynamorio { namespace drmemtrace { @@ -44,6 +45,17 @@ namespace drmemtrace { * Holds the necessary information to implement a cache replacement policy, * and provides a replacement-specific get_next_way_to_replace() method for * `caching_device_t`. + * + * The policy recieves the following updates: + * - When an existing way is accessed, `access_update()` is called. + * - When a way is evicted, `eviction_update()` is called on the evicted way, and + * `access_update()` is called on the new way immediately after. + * - When a way is invalidated, nothing is done - caching_device_t should keep track of + * which ways are valid. + * + * The policy also provides a `get_next_way_to_replace()` method that returns + * the next way to replace in the block. `valid_ways` is a vector of booleans, + * where `valid_ways[way]` is true if the way is currently valid. */ class cache_replacement_policy_t { public: @@ -58,9 +70,13 @@ class cache_replacement_policy_t { /// Informs the replacement policy that an eviction has occurred. virtual void eviction_update(int block_idx, int way) = 0; - /// Returns the next way to replace in the block. + /* + * Returns the next way to replace in the block. + * valid_ways is a vector of booleans, where valid_ways[way] is true if the way + * is currently valid. + */ virtual int - get_next_way_to_replace(int block_idx) = 0; + get_next_way_to_replace(int block_idx, const std::vector &valid_ways) const = 0; /// Returns the name of the replacement policy. virtual std::string get_name() const = 0; @@ -69,13 +85,24 @@ class cache_replacement_policy_t { protected: virtual int - get_block_index(int block_idx) + get_block_index(int block_idx) const { // The block index points to the first way in the block, and the ways are stored // in a contiguous array, so we divide by the associativity to get the block // index. return block_idx / associativity_; } + /// Returns the first invalid way in the block, or -1 if all ways are valid. + virtual int + get_first_invalid_way(const std::vector &valid_ways) const + { + for (int way = 0; way < associativity_; ++way) { + if (!valid_ways[way]) { + return way; + } + } + return -1; + } int associativity_; int num_blocks_; }; diff --git a/clients/drcachesim/simulator/caching_device.cpp b/clients/drcachesim/simulator/caching_device.cpp index 596331ac491..789ac0de65c 100644 --- a/clients/drcachesim/simulator/caching_device.cpp +++ b/clients/drcachesim/simulator/caching_device.cpp @@ -286,11 +286,11 @@ caching_device_t::replace_which_way(int block_idx) int caching_device_t::get_next_way_to_replace(const int block_idx) const { + std::vector valid_ways(associativity_, false); for (int way = 0; way < associativity_; ++way) { - if (get_caching_device_block(block_idx, way).tag_ == TAG_INVALID) - return way; + valid_ways[way] = get_caching_device_block(block_idx, way).tag_ != TAG_INVALID; } - return replacement_policy_->get_next_way_to_replace(block_idx); + return replacement_policy_->get_next_way_to_replace(block_idx, valid_ways); } void diff --git a/clients/drcachesim/simulator/policy_bit_plru.cpp b/clients/drcachesim/simulator/policy_bit_plru.cpp index 02ac08c4b5b..a6f3a0b2549 100644 --- a/clients/drcachesim/simulator/policy_bit_plru.cpp +++ b/clients/drcachesim/simulator/policy_bit_plru.cpp @@ -78,8 +78,13 @@ policy_bit_plru_t::eviction_update(int block_idx, int way) } int -policy_bit_plru_t::get_next_way_to_replace(int block_idx) +policy_bit_plru_t::get_next_way_to_replace(int block_idx, + const std::vector &valid_ways) const { + int first_invalid_way = get_first_invalid_way(valid_ways); + if (first_invalid_way != -1) { + return first_invalid_way; + } block_idx = get_block_index(block_idx); std::vector unset_bits; for (int i = 0; i < associativity_; ++i) { diff --git a/clients/drcachesim/simulator/policy_bit_plru.h b/clients/drcachesim/simulator/policy_bit_plru.h index d142088ec40..458f326d088 100644 --- a/clients/drcachesim/simulator/policy_bit_plru.h +++ b/clients/drcachesim/simulator/policy_bit_plru.h @@ -57,7 +57,8 @@ class policy_bit_plru_t : public cache_replacement_policy_t { void eviction_update(int block_idx, int way) override; int - get_next_way_to_replace(int block_idx) override; + get_next_way_to_replace(int block_idx, + const std::vector &valid_ways) const override; std::string get_name() const override; @@ -68,7 +69,7 @@ class policy_bit_plru_t : public cache_replacement_policy_t { std::vector> block_bits_; // The amount of bits set to 1 for each block. std::vector block_num_ones_; - std::mt19937 gen_; + mutable std::mt19937 gen_; }; } // namespace drmemtrace diff --git a/clients/drcachesim/simulator/policy_fifo.cpp b/clients/drcachesim/simulator/policy_fifo.cpp index c33f0bff845..88de38e5bdb 100644 --- a/clients/drcachesim/simulator/policy_fifo.cpp +++ b/clients/drcachesim/simulator/policy_fifo.cpp @@ -67,7 +67,8 @@ policy_fifo_t::eviction_update(int block_idx, int way) } int -policy_fifo_t::get_next_way_to_replace(int block_idx) +policy_fifo_t::get_next_way_to_replace(int block_idx, + const std::vector &valid_ways) const { block_idx = get_block_index(block_idx); // The next way to replace is at the front of the FIFO list. diff --git a/clients/drcachesim/simulator/policy_fifo.h b/clients/drcachesim/simulator/policy_fifo.h index a14dc99fefa..afad2322f59 100644 --- a/clients/drcachesim/simulator/policy_fifo.h +++ b/clients/drcachesim/simulator/policy_fifo.h @@ -45,7 +45,8 @@ namespace drmemtrace { /** * A FIFO cache replacement policy. * - * The way wich was added (not accessed) first is replaced first. + * It is initialized with the ways in ascending order of their index, and ignores which + * ways are valid. */ class policy_fifo_t : public cache_replacement_policy_t { public: @@ -55,7 +56,8 @@ class policy_fifo_t : public cache_replacement_policy_t { void eviction_update(int block_idx, int way) override; int - get_next_way_to_replace(int block_idx) override; + get_next_way_to_replace(int block_idx, + const std::vector &valid_ways) const override; std::string get_name() const override; diff --git a/clients/drcachesim/simulator/policy_lfu.cpp b/clients/drcachesim/simulator/policy_lfu.cpp index 78add9335df..0cb772df914 100644 --- a/clients/drcachesim/simulator/policy_lfu.cpp +++ b/clients/drcachesim/simulator/policy_lfu.cpp @@ -63,8 +63,13 @@ policy_lfu_t::eviction_update(int block_idx, int way) } int -policy_lfu_t::get_next_way_to_replace(int block_idx) +policy_lfu_t::get_next_way_to_replace(int block_idx, + const std::vector &valid_ways) const { + int first_invalid_way = get_first_invalid_way(valid_ways); + if (first_invalid_way != -1) { + return first_invalid_way; + } // Find the way with the minimum frequency counter. block_idx = get_block_index(block_idx); int min_freq = access_counts_[block_idx][0]; diff --git a/clients/drcachesim/simulator/policy_lfu.h b/clients/drcachesim/simulator/policy_lfu.h index a7a17883025..ee6cb14e167 100644 --- a/clients/drcachesim/simulator/policy_lfu.h +++ b/clients/drcachesim/simulator/policy_lfu.h @@ -53,7 +53,8 @@ class policy_lfu_t : public cache_replacement_policy_t { void eviction_update(int block_idx, int way) override; int - get_next_way_to_replace(int block_idx) override; + get_next_way_to_replace(int block_idx, + const std::vector &valid_ways) const override; std::string get_name() const override; diff --git a/clients/drcachesim/simulator/policy_lru.cpp b/clients/drcachesim/simulator/policy_lru.cpp index 0d09778f900..df2e0b4edfb 100644 --- a/clients/drcachesim/simulator/policy_lru.cpp +++ b/clients/drcachesim/simulator/policy_lru.cpp @@ -69,8 +69,13 @@ policy_lru_t::eviction_update(int block_idx, int way) } int -policy_lru_t::get_next_way_to_replace(int block_idx) +policy_lru_t::get_next_way_to_replace(int block_idx, + const std::vector &valid_ways) const { + int first_invalid_way = get_first_invalid_way(valid_ways); + if (first_invalid_way != -1) { + return first_invalid_way; + } block_idx = get_block_index(block_idx); // We implement LRU by picking the slot with the largest counter value. int max_counter = 0; diff --git a/clients/drcachesim/simulator/policy_lru.h b/clients/drcachesim/simulator/policy_lru.h index 60719945d26..42966b34bf5 100644 --- a/clients/drcachesim/simulator/policy_lru.h +++ b/clients/drcachesim/simulator/policy_lru.h @@ -55,7 +55,8 @@ class policy_lru_t : public cache_replacement_policy_t { void eviction_update(int block_idx, int way) override; int - get_next_way_to_replace(int block_idx) override; + get_next_way_to_replace(int block_idx, + const std::vector &valid_ways) const override; std::string get_name() const override; diff --git a/clients/drcachesim/simulator/tlb_simulator.cpp b/clients/drcachesim/simulator/tlb_simulator.cpp index c538421eb81..ee304e794ce 100644 --- a/clients/drcachesim/simulator/tlb_simulator.cpp +++ b/clients/drcachesim/simulator/tlb_simulator.cpp @@ -96,15 +96,10 @@ tlb_simulator_t::tlb_simulator_t(const tlb_simulator_knobs_t &knobs) lltlbs_[i] = NULL; } for (unsigned int i = 0; i < knobs_.num_cores; i++) { - std::stringstream ss_itlb; - ss_itlb << "itlb " << i; - itlbs_[i] = new tlb_t(ss_itlb.str()); - std::stringstream ss_dtlb; - ss_dtlb << "dtlb " << i; - dtlbs_[i] = new tlb_t(ss_dtlb.str()); - std::stringstream ss_lltlb; - ss_lltlb << "lltlb " << i; - lltlbs_[i] = new tlb_t(ss_lltlb.str()); + std::string core_str = std::to_string(i); + itlbs_[i] = new tlb_t("itlb " + core_str); + dtlbs_[i] = new tlb_t("dtlb " + core_str); + lltlbs_[i] = new tlb_t("lltlb " + core_str); auto replace_policy = create_cache_replacement_policy( knobs_.TLB_replace_policy, knobs_.TLB_L1I_entries / knobs_.TLB_L1I_assoc, knobs_.TLB_L1I_assoc); diff --git a/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp b/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp index 3d9ab8a2a2f..e4ea99006d5 100644 --- a/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp +++ b/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp @@ -265,18 +265,18 @@ unit_test_cache_fifo_four_way() cache_fifo_test.access_and_check(addr_vec[ADDR_H], 0); // e F G H cache_fifo_test.access_and_check(addr_vec[ADDR_A], 1); // A f G H - cache_fifo_test.invalidate_and_check(addr_vec[ADDR_G], 2); // A F x H + cache_fifo_test.invalidate_and_check(addr_vec[ADDR_G], 1); // A f X H - cache_fifo_test.access_and_check(addr_vec[ADDR_G], 1); // A f G H - cache_fifo_test.access_and_check(addr_vec[ADDR_B], 3); // A B G h + cache_fifo_test.access_and_check(addr_vec[ADDR_G], 2); // A G x H + cache_fifo_test.access_and_check(addr_vec[ADDR_B], 3); // A G B h - cache_fifo_test.invalidate_and_check(addr_vec[ADDR_H], 3); // A B G x - cache_fifo_test.invalidate_and_check(addr_vec[ADDR_A], 0); // x B G X + cache_fifo_test.invalidate_and_check(addr_vec[ADDR_H], 3); //n A G B x + cache_fifo_test.invalidate_and_check(addr_vec[ADDR_A], 3); // X G B x - cache_fifo_test.access_and_check(addr_vec[ADDR_A], 3); // A B G x - cache_fifo_test.access_and_check(addr_vec[ADDR_B], 3); // A B G x - cache_fifo_test.access_and_check(addr_vec[ADDR_C], 2); // A B g C - cache_fifo_test.access_and_check(addr_vec[ADDR_D], 1); // A b D C + cache_fifo_test.access_and_check(addr_vec[ADDR_A], 0); // x G B A + cache_fifo_test.access_and_check(addr_vec[ADDR_B], 0); // x G B A + cache_fifo_test.access_and_check(addr_vec[ADDR_C], 1); // C g B A + cache_fifo_test.access_and_check(addr_vec[ADDR_D], 2); // C D B A } void @@ -311,13 +311,13 @@ unit_test_cache_fifo_eight_way() cache_fifo_test.access_and_check(addr_vec[ADDR_L], 4); // I J K L e F G H cache_fifo_test.access_and_check(addr_vec[ADDR_L], 4); // I J K L e F G H - cache_fifo_test.invalidate_and_check(addr_vec[ADDR_G], 6); // I J K L R F x H - cache_fifo_test.invalidate_and_check(addr_vec[ADDR_K], 2); // I J x L E F X H + cache_fifo_test.invalidate_and_check(addr_vec[ADDR_G], 4); // I J K L e F X H + cache_fifo_test.invalidate_and_check(addr_vec[ADDR_K], 4); // I J X L e F X H - cache_fifo_test.access_and_check(addr_vec[ADDR_A], 6); // I J A L E F x H - cache_fifo_test.access_and_check(addr_vec[ADDR_B], 4); // I J K L e F B H - cache_fifo_test.access_and_check(addr_vec[ADDR_C], 5); // i J K L C f B H - cache_fifo_test.access_and_check(addr_vec[ADDR_D], 7); // I j K L C D b H + cache_fifo_test.access_and_check(addr_vec[ADDR_A], 5); // I J K L A f G H + cache_fifo_test.access_and_check(addr_vec[ADDR_B], 6); // I J K L A B g H + cache_fifo_test.access_and_check(addr_vec[ADDR_C], 7); // I J K L A B C h + cache_fifo_test.access_and_check(addr_vec[ADDR_D], 0); // i J K L A B C D } void From 0ff63004f09ba6637c9a02adb46dff98c438490a Mon Sep 17 00:00:00 2001 From: Or Almer Date: Sun, 9 Mar 2025 15:59:00 +0000 Subject: [PATCH 37/42] Fix test --- clients/drcachesim/tests/drcachesim_unit_tests.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/clients/drcachesim/tests/drcachesim_unit_tests.cpp b/clients/drcachesim/tests/drcachesim_unit_tests.cpp index 7495e8f7def..eafbe7a31a9 100644 --- a/clients/drcachesim/tests/drcachesim_unit_tests.cpp +++ b/clients/drcachesim/tests/drcachesim_unit_tests.cpp @@ -464,9 +464,12 @@ unit_test_set_parent() cache_t child_1; cache_t child_2; cache_t parent; - assert(child_1.init(1, 64, 1024, nullptr, new cache_stats_t(64, "", false, false))); - assert(child_2.init(1, 64, 1024, nullptr, new cache_stats_t(64, "", false, false))); - assert(parent.init(1, 64, 1024, nullptr, new cache_stats_t(64, "", false, false))); + assert(child_1.init(1, 64, 1024, nullptr, new cache_stats_t(64, "", false, false), + std::unique_ptr(new policy_lru_t(1024, 1)))); + assert(child_2.init(1, 64, 1024, nullptr, new cache_stats_t(64, "", false, false), + std::unique_ptr(new policy_lru_t(1024, 1)))); + assert(parent.init(1, 64, 1024, nullptr, new cache_stats_t(64, "", false, false), + std::unique_ptr(new policy_lru_t(1024, 1)))); // Test setting parent. child_1.set_parent(&parent); assert(child_1.get_parent() == &parent); From d0491329aff38178d7115cd77e567fc1fa93aa58 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Sun, 9 Mar 2025 16:22:58 +0000 Subject: [PATCH 38/42] Formatting --- clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp b/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp index e4ea99006d5..4c29869e123 100644 --- a/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp +++ b/clients/drcachesim/tests/cache_replacement_policy_unit_test.cpp @@ -270,7 +270,7 @@ unit_test_cache_fifo_four_way() cache_fifo_test.access_and_check(addr_vec[ADDR_G], 2); // A G x H cache_fifo_test.access_and_check(addr_vec[ADDR_B], 3); // A G B h - cache_fifo_test.invalidate_and_check(addr_vec[ADDR_H], 3); //n A G B x + cache_fifo_test.invalidate_and_check(addr_vec[ADDR_H], 3); // A G B x cache_fifo_test.invalidate_and_check(addr_vec[ADDR_A], 3); // X G B x cache_fifo_test.access_and_check(addr_vec[ADDR_A], 0); // x G B A From fd3aa95072095dbb6d475b8895fa0cc425e84e31 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Sun, 9 Mar 2025 16:52:14 +0000 Subject: [PATCH 39/42] Fix imports --- clients/drcachesim/simulator/create_cache_replacement_policy.h | 2 +- clients/drcachesim/simulator/policy_lfu.cpp | 1 - clients/drcachesim/simulator/tlb.cpp | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/clients/drcachesim/simulator/create_cache_replacement_policy.h b/clients/drcachesim/simulator/create_cache_replacement_policy.h index f6de68b952c..4dd9c29872f 100644 --- a/clients/drcachesim/simulator/create_cache_replacement_policy.h +++ b/clients/drcachesim/simulator/create_cache_replacement_policy.h @@ -33,8 +33,8 @@ #ifndef _CREATE_CACHE_REPLACEMENT_POLICY_H_ #define _CREATE_CACHE_REPLACEMENT_POLICY_H_ 1 -#include #include +#include #include "cache_replacement_policy.h" diff --git a/clients/drcachesim/simulator/policy_lfu.cpp b/clients/drcachesim/simulator/policy_lfu.cpp index 0cb772df914..c846bbccb7a 100644 --- a/clients/drcachesim/simulator/policy_lfu.cpp +++ b/clients/drcachesim/simulator/policy_lfu.cpp @@ -34,7 +34,6 @@ #include #include -#include namespace dynamorio { namespace drmemtrace { diff --git a/clients/drcachesim/simulator/tlb.cpp b/clients/drcachesim/simulator/tlb.cpp index 3f672e2c171..83c95acb228 100644 --- a/clients/drcachesim/simulator/tlb.cpp +++ b/clients/drcachesim/simulator/tlb.cpp @@ -35,7 +35,6 @@ #include #include -#include "memref.h" #include "caching_device.h" #include "caching_device_block.h" #include "memref.h" From 2e6e9bc8320b5fa1b8242252c11aef175a74cf01 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Tue, 11 Mar 2025 14:51:20 +0000 Subject: [PATCH 40/42] add in\validation tracking to the policy, and renamed blocks to the more appropriate lines --- clients/drcachesim/simulator/cache.cpp | 2 + .../simulator/cache_replacement_policy.h | 24 +++++---- .../drcachesim/simulator/cache_simulator.cpp | 8 +-- .../drcachesim/simulator/caching_device.cpp | 8 ++- clients/drcachesim/simulator/caching_device.h | 1 + .../drcachesim/simulator/policy_bit_plru.cpp | 54 ++++++++++++------- .../drcachesim/simulator/policy_bit_plru.h | 19 ++++--- clients/drcachesim/simulator/policy_fifo.cpp | 32 +++++++---- clients/drcachesim/simulator/policy_fifo.h | 11 ++-- clients/drcachesim/simulator/policy_lfu.cpp | 48 +++++++++++------ clients/drcachesim/simulator/policy_lfu.h | 13 +++-- clients/drcachesim/simulator/policy_lru.cpp | 46 ++++++++++------ clients/drcachesim/simulator/policy_lru.h | 11 ++-- 13 files changed, 182 insertions(+), 95 deletions(-) diff --git a/clients/drcachesim/simulator/cache.cpp b/clients/drcachesim/simulator/cache.cpp index 95e15ef17dc..7a978924ee6 100644 --- a/clients/drcachesim/simulator/cache.cpp +++ b/clients/drcachesim/simulator/cache.cpp @@ -96,6 +96,8 @@ cache_t::flush(const memref_t &memref) auto block_way = find_caching_device_block(tag); if (block_way.first == nullptr) continue; + replacement_policy_->invalidation_update(compute_block_idx(tag), + block_way.second); invalidate_caching_device_block(block_way.first); } // We flush parent_'s code cache here. diff --git a/clients/drcachesim/simulator/cache_replacement_policy.h b/clients/drcachesim/simulator/cache_replacement_policy.h index 335ab97a2e2..91f59abcc26 100644 --- a/clients/drcachesim/simulator/cache_replacement_policy.h +++ b/clients/drcachesim/simulator/cache_replacement_policy.h @@ -50,18 +50,18 @@ namespace drmemtrace { * - When an existing way is accessed, `access_update()` is called. * - When a way is evicted, `eviction_update()` is called on the evicted way, and * `access_update()` is called on the new way immediately after. - * - When a way is invalidated, nothing is done - caching_device_t should keep track of - * which ways are valid. + * - When a way is invalidated, `invalidation_update()` is called. + * - When a way is made valid, `validation_update()` is called. this can happen + * when a snooping is used. * * The policy also provides a `get_next_way_to_replace()` method that returns - * the next way to replace in the block. `valid_ways` is a vector of booleans, - * where `valid_ways[way]` is true if the way is currently valid. + * the next way to replace in the block. */ class cache_replacement_policy_t { public: - cache_replacement_policy_t(int num_blocks, int associativity) + cache_replacement_policy_t(int num_lines, int associativity) : associativity_(associativity) - , num_blocks_(num_blocks) + , num_lines_(num_lines) { } /// Informs the replacement policy that an access has occurred. @@ -70,13 +70,19 @@ class cache_replacement_policy_t { /// Informs the replacement policy that an eviction has occurred. virtual void eviction_update(int block_idx, int way) = 0; + /// Informs the replacement policy that an invalidation has occurred. + virtual void + invalidation_update(int block_idx, int way) = 0; + /// Informs the replacement policy that a way is now valid. + virtual void + validation_update(int block_idx, int way) = 0; /* * Returns the next way to replace in the block. * valid_ways is a vector of booleans, where valid_ways[way] is true if the way * is currently valid. */ virtual int - get_next_way_to_replace(int block_idx, const std::vector &valid_ways) const = 0; + get_next_way_to_replace(int block_idx) const = 0; /// Returns the name of the replacement policy. virtual std::string get_name() const = 0; @@ -85,7 +91,7 @@ class cache_replacement_policy_t { protected: virtual int - get_block_index(int block_idx) const + get_line_index(int block_idx) const { // The block index points to the first way in the block, and the ways are stored // in a contiguous array, so we divide by the associativity to get the block @@ -104,7 +110,7 @@ class cache_replacement_policy_t { return -1; } int associativity_; - int num_blocks_; + int num_lines_; }; } // namespace drmemtrace diff --git a/clients/drcachesim/simulator/cache_simulator.cpp b/clients/drcachesim/simulator/cache_simulator.cpp index 097135a8613..bae1638fe6a 100644 --- a/clients/drcachesim/simulator/cache_simulator.cpp +++ b/clients/drcachesim/simulator/cache_simulator.cpp @@ -127,7 +127,7 @@ cache_simulator_t::cache_simulator_t(const cache_simulator_knobs_t &knobs, new cache_stats_t((int)knobs_.line_size, knobs_.LL_miss_file, warmup_enabled_), create_cache_replacement_policy( - knobs_.replace_policy, (int)knobs_.LL_size / (int)knobs_.LL_assoc, + knobs_.replace_policy, (int)knobs_.LL_size / (int)knobs_.line_size, (int)knobs_.LL_assoc))) { error_string_ = "Usage error: failed to initialize LL cache. Ensure size divided by " @@ -158,7 +158,7 @@ cache_simulator_t::cache_simulator_t(const cache_simulator_knobs_t &knobs, new cache_stats_t((int)knobs_.line_size, "", warmup_enabled_, knobs_.model_coherence), create_cache_replacement_policy( - knobs_.replace_policy, (int)knobs_.L1I_size / (int)knobs_.L1I_assoc, + knobs_.replace_policy, (int)knobs_.L1I_size / (int)knobs_.line_size, (int)knobs_.L1I_assoc) /*replacement_policy*/, nullptr /*prefetcher*/, cache_inclusion_policy_t::NON_INC_NON_EXC, knobs_.model_coherence, 2 * i, snoop_filter_) || @@ -167,7 +167,7 @@ cache_simulator_t::cache_simulator_t(const cache_simulator_knobs_t &knobs, new cache_stats_t((int)knobs_.line_size, "", warmup_enabled_, knobs_.model_coherence), create_cache_replacement_policy( - knobs_.replace_policy, (int)knobs_.L1D_size / (int)knobs_.L1D_assoc, + knobs_.replace_policy, (int)knobs_.L1D_size / (int)knobs_.line_size, (int)knobs_.L1D_assoc) /*replacement_policy*/, get_prefetcher(knobs_.data_prefetcher), cache_inclusion_policy_t::NON_INC_NON_EXC, knobs_.model_coherence, @@ -346,7 +346,7 @@ cache_simulator_t::cache_simulator_t(std::istream *config_file, warmup_enabled_, is_coherent_), create_cache_replacement_policy(cache_config.replace_policy, (int)cache_config.size / - (int)cache_config.assoc, + (int)knobs_.line_size, (int)cache_config.assoc), get_prefetcher(cache_config.prefetcher), inclusion_policy, is_coherent_, is_snooped ? snoop_id : -1, diff --git a/clients/drcachesim/simulator/caching_device.cpp b/clients/drcachesim/simulator/caching_device.cpp index 789ac0de65c..9de99783eab 100644 --- a/clients/drcachesim/simulator/caching_device.cpp +++ b/clients/drcachesim/simulator/caching_device.cpp @@ -286,11 +286,7 @@ caching_device_t::replace_which_way(int block_idx) int caching_device_t::get_next_way_to_replace(const int block_idx) const { - std::vector valid_ways(associativity_, false); - for (int way = 0; way < associativity_; ++way) { - valid_ways[way] = get_caching_device_block(block_idx, way).tag_ != TAG_INVALID; - } - return replacement_policy_->get_next_way_to_replace(block_idx, valid_ways); + return replacement_policy_->get_next_way_to_replace(block_idx); } void @@ -302,6 +298,8 @@ caching_device_t::invalidate(addr_t tag, invalidation_type_t invalidation_type) loaded_blocks_--; stats_->invalidate(invalidation_type); // Invalidate last_tag_ if it was this tag. + replacement_policy_->invalidation_update(compute_block_idx(tag), + block_way.second); if (last_tag_ == tag) { last_tag_ = TAG_INVALID; } diff --git a/clients/drcachesim/simulator/caching_device.h b/clients/drcachesim/simulator/caching_device.h index d9005b94833..a20d4dc3de9 100644 --- a/clients/drcachesim/simulator/caching_device.h +++ b/clients/drcachesim/simulator/caching_device.h @@ -262,6 +262,7 @@ class caching_device_t { tag2block[new_tag] = std::make_pair(block, way); } block->tag_ = new_tag; + replacement_policy_->validation_update(compute_block_idx(new_tag), way); } // Returns the block (and its way) whose tag equals `tag`. diff --git a/clients/drcachesim/simulator/policy_bit_plru.cpp b/clients/drcachesim/simulator/policy_bit_plru.cpp index a6f3a0b2549..e60bbe6b7c2 100644 --- a/clients/drcachesim/simulator/policy_bit_plru.cpp +++ b/clients/drcachesim/simulator/policy_bit_plru.cpp @@ -38,37 +38,40 @@ namespace dynamorio { namespace drmemtrace { -policy_bit_plru_t::policy_bit_plru_t(int num_blocks, int associativity, int seed) - : cache_replacement_policy_t(num_blocks, associativity) - , block_num_ones_(num_blocks, 0) +policy_bit_plru_t::policy_bit_plru_t(int num_lines, int associativity, int seed) + : cache_replacement_policy_t(num_lines, associativity) + , num_ones_(num_lines, 0) , gen_(seed == -1 ? std::random_device()() : seed) { // Initialize the bit vector for each block. - block_bits_.reserve(num_blocks); - for (int i = 0; i < num_blocks; ++i) { - block_bits_.emplace_back(associativity, false); + plru_bits_.reserve(num_lines); + valid_ways_.reserve(num_lines); + for (int i = 0; i < num_lines; ++i) { + plru_bits_.emplace_back(associativity, false); + valid_ways_.emplace_back(associativity, false); } } void policy_bit_plru_t::access_update(int block_idx, int way) { - block_idx = get_block_index(block_idx); + int line_idx = get_line_index(block_idx); + valid_ways_[line_idx][way] = true; // Set the bit for the accessed way. - if (!block_bits_[block_idx][way]) { - block_bits_[block_idx][way] = true; - block_num_ones_[block_idx]++; + if (!plru_bits_[line_idx][way]) { + plru_bits_[line_idx][way] = true; + num_ones_[line_idx]++; } - if (block_num_ones_[block_idx] < associativity_) { + if (num_ones_[line_idx] < associativity_) { // Finished. return; } // If all bits are set, reset them. for (int i = 0; i < associativity_; ++i) { - block_bits_[block_idx][i] = false; + plru_bits_[line_idx][i] = false; } - block_num_ones_[block_idx] = 1; - block_bits_[block_idx][way] = true; + num_ones_[line_idx] = 1; + plru_bits_[line_idx][way] = true; } void @@ -77,18 +80,31 @@ policy_bit_plru_t::eviction_update(int block_idx, int way) // Nothing to update, when the way is accessed we will update it. } +void +policy_bit_plru_t::invalidation_update(int block_idx, int way) +{ + int line_idx = get_line_index(block_idx); + valid_ways_[line_idx][way] = false; +} + +void +policy_bit_plru_t::validation_update(int block_idx, int way) +{ + int line_idx = get_line_index(block_idx); + valid_ways_[line_idx][way] = true; +} + int -policy_bit_plru_t::get_next_way_to_replace(int block_idx, - const std::vector &valid_ways) const +policy_bit_plru_t::get_next_way_to_replace(int block_idx) const { - int first_invalid_way = get_first_invalid_way(valid_ways); + int line_idx = get_line_index(block_idx); + int first_invalid_way = get_first_invalid_way(valid_ways_[line_idx]); if (first_invalid_way != -1) { return first_invalid_way; } - block_idx = get_block_index(block_idx); std::vector unset_bits; for (int i = 0; i < associativity_; ++i) { - if (!block_bits_[block_idx][i]) { + if (!plru_bits_[line_idx][i]) { unset_bits.push_back(i); } } diff --git a/clients/drcachesim/simulator/policy_bit_plru.h b/clients/drcachesim/simulator/policy_bit_plru.h index 458f326d088..06a4ad2844e 100644 --- a/clients/drcachesim/simulator/policy_bit_plru.h +++ b/clients/drcachesim/simulator/policy_bit_plru.h @@ -51,24 +51,29 @@ namespace drmemtrace { class policy_bit_plru_t : public cache_replacement_policy_t { public: /// If seed is -1, a random seed will be used. - policy_bit_plru_t(int num_blocks, int associativity, int seed = -1); + policy_bit_plru_t(int num_lines, int associativity, int seed = -1); void access_update(int block_idx, int way) override; void eviction_update(int block_idx, int way) override; int - get_next_way_to_replace(int block_idx, - const std::vector &valid_ways) const override; + get_next_way_to_replace(int block_idx) const override; + void + invalidation_update(int block_idx, int way) override; + void + validation_update(int block_idx, int way) override; std::string get_name() const override; ~policy_bit_plru_t() override = default; private: - // A bit per way for each block. - std::vector> block_bits_; - // The amount of bits set to 1 for each block. - std::vector block_num_ones_; + // A bit per way for each line. + std::vector> plru_bits_; + // The amount of bits set to 1 for each line. + std::vector num_ones_; + // Which ways are valid per line. + std::vector> valid_ways_; mutable std::mt19937 gen_; }; diff --git a/clients/drcachesim/simulator/policy_fifo.cpp b/clients/drcachesim/simulator/policy_fifo.cpp index 88de38e5bdb..608fe677c78 100644 --- a/clients/drcachesim/simulator/policy_fifo.cpp +++ b/clients/drcachesim/simulator/policy_fifo.cpp @@ -37,12 +37,12 @@ namespace dynamorio { namespace drmemtrace { -policy_fifo_t::policy_fifo_t(int num_blocks, int associativity) - : cache_replacement_policy_t(num_blocks, associativity) +policy_fifo_t::policy_fifo_t(int num_lines, int associativity) + : cache_replacement_policy_t(num_lines, associativity) { // Initialize the FIFO list for each block. - queues_.reserve(num_blocks); - for (int i = 0; i < num_blocks; ++i) { + queues_.reserve(num_lines); + for (int i = 0; i < num_lines; ++i) { queues_.push_back(std::list()); for (int j = 0; j < associativity; ++j) { queues_[i].push_back(j); @@ -59,20 +59,32 @@ policy_fifo_t::access_update(int block_idx, int way) void policy_fifo_t::eviction_update(int block_idx, int way) { - block_idx = get_block_index(block_idx); + int line_idx = get_line_index(block_idx); // Move the evicted way to the back of the queue. - auto &fifo_block = queues_[block_idx]; + auto &fifo_block = queues_[line_idx]; fifo_block.remove(way); fifo_block.push_back(way); } +void +policy_fifo_t::invalidation_update(int block_idx, int way) +{ + // Nothing to update, FIFO does not change on invalidation. +} + + +void +policy_fifo_t::validation_update(int block_idx, int way) +{ + // Nothing to update, FIFO does not change on validation. +} + int -policy_fifo_t::get_next_way_to_replace(int block_idx, - const std::vector &valid_ways) const +policy_fifo_t::get_next_way_to_replace(int block_idx) const { - block_idx = get_block_index(block_idx); + int line_idx = get_line_index(block_idx); // The next way to replace is at the front of the FIFO list. - return queues_[block_idx].front(); + return queues_[line_idx].front(); } std::string diff --git a/clients/drcachesim/simulator/policy_fifo.h b/clients/drcachesim/simulator/policy_fifo.h index afad2322f59..e8705055940 100644 --- a/clients/drcachesim/simulator/policy_fifo.h +++ b/clients/drcachesim/simulator/policy_fifo.h @@ -50,21 +50,24 @@ namespace drmemtrace { */ class policy_fifo_t : public cache_replacement_policy_t { public: - policy_fifo_t(int num_blocks, int associativity); + policy_fifo_t(int num_lines, int associativity); void access_update(int block_idx, int way) override; void eviction_update(int block_idx, int way) override; + void + invalidation_update(int block_idx, int way) override; + void + validation_update(int block_idx, int way) override; int - get_next_way_to_replace(int block_idx, - const std::vector &valid_ways) const override; + get_next_way_to_replace(int block_idx) const override; std::string get_name() const override; ~policy_fifo_t() override = default; private: - // FIFO queue for each block. + // FIFO queue for each line. std::vector> queues_; }; diff --git a/clients/drcachesim/simulator/policy_lfu.cpp b/clients/drcachesim/simulator/policy_lfu.cpp index c846bbccb7a..b0f0f3a95f9 100644 --- a/clients/drcachesim/simulator/policy_lfu.cpp +++ b/clients/drcachesim/simulator/policy_lfu.cpp @@ -34,48 +34,66 @@ #include #include +#include namespace dynamorio { namespace drmemtrace { -policy_lfu_t::policy_lfu_t(int num_blocks, int associativity) - : cache_replacement_policy_t(num_blocks, associativity) +policy_lfu_t::policy_lfu_t(int num_lines, int associativity) + : cache_replacement_policy_t(num_lines, associativity) { - access_counts_.reserve(num_blocks); - for (int i = 0; i < num_blocks; ++i) { + access_counts_.reserve(num_lines); + valid_ways_.reserve(num_lines); + for (int i = 0; i < num_lines; ++i) { access_counts_.emplace_back(associativity, 0); + valid_ways_.emplace_back(associativity, false); } } void policy_lfu_t::access_update(int block_idx, int way) { - block_idx = get_block_index(block_idx); - access_counts_[block_idx][way]++; + int line_idx = get_line_index(block_idx); + valid_ways_[line_idx][way] = true; + access_counts_[line_idx][way]++; } void policy_lfu_t::eviction_update(int block_idx, int way) { - block_idx = get_block_index(block_idx); - access_counts_[block_idx][way] = 0; + int line_idx = get_line_index(block_idx); + access_counts_[line_idx][way] = 0; +} + +void +policy_lfu_t::invalidation_update(int block_idx, int way) +{ + int line_idx = get_line_index(block_idx); + valid_ways_[line_idx][way] = false; + access_counts_[line_idx][way] = 0; +} + +void +policy_lfu_t::validation_update(int block_idx, int way) +{ + int line_idx = get_line_index(block_idx); + valid_ways_[line_idx][way] = true; } int -policy_lfu_t::get_next_way_to_replace(int block_idx, - const std::vector &valid_ways) const +policy_lfu_t::get_next_way_to_replace(int block_idx) const { - int first_invalid_way = get_first_invalid_way(valid_ways); + int line_idx = get_line_index(block_idx); + int first_invalid_way = get_first_invalid_way(valid_ways_[line_idx]); if (first_invalid_way != -1) { return first_invalid_way; } // Find the way with the minimum frequency counter. - block_idx = get_block_index(block_idx); - int min_freq = access_counts_[block_idx][0]; + int min_freq = access_counts_[line_idx][0]; int min_way = 0; for (int i = 1; i < associativity_; ++i) { - if (access_counts_[block_idx][i] < min_freq) { - min_freq = access_counts_[block_idx][i]; + if (access_counts_[line_idx][i] < min_freq) { + min_freq = access_counts_[line_idx][i]; min_way = i; } } diff --git a/clients/drcachesim/simulator/policy_lfu.h b/clients/drcachesim/simulator/policy_lfu.h index ee6cb14e167..a7a73f0ab74 100644 --- a/clients/drcachesim/simulator/policy_lfu.h +++ b/clients/drcachesim/simulator/policy_lfu.h @@ -47,22 +47,27 @@ namespace drmemtrace { */ class policy_lfu_t : public cache_replacement_policy_t { public: - policy_lfu_t(int num_blocks, int associativity); + policy_lfu_t(int num_lines, int associativity); void access_update(int block_idx, int way) override; void eviction_update(int block_idx, int way) override; + void + invalidation_update(int block_idx, int way) override; + void + validation_update(int block_idx, int way) override; int - get_next_way_to_replace(int block_idx, - const std::vector &valid_ways) const override; + get_next_way_to_replace(int block_idx) const override; std::string get_name() const override; ~policy_lfu_t() override = default; private: - // Frequency counters for each way in each block. + // Frequency counters for each way in each line. std::vector> access_counts_; + // Which ways are valid per line. + std::vector> valid_ways_; }; } // namespace drmemtrace diff --git a/clients/drcachesim/simulator/policy_lru.cpp b/clients/drcachesim/simulator/policy_lru.cpp index df2e0b4edfb..47bc8a51aeb 100644 --- a/clients/drcachesim/simulator/policy_lru.cpp +++ b/clients/drcachesim/simulator/policy_lru.cpp @@ -35,31 +35,34 @@ namespace dynamorio { namespace drmemtrace { -policy_lru_t::policy_lru_t(int num_blocks, int associativity) - : cache_replacement_policy_t(num_blocks, associativity) +policy_lru_t::policy_lru_t(int num_lines, int associativity) + : cache_replacement_policy_t(num_lines, associativity) { // Initialize the LRU list for each block. - lru_counters_.reserve(num_blocks); - for (int i = 0; i < num_blocks; ++i) { + lru_counters_.reserve(num_lines); + valid_ways_.reserve(num_lines); + for (int i = 0; i < num_lines; ++i) { lru_counters_.emplace_back(associativity, 1); + valid_ways_.emplace_back(associativity, false); } } void policy_lru_t::access_update(int block_idx, int way) { - block_idx = get_block_index(block_idx); - int count = lru_counters_[block_idx][way]; + int line_idx = get_line_index(block_idx); + valid_ways_[line_idx][way] = true; + int count = lru_counters_[line_idx][way]; // Optimization: return early if it is a repeated access. if (count == 0) return; // We inc all the counters that are not larger than count for LRU. for (int i = 0; i < associativity_; ++i) { - if (i != way && lru_counters_[block_idx][i] <= count) - lru_counters_[block_idx][i]++; + if (i != way && lru_counters_[line_idx][i] <= count) + lru_counters_[line_idx][i]++; } // Clear the counter for LRU. - lru_counters_[block_idx][way] = 0; + lru_counters_[line_idx][way] = 0; } void @@ -68,21 +71,34 @@ policy_lru_t::eviction_update(int block_idx, int way) // Nothing to update, when the way is accessed we will update it. } +void +policy_lru_t::invalidation_update(int block_idx, int way) +{ + int line_idx = get_line_index(block_idx); + valid_ways_[line_idx][way] = false; +} + +void +policy_lru_t::validation_update(int block_idx, int way) +{ + int line_idx = get_line_index(block_idx); + valid_ways_[line_idx][way] = true; +} + int -policy_lru_t::get_next_way_to_replace(int block_idx, - const std::vector &valid_ways) const +policy_lru_t::get_next_way_to_replace(int block_idx) const { - int first_invalid_way = get_first_invalid_way(valid_ways); + int line_idx = get_line_index(block_idx); + int first_invalid_way = get_first_invalid_way(valid_ways_[line_idx]); if (first_invalid_way != -1) { return first_invalid_way; } - block_idx = get_block_index(block_idx); // We implement LRU by picking the slot with the largest counter value. int max_counter = 0; int max_way = 0; for (int way = 0; way < associativity_; ++way) { - if (lru_counters_[block_idx][way] > max_counter) { - max_counter = lru_counters_[block_idx][way]; + if (lru_counters_[line_idx][way] > max_counter) { + max_counter = lru_counters_[line_idx][way]; max_way = way; } } diff --git a/clients/drcachesim/simulator/policy_lru.h b/clients/drcachesim/simulator/policy_lru.h index 42966b34bf5..528247e6c66 100644 --- a/clients/drcachesim/simulator/policy_lru.h +++ b/clients/drcachesim/simulator/policy_lru.h @@ -49,14 +49,17 @@ namespace drmemtrace { */ class policy_lru_t : public cache_replacement_policy_t { public: - policy_lru_t(int num_blocks, int associativity); + policy_lru_t(int num_lines, int associativity); void access_update(int block_idx, int way) override; void eviction_update(int block_idx, int way) override; + void + invalidation_update(int block_idx, int way) override; + void + validation_update(int block_idx, int way) override; int - get_next_way_to_replace(int block_idx, - const std::vector &valid_ways) const override; + get_next_way_to_replace(int block_idx) const override; std::string get_name() const override; @@ -65,6 +68,8 @@ class policy_lru_t : public cache_replacement_policy_t { private: // LRU list for each block. std::vector> lru_counters_; + // Which ways are valid per line. + std::vector> valid_ways_; }; } // namespace drmemtrace From cc03a237bf23ea1f108c94feaf8fedcd47912117 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Tue, 11 Mar 2025 14:52:05 +0000 Subject: [PATCH 41/42] format --- clients/drcachesim/simulator/policy_fifo.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/clients/drcachesim/simulator/policy_fifo.cpp b/clients/drcachesim/simulator/policy_fifo.cpp index 608fe677c78..80ce9f20cbe 100644 --- a/clients/drcachesim/simulator/policy_fifo.cpp +++ b/clients/drcachesim/simulator/policy_fifo.cpp @@ -72,7 +72,6 @@ policy_fifo_t::invalidation_update(int block_idx, int way) // Nothing to update, FIFO does not change on invalidation. } - void policy_fifo_t::validation_update(int block_idx, int way) { From d9b9cb4734a5d89dce09d18818d5592827db26c4 Mon Sep 17 00:00:00 2001 From: Or Almer Date: Tue, 11 Mar 2025 15:10:59 +0000 Subject: [PATCH 42/42] spelling --- clients/drcachesim/simulator/cache_replacement_policy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/drcachesim/simulator/cache_replacement_policy.h b/clients/drcachesim/simulator/cache_replacement_policy.h index 91f59abcc26..ba7d87f5c5b 100644 --- a/clients/drcachesim/simulator/cache_replacement_policy.h +++ b/clients/drcachesim/simulator/cache_replacement_policy.h @@ -46,7 +46,7 @@ namespace drmemtrace { * and provides a replacement-specific get_next_way_to_replace() method for * `caching_device_t`. * - * The policy recieves the following updates: + * The policy receives the following updates: * - When an existing way is accessed, `access_update()` is called. * - When a way is evicted, `eviction_update()` is called on the evicted way, and * `access_update()` is called on the new way immediately after.