summaryrefslogtreecommitdiff
path: root/src/gpgpu-sim/gpu-cache.cc
diff options
context:
space:
mode:
authorMahmoud <[email protected]>2019-09-16 10:47:08 -0400
committerMahmoud <[email protected]>2019-09-16 10:47:08 -0400
commit0785ce7c9471bf1a0c70500eb60cb293fb5aa2fa (patch)
tree15dcaeaf1b1e0e9e3c04af74e72545854793d244 /src/gpgpu-sim/gpu-cache.cc
parent688044e9f7a9aef0a63a9610b496baafd886c556 (diff)
parentdba877b45fe11187d56904bbd169f4e0a5ad0586 (diff)
Merge branch 'dev' of https://github.com/purdue-aalp/gpgpu-sim_distribution into dev-private
Diffstat (limited to 'src/gpgpu-sim/gpu-cache.cc')
-rw-r--r--src/gpgpu-sim/gpu-cache.cc2891
1 files changed, 1438 insertions, 1453 deletions
diff --git a/src/gpgpu-sim/gpu-cache.cc b/src/gpgpu-sim/gpu-cache.cc
index 65f2f6d..5cdeeb1 100644
--- a/src/gpgpu-sim/gpu-cache.cc
+++ b/src/gpgpu-sim/gpu-cache.cc
@@ -7,1642 +7,1634 @@
//
// 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 The University of British Columbia nor the names of its
-// contributors may be used to endorse or promote products derived from this
-// software without specific prior written permission.
+// 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
+// The University of British Columbia 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 THE COPYRIGHT HOLDER 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.
+// 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 THE COPYRIGHT HOLDER 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 "gpu-cache.h"
+#include <assert.h>
#include "gpu-sim.h"
#include "stat-tool.h"
-#include <assert.h>
-// used to allocate memory that is large enough to adapt the changes in cache size across kernels
+// used to allocate memory that is large enough to adapt the changes in cache
+// size across kernels
-const char * cache_request_status_str(enum cache_request_status status)
-{
- static const char * static_cache_request_status_str[] = {
- "HIT",
- "HIT_RESERVED",
- "MISS",
- "RESERVATION_FAIL",
- "SECTOR_MISS"
- };
+const char *cache_request_status_str(enum cache_request_status status) {
+ static const char *static_cache_request_status_str[] = {
+ "HIT", "HIT_RESERVED", "MISS", "RESERVATION_FAIL", "SECTOR_MISS"};
- assert(sizeof(static_cache_request_status_str) / sizeof(const char*) == NUM_CACHE_REQUEST_STATUS);
- assert(status < NUM_CACHE_REQUEST_STATUS);
+ assert(sizeof(static_cache_request_status_str) / sizeof(const char *) ==
+ NUM_CACHE_REQUEST_STATUS);
+ assert(status < NUM_CACHE_REQUEST_STATUS);
- return static_cache_request_status_str[status];
+ return static_cache_request_status_str[status];
}
-const char * cache_fail_status_str(enum cache_reservation_fail_reason status)
-{
- static const char * static_cache_reservation_fail_reason_str[] = {
- "LINE_ALLOC_FAIL",
- "MISS_QUEUE_FULL",
- "MSHR_ENRTY_FAIL",
- "MSHR_MERGE_ENRTY_FAIL",
- "MSHR_RW_PENDING"
- };
+const char *cache_fail_status_str(enum cache_reservation_fail_reason status) {
+ static const char *static_cache_reservation_fail_reason_str[] = {
+ "LINE_ALLOC_FAIL", "MISS_QUEUE_FULL", "MSHR_ENRTY_FAIL",
+ "MSHR_MERGE_ENRTY_FAIL", "MSHR_RW_PENDING"};
- assert(sizeof(static_cache_reservation_fail_reason_str) / sizeof(const char*) == NUM_CACHE_RESERVATION_FAIL_STATUS);
- assert(status < NUM_CACHE_RESERVATION_FAIL_STATUS);
+ assert(sizeof(static_cache_reservation_fail_reason_str) /
+ sizeof(const char *) ==
+ NUM_CACHE_RESERVATION_FAIL_STATUS);
+ assert(status < NUM_CACHE_RESERVATION_FAIL_STATUS);
- return static_cache_reservation_fail_reason_str[status];
+ return static_cache_reservation_fail_reason_str[status];
}
-unsigned l1d_cache_config::set_bank(new_addr_type addr) const{
-
- //For sector cache, we select one sector per bank (sector interleaving)
- //This is what was found in Volta (one sector per bank, sector interleaving)
- //otherwise, line interleaving
- if(m_cache_type == SECTOR) {
- //assert(l1_banks == SECTOR_CHUNCK_SIZE);
- return (addr >> m_sector_sz_log2) & (l1_banks-1);
- }
- else
- return (addr >> m_line_sz_log2) & (l1_banks-1);
+unsigned l1d_cache_config::set_bank(new_addr_type addr) const {
+ //For sector cache, we select one sector per bank (sector interleaving)
+ //This is what was found in Volta (one sector per bank, sector interleaving)
+ //otherwise, line interleaving
+ if (m_cache_type == SECTOR)
+ return (addr >> m_sector_sz_log2) & (l1_banks - 1);
+ else
+ return (addr >> m_line_sz_log2) & (l1_banks - 1);
}
-unsigned l1d_cache_config::set_index(new_addr_type addr) const{
- unsigned set_index = m_nset; // Default to linear set index function
- unsigned lower_xor = 0;
- unsigned upper_xor = 0;
+unsigned l1d_cache_config::set_index(new_addr_type addr) const {
+ unsigned set_index = m_nset; // Default to linear set index function
+ unsigned lower_xor = 0;
+ unsigned upper_xor = 0;
- switch(m_set_index_function){
+ switch (m_set_index_function) {
case FERMI_HASH_SET_FUNCTION:
case BITWISE_XORING_FUNCTION:
- /*
- * Set Indexing function from "A Detailed GPU Cache Model Based on Reuse Distance Theory"
- * Cedric Nugteren et al.
- * HPCA 2014
- */
- if(m_nset == 32 || m_nset == 64){
- // Lower xor value is bits 7-11
- lower_xor = (addr >> m_line_sz_log2) & 0x1F;
+ /*
+ * Set Indexing function from "A Detailed GPU Cache Model Based on Reuse
+ * Distance Theory" Cedric Nugteren et al. HPCA 2014
+ */
+ if (m_nset == 32 || m_nset == 64) {
+ // Lower xor value is bits 7-11
+ lower_xor = (addr >> m_line_sz_log2) & 0x1F;
- // Upper xor value is bits 13, 14, 15, 17, and 19
- upper_xor = (addr & 0xE000) >> 13; // Bits 13, 14, 15
- upper_xor |= (addr & 0x20000) >> 14; // Bit 17
- upper_xor |= (addr & 0x80000) >> 15; // Bit 19
+ // Upper xor value is bits 13, 14, 15, 17, and 19
+ upper_xor = (addr & 0xE000) >> 13; // Bits 13, 14, 15
+ upper_xor |= (addr & 0x20000) >> 14; // Bit 17
+ upper_xor |= (addr & 0x80000) >> 15; // Bit 19
- set_index = (lower_xor ^ upper_xor);
+ set_index = (lower_xor ^ upper_xor);
- // 48KB cache prepends the set_index with bit 12
- if(m_nset == 64)
- set_index |= (addr & 0x1000) >> 7;
+ // 48KB cache prepends the set_index with bit 12
+ if (m_nset == 64) set_index |= (addr & 0x1000) >> 7;
- }else{ /* Else incorrect number of sets for the hashing function */
- assert("\nGPGPU-Sim cache configuration error: The number of sets should be "
- "32 or 64 for the hashing set index function.\n" && 0);
- }
- break;
+ } else { /* Else incorrect number of sets for the hashing function */
+ assert(
+ "\nGPGPU-Sim cache configuration error: The number of sets should "
+ "be "
+ "32 or 64 for the hashing set index function.\n" &&
+ 0);
+ }
+ break;
case HASH_IPOLY_FUNCTION:
- /*
- * Set Indexing function from "Pseudo-randomly interleaved memory."
- * Rau, B. R et al.
- * ISCA 1991
- *
- * "Sacat: streaming-aware conflict-avoiding thrashing-resistant gpgpu cache management scheme."
- * Khairy et al.
- * IEEE TPDS 2017.
- */
- if(m_nset == 32 || m_nset == 64){
- std::bitset<64> a(addr);
- std::bitset<6> index;
- index[0] = a[25]^a[24]^a[23]^a[22]^a[21]^a[18]^a[17]^a[15]^a[12]^a[7]; //10
- index[1] = a[26]^a[25]^a[24]^a[23]^a[22]^a[19]^a[18]^a[16]^a[13]^a[8]; //10
- index[2] = a[26]^a[22]^a[21]^a[20]^a[19]^a[18]^a[15]^a[14]^a[12]^a[9]; //10
- index[3] = a[23]^a[22]^a[21]^a[20]^a[19]^a[16]^a[15]^a[13]^a[10]; //9
- index[4] = a[24]^a[23]^a[22]^a[21]^a[20]^a[17]^a[16]^a[14]^a[11]; //9
+ /*
+ * Set Indexing function from "Pseudo-randomly interleaved memory."
+ * Rau, B. R et al.
+ * ISCA 1991
+ *
+ * "Sacat: streaming-aware conflict-avoiding thrashing-resistant gpgpu
+ * cache management scheme." Khairy et al. IEEE TPDS 2017.
+ */
+ if (m_nset == 32 || m_nset == 64) {
+ std::bitset<64> a(addr);
+ std::bitset<6> index;
+ index[0] = a[25] ^ a[24] ^ a[23] ^ a[22] ^ a[21] ^ a[18] ^ a[17] ^
+ a[15] ^ a[12] ^ a[7]; // 10
+ index[1] = a[26] ^ a[25] ^ a[24] ^ a[23] ^ a[22] ^ a[19] ^ a[18] ^
+ a[16] ^ a[13] ^ a[8]; // 10
+ index[2] = a[26] ^ a[22] ^ a[21] ^ a[20] ^ a[19] ^ a[18] ^ a[15] ^
+ a[14] ^ a[12] ^ a[9]; // 10
+ index[3] = a[23] ^ a[22] ^ a[21] ^ a[20] ^ a[19] ^ a[16] ^ a[15] ^
+ a[13] ^ a[10]; // 9
+ index[4] = a[24] ^ a[23] ^ a[22] ^ a[21] ^ a[20] ^ a[17] ^ a[16] ^
+ a[14] ^ a[11]; // 9
- if(m_nset == 64)
- index[5] = a[12];
+ if (m_nset == 64) index[5] = a[12];
- set_index = index.to_ulong();
+ set_index = index.to_ulong();
- }else{ /* Else incorrect number of sets for the hashing function */
- assert("\nGPGPU-Sim cache configuration error: The number of sets should be "
- "32 or 64 for the hashing set index function.\n" && 0);
- }
- break;
+ } else { /* Else incorrect number of sets for the hashing function */
+ assert(
+ "\nGPGPU-Sim cache configuration error: The number of sets should "
+ "be "
+ "32 or 64 for the hashing set index function.\n" &&
+ 0);
+ }
+ break;
case CUSTOM_SET_FUNCTION:
- /* No custom set function implemented */
- break;
+ /* No custom set function implemented */
+ break;
case LINEAR_SET_FUNCTION:
- set_index = (addr >> m_line_sz_log2) & (m_nset-1);
- break;
+ set_index = (addr >> m_line_sz_log2) & (m_nset - 1);
+ break;
default:
- assert("\nUndefined set index function.\n" && 0);
- break;
- }
+ assert("\nUndefined set index function.\n" && 0);
+ break;
+ }
- // Linear function selected or custom set index function not implemented
- assert((set_index < m_nset) && "\nError: Set index out of bounds. This is caused by "
- "an incorrect or unimplemented custom set index function.\n");
+ // Linear function selected or custom set index function not implemented
+ assert((set_index < m_nset) &&
+ "\nError: Set index out of bounds. This is caused by "
+ "an incorrect or unimplemented custom set index function.\n");
- return set_index;
+ return set_index;
}
-void l2_cache_config::init(linear_to_raw_address_translation *address_mapping){
- cache_config::init(m_config_string,FuncCachePreferNone);
- m_address_mapping = address_mapping;
+void l2_cache_config::init(linear_to_raw_address_translation *address_mapping) {
+ cache_config::init(m_config_string, FuncCachePreferNone);
+ m_address_mapping = address_mapping;
}
-unsigned l2_cache_config::set_index(new_addr_type addr) const{
- if(!m_address_mapping){
- return(addr >> m_line_sz_log2) & (m_nset-1);
- }else{
- // Calculate set index without memory partition bits to reduce set camping
- new_addr_type part_addr = m_address_mapping->partition_address(addr);
- return(part_addr >> m_line_sz_log2) & (m_nset -1);
- }
+unsigned l2_cache_config::set_index(new_addr_type addr) const {
+ if (!m_address_mapping) {
+ return (addr >> m_line_sz_log2) & (m_nset - 1);
+ } else {
+ // Calculate set index without memory partition bits to reduce set camping
+ new_addr_type part_addr = m_address_mapping->partition_address(addr);
+ return (part_addr >> m_line_sz_log2) & (m_nset - 1);
+ }
}
-tag_array::~tag_array()
-{
- unsigned cache_lines_num = m_config.get_max_num_lines();
- for(unsigned i=0; i<cache_lines_num; ++i)
- delete m_lines[i];
- delete[] m_lines;
+tag_array::~tag_array() {
+ unsigned cache_lines_num = m_config.get_max_num_lines();
+ for (unsigned i = 0; i < cache_lines_num; ++i) delete m_lines[i];
+ delete[] m_lines;
}
-tag_array::tag_array( cache_config &config,
- int core_id,
- int type_id,
- cache_block_t** new_lines)
- : m_config( config ),
- m_lines( new_lines )
-{
- init( core_id, type_id );
+tag_array::tag_array(cache_config &config, int core_id, int type_id,
+ cache_block_t **new_lines)
+ : m_config(config), m_lines(new_lines) {
+ init(core_id, type_id);
}
-void tag_array::update_cache_parameters(cache_config &config)
-{
- m_config=config;
+void tag_array::update_cache_parameters(cache_config &config) {
+ m_config = config;
}
-tag_array::tag_array( cache_config &config,
- int core_id,
- int type_id )
- : m_config( config )
-{
- //assert( m_config.m_write_policy == READ_ONLY ); Old assert
- unsigned cache_lines_num = config.get_max_num_lines();
- m_lines = new cache_block_t*[cache_lines_num];
- if(config.m_cache_type == NORMAL)
- {
- for(unsigned i=0; i<cache_lines_num; ++i)
- m_lines[i] = new line_cache_block();
- }
- else if(config.m_cache_type == SECTOR)
- {
- for(unsigned i=0; i<cache_lines_num; ++i)
- m_lines[i] = new sector_cache_block();
- }
- else
- assert(0);
+tag_array::tag_array(cache_config &config, int core_id, int type_id)
+ : m_config(config) {
+ // assert( m_config.m_write_policy == READ_ONLY ); Old assert
+ unsigned cache_lines_num = config.get_max_num_lines();
+ m_lines = new cache_block_t *[cache_lines_num];
+ if (config.m_cache_type == NORMAL) {
+ for (unsigned i = 0; i < cache_lines_num; ++i)
+ m_lines[i] = new line_cache_block();
+ } else if (config.m_cache_type == SECTOR) {
+ for (unsigned i = 0; i < cache_lines_num; ++i)
+ m_lines[i] = new sector_cache_block();
+ } else
+ assert(0);
- init( core_id, type_id );
+ init(core_id, type_id);
}
-void tag_array::init( int core_id, int type_id )
-{
- m_access = 0;
- m_miss = 0;
- m_pending_hit = 0;
- m_res_fail = 0;
- m_sector_miss = 0;
- // initialize snapshot counters for visualizer
- m_prev_snapshot_access = 0;
- m_prev_snapshot_miss = 0;
- m_prev_snapshot_pending_hit = 0;
- m_core_id = core_id;
- m_type_id = type_id;
- is_used = false;
+void tag_array::init(int core_id, int type_id) {
+ m_access = 0;
+ m_miss = 0;
+ m_pending_hit = 0;
+ m_res_fail = 0;
+ m_sector_miss = 0;
+ // initialize snapshot counters for visualizer
+ m_prev_snapshot_access = 0;
+ m_prev_snapshot_miss = 0;
+ m_prev_snapshot_pending_hit = 0;
+ m_core_id = core_id;
+ m_type_id = type_id;
+ is_used = false;
}
-void tag_array::add_pending_line(mem_fetch *mf){
- assert(mf);
- new_addr_type addr = m_config.block_addr(mf->get_addr());
- line_table::const_iterator i = pending_lines.find(addr);
- if ( i == pending_lines.end() ) {
- pending_lines[addr] = mf->get_inst().get_uid();
- }
+void tag_array::add_pending_line(mem_fetch *mf) {
+ assert(mf);
+ new_addr_type addr = m_config.block_addr(mf->get_addr());
+ line_table::const_iterator i = pending_lines.find(addr);
+ if (i == pending_lines.end()) {
+ pending_lines[addr] = mf->get_inst().get_uid();
+ }
}
-void tag_array::remove_pending_line(mem_fetch *mf){
- assert(mf);
- new_addr_type addr = m_config.block_addr(mf->get_addr());
- line_table::const_iterator i = pending_lines.find(addr);
- if ( i != pending_lines.end() ) {
- pending_lines.erase(addr);
- }
+void tag_array::remove_pending_line(mem_fetch *mf) {
+ assert(mf);
+ new_addr_type addr = m_config.block_addr(mf->get_addr());
+ line_table::const_iterator i = pending_lines.find(addr);
+ if (i != pending_lines.end()) {
+ pending_lines.erase(addr);
+ }
}
-enum cache_request_status tag_array::probe( new_addr_type addr, unsigned &idx, mem_fetch* mf, bool probe_mode) const {
- mem_access_sector_mask_t mask = mf->get_access_sector_mask();
- return probe(addr, idx, mask, probe_mode, mf);
+enum cache_request_status tag_array::probe(new_addr_type addr, unsigned &idx,
+ mem_fetch *mf,
+ bool probe_mode) const {
+ mem_access_sector_mask_t mask = mf->get_access_sector_mask();
+ return probe(addr, idx, mask, probe_mode, mf);
}
+enum cache_request_status tag_array::probe(new_addr_type addr, unsigned &idx,
+ mem_access_sector_mask_t mask,
+ bool probe_mode,
+ mem_fetch *mf) const {
+ // assert( m_config.m_write_policy == READ_ONLY );
+ unsigned set_index = m_config.set_index(addr);
+ new_addr_type tag = m_config.tag(addr);
-enum cache_request_status tag_array::probe( new_addr_type addr, unsigned &idx, mem_access_sector_mask_t mask, bool probe_mode, mem_fetch* mf) const {
- //assert( m_config.m_write_policy == READ_ONLY );
- unsigned set_index = m_config.set_index(addr);
- new_addr_type tag = m_config.tag(addr);
-
- unsigned invalid_line = (unsigned)-1;
- unsigned valid_line = (unsigned)-1;
- unsigned long long valid_timestamp = (unsigned)-1;
-
- bool all_reserved = true;
+ unsigned invalid_line = (unsigned)-1;
+ unsigned valid_line = (unsigned)-1;
+ unsigned long long valid_timestamp = (unsigned)-1;
- // check for hit or pending hit
- for (unsigned way=0; way<m_config.m_assoc; way++) {
- unsigned index = set_index*m_config.m_assoc+way;
- cache_block_t *line = m_lines[index];
- if (line->m_tag == tag) {
- if ( line->get_status(mask) == RESERVED ) {
- idx = index;
- return HIT_RESERVED;
- } else if ( line->get_status(mask) == VALID ) {
- idx = index;
- return HIT;
- } else if ( line->get_status(mask) == MODIFIED) {
- if(line->is_readable(mask)) {
- idx = index;
- return HIT;
- }
- else {
- idx = index;
- return SECTOR_MISS;
- }
+ bool all_reserved = true;
- } else if ( line->is_valid_line() && line->get_status(mask) == INVALID ) {
- idx = index;
- return SECTOR_MISS;
- }else {
- assert( line->get_status(mask) == INVALID );
- }
- }
- if (!line->is_reserved_line()) {
- all_reserved = false;
- if (line->is_invalid_line()) {
- invalid_line = index;
- } else {
- // valid line : keep track of most appropriate replacement candidate
- if ( m_config.m_replacement_policy == LRU ) {
- if ( line->get_last_access_time() < valid_timestamp ) {
- valid_timestamp = line->get_last_access_time();
- valid_line = index;
- }
- } else if ( m_config.m_replacement_policy == FIFO ) {
- if ( line->get_alloc_time() < valid_timestamp ) {
- valid_timestamp = line->get_alloc_time();
- valid_line = index;
- }
- }
- }
+ // check for hit or pending hit
+ for (unsigned way = 0; way < m_config.m_assoc; way++) {
+ unsigned index = set_index * m_config.m_assoc + way;
+ cache_block_t *line = m_lines[index];
+ if (line->m_tag == tag) {
+ if (line->get_status(mask) == RESERVED) {
+ idx = index;
+ return HIT_RESERVED;
+ } else if (line->get_status(mask) == VALID) {
+ idx = index;
+ return HIT;
+ } else if (line->get_status(mask) == MODIFIED) {
+ if (line->is_readable(mask)) {
+ idx = index;
+ return HIT;
+ } else {
+ idx = index;
+ return SECTOR_MISS;
}
+
+ } else if (line->is_valid_line() && line->get_status(mask) == INVALID) {
+ idx = index;
+ return SECTOR_MISS;
+ } else {
+ assert(line->get_status(mask) == INVALID);
+ }
}
- if ( all_reserved ) {
- assert( m_config.m_alloc_policy == ON_MISS );
- return RESERVATION_FAIL; // miss and not enough space in cache to allocate on miss
+ if (!line->is_reserved_line()) {
+ all_reserved = false;
+ if (line->is_invalid_line()) {
+ invalid_line = index;
+ } else {
+ // valid line : keep track of most appropriate replacement candidate
+ if (m_config.m_replacement_policy == LRU) {
+ if (line->get_last_access_time() < valid_timestamp) {
+ valid_timestamp = line->get_last_access_time();
+ valid_line = index;
+ }
+ } else if (m_config.m_replacement_policy == FIFO) {
+ if (line->get_alloc_time() < valid_timestamp) {
+ valid_timestamp = line->get_alloc_time();
+ valid_line = index;
+ }
+ }
+ }
}
+ }
+ if (all_reserved) {
+ assert(m_config.m_alloc_policy == ON_MISS);
+ return RESERVATION_FAIL; // miss and not enough space in cache to allocate
+ // on miss
+ }
- if ( invalid_line != (unsigned)-1 ) {
- idx = invalid_line;
- } else if ( valid_line != (unsigned)-1) {
- idx = valid_line;
- } else abort(); // if an unreserved block exists, it is either invalid or replaceable
-
+ if (invalid_line != (unsigned)-1) {
+ idx = invalid_line;
+ } else if (valid_line != (unsigned)-1) {
+ idx = valid_line;
+ } else
+ abort(); // if an unreserved block exists, it is either invalid or
+ // replaceable
- if(probe_mode && m_config.is_streaming()){
- line_table::const_iterator i = pending_lines.find(m_config.block_addr(addr));
- assert(mf);
- if ( !mf->is_write() && i != pending_lines.end() ) {
- if(i->second != mf->get_inst().get_uid())
- return SECTOR_MISS;
- }
+ if (probe_mode && m_config.is_streaming()) {
+ line_table::const_iterator i =
+ pending_lines.find(m_config.block_addr(addr));
+ assert(mf);
+ if (!mf->is_write() && i != pending_lines.end()) {
+ if (i->second != mf->get_inst().get_uid()) return SECTOR_MISS;
}
+ }
- return MISS;
+ return MISS;
}
-enum cache_request_status tag_array::access( new_addr_type addr, unsigned time, unsigned &idx, mem_fetch* mf)
-{
- bool wb=false;
- evicted_block_info evicted;
- enum cache_request_status result = access(addr,time,idx,wb,evicted,mf);
- assert(!wb);
- return result;
+enum cache_request_status tag_array::access(new_addr_type addr, unsigned time,
+ unsigned &idx, mem_fetch *mf) {
+ bool wb = false;
+ evicted_block_info evicted;
+ enum cache_request_status result = access(addr, time, idx, wb, evicted, mf);
+ assert(!wb);
+ return result;
}
-enum cache_request_status tag_array::access( new_addr_type addr, unsigned time, unsigned &idx, bool &wb, evicted_block_info &evicted, mem_fetch* mf )
-{
- m_access++;
- is_used = true;
- shader_cache_access_log(m_core_id, m_type_id, 0); // log accesses to cache
- enum cache_request_status status = probe(addr,idx,mf);
- switch (status) {
- case HIT_RESERVED:
- m_pending_hit++;
- case HIT:
- m_lines[idx]->set_last_access_time(time, mf->get_access_sector_mask());
- break;
+enum cache_request_status tag_array::access(new_addr_type addr, unsigned time,
+ unsigned &idx, bool &wb,
+ evicted_block_info &evicted,
+ mem_fetch *mf) {
+ m_access++;
+ is_used = true;
+ shader_cache_access_log(m_core_id, m_type_id, 0); // log accesses to cache
+ enum cache_request_status status = probe(addr, idx, mf);
+ switch (status) {
+ case HIT_RESERVED:
+ m_pending_hit++;
+ case HIT:
+ m_lines[idx]->set_last_access_time(time, mf->get_access_sector_mask());
+ break;
case MISS:
- m_miss++;
- shader_cache_access_log(m_core_id, m_type_id, 1); // log cache misses
- if ( m_config.m_alloc_policy == ON_MISS ) {
- if( m_lines[idx]->is_modified_line()) {
- wb = true;
- evicted.set_info(m_lines[idx]->m_block_addr, m_lines[idx]->get_modified_size());
- }
- m_lines[idx]->allocate( m_config.tag(addr), m_config.block_addr(addr), time, mf->get_access_sector_mask());
+ m_miss++;
+ shader_cache_access_log(m_core_id, m_type_id, 1); // log cache misses
+ if (m_config.m_alloc_policy == ON_MISS) {
+ if (m_lines[idx]->is_modified_line()) {
+ wb = true;
+ evicted.set_info(m_lines[idx]->m_block_addr,
+ m_lines[idx]->get_modified_size());
}
- break;
+ m_lines[idx]->allocate(m_config.tag(addr), m_config.block_addr(addr),
+ time, mf->get_access_sector_mask());
+ }
+ break;
case SECTOR_MISS:
- assert(m_config.m_cache_type == SECTOR);
- m_sector_miss++;
- shader_cache_access_log(m_core_id, m_type_id, 1); // log cache misses
- if ( m_config.m_alloc_policy == ON_MISS ) {
- ((sector_cache_block*)m_lines[idx])->allocate_sector( time, mf->get_access_sector_mask() );
- }
- break;
+ assert(m_config.m_cache_type == SECTOR);
+ m_sector_miss++;
+ shader_cache_access_log(m_core_id, m_type_id, 1); // log cache misses
+ if (m_config.m_alloc_policy == ON_MISS) {
+ ((sector_cache_block *)m_lines[idx])
+ ->allocate_sector(time, mf->get_access_sector_mask());
+ }
+ break;
case RESERVATION_FAIL:
- m_res_fail++;
- shader_cache_access_log(m_core_id, m_type_id, 1); // log cache misses
- break;
+ m_res_fail++;
+ shader_cache_access_log(m_core_id, m_type_id, 1); // log cache misses
+ break;
default:
- fprintf( stderr, "tag_array::access - Error: Unknown"
- "cache_request_status %d\n", status );
- abort();
- }
- return status;
+ fprintf(stderr,
+ "tag_array::access - Error: Unknown"
+ "cache_request_status %d\n",
+ status);
+ abort();
+ }
+ return status;
}
-void tag_array::fill( new_addr_type addr, unsigned time, mem_fetch* mf)
-{
- fill(addr, time, mf->get_access_sector_mask());
+void tag_array::fill(new_addr_type addr, unsigned time, mem_fetch *mf) {
+ fill(addr, time, mf->get_access_sector_mask());
}
-void tag_array::fill( new_addr_type addr, unsigned time, mem_access_sector_mask_t mask )
-{
- //assert( m_config.m_alloc_policy == ON_FILL );
- unsigned idx;
- enum cache_request_status status = probe(addr,idx,mask);
- //assert(status==MISS||status==SECTOR_MISS); // MSHR should have prevented redundant memory request
- if(status==MISS)
- m_lines[idx]->allocate( m_config.tag(addr), m_config.block_addr(addr), time, mask );
- else if (status==SECTOR_MISS) {
- assert(m_config.m_cache_type == SECTOR);
- ((sector_cache_block*)m_lines[idx])->allocate_sector( time, mask );
- }
+void tag_array::fill(new_addr_type addr, unsigned time,
+ mem_access_sector_mask_t mask) {
+ // assert( m_config.m_alloc_policy == ON_FILL );
+ unsigned idx;
+ enum cache_request_status status = probe(addr, idx, mask);
+ // assert(status==MISS||status==SECTOR_MISS); // MSHR should have prevented
+ // redundant memory request
+ if (status == MISS)
+ m_lines[idx]->allocate(m_config.tag(addr), m_config.block_addr(addr), time,
+ mask);
+ else if (status == SECTOR_MISS) {
+ assert(m_config.m_cache_type == SECTOR);
+ ((sector_cache_block *)m_lines[idx])->allocate_sector(time, mask);
+ }
- m_lines[idx]->fill(time, mask);
+ m_lines[idx]->fill(time, mask);
}
-void tag_array::fill( unsigned index, unsigned time, mem_fetch* mf)
-{
- assert( m_config.m_alloc_policy == ON_MISS );
- m_lines[index]->fill(time, mf->get_access_sector_mask());
+void tag_array::fill(unsigned index, unsigned time, mem_fetch *mf) {
+ assert(m_config.m_alloc_policy == ON_MISS);
+ m_lines[index]->fill(time, mf->get_access_sector_mask());
}
+// TODO: we need write back the flushed data to the upper level
+void tag_array::flush() {
+ if (!is_used) return;
-//TODO: we need write back the flushed data to the upper level
-void tag_array::flush()
-{
- if(!is_used)
- return;
-
- for (unsigned i=0; i < m_config.get_num_lines(); i++)
- if(m_lines[i]->is_modified_line()) {
- for(unsigned j=0; j < SECTOR_CHUNCK_SIZE; j++)
- m_lines[i]->set_status(INVALID, mem_access_sector_mask_t().set(j)) ;
- }
+ for (unsigned i = 0; i < m_config.get_num_lines(); i++)
+ if (m_lines[i]->is_modified_line()) {
+ for (unsigned j = 0; j < SECTOR_CHUNCK_SIZE; j++)
+ m_lines[i]->set_status(INVALID, mem_access_sector_mask_t().set(j));
+ }
- is_used = false;
+ is_used = false;
}
-void tag_array::invalidate()
-{
- if(!is_used)
- return;
+void tag_array::invalidate() {
+ if (!is_used) return;
- for (unsigned i=0; i < m_config.get_num_lines(); i++)
- for(unsigned j=0; j < SECTOR_CHUNCK_SIZE; j++)
- m_lines[i]->set_status(INVALID, mem_access_sector_mask_t().set(j)) ;
+ for (unsigned i = 0; i < m_config.get_num_lines(); i++)
+ for (unsigned j = 0; j < SECTOR_CHUNCK_SIZE; j++)
+ m_lines[i]->set_status(INVALID, mem_access_sector_mask_t().set(j));
- is_used = false;
+ is_used = false;
}
-float tag_array::windowed_miss_rate( ) const
-{
- unsigned n_access = m_access - m_prev_snapshot_access;
- unsigned n_miss = (m_miss+m_sector_miss) - m_prev_snapshot_miss;
- // unsigned n_pending_hit = m_pending_hit - m_prev_snapshot_pending_hit;
+float tag_array::windowed_miss_rate() const {
+ unsigned n_access = m_access - m_prev_snapshot_access;
+ unsigned n_miss = (m_miss + m_sector_miss) - m_prev_snapshot_miss;
+ // unsigned n_pending_hit = m_pending_hit - m_prev_snapshot_pending_hit;
- float missrate = 0.0f;
- if (n_access != 0)
- missrate = (float) (n_miss+m_sector_miss) / n_access;
- return missrate;
+ float missrate = 0.0f;
+ if (n_access != 0) missrate = (float)(n_miss + m_sector_miss) / n_access;
+ return missrate;
}
-void tag_array::new_window()
-{
- m_prev_snapshot_access = m_access;
- m_prev_snapshot_miss = m_miss;
- m_prev_snapshot_miss = m_miss + m_sector_miss;
- m_prev_snapshot_pending_hit = m_pending_hit;
+void tag_array::new_window() {
+ m_prev_snapshot_access = m_access;
+ m_prev_snapshot_miss = m_miss;
+ m_prev_snapshot_miss = m_miss + m_sector_miss;
+ m_prev_snapshot_pending_hit = m_pending_hit;
}
-void tag_array::print( FILE *stream, unsigned &total_access, unsigned &total_misses ) const
-{
- m_config.print(stream);
- fprintf( stream, "\t\tAccess = %d, Miss = %d, Sector_Miss = %d, Total_Miss = %d (%.3g), PendingHit = %d (%.3g)\n",
- m_access, m_miss, m_sector_miss, (m_miss+m_sector_miss), (float) (m_miss+m_sector_miss) / m_access,
- m_pending_hit, (float) m_pending_hit / m_access);
- total_misses+=(m_miss+m_sector_miss);
- total_access+=m_access;
+void tag_array::print(FILE *stream, unsigned &total_access,
+ unsigned &total_misses) const {
+ m_config.print(stream);
+ fprintf(stream,
+ "\t\tAccess = %d, Miss = %d, Sector_Miss = %d, Total_Miss = %d "
+ "(%.3g), PendingHit = %d (%.3g)\n",
+ m_access, m_miss, m_sector_miss, (m_miss + m_sector_miss),
+ (float)(m_miss + m_sector_miss) / m_access, m_pending_hit,
+ (float)m_pending_hit / m_access);
+ total_misses += (m_miss + m_sector_miss);
+ total_access += m_access;
}
-void tag_array::get_stats(unsigned &total_access, unsigned &total_misses, unsigned &total_hit_res, unsigned &total_res_fail) const{
- // Update statistics from the tag array
- total_access = m_access;
- total_misses = (m_miss+m_sector_miss);
- total_hit_res = m_pending_hit;
- total_res_fail = m_res_fail;
+void tag_array::get_stats(unsigned &total_access, unsigned &total_misses,
+ unsigned &total_hit_res,
+ unsigned &total_res_fail) const {
+ // Update statistics from the tag array
+ total_access = m_access;
+ total_misses = (m_miss + m_sector_miss);
+ total_hit_res = m_pending_hit;
+ total_res_fail = m_res_fail;
}
-
-bool was_write_sent( const std::list<cache_event> &events )
-{
- for( std::list<cache_event>::const_iterator e=events.begin(); e!=events.end(); e++ ) {
- if( (*e).m_cache_event_type == WRITE_REQUEST_SENT )
- return true;
- }
- return false;
+bool was_write_sent(const std::list<cache_event> &events) {
+ for (std::list<cache_event>::const_iterator e = events.begin();
+ e != events.end(); e++) {
+ if ((*e).m_cache_event_type == WRITE_REQUEST_SENT) return true;
+ }
+ return false;
}
-bool was_writeback_sent( const std::list<cache_event> &events, cache_event& wb_event)
-{
- for( std::list<cache_event>::const_iterator e=events.begin(); e!=events.end(); e++ ) {
- if( (*e).m_cache_event_type == WRITE_BACK_REQUEST_SENT )
- wb_event = *e;
- return true;
- }
- return false;
+bool was_writeback_sent(const std::list<cache_event> &events,
+ cache_event &wb_event) {
+ for (std::list<cache_event>::const_iterator e = events.begin();
+ e != events.end(); e++) {
+ if ((*e).m_cache_event_type == WRITE_BACK_REQUEST_SENT) wb_event = *e;
+ return true;
+ }
+ return false;
}
-bool was_read_sent( const std::list<cache_event> &events )
-{
- for( std::list<cache_event>::const_iterator e=events.begin(); e!=events.end(); e++ ) {
- if( (*e).m_cache_event_type == READ_REQUEST_SENT )
- return true;
- }
- return false;
+bool was_read_sent(const std::list<cache_event> &events) {
+ for (std::list<cache_event>::const_iterator e = events.begin();
+ e != events.end(); e++) {
+ if ((*e).m_cache_event_type == READ_REQUEST_SENT) return true;
+ }
+ return false;
}
-bool was_writeallocate_sent( const std::list<cache_event> &events )
-{
- for( std::list<cache_event>::const_iterator e=events.begin(); e!=events.end(); e++ ) {
- if( (*e).m_cache_event_type == WRITE_ALLOCATE_SENT )
- return true;
- }
- return false;
+bool was_writeallocate_sent(const std::list<cache_event> &events) {
+ for (std::list<cache_event>::const_iterator e = events.begin();
+ e != events.end(); e++) {
+ if ((*e).m_cache_event_type == WRITE_ALLOCATE_SENT) return true;
+ }
+ return false;
}
-/****************************************************************** MSHR ******************************************************************/
+/****************************************************************** MSHR
+ * ******************************************************************/
/// Checks if there is a pending request to the lower memory level already
-bool mshr_table::probe( new_addr_type block_addr ) const{
- table::const_iterator a = m_data.find(block_addr);
- return a != m_data.end();
+bool mshr_table::probe(new_addr_type block_addr) const {
+ table::const_iterator a = m_data.find(block_addr);
+ return a != m_data.end();
}
/// Checks if there is space for tracking a new memory access
-bool mshr_table::full( new_addr_type block_addr ) const{
- table::const_iterator i=m_data.find(block_addr);
- if ( i != m_data.end() )
- return i->second.m_list.size() >= m_max_merged;
- else
- return m_data.size() >= m_num_entries;
+bool mshr_table::full(new_addr_type block_addr) const {
+ table::const_iterator i = m_data.find(block_addr);
+ if (i != m_data.end())
+ return i->second.m_list.size() >= m_max_merged;
+ else
+ return m_data.size() >= m_num_entries;
}
/// Add or merge this access
-void mshr_table::add( new_addr_type block_addr, mem_fetch *mf ){
- m_data[block_addr].m_list.push_back(mf);
- assert( m_data.size() <= m_num_entries );
- assert( m_data[block_addr].m_list.size() <= m_max_merged );
- // indicate that this MSHR entry contains an atomic operation
- if ( mf->isatomic() ) {
- m_data[block_addr].m_has_atomic = true;
- }
+void mshr_table::add(new_addr_type block_addr, mem_fetch *mf) {
+ m_data[block_addr].m_list.push_back(mf);
+ assert(m_data.size() <= m_num_entries);
+ assert(m_data[block_addr].m_list.size() <= m_max_merged);
+ // indicate that this MSHR entry contains an atomic operation
+ if (mf->isatomic()) {
+ m_data[block_addr].m_has_atomic = true;
+ }
}
/// check is_read_after_write_pending
-bool mshr_table::is_read_after_write_pending( new_addr_type block_addr){
- std::list<mem_fetch*> my_list = m_data[block_addr].m_list;
- bool write_found = false;
- for (std::list<mem_fetch*>::iterator it=my_list.begin(); it != my_list.end(); ++it)
- {
- if((*it)->is_write()) //Pending Write Request
- write_found = true;
- else if(write_found) //Pending Read Request and we found previous Write
- return true;
- }
-
- return false;
+bool mshr_table::is_read_after_write_pending(new_addr_type block_addr) {
+ std::list<mem_fetch *> my_list = m_data[block_addr].m_list;
+ bool write_found = false;
+ for (std::list<mem_fetch *>::iterator it = my_list.begin();
+ it != my_list.end(); ++it) {
+ if ((*it)->is_write()) // Pending Write Request
+ write_found = true;
+ else if (write_found) // Pending Read Request and we found previous Write
+ return true;
+ }
+ return false;
}
/// Accept a new cache fill response: mark entry ready for processing
-void mshr_table::mark_ready( new_addr_type block_addr, bool &has_atomic ){
- assert( !busy() );
- table::iterator a = m_data.find(block_addr);
- assert( a != m_data.end() );
- m_current_response.push_back( block_addr );
- has_atomic = a->second.m_has_atomic;
- assert( m_current_response.size() <= m_data.size() );
+void mshr_table::mark_ready(new_addr_type block_addr, bool &has_atomic) {
+ assert(!busy());
+ table::iterator a = m_data.find(block_addr);
+ assert(a != m_data.end());
+ m_current_response.push_back(block_addr);
+ has_atomic = a->second.m_has_atomic;
+ assert(m_current_response.size() <= m_data.size());
}
/// Returns next ready access
-mem_fetch *mshr_table::next_access(){
- assert( access_ready() );
- new_addr_type block_addr = m_current_response.front();
- assert( !m_data[block_addr].m_list.empty() );
- mem_fetch *result = m_data[block_addr].m_list.front();
- m_data[block_addr].m_list.pop_front();
- if ( m_data[block_addr].m_list.empty() ) {
- // release entry
- m_data.erase(block_addr);
- m_current_response.pop_front();
- }
- return result;
+mem_fetch *mshr_table::next_access() {
+ assert(access_ready());
+ new_addr_type block_addr = m_current_response.front();
+ assert(!m_data[block_addr].m_list.empty());
+ mem_fetch *result = m_data[block_addr].m_list.front();
+ m_data[block_addr].m_list.pop_front();
+ if (m_data[block_addr].m_list.empty()) {
+ // release entry
+ m_data.erase(block_addr);
+ m_current_response.pop_front();
+ }
+ return result;
}
-void mshr_table::display( FILE *fp ) const{
- fprintf(fp,"MSHR contents\n");
- for ( table::const_iterator e=m_data.begin(); e!=m_data.end(); ++e ) {
- unsigned block_addr = e->first;
- fprintf(fp,"MSHR: tag=0x%06x, atomic=%d %zu entries : ", block_addr, e->second.m_has_atomic, e->second.m_list.size());
- if ( !e->second.m_list.empty() ) {
- mem_fetch *mf = e->second.m_list.front();
- fprintf(fp,"%p :",mf);
- mf->print(fp);
- } else {
- fprintf(fp," no memory requests???\n");
- }
+void mshr_table::display(FILE *fp) const {
+ fprintf(fp, "MSHR contents\n");
+ for (table::const_iterator e = m_data.begin(); e != m_data.end(); ++e) {
+ unsigned block_addr = e->first;
+ fprintf(fp, "MSHR: tag=0x%06x, atomic=%d %zu entries : ", block_addr,
+ e->second.m_has_atomic, e->second.m_list.size());
+ if (!e->second.m_list.empty()) {
+ mem_fetch *mf = e->second.m_list.front();
+ fprintf(fp, "%p :", mf);
+ mf->print(fp);
+ } else {
+ fprintf(fp, " no memory requests???\n");
}
+ }
}
-/***************************************************************** Caches *****************************************************************/
-cache_stats::cache_stats(){
- m_stats.resize(NUM_MEM_ACCESS_TYPE);
- m_stats_pw.resize(NUM_MEM_ACCESS_TYPE);
- m_fail_stats.resize(NUM_MEM_ACCESS_TYPE);
- for(unsigned i=0; i<NUM_MEM_ACCESS_TYPE; ++i){
- m_stats[i].resize(NUM_CACHE_REQUEST_STATUS, 0);
- m_stats_pw[i].resize(NUM_CACHE_REQUEST_STATUS, 0);
- m_fail_stats[i].resize(NUM_CACHE_RESERVATION_FAIL_STATUS, 0);
- }
- m_cache_port_available_cycles = 0;
- m_cache_data_port_busy_cycles = 0;
- m_cache_fill_port_busy_cycles = 0;
+/***************************************************************** Caches
+ * *****************************************************************/
+cache_stats::cache_stats() {
+ m_stats.resize(NUM_MEM_ACCESS_TYPE);
+ m_stats_pw.resize(NUM_MEM_ACCESS_TYPE);
+ m_fail_stats.resize(NUM_MEM_ACCESS_TYPE);
+ for (unsigned i = 0; i < NUM_MEM_ACCESS_TYPE; ++i) {
+ m_stats[i].resize(NUM_CACHE_REQUEST_STATUS, 0);
+ m_stats_pw[i].resize(NUM_CACHE_REQUEST_STATUS, 0);
+ m_fail_stats[i].resize(NUM_CACHE_RESERVATION_FAIL_STATUS, 0);
+ }
+ m_cache_port_available_cycles = 0;
+ m_cache_data_port_busy_cycles = 0;
+ m_cache_fill_port_busy_cycles = 0;
}
-void cache_stats::clear(){
- ///
- /// Zero out all current cache statistics
- ///
- for(unsigned i=0; i<NUM_MEM_ACCESS_TYPE; ++i){
- std::fill(m_stats[i].begin(), m_stats[i].end(), 0);
- std::fill(m_fail_stats[i].begin(), m_fail_stats[i].end(), 0);
- }
- m_cache_port_available_cycles = 0;
- m_cache_data_port_busy_cycles = 0;
- m_cache_fill_port_busy_cycles = 0;
+void cache_stats::clear() {
+ ///
+ /// Zero out all current cache statistics
+ ///
+ for (unsigned i = 0; i < NUM_MEM_ACCESS_TYPE; ++i) {
+ std::fill(m_stats[i].begin(), m_stats[i].end(), 0);
+ std::fill(m_fail_stats[i].begin(), m_fail_stats[i].end(), 0);
+ }
+ m_cache_port_available_cycles = 0;
+ m_cache_data_port_busy_cycles = 0;
+ m_cache_fill_port_busy_cycles = 0;
}
-void cache_stats::clear_pw(){
- ///
- /// Zero out per-window cache statistics
- ///
- for(unsigned i=0; i<NUM_MEM_ACCESS_TYPE; ++i){
- std::fill(m_stats_pw[i].begin(), m_stats_pw[i].end(), 0);
- }
+void cache_stats::clear_pw() {
+ ///
+ /// Zero out per-window cache statistics
+ ///
+ for (unsigned i = 0; i < NUM_MEM_ACCESS_TYPE; ++i) {
+ std::fill(m_stats_pw[i].begin(), m_stats_pw[i].end(), 0);
+ }
}
-void cache_stats::inc_stats(int access_type, int access_outcome){
- ///
- /// Increment the stat corresponding to (access_type, access_outcome) by 1.
- ///
- if(!check_valid(access_type, access_outcome))
- assert(0 && "Unknown cache access type or access outcome");
+void cache_stats::inc_stats(int access_type, int access_outcome) {
+ ///
+ /// Increment the stat corresponding to (access_type, access_outcome) by 1.
+ ///
+ if (!check_valid(access_type, access_outcome))
+ assert(0 && "Unknown cache access type or access outcome");
- m_stats[access_type][access_outcome]++;
+ m_stats[access_type][access_outcome]++;
}
-void cache_stats::inc_stats_pw(int access_type, int access_outcome){
- ///
- /// Increment the corresponding per-window cache stat
- ///
- if(!check_valid(access_type, access_outcome))
- assert(0 && "Unknown cache access type or access outcome");
- m_stats_pw[access_type][access_outcome]++;
+void cache_stats::inc_stats_pw(int access_type, int access_outcome) {
+ ///
+ /// Increment the corresponding per-window cache stat
+ ///
+ if (!check_valid(access_type, access_outcome))
+ assert(0 && "Unknown cache access type or access outcome");
+ m_stats_pw[access_type][access_outcome]++;
}
-void cache_stats::inc_fail_stats(int access_type, int fail_outcome){
-
- if(!check_fail_valid(access_type, fail_outcome))
- assert(0 && "Unknown cache access type or access fail");
+void cache_stats::inc_fail_stats(int access_type, int fail_outcome) {
+ if (!check_fail_valid(access_type, fail_outcome))
+ assert(0 && "Unknown cache access type or access fail");
- m_fail_stats[access_type][fail_outcome]++;
+ m_fail_stats[access_type][fail_outcome]++;
}
-
-enum cache_request_status cache_stats::select_stats_status(enum cache_request_status probe, enum cache_request_status access) const {
- ///
- /// This function selects how the cache access outcome should be counted. HIT_RESERVED is considered as a MISS
- /// in the cores, however, it should be counted as a HIT_RESERVED in the caches.
- ///
- if(probe == HIT_RESERVED && access != RESERVATION_FAIL)
- return probe;
- else if(probe == SECTOR_MISS && access == MISS)
- return probe;
- else
- return access;
+enum cache_request_status cache_stats::select_stats_status(
+ enum cache_request_status probe, enum cache_request_status access) const {
+ ///
+ /// This function selects how the cache access outcome should be counted.
+ /// HIT_RESERVED is considered as a MISS in the cores, however, it should be
+ /// counted as a HIT_RESERVED in the caches.
+ ///
+ if (probe == HIT_RESERVED && access != RESERVATION_FAIL)
+ return probe;
+ else if (probe == SECTOR_MISS && access == MISS)
+ return probe;
+ else
+ return access;
}
-unsigned long long &cache_stats::operator()(int access_type, int access_outcome, bool fail_outcome){
- ///
- /// Simple method to read/modify the stat corresponding to (access_type, access_outcome)
- /// Used overloaded () to avoid the need for separate read/write member functions
- ///
- if(fail_outcome) {
- if(!check_fail_valid(access_type, access_outcome))
- assert(0 && "Unknown cache access type or fail outcome");
+unsigned long long &cache_stats::operator()(int access_type, int access_outcome,
+ bool fail_outcome) {
+ ///
+ /// Simple method to read/modify the stat corresponding to (access_type,
+ /// access_outcome) Used overloaded () to avoid the need for separate
+ /// read/write member functions
+ ///
+ if (fail_outcome) {
+ if (!check_fail_valid(access_type, access_outcome))
+ assert(0 && "Unknown cache access type or fail outcome");
- return m_fail_stats[access_type][access_outcome];
- }
- else {
- if(!check_valid(access_type, access_outcome))
- assert(0 && "Unknown cache access type or access outcome");
+ return m_fail_stats[access_type][access_outcome];
+ } else {
+ if (!check_valid(access_type, access_outcome))
+ assert(0 && "Unknown cache access type or access outcome");
- return m_stats[access_type][access_outcome];
- }
+ return m_stats[access_type][access_outcome];
+ }
}
-unsigned long long cache_stats::operator()(int access_type, int access_outcome, bool fail_outcome) const{
- ///
- /// Const accessor into m_stats.
- ///
- if(fail_outcome) {
- if(!check_fail_valid(access_type, access_outcome))
- assert(0 && "Unknown cache access type or fail outcome");
+unsigned long long cache_stats::operator()(int access_type, int access_outcome,
+ bool fail_outcome) const {
+ ///
+ /// Const accessor into m_stats.
+ ///
+ if (fail_outcome) {
+ if (!check_fail_valid(access_type, access_outcome))
+ assert(0 && "Unknown cache access type or fail outcome");
- return m_fail_stats[access_type][access_outcome];
- }
- else {
- if(!check_valid(access_type, access_outcome))
- assert(0 && "Unknown cache access type or access outcome");
+ return m_fail_stats[access_type][access_outcome];
+ } else {
+ if (!check_valid(access_type, access_outcome))
+ assert(0 && "Unknown cache access type or access outcome");
- return m_stats[access_type][access_outcome];
- }
+ return m_stats[access_type][access_outcome];
+ }
}
-cache_stats cache_stats::operator+(const cache_stats &cs){
- ///
- /// Overloaded + operator to allow for simple stat accumulation
- ///
- cache_stats ret;
- for(unsigned type=0; type<NUM_MEM_ACCESS_TYPE; ++type){
- for(unsigned status=0; status<NUM_CACHE_REQUEST_STATUS; ++status){
- ret(type, status, false) = m_stats[type][status] + cs(type, status, false);
- }
- for(unsigned status=0; status<NUM_CACHE_RESERVATION_FAIL_STATUS; ++status){
- ret(type, status, true) = m_fail_stats[type][status] + cs(type, status, true);
- }
- }
- ret.m_cache_port_available_cycles = m_cache_port_available_cycles + cs.m_cache_port_available_cycles;
- ret.m_cache_data_port_busy_cycles = m_cache_data_port_busy_cycles + cs.m_cache_data_port_busy_cycles;
- ret.m_cache_fill_port_busy_cycles = m_cache_fill_port_busy_cycles + cs.m_cache_fill_port_busy_cycles;
- return ret;
+cache_stats cache_stats::operator+(const cache_stats &cs) {
+ ///
+ /// Overloaded + operator to allow for simple stat accumulation
+ ///
+ cache_stats ret;
+ for (unsigned type = 0; type < NUM_MEM_ACCESS_TYPE; ++type) {
+ for (unsigned status = 0; status < NUM_CACHE_REQUEST_STATUS; ++status) {
+ ret(type, status, false) =
+ m_stats[type][status] + cs(type, status, false);
+ }
+ for (unsigned status = 0; status < NUM_CACHE_RESERVATION_FAIL_STATUS;
+ ++status) {
+ ret(type, status, true) =
+ m_fail_stats[type][status] + cs(type, status, true);
+ }
+ }
+ ret.m_cache_port_available_cycles =
+ m_cache_port_available_cycles + cs.m_cache_port_available_cycles;
+ ret.m_cache_data_port_busy_cycles =
+ m_cache_data_port_busy_cycles + cs.m_cache_data_port_busy_cycles;
+ ret.m_cache_fill_port_busy_cycles =
+ m_cache_fill_port_busy_cycles + cs.m_cache_fill_port_busy_cycles;
+ return ret;
}
-cache_stats &cache_stats::operator+=(const cache_stats &cs){
- ///
- /// Overloaded += operator to allow for simple stat accumulation
- ///
- for(unsigned type=0; type<NUM_MEM_ACCESS_TYPE; ++type){
- for(unsigned status=0; status<NUM_CACHE_REQUEST_STATUS; ++status){
- m_stats[type][status] += cs(type, status, false);
- }
- for(unsigned status=0; status<NUM_CACHE_REQUEST_STATUS; ++status){
- m_stats_pw[type][status] += cs(type, status, false);
- }
- for(unsigned status=0; status<NUM_CACHE_RESERVATION_FAIL_STATUS; ++status){
- m_fail_stats[type][status] += cs(type, status, true);
- }
+cache_stats &cache_stats::operator+=(const cache_stats &cs) {
+ ///
+ /// Overloaded += operator to allow for simple stat accumulation
+ ///
+ for (unsigned type = 0; type < NUM_MEM_ACCESS_TYPE; ++type) {
+ for (unsigned status = 0; status < NUM_CACHE_REQUEST_STATUS; ++status) {
+ m_stats[type][status] += cs(type, status, false);
+ }
+ for (unsigned status = 0; status < NUM_CACHE_REQUEST_STATUS; ++status) {
+ m_stats_pw[type][status] += cs(type, status, false);
+ }
+ for (unsigned status = 0; status < NUM_CACHE_RESERVATION_FAIL_STATUS;
+ ++status) {
+ m_fail_stats[type][status] += cs(type, status, true);
}
- m_cache_port_available_cycles += cs.m_cache_port_available_cycles;
- m_cache_data_port_busy_cycles += cs.m_cache_data_port_busy_cycles;
- m_cache_fill_port_busy_cycles += cs.m_cache_fill_port_busy_cycles;
- return *this;
+ }
+ m_cache_port_available_cycles += cs.m_cache_port_available_cycles;
+ m_cache_data_port_busy_cycles += cs.m_cache_data_port_busy_cycles;
+ m_cache_fill_port_busy_cycles += cs.m_cache_fill_port_busy_cycles;
+ return *this;
}
-void cache_stats::print_stats(FILE *fout, const char *cache_name) const{
- ///
- /// Print out each non-zero cache statistic for every memory access type and status
- /// "cache_name" defaults to "Cache_stats" when no argument is provided, otherwise
- /// the provided name is used.
- /// The printed format is "<cache_name>[<request_type>][<request_status>] = <stat_value>"
- ///
- std::vector< unsigned > total_access;
- total_access.resize(NUM_MEM_ACCESS_TYPE, 0);
- std::string m_cache_name = cache_name;
- for (unsigned type = 0; type < NUM_MEM_ACCESS_TYPE; ++type) {
- for (unsigned status = 0; status < NUM_CACHE_REQUEST_STATUS; ++status) {
- fprintf(fout, "\t%s[%s][%s] = %llu\n",
- m_cache_name.c_str(),
- mem_access_type_str((enum mem_access_type)type),
- cache_request_status_str((enum cache_request_status)status),
- m_stats[type][status]);
+void cache_stats::print_stats(FILE *fout, const char *cache_name) const {
+ ///
+ /// Print out each non-zero cache statistic for every memory access type and
+ /// status "cache_name" defaults to "Cache_stats" when no argument is
+ /// provided, otherwise the provided name is used. The printed format is
+ /// "<cache_name>[<request_type>][<request_status>] = <stat_value>"
+ ///
+ std::vector<unsigned> total_access;
+ total_access.resize(NUM_MEM_ACCESS_TYPE, 0);
+ std::string m_cache_name = cache_name;
+ for (unsigned type = 0; type < NUM_MEM_ACCESS_TYPE; ++type) {
+ for (unsigned status = 0; status < NUM_CACHE_REQUEST_STATUS; ++status) {
+ fprintf(fout, "\t%s[%s][%s] = %llu\n", m_cache_name.c_str(),
+ mem_access_type_str((enum mem_access_type)type),
+ cache_request_status_str((enum cache_request_status)status),
+ m_stats[type][status]);
- if(status != RESERVATION_FAIL)
- total_access[type]+= m_stats[type][status];
- }
- }
- for (unsigned type = 0; type < NUM_MEM_ACCESS_TYPE; ++type) {
- if(total_access[type] > 0)
- fprintf(fout, "\t%s[%s][%s] = %u\n",
- m_cache_name.c_str(),
- mem_access_type_str((enum mem_access_type)type),
- "TOTAL_ACCESS",
- total_access[type]);
+ if (status != RESERVATION_FAIL)
+ total_access[type] += m_stats[type][status];
}
+ }
+ for (unsigned type = 0; type < NUM_MEM_ACCESS_TYPE; ++type) {
+ if (total_access[type] > 0)
+ fprintf(fout, "\t%s[%s][%s] = %u\n", m_cache_name.c_str(),
+ mem_access_type_str((enum mem_access_type)type), "TOTAL_ACCESS",
+ total_access[type]);
+ }
}
-void cache_stats::print_fail_stats(FILE *fout, const char *cache_name) const{
- std::string m_cache_name = cache_name;
- for (unsigned type = 0; type < NUM_MEM_ACCESS_TYPE; ++type) {
- for (unsigned fail = 0; fail < NUM_CACHE_RESERVATION_FAIL_STATUS; ++fail) {
- if(m_fail_stats[type][fail] > 0){
- fprintf(fout, "\t%s[%s][%s] = %llu\n",
- m_cache_name.c_str(),
- mem_access_type_str((enum mem_access_type)type),
- cache_fail_status_str((enum cache_reservation_fail_reason)fail),
- m_fail_stats[type][fail]);
- }
- }
- }
+void cache_stats::print_fail_stats(FILE *fout, const char *cache_name) const {
+ std::string m_cache_name = cache_name;
+ for (unsigned type = 0; type < NUM_MEM_ACCESS_TYPE; ++type) {
+ for (unsigned fail = 0; fail < NUM_CACHE_RESERVATION_FAIL_STATUS; ++fail) {
+ if (m_fail_stats[type][fail] > 0) {
+ fprintf(fout, "\t%s[%s][%s] = %llu\n", m_cache_name.c_str(),
+ mem_access_type_str((enum mem_access_type)type),
+ cache_fail_status_str((enum cache_reservation_fail_reason)fail),
+ m_fail_stats[type][fail]);
+ }
+ }
+ }
}
-void cache_sub_stats::print_port_stats(FILE *fout, const char *cache_name) const
-{
- float data_port_util = 0.0f;
- if (port_available_cycles > 0) {
- data_port_util = (float) data_port_busy_cycles / port_available_cycles;
- }
- fprintf(fout, "%s_data_port_util = %.3f\n", cache_name, data_port_util);
- float fill_port_util = 0.0f;
- if (port_available_cycles > 0) {
- fill_port_util = (float) fill_port_busy_cycles / port_available_cycles;
- }
- fprintf(fout, "%s_fill_port_util = %.3f\n", cache_name, fill_port_util);
+void cache_sub_stats::print_port_stats(FILE *fout,
+ const char *cache_name) const {
+ float data_port_util = 0.0f;
+ if (port_available_cycles > 0) {
+ data_port_util = (float)data_port_busy_cycles / port_available_cycles;
+ }
+ fprintf(fout, "%s_data_port_util = %.3f\n", cache_name, data_port_util);
+ float fill_port_util = 0.0f;
+ if (port_available_cycles > 0) {
+ fill_port_util = (float)fill_port_busy_cycles / port_available_cycles;
+ }
+ fprintf(fout, "%s_fill_port_util = %.3f\n", cache_name, fill_port_util);
}
-unsigned long long cache_stats::get_stats(enum mem_access_type *access_type, unsigned num_access_type, enum cache_request_status *access_status, unsigned num_access_status) const{
- ///
- /// Returns a sum of the stats corresponding to each "access_type" and "access_status" pair.
- /// "access_type" is an array of "num_access_type" mem_access_types.
- /// "access_status" is an array of "num_access_status" cache_request_statuses.
- ///
- unsigned long long total=0;
- for(unsigned type =0; type < num_access_type; ++type){
- for(unsigned status=0; status < num_access_status; ++status){
- if(!check_valid((int)access_type[type], (int)access_status[status]))
- assert(0 && "Unknown cache access type or access outcome");
- total += m_stats[access_type[type]][access_status[status]];
- }
+unsigned long long cache_stats::get_stats(
+ enum mem_access_type *access_type, unsigned num_access_type,
+ enum cache_request_status *access_status,
+ unsigned num_access_status) const {
+ ///
+ /// Returns a sum of the stats corresponding to each "access_type" and
+ /// "access_status" pair. "access_type" is an array of "num_access_type"
+ /// mem_access_types. "access_status" is an array of "num_access_status"
+ /// cache_request_statuses.
+ ///
+ unsigned long long total = 0;
+ for (unsigned type = 0; type < num_access_type; ++type) {
+ for (unsigned status = 0; status < num_access_status; ++status) {
+ if (!check_valid((int)access_type[type], (int)access_status[status]))
+ assert(0 && "Unknown cache access type or access outcome");
+ total += m_stats[access_type[type]][access_status[status]];
}
- return total;
+ }
+ return total;
}
-void cache_stats::get_sub_stats(struct cache_sub_stats &css) const{
- ///
- /// Overwrites "css" with the appropriate statistics from this cache.
- ///
- struct cache_sub_stats t_css;
- t_css.clear();
+void cache_stats::get_sub_stats(struct cache_sub_stats &css) const {
+ ///
+ /// Overwrites "css" with the appropriate statistics from this cache.
+ ///
+ struct cache_sub_stats t_css;
+ t_css.clear();
- for (unsigned type = 0; type < NUM_MEM_ACCESS_TYPE; ++type) {
- for (unsigned status = 0; status < NUM_CACHE_REQUEST_STATUS; ++status) {
- if(status == HIT || status == MISS || status == SECTOR_MISS || status == HIT_RESERVED)
- t_css.accesses += m_stats[type][status];
+ for (unsigned type = 0; type < NUM_MEM_ACCESS_TYPE; ++type) {
+ for (unsigned status = 0; status < NUM_CACHE_REQUEST_STATUS; ++status) {
+ if (status == HIT || status == MISS || status == SECTOR_MISS ||
+ status == HIT_RESERVED)
+ t_css.accesses += m_stats[type][status];
- if(status == MISS || status == SECTOR_MISS)
- t_css.misses += m_stats[type][status];
+ if (status == MISS || status == SECTOR_MISS)
+ t_css.misses += m_stats[type][status];
- if(status == HIT_RESERVED)
- t_css.pending_hits += m_stats[type][status];
+ if (status == HIT_RESERVED) t_css.pending_hits += m_stats[type][status];
- if(status == RESERVATION_FAIL)
- t_css.res_fails += m_stats[type][status];
- }
+ if (status == RESERVATION_FAIL) t_css.res_fails += m_stats[type][status];
}
+ }
- t_css.port_available_cycles = m_cache_port_available_cycles;
- t_css.data_port_busy_cycles = m_cache_data_port_busy_cycles;
- t_css.fill_port_busy_cycles = m_cache_fill_port_busy_cycles;
+ t_css.port_available_cycles = m_cache_port_available_cycles;
+ t_css.data_port_busy_cycles = m_cache_data_port_busy_cycles;
+ t_css.fill_port_busy_cycles = m_cache_fill_port_busy_cycles;
- css = t_css;
+ css = t_css;
}
-void cache_stats::get_sub_stats_pw(struct cache_sub_stats_pw &css) const{
- ///
- /// Overwrites "css" with the appropriate statistics from this cache.
- ///
- struct cache_sub_stats_pw t_css;
- t_css.clear();
+void cache_stats::get_sub_stats_pw(struct cache_sub_stats_pw &css) const {
+ ///
+ /// Overwrites "css" with the appropriate statistics from this cache.
+ ///
+ struct cache_sub_stats_pw t_css;
+ t_css.clear();
- for (unsigned type = 0; type < NUM_MEM_ACCESS_TYPE; ++type) {
- for (unsigned status = 0; status < NUM_CACHE_REQUEST_STATUS; ++status) {
- if(status == HIT || status == MISS || status == SECTOR_MISS || status == HIT_RESERVED)
- t_css.accesses += m_stats_pw[type][status];
+ for (unsigned type = 0; type < NUM_MEM_ACCESS_TYPE; ++type) {
+ for (unsigned status = 0; status < NUM_CACHE_REQUEST_STATUS; ++status) {
+ if (status == HIT || status == MISS || status == SECTOR_MISS ||
+ status == HIT_RESERVED)
+ t_css.accesses += m_stats_pw[type][status];
- if(status == HIT){
- if(type == GLOBAL_ACC_R || type == CONST_ACC_R || type == INST_ACC_R){
- t_css.read_hits += m_stats_pw[type][status];
- } else if(type == GLOBAL_ACC_W){
- t_css.write_hits += m_stats_pw[type][status];
- }
- }
+ if (status == HIT) {
+ if (type == GLOBAL_ACC_R || type == CONST_ACC_R || type == INST_ACC_R) {
+ t_css.read_hits += m_stats_pw[type][status];
+ } else if (type == GLOBAL_ACC_W) {
+ t_css.write_hits += m_stats_pw[type][status];
+ }
+ }
- if(status == MISS || status == SECTOR_MISS){
- if(type == GLOBAL_ACC_R || type == CONST_ACC_R || type == INST_ACC_R){
- t_css.read_misses += m_stats_pw[type][status];
- } else if(type == GLOBAL_ACC_W){
- t_css.write_misses += m_stats_pw[type][status];
- }
- }
+ if (status == MISS || status == SECTOR_MISS) {
+ if (type == GLOBAL_ACC_R || type == CONST_ACC_R || type == INST_ACC_R) {
+ t_css.read_misses += m_stats_pw[type][status];
+ } else if (type == GLOBAL_ACC_W) {
+ t_css.write_misses += m_stats_pw[type][status];
+ }
+ }
- if(status == HIT_RESERVED){
- if(type == GLOBAL_ACC_R || type == CONST_ACC_R || type == INST_ACC_R){
- t_css.read_pending_hits += m_stats_pw[type][status];
- } else if(type == GLOBAL_ACC_W){
- t_css.write_pending_hits += m_stats_pw[type][status];
- }
- }
+ if (status == HIT_RESERVED) {
+ if (type == GLOBAL_ACC_R || type == CONST_ACC_R || type == INST_ACC_R) {
+ t_css.read_pending_hits += m_stats_pw[type][status];
+ } else if (type == GLOBAL_ACC_W) {
+ t_css.write_pending_hits += m_stats_pw[type][status];
+ }
+ }
- if(status == RESERVATION_FAIL){
- if(type == GLOBAL_ACC_R || type == CONST_ACC_R || type == INST_ACC_R){
- t_css.read_res_fails += m_stats_pw[type][status];
- } else if(type == GLOBAL_ACC_W){
- t_css.write_res_fails += m_stats_pw[type][status];
- }
- }
+ if (status == RESERVATION_FAIL) {
+ if (type == GLOBAL_ACC_R || type == CONST_ACC_R || type == INST_ACC_R) {
+ t_css.read_res_fails += m_stats_pw[type][status];
+ } else if (type == GLOBAL_ACC_W) {
+ t_css.write_res_fails += m_stats_pw[type][status];
}
+ }
}
+ }
- css = t_css;
+ css = t_css;
}
-bool cache_stats::check_valid(int type, int status) const{
- ///
- /// Verify a valid access_type/access_status
- ///
- if((type >= 0) && (type < NUM_MEM_ACCESS_TYPE) && (status >= 0) && (status < NUM_CACHE_REQUEST_STATUS))
- return true;
- else
- return false;
+bool cache_stats::check_valid(int type, int status) const {
+ ///
+ /// Verify a valid access_type/access_status
+ ///
+ if ((type >= 0) && (type < NUM_MEM_ACCESS_TYPE) && (status >= 0) &&
+ (status < NUM_CACHE_REQUEST_STATUS))
+ return true;
+ else
+ return false;
}
-bool cache_stats::check_fail_valid(int type, int fail) const{
- ///
- /// Verify a valid access_type/access_status
- ///
- if((type >= 0) && (type < NUM_MEM_ACCESS_TYPE) && (fail >= 0) && (fail < NUM_CACHE_RESERVATION_FAIL_STATUS))
- return true;
- else
- return false;
+bool cache_stats::check_fail_valid(int type, int fail) const {
+ ///
+ /// Verify a valid access_type/access_status
+ ///
+ if ((type >= 0) && (type < NUM_MEM_ACCESS_TYPE) && (fail >= 0) &&
+ (fail < NUM_CACHE_RESERVATION_FAIL_STATUS))
+ return true;
+ else
+ return false;
}
-void cache_stats::sample_cache_port_utility(bool data_port_busy, bool fill_port_busy)
-{
- m_cache_port_available_cycles += 1;
- if (data_port_busy) {
- m_cache_data_port_busy_cycles += 1;
- }
- if (fill_port_busy) {
- m_cache_fill_port_busy_cycles += 1;
- }
+void cache_stats::sample_cache_port_utility(bool data_port_busy,
+ bool fill_port_busy) {
+ m_cache_port_available_cycles += 1;
+ if (data_port_busy) {
+ m_cache_data_port_busy_cycles += 1;
+ }
+ if (fill_port_busy) {
+ m_cache_fill_port_busy_cycles += 1;
+ }
}
-baseline_cache::bandwidth_management::bandwidth_management(cache_config &config)
-: m_config(config)
-{
- m_data_port_occupied_cycles = 0;
- m_fill_port_occupied_cycles = 0;
+baseline_cache::bandwidth_management::bandwidth_management(cache_config &config)
+ : m_config(config) {
+ m_data_port_occupied_cycles = 0;
+ m_fill_port_occupied_cycles = 0;
}
-/// use the data port based on the outcome and events generated by the mem_fetch request
-void baseline_cache::bandwidth_management::use_data_port(mem_fetch *mf, enum cache_request_status outcome, const std::list<cache_event> &events)
-{
- unsigned data_size = mf->get_data_size();
- unsigned port_width = m_config.m_data_port_width;
- switch (outcome) {
+/// use the data port based on the outcome and events generated by the mem_fetch
+/// request
+void baseline_cache::bandwidth_management::use_data_port(
+ mem_fetch *mf, enum cache_request_status outcome,
+ const std::list<cache_event> &events) {
+ unsigned data_size = mf->get_data_size();
+ unsigned port_width = m_config.m_data_port_width;
+ switch (outcome) {
case HIT: {
- unsigned data_cycles = data_size / port_width + ((data_size % port_width > 0)? 1 : 0);
- m_data_port_occupied_cycles += data_cycles;
- } break;
+ unsigned data_cycles =
+ data_size / port_width + ((data_size % port_width > 0) ? 1 : 0);
+ m_data_port_occupied_cycles += data_cycles;
+ } break;
case HIT_RESERVED:
case MISS: {
- // the data array is accessed to read out the entire line for write-back
- // in case of sector cache we need to write bank only the modified sectors
- cache_event ev(WRITE_BACK_REQUEST_SENT);
- if (was_writeback_sent(events, ev)) {
- unsigned data_cycles = ev.m_evicted_block.m_modified_size / port_width;
- m_data_port_occupied_cycles += data_cycles;
- }
- } break;
+ // the data array is accessed to read out the entire line for write-back
+ // in case of sector cache we need to write bank only the modified sectors
+ cache_event ev(WRITE_BACK_REQUEST_SENT);
+ if (was_writeback_sent(events, ev)) {
+ unsigned data_cycles = ev.m_evicted_block.m_modified_size / port_width;
+ m_data_port_occupied_cycles += data_cycles;
+ }
+ } break;
case SECTOR_MISS:
case RESERVATION_FAIL:
- // Does not consume any port bandwidth
- break;
- default:
- assert(0);
- break;
- }
+ // Does not consume any port bandwidth
+ break;
+ default:
+ assert(0);
+ break;
+ }
}
-/// use the fill port
-void baseline_cache::bandwidth_management::use_fill_port(mem_fetch *mf)
-{
- // assume filling the entire line with the returned request
- unsigned fill_cycles = m_config.get_atom_sz() / m_config.m_data_port_width;
- m_fill_port_occupied_cycles += fill_cycles;
+/// use the fill port
+void baseline_cache::bandwidth_management::use_fill_port(mem_fetch *mf) {
+ // assume filling the entire line with the returned request
+ unsigned fill_cycles = m_config.get_atom_sz() / m_config.m_data_port_width;
+ m_fill_port_occupied_cycles += fill_cycles;
}
-/// called every cache cycle to free up the ports
-void baseline_cache::bandwidth_management::replenish_port_bandwidth()
-{
- if (m_data_port_occupied_cycles > 0) {
- m_data_port_occupied_cycles -= 1;
- }
- assert(m_data_port_occupied_cycles >= 0);
+/// called every cache cycle to free up the ports
+void baseline_cache::bandwidth_management::replenish_port_bandwidth() {
+ if (m_data_port_occupied_cycles > 0) {
+ m_data_port_occupied_cycles -= 1;
+ }
+ assert(m_data_port_occupied_cycles >= 0);
- if (m_fill_port_occupied_cycles > 0) {
- m_fill_port_occupied_cycles -= 1;
- }
- assert(m_fill_port_occupied_cycles >= 0);
+ if (m_fill_port_occupied_cycles > 0) {
+ m_fill_port_occupied_cycles -= 1;
+ }
+ assert(m_fill_port_occupied_cycles >= 0);
}
-/// query for data port availability
-bool baseline_cache::bandwidth_management::data_port_free() const
-{
- return (m_data_port_occupied_cycles == 0);
+/// query for data port availability
+bool baseline_cache::bandwidth_management::data_port_free() const {
+ return (m_data_port_occupied_cycles == 0);
}
-/// query for fill port availability
-bool baseline_cache::bandwidth_management::fill_port_free() const
-{
- return (m_fill_port_occupied_cycles == 0);
+/// query for fill port availability
+bool baseline_cache::bandwidth_management::fill_port_free() const {
+ return (m_fill_port_occupied_cycles == 0);
}
/// Sends next request to lower level of memory
-void baseline_cache::cycle(){
- if ( !m_miss_queue.empty() ) {
- mem_fetch *mf = m_miss_queue.front();
- if ( !m_memport->full(mf->size(),mf->get_is_write()) ) {
- m_miss_queue.pop_front();
- m_memport->push(mf);
- }
+void baseline_cache::cycle() {
+ if (!m_miss_queue.empty()) {
+ mem_fetch *mf = m_miss_queue.front();
+ if (!m_memport->full(mf->size(), mf->get_is_write())) {
+ m_miss_queue.pop_front();
+ m_memport->push(mf);
}
- bool data_port_busy = !m_bandwidth_management.data_port_free();
- bool fill_port_busy = !m_bandwidth_management.fill_port_free();
- m_stats.sample_cache_port_utility(data_port_busy, fill_port_busy);
- m_bandwidth_management.replenish_port_bandwidth();
+ }
+ bool data_port_busy = !m_bandwidth_management.data_port_free();
+ bool fill_port_busy = !m_bandwidth_management.fill_port_free();
+ m_stats.sample_cache_port_utility(data_port_busy, fill_port_busy);
+ m_bandwidth_management.replenish_port_bandwidth();
}
-/// Interface for response from lower memory level (model bandwidth restictions in caller)
-void baseline_cache::fill(mem_fetch *mf, unsigned time){
-
- if(m_config.m_mshr_type == SECTOR_ASSOC) {
- assert(mf->get_original_mf());
- extra_mf_fields_lookup::iterator e = m_extra_mf_fields.find(mf->get_original_mf());
- assert( e != m_extra_mf_fields.end() );
+/// Interface for response from lower memory level (model bandwidth restictions
+/// in caller)
+void baseline_cache::fill(mem_fetch *mf, unsigned time) {
+ if (m_config.m_mshr_type == SECTOR_ASSOC) {
+ assert(mf->get_original_mf());
+ extra_mf_fields_lookup::iterator e =
+ m_extra_mf_fields.find(mf->get_original_mf());
+ assert(e != m_extra_mf_fields.end());
e->second.pending_read--;
- if(e->second.pending_read > 0) {
- //wait for the other requests to come back
- delete mf;
- return;
- } else {
- mem_fetch *temp = mf;
- mf = mf->get_original_mf();
- delete temp;
- }
- }
-
- extra_mf_fields_lookup::iterator e = m_extra_mf_fields.find(mf);
- assert( e != m_extra_mf_fields.end() );
- assert( e->second.m_valid );
- mf->set_data_size( e->second.m_data_size );
- mf->set_addr( e->second.m_addr );
- if ( m_config.m_alloc_policy == ON_MISS )
- m_tag_array->fill(e->second.m_cache_index,time,mf);
- else if ( m_config.m_alloc_policy == ON_FILL ) {
- m_tag_array->fill(e->second.m_block_addr,time,mf);
- if(m_config.is_streaming())
- m_tag_array->remove_pending_line(mf);
- }
- else abort();
- bool has_atomic = false;
- m_mshrs.mark_ready(e->second.m_block_addr, has_atomic);
- if (has_atomic) {
- assert(m_config.m_alloc_policy == ON_MISS);
- cache_block_t* block = m_tag_array->get_block(e->second.m_cache_index);
- block->set_status(MODIFIED, mf->get_access_sector_mask()); // mark line as dirty for atomic operation
+ if (e->second.pending_read > 0) {
+ // wait for the other requests to come back
+ delete mf;
+ return;
+ } else {
+ mem_fetch *temp = mf;
+ mf = mf->get_original_mf();
+ delete temp;
}
- m_extra_mf_fields.erase(mf);
- m_bandwidth_management.use_fill_port(mf);
+ }
+
+ extra_mf_fields_lookup::iterator e = m_extra_mf_fields.find(mf);
+ assert(e != m_extra_mf_fields.end());
+ assert(e->second.m_valid);
+ mf->set_data_size(e->second.m_data_size);
+ mf->set_addr(e->second.m_addr);
+ if (m_config.m_alloc_policy == ON_MISS)
+ m_tag_array->fill(e->second.m_cache_index, time, mf);
+ else if (m_config.m_alloc_policy == ON_FILL) {
+ m_tag_array->fill(e->second.m_block_addr, time, mf);
+ if (m_config.is_streaming()) m_tag_array->remove_pending_line(mf);
+ } else
+ abort();
+ bool has_atomic = false;
+ m_mshrs.mark_ready(e->second.m_block_addr, has_atomic);
+ if (has_atomic) {
+ assert(m_config.m_alloc_policy == ON_MISS);
+ cache_block_t *block = m_tag_array->get_block(e->second.m_cache_index);
+ block->set_status(MODIFIED,
+ mf->get_access_sector_mask()); // mark line as dirty for
+ // atomic operation
+ }
+ m_extra_mf_fields.erase(mf);
+ m_bandwidth_management.use_fill_port(mf);
}
/// Checks if mf is waiting to be filled by lower memory level
-bool baseline_cache::waiting_for_fill( mem_fetch *mf ){
- extra_mf_fields_lookup::iterator e = m_extra_mf_fields.find(mf);
- return e != m_extra_mf_fields.end();
+bool baseline_cache::waiting_for_fill(mem_fetch *mf) {
+ extra_mf_fields_lookup::iterator e = m_extra_mf_fields.find(mf);
+ return e != m_extra_mf_fields.end();
}
-void baseline_cache::print(FILE *fp, unsigned &accesses, unsigned &misses) const{
- fprintf( fp, "Cache %s:\t", m_name.c_str() );
- m_tag_array->print(fp,accesses,misses);
+void baseline_cache::print(FILE *fp, unsigned &accesses,
+ unsigned &misses) const {
+ fprintf(fp, "Cache %s:\t", m_name.c_str());
+ m_tag_array->print(fp, accesses, misses);
}
-void baseline_cache::display_state( FILE *fp ) const{
- fprintf(fp,"Cache %s:\n", m_name.c_str() );
- m_mshrs.display(fp);
- fprintf(fp,"\n");
+void baseline_cache::display_state(FILE *fp) const {
+ fprintf(fp, "Cache %s:\n", m_name.c_str());
+ m_mshrs.display(fp);
+ fprintf(fp, "\n");
}
/// Read miss handler without writeback
-void baseline_cache::send_read_request(new_addr_type addr, new_addr_type block_addr, unsigned cache_index, mem_fetch *mf,
- unsigned time, bool &do_miss, std::list<cache_event> &events, bool read_only, bool wa){
-
- bool wb=false;
- evicted_block_info e;
- send_read_request(addr, block_addr, cache_index, mf, time, do_miss, wb, e, events, read_only, wa);
+void baseline_cache::send_read_request(new_addr_type addr,
+ new_addr_type block_addr,
+ unsigned cache_index, mem_fetch *mf,
+ unsigned time, bool &do_miss,
+ std::list<cache_event> &events,
+ bool read_only, bool wa) {
+ bool wb = false;
+ evicted_block_info e;
+ send_read_request(addr, block_addr, cache_index, mf, time, do_miss, wb, e,
+ events, read_only, wa);
}
/// Read miss handler. Check MSHR hit or MSHR available
-void baseline_cache::send_read_request(new_addr_type addr, new_addr_type block_addr, unsigned cache_index, mem_fetch *mf,
- unsigned time, bool &do_miss, bool &wb, evicted_block_info &evicted, std::list<cache_event> &events, bool read_only, bool wa){
-
- new_addr_type mshr_addr = m_config.mshr_addr(mf->get_addr());
- bool mshr_hit = m_mshrs.probe(mshr_addr);
- bool mshr_avail = !m_mshrs.full(mshr_addr);
- if ( mshr_hit && mshr_avail ) {
- if(read_only)
- m_tag_array->access(block_addr,time,cache_index,mf);
- else
- m_tag_array->access(block_addr,time,cache_index,wb,evicted,mf);
-
- m_mshrs.add(mshr_addr,mf);
- do_miss = true;
+void baseline_cache::send_read_request(new_addr_type addr,
+ new_addr_type block_addr,
+ unsigned cache_index, mem_fetch *mf,
+ unsigned time, bool &do_miss, bool &wb,
+ evicted_block_info &evicted,
+ std::list<cache_event> &events,
+ bool read_only, bool wa) {
+ new_addr_type mshr_addr = m_config.mshr_addr(mf->get_addr());
+ bool mshr_hit = m_mshrs.probe(mshr_addr);
+ bool mshr_avail = !m_mshrs.full(mshr_addr);
+ if (mshr_hit && mshr_avail) {
+ if (read_only)
+ m_tag_array->access(block_addr, time, cache_index, mf);
+ else
+ m_tag_array->access(block_addr, time, cache_index, wb, evicted, mf);
- } else if ( !mshr_hit && mshr_avail && (m_miss_queue.size() < m_config.m_miss_queue_size) ) {
- if(read_only)
- m_tag_array->access(block_addr,time,cache_index,mf);
- else
- m_tag_array->access(block_addr,time,cache_index,wb,evicted,mf);
+ m_mshrs.add(mshr_addr, mf);
+ do_miss = true;
- m_mshrs.add(mshr_addr,mf);
- if(m_config.is_streaming() && m_config.m_cache_type == SECTOR){
- m_tag_array->add_pending_line(mf);
- }
- m_extra_mf_fields[mf] = extra_mf_fields(mshr_addr,mf->get_addr(),cache_index, mf->get_data_size(), m_config);
- mf->set_data_size( m_config.get_atom_sz() );
- mf->set_addr( mshr_addr );
- m_miss_queue.push_back(mf);
- mf->set_status(m_miss_queue_status,time);
- if(!wa)
- events.push_back(cache_event(READ_REQUEST_SENT));
+ } else if (!mshr_hit && mshr_avail &&
+ (m_miss_queue.size() < m_config.m_miss_queue_size)) {
+ if (read_only)
+ m_tag_array->access(block_addr, time, cache_index, mf);
+ else
+ m_tag_array->access(block_addr, time, cache_index, wb, evicted, mf);
- do_miss = true;
+ m_mshrs.add(mshr_addr, mf);
+ if (m_config.is_streaming() && m_config.m_cache_type == SECTOR) {
+ m_tag_array->add_pending_line(mf);
}
- else if(mshr_hit && !mshr_avail)
- m_stats.inc_fail_stats(mf->get_access_type(), MSHR_MERGE_ENRTY_FAIL);
- else if (!mshr_hit && !mshr_avail)
- m_stats.inc_fail_stats(mf->get_access_type(), MSHR_ENRTY_FAIL);
- else
- assert(0);
-}
+ m_extra_mf_fields[mf] = extra_mf_fields(
+ mshr_addr, mf->get_addr(), cache_index, mf->get_data_size(), m_config);
+ mf->set_data_size(m_config.get_atom_sz());
+ mf->set_addr(mshr_addr);
+ m_miss_queue.push_back(mf);
+ mf->set_status(m_miss_queue_status, time);
+ if (!wa) events.push_back(cache_event(READ_REQUEST_SENT));
+ do_miss = true;
+ } else if (mshr_hit && !mshr_avail)
+ m_stats.inc_fail_stats(mf->get_access_type(), MSHR_MERGE_ENRTY_FAIL);
+ else if (!mshr_hit && !mshr_avail)
+ m_stats.inc_fail_stats(mf->get_access_type(), MSHR_ENRTY_FAIL);
+ else
+ assert(0);
+}
/// Sends write request to lower level memory (write or writeback)
-void data_cache::send_write_request(mem_fetch *mf, cache_event request, unsigned time, std::list<cache_event> &events){
-
- events.push_back(request);
- m_miss_queue.push_back(mf);
- mf->set_status(m_miss_queue_status,time);
+void data_cache::send_write_request(mem_fetch *mf, cache_event request,
+ unsigned time,
+ std::list<cache_event> &events) {
+ events.push_back(request);
+ m_miss_queue.push_back(mf);
+ mf->set_status(m_miss_queue_status, time);
}
-
/****** Write-hit functions (Set by config file) ******/
/// Write-back hit: Mark block as modified
-cache_request_status data_cache::wr_hit_wb(new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time, std::list<cache_event> &events, enum cache_request_status status ){
- new_addr_type block_addr = m_config.block_addr(addr);
- m_tag_array->access(block_addr,time,cache_index,mf); // update LRU state
- cache_block_t* block = m_tag_array->get_block(cache_index);
- block->set_status(MODIFIED, mf->get_access_sector_mask());
+cache_request_status data_cache::wr_hit_wb(new_addr_type addr,
+ unsigned cache_index, mem_fetch *mf,
+ unsigned time,
+ std::list<cache_event> &events,
+ enum cache_request_status status) {
+ new_addr_type block_addr = m_config.block_addr(addr);
+ m_tag_array->access(block_addr, time, cache_index, mf); // update LRU state
+ cache_block_t *block = m_tag_array->get_block(cache_index);
+ block->set_status(MODIFIED, mf->get_access_sector_mask());
- return HIT;
+ return HIT;
}
/// Write-through hit: Directly send request to lower level memory
-cache_request_status data_cache::wr_hit_wt(new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time, std::list<cache_event> &events, enum cache_request_status status ){
- if(miss_queue_full(0)) {
- m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
- return RESERVATION_FAIL; // cannot handle request this cycle
- }
+cache_request_status data_cache::wr_hit_wt(new_addr_type addr,
+ unsigned cache_index, mem_fetch *mf,
+ unsigned time,
+ std::list<cache_event> &events,
+ enum cache_request_status status) {
+ if (miss_queue_full(0)) {
+ m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
+ return RESERVATION_FAIL; // cannot handle request this cycle
+ }
- new_addr_type block_addr = m_config.block_addr(addr);
- m_tag_array->access(block_addr,time,cache_index,mf); // update LRU state
- cache_block_t* block = m_tag_array->get_block(cache_index);
- block->set_status(MODIFIED, mf->get_access_sector_mask());
+ new_addr_type block_addr = m_config.block_addr(addr);
+ m_tag_array->access(block_addr, time, cache_index, mf); // update LRU state
+ cache_block_t *block = m_tag_array->get_block(cache_index);
+ block->set_status(MODIFIED, mf->get_access_sector_mask());
- // generate a write-through
- send_write_request(mf, cache_event(WRITE_REQUEST_SENT), time, events);
+ // generate a write-through
+ send_write_request(mf, cache_event(WRITE_REQUEST_SENT), time, events);
- return HIT;
+ return HIT;
}
-/// Write-evict hit: Send request to lower level memory and invalidate corresponding block
-cache_request_status data_cache::wr_hit_we(new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time, std::list<cache_event> &events, enum cache_request_status status ){
- if(miss_queue_full(0)) {
- m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
- return RESERVATION_FAIL; // cannot handle request this cycle
- }
+/// Write-evict hit: Send request to lower level memory and invalidate
+/// corresponding block
+cache_request_status data_cache::wr_hit_we(new_addr_type addr,
+ unsigned cache_index, mem_fetch *mf,
+ unsigned time,
+ std::list<cache_event> &events,
+ enum cache_request_status status) {
+ if (miss_queue_full(0)) {
+ m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
+ return RESERVATION_FAIL; // cannot handle request this cycle
+ }
- // generate a write-through/evict
- cache_block_t* block = m_tag_array->get_block(cache_index);
- send_write_request(mf, cache_event(WRITE_REQUEST_SENT), time, events);
+ // generate a write-through/evict
+ cache_block_t *block = m_tag_array->get_block(cache_index);
+ send_write_request(mf, cache_event(WRITE_REQUEST_SENT), time, events);
- // Invalidate block
- block->set_status(INVALID, mf->get_access_sector_mask());
+ // Invalidate block
+ block->set_status(INVALID, mf->get_access_sector_mask());
- return HIT;
+ return HIT;
}
/// Global write-evict, local write-back: Useful for private caches
-enum cache_request_status data_cache::wr_hit_global_we_local_wb(new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time, std::list<cache_event> &events, enum cache_request_status status ){
- bool evict = (mf->get_access_type() == GLOBAL_ACC_W); // evict a line that hits on global memory write
- if(evict)
- return wr_hit_we(addr, cache_index, mf, time, events, status); // Write-evict
- else
- return wr_hit_wb(addr, cache_index, mf, time, events, status); // Write-back
+enum cache_request_status data_cache::wr_hit_global_we_local_wb(
+ new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time,
+ std::list<cache_event> &events, enum cache_request_status status) {
+ bool evict = (mf->get_access_type() ==
+ GLOBAL_ACC_W); // evict a line that hits on global memory write
+ if (evict)
+ return wr_hit_we(addr, cache_index, mf, time, events,
+ status); // Write-evict
+ else
+ return wr_hit_wb(addr, cache_index, mf, time, events,
+ status); // Write-back
}
/****** Write-miss functions (Set by config file) ******/
/// Write-allocate miss: Send write request to lower level memory
// and send a read request for the same block
-enum cache_request_status
-data_cache::wr_miss_wa_naive( new_addr_type addr,
- unsigned cache_index, mem_fetch *mf,
- unsigned time, std::list<cache_event> &events,
- enum cache_request_status status )
-{
- new_addr_type block_addr = m_config.block_addr(addr);
- new_addr_type mshr_addr = m_config.mshr_addr(mf->get_addr());
+enum cache_request_status data_cache::wr_miss_wa_naive(
+ new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time,
+ std::list<cache_event> &events, enum cache_request_status status) {
+ new_addr_type block_addr = m_config.block_addr(addr);
+ new_addr_type mshr_addr = m_config.mshr_addr(mf->get_addr());
- // Write allocate, maximum 3 requests (write miss, read request, write back request)
- // Conservatively ensure the worst-case request can be handled this cycle
- bool mshr_hit = m_mshrs.probe(mshr_addr);
- bool mshr_avail = !m_mshrs.full(mshr_addr);
- if(miss_queue_full(2)
- || (!(mshr_hit && mshr_avail)
- && !(!mshr_hit && mshr_avail && (m_miss_queue.size() < m_config.m_miss_queue_size)))) {
- //check what is the exactly the failure reason
- if(miss_queue_full(2) )
- m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
- else if(mshr_hit && !mshr_avail)
- m_stats.inc_fail_stats(mf->get_access_type(), MSHR_MERGE_ENRTY_FAIL);
- else if (!mshr_hit && !mshr_avail)
- m_stats.inc_fail_stats(mf->get_access_type(), MSHR_ENRTY_FAIL);
- else
- assert(0);
+ // Write allocate, maximum 3 requests (write miss, read request, write back
+ // request) Conservatively ensure the worst-case request can be handled this
+ // cycle
+ bool mshr_hit = m_mshrs.probe(mshr_addr);
+ bool mshr_avail = !m_mshrs.full(mshr_addr);
+ if (miss_queue_full(2) ||
+ (!(mshr_hit && mshr_avail) &&
+ !(!mshr_hit && mshr_avail &&
+ (m_miss_queue.size() < m_config.m_miss_queue_size)))) {
+ // check what is the exactly the failure reason
+ if (miss_queue_full(2))
+ m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
+ else if (mshr_hit && !mshr_avail)
+ m_stats.inc_fail_stats(mf->get_access_type(), MSHR_MERGE_ENRTY_FAIL);
+ else if (!mshr_hit && !mshr_avail)
+ m_stats.inc_fail_stats(mf->get_access_type(), MSHR_ENRTY_FAIL);
+ else
+ assert(0);
- return RESERVATION_FAIL;
- }
+ return RESERVATION_FAIL;
+ }
- send_write_request(mf, cache_event(WRITE_REQUEST_SENT), time, events);
- // Tries to send write allocate request, returns true on success and false on failure
- //if(!send_write_allocate(mf, addr, block_addr, cache_index, time, events))
- // return RESERVATION_FAIL;
+ send_write_request(mf, cache_event(WRITE_REQUEST_SENT), time, events);
+ // Tries to send write allocate request, returns true on success and false on
+ // failure
+ // if(!send_write_allocate(mf, addr, block_addr, cache_index, time, events))
+ // return RESERVATION_FAIL;
- const mem_access_t *ma = new mem_access_t( m_wr_alloc_type,
- mf->get_addr(),
- m_config.get_atom_sz(),
- false, // Now performing a read
- mf->get_access_warp_mask(),
- mf->get_access_byte_mask(),
- mf->get_access_sector_mask(),
- m_gpu->gpgpu_ctx);
+ const mem_access_t *ma =
+ new mem_access_t(m_wr_alloc_type, mf->get_addr(), m_config.get_atom_sz(),
+ false, // Now performing a read
+ mf->get_access_warp_mask(), mf->get_access_byte_mask(),
+ mf->get_access_sector_mask(), m_gpu->gpgpu_ctx);
- mem_fetch *n_mf = new mem_fetch( *ma,
- NULL,
- mf->get_ctrl_size(),
- mf->get_wid(),
- mf->get_sid(),
- mf->get_tpc(),
- mf->get_mem_config(),
- m_gpu->gpu_tot_sim_cycle+m_gpu->gpu_sim_cycle);
+ mem_fetch *n_mf =
+ new mem_fetch(*ma, NULL, mf->get_ctrl_size(), mf->get_wid(),
+ mf->get_sid(), mf->get_tpc(), mf->get_mem_config(),
+ m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle);
- bool do_miss = false;
- bool wb = false;
- evicted_block_info evicted;
+ bool do_miss = false;
+ bool wb = false;
+ evicted_block_info evicted;
- // Send read request resulting from write miss
- send_read_request(addr, block_addr, cache_index, n_mf, time, do_miss, wb,
- evicted, events, false, true);
+ // Send read request resulting from write miss
+ send_read_request(addr, block_addr, cache_index, n_mf, time, do_miss, wb,
+ evicted, events, false, true);
- events.push_back(cache_event(WRITE_ALLOCATE_SENT));
+ events.push_back(cache_event(WRITE_ALLOCATE_SENT));
- if( do_miss ){
- // If evicted block is modified and not a write-through
- // (already modified lower level)
- if( wb && (m_config.m_write_policy != WRITE_THROUGH) ) {
- assert(status == MISS); //SECTOR_MISS and HIT_RESERVED should not send write back
- mem_fetch *wb = m_memfetch_creator->alloc(evicted.m_block_addr,
- m_wrbk_type,evicted.m_modified_size,true,m_gpu->gpu_tot_sim_cycle+m_gpu->gpu_sim_cycle);
- send_write_request(wb, cache_event(WRITE_BACK_REQUEST_SENT, evicted), time, events);
- }
- return MISS;
+ if (do_miss) {
+ // If evicted block is modified and not a write-through
+ // (already modified lower level)
+ if (wb && (m_config.m_write_policy != WRITE_THROUGH)) {
+ assert(status ==
+ MISS); // SECTOR_MISS and HIT_RESERVED should not send write back
+ mem_fetch *wb = m_memfetch_creator->alloc(
+ evicted.m_block_addr, m_wrbk_type, evicted.m_modified_size, true,
+ m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle);
+ send_write_request(wb, cache_event(WRITE_BACK_REQUEST_SENT, evicted),
+ time, events);
}
+ return MISS;
+ }
- return RESERVATION_FAIL;
+ return RESERVATION_FAIL;
}
+enum cache_request_status data_cache::wr_miss_wa_fetch_on_write(
+ new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time,
+ std::list<cache_event> &events, enum cache_request_status status) {
+ new_addr_type block_addr = m_config.block_addr(addr);
+ new_addr_type mshr_addr = m_config.mshr_addr(mf->get_addr());
-enum cache_request_status
-data_cache::wr_miss_wa_fetch_on_write( new_addr_type addr,
- unsigned cache_index, mem_fetch *mf,
- unsigned time, std::list<cache_event> &events,
- enum cache_request_status status )
-{
- new_addr_type block_addr = m_config.block_addr(addr);
- new_addr_type mshr_addr = m_config.mshr_addr(mf->get_addr());
-
- if(mf->get_access_byte_mask().count() == m_config.get_atom_sz())
- {
- //if the request writes to the whole cache line/sector, then, write and set cache line Modified.
- //and no need to send read request to memory or reserve mshr
-
- if(miss_queue_full(0)) {
- m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
- return RESERVATION_FAIL; // cannot handle request this cycle
- }
-
- bool wb = false;
- evicted_block_info evicted;
+ if (mf->get_access_byte_mask().count() == m_config.get_atom_sz()) {
+ // if the request writes to the whole cache line/sector, then, write and set
+ // cache line Modified. and no need to send read request to memory or
+ // reserve mshr
- cache_request_status status = m_tag_array->access(block_addr,time,cache_index,wb,evicted,mf);
- assert(status != HIT);
- cache_block_t* block = m_tag_array->get_block(cache_index);
- block->set_status(MODIFIED, mf->get_access_sector_mask());
- if(status == HIT_RESERVED)
- block->set_ignore_on_fill(true, mf->get_access_sector_mask());
+ if (miss_queue_full(0)) {
+ m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
+ return RESERVATION_FAIL; // cannot handle request this cycle
+ }
- if( status != RESERVATION_FAIL ){
- // If evicted block is modified and not a write-through
- // (already modified lower level)
- if( wb && (m_config.m_write_policy != WRITE_THROUGH) ) {
- mem_fetch *wb = m_memfetch_creator->alloc(evicted.m_block_addr,
- m_wrbk_type,evicted.m_modified_size,true,m_gpu->gpu_tot_sim_cycle+m_gpu->gpu_sim_cycle);
- send_write_request(wb, cache_event(WRITE_BACK_REQUEST_SENT, evicted), time, events);
- }
- return MISS;
- }
- return RESERVATION_FAIL;
- }
- else
- {
- bool mshr_hit = m_mshrs.probe(mshr_addr);
- bool mshr_avail = !m_mshrs.full(mshr_addr);
- if(miss_queue_full(1)
- || (!(mshr_hit && mshr_avail)
- && !(!mshr_hit && mshr_avail && (m_miss_queue.size() < m_config.m_miss_queue_size)))) {
- //check what is the exactly the failure reason
- if(miss_queue_full(1) )
- m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
- else if(mshr_hit && !mshr_avail)
- m_stats.inc_fail_stats(mf->get_access_type(), MSHR_MERGE_ENRTY_FAIL);
- else if (!mshr_hit && !mshr_avail)
- m_stats.inc_fail_stats(mf->get_access_type(), MSHR_ENRTY_FAIL);
- else
- assert(0);
+ bool wb = false;
+ evicted_block_info evicted;
- return RESERVATION_FAIL;
- }
+ cache_request_status status =
+ m_tag_array->access(block_addr, time, cache_index, wb, evicted, mf);
+ assert(status != HIT);
+ cache_block_t *block = m_tag_array->get_block(cache_index);
+ block->set_status(MODIFIED, mf->get_access_sector_mask());
+ if (status == HIT_RESERVED)
+ block->set_ignore_on_fill(true, mf->get_access_sector_mask());
+ if (status != RESERVATION_FAIL) {
+ // If evicted block is modified and not a write-through
+ // (already modified lower level)
+ if (wb && (m_config.m_write_policy != WRITE_THROUGH)) {
+ mem_fetch *wb = m_memfetch_creator->alloc(
+ evicted.m_block_addr, m_wrbk_type, evicted.m_modified_size, true,
+ m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle);
+ send_write_request(wb, cache_event(WRITE_BACK_REQUEST_SENT, evicted),
+ time, events);
+ }
+ return MISS;
+ }
+ return RESERVATION_FAIL;
+ } else {
+ bool mshr_hit = m_mshrs.probe(mshr_addr);
+ bool mshr_avail = !m_mshrs.full(mshr_addr);
+ if (miss_queue_full(1) ||
+ (!(mshr_hit && mshr_avail) &&
+ !(!mshr_hit && mshr_avail &&
+ (m_miss_queue.size() < m_config.m_miss_queue_size)))) {
+ // check what is the exactly the failure reason
+ if (miss_queue_full(1))
+ m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
+ else if (mshr_hit && !mshr_avail)
+ m_stats.inc_fail_stats(mf->get_access_type(), MSHR_MERGE_ENRTY_FAIL);
+ else if (!mshr_hit && !mshr_avail)
+ m_stats.inc_fail_stats(mf->get_access_type(), MSHR_ENRTY_FAIL);
+ else
+ assert(0);
- //prevent Write - Read - Write in pending mshr
- //allowing another write will override the value of the first write, and the pending read request will read incorrect result from the second write
- if(m_mshrs.probe(mshr_addr) && m_mshrs.is_read_after_write_pending(mshr_addr) && mf->is_write())
- {
- //assert(0);
- m_stats.inc_fail_stats(mf->get_access_type(), MSHR_RW_PENDING);
- return RESERVATION_FAIL;
- }
+ return RESERVATION_FAIL;
+ }
- const mem_access_t *ma = new mem_access_t( m_wr_alloc_type,
- mf->get_addr(),
- m_config.get_atom_sz(),
- false, // Now performing a read
- mf->get_access_warp_mask(),
- mf->get_access_byte_mask(),
- mf->get_access_sector_mask(),
- m_gpu->gpgpu_ctx);
+ // prevent Write - Read - Write in pending mshr
+ // allowing another write will override the value of the first write, and
+ // the pending read request will read incorrect result from the second write
+ if (m_mshrs.probe(mshr_addr) &&
+ m_mshrs.is_read_after_write_pending(mshr_addr) && mf->is_write()) {
+ // assert(0);
+ m_stats.inc_fail_stats(mf->get_access_type(), MSHR_RW_PENDING);
+ return RESERVATION_FAIL;
+ }
- mem_fetch *n_mf = new mem_fetch( *ma,
- NULL,
- mf->get_ctrl_size(),
- mf->get_wid(),
- mf->get_sid(),
- mf->get_tpc(),
- mf->get_mem_config(),
- m_gpu->gpu_tot_sim_cycle+m_gpu->gpu_sim_cycle,
- NULL,
- mf);
+ const mem_access_t *ma = new mem_access_t(
+ m_wr_alloc_type, mf->get_addr(), m_config.get_atom_sz(),
+ false, // Now performing a read
+ mf->get_access_warp_mask(), mf->get_access_byte_mask(),
+ mf->get_access_sector_mask(), m_gpu->gpgpu_ctx);
+ mem_fetch *n_mf = new mem_fetch(
+ *ma, NULL, mf->get_ctrl_size(), mf->get_wid(), mf->get_sid(),
+ mf->get_tpc(), mf->get_mem_config(),
+ m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle, NULL, mf);
- new_addr_type block_addr = m_config.block_addr(addr);
- bool do_miss = false;
- bool wb = false;
- evicted_block_info evicted;
- send_read_request( addr,
- block_addr,
- cache_index,
- n_mf, time, do_miss, wb, evicted, events, false, true);
+ new_addr_type block_addr = m_config.block_addr(addr);
+ bool do_miss = false;
+ bool wb = false;
+ evicted_block_info evicted;
+ send_read_request(addr, block_addr, cache_index, n_mf, time, do_miss, wb,
+ evicted, events, false, true);
- cache_block_t* block = m_tag_array->get_block(cache_index);
- block->set_modified_on_fill(true, mf->get_access_sector_mask());
+ cache_block_t *block = m_tag_array->get_block(cache_index);
+ block->set_modified_on_fill(true, mf->get_access_sector_mask());
- events.push_back(cache_event(WRITE_ALLOCATE_SENT));
+ events.push_back(cache_event(WRITE_ALLOCATE_SENT));
- if( do_miss ){
- // If evicted block is modified and not a write-through
- // (already modified lower level)
- if(wb && (m_config.m_write_policy != WRITE_THROUGH) ){
- mem_fetch *wb = m_memfetch_creator->alloc(evicted.m_block_addr,
- m_wrbk_type,evicted.m_modified_size,true,m_gpu->gpu_tot_sim_cycle+m_gpu->gpu_sim_cycle);
- send_write_request(wb, cache_event(WRITE_BACK_REQUEST_SENT, evicted), time, events);
- }
- return MISS;
- }
- return RESERVATION_FAIL;
- }
+ if (do_miss) {
+ // If evicted block is modified and not a write-through
+ // (already modified lower level)
+ if (wb && (m_config.m_write_policy != WRITE_THROUGH)) {
+ mem_fetch *wb = m_memfetch_creator->alloc(
+ evicted.m_block_addr, m_wrbk_type, evicted.m_modified_size, true,
+ m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle);
+ send_write_request(wb, cache_event(WRITE_BACK_REQUEST_SENT, evicted),
+ time, events);
+ }
+ return MISS;
+ }
+ return RESERVATION_FAIL;
+ }
}
-enum cache_request_status
-data_cache::wr_miss_wa_lazy_fetch_on_read( new_addr_type addr,
- unsigned cache_index, mem_fetch *mf,
- unsigned time, std::list<cache_event> &events,
- enum cache_request_status status )
-{
-
- new_addr_type block_addr = m_config.block_addr(addr);
+enum cache_request_status data_cache::wr_miss_wa_lazy_fetch_on_read(
+ new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time,
+ std::list<cache_event> &events, enum cache_request_status status) {
+ new_addr_type block_addr = m_config.block_addr(addr);
- //if the request writes to the whole cache line/sector, then, write and set cache line Modified.
- //and no need to send read request to memory or reserve mshr
+ // if the request writes to the whole cache line/sector, then, write and set
+ // cache line Modified. and no need to send read request to memory or reserve
+ // mshr
- if(miss_queue_full(0)) {
- m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
- return RESERVATION_FAIL; // cannot handle request this cycle
- }
+ if (miss_queue_full(0)) {
+ m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
+ return RESERVATION_FAIL; // cannot handle request this cycle
+ }
- bool wb = false;
- evicted_block_info evicted;
+ bool wb = false;
+ evicted_block_info evicted;
- cache_request_status m_status = m_tag_array->access(block_addr,time,cache_index,wb,evicted,mf);
- assert(m_status != HIT);
- cache_block_t* block = m_tag_array->get_block(cache_index);
- block->set_status(MODIFIED, mf->get_access_sector_mask());
- if(m_status == HIT_RESERVED) {
- block->set_ignore_on_fill(true, mf->get_access_sector_mask());
- block->set_modified_on_fill(true, mf->get_access_sector_mask());
- }
+ cache_request_status m_status =
+ m_tag_array->access(block_addr, time, cache_index, wb, evicted, mf);
+ assert(m_status != HIT);
+ cache_block_t *block = m_tag_array->get_block(cache_index);
+ block->set_status(MODIFIED, mf->get_access_sector_mask());
+ if (m_status == HIT_RESERVED) {
+ block->set_ignore_on_fill(true, mf->get_access_sector_mask());
+ block->set_modified_on_fill(true, mf->get_access_sector_mask());
+ }
- if(mf->get_access_byte_mask().count() == m_config.get_atom_sz())
- {
- block->set_m_readable(true, mf->get_access_sector_mask());
- } else
- {
- block->set_m_readable(false, mf->get_access_sector_mask());
- }
+ if (mf->get_access_byte_mask().count() == m_config.get_atom_sz()) {
+ block->set_m_readable(true, mf->get_access_sector_mask());
+ } else {
+ block->set_m_readable(false, mf->get_access_sector_mask());
+ }
- if( m_status != RESERVATION_FAIL ){
- // If evicted block is modified and not a write-through
- // (already modified lower level)
- if( wb && (m_config.m_write_policy != WRITE_THROUGH) ) {
- mem_fetch *wb = m_memfetch_creator->alloc(evicted.m_block_addr,
- m_wrbk_type,evicted.m_modified_size,true,m_gpu->gpu_tot_sim_cycle+m_gpu->gpu_sim_cycle);
- send_write_request(wb, cache_event(WRITE_BACK_REQUEST_SENT, evicted), time, events);
- }
- return MISS;
- }
- return RESERVATION_FAIL;
+ if (m_status != RESERVATION_FAIL) {
+ // If evicted block is modified and not a write-through
+ // (already modified lower level)
+ if (wb && (m_config.m_write_policy != WRITE_THROUGH)) {
+ mem_fetch *wb = m_memfetch_creator->alloc(
+ evicted.m_block_addr, m_wrbk_type, evicted.m_modified_size, true,
+ m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle);
+ send_write_request(wb, cache_event(WRITE_BACK_REQUEST_SENT, evicted),
+ time, events);
+ }
+ return MISS;
+ }
+ return RESERVATION_FAIL;
}
/// No write-allocate miss: Simply send write request to lower level memory
-enum cache_request_status
-data_cache::wr_miss_no_wa( new_addr_type addr,
- unsigned cache_index,
- mem_fetch *mf,
- unsigned time,
- std::list<cache_event> &events,
- enum cache_request_status status )
-{
- if(miss_queue_full(0)) {
- m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
- return RESERVATION_FAIL; // cannot handle request this cycle
- }
+enum cache_request_status data_cache::wr_miss_no_wa(
+ new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time,
+ std::list<cache_event> &events, enum cache_request_status status) {
+ if (miss_queue_full(0)) {
+ m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
+ return RESERVATION_FAIL; // cannot handle request this cycle
+ }
+ // on miss, generate write through (no write buffering -- too many threads for
+ // that)
+ send_write_request(mf, cache_event(WRITE_REQUEST_SENT), time, events);
- // on miss, generate write through (no write buffering -- too many threads for that)
- send_write_request(mf, cache_event(WRITE_REQUEST_SENT), time, events);
-
- return MISS;
+ return MISS;
}
/****** Read hit functions (Set by config file) ******/
/// Baseline read hit: Update LRU status of block.
// Special case for atomic instructions -> Mark block as modified
-enum cache_request_status
-data_cache::rd_hit_base( new_addr_type addr,
- unsigned cache_index,
- mem_fetch *mf,
- unsigned time,
- std::list<cache_event> &events,
- enum cache_request_status status )
-{
- new_addr_type block_addr = m_config.block_addr(addr);
- m_tag_array->access(block_addr,time,cache_index,mf);
- // Atomics treated as global read/write requests - Perform read, mark line as
- // MODIFIED
- if(mf->isatomic()){
- assert(mf->get_access_type() == GLOBAL_ACC_R);
- cache_block_t* block = m_tag_array->get_block(cache_index);
- block->set_status(MODIFIED, mf->get_access_sector_mask()) ; // mark line as dirty
- }
- return HIT;
+enum cache_request_status data_cache::rd_hit_base(
+ new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time,
+ std::list<cache_event> &events, enum cache_request_status status) {
+ new_addr_type block_addr = m_config.block_addr(addr);
+ m_tag_array->access(block_addr, time, cache_index, mf);
+ // Atomics treated as global read/write requests - Perform read, mark line as
+ // MODIFIED
+ if (mf->isatomic()) {
+ assert(mf->get_access_type() == GLOBAL_ACC_R);
+ cache_block_t *block = m_tag_array->get_block(cache_index);
+ block->set_status(MODIFIED,
+ mf->get_access_sector_mask()); // mark line as dirty
+ }
+ return HIT;
}
/****** Read miss functions (Set by config file) ******/
/// Baseline read miss: Send read request to lower level memory,
// perform write-back as necessary
-enum cache_request_status
-data_cache::rd_miss_base( new_addr_type addr,
- unsigned cache_index,
- mem_fetch *mf,
- unsigned time,
- std::list<cache_event> &events,
- enum cache_request_status status ){
- if(miss_queue_full(1)) {
- // cannot handle request this cycle
- // (might need to generate two requests)
- m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
- return RESERVATION_FAIL;
- }
+enum cache_request_status data_cache::rd_miss_base(
+ new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time,
+ std::list<cache_event> &events, enum cache_request_status status) {
+ if (miss_queue_full(1)) {
+ // cannot handle request this cycle
+ // (might need to generate two requests)
+ m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
+ return RESERVATION_FAIL;
+ }
- new_addr_type block_addr = m_config.block_addr(addr);
- bool do_miss = false;
- bool wb = false;
- evicted_block_info evicted;
- send_read_request( addr,
- block_addr,
- cache_index,
- mf, time, do_miss, wb, evicted, events, false, false);
+ new_addr_type block_addr = m_config.block_addr(addr);
+ bool do_miss = false;
+ bool wb = false;
+ evicted_block_info evicted;
+ send_read_request(addr, block_addr, cache_index, mf, time, do_miss, wb,
+ evicted, events, false, false);
- if( do_miss ){
- // If evicted block is modified and not a write-through
- // (already modified lower level)
- if(wb && (m_config.m_write_policy != WRITE_THROUGH) ){
- mem_fetch *wb = m_memfetch_creator->alloc(evicted.m_block_addr,
- m_wrbk_type,evicted.m_modified_size,true,m_gpu->gpu_tot_sim_cycle+m_gpu->gpu_sim_cycle);
- send_write_request(wb, WRITE_BACK_REQUEST_SENT, time, events);
- }
- return MISS;
+ if (do_miss) {
+ // If evicted block is modified and not a write-through
+ // (already modified lower level)
+ if (wb && (m_config.m_write_policy != WRITE_THROUGH)) {
+ mem_fetch *wb = m_memfetch_creator->alloc(
+ evicted.m_block_addr, m_wrbk_type, evicted.m_modified_size, true,
+ m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle);
+ send_write_request(wb, WRITE_BACK_REQUEST_SENT, time, events);
}
- return RESERVATION_FAIL;
+ return MISS;
+ }
+ return RESERVATION_FAIL;
}
/// Access cache for read_only_cache: returns RESERVATION_FAIL if
// request could not be accepted (for any reason)
-enum cache_request_status
-read_only_cache::access( new_addr_type addr,
- mem_fetch *mf,
- unsigned time,
- std::list<cache_event> &events )
-{
- assert( mf->get_data_size() <= m_config.get_atom_sz());
- assert(m_config.m_write_policy == READ_ONLY);
- assert(!mf->get_is_write());
- new_addr_type block_addr = m_config.block_addr(addr);
- unsigned cache_index = (unsigned)-1;
- enum cache_request_status status = m_tag_array->probe(block_addr,cache_index,mf);
- enum cache_request_status cache_status = RESERVATION_FAIL;
+enum cache_request_status read_only_cache::access(
+ new_addr_type addr, mem_fetch *mf, unsigned time,
+ std::list<cache_event> &events) {
+ assert(mf->get_data_size() <= m_config.get_atom_sz());
+ assert(m_config.m_write_policy == READ_ONLY);
+ assert(!mf->get_is_write());
+ new_addr_type block_addr = m_config.block_addr(addr);
+ unsigned cache_index = (unsigned)-1;
+ enum cache_request_status status =
+ m_tag_array->probe(block_addr, cache_index, mf);
+ enum cache_request_status cache_status = RESERVATION_FAIL;
- if ( status == HIT ) {
- cache_status = m_tag_array->access(block_addr,time,cache_index,mf); // update LRU state
- }else if ( status != RESERVATION_FAIL ) {
- if(!miss_queue_full(0)){
- bool do_miss=false;
- send_read_request(addr, block_addr, cache_index, mf, time, do_miss, events, true, false);
- if(do_miss)
- cache_status = MISS;
- else
- cache_status = RESERVATION_FAIL;
- }else{
- cache_status = RESERVATION_FAIL;
- m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
- }
- }else {
- m_stats.inc_fail_stats(mf->get_access_type(), LINE_ALLOC_FAIL);
+ if (status == HIT) {
+ cache_status = m_tag_array->access(block_addr, time, cache_index,
+ mf); // update LRU state
+ } else if (status != RESERVATION_FAIL) {
+ if (!miss_queue_full(0)) {
+ bool do_miss = false;
+ send_read_request(addr, block_addr, cache_index, mf, time, do_miss,
+ events, true, false);
+ if (do_miss)
+ cache_status = MISS;
+ else
+ cache_status = RESERVATION_FAIL;
+ } else {
+ cache_status = RESERVATION_FAIL;
+ m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
}
+ } else {
+ m_stats.inc_fail_stats(mf->get_access_type(), LINE_ALLOC_FAIL);
+ }
- m_stats.inc_stats(mf->get_access_type(), m_stats.select_stats_status(status, cache_status));
- m_stats.inc_stats_pw(mf->get_access_type(), m_stats.select_stats_status(status, cache_status));
- return cache_status;
+ m_stats.inc_stats(mf->get_access_type(),
+ m_stats.select_stats_status(status, cache_status));
+ m_stats.inc_stats_pw(mf->get_access_type(),
+ m_stats.select_stats_status(status, cache_status));
+ return cache_status;
}
//! A general function that takes the result of a tag_array probe
// and performs the correspding functions based on the cache configuration
// The access fucntion calls this function
-enum cache_request_status
-data_cache::process_tag_probe( bool wr,
- enum cache_request_status probe_status,
- new_addr_type addr,
- unsigned cache_index,
- mem_fetch* mf,
- unsigned time,
- std::list<cache_event>& events )
-{
- // Each function pointer ( m_[rd/wr]_[hit/miss] ) is set in the
- // data_cache constructor to reflect the corresponding cache configuration
- // options. Function pointers were used to avoid many long conditional
- // branches resulting from many cache configuration options.
- cache_request_status access_status = probe_status;
- if(wr){ // Write
- if(probe_status == HIT){
- access_status = (this->*m_wr_hit)( addr,
- cache_index,
- mf, time, events, probe_status );
- }else if ( (probe_status != RESERVATION_FAIL) || (probe_status == RESERVATION_FAIL && m_config.m_write_alloc_policy == NO_WRITE_ALLOCATE) ) {
- access_status = (this->*m_wr_miss)( addr,
- cache_index,
- mf, time, events, probe_status );
- }else {
- //the only reason for reservation fail here is LINE_ALLOC_FAIL (i.e all lines are reserved)
- m_stats.inc_fail_stats(mf->get_access_type(), LINE_ALLOC_FAIL);
- }
- }else{ // Read
- if(probe_status == HIT){
- access_status = (this->*m_rd_hit)( addr,
- cache_index,
- mf, time, events, probe_status );
- }else if ( probe_status != RESERVATION_FAIL ) {
- access_status = (this->*m_rd_miss)( addr,
- cache_index,
- mf, time, events, probe_status );
- }else {
- //the only reason for reservation fail here is LINE_ALLOC_FAIL (i.e all lines are reserved)
- m_stats.inc_fail_stats(mf->get_access_type(), LINE_ALLOC_FAIL);
- }
+enum cache_request_status data_cache::process_tag_probe(
+ bool wr, enum cache_request_status probe_status, new_addr_type addr,
+ unsigned cache_index, mem_fetch *mf, unsigned time,
+ std::list<cache_event> &events) {
+ // Each function pointer ( m_[rd/wr]_[hit/miss] ) is set in the
+ // data_cache constructor to reflect the corresponding cache configuration
+ // options. Function pointers were used to avoid many long conditional
+ // branches resulting from many cache configuration options.
+ cache_request_status access_status = probe_status;
+ if (wr) { // Write
+ if (probe_status == HIT) {
+ access_status =
+ (this->*m_wr_hit)(addr, cache_index, mf, time, events, probe_status);
+ } else if ((probe_status != RESERVATION_FAIL) ||
+ (probe_status == RESERVATION_FAIL &&
+ m_config.m_write_alloc_policy == NO_WRITE_ALLOCATE)) {
+ access_status =
+ (this->*m_wr_miss)(addr, cache_index, mf, time, events, probe_status);
+ } else {
+ // the only reason for reservation fail here is LINE_ALLOC_FAIL (i.e all
+ // lines are reserved)
+ m_stats.inc_fail_stats(mf->get_access_type(), LINE_ALLOC_FAIL);
+ }
+ } else { // Read
+ if (probe_status == HIT) {
+ access_status =
+ (this->*m_rd_hit)(addr, cache_index, mf, time, events, probe_status);
+ } else if (probe_status != RESERVATION_FAIL) {
+ access_status =
+ (this->*m_rd_miss)(addr, cache_index, mf, time, events, probe_status);
+ } else {
+ // the only reason for reservation fail here is LINE_ALLOC_FAIL (i.e all
+ // lines are reserved)
+ m_stats.inc_fail_stats(mf->get_access_type(), LINE_ALLOC_FAIL);
}
+ }
- m_bandwidth_management.use_data_port(mf, access_status, events);
- return access_status;
+ m_bandwidth_management.use_data_port(mf, access_status, events);
+ return access_status;
}
// Both the L1 and L2 currently use the same access function.
@@ -1650,51 +1642,41 @@ data_cache::process_tag_probe( bool wr,
// of caching policies.
// Both the L1 and L2 override this function to provide a means of
// performing actions specific to each cache when such actions are implemnted.
-enum cache_request_status
-data_cache::access( new_addr_type addr,
- mem_fetch *mf,
- unsigned time,
- std::list<cache_event> &events )
-{
-
- assert( mf->get_data_size() <= m_config.get_atom_sz());
- bool wr = mf->get_is_write();
- new_addr_type block_addr = m_config.block_addr(addr);
- unsigned cache_index = (unsigned)-1;
- enum cache_request_status probe_status
- = m_tag_array->probe( block_addr, cache_index, mf, true);
- enum cache_request_status access_status
- = process_tag_probe( wr, probe_status, addr, cache_index, mf, time, events );
- m_stats.inc_stats(mf->get_access_type(),
- m_stats.select_stats_status(probe_status, access_status));
- m_stats.inc_stats_pw(mf->get_access_type(),
- m_stats.select_stats_status(probe_status, access_status));
- return access_status;
+enum cache_request_status data_cache::access(new_addr_type addr, mem_fetch *mf,
+ unsigned time,
+ std::list<cache_event> &events) {
+ assert(mf->get_data_size() <= m_config.get_atom_sz());
+ bool wr = mf->get_is_write();
+ new_addr_type block_addr = m_config.block_addr(addr);
+ unsigned cache_index = (unsigned)-1;
+ enum cache_request_status probe_status =
+ m_tag_array->probe(block_addr, cache_index, mf, true);
+ enum cache_request_status access_status =
+ process_tag_probe(wr, probe_status, addr, cache_index, mf, time, events);
+ m_stats.inc_stats(mf->get_access_type(),
+ m_stats.select_stats_status(probe_status, access_status));
+ m_stats.inc_stats_pw(mf->get_access_type(), m_stats.select_stats_status(
+ probe_status, access_status));
+ return access_status;
}
/// This is meant to model the first level data cache in Fermi.
/// It is write-evict (global) or write-back (local) at the
/// granularity of individual blocks (Set by GPGPU-Sim configuration file)
/// (the policy used in fermi according to the CUDA manual)
-enum cache_request_status
-l1_cache::access( new_addr_type addr,
- mem_fetch *mf,
- unsigned time,
- std::list<cache_event> &events )
-{
- return data_cache::access( addr, mf, time, events );
+enum cache_request_status l1_cache::access(new_addr_type addr, mem_fetch *mf,
+ unsigned time,
+ std::list<cache_event> &events) {
+ return data_cache::access(addr, mf, time, events);
}
// The l2 cache access function calls the base data_cache access
// implementation. When the L2 needs to diverge from L1, L2 specific
// changes should be made here.
-enum cache_request_status
-l2_cache::access( new_addr_type addr,
- mem_fetch *mf,
- unsigned time,
- std::list<cache_event> &events )
-{
- return data_cache::access( addr, mf, time, events );
+enum cache_request_status l2_cache::access(new_addr_type addr, mem_fetch *mf,
+ unsigned time,
+ std::list<cache_event> &events) {
+ return data_cache::access(addr, mf, time, events);
}
/// Access function for tex_cache
@@ -1702,141 +1684,144 @@ l2_cache::access( new_addr_type addr,
/// otherwise returns HIT_RESERVED or MISS; NOTE: *never* returns HIT
/// since unlike a normal CPU cache, a "HIT" in texture cache does not
/// mean the data is ready (still need to get through fragment fifo)
-enum cache_request_status tex_cache::access( new_addr_type addr, mem_fetch *mf,
- unsigned time, std::list<cache_event> &events )
-{
- if ( m_fragment_fifo.full() || m_request_fifo.full() || m_rob.full() )
- return RESERVATION_FAIL;
+enum cache_request_status tex_cache::access(new_addr_type addr, mem_fetch *mf,
+ unsigned time,
+ std::list<cache_event> &events) {
+ if (m_fragment_fifo.full() || m_request_fifo.full() || m_rob.full())
+ return RESERVATION_FAIL;
- assert( mf->get_data_size() <= m_config.get_line_sz());
+ assert(mf->get_data_size() <= m_config.get_line_sz());
- // at this point, we will accept the request : access tags and immediately allocate line
- new_addr_type block_addr = m_config.block_addr(addr);
- unsigned cache_index = (unsigned)-1;
- enum cache_request_status status = m_tags.access(block_addr,time,cache_index,mf);
- enum cache_request_status cache_status = RESERVATION_FAIL;
- assert( status != RESERVATION_FAIL );
- assert( status != HIT_RESERVED ); // as far as tags are concerned: HIT or MISS
- m_fragment_fifo.push( fragment_entry(mf,cache_index,status==MISS,mf->get_data_size()) );
- if ( status == MISS ) {
- // we need to send a memory request...
- unsigned rob_index = m_rob.push( rob_entry(cache_index, mf, block_addr) );
- m_extra_mf_fields[mf] = extra_mf_fields(rob_index, m_config);
- mf->set_data_size(m_config.get_line_sz());
- m_tags.fill(cache_index,time,mf); // mark block as valid
- m_request_fifo.push(mf);
- mf->set_status(m_request_queue_status,time);
- events.push_back(cache_event(READ_REQUEST_SENT));
- cache_status = MISS;
- } else {
- // the value *will* *be* in the cache already
- cache_status = HIT_RESERVED;
- }
- m_stats.inc_stats(mf->get_access_type(), m_stats.select_stats_status(status, cache_status));
- m_stats.inc_stats_pw(mf->get_access_type(), m_stats.select_stats_status(status, cache_status));
- return cache_status;
+ // at this point, we will accept the request : access tags and immediately
+ // allocate line
+ new_addr_type block_addr = m_config.block_addr(addr);
+ unsigned cache_index = (unsigned)-1;
+ enum cache_request_status status =
+ m_tags.access(block_addr, time, cache_index, mf);
+ enum cache_request_status cache_status = RESERVATION_FAIL;
+ assert(status != RESERVATION_FAIL);
+ assert(status != HIT_RESERVED); // as far as tags are concerned: HIT or MISS
+ m_fragment_fifo.push(
+ fragment_entry(mf, cache_index, status == MISS, mf->get_data_size()));
+ if (status == MISS) {
+ // we need to send a memory request...
+ unsigned rob_index = m_rob.push(rob_entry(cache_index, mf, block_addr));
+ m_extra_mf_fields[mf] = extra_mf_fields(rob_index, m_config);
+ mf->set_data_size(m_config.get_line_sz());
+ m_tags.fill(cache_index, time, mf); // mark block as valid
+ m_request_fifo.push(mf);
+ mf->set_status(m_request_queue_status, time);
+ events.push_back(cache_event(READ_REQUEST_SENT));
+ cache_status = MISS;
+ } else {
+ // the value *will* *be* in the cache already
+ cache_status = HIT_RESERVED;
+ }
+ m_stats.inc_stats(mf->get_access_type(),
+ m_stats.select_stats_status(status, cache_status));
+ m_stats.inc_stats_pw(mf->get_access_type(),
+ m_stats.select_stats_status(status, cache_status));
+ return cache_status;
}
-void tex_cache::cycle(){
- // send next request to lower level of memory
- if ( !m_request_fifo.empty() ) {
- mem_fetch *mf = m_request_fifo.peek();
- if ( !m_memport->full(mf->get_ctrl_size(),false) ) {
- m_request_fifo.pop();
- m_memport->push(mf);
- }
+void tex_cache::cycle() {
+ // send next request to lower level of memory
+ if (!m_request_fifo.empty()) {
+ mem_fetch *mf = m_request_fifo.peek();
+ if (!m_memport->full(mf->get_ctrl_size(), false)) {
+ m_request_fifo.pop();
+ m_memport->push(mf);
}
- // read ready lines from cache
- if ( !m_fragment_fifo.empty() && !m_result_fifo.full() ) {
- const fragment_entry &e = m_fragment_fifo.peek();
- if ( e.m_miss ) {
- // check head of reorder buffer to see if data is back from memory
- unsigned rob_index = m_rob.next_pop_index();
- const rob_entry &r = m_rob.peek(rob_index);
- assert( r.m_request == e.m_request );
- //assert( r.m_block_addr == m_config.block_addr(e.m_request->get_addr()) );
- if ( r.m_ready ) {
- assert( r.m_index == e.m_cache_index );
- m_cache[r.m_index].m_valid = true;
- m_cache[r.m_index].m_block_addr = r.m_block_addr;
- m_result_fifo.push(e.m_request);
- m_rob.pop();
- m_fragment_fifo.pop();
- }
- } else {
- // hit:
- assert( m_cache[e.m_cache_index].m_valid );
- assert( m_cache[e.m_cache_index].m_block_addr
- == m_config.block_addr(e.m_request->get_addr()) );
- m_result_fifo.push( e.m_request );
- m_fragment_fifo.pop();
- }
+ }
+ // read ready lines from cache
+ if (!m_fragment_fifo.empty() && !m_result_fifo.full()) {
+ const fragment_entry &e = m_fragment_fifo.peek();
+ if (e.m_miss) {
+ // check head of reorder buffer to see if data is back from memory
+ unsigned rob_index = m_rob.next_pop_index();
+ const rob_entry &r = m_rob.peek(rob_index);
+ assert(r.m_request == e.m_request);
+ // assert( r.m_block_addr == m_config.block_addr(e.m_request->get_addr())
+ // );
+ if (r.m_ready) {
+ assert(r.m_index == e.m_cache_index);
+ m_cache[r.m_index].m_valid = true;
+ m_cache[r.m_index].m_block_addr = r.m_block_addr;
+ m_result_fifo.push(e.m_request);
+ m_rob.pop();
+ m_fragment_fifo.pop();
+ }
+ } else {
+ // hit:
+ assert(m_cache[e.m_cache_index].m_valid);
+ assert(m_cache[e.m_cache_index].m_block_addr ==
+ m_config.block_addr(e.m_request->get_addr()));
+ m_result_fifo.push(e.m_request);
+ m_fragment_fifo.pop();
}
+ }
}
/// Place returning cache block into reorder buffer
-void tex_cache::fill( mem_fetch *mf, unsigned time )
-{
- if(m_config.m_mshr_type == SECTOR_TEX_FIFO) {
- assert(mf->get_original_mf());
- extra_mf_fields_lookup::iterator e = m_extra_mf_fields.find(mf->get_original_mf());
- assert( e != m_extra_mf_fields.end() );
+void tex_cache::fill(mem_fetch *mf, unsigned time) {
+ if (m_config.m_mshr_type == SECTOR_TEX_FIFO) {
+ assert(mf->get_original_mf());
+ extra_mf_fields_lookup::iterator e =
+ m_extra_mf_fields.find(mf->get_original_mf());
+ assert(e != m_extra_mf_fields.end());
e->second.pending_read--;
- if(e->second.pending_read > 0) {
- //wait for the other requests to come back
- delete mf;
- return;
- } else {
- mem_fetch *temp = mf;
- mf = mf->get_original_mf();
- delete temp;
- }
- }
+ if (e->second.pending_read > 0) {
+ // wait for the other requests to come back
+ delete mf;
+ return;
+ } else {
+ mem_fetch *temp = mf;
+ mf = mf->get_original_mf();
+ delete temp;
+ }
+ }
- extra_mf_fields_lookup::iterator e = m_extra_mf_fields.find(mf);
- assert( e != m_extra_mf_fields.end() );
- assert( e->second.m_valid );
- assert( !m_rob.empty() );
- mf->set_status(m_rob_status,time);
+ extra_mf_fields_lookup::iterator e = m_extra_mf_fields.find(mf);
+ assert(e != m_extra_mf_fields.end());
+ assert(e->second.m_valid);
+ assert(!m_rob.empty());
+ mf->set_status(m_rob_status, time);
- unsigned rob_index = e->second.m_rob_index;
- rob_entry &r = m_rob.peek(rob_index);
- assert( !r.m_ready );
- r.m_ready = true;
- r.m_time = time;
- assert( r.m_block_addr == m_config.block_addr(mf->get_addr()) );
+ unsigned rob_index = e->second.m_rob_index;
+ rob_entry &r = m_rob.peek(rob_index);
+ assert(!r.m_ready);
+ r.m_ready = true;
+ r.m_time = time;
+ assert(r.m_block_addr == m_config.block_addr(mf->get_addr()));
}
-void tex_cache::display_state( FILE *fp ) const
-{
- fprintf(fp,"%s (texture cache) state:\n", m_name.c_str() );
- fprintf(fp,"fragment fifo entries = %u / %u\n",
- m_fragment_fifo.size(), m_fragment_fifo.capacity() );
- fprintf(fp,"reorder buffer entries = %u / %u\n",
- m_rob.size(), m_rob.capacity() );
- fprintf(fp,"request fifo entries = %u / %u\n",
- m_request_fifo.size(), m_request_fifo.capacity() );
- if ( !m_rob.empty() )
- fprintf(fp,"reorder buffer contents:\n");
- for ( int n=m_rob.size()-1; n>=0; n-- ) {
- unsigned index = (m_rob.next_pop_index() + n)%m_rob.capacity();
- const rob_entry &r = m_rob.peek(index);
- fprintf(fp, "tex rob[%3d] : %s ",
- index, (r.m_ready?"ready ":"pending") );
- if ( r.m_ready )
- fprintf(fp,"@%6u", r.m_time );
- else
- fprintf(fp," ");
- fprintf(fp,"[idx=%4u]",r.m_index);
- r.m_request->print(fp,false);
- }
- if ( !m_fragment_fifo.empty() ) {
- fprintf(fp,"fragment fifo (oldest) :");
- fragment_entry &f = m_fragment_fifo.peek();
- fprintf(fp,"%s: ", f.m_miss?"miss":"hit ");
- f.m_request->print(fp,false);
- }
+void tex_cache::display_state(FILE *fp) const {
+ fprintf(fp, "%s (texture cache) state:\n", m_name.c_str());
+ fprintf(fp, "fragment fifo entries = %u / %u\n", m_fragment_fifo.size(),
+ m_fragment_fifo.capacity());
+ fprintf(fp, "reorder buffer entries = %u / %u\n", m_rob.size(),
+ m_rob.capacity());
+ fprintf(fp, "request fifo entries = %u / %u\n", m_request_fifo.size(),
+ m_request_fifo.capacity());
+ if (!m_rob.empty()) fprintf(fp, "reorder buffer contents:\n");
+ for (int n = m_rob.size() - 1; n >= 0; n--) {
+ unsigned index = (m_rob.next_pop_index() + n) % m_rob.capacity();
+ const rob_entry &r = m_rob.peek(index);
+ fprintf(fp, "tex rob[%3d] : %s ", index,
+ (r.m_ready ? "ready " : "pending"));
+ if (r.m_ready)
+ fprintf(fp, "@%6u", r.m_time);
+ else
+ fprintf(fp, " ");
+ fprintf(fp, "[idx=%4u]", r.m_index);
+ r.m_request->print(fp, false);
+ }
+ if (!m_fragment_fifo.empty()) {
+ fprintf(fp, "fragment fifo (oldest) :");
+ fragment_entry &f = m_fragment_fifo.peek();
+ fprintf(fp, "%s: ", f.m_miss ? "miss" : "hit ");
+ f.m_request->print(fp, false);
+ }
}
/******************************************************************************************************************************************/
-