summaryrefslogtreecommitdiff
path: root/src/gpgpu-sim/gpu-cache.h
diff options
context:
space:
mode:
authorVijay Kandiah <[email protected]>2021-10-17 02:07:39 -0500
committerGitHub <[email protected]>2021-10-17 02:07:39 -0500
commit4a4fc87a2dcd95bfe298f2b3d18a9833a506e499 (patch)
treef45fe00a86fb814ebf3f5e711674f233dcdb73a2 /src/gpgpu-sim/gpu-cache.h
parent90ec3399763d7c8512cfe7dc193473086c38ca38 (diff)
parent84c4f46fb78b529ab2447d7a676f5b3ac2d9c05f (diff)
Merge pull request #5 from accel-sim/dev
GPGPU-Sim Latest Dev Integration
Diffstat (limited to 'src/gpgpu-sim/gpu-cache.h')
-rw-r--r--src/gpgpu-sim/gpu-cache.h203
1 files changed, 161 insertions, 42 deletions
diff --git a/src/gpgpu-sim/gpu-cache.h b/src/gpgpu-sim/gpu-cache.h
index 5c28b41..67d084c 100644
--- a/src/gpgpu-sim/gpu-cache.h
+++ b/src/gpgpu-sim/gpu-cache.h
@@ -49,6 +49,7 @@ enum cache_request_status {
MISS,
RESERVATION_FAIL,
SECTOR_MISS,
+ MSHR_HIT,
NUM_CACHE_REQUEST_STATUS
};
@@ -71,14 +72,26 @@ enum cache_event_type {
struct evicted_block_info {
new_addr_type m_block_addr;
unsigned m_modified_size;
+ mem_access_byte_mask_t m_byte_mask;
+ mem_access_sector_mask_t m_sector_mask;
evicted_block_info() {
m_block_addr = 0;
m_modified_size = 0;
+ m_byte_mask.reset();
+ m_sector_mask.reset();
}
void set_info(new_addr_type block_addr, unsigned modified_size) {
m_block_addr = block_addr;
m_modified_size = modified_size;
}
+ void set_info(new_addr_type block_addr, unsigned modified_size,
+ mem_access_byte_mask_t byte_mask,
+ mem_access_sector_mask_t sector_mask) {
+ m_block_addr = block_addr;
+ m_modified_size = modified_size;
+ m_byte_mask = byte_mask;
+ m_sector_mask = sector_mask;
+ }
};
struct cache_event {
@@ -108,7 +121,8 @@ struct cache_block_t {
virtual void allocate(new_addr_type tag, new_addr_type block_addr,
unsigned time,
mem_access_sector_mask_t sector_mask) = 0;
- virtual void fill(unsigned time, mem_access_sector_mask_t sector_mask) = 0;
+ virtual void fill(unsigned time, mem_access_sector_mask_t sector_mask,
+ mem_access_byte_mask_t byte_mask) = 0;
virtual bool is_invalid_line() = 0;
virtual bool is_valid_line() = 0;
@@ -119,7 +133,10 @@ struct cache_block_t {
mem_access_sector_mask_t sector_mask) = 0;
virtual void set_status(enum cache_block_state m_status,
mem_access_sector_mask_t sector_mask) = 0;
-
+ virtual void set_byte_mask(mem_fetch *mf) = 0;
+ virtual void set_byte_mask(mem_access_byte_mask_t byte_mask) = 0;
+ virtual mem_access_byte_mask_t get_dirty_byte_mask() = 0;
+ virtual mem_access_sector_mask_t get_dirty_sector_mask() = 0;
virtual unsigned long long get_last_access_time() = 0;
virtual void set_last_access_time(unsigned long long time,
mem_access_sector_mask_t sector_mask) = 0;
@@ -128,6 +145,9 @@ struct cache_block_t {
mem_access_sector_mask_t sector_mask) = 0;
virtual void set_modified_on_fill(bool m_modified,
mem_access_sector_mask_t sector_mask) = 0;
+ virtual void set_readable_on_fill(bool readable,
+ mem_access_sector_mask_t sector_mask) = 0;
+ virtual void set_byte_mask_on_fill(bool m_modified) = 0;
virtual unsigned get_modified_size() = 0;
virtual void set_m_readable(bool readable,
mem_access_sector_mask_t sector_mask) = 0;
@@ -147,6 +167,7 @@ struct line_cache_block : public cache_block_t {
m_status = INVALID;
m_ignore_on_fill_status = false;
m_set_modified_on_fill = false;
+ m_set_readable_on_fill = false;
m_readable = true;
}
void allocate(new_addr_type tag, new_addr_type block_addr, unsigned time,
@@ -159,13 +180,19 @@ struct line_cache_block : public cache_block_t {
m_status = RESERVED;
m_ignore_on_fill_status = false;
m_set_modified_on_fill = false;
+ m_set_readable_on_fill = false;
+ m_set_byte_mask_on_fill = false;
}
- void fill(unsigned time, mem_access_sector_mask_t sector_mask) {
+ virtual void fill(unsigned time, mem_access_sector_mask_t sector_mask,
+ mem_access_byte_mask_t byte_mask) {
// if(!m_ignore_on_fill_status)
// assert( m_status == RESERVED );
m_status = m_set_modified_on_fill ? MODIFIED : VALID;
+ if (m_set_readable_on_fill) m_readable = true;
+ if (m_set_byte_mask_on_fill) set_byte_mask(byte_mask);
+
m_fill_time = time;
}
virtual bool is_invalid_line() { return m_status == INVALID; }
@@ -181,6 +208,20 @@ struct line_cache_block : public cache_block_t {
mem_access_sector_mask_t sector_mask) {
m_status = status;
}
+ virtual void set_byte_mask(mem_fetch *mf) {
+ m_dirty_byte_mask = m_dirty_byte_mask | mf->get_access_byte_mask();
+ }
+ virtual void set_byte_mask(mem_access_byte_mask_t byte_mask) {
+ m_dirty_byte_mask = m_dirty_byte_mask | byte_mask;
+ }
+ virtual mem_access_byte_mask_t get_dirty_byte_mask() {
+ return m_dirty_byte_mask;
+ }
+ virtual mem_access_sector_mask_t get_dirty_sector_mask() {
+ mem_access_sector_mask_t sector_mask;
+ if (m_status == MODIFIED) sector_mask.set();
+ return sector_mask;
+ }
virtual unsigned long long get_last_access_time() {
return m_last_access_time;
}
@@ -197,6 +238,13 @@ struct line_cache_block : public cache_block_t {
mem_access_sector_mask_t sector_mask) {
m_set_modified_on_fill = m_modified;
}
+ virtual void set_readable_on_fill(bool readable,
+ mem_access_sector_mask_t sector_mask) {
+ m_set_readable_on_fill = readable;
+ }
+ virtual void set_byte_mask_on_fill(bool m_modified) {
+ m_set_byte_mask_on_fill = m_modified;
+ }
virtual unsigned get_modified_size() {
return SECTOR_CHUNCK_SIZE * SECTOR_SIZE; // i.e. cache line size
}
@@ -218,7 +266,10 @@ struct line_cache_block : public cache_block_t {
cache_block_state m_status;
bool m_ignore_on_fill_status;
bool m_set_modified_on_fill;
+ bool m_set_readable_on_fill;
+ bool m_set_byte_mask_on_fill;
bool m_readable;
+ mem_access_byte_mask_t m_dirty_byte_mask;
};
struct sector_cache_block : public cache_block_t {
@@ -232,11 +283,13 @@ struct sector_cache_block : public cache_block_t {
m_status[i] = INVALID;
m_ignore_on_fill_status[i] = false;
m_set_modified_on_fill[i] = false;
+ m_set_readable_on_fill[i] = false;
m_readable[i] = true;
}
m_line_alloc_time = 0;
m_line_last_access_time = 0;
m_line_fill_time = 0;
+ m_dirty_byte_mask.reset();
}
virtual void allocate(new_addr_type tag, new_addr_type block_addr,
@@ -261,6 +314,8 @@ struct sector_cache_block : public cache_block_t {
m_status[sidx] = RESERVED;
m_ignore_on_fill_status[sidx] = false;
m_set_modified_on_fill[sidx] = false;
+ m_set_readable_on_fill[sidx] = false;
+ m_set_byte_mask_on_fill = false;
// set line stats
m_line_alloc_time = time; // only set this for the first allocated sector
@@ -283,6 +338,8 @@ struct sector_cache_block : public cache_block_t {
else
m_set_modified_on_fill[sidx] = false;
+ m_set_readable_on_fill[sidx] = false;
+
m_status[sidx] = RESERVED;
m_ignore_on_fill_status[sidx] = false;
// m_set_modified_on_fill[sidx] = false;
@@ -293,14 +350,20 @@ struct sector_cache_block : public cache_block_t {
m_line_fill_time = 0;
}
- virtual void fill(unsigned time, mem_access_sector_mask_t sector_mask) {
+ virtual void fill(unsigned time, mem_access_sector_mask_t sector_mask,
+ mem_access_byte_mask_t byte_mask) {
unsigned sidx = get_sector_index(sector_mask);
// if(!m_ignore_on_fill_status[sidx])
// assert( m_status[sidx] == RESERVED );
-
m_status[sidx] = m_set_modified_on_fill[sidx] ? MODIFIED : VALID;
+ if (m_set_readable_on_fill[sidx]) {
+ m_readable[sidx] = true;
+ m_set_readable_on_fill[sidx] = false;
+ }
+ if (m_set_byte_mask_on_fill) set_byte_mask(byte_mask);
+
m_sector_fill_time[sidx] = time;
m_line_fill_time = time;
}
@@ -340,6 +403,22 @@ struct sector_cache_block : public cache_block_t {
m_status[sidx] = status;
}
+ virtual void set_byte_mask(mem_fetch *mf) {
+ m_dirty_byte_mask = m_dirty_byte_mask | mf->get_access_byte_mask();
+ }
+ virtual void set_byte_mask(mem_access_byte_mask_t byte_mask) {
+ m_dirty_byte_mask = m_dirty_byte_mask | byte_mask;
+ }
+ virtual mem_access_byte_mask_t get_dirty_byte_mask() {
+ return m_dirty_byte_mask;
+ }
+ virtual mem_access_sector_mask_t get_dirty_sector_mask() {
+ mem_access_sector_mask_t sector_mask;
+ for (unsigned i = 0; i < SECTOR_CHUNCK_SIZE; i++) {
+ if (m_status[i] == MODIFIED) sector_mask.set(i);
+ }
+ return sector_mask;
+ }
virtual unsigned long long get_last_access_time() {
return m_line_last_access_time;
}
@@ -365,7 +444,15 @@ struct sector_cache_block : public cache_block_t {
unsigned sidx = get_sector_index(sector_mask);
m_set_modified_on_fill[sidx] = m_modified;
}
+ virtual void set_byte_mask_on_fill(bool m_modified) {
+ m_set_byte_mask_on_fill = m_modified;
+ }
+ virtual void set_readable_on_fill(bool readable,
+ mem_access_sector_mask_t sector_mask) {
+ unsigned sidx = get_sector_index(sector_mask);
+ m_set_readable_on_fill[sidx] = readable;
+ }
virtual void set_m_readable(bool readable,
mem_access_sector_mask_t sector_mask) {
unsigned sidx = get_sector_index(sector_mask);
@@ -400,7 +487,10 @@ struct sector_cache_block : public cache_block_t {
cache_block_state m_status[SECTOR_CHUNCK_SIZE];
bool m_ignore_on_fill_status[SECTOR_CHUNCK_SIZE];
bool m_set_modified_on_fill[SECTOR_CHUNCK_SIZE];
+ bool m_set_readable_on_fill[SECTOR_CHUNCK_SIZE];
+ bool m_set_byte_mask_on_fill;
bool m_readable[SECTOR_CHUNCK_SIZE];
+ mem_access_byte_mask_t m_dirty_byte_mask;
unsigned get_sector_index(mem_access_sector_mask_t sector_mask) {
assert(sector_mask.count() == 1);
@@ -463,6 +553,7 @@ class cache_config {
m_data_port_width = 0;
m_set_index_function = LINEAR_SET_FUNCTION;
m_is_streaming = false;
+ m_wr_percent = 0;
}
void init(char *config, FuncCache status) {
cache_status = status;
@@ -503,16 +594,6 @@ class cache_config {
default:
exit_parse_error();
}
- switch (rp) {
- case 'L':
- m_replacement_policy = LRU;
- break;
- case 'F':
- m_replacement_policy = FIFO;
- break;
- default:
- exit_parse_error();
- }
switch (wp) {
case 'R':
m_write_policy = READ_ONLY;
@@ -546,22 +627,27 @@ class cache_config {
exit_parse_error();
}
if (m_alloc_policy == STREAMING) {
- // For streaming cache, we set the alloc policy to be on-fill to remove
- // all line_alloc_fail stalls we set the MSHRs to be equal to max
- // allocated cache lines. This is possible by moving TAG to be shared
- // between cache line and MSHR enrty (i.e. for each cache line, there is
- // an MSHR rntey associated with it) This is the easiest think we can
- // think about to model (mimic) L1 streaming cache in Pascal and Volta
- // Based on our microbenchmakrs, MSHRs entries have been increasing
- // substantially in Pascal and Volta For more information about streaming
- // cache, see:
- // http://on-demand.gputechconf.com/gtc/2017/presentation/s7798-luke-durant-inside-volta.pdf
- // https://ieeexplore.ieee.org/document/8344474/
+ /*
+ For streaming cache:
+ (1) we set the alloc policy to be on-fill to remove all line_alloc_fail
+ stalls. if the whole memory is allocated to the L1 cache, then make the
+ allocation to be on_MISS otherwise, make it ON_FILL to eliminate line
+ allocation fails. i.e. MSHR throughput is the same, independent on the L1
+ cache size/associativity So, we set the allocation policy per kernel
+ basis, see shader.cc, max_cta() function
+
+ (2) We also set the MSHRs to be equal to max
+ allocated cache lines. This is possible by moving TAG to be shared
+ between cache line and MSHR enrty (i.e. for each cache line, there is
+ an MSHR rntey associated with it). This is the easiest think we can
+ think of to model (mimic) L1 streaming cache in Pascal and Volta
+
+ For more information about streaming cache, see:
+ http://on-demand.gputechconf.com/gtc/2017/presentation/s7798-luke-durant-inside-volta.pdf
+ https://ieeexplore.ieee.org/document/8344474/
+ */
m_is_streaming = true;
m_alloc_policy = ON_FILL;
- m_mshr_entries = m_nset * m_assoc * MAX_DEFAULT_CACHE_SIZE_MULTIBLIER;
- if (m_cache_type == SECTOR) m_mshr_entries *= SECTOR_CHUNCK_SIZE;
- m_mshr_max_merge = MAX_WARP_PER_SM;
}
switch (mshr_type) {
case 'F':
@@ -610,7 +696,8 @@ class cache_config {
}
// detect invalid configuration
- if (m_alloc_policy == ON_FILL and m_write_policy == WRITE_BACK) {
+ if ((m_alloc_policy == ON_FILL || m_alloc_policy == STREAMING) and
+ m_write_policy == WRITE_BACK) {
// A writeback cache with allocate-on-fill policy will inevitably lead to
// deadlock: The deadlock happens when an incoming cache-fill evicts a
// dirty line, generating a writeback request. If the memory subsystem is
@@ -656,6 +743,9 @@ class cache_config {
case 'L':
m_set_index_function = LINEAR_SET_FUNCTION;
break;
+ case 'X':
+ m_set_index_function = BITWISE_XORING_FUNCTION;
+ break;
default:
exit_parse_error();
}
@@ -675,11 +765,11 @@ class cache_config {
}
unsigned get_max_num_lines() const {
assert(m_valid);
- return MAX_DEFAULT_CACHE_SIZE_MULTIBLIER * m_nset * original_m_assoc;
+ return get_max_cache_multiplier() * m_nset * original_m_assoc;
}
unsigned get_max_assoc() const {
assert(m_valid);
- return MAX_DEFAULT_CACHE_SIZE_MULTIBLIER * original_m_assoc;
+ return get_max_cache_multiplier() * original_m_assoc;
}
void print(FILE *fp) const {
fprintf(fp, "Size = %d B (%d Set x %d-way x %d byte line)\n",
@@ -688,6 +778,10 @@ class cache_config {
virtual unsigned set_index(new_addr_type addr) const;
+ virtual unsigned get_max_cache_multiplier() const {
+ return MAX_DEFAULT_CACHE_SIZE_MULTIBLIER;
+ }
+
unsigned hash_function(new_addr_type addr, unsigned m_nset,
unsigned m_line_sz_log2, unsigned m_nset_log2,
unsigned m_index_function) const;
@@ -722,10 +816,18 @@ class cache_config {
}
bool is_streaming() { return m_is_streaming; }
FuncCache get_cache_status() { return cache_status; }
+ void set_allocation_policy(enum allocation_policy_t alloc) {
+ m_alloc_policy = alloc;
+ }
char *m_config_string;
char *m_config_stringPrefL1;
char *m_config_stringPrefShared;
FuncCache cache_status;
+ unsigned m_wr_percent;
+ write_allocate_policy_t get_write_allocate_policy() {
+ return m_write_alloc_policy;
+ }
+ write_policy_t get_write_policy() { return m_write_policy; }
protected:
void exit_parse_error() {
@@ -789,16 +891,28 @@ class l1d_cache_config : public cache_config {
l1d_cache_config() : cache_config() {}
unsigned set_bank(new_addr_type addr) const;
void init(char *config, FuncCache status) {
- m_banks_byte_interleaving_log2 = LOGB2(l1_banks_byte_interleaving);
- m_l1_banks_log2 = LOGB2(l1_banks);
+ l1_banks_byte_interleaving_log2 = LOGB2(l1_banks_byte_interleaving);
+ l1_banks_log2 = LOGB2(l1_banks);
cache_config::init(config, status);
}
unsigned l1_latency;
unsigned l1_banks;
- unsigned m_l1_banks_log2;
+ unsigned l1_banks_log2;
unsigned l1_banks_byte_interleaving;
- unsigned m_banks_byte_interleaving_log2;
+ unsigned l1_banks_byte_interleaving_log2;
unsigned l1_banks_hashing_function;
+ unsigned m_unified_cache_size;
+ virtual unsigned get_max_cache_multiplier() const {
+ // set * assoc * cacheline size. Then convert Byte to KB
+ // gpgpu_unified_cache_size is in KB while original_sz is in B
+ if (m_unified_cache_size > 0) {
+ unsigned original_size = m_nset * original_m_assoc * m_line_sz / 1024;
+ assert(m_unified_cache_size % original_size == 0);
+ return m_unified_cache_size / original_size;
+ } else {
+ return MAX_DEFAULT_CACHE_SIZE_MULTIBLIER;
+ }
+ }
};
class l2_cache_config : public cache_config {
@@ -818,9 +932,10 @@ class tag_array {
~tag_array();
enum cache_request_status probe(new_addr_type addr, unsigned &idx,
- mem_fetch *mf, bool probe_mode = false) const;
+ mem_fetch *mf, bool is_write,
+ bool probe_mode = false) const;
enum cache_request_status probe(new_addr_type addr, unsigned &idx,
- mem_access_sector_mask_t mask,
+ mem_access_sector_mask_t mask, bool is_write,
bool probe_mode = false,
mem_fetch *mf = NULL) const;
enum cache_request_status access(new_addr_type addr, unsigned time,
@@ -829,9 +944,10 @@ class tag_array {
unsigned &idx, bool &wb,
evicted_block_info &evicted, mem_fetch *mf);
- void fill(new_addr_type addr, unsigned time, mem_fetch *mf);
+ void fill(new_addr_type addr, unsigned time, mem_fetch *mf, bool is_write);
void fill(unsigned idx, unsigned time, mem_fetch *mf);
- void fill(new_addr_type addr, unsigned time, mem_access_sector_mask_t mask);
+ void fill(new_addr_type addr, unsigned time, mem_access_sector_mask_t mask,
+ mem_access_byte_mask_t byte_mask, bool is_write);
unsigned size() const { return m_config.get_num_lines(); }
cache_block_t *get_block(unsigned idx) { return m_lines[idx]; }
@@ -849,6 +965,7 @@ class tag_array {
void update_cache_parameters(cache_config &config);
void add_pending_line(mem_fetch *mf);
void remove_pending_line(mem_fetch *mf);
+ void inc_dirty() { m_dirty++; }
protected:
// This constructor is intended for use only from derived classes that wish to
@@ -869,6 +986,7 @@ class tag_array {
// allocated but not filled
unsigned m_res_fail;
unsigned m_sector_miss;
+ unsigned m_dirty;
// performance counters for calculating the amount of misses within a time
// window
@@ -1214,7 +1332,8 @@ class baseline_cache : public cache_t {
// something is read or written without doing anything else.
void force_tag_access(new_addr_type addr, unsigned time,
mem_access_sector_mask_t mask) {
- m_tag_array->fill(addr, time, mask);
+ mem_access_byte_mask_t byte_mask;
+ m_tag_array->fill(addr, time, mask, byte_mask, true);
}
protected:
@@ -1451,7 +1570,7 @@ class data_cache : public baseline_cache {
/// Sends write request to lower level memory (write or writeback)
void send_write_request(mem_fetch *mf, cache_event request, unsigned time,
std::list<cache_event> &events);
-
+ void update_m_readable(mem_fetch *mf, unsigned cache_index);
// Member Function pointers - Set by configuration options
// to the functions below each grouping
/******* Write-hit configs *******/