diff options
| author | Vijay Kandiah <[email protected]> | 2021-10-17 02:07:39 -0500 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-10-17 02:07:39 -0500 |
| commit | 4a4fc87a2dcd95bfe298f2b3d18a9833a506e499 (patch) | |
| tree | f45fe00a86fb814ebf3f5e711674f233dcdb73a2 /src/gpgpu-sim/gpu-cache.h | |
| parent | 90ec3399763d7c8512cfe7dc193473086c38ca38 (diff) | |
| parent | 84c4f46fb78b529ab2447d7a676f5b3ac2d9c05f (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.h | 203 |
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 *******/ |
