diff options
| author | Mahmoud <[email protected]> | 2019-07-29 21:18:06 -0400 |
|---|---|---|
| committer | Mahmoud <[email protected]> | 2019-07-29 21:18:06 -0400 |
| commit | 5875fda72d4402413bc5c04ee5ec15085ff2b90a (patch) | |
| tree | c920268d899df331e1a5e451a35133eaff7ca341 /src/gpgpu-sim | |
| parent | c05dc90da35fc2bd9dd42da9626bf3a60e2c9e8d (diff) | |
| parent | 21d937256fbca004c926531cfef1adefcedeef91 (diff) | |
Merge branch 'dev' of https://github.com/mkhairy/gpgpu-sim-private into dev-purdue-integration-trace
Diffstat (limited to 'src/gpgpu-sim')
| -rw-r--r-- | src/gpgpu-sim/addrdec.cc | 54 | ||||
| -rw-r--r-- | src/gpgpu-sim/addrdec.h | 6 | ||||
| -rw-r--r-- | src/gpgpu-sim/dram.cc | 101 | ||||
| -rw-r--r-- | src/gpgpu-sim/dram.h | 75 | ||||
| -rw-r--r-- | src/gpgpu-sim/dram_sched.cc | 6 | ||||
| -rw-r--r-- | src/gpgpu-sim/gpu-cache.cc | 294 | ||||
| -rw-r--r-- | src/gpgpu-sim/gpu-cache.h | 239 | ||||
| -rw-r--r-- | src/gpgpu-sim/gpu-sim.cc | 208 | ||||
| -rw-r--r-- | src/gpgpu-sim/gpu-sim.h | 56 | ||||
| -rw-r--r-- | src/gpgpu-sim/icnt_wrapper.cc | 90 | ||||
| -rw-r--r-- | src/gpgpu-sim/icnt_wrapper.h | 5 | ||||
| -rw-r--r-- | src/gpgpu-sim/l2cache.cc | 148 | ||||
| -rw-r--r-- | src/gpgpu-sim/l2cache.h | 6 | ||||
| -rw-r--r-- | src/gpgpu-sim/local_interconnect.cc | 301 | ||||
| -rw-r--r-- | src/gpgpu-sim/local_interconnect.h | 127 | ||||
| -rw-r--r-- | src/gpgpu-sim/mem_fetch.cc | 3 | ||||
| -rw-r--r-- | src/gpgpu-sim/mem_fetch.h | 14 | ||||
| -rw-r--r-- | src/gpgpu-sim/mem_latency_stat.cc | 10 | ||||
| -rw-r--r-- | src/gpgpu-sim/mem_latency_stat.h | 8 | ||||
| -rw-r--r-- | src/gpgpu-sim/scoreboard.cc | 22 | ||||
| -rw-r--r-- | src/gpgpu-sim/shader.cc | 810 | ||||
| -rw-r--r-- | src/gpgpu-sim/shader.h | 206 |
22 files changed, 2312 insertions, 477 deletions
diff --git a/src/gpgpu-sim/addrdec.cc b/src/gpgpu-sim/addrdec.cc index cfd90ec..ca88ec9 100644 --- a/src/gpgpu-sim/addrdec.cc +++ b/src/gpgpu-sim/addrdec.cc @@ -111,11 +111,14 @@ void linear_to_raw_address_translation::addrdec_tlx(new_addr_type addr, addrdec_ //Do nothing break; case BITWISE_PERMUTATION: + { assert(!gap); tlx->chip = (tlx->chip) ^ (tlx->row & (m_n_channel-1)); assert(tlx->chip < m_n_channel); break; + } case IPOLY: + { /* * Set Indexing function from "Pseudo-randomly interleaved memory." * Rau, B. R et al. @@ -132,7 +135,7 @@ void linear_to_raw_address_translation::addrdec_tlx(new_addr_type addr, addrdec_ chip[0] = a[13]^a[12]^a[11]^a[10]^a[9]^a[6]^a[5]^a[3]^a[0]^chip[0]; chip[1] = a[14]^a[13]^a[12]^a[11]^a[10]^a[7]^a[6]^a[4]^a[1]^chip[1]; chip[2] = a[14]^a[10]^a[9]^a[8]^a[7]^a[6]^a[3]^a[2]^a[0]^chip[2]; - chip[3] = a[11]^a[10]^a[9]^a[8]^a[7]^a[4]^a[3]^a[1]^chip[3]; + chip[3] = a[11]^a[10]^a[9]^a[8]^a[7]^a[4]^a[3]^a[1]^chip[3]; chip[4] = a[12]^a[11]^a[10]^a[9]^a[8]^a[5]^a[4]^a[2]^chip[4]; tlx->chip = chip.to_ulong(); @@ -143,8 +146,49 @@ void linear_to_raw_address_translation::addrdec_tlx(new_addr_type addr, addrdec_ } assert(tlx->chip < m_n_channel); break; + } + case PAE: + { + //Page Address Entropy + //random selected bits from the page and bank bits + //similar to + //Liu, Yuxi, et al. "Get Out of the Valley: Power-Efficient Address Mapping for GPUs." ISCA 2018 + std::bitset<64> a(tlx->row); + std::bitset<5> chip(tlx->chip); + std::bitset<4> b(tlx->bk); + chip[0] = a[13]^a[10]^a[9]^a[5]^a[0]^b[3]^b[0]^chip[0]; + chip[1] = a[12]^a[11]^a[6]^a[1]^b[3]^b[2]^b[1]^chip[1]; + chip[2] = a[14]^a[9]^a[8]^a[7]^a[2]^b[1]^chip[2]; + chip[3] = a[11]^a[10]^a[8]^a[3]^b[2]^b[3]^chip[3]; + chip[4] = a[12]^a[9]^a[8]^a[5]^a[4]^b[1]^b[0]^chip[4]; + tlx->chip = chip.to_ulong(); + assert(tlx->chip < m_n_channel); + break; + } + case RANDOM: + { + new_addr_type chip_address = (addr>>ADDR_CHIP_S); + tr1_hash_map<new_addr_type,unsigned>::const_iterator got = address_random_interleaving.find (chip_address); + if ( got == address_random_interleaving.end() ) { + unsigned new_chip_id = rand() % (m_n_channel*m_n_sub_partition_in_channel); + address_random_interleaving[chip_address] = new_chip_id; + tlx->chip = new_chip_id/m_n_sub_partition_in_channel; + tlx->sub_partition = new_chip_id; + } + else { + unsigned new_chip_id = got->second; + tlx->chip = new_chip_id/m_n_sub_partition_in_channel; + tlx->sub_partition = new_chip_id; + } + + assert(tlx->chip < m_n_channel); + assert(tlx->sub_partition < m_n_channel*m_n_sub_partition_in_channel); + return; + break; + } case CUSTOM: /* No custom set function implemented */ + //Do you custom index here break; default: assert("\nUndefined set index function.\n" && 0); @@ -152,9 +196,9 @@ void linear_to_raw_address_translation::addrdec_tlx(new_addr_type addr, addrdec_ } // combine the chip address and the lower bits of DRAM bank address to form the subpartition ID - unsigned sub_partition_addr_mask = m_n_sub_partition_in_channel - 1; + unsigned sub_partition_addr_mask = m_n_sub_partition_in_channel - 1; tlx->sub_partition = tlx->chip * m_n_sub_partition_in_channel - + (tlx->bk & sub_partition_addr_mask); + + (tlx->bk & sub_partition_addr_mask); } void linear_to_raw_address_translation::addrdec_parseoption(const char *option) @@ -373,6 +417,10 @@ void linear_to_raw_address_translation::init(unsigned int n_channel, unsigned in if (run_test) { sweep_test(); } + + if(memory_partition_indexing == RANDOM) + srand (1); + } #include "../tr1_hash_map.h" diff --git a/src/gpgpu-sim/addrdec.h b/src/gpgpu-sim/addrdec.h index a18ff63..a5333fb 100644 --- a/src/gpgpu-sim/addrdec.h +++ b/src/gpgpu-sim/addrdec.h @@ -39,6 +39,8 @@ enum partition_index_function{ CONSECUTIVE = 0, BITWISE_PERMUTATION, IPOLY, + PAE, + RANDOM, CUSTOM }; @@ -54,6 +56,7 @@ struct addrdec_t { unsigned sub_partition; }; + class linear_to_raw_address_translation { public: linear_to_raw_address_translation(); @@ -61,7 +64,7 @@ public: void init(unsigned int n_channel, unsigned int n_sub_partition_in_channel); // accessors - void addrdec_tlx(new_addr_type addr, addrdec_t *tlx) const; + void addrdec_tlx(new_addr_type addr, addrdec_t *tlx) const; new_addr_type partition_address( new_addr_type addr ) const; private: @@ -91,6 +94,7 @@ private: unsigned int gap; int m_n_channel; int m_n_sub_partition_in_channel; + }; #endif diff --git a/src/gpgpu-sim/dram.cc b/src/gpgpu-sim/dram.cc index 92aa819..192cb65 100644 --- a/src/gpgpu-sim/dram.cc +++ b/src/gpgpu-sim/dram.cc @@ -199,15 +199,28 @@ dram_req_t::dram_req_t( class mem_fetch *mf, unsigned banks, unsigned dram_bnk_i const addrdec_t &tlx = mf->get_tlx_addr(); - if(dram_bnk_indexing_policy == 0) { - bk = tlx.bk; - } - else if(dram_bnk_indexing_policy == 1) { - int lbank = log2(banks); - bk = tlx.bk ^ (tlx.row & ((1<<lbank)-1)); - } - else - assert(1); + switch(dram_bnk_indexing_policy){ + case LINEAR_BK_INDEX: + { + bk = tlx.bk; + break; + } + case BITWISE_XORING_BK_INDEX: + { + //xoring bank bits with lower bits of the page + int lbank = log2(banks); + bk = tlx.bk ^ (tlx.row & ((1<<lbank)-1)); + break; + } + case CUSTOM_BK_INDEX: + /* No custom set function implemented */ + //Do you custom index here + break; + default: + assert("\nUndefined bank index function.\n" && 0); + break; + } + row = tlx.row; col = tlx.col; @@ -710,10 +723,10 @@ void dram_t::print( FILE* simFile) const id, m_config->nbk, m_config->busW, m_config->BL, m_config->CL ); fprintf(simFile,"tRRD=%d tCCD=%d, tRCD=%d tRAS=%d tRP=%d tRC=%d\n", m_config->tRRD, m_config->tCCD, m_config->tRCD, m_config->tRAS, m_config->tRP, m_config->tRC ); - fprintf(simFile,"n_cmd=%d n_nop=%d n_act=%d n_pre=%d n_ref_event=%d n_req=%d n_rd=%d n_rd_L2_A=%d n_write=%d n_wr_bk=%d bw_util=%.4g\n", + fprintf(simFile,"n_cmd=%llu n_nop=%llu n_act=%llu n_pre=%llu n_ref_event=%llu n_req=%llu n_rd=%llu n_rd_L2_A=%llu n_write=%llu n_wr_bk=%llu bw_util=%.4g\n", n_cmd, n_nop, n_act, n_pre, n_ref, n_req, n_rd, n_rd_L2_A, n_wr, n_wr_WB, (float)bwutil/n_cmd); - fprintf(simFile,"n_activity=%d dram_eff=%.4g\n", + fprintf(simFile,"n_activity=%llu dram_eff=%.4g\n", n_activity, (float)bwutil/n_activity); for (i=0;i<m_config->nbk;i++) { fprintf(simFile, "bk%d: %da %di ",i,bk[i]->n_access,bk[i]->n_idle); @@ -730,37 +743,41 @@ void dram_t::print( FILE* simFile) const printf("\nwrite_to_read_ratio_blp_rw_average = %.6f", write_to_read_ratio_blp_rw_average /banks_access_rw_total); printf("\nGrpLevelPara = %.6f \n", (float)bkgrp_parallsim_rw /banks_access_rw_total); - printf("\nbwutil = %.6f \n", (float)bwutil/n_cmd); - printf("total_CMD = %d \n", n_cmd); - printf("util_bw = %d \n", util_bw); - printf("Wasted_Col = %d \n", wasted_bw_col); - printf("Wasted_Row %d \n", wasted_bw_row); - printf("Idle = %d \n\n", idle_bw); + printf("\nBW Util details:\n"); + printf("bwutil = %.6f \n", (float)bwutil/n_cmd); + printf("total_CMD = %llu \n", n_cmd); + printf("util_bw = %llu \n", util_bw); + printf("Wasted_Col = %llu \n", wasted_bw_col); + printf("Wasted_Row = %llu \n", wasted_bw_row); + printf("Idle = %llu \n", idle_bw); - printf("RCDc_limit = %d \n", RCDc_limit); - printf("RCDWRc_limit = %d \n", RCDWRc_limit); - printf("WTRc_limit = %d \n", WTRc_limit); - printf("RTWc_limit = %d \n", RTWc_limit); - printf("CCDLc_limit = %d \n", CCDLc_limit); - printf("rwq = %d \n", rwq_limit); - printf("CCDLc_limit_alone = %d \n", CCDLc_limit_alone); - printf("WTRc_limit_alone = %d \n", WTRc_limit_alone); - printf("RTWc_limit_alone = %d \n", RTWc_limit_alone); + printf("\nBW Util Bottlenecks: \n"); + printf("RCDc_limit = %llu \n", RCDc_limit); + printf("RCDWRc_limit = %llu \n", RCDWRc_limit); + printf("WTRc_limit = %llu \n", WTRc_limit); + printf("RTWc_limit = %llu \n", RTWc_limit); + printf("CCDLc_limit = %llu \n", CCDLc_limit); + printf("rwq = %llu \n", rwq_limit); + printf("CCDLc_limit_alone = %llu \n", CCDLc_limit_alone); + printf("WTRc_limit_alone = %llu \n", WTRc_limit_alone); + printf("RTWc_limit_alone = %llu \n", RTWc_limit_alone); - printf("total_CMD = %d \n", n_cmd); - printf("n_nop = %d \n", n_nop); - printf("Read = %d \n", n_rd); - printf("Write = %d \n",n_wr); - printf("L2_Alloc = %d \n", n_rd_L2_A); - printf("L2_WB = %d \n", n_wr_WB); - printf("n_act = %d \n", n_act); - printf("n_pre = %d \n", n_pre); - printf("n_ref = %d \n", n_ref); - printf("n_req = %d \n", n_req ); - printf("total_req = %d \n\n", n_rd+n_wr+n_rd_L2_A+n_wr_WB); + printf("\nCommands details: \n"); + printf("total_CMD = %llu \n", n_cmd); + printf("n_nop = %llu \n", n_nop); + printf("Read = %llu \n", n_rd); + printf("Write = %llu \n",n_wr); + printf("L2_Alloc = %llu \n", n_rd_L2_A); + printf("L2_WB = %llu \n", n_wr_WB); + printf("n_act = %llu \n", n_act); + printf("n_pre = %llu \n", n_pre); + printf("n_ref = %llu \n", n_ref); + printf("n_req = %llu \n", n_req ); + printf("total_req = %llu \n", n_rd+n_wr+n_rd_L2_A+n_wr_WB); - printf("issued_total_row = %lu \n", issued_total_row); - printf("issued_total_col = %lu \n", issued_total_col); + printf("\nDual Bus Interface Util: \n"); + printf("issued_total_row = %llu \n", issued_total_row); + printf("issued_total_col = %llu \n", issued_total_col); printf("Row_Bus_Util = %.6f \n", (float)issued_total_row / n_cmd); printf("CoL_Bus_Util = %.6f \n", (float)issued_total_col / n_cmd); printf("Either_Row_CoL_Bus_Util = %.6f \n", (float)issued_total / n_cmd); @@ -798,7 +815,7 @@ void dram_t::visualize() const void dram_t::print_stat( FILE* simFile ) { - fprintf(simFile,"DRAM (%d): n_cmd=%d n_nop=%d n_act=%d n_pre=%d n_ref=%d n_req=%d n_rd=%d n_write=%d bw_util=%.4g ", + fprintf(simFile,"DRAM (%llu): n_cmd=%llu n_nop=%llu n_act=%llu n_pre=%llu n_ref=%llu n_req=%llu n_rd=%llu n_write=%llu bw_util=%.4g ", id, n_cmd, n_nop, n_act, n_pre, n_ref, n_req, n_rd, n_wr, (float)bwutil/n_cmd); fprintf(simFile, "mrqq: %d %.4g mrqsmax=%d ", max_mrqs, (float)ave_mrqs/n_cmd, max_mrqs_temp); @@ -879,10 +896,10 @@ void dram_t::set_dram_power_stats( unsigned &cmd, unsigned dram_t::get_bankgrp_number(unsigned i) { - if(m_config->dram_bnkgrp_indexing_policy == 0) { //higher bits + if(m_config->dram_bnkgrp_indexing_policy == HIGHER_BITS) { //higher bits return i>>m_config->bk_tag_length; } - else if (m_config->dram_bnkgrp_indexing_policy == 1) { //lower bits + else if (m_config->dram_bnkgrp_indexing_policy == LOWER_BITS) { //lower bits return i&((m_config->nbkgrp-1)); } else { diff --git a/src/gpgpu-sim/dram.h b/src/gpgpu-sim/dram.h index 0d4c0e7..1ab0153 100644 --- a/src/gpgpu-sim/dram.h +++ b/src/gpgpu-sim/dram.h @@ -93,7 +93,18 @@ struct bank_t unsigned int bkgrpindex; }; -struct mem_fetch; +enum bank_index_function{ + LINEAR_BK_INDEX = 0, + BITWISE_XORING_BK_INDEX, + CUSTOM_BK_INDEX +}; + +enum bank_grp_bits_position{ + HIGHER_BITS = 0, + LOWER_BITS +}; + +class mem_fetch; class dram_t { @@ -167,39 +178,39 @@ private: unsigned int dram_eff_bins[10]; unsigned int last_n_cmd, last_n_activity, last_bwutil; - unsigned int n_cmd; - unsigned int n_activity; - unsigned int n_nop; - unsigned int n_act; - unsigned int n_pre; - unsigned int n_ref; - unsigned int n_rd; - unsigned int n_rd_L2_A; - unsigned int n_wr; - unsigned int n_wr_WB; - unsigned int n_req; - unsigned int max_mrqs_temp; + unsigned long long n_cmd; + unsigned long long n_activity; + unsigned long long n_nop; + unsigned long long n_act; + unsigned long long n_pre; + unsigned long long n_ref; + unsigned long long n_rd; + unsigned long long n_rd_L2_A; + unsigned long long n_wr; + unsigned long long n_wr_WB; + unsigned long long n_req; + unsigned long long max_mrqs_temp; - //some statistics to collect to see where BW is wasted? - unsigned wasted_bw_row; - unsigned wasted_bw_col; - unsigned util_bw; - unsigned idle_bw; - unsigned RCDc_limit; - unsigned CCDLc_limit; - unsigned CCDLc_limit_alone; - unsigned CCDc_limit; - unsigned WTRc_limit; - unsigned WTRc_limit_alone; - unsigned RCDWRc_limit; - unsigned RTWc_limit; - unsigned RTWc_limit_alone; - unsigned rwq_limit; + //some statistics to see where BW is wasted? + unsigned long long wasted_bw_row; + unsigned long long wasted_bw_col; + unsigned long long util_bw; + unsigned long long idle_bw; + unsigned long long RCDc_limit; + unsigned long long CCDLc_limit; + unsigned long long CCDLc_limit_alone; + unsigned long long CCDc_limit; + unsigned long long WTRc_limit; + unsigned long long WTRc_limit_alone; + unsigned long long RCDWRc_limit; + unsigned long long RTWc_limit; + unsigned long long RTWc_limit_alone; + unsigned long long rwq_limit; //row locality, BLP and other statistics - unsigned long access_num; - unsigned long read_num; - unsigned long write_num; + unsigned long long access_num; + unsigned long long read_num; + unsigned long long write_num; unsigned long long hits_num; unsigned long long hits_read_num; unsigned long long hits_write_num; @@ -232,7 +243,7 @@ private: unsigned int ave_mrqs_partial; unsigned int bwutil_partial; - struct memory_stats_t *m_stats; + class memory_stats_t *m_stats; class Stats* mrqq_Dist; //memory request queue inside DRAM friend class frfcfs_scheduler; diff --git a/src/gpgpu-sim/dram_sched.cc b/src/gpgpu-sim/dram_sched.cc index f754d36..ff50050 100644 --- a/src/gpgpu-sim/dram_sched.cc +++ b/src/gpgpu-sim/dram_sched.cc @@ -109,12 +109,14 @@ dram_req_t *frfcfs_scheduler::schedule( unsigned bank, unsigned curr_row ) if(m_config->seperate_write_queue_enabled) { if(m_mode == READ_MODE && ((m_num_write_pending >= m_config->write_high_watermark ) - || (m_queue[bank].empty() && !m_write_queue[bank].empty()))) { + // || (m_queue[bank].empty() && !m_write_queue[bank].empty()) + )) { m_mode = WRITE_MODE; } else if(m_mode == WRITE_MODE && (( m_num_write_pending < m_config->write_low_watermark ) - || (!m_queue[bank].empty() && m_write_queue[bank].empty()))){ + // || (!m_queue[bank].empty() && m_write_queue[bank].empty()) + )){ m_mode = READ_MODE; } } diff --git a/src/gpgpu-sim/gpu-cache.cc b/src/gpgpu-sim/gpu-cache.cc index 75ec00a..370f6e6 100644 --- a/src/gpgpu-sim/gpu-cache.cc +++ b/src/gpgpu-sim/gpu-cache.cc @@ -29,7 +29,6 @@ #include "stat-tool.h" #include <assert.h> -#define MAX_DEFAULT_CACHE_SIZE_MULTIBLIER 4 // 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) @@ -71,6 +70,7 @@ unsigned l1d_cache_config::set_index(new_addr_type addr) const{ 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. @@ -164,7 +164,7 @@ unsigned l2_cache_config::set_index(new_addr_type addr) const{ tag_array::~tag_array() { - unsigned cache_lines_num = MAX_DEFAULT_CACHE_SIZE_MULTIBLIER*m_config.get_num_lines(); + 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; @@ -191,7 +191,7 @@ tag_array::tag_array( cache_config &config, : m_config( config ) { //assert( m_config.m_write_policy == READ_ONLY ); Old assert - unsigned cache_lines_num = MAX_DEFAULT_CACHE_SIZE_MULTIBLIER*config.get_num_lines(); + unsigned cache_lines_num = config.get_max_num_lines(); m_lines = new cache_block_t*[cache_lines_num]; if(config.m_cache_type == NORMAL) { @@ -222,23 +222,41 @@ void tag_array::init( int core_id, int type_id ) 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::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) const { +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); + 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) const { +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 valid_timestamp = (unsigned)-1; + unsigned long long valid_timestamp = (unsigned)-1; bool all_reserved = true; @@ -301,6 +319,16 @@ enum cache_request_status tag_array::probe( new_addr_type addr, unsigned &idx, m 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; + } + } + return MISS; } @@ -316,6 +344,7 @@ enum cache_request_status tag_array::access( new_addr_type addr, unsigned time, 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) { @@ -382,13 +411,32 @@ void tag_array::fill( unsigned index, unsigned time, mem_fetch* mf) 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; + 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; +} + +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)) ; + + is_used = false; } float tag_array::windowed_miss_rate( ) const @@ -552,9 +600,11 @@ void mshr_table::display( FILE *fp ) const{ /***************************************************************** 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; @@ -575,6 +625,15 @@ void cache_stats::clear(){ 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::inc_stats(int access_type, int access_outcome){ /// /// Increment the stat corresponding to (access_type, access_outcome) by 1. @@ -584,6 +643,16 @@ void cache_stats::inc_stats(int access_type, int 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_fail_stats(int access_type, int fail_outcome){ if(!check_fail_valid(access_type, fail_outcome)) @@ -606,7 +675,7 @@ enum cache_request_status cache_stats::select_stats_status(enum cache_request_st return access; } -unsigned &cache_stats::operator()(int access_type, int access_outcome, bool 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 @@ -625,7 +694,7 @@ unsigned &cache_stats::operator()(int access_type, int access_outcome, bool fail } } -unsigned cache_stats::operator()(int access_type, int access_outcome, bool fail_outcome) const{ +unsigned long long cache_stats::operator()(int access_type, int access_outcome, bool fail_outcome) const{ /// /// Const accessor into m_stats. /// @@ -670,6 +739,9 @@ cache_stats &cache_stats::operator+=(const cache_stats &cs){ 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); } @@ -687,23 +759,24 @@ void cache_stats::print_stats(FILE *fout, const char *cache_name) const{ /// 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::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] = %u\n", + 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", + fprintf(fout, "\t%s[%s][%s] = %llu\n", m_cache_name.c_str(), mem_access_type_str((enum mem_access_type)type), "TOTAL_ACCESS", @@ -740,13 +813,13 @@ void cache_sub_stats::print_port_stats(FILE *fout, const char *cache_name) const fprintf(fout, "%s_fill_port_util = %.3f\n", cache_name, fill_port_util); } -unsigned 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{ +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 total=0; + 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])) @@ -756,6 +829,7 @@ unsigned cache_stats::get_stats(enum mem_access_type *access_type, unsigned num_ } return total; } + void cache_stats::get_sub_stats(struct cache_sub_stats &css) const{ /// /// Overwrites "css" with the appropriate statistics from this cache. @@ -786,6 +860,55 @@ void cache_stats::get_sub_stats(struct cache_sub_stats &css) const{ 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(); + + 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 == 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 == 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; +} + bool cache_stats::check_valid(int type, int status) const{ /// /// Verify a valid access_type/access_status @@ -907,8 +1030,8 @@ void baseline_cache::cycle(){ void baseline_cache::fill(mem_fetch *mf, unsigned time){ if(m_config.m_mshr_type == SECTOR_ASSOC) { - assert(mf->original_mf); - extra_mf_fields_lookup::iterator e = m_extra_mf_fields.find(mf->original_mf); + 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--; @@ -918,7 +1041,7 @@ void baseline_cache::fill(mem_fetch *mf, unsigned time){ return; } else { mem_fetch *temp = mf; - mf = mf->original_mf; + mf = mf->get_original_mf(); delete temp; } } @@ -930,8 +1053,11 @@ void baseline_cache::fill(mem_fetch *mf, unsigned time){ 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 ) + 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); @@ -985,6 +1111,7 @@ void baseline_cache::send_read_request(new_addr_type addr, new_addr_type block_a m_mshrs.add(mshr_addr,mf); do_miss = true; + } 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); @@ -992,6 +1119,9 @@ void baseline_cache::send_read_request(new_addr_type addr, new_addr_type block_a m_tag_array->access(block_addr,time,cache_index,wb,evicted,mf); 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 ); @@ -1162,52 +1292,7 @@ data_cache::wr_miss_wa_fetch_on_write( new_addr_type addr, 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 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; - - 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( 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); - send_write_request(wb, cache_event(WRITE_BACK_REQUEST_SENT, evicted), time, events); - } - return MISS; - } - return RESERVATION_FAIL; - - /*new_addr_type block_addr = m_config.block_addr(addr); + 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()) @@ -1316,7 +1401,59 @@ data_cache::wr_miss_wa_fetch_on_write( new_addr_type addr, 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); + new_addr_type mshr_addr = m_config.mshr_addr(mf->get_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(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; + + 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( 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); + 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 @@ -1439,6 +1576,7 @@ read_only_cache::access( new_addr_type addr, } 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; } @@ -1508,11 +1646,13 @@ data_cache::access( new_addr_type addr, 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 ); + = 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; } @@ -1565,7 +1705,7 @@ enum cache_request_status tex_cache::access( new_addr_type addr, mem_fetch *mf, 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_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); @@ -1577,6 +1717,7 @@ enum cache_request_status tex_cache::access( new_addr_type addr, mem_fetch *mf, 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; } @@ -1620,6 +1761,23 @@ void tex_cache::cycle(){ /// 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() ); + 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 ); diff --git a/src/gpgpu-sim/gpu-cache.h b/src/gpgpu-sim/gpu-cache.h index d2b7757..337f710 100644 --- a/src/gpgpu-sim/gpu-cache.h +++ b/src/gpgpu-sim/gpu-cache.h @@ -38,6 +38,8 @@ #include "addrdec.h" #include <iostream> +#define MAX_DEFAULT_CACHE_SIZE_MULTIBLIER 4 + enum cache_block_state { INVALID=0, RESERVED, @@ -117,9 +119,9 @@ struct cache_block_t { virtual enum cache_block_state get_status( mem_access_sector_mask_t sector_mask) = 0; virtual void set_status(enum cache_block_state m_status, mem_access_sector_mask_t sector_mask) = 0; - virtual unsigned get_last_access_time() = 0; - virtual void set_last_access_time(unsigned time, mem_access_sector_mask_t sector_mask) = 0; - virtual unsigned get_alloc_time() = 0; + virtual unsigned long long get_last_access_time() = 0; + virtual void set_last_access_time(unsigned long long time, mem_access_sector_mask_t sector_mask) = 0; + virtual unsigned long long get_alloc_time() = 0; virtual void set_ignore_on_fill(bool m_ignore, mem_access_sector_mask_t sector_mask) = 0; virtual void set_modified_on_fill(bool m_modified, mem_access_sector_mask_t sector_mask) = 0; virtual unsigned get_modified_size() = 0; @@ -190,15 +192,15 @@ struct line_cache_block: public cache_block_t { { m_status = status; } - virtual unsigned get_last_access_time() + virtual unsigned long long get_last_access_time() { return m_last_access_time; } - virtual void set_last_access_time(unsigned time, mem_access_sector_mask_t sector_mask) + virtual void set_last_access_time(unsigned long long time, mem_access_sector_mask_t sector_mask) { m_last_access_time = time; } - virtual unsigned get_alloc_time() + virtual unsigned long long get_alloc_time() { return m_alloc_time; } @@ -222,14 +224,14 @@ struct line_cache_block: public cache_block_t { return m_readable; } virtual void print_status() { - printf("m_block_addr is %u, status = %u\n", m_block_addr, m_status); + printf("m_block_addr is %llu, status = %u\n", m_block_addr, m_status); } private: - unsigned m_alloc_time; - unsigned m_last_access_time; - unsigned m_fill_time; + unsigned long long m_alloc_time; + unsigned long long m_last_access_time; + unsigned long long m_fill_time; cache_block_state m_status; bool m_ignore_on_fill_status; bool m_set_modified_on_fill; @@ -355,41 +357,49 @@ struct sector_cache_block : public cache_block_t { return m_status[sidx]; } + virtual void set_status(enum cache_block_state status, mem_access_sector_mask_t sector_mask) { unsigned sidx = get_sector_index(sector_mask); m_status[sidx] = status; } - virtual unsigned get_last_access_time() + + virtual unsigned long long get_last_access_time() { return m_line_last_access_time; } - virtual void set_last_access_time(unsigned time, mem_access_sector_mask_t sector_mask) + + virtual void set_last_access_time(unsigned long long time, mem_access_sector_mask_t sector_mask) { unsigned sidx = get_sector_index(sector_mask); m_last_sector_access_time[sidx] = time; m_line_last_access_time = time; } - virtual unsigned get_alloc_time() + + virtual unsigned long long get_alloc_time() { return m_line_alloc_time; } + virtual void set_ignore_on_fill(bool m_ignore, mem_access_sector_mask_t sector_mask) { unsigned sidx = get_sector_index(sector_mask); m_ignore_on_fill_status[sidx] = m_ignore; } + virtual void set_modified_on_fill(bool m_modified, mem_access_sector_mask_t sector_mask) { unsigned sidx = get_sector_index(sector_mask); m_set_modified_on_fill[sidx] = m_modified; } + virtual void set_m_readable(bool readable, mem_access_sector_mask_t sector_mask) { unsigned sidx = get_sector_index(sector_mask); m_readable[sidx] = readable; } + virtual bool is_readable(mem_access_sector_mask_t sector_mask) { unsigned sidx = get_sector_index(sector_mask); return m_readable[sidx]; @@ -406,7 +416,7 @@ struct sector_cache_block : public cache_block_t { } virtual void print_status() { - printf("m_block_addr is %u, status = %u %u %u %u\n", m_block_addr, m_status[0], m_status[1], m_status[2], m_status[3]); + printf("m_block_addr is %llu, status = %u %u %u %u\n", m_block_addr, m_status[0], m_status[1], m_status[2], m_status[3]); } @@ -447,19 +457,22 @@ enum write_policy_t { enum allocation_policy_t { ON_MISS, - ON_FILL + ON_FILL, + STREAMING }; enum write_allocate_policy_t { NO_WRITE_ALLOCATE, WRITE_ALLOCATE, - FETCH_ON_WRITE + FETCH_ON_WRITE, + LAZY_FETCH_ON_READ }; enum mshr_config_t { - TEX_FIFO, + TEX_FIFO, // Tex cache ASSOC, // normal cache + SECTOR_TEX_FIFO, //Tex cache sends requests to high-level sector cache SECTOR_ASSOC // normal cache sends requests to high-level sector cache }; @@ -476,6 +489,12 @@ enum cache_type{ SECTOR }; +#define MAX_WARP_PER_SHADER 64 +#define INCT_TOTAL_BUFFER 64 +#define L2_TOTAL 64 +#define MAX_WARP_PER_SHADER 64 +#define MAX_WARP_PER_SHADER 64 + class cache_config { public: cache_config() @@ -487,6 +506,7 @@ public: m_config_stringPrefShared = NULL; m_data_port_width = 0; m_set_index_function = LINEAR_SET_FUNCTION; + m_is_streaming = false; } void init(char * config, FuncCache status) { @@ -535,10 +555,27 @@ public: switch (ap) { case 'm': m_alloc_policy = ON_MISS; break; case 'f': m_alloc_policy = ON_FILL; break; + case 's': m_alloc_policy = STREAMING; break; default: exit_parse_error(); } + if(m_alloc_policy == STREAMING) { + //For streaming cache, we set the alloc policy to be on-fill to remove all line_alloc_fail stalls + //we set the MSHRs to be equal to max allocated cache lines. This is possible by moving TAG to be shared between cache line and MSHR enrty (i.e. for each cache line, there is an MSHR rntey associated with it) + //This is the easiest think we can think about to model (mimic) L1 streaming cache in Pascal and Volta + //Based on our microbenchmakrs, MSHRs entries have been increasing substantially in Pascal and Volta + //For more information about streaming cache, see: + // http://on-demand.gputechconf.com/gtc/2017/presentation/s7798-luke-durant-inside-volta.pdf + // https://ieeexplore.ieee.org/document/8344474/ + m_is_streaming = true; + m_alloc_policy = ON_FILL; + m_mshr_entries = m_nset*m_assoc*MAX_DEFAULT_CACHE_SIZE_MULTIBLIER; + if(m_cache_type == SECTOR) + m_mshr_entries *= SECTOR_CHUNCK_SIZE; + m_mshr_max_merge = MAX_WARP_PER_SM; + } switch (mshr_type) { case 'F': m_mshr_type = TEX_FIFO; assert(ntok==14); break; + case 'T': m_mshr_type = SECTOR_TEX_FIFO; assert(ntok==14); break; case 'A': m_mshr_type = ASSOC; break; case 'S' : m_mshr_type = SECTOR_ASSOC; break; default: exit_parse_error(); @@ -547,6 +584,7 @@ public: m_nset_log2 = LOGB2(m_nset); m_valid = true; m_atom_sz = (m_cache_type == SECTOR)? SECTOR_SIZE : m_line_sz; + original_m_assoc = m_assoc; //For more details about difference between FETCH_ON_WRITE and WRITE VALIDAE policies //Read: Jouppi, Norman P. "Cache write policies and performance". ISCA 93. @@ -555,6 +593,7 @@ public: case 'N': m_write_alloc_policy = NO_WRITE_ALLOCATE; break; case 'W': m_write_alloc_policy = WRITE_ALLOCATE; break; case 'F': m_write_alloc_policy = FETCH_ON_WRITE; break; + case 'L': m_write_alloc_policy = LAZY_FETCH_ON_READ; break; default: exit_parse_error(); } @@ -572,9 +611,9 @@ public: assert(0 && "Invalid cache configuration: Writeback cache cannot allocate new line on fill. "); } - if(m_write_alloc_policy == FETCH_ON_WRITE && m_alloc_policy == ON_FILL) + if((m_write_alloc_policy == FETCH_ON_WRITE || m_write_alloc_policy == LAZY_FETCH_ON_READ )&& m_alloc_policy == ON_FILL) { - assert(0 && "Invalid cache configuration: FETCH_ON_WRITE cannot work properly with ON_FILL policy. Cache must be ON_MISS. "); + assert(0 && "Invalid cache configuration: FETCH_ON_WRITE and LAZY_FETCH_ON_READ cannot work properly with ON_FILL policy. Cache must be ON_MISS. "); } if(m_cache_type == SECTOR) { @@ -611,7 +650,11 @@ public: assert( m_valid ); return m_nset * m_assoc; } - + unsigned get_max_num_lines() const + { + assert( m_valid ); + return MAX_DEFAULT_CACHE_SIZE_MULTIBLIER * m_nset * original_m_assoc; + } void print( FILE *fp ) const { fprintf( fp, "Size = %d B (%d Set x %d-way x %d byte line)\n", @@ -638,20 +681,38 @@ public: // tag + index is required to check for hit/miss. Tag is now identical to the block address. //return addr >> (m_line_sz_log2+m_nset_log2); - return addr & ~(m_line_sz-1); + return addr & ~(new_addr_type)(m_line_sz-1); } new_addr_type block_addr( new_addr_type addr ) const { - return addr & ~(m_line_sz-1); + return addr & ~(new_addr_type)(m_line_sz-1); } new_addr_type mshr_addr( new_addr_type addr ) const { - return addr & ~(m_atom_sz-1); + return addr & ~(new_addr_type)(m_atom_sz-1); } enum mshr_config_t get_mshr_type() const { return m_mshr_type; } + void set_assoc(unsigned n) + { + //set new assoc. L1 cache dynamically resized in Volta + m_assoc = n; + } + unsigned get_nset() const + { + assert( m_valid ); + return m_nset; + } + unsigned get_total_size_inKB() const + { + assert( m_valid ); + return (m_assoc*m_nset*m_line_sz)/1024; + } + bool is_streaming() { + return m_is_streaming; + } FuncCache get_cache_status() {return cache_status;} char *m_config_string; char *m_config_stringPrefL1; @@ -673,6 +734,8 @@ protected: unsigned m_nset_log2; unsigned m_assoc; unsigned m_atom_sz; + unsigned original_m_assoc; + bool m_is_streaming; enum replacement_policy_t m_replacement_policy; // 'L' = LRU, 'F' = FIFO enum write_policy_t m_write_policy; // 'T' = write through, 'B' = write back, 'R' = read only @@ -712,6 +775,7 @@ class l1d_cache_config : public cache_config{ public: l1d_cache_config() : cache_config(){} virtual unsigned set_index(new_addr_type addr) const; + unsigned l1_latency; }; class l2_cache_config : public cache_config { @@ -730,8 +794,8 @@ public: tag_array(cache_config &config, int core_id, int type_id ); ~tag_array(); - enum cache_request_status probe( new_addr_type addr, unsigned &idx, mem_fetch* mf ) const; - enum cache_request_status probe( new_addr_type addr, unsigned &idx, mem_access_sector_mask_t mask ) const; + enum cache_request_status probe( new_addr_type addr, unsigned &idx, mem_fetch* mf, bool probe_mode=false ) const; + enum cache_request_status probe( new_addr_type addr, unsigned &idx, mem_access_sector_mask_t mask, bool probe_mode=false, mem_fetch* mf = NULL ) const; enum cache_request_status access( new_addr_type addr, unsigned time, unsigned &idx, mem_fetch* mf ); enum cache_request_status access( new_addr_type addr, unsigned time, unsigned &idx, bool &wb, evicted_block_info &evicted, mem_fetch* mf ); @@ -742,7 +806,8 @@ public: unsigned size() const { return m_config.get_num_lines();} cache_block_t* get_block(unsigned idx) { return m_lines[idx];} - void flush(); // flash invalidate all entries + void flush(); // flush all written entries + void invalidate(); // invalidate all entries void new_window(); void print( FILE *stream, unsigned &total_access, unsigned &total_misses ) const; @@ -750,6 +815,8 @@ public: void get_stats(unsigned &total_access, unsigned &total_misses, unsigned &total_hit_res, unsigned &total_res_fail) const; void update_cache_parameters(cache_config &config); + void add_pending_line(mem_fetch *mf); + void remove_pending_line(mem_fetch *mf); protected: // This constructor is intended for use only from derived classes that wish to // avoid unnecessary memory allocation that takes place in the @@ -779,6 +846,11 @@ protected: int m_core_id; // which shader core is using this int m_type_id; // what kind of cache is this (normal, texture, constant) + + bool is_used; //a flag if the whole cache has ever been accessed before + + typedef tr1_hash_map<new_addr_type,unsigned> line_table; + line_table pending_lines; }; class mshr_table { @@ -828,7 +900,9 @@ private: mshr_entry() : m_has_atomic(false) { } }; typedef tr1_hash_map<new_addr_type,mshr_entry> table; + typedef tr1_hash_map<new_addr_type,mshr_entry> line_table; table m_data; + line_table pending_lines; // it may take several cycles to process the merged requests bool m_current_response_ready; @@ -841,10 +915,10 @@ private: /// Simple struct to maintain cache accesses, misses, pending hits, and reservation fails. /// struct cache_sub_stats{ - unsigned accesses; - unsigned misses; - unsigned pending_hits; - unsigned res_fails; + unsigned long long accesses; + unsigned long long misses; + unsigned long long pending_hits; + unsigned long long res_fails; unsigned long long port_available_cycles; unsigned long long data_port_busy_cycles; @@ -894,6 +968,66 @@ struct cache_sub_stats{ void print_port_stats(FILE *fout, const char *cache_name) const; }; + +// Used for collecting AerialVision per-window statistics +struct cache_sub_stats_pw{ + unsigned accesses; + unsigned write_misses; + unsigned write_hits; + unsigned write_pending_hits; + unsigned write_res_fails; + + unsigned read_misses; + unsigned read_hits; + unsigned read_pending_hits; + unsigned read_res_fails; + + cache_sub_stats_pw(){ + clear(); + } + void clear(){ + accesses = 0; + write_misses = 0; + write_hits = 0; + write_pending_hits = 0; + write_res_fails = 0; + read_misses = 0; + read_hits = 0; + read_pending_hits = 0; + read_res_fails = 0; + } + cache_sub_stats_pw &operator+=(const cache_sub_stats_pw &css){ + /// + /// Overloading += operator to easily accumulate stats + /// + accesses += css.accesses; + write_misses += css.write_misses; + read_misses += css.read_misses; + write_pending_hits += css.write_pending_hits; + read_pending_hits += css.read_pending_hits; + write_res_fails += css.write_res_fails; + read_res_fails += css.read_res_fails; + return *this; + } + + cache_sub_stats_pw operator+(const cache_sub_stats_pw &cs){ + /// + /// Overloading + operator to easily accumulate stats + /// + cache_sub_stats_pw ret; + ret.accesses = accesses + cs.accesses; + ret.write_misses = write_misses + cs.write_misses; + ret.read_misses = read_misses + cs.read_misses; + ret.write_pending_hits = write_pending_hits + cs.write_pending_hits; + ret.read_pending_hits = read_pending_hits + cs.read_pending_hits; + ret.write_res_fails = write_res_fails + cs.write_res_fails; + ret.read_res_fails = read_res_fails + cs.read_res_fails; + return ret; + } + +}; + + /// /// Cache_stats /// Used to record statistics for each cache. @@ -904,26 +1038,36 @@ class cache_stats { public: cache_stats(); void clear(); + // Clear AerialVision cache stats after each window + void clear_pw(); void inc_stats(int access_type, int access_outcome); + // Increment AerialVision cache stats + void inc_stats_pw(int access_type, int access_outcome); void inc_fail_stats(int access_type, int fail_outcome); enum cache_request_status select_stats_status(enum cache_request_status probe, enum cache_request_status access) const; - unsigned &operator()(int access_type, int access_outcome, bool fail_outcome); - unsigned operator()(int access_type, int access_outcome, bool fail_outcome) const; + unsigned long long &operator()(int access_type, int access_outcome, bool fail_outcome); + unsigned long long operator()(int access_type, int access_outcome, bool fail_outcome) const; cache_stats operator+(const cache_stats &cs); cache_stats &operator+=(const cache_stats &cs); void print_stats(FILE *fout, const char *cache_name = "Cache_stats") const; void print_fail_stats(FILE *fout, const char *cache_name = "Cache_fail_stats") const; - unsigned get_stats(enum mem_access_type *access_type, unsigned num_access_type, enum cache_request_status *access_status, unsigned num_access_status) const; + unsigned long long get_stats(enum mem_access_type *access_type, unsigned num_access_type, enum cache_request_status *access_status, unsigned num_access_status) const; void get_sub_stats(struct cache_sub_stats &css) const; + // Get per-window cache stats for AerialVision + void get_sub_stats_pw(struct cache_sub_stats_pw &css) const; + void sample_cache_port_utility(bool data_port_busy, bool fill_port_busy); private: bool check_valid(int type, int status) const; bool check_fail_valid(int type, int fail) const; - std::vector< std::vector<unsigned> > m_stats; - std::vector< std::vector<unsigned> > m_fail_stats; + + std::vector< std::vector<unsigned long long> > m_stats; + // AerialVision cache stats (per-window) + std::vector< std::vector<unsigned long long> > m_stats_pw; + std::vector< std::vector<unsigned long long> > m_fail_stats; unsigned long long m_cache_port_available_cycles; unsigned long long m_cache_data_port_busy_cycles; @@ -994,6 +1138,7 @@ public: mem_fetch *next_access(){return m_mshrs.next_access();} // flash invalidate all entries in cache void flush(){m_tag_array->flush();} + void invalidate(){m_tag_array->invalidate();} void print(FILE *fp, unsigned &accesses, unsigned &misses) const; void display_state( FILE *fp ) const; @@ -1007,6 +1152,14 @@ public: void get_sub_stats(struct cache_sub_stats &css) const { m_stats.get_sub_stats(css); } + // Clear per-window stats for AerialVision support + void clear_pw(){ + m_stats.clear_pw(); + } + // Per-window sub stats for AerialVision support + void get_sub_stats_pw(struct cache_sub_stats_pw &css) const { + m_stats.get_sub_stats_pw(css); + } // accessors for cache bandwidth availability bool data_port_free() const { return m_bandwidth_management.data_port_free(); } @@ -1179,6 +1332,7 @@ public: case NO_WRITE_ALLOCATE: m_wr_miss = &data_cache::wr_miss_no_wa; break; case WRITE_ALLOCATE: m_wr_miss = &data_cache::wr_miss_wa_naive; break; case FETCH_ON_WRITE: m_wr_miss = &data_cache::wr_miss_wa_fetch_on_write; break; + case LAZY_FETCH_ON_READ: m_wr_miss = &data_cache::wr_miss_wa_lazy_fetch_on_read; break; default: assert(0 && "Error: Must set valid cache write miss policy\n"); break; // Need to set a write miss function @@ -1299,7 +1453,14 @@ protected: mem_fetch *mf, unsigned time, std::list<cache_event> &events, - enum cache_request_status status ); // write-allocate with read-fetch-only + enum cache_request_status status ); // write-allocate with fetch-on-every-write + enum cache_request_status + 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 ); // write-allocate with read-fetch-only enum cache_request_status wr_miss_wa_write_validate( new_addr_type addr, unsigned cache_index, @@ -1422,7 +1583,7 @@ public: m_result_fifo(config.m_result_fifo_entries) { m_name = name; - assert(config.m_mshr_type == TEX_FIFO); + assert(config.m_mshr_type == TEX_FIFO || config.m_mshr_type == SECTOR_TEX_FIFO ); assert(config.m_write_policy == READ_ONLY); assert(config.m_alloc_policy == ON_MISS); m_memport=memport; @@ -1575,13 +1736,15 @@ private: struct extra_mf_fields { extra_mf_fields() { m_valid = false;} - extra_mf_fields( unsigned i ) + extra_mf_fields( unsigned i, const cache_config &m_config ) { m_valid = true; m_rob_index = i; + pending_read = m_config.m_mshr_type == SECTOR_TEX_FIFO? m_config.m_line_sz/SECTOR_SIZE : 0; } bool m_valid; unsigned m_rob_index; + unsigned pending_read; }; cache_stats m_stats; diff --git a/src/gpgpu-sim/gpu-sim.cc b/src/gpgpu-sim/gpu-sim.cc index c5d4464..92d5366 100644 --- a/src/gpgpu-sim/gpu-sim.cc +++ b/src/gpgpu-sim/gpu-sim.cc @@ -32,6 +32,7 @@ #include <stdio.h> #include <stdlib.h> #include <math.h> +#include <signal.h> #include "zlib.h" @@ -57,6 +58,7 @@ #include "../debug.h" #include "../gpgpusim_entrypoint.h" #include "../cuda-sim/cuda-sim.h" +#include "../cuda-sim/ptx_ir.h" #include "../trace.h" #include "mem_latency_stat.h" #include "power_stat.h" @@ -83,6 +85,7 @@ bool g_interactive_debugger_enabled=false; unsigned long long gpu_sim_cycle = 0; unsigned long long gpu_tot_sim_cycle = 0; +unsigned long long elapsed_cycles_sm_tot = 0; //this is a equivalent metric generated as nvprof. that only counts when SM is active // performance counter for stalls due to congestion. @@ -97,6 +100,8 @@ unsigned long long gpu_tot_sim_cycle_parition_util = 0; unsigned long long partiton_replys_in_parallel = 0; unsigned long long partiton_replys_in_parallel_total = 0; +tr1_hash_map<new_addr_type,unsigned> address_random_interleaving; + /* Clock Domains */ #define CORE 0x01 @@ -151,6 +156,8 @@ void memory_config::reg_options(class OptionParser * opp) { option_parser_register(opp, "-perf_sim_memcpy", OPT_BOOL, &m_perf_sim_memcpy, "Fill the L2 cache on memcpy", "1"); + option_parser_register(opp, "-simple_dram_model", OPT_BOOL, &simple_dram_model, + "simple_dram_model with fixed latency and BW", "0"); option_parser_register(opp, "-gpgpu_dram_scheduler", OPT_INT32, &scheduler_type, "0 = fifo, 1 = FR-FCFS (defaul)", "1"); option_parser_register(opp, "-gpgpu_dram_partition_queues", OPT_CSTR, &gpgpu_L2_queue_config, @@ -250,6 +257,12 @@ void shader_core_config::reg_options(class OptionParser * opp) "per-shader L1 data cache config " " {<nsets>:<bsize>:<assoc>,<rep>:<wr>:<alloc>:<wr_alloc>,<mshr>:<N>:<merge>,<mq> | none}", "none" ); + option_parser_register(opp, "-l1_latency", OPT_UINT32, &m_L1D_config.l1_latency, + "L1 Hit Latency", + "0"); + option_parser_register(opp, "-smem_latency", OPT_UINT32, &smem_latency, + "smem Latency", + "3"); option_parser_register(opp, "-gpgpu_cache:dl1PrefL1", OPT_CSTR, &m_L1D_config.m_config_stringPrefL1, "per-shader L1 data cache config " " {<nsets>:<bsize>:<assoc>,<rep>:<wr>:<alloc>:<wr_alloc>,<mshr>:<N>:<merge>,<mq> | none}", @@ -277,6 +290,9 @@ void shader_core_config::reg_options(class OptionParser * opp) option_parser_register(opp, "-gpgpu_shader_registers", OPT_UINT32, &gpgpu_shader_registers, "Number of registers per shader core. Limits number of concurrent CTAs. (default 8192)", "8192"); + option_parser_register(opp, "-gpgpu_registers_per_block", OPT_UINT32, &gpgpu_registers_per_block, + "Maximum number of registers per CTA. (default 8192)", + "8192"); option_parser_register(opp, "-gpgpu_ignore_resources_limitation", OPT_BOOL, &gpgpu_ignore_resources_limitation, "gpgpu_ignore_resources_limitation (default 0)", "0"); @@ -298,10 +314,16 @@ void shader_core_config::reg_options(class OptionParser * opp) option_parser_register(opp, "-gpgpu_n_ldst_response_buffer_size", OPT_UINT32, &ldst_unit_response_queue_size, "number of response packets in ld/st unit ejection buffer", "2"); + option_parser_register(opp, "-gpgpu_shmem_per_block", OPT_UINT32, &gpgpu_shmem_per_block, + "Size of shared memory per thread block or CTA (default 48kB)", + "49152"); option_parser_register(opp, "-gpgpu_shmem_size", OPT_UINT32, &gpgpu_shmem_size, "Size of shared memory per shader core (default 16kB)", "16384"); - option_parser_register(opp, "-gpgpu_shmem_size", OPT_UINT32, &gpgpu_shmem_sizeDefault, + option_parser_register(opp, "-adaptive_volta_cache_config", OPT_BOOL, &adaptive_volta_cache_config, + "adaptive_volta_cache_config", + "0"); + option_parser_register(opp, "-gpgpu_shmem_sizeDefault", OPT_UINT32, &gpgpu_shmem_sizeDefault, "Size of shared memory per shader core (default 16kB)", "16384"); option_parser_register(opp, "-gpgpu_shmem_size_PrefL1", OPT_UINT32, &gpgpu_shmem_sizePrefL1, @@ -319,6 +341,9 @@ void shader_core_config::reg_options(class OptionParser * opp) option_parser_register(opp, "-gpgpu_shmem_warp_parts", OPT_INT32, &mem_warp_parts, "Number of portions a warp is divided into for shared memory bank conflict check ", "2"); + option_parser_register(opp, "-mem_unit_ports", OPT_INT32, &mem_unit_ports, + "The number of memory transactions allowed per core cycle", + "1"); option_parser_register(opp, "-gpgpu_shmem_warp_parts", OPT_INT32, &mem_warp_parts, "Number of portions a warp is divided into for shared memory bank conflict check ", "2"); @@ -337,8 +362,14 @@ void shader_core_config::reg_options(class OptionParser * opp) option_parser_register(opp, "-gpgpu_reg_bank_use_warp_id", OPT_BOOL, &gpgpu_reg_bank_use_warp_id, "Use warp ID in mapping registers to banks (default = off)", "0"); + option_parser_register(opp, "-sub_core_model", OPT_BOOL, &sub_core_model, + "Sub Core Volta/Pascal model (default = off)", + "0"); + option_parser_register(opp, "-enable_specialized_operand_collector", OPT_BOOL, &enable_specialized_operand_collector, + "enable_specialized_operand_collector", + "1"); option_parser_register(opp, "-gpgpu_operand_collector_num_units_sp", OPT_INT32, &gpgpu_operand_collector_num_units_sp, - "number of collector units (default = 4)", + "number of collector units (default = 4)", "4"); option_parser_register(opp, "-gpgpu_operand_collector_num_units_dp", OPT_INT32, &gpgpu_operand_collector_num_units_dp, "number of collector units (default = 0)", @@ -346,6 +377,12 @@ void shader_core_config::reg_options(class OptionParser * opp) option_parser_register(opp, "-gpgpu_operand_collector_num_units_sfu", OPT_INT32, &gpgpu_operand_collector_num_units_sfu, "number of collector units (default = 4)", "4"); + option_parser_register(opp, "-gpgpu_operand_collector_num_units_int", OPT_INT32, &gpgpu_operand_collector_num_units_int, + "number of collector units (default = 0)", + "0"); + option_parser_register(opp, "-gpgpu_operand_collector_num_units_tensor_core", OPT_INT32, &gpgpu_operand_collector_num_units_tensor_core, + "number of collector units (default = 4)", + "4"); option_parser_register(opp, "-gpgpu_operand_collector_num_units_mem", OPT_INT32, &gpgpu_operand_collector_num_units_mem, "number of collector units (default = 2)", "2"); @@ -361,6 +398,12 @@ void shader_core_config::reg_options(class OptionParser * opp) option_parser_register(opp, "-gpgpu_operand_collector_num_in_ports_sfu", OPT_INT32, &gpgpu_operand_collector_num_in_ports_sfu, "number of collector unit in ports (default = 1)", "1"); + option_parser_register(opp, "-gpgpu_operand_collector_num_in_ports_int", OPT_INT32, &gpgpu_operand_collector_num_in_ports_int, + "number of collector unit in ports (default = 0)", + "0"); + option_parser_register(opp, "-gpgpu_operand_collector_num_in_ports_tensor_core", OPT_INT32, &gpgpu_operand_collector_num_in_ports_tensor_core, + "number of collector unit in ports (default = 1)", + "1"); option_parser_register(opp, "-gpgpu_operand_collector_num_in_ports_mem", OPT_INT32, &gpgpu_operand_collector_num_in_ports_mem, "number of collector unit in ports (default = 1)", "1"); @@ -376,6 +419,12 @@ void shader_core_config::reg_options(class OptionParser * opp) option_parser_register(opp, "-gpgpu_operand_collector_num_out_ports_sfu", OPT_INT32, &gpgpu_operand_collector_num_out_ports_sfu, "number of collector unit in ports (default = 1)", "1"); + option_parser_register(opp, "-gpgpu_operand_collector_num_out_ports_int", OPT_INT32, &gpgpu_operand_collector_num_out_ports_int, + "number of collector unit in ports (default = 0)", + "0"); + option_parser_register(opp, "-gpgpu_operand_collector_num_out_ports_tensor_core", OPT_INT32, &gpgpu_operand_collector_num_out_ports_tensor_core, + "number of collector unit in ports (default = 1)", + "1"); option_parser_register(opp, "-gpgpu_operand_collector_num_out_ports_mem", OPT_INT32, &gpgpu_operand_collector_num_out_ports_mem, "number of collector unit in ports (default = 1)", "1"); @@ -399,17 +448,26 @@ void shader_core_config::reg_options(class OptionParser * opp) "1"); option_parser_register(opp, "-gpgpu_pipeline_widths", OPT_CSTR, &pipeline_widths_string, "Pipeline widths " - "ID_OC_SP,ID_OC_DP,ID_OC_SFU,ID_OC_MEM,OC_EX_SP,OC_EX_DP,OC_EX_SFU,OC_EX_MEM,EX_WB", - "1,1,1,1,1,1,1,1,1" ); + "ID_OC_SP,ID_OC_DP,ID_OC_INT,ID_OC_SFU,ID_OC_MEM,OC_EX_SP,OC_EX_DP,OC_EX_INT,OC_EX_SFU,OC_EX_MEM,EX_WB,ID_OC_TENSOR_CORE,OC_EX_TENSOR_CORE", + "1,1,1,1,1,1,1,1,1,1,1,1,1" ); + option_parser_register(opp, "-gpgpu_tensor_core_avail", OPT_INT32, &gpgpu_tensor_core_avail, + "Tensor Core Available (default=0)", + "0"); option_parser_register(opp, "-gpgpu_num_sp_units", OPT_INT32, &gpgpu_num_sp_units, "Number of SP units (default=1)", "1"); option_parser_register(opp, "-gpgpu_num_dp_units", OPT_INT32, &gpgpu_num_dp_units, "Number of DP units (default=0)", "0"); + option_parser_register(opp, "-gpgpu_num_int_units", OPT_INT32, &gpgpu_num_int_units, + "Number of INT units (default=0)", + "0"); option_parser_register(opp, "-gpgpu_num_sfu_units", OPT_INT32, &gpgpu_num_sfu_units, "Number of SF units (default=1)", "1"); + option_parser_register(opp, "-gpgpu_num_tensor_core_units", OPT_INT32, &gpgpu_num_tensor_core_units, + "Number of tensor_core units (default=1)", + "1"); option_parser_register(opp, "-gpgpu_num_mem_units", OPT_INT32, &gpgpu_num_mem_units, "Number if ldst units (default=1) WARNING: not hooked up to anything", "1"); @@ -423,6 +481,7 @@ void shader_core_config::reg_options(class OptionParser * opp) option_parser_register(opp, "-gpgpu_concurrent_kernel_sm", OPT_BOOL, &gpgpu_concurrent_kernel_sm, "Support concurrent kernels on a SM (default = disabled)", "0"); + } void gpgpu_sim_config::reg_options(option_parser_t opp) @@ -446,6 +505,12 @@ void gpgpu_sim_config::reg_options(option_parser_t opp) option_parser_register(opp, "-liveness_message_freq", OPT_INT64, &liveness_message_freq, "Minimum number of seconds between simulation liveness messages (0 = always print)", "1"); + option_parser_register(opp, "-gpgpu_compute_capability_major", OPT_UINT32, &gpgpu_compute_capability_major, + "Major compute capability version number", + "7"); + option_parser_register(opp, "-gpgpu_compute_capability_minor", OPT_UINT32, &gpgpu_compute_capability_minor, + "Minor compute capability version number", + "0"); option_parser_register(opp, "-gpgpu_flush_l1_cache", OPT_BOOL, &gpgpu_flush_l1_cache, "Flush L1 cache at the end of each kernel call", "0"); @@ -479,6 +544,14 @@ void gpgpu_sim_config::reg_options(option_parser_t opp) option_parser_register(opp, "-visualizer_zlevel", OPT_INT32, &g_visualizer_zlevel, "Compression level of the visualizer output log (0=no comp, 9=highest)", "6"); + option_parser_register(opp, "-gpgpu_stack_size_limit", OPT_INT32, &stack_size_limit, + "GPU thread stack size", "1024" ); + option_parser_register(opp, "-gpgpu_heap_size_limit", OPT_INT32, &heap_size_limit, + "GPU malloc heap size ", "8388608" ); + option_parser_register(opp, "-gpgpu_runtime_sync_depth_limit", OPT_INT32, &runtime_sync_depth_limit, + "GPU device runtime synchronize depth", "2" ); + option_parser_register(opp, "-gpgpu_runtime_pending_launch_count_limit", OPT_INT32, &runtime_pending_launch_count_limit, + "GPU device runtime pending launch count", "2048" ); option_parser_register(opp, "-trace_enabled", OPT_BOOL, &Trace::enabled, "Turn on traces", "0"); @@ -711,11 +784,21 @@ int gpgpu_sim::shared_mem_size() const return m_shader_config->gpgpu_shmem_size; } +int gpgpu_sim::shared_mem_per_block() const +{ + return m_shader_config->gpgpu_shmem_per_block; +} + int gpgpu_sim::num_registers_per_core() const { return m_shader_config->gpgpu_shader_registers; } +int gpgpu_sim::num_registers_per_block() const +{ + return m_shader_config->gpgpu_registers_per_block; +} + int gpgpu_sim::wrp_size() const { return m_shader_config->warp_size; @@ -726,11 +809,31 @@ int gpgpu_sim::shader_clock() const return m_config.core_freq/1000; } +int gpgpu_sim::max_cta_per_core() const +{ + return m_shader_config->max_cta_per_core; +} + +int gpgpu_sim::get_max_cta( const kernel_info_t &k ) const +{ + return m_shader_config->max_cta(k); +} + void gpgpu_sim::set_prop( cudaDeviceProp *prop ) { m_cuda_properties = prop; } +int gpgpu_sim::compute_capability_major() const +{ + return m_config.gpgpu_compute_capability_major; +} + +int gpgpu_sim::compute_capability_minor() const +{ + return m_config.gpgpu_compute_capability_minor; +} + const struct cudaDeviceProp *gpgpu_sim::get_prop() const { return m_cuda_properties; @@ -839,6 +942,7 @@ void gpgpu_sim::update_stats() { partiton_replys_in_parallel_total += partiton_replys_in_parallel; partiton_reqs_in_parallel_util_total += partiton_reqs_in_parallel_util; gpu_tot_sim_cycle_parition_util += gpu_sim_cycle_parition_util ; + gpu_tot_occupancy += gpu_occupancy; gpu_sim_cycle = 0; partiton_reqs_in_parallel = 0; @@ -847,6 +951,7 @@ void gpgpu_sim::update_stats() { gpu_sim_cycle_parition_util = 0; gpu_sim_insn = 0; m_total_cta_launched = 0; + gpu_occupancy = occupancy_stats(); } void gpgpu_sim::print_stats() @@ -963,7 +1068,7 @@ void gpgpu_sim::change_cache_config(FuncCache cache_config) if(cache_config != m_shader_config->m_L1D_config.get_cache_status()){ printf("FLUSH L1 Cache at configuration change between kernels\n"); for (unsigned i=0;i<m_shader_config->n_simt_clusters;i++) { - m_cluster[i]->cache_flush(); + m_cluster[i]->cache_invalidate(); } } @@ -1017,9 +1122,13 @@ void gpgpu_sim::gpu_print_stat() printf("gpu_sim_insn = %lld\n", gpu_sim_insn); printf("gpu_ipc = %12.4f\n", (float)gpu_sim_insn / gpu_sim_cycle); printf("gpu_tot_sim_cycle = %lld\n", gpu_tot_sim_cycle+gpu_sim_cycle); + printf("elapsed_cycles_sm_tot = %lld\n", elapsed_cycles_sm_tot); printf("gpu_tot_sim_insn = %lld\n", gpu_tot_sim_insn+gpu_sim_insn); printf("gpu_tot_ipc = %12.4f\n", (float)(gpu_tot_sim_insn+gpu_sim_insn) / (gpu_tot_sim_cycle+gpu_sim_cycle)); printf("gpu_tot_issued_cta = %lld\n", gpu_tot_issued_cta + m_total_cta_launched); + printf("gpu_occupancy = %.4f\% \n", gpu_occupancy.get_occ_fraction() * 100); + printf("gpu_tot_occupancy = %.4f\% \n", (gpu_occupancy + gpu_tot_occupancy).get_occ_fraction() * 100); + extern unsigned long long g_max_total_param_size; fprintf(statfout, "max_total_param_size = %llu\n", g_max_total_param_size); @@ -1028,18 +1137,18 @@ void gpgpu_sim::gpu_print_stat() printf("gpu_stall_dramfull = %d\n", gpu_stall_dramfull); printf("gpu_stall_icnt2sh = %d\n", gpu_stall_icnt2sh ); - printf("partiton_reqs_in_parallel = %lld\n", partiton_reqs_in_parallel); - printf("partiton_reqs_in_parallel_total = %lld\n", partiton_reqs_in_parallel_total ); + //printf("partiton_reqs_in_parallel = %lld\n", partiton_reqs_in_parallel); + //printf("partiton_reqs_in_parallel_total = %lld\n", partiton_reqs_in_parallel_total ); printf("partiton_level_parallism = %12.4f\n", (float)partiton_reqs_in_parallel / gpu_sim_cycle); printf("partiton_level_parallism_total = %12.4f\n", (float)(partiton_reqs_in_parallel+partiton_reqs_in_parallel_total) / (gpu_tot_sim_cycle+gpu_sim_cycle) ); - printf("partiton_reqs_in_parallel_util = %lld\n", partiton_reqs_in_parallel_util); - printf("partiton_reqs_in_parallel_util_total = %lld\n", partiton_reqs_in_parallel_util_total ); - printf("gpu_sim_cycle_parition_util = %lld\n", gpu_sim_cycle_parition_util); - printf("gpu_tot_sim_cycle_parition_util = %lld\n", gpu_tot_sim_cycle_parition_util ); + //printf("partiton_reqs_in_parallel_util = %lld\n", partiton_reqs_in_parallel_util); + //printf("partiton_reqs_in_parallel_util_total = %lld\n", partiton_reqs_in_parallel_util_total ); + //printf("gpu_sim_cycle_parition_util = %lld\n", gpu_sim_cycle_parition_util); + // printf("gpu_tot_sim_cycle_parition_util = %lld\n", gpu_tot_sim_cycle_parition_util ); printf("partiton_level_parallism_util = %12.4f\n", (float)partiton_reqs_in_parallel_util / gpu_sim_cycle_parition_util); printf("partiton_level_parallism_util_total = %12.4f\n", (float)(partiton_reqs_in_parallel_util+partiton_reqs_in_parallel_util_total) / (gpu_sim_cycle_parition_util+gpu_tot_sim_cycle_parition_util) ); - printf("partiton_replys_in_parallel = %lld\n", partiton_replys_in_parallel); - printf("partiton_replys_in_parallel_total = %lld\n", partiton_replys_in_parallel_total ); + //printf("partiton_replys_in_parallel = %lld\n", partiton_replys_in_parallel); + //printf("partiton_replys_in_parallel_total = %lld\n", partiton_replys_in_parallel_total ); printf("L2_BW = %12.4f GB/Sec\n", ((float)(partiton_replys_in_parallel * 32) / (gpu_sim_cycle * m_config.icnt_period)) / 1000000000); printf("L2_BW_total = %12.4f GB/Sec\n", ((float)((partiton_replys_in_parallel+partiton_replys_in_parallel_total) * 32) / ((gpu_tot_sim_cycle+gpu_sim_cycle) * m_config.icnt_period)) / 1000000000 ); @@ -1089,19 +1198,19 @@ void gpgpu_sim::gpu_print_stat() m_memory_sub_partition[i]->accumulate_L2cache_stats(l2_stats); m_memory_sub_partition[i]->get_L2cache_sub_stats(l2_css); - fprintf( stdout, "L2_cache_bank[%d]: Access = %u, Miss = %u, Miss_rate = %.3lf, Pending_hits = %u, Reservation_fails = %u\n", + fprintf( stdout, "L2_cache_bank[%d]: Access = %llu, Miss = %llu, Miss_rate = %.3lf, Pending_hits = %llu, Reservation_fails = %llu\n", i, l2_css.accesses, l2_css.misses, (double)l2_css.misses / (double)l2_css.accesses, l2_css.pending_hits, l2_css.res_fails); total_l2_css += l2_css; } if (!m_memory_config->m_L2_config.disabled() && m_memory_config->m_L2_config.get_num_lines()) { //L2c_print_cache_stat(); - printf("L2_total_cache_accesses = %u\n", total_l2_css.accesses); - printf("L2_total_cache_misses = %u\n", total_l2_css.misses); + printf("L2_total_cache_accesses = %llu\n", total_l2_css.accesses); + printf("L2_total_cache_misses = %llu\n", total_l2_css.misses); if(total_l2_css.accesses > 0) printf("L2_total_cache_miss_rate = %.4lf\n", (double)total_l2_css.misses/(double)total_l2_css.accesses); - printf("L2_total_cache_pending_hits = %u\n", total_l2_css.pending_hits); - printf("L2_total_cache_reservation_fails = %u\n", total_l2_css.res_fails); + printf("L2_total_cache_pending_hits = %llu\n", total_l2_css.pending_hits); + printf("L2_total_cache_reservation_fails = %llu\n", total_l2_css.res_fails); printf("L2_total_cache_breakdown:\n"); l2_stats.print_stats(stdout, "L2_cache_stats_breakdown"); printf("L2_total_cache_reservation_fail_breakdown:\n"); @@ -1163,6 +1272,9 @@ void shader_core_ctx::mem_instruction_stats(const warp_inst_t &inst) case shared_space: m_stats->gpgpu_n_shmem_insn += active_count; break; + case sstarr_space: + m_stats->gpgpu_n_sstarr_insn += active_count; + break; case const_space: m_stats->gpgpu_n_const_insn += active_count; break; @@ -1364,22 +1476,44 @@ void shader_core_ctx::issue_block2core( kernel_info_t &kernel ) // bind functional simulation state of threads to hardware resources (simulation) warp_set_t warps; unsigned nthreads_in_block= 0; + function_info *kernel_func_info = kernel.entry(); + symbol_table * symtab= kernel_func_info->get_symtab(); + unsigned ctaid= kernel.get_next_cta_id_single(); + checkpoint *g_checkpoint= new checkpoint(); for (unsigned i = start_thread; i<end_thread; i++) { m_threadState[i].m_cta_id = free_cta_hw_id; unsigned warp_id = i/m_config->warp_size; nthreads_in_block += ptx_sim_init_thread(kernel,&m_thread[i],m_sid,i,cta_size-(i-start_thread),m_config->n_thread_per_shader,this,free_cta_hw_id,warp_id,m_cluster->get_gpu()); m_threadState[i].m_active = true; + // load thread local memory and register file + if(m_gpu->resume_option==1 && kernel.get_uid()==m_gpu->resume_kernel && ctaid>=m_gpu->resume_CTA && ctaid<m_gpu->checkpoint_CTA_t ) + { + char fname[2048]; + snprintf(fname,2048,"checkpoint_files/thread_%d_%d_reg.txt",i%cta_size,ctaid ); + m_thread[i]->resume_reg_thread(fname,symtab); + char f1name[2048]; + snprintf(f1name,2048,"checkpoint_files/local_mem_thread_%d_%d_reg.txt",i%cta_size,ctaid); + g_checkpoint->load_global_mem(m_thread[i]->m_local_mem, f1name); + } + // warps.set( warp_id ); } assert( nthreads_in_block > 0 && nthreads_in_block <= m_config->n_thread_per_shader); // should be at least one, but less than max m_cta_status[free_cta_hw_id]=nthreads_in_block; + if(m_gpu->resume_option==1 && kernel.get_uid()==m_gpu->resume_kernel && ctaid>=m_gpu->resume_CTA && ctaid<m_gpu->checkpoint_CTA_t ) + { + char f1name[2048]; + snprintf(f1name,2048,"checkpoint_files/shared_mem_%d.txt", ctaid); + + g_checkpoint->load_global_mem(m_thread[start_thread]->m_shared_mem, f1name); + } // now that we know which warps are used in this CTA, we can allocate // resources for use in CTA-wide barrier operations m_barriers.allocate_barrier(free_cta_hw_id,warps); // initialize the SIMT stacks and fetch hardware - init_warps( free_cta_hw_id, start_thread, end_thread); + init_warps( free_cta_hw_id, start_thread, end_thread, ctaid, cta_size, kernel.get_uid()); m_n_active_cta++; shader_CTA_count_log(m_sid, 1); @@ -1474,7 +1608,10 @@ void gpgpu_sim::cycle() if (clock_mask & DRAM) { for (unsigned i=0;i<m_memory_config->m_n_mem;i++){ - m_memory_partition_unit[i]->dram_cycle(); // Issue the dram command (scheduler + delay model) + if(m_memory_config->simple_dram_model) + m_memory_partition_unit[i]->simple_dram_model_cycle(); + else + m_memory_partition_unit[i]->dram_cycle(); // Issue the dram command (scheduler + delay model) // Update performance counters for DRAM m_memory_partition_unit[i]->set_dram_power_stats(m_power_stats->pwr_mem_stat->n_cmd[CURRENT_STAT_IDX][i], m_power_stats->pwr_mem_stat->n_activity[CURRENT_STAT_IDX][i], m_power_stats->pwr_mem_stat->n_nop[CURRENT_STAT_IDX][i], m_power_stats->pwr_mem_stat->n_act[CURRENT_STAT_IDX][i], m_power_stats->pwr_mem_stat->n_pre[CURRENT_STAT_IDX][i], @@ -1495,7 +1632,8 @@ void gpgpu_sim::cycle() } else { mem_fetch* mf = (mem_fetch*) icnt_pop( m_shader_config->mem2device(i) ); m_memory_sub_partition[i]->push( mf, gpu_sim_cycle + gpu_tot_sim_cycle ); - partiton_reqs_in_parallel_per_cycle++; + if(mf) + partiton_reqs_in_parallel_per_cycle++; } m_memory_sub_partition[i]->cache_cycle(gpu_sim_cycle+gpu_tot_sim_cycle); m_memory_sub_partition[i]->accumulate_L2cache_stats(m_power_stats->pwr_mem_stat->l2_cache_stats[CURRENT_STAT_IDX]); @@ -1522,6 +1660,8 @@ void gpgpu_sim::cycle() // Update core icnt/cache stats for GPUWattch m_cluster[i]->get_icnt_stats(m_power_stats->pwr_mem_stat->n_simt_to_mem[CURRENT_STAT_IDX][i], m_power_stats->pwr_mem_stat->n_mem_to_simt[CURRENT_STAT_IDX][i]); m_cluster[i]->get_cache_stats(m_power_stats->pwr_mem_stat->core_cache_stats[CURRENT_STAT_IDX]); + m_cluster[i]->get_current_occupancy(gpu_occupancy.aggregate_warp_slot_filled, gpu_occupancy.aggregate_theoretical_warp_slots); + } float temp=0; for (unsigned i=0;i<m_shader_config->num_shader();i++){ @@ -1533,9 +1673,10 @@ void gpgpu_sim::cycle() if( g_single_step && ((gpu_sim_cycle+gpu_tot_sim_cycle) >= g_single_step) ) { - asm("int $03"); + raise(SIGTRAP); // Debug breakpoint } - gpu_sim_cycle++; + gpu_sim_cycle++; + if( g_interactive_debugger_enabled ) gpgpu_debug(); @@ -1548,12 +1689,12 @@ void gpgpu_sim::cycle() issue_block2core(); - // Depending on configuration, flush the caches once all of threads are completed. + // Depending on configuration, invalidate the caches once all of threads are completed. int all_threads_complete = 1; if (m_config.gpgpu_flush_l1_cache) { for (unsigned i=0;i<m_shader_config->n_simt_clusters;i++) { if (m_cluster[i]->get_not_completed() == 0) - m_cluster[i]->cache_flush(); + m_cluster[i]->cache_invalidate(); else all_threads_complete = 0 ; } @@ -1575,7 +1716,7 @@ void gpgpu_sim::cycle() int dlc = 0; for (unsigned i=0;i<m_memory_config->m_n_mem;i++) { dlc = m_memory_sub_partition[i]->flushL2(); - assert (dlc == 0); // need to model actual writes to DRAM here + assert (dlc == 0); // TODO: need to model actual writes to DRAM here printf("Dirty lines flushed from L2 %d is %d\n", i, dlc ); } } @@ -1587,15 +1728,20 @@ void gpgpu_sim::cycle() time_t curr_time; time(&curr_time); unsigned long long elapsed_time = MAX(curr_time - g_simulation_starttime, 1); - if ( (elapsed_time - last_liveness_message_time) >= m_config.liveness_message_freq ) { + if ( (elapsed_time - last_liveness_message_time) >= m_config.liveness_message_freq && DTRACE(LIVENESS) ) { days = elapsed_time/(3600*24); hrs = elapsed_time/3600 - 24*days; minutes = elapsed_time/60 - 60*(hrs + 24*days); sec = elapsed_time - 60*(minutes + 60*(hrs + 24*days)); - - DPRINTF(LIVENESS, "GPGPU-Sim uArch: cycles simulated: %lld inst.: %lld (ipc=%4.1f) sim_rate=%u (inst/sec) elapsed = %u:%u:%02u:%02u / %s", - gpu_tot_sim_cycle + gpu_sim_cycle, gpu_tot_sim_insn + gpu_sim_insn, + + unsigned long long active = 0, total = 0; + for (unsigned i=0;i<m_shader_config->n_simt_clusters;i++) { + m_cluster[i]->get_current_occupancy(active, total); + } + DPRINTF(LIVENESS, "uArch: inst.: %lld (ipc=%4.1f, occ=%0.4f\% [%llu / %llu]) sim_rate=%u (inst/sec) elapsed = %u:%u:%02u:%02u / %s", + gpu_tot_sim_insn + gpu_sim_insn, (double)gpu_sim_insn/(double)gpu_sim_cycle, + float(active)/float(total) * 100, active, total, (unsigned)((gpu_tot_sim_insn+gpu_sim_insn) / elapsed_time), (unsigned)days,(unsigned)hrs,(unsigned)minutes,(unsigned)sec, ctime(&curr_time)); @@ -1620,7 +1766,7 @@ void gpgpu_sim::cycle() } } - if (!(gpu_sim_cycle % 20000)) { + if (!(gpu_sim_cycle % 50000)) { // deadlock detection if (m_config.gpu_deadlock_detect && gpu_sim_insn == last_gpu_sim_insn) { gpu_deadlock = true; diff --git a/src/gpgpu-sim/gpu-sim.h b/src/gpgpu-sim/gpu-sim.h index 1778008..c14d0a7 100644 --- a/src/gpgpu-sim/gpu-sim.h +++ b/src/gpgpu-sim/gpu-sim.h @@ -62,8 +62,7 @@ #define SAMPLELOG 222 #define DUMPLOG 333 - - +extern tr1_hash_map<new_addr_type,unsigned> address_random_interleaving; enum dram_ctrl_t { @@ -291,11 +290,13 @@ struct memory_config { unsigned write_high_watermark; unsigned write_low_watermark; bool m_perf_sim_memcpy; + bool simple_dram_model; }; // global counters and flags (please try not to add to this list!!!) extern unsigned long long gpu_sim_cycle; extern unsigned long long gpu_tot_sim_cycle; +extern unsigned long long elapsed_cycles_sm_tot; extern bool g_interactive_debugger_enabled; class gpgpu_sim_config : public power_config, public gpgpu_functional_sim_config { @@ -335,6 +336,12 @@ public: unsigned num_shader() const { return m_shader_config.num_shader(); } unsigned num_cluster() const { return m_shader_config.n_simt_clusters; } unsigned get_max_concurrent_kernel() const { return max_concurrent_kernel; } + unsigned checkpoint_option; + + size_t stack_limit() const {return stack_size_limit; } + size_t heap_limit() const {return heap_size_limit; } + size_t sync_depth_limit() const {return runtime_sync_depth_limit; } + size_t pending_launch_count_limit() const {return runtime_pending_launch_count_limit;} private: void init_clock_domains(void ); @@ -376,13 +383,46 @@ private: int gpu_stat_sample_freq; int gpu_runtime_stat_flag; + // Device Limits + size_t stack_size_limit; + size_t heap_size_limit; + size_t runtime_sync_depth_limit; + size_t runtime_pending_launch_count_limit; - + //gpu compute capability options + unsigned int gpgpu_compute_capability_major; + unsigned int gpgpu_compute_capability_minor; unsigned long long liveness_message_freq; friend class gpgpu_sim; }; +struct occupancy_stats { + occupancy_stats() : aggregate_warp_slot_filled(0), aggregate_theoretical_warp_slots(0){} + occupancy_stats( unsigned long long wsf, unsigned long long tws ) + : aggregate_warp_slot_filled(wsf), aggregate_theoretical_warp_slots(tws){} + + unsigned long long aggregate_warp_slot_filled; + unsigned long long aggregate_theoretical_warp_slots; + + float get_occ_fraction() const { + return float(aggregate_warp_slot_filled) / float(aggregate_theoretical_warp_slots); + } + + occupancy_stats& operator+=(const occupancy_stats& rhs) { + aggregate_warp_slot_filled += rhs.aggregate_warp_slot_filled; + aggregate_theoretical_warp_slots += rhs.aggregate_theoretical_warp_slots; + return *this; + } + + occupancy_stats operator+(const occupancy_stats& rhs) const{ + return occupancy_stats( aggregate_warp_slot_filled + rhs.aggregate_warp_slot_filled, + aggregate_theoretical_warp_slots + rhs.aggregate_theoretical_warp_slots + ); + } +}; + + class gpgpu_sim : public gpgpu_t { public: gpgpu_sim( const gpgpu_sim_config &config ); @@ -410,9 +450,15 @@ public: void get_pdom_stack_top_info( unsigned sid, unsigned tid, unsigned *pc, unsigned *rpc ); int shared_mem_size() const; + int shared_mem_per_block() const; + int compute_capability_major() const; + int compute_capability_minor() const; int num_registers_per_core() const; + int num_registers_per_block() const; int wrp_size() const; int shader_clock() const; + int max_cta_per_core() const; + int get_max_cta( const kernel_info_t &k ) const; const struct cudaDeviceProp *get_prop() const; enum divergence_support_t simd_model() const; @@ -521,6 +567,9 @@ public: unsigned long long gpu_tot_sim_insn; unsigned long long gpu_sim_insn_last_update; unsigned gpu_sim_insn_last_update_sid; + occupancy_stats gpu_occupancy; + occupancy_stats gpu_tot_occupancy; + FuncCache get_cache_config(std::string kernel_name); void set_cache_config(std::string kernel_name, FuncCache cacheConfig ); @@ -549,4 +598,5 @@ public: } }; + #endif diff --git a/src/gpgpu-sim/icnt_wrapper.cc b/src/gpgpu-sim/icnt_wrapper.cc index ee58ece..6e0950c 100644 --- a/src/gpgpu-sim/icnt_wrapper.cc +++ b/src/gpgpu-sim/icnt_wrapper.cc @@ -29,6 +29,8 @@ #include <assert.h> #include "../intersim2/globals.hpp" #include "../intersim2/interconnect_interface.hpp" +#include "local_interconnect.h" + icnt_create_p icnt_create; icnt_init_p icnt_init; @@ -42,9 +44,13 @@ icnt_display_overall_stats_p icnt_display_overall_stats; icnt_display_state_p icnt_display_state; icnt_get_flit_size_p icnt_get_flit_size; -int g_network_mode; +unsigned g_network_mode; char* g_network_config_filename; + +struct inct_config g_inct_config; +LocalInterconnect *g_localicnt_interface; + #include "../option_parser.h" // Wrapper to intersim2 to accompany old icnt_wrapper @@ -105,10 +111,78 @@ static unsigned intersim2_get_flit_size() return g_icnt_interface->GetFlitSize(); } + +////////////////////////////////////////////////////// + +static void LocalInterconnect_create(unsigned int n_shader, unsigned int n_mem) +{ + g_localicnt_interface->CreateInterconnect(n_shader, n_mem); +} + +static void LocalInterconnect_init() +{ + g_localicnt_interface->Init(); +} + +static bool LocalInterconnect_has_buffer(unsigned input, unsigned int size) +{ + return g_localicnt_interface->HasBuffer(input, size); +} + +static void LocalInterconnect_push(unsigned input, unsigned output, void* data, unsigned int size) +{ + g_localicnt_interface->Push(input, output, data, size); +} + +static void* LocalInterconnect_pop(unsigned output) +{ + return g_localicnt_interface->Pop(output); +} + +static void LocalInterconnect_transfer() +{ + g_localicnt_interface->Advance(); +} + +static bool LocalInterconnect_busy() +{ + return g_localicnt_interface->Busy(); +} + +static void LocalInterconnect_display_stats() +{ + g_localicnt_interface->DisplayStats(); +} + +static void LocalInterconnect_display_overall_stats() +{ + g_localicnt_interface->DisplayOverallStats(); +} + +static void LocalInterconnect_display_state(FILE *fp) +{ + g_localicnt_interface->DisplayState(fp); +} + +static unsigned LocalInterconnect_get_flit_size() +{ + return g_localicnt_interface->GetFlitSize(); +} + + +/////////////////////////// + void icnt_reg_options( class OptionParser * opp ) { option_parser_register(opp, "-network_mode", OPT_INT32, &g_network_mode, "Interconnection network mode", "1"); option_parser_register(opp, "-inter_config_file", OPT_CSTR, &g_network_config_filename, "Interconnection network config file", "mesh"); + + + //parameters for local xbar + option_parser_register(opp, "-inct_in_buffer_limit", OPT_UINT32, &g_inct_config.in_buffer_limit, "in_buffer_limit", "64"); + option_parser_register(opp, "-inct_out_buffer_limit", OPT_UINT32, &g_inct_config.out_buffer_limit, "out_buffer_limit", "64"); + option_parser_register(opp, "-inct_subnets", OPT_UINT32, &g_inct_config.subnets, "subnets", "2"); + } void icnt_wrapper_init() @@ -129,6 +203,20 @@ void icnt_wrapper_init() icnt_display_state = intersim2_display_state; icnt_get_flit_size = intersim2_get_flit_size; break; + case LOCAL_XBAR: + g_localicnt_interface = LocalInterconnect::New(g_inct_config); + icnt_create = LocalInterconnect_create; + icnt_init = LocalInterconnect_init; + icnt_has_buffer = LocalInterconnect_has_buffer; + icnt_push = LocalInterconnect_push; + icnt_pop = LocalInterconnect_pop; + icnt_transfer = LocalInterconnect_transfer; + icnt_busy = LocalInterconnect_busy; + icnt_display_stats = LocalInterconnect_display_stats; + icnt_display_overall_stats = LocalInterconnect_display_overall_stats; + icnt_display_state = LocalInterconnect_display_state; + icnt_get_flit_size = LocalInterconnect_get_flit_size; + break; default: assert(0); break; diff --git a/src/gpgpu-sim/icnt_wrapper.h b/src/gpgpu-sim/icnt_wrapper.h index a4d123e..e1086f9 100644 --- a/src/gpgpu-sim/icnt_wrapper.h +++ b/src/gpgpu-sim/icnt_wrapper.h @@ -57,13 +57,16 @@ extern icnt_display_stats_p icnt_display_stats; extern icnt_display_overall_stats_p icnt_display_overall_stats; extern icnt_display_state_p icnt_display_state; extern icnt_get_flit_size_p icnt_get_flit_size; -extern int g_network_mode; +extern unsigned g_network_mode; enum network_mode { INTERSIM = 1, + LOCAL_XBAR = 2, N_NETWORK_MODE }; + + void icnt_wrapper_init(); void icnt_reg_options( class OptionParser * opp ); diff --git a/src/gpgpu-sim/l2cache.cc b/src/gpgpu-sim/l2cache.cc index b1465a8..f24a596 100644 --- a/src/gpgpu-sim/l2cache.cc +++ b/src/gpgpu-sim/l2cache.cc @@ -203,7 +203,67 @@ int memory_partition_unit::global_sub_partition_id_to_local_id(int global_sub_pa return (global_sub_partition_id - m_id * m_config->m_n_sub_partition_per_memory_channel); } -void memory_partition_unit::dram_cycle() +void memory_partition_unit::simple_dram_model_cycle() +{ + + // pop completed memory request from dram and push it to dram-to-L2 queue + // of the original sub partition + if (!m_dram_latency_queue.empty() && ( (gpu_sim_cycle+gpu_tot_sim_cycle) >= m_dram_latency_queue.front().ready_cycle )) { + mem_fetch* mf_return = m_dram_latency_queue.front().req; + if( mf_return->get_access_type() != L1_WRBK_ACC && mf_return->get_access_type() != L2_WRBK_ACC ) { + mf_return->set_reply(); + + unsigned dest_global_spid = mf_return->get_sub_partition_id(); + int dest_spid = global_sub_partition_id_to_local_id(dest_global_spid); + assert(m_sub_partition[dest_spid]->get_id() == dest_global_spid); + if (!m_sub_partition[dest_spid]->dram_L2_queue_full()) { + if( mf_return->get_access_type() == L1_WRBK_ACC ) { + m_sub_partition[dest_spid]->set_done(mf_return); + delete mf_return; + } else { + m_sub_partition[dest_spid]->dram_L2_queue_push(mf_return); + mf_return->set_status(IN_PARTITION_DRAM_TO_L2_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); + m_arbitration_metadata.return_credit(dest_spid); + MEMPART_DPRINTF("mem_fetch request %p return from dram to sub partition %d\n", mf_return, dest_spid); + } + m_dram_latency_queue.pop_front(); + } + + } else { + this->set_done(mf_return); + delete mf_return; + m_dram_latency_queue.pop_front(); + } + } + + // mem_fetch *mf = m_sub_partition[spid]->L2_dram_queue_top(); + //if( !m_dram->full(mf->is_write()) ) { + // L2->DRAM queue to DRAM latency queue + // Arbitrate among multiple L2 subpartitions + int last_issued_partition = m_arbitration_metadata.last_borrower(); + for (unsigned p = 0; p < m_config->m_n_sub_partition_per_memory_channel; p++) { + int spid = (p + last_issued_partition + 1) % m_config->m_n_sub_partition_per_memory_channel; + if (!m_sub_partition[spid]->L2_dram_queue_empty() && can_issue_to_dram(spid)) { + mem_fetch *mf = m_sub_partition[spid]->L2_dram_queue_top(); + if(m_dram->full(mf->is_write()) ) + break; + + m_sub_partition[spid]->L2_dram_queue_pop(); + MEMPART_DPRINTF("Issue mem_fetch request %p from sub partition %d to dram\n", mf, spid); + dram_delay_t d; + d.req = mf; + d.ready_cycle = gpu_sim_cycle+gpu_tot_sim_cycle + m_config->dram_latency; + m_dram_latency_queue.push_back(d); + mf->set_status(IN_PARTITION_DRAM_LATENCY_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); + m_arbitration_metadata.borrow_credit(spid); + break; // the DRAM should only accept one request per cycle + } + } + //} + +} + +void memory_partition_unit::dram_cycle() { // pop completed memory request from dram and push it to dram-to-L2 queue // of the original sub partition @@ -228,8 +288,8 @@ void memory_partition_unit::dram_cycle() m_dram->return_queue_pop(); } - m_dram->cycle(); - m_dram->dram_log(SAMPLELOG); + m_dram->cycle(); + m_dram->dram_log(SAMPLELOG); // mem_fetch *mf = m_sub_partition[spid]->L2_dram_queue_top(); //if( !m_dram->full(mf->is_write()) ) { @@ -257,12 +317,11 @@ void memory_partition_unit::dram_cycle() //} // DRAM latency queue - - if( !m_dram_latency_queue.empty() && ( (gpu_sim_cycle+gpu_tot_sim_cycle) >= m_dram_latency_queue.front().ready_cycle ) && !m_dram->full(m_dram_latency_queue.front().req->is_write()) ) { - mem_fetch* mf = m_dram_latency_queue.front().req; - m_dram_latency_queue.pop_front(); - m_dram->push(mf); - } + if( !m_dram_latency_queue.empty() && ( (gpu_sim_cycle+gpu_tot_sim_cycle) >= m_dram_latency_queue.front().ready_cycle ) && !m_dram->full(m_dram_latency_queue.front().req->is_write()) ) { + mem_fetch* mf = m_dram_latency_queue.front().req; + m_dram_latency_queue.pop_front(); + m_dram->push(mf); + } } void memory_partition_unit::set_done( mem_fetch *mf ) @@ -362,10 +421,11 @@ void memory_sub_partition::cache_cycle( unsigned cycle ) }else{ if(m_config->m_L2_config.m_write_alloc_policy == FETCH_ON_WRITE) { - assert(mf->original_wr_mf); - mf->original_wr_mf->set_reply(); - mf->original_wr_mf->set_status(IN_PARTITION_L2_TO_ICNT_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); - m_L2_icnt_queue->push(mf->original_wr_mf); + mem_fetch* original_wr_mf = mf->get_original_wr_mf(); + assert(original_wr_mf); + original_wr_mf->set_reply(); + original_wr_mf->set_status(IN_PARTITION_L2_TO_ICNT_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); + m_L2_icnt_queue->push(original_wr_mf); } m_request_tracker.erase(mf); delete mf; @@ -428,7 +488,7 @@ void memory_sub_partition::cache_cycle( unsigned cycle ) m_icnt_L2_queue->pop(); } } else if ( status != RESERVATION_FAIL ) { - if(mf->is_write() && m_config->m_L2_config.m_write_alloc_policy == FETCH_ON_WRITE && !was_writeallocate_sent(events)) { + if(mf->is_write() && (m_config->m_L2_config.m_write_alloc_policy == FETCH_ON_WRITE || m_config->m_L2_config.m_write_alloc_policy == LAZY_FETCH_ON_READ) && !was_writeallocate_sent(events)) { mf->set_reply(); mf->set_status(IN_PARTITION_L2_TO_ICNT_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); m_L2_icnt_queue->push(mf); @@ -518,14 +578,23 @@ void memory_sub_partition::print( FILE *fp ) const void memory_stats_t::visualizer_print( gzFile visualizer_file ) { - // gzprintf(visualizer_file, "Ltwowritemiss: %d\n", L2_write_miss); - // gzprintf(visualizer_file, "Ltwowritehit: %d\n", L2_write_access-L2_write_miss); - // gzprintf(visualizer_file, "Ltworeadmiss: %d\n", L2_read_miss); - // gzprintf(visualizer_file, "Ltworeadhit: %d\n", L2_read_access-L2_read_miss); + gzprintf(visualizer_file, "Ltwowritemiss: %d\n", L2_write_miss); + gzprintf(visualizer_file, "Ltwowritehit: %d\n", L2_write_hit); + gzprintf(visualizer_file, "Ltworeadmiss: %d\n", L2_read_miss); + gzprintf(visualizer_file, "Ltworeadhit: %d\n", L2_read_hit); + clear_L2_stats_pw(); + if (num_mfs) gzprintf(visualizer_file, "averagemflatency: %lld\n", mf_total_lat/num_mfs); } +void memory_stats_t::clear_L2_stats_pw(){ + L2_write_miss = 0; + L2_write_hit = 0; + L2_read_miss = 0; + L2_read_hit = 0; +} + void gpgpu_sim::print_dram_stats(FILE *fout) const { unsigned cmd=0; @@ -568,7 +637,15 @@ unsigned memory_sub_partition::flushL2() if (!m_config->m_L2_config.disabled()) { m_L2cache->flush(); } - return 0; // L2 is read only in this version + return 0; //TODO: write the flushed data to the main memory +} + +unsigned memory_sub_partition::invalidateL2() +{ + if (!m_config->m_L2_config.disabled()) { + m_L2cache->invalidate(); + } + return 0; } bool memory_sub_partition::busy() const @@ -600,7 +677,7 @@ std::vector<mem_fetch*> memory_sub_partition::breakdown_request_to_sector_reques } else { printf("Invalid sector received, address = 0x%06x, sector mask = %s, data size = %d", - mf->get_addr(), mf->get_access_sector_mask(), mf->get_data_size(), mf->get_data_size()); + mf->get_addr(), mf->get_access_sector_mask(), mf->get_data_size()); assert(0 && "Undefined sector mask is received"); } @@ -631,7 +708,11 @@ std::vector<mem_fetch*> memory_sub_partition::breakdown_request_to_sector_reques result.push_back(n_mf); byte_sector_mask <<= SECTOR_SIZE; } - } else assert(0 && "Undefined data size is received"); + } else { + printf("Invalid sector received, address = 0x%06x, sector mask = %d, byte mask = , data size = %d", + mf->get_addr(), mf->get_access_sector_mask().count(), mf->get_data_size()); + assert(0 && "Undefined data size is received"); + } return result; } @@ -705,8 +786,29 @@ void memory_sub_partition::get_L2cache_sub_stats(struct cache_sub_stats &css) co } } +void memory_sub_partition::get_L2cache_sub_stats_pw(struct cache_sub_stats_pw &css) const{ + if (!m_config->m_L2_config.disabled()) { + m_L2cache->get_sub_stats_pw(css); + } +} + +void memory_sub_partition::clear_L2cache_stats_pw() { + if (!m_config->m_L2_config.disabled()) { + m_L2cache->clear_pw(); + } +} + void memory_sub_partition::visualizer_print( gzFile visualizer_file ) { - // TODO: Add visualizer stats for L2 cache -} + // Support for L2 AerialVision stats + // Per-sub-partition stats would be trivial to extend from this + cache_sub_stats_pw temp_sub_stats; + get_L2cache_sub_stats_pw(temp_sub_stats); + m_stats->L2_read_miss += temp_sub_stats.read_misses; + m_stats->L2_write_miss += temp_sub_stats.write_misses; + m_stats->L2_read_hit += temp_sub_stats.read_hits; + m_stats->L2_write_hit += temp_sub_stats.write_hits; + + clear_L2cache_stats_pw(); +} diff --git a/src/gpgpu-sim/l2cache.h b/src/gpgpu-sim/l2cache.h index 2d13918..9a51c0e 100644 --- a/src/gpgpu-sim/l2cache.h +++ b/src/gpgpu-sim/l2cache.h @@ -65,6 +65,7 @@ public: void cache_cycle( unsigned cycle ); void dram_cycle(); + void simple_dram_model_cycle(); void set_done( mem_fetch *mf ); @@ -162,6 +163,7 @@ public: void set_done( mem_fetch *mf ); unsigned flushL2(); + unsigned invalidateL2(); // interface to L2_dram_queue bool L2_dram_queue_empty() const; @@ -179,6 +181,10 @@ public: void accumulate_L2cache_stats(class cache_stats &l2_stats) const; void get_L2cache_sub_stats(struct cache_sub_stats &css) const; + // Support for getting per-window L2 stats for AerialVision + void get_L2cache_sub_stats_pw(struct cache_sub_stats_pw &css) const; + void clear_L2cache_stats_pw(); + void force_l2_tag_update(new_addr_type addr, unsigned time, mem_access_sector_mask_t mask) { m_L2cache->force_tag_access( addr, m_memcpy_cycle_offset + time, mask ); diff --git a/src/gpgpu-sim/local_interconnect.cc b/src/gpgpu-sim/local_interconnect.cc new file mode 100644 index 0000000..66d6648 --- /dev/null +++ b/src/gpgpu-sim/local_interconnect.cc @@ -0,0 +1,301 @@ +// Copyright (c) 2019, Mahmoud Khairy +// Purdue University +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// Neither the name of 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. + +#include <fstream> +#include <iostream> +#include <sstream> +#include <iomanip> +#include <cmath> +#include <utility> +#include <algorithm> + +#include "local_interconnect.h" +#include "mem_fetch.h" + +xbar_router::xbar_router(unsigned router_id, enum Interconnect_type m_type, unsigned n_shader, unsigned n_mem, unsigned m_in_buffer_limit, unsigned m_out_buffer_limit) +{ + m_id=router_id; + router_type=m_type; + _n_mem = n_mem; + _n_shader = n_shader; + total_nodes = n_shader+n_mem; + in_buffers.resize(total_nodes); + out_buffers.resize(total_nodes); + next_node=0; + in_buffer_limit = m_in_buffer_limit; + out_buffer_limit = m_out_buffer_limit; + if(m_type == REQ_NET) { + active_in_buffers=n_shader; + active_out_buffers=n_mem; + } + else if(m_type == REPLY_NET) { + active_in_buffers=n_mem; + active_out_buffers=n_shader; + } + + cycles = 0; + conflicts= 0; + out_buffer_full=0; + in_buffer_full=0; + out_buffer_util=0; + in_buffer_util=0; + packets_num=0; +} + + +xbar_router::~xbar_router() +{ + +} + +void xbar_router::Push(unsigned input_deviceID, unsigned output_deviceID, void* data, unsigned int size) +{ + assert(input_deviceID < total_nodes); + in_buffers[input_deviceID].push(Packet(data, output_deviceID)); + packets_num++; +} + +void* xbar_router::Pop(unsigned ouput_deviceID) +{ + assert(ouput_deviceID < total_nodes); + void* data = NULL; + + if(!out_buffers[ouput_deviceID].empty()) { + data = out_buffers[ouput_deviceID].front().data; + out_buffers[ouput_deviceID].pop(); + } + + return data; +} + + +bool xbar_router::Has_Buffer_In(unsigned input_deviceID, unsigned size, bool update_counter){ + + assert(input_deviceID < total_nodes); + + bool has_buffer = (in_buffers[input_deviceID].size() + size <= in_buffer_limit); + if(update_counter && !has_buffer) + in_buffer_full++; + + return has_buffer; + +} + +bool xbar_router::Has_Buffer_Out(unsigned output_deviceID, unsigned size){ + return (out_buffers[output_deviceID].size() + size <= out_buffer_limit); +} + +void xbar_router::Advance() { + cycles++; + + vector<bool> issued(total_nodes, false); + + for(unsigned i=0; i<total_nodes; ++i){ + unsigned node_id = (i+next_node)%total_nodes; + + if(!in_buffers[node_id].empty()) { + Packet _packet = in_buffers[node_id].front(); + //ensure that the outbuffer has space and not issued before in this cycle + if(Has_Buffer_Out(_packet.output_deviceID, 1)){ + if(!issued[_packet.output_deviceID]) { + out_buffers[_packet.output_deviceID].push(_packet); + in_buffers[node_id].pop(); + issued[_packet.output_deviceID]=true; + } + else + conflicts++; + } + else + out_buffer_full++; + } + } + + next_node = (++next_node % total_nodes); + + //collect some stats about buffer util + for(unsigned i=0; i<total_nodes; ++i){ + in_buffer_util+=in_buffers[i].size(); + out_buffer_util+=out_buffers[i].size(); + } +} + +bool xbar_router::Busy() const { + + for(unsigned i=0; i<total_nodes; ++i){ + if(!in_buffers[i].empty()) + return true; + + if(!out_buffers[i].empty()) + return true; + } + return false; +} + + +//////////////////////////////////////////////////// +/////////////LocalInterconnect///////////////////// + +//assume all the packets are one flit +#define LOCAL_INCT_FLIT_SIZE 40 + +LocalInterconnect* LocalInterconnect::New(const struct inct_config& m_localinct_config) +{ + + LocalInterconnect* icnt_interface = new LocalInterconnect(m_localinct_config); + + return icnt_interface; +} + +LocalInterconnect::LocalInterconnect(const struct inct_config& m_localinct_config): m_inct_config(m_localinct_config){ + n_shader=0; + n_mem=0; + n_subnets = m_localinct_config.subnets; +} + +LocalInterconnect::~LocalInterconnect(){ + for (int i=0; i<m_inct_config.subnets; ++i) { + delete net[i]; + } +} + +void LocalInterconnect::CreateInterconnect(unsigned m_n_shader, unsigned m_n_mem){ + n_shader = m_n_shader; + n_mem = m_n_mem; + + net.resize(n_subnets); + for (unsigned i = 0; i < n_subnets; ++i) { + net[i] = new xbar_router( i, static_cast<Interconnect_type>(i), m_n_shader, m_n_mem, m_inct_config.in_buffer_limit, m_inct_config.out_buffer_limit ); + } + +} + + +void LocalInterconnect::Init() { + //empty + //there is nothing to do + +} + +void LocalInterconnect::Push(unsigned input_deviceID, unsigned output_deviceID, void* data, unsigned int size){ + + unsigned subnet; + if (n_subnets == 1) { + subnet = 0; + } else { + if (input_deviceID < n_shader ) { + subnet = 0; + } else { + subnet = 1; + } + } + + // it should have free buffer + //assume all the packets have size of one + //no flits are implemented + assert(net[subnet]->Has_Buffer_In(input_deviceID, 1)); + + net[subnet]->Push(input_deviceID, output_deviceID, data, size); + +} + +void* LocalInterconnect::Pop(unsigned ouput_deviceID){ + + // 0-_n_shader-1 indicates reply(network 1), otherwise request(network 0) + int subnet = 0; + if (ouput_deviceID < n_shader) + subnet = 1; + + return net[subnet]->Pop(ouput_deviceID); + +} + +void LocalInterconnect::Advance(){ + + for (unsigned i = 0; i < n_subnets; ++i) { + net[i]->Advance(); + } + +} + +bool LocalInterconnect::Busy() const{ + + for (unsigned i = 0; i < n_subnets; ++i) { + if(net[i]->Busy()) + return true; + } + return false; +} + +bool LocalInterconnect::HasBuffer(unsigned deviceID, unsigned int size) const{ + + bool has_buffer = false; + + if ((n_subnets>1) && deviceID >= n_shader) // deviceID is memory node + has_buffer = net[REPLY_NET]->Has_Buffer_In(deviceID, 1, true); + else + has_buffer = net[REQ_NET]->Has_Buffer_In(deviceID, 1, true); + + return has_buffer; + +} + +void LocalInterconnect::DisplayStats() const{ + + cout<<"Req_Network_injected_packets_num = "<<net[REQ_NET]->packets_num<<endl; + cout<<"Req_Network_cycles = "<<net[REQ_NET]->cycles<<endl; + cout<<"Req_Network_injected_packets_per_cycle = "<<(float)(net[REQ_NET]->packets_num) / (net[REQ_NET]->cycles)<<endl; + cout<<"Req_Network_conflicts_per_cycle = "<<(float)(net[REQ_NET]->conflicts) / (net[REQ_NET]->cycles)<<endl; + cout<<"Req_Network_in_buffer_full_per_cycle = "<<(float)(net[REQ_NET]->in_buffer_full) / (net[REQ_NET]->cycles)<<endl; + cout<<"Req_Network_in_buffer_avg_util = "<<((float)(net[REQ_NET]->in_buffer_util) / (net[REQ_NET]->cycles) / net[REQ_NET]->active_in_buffers)<<endl; + cout<<"Req_Network_out_buffer_full_per_cycle = "<<(float)(net[REQ_NET]->out_buffer_full) / (net[REQ_NET]->cycles)<<endl; + cout<<"Req_Network_out_buffer_avg_util = "<<((float)(net[REQ_NET]->out_buffer_util) / (net[REQ_NET]->cycles) / net[REQ_NET]->active_out_buffers)<<endl; + + cout<<endl; + cout<<"Reply_Network_injected_packets_num = "<<net[REPLY_NET]->packets_num<<endl; + cout<<"Reply_Network_cycles = "<<net[REPLY_NET]->cycles<<endl; + cout<<"Reply_Network_injected_packets_per_cycle = "<<(float)(net[REPLY_NET]->packets_num) / (net[REPLY_NET]->cycles)<<endl; + cout<<"Reply_Network_conflicts_per_cycle = "<<(float)(net[REPLY_NET]->conflicts) / (net[REPLY_NET]->cycles)<<endl; + cout<<"Reply_Network_in_buffer_full_per_cycle = "<<(float)(net[REPLY_NET]->in_buffer_full) / (net[REPLY_NET]->cycles)<<endl; + cout<<"Reply_Network_in_buffer_avg_util = "<<((float)(net[REPLY_NET]->in_buffer_util) / (net[REPLY_NET]->cycles) / net[REPLY_NET]->active_in_buffers)<<endl; + cout<<"Reply_Network_out_buffer_full_per_cycle = "<<(float)(net[REPLY_NET]->out_buffer_full) / (net[REPLY_NET]->cycles)<<endl; + cout<<"Reply_Network_out_buffer_avg_util= "<<((float)(net[REPLY_NET]->out_buffer_util) / (net[REPLY_NET]->cycles) / net[REPLY_NET]->active_out_buffers)<<endl; + +} + +void LocalInterconnect::DisplayOverallStats() const{ + +} + +unsigned LocalInterconnect::GetFlitSize() const{ + return LOCAL_INCT_FLIT_SIZE; +} + +void LocalInterconnect::DisplayState(FILE* fp) const{ + + fprintf(fp, "GPGPU-Sim uArch: ICNT:Display State: Under implementation\n"); +} + diff --git a/src/gpgpu-sim/local_interconnect.h b/src/gpgpu-sim/local_interconnect.h new file mode 100644 index 0000000..502c80d --- /dev/null +++ b/src/gpgpu-sim/local_interconnect.h @@ -0,0 +1,127 @@ +// Copyright (c) 2019, Mahmoud Khairy +// Purdue University +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// Neither the name of 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. + +#ifndef _LOCAL_INTERCONNECT_HPP_ +#define _LOCAL_INTERCONNECT_HPP_ + +#include <vector> +#include <queue> +#include <iostream> +#include <map> +using namespace std; + + +struct inct_config +{ + + //config for local interconnect + unsigned in_buffer_limit; + unsigned out_buffer_limit; + unsigned subnets; +}; + +enum Interconnect_type { + REQ_NET=0, + REPLY_NET=1 +}; +class xbar_router { + +public: + xbar_router(unsigned router_id, enum Interconnect_type m_type, unsigned n_shader, unsigned n_mem, unsigned m_in_buffer_limit, unsigned m_out_buffer_limit); + ~xbar_router(); + void Push(unsigned input_deviceID, unsigned output_deviceID, void* data, unsigned int size); + void* Pop(unsigned ouput_deviceID); + void Advance(); + bool Busy() const; + bool Has_Buffer_In(unsigned input_deviceID, unsigned size, bool update_counter=false); + bool Has_Buffer_Out(unsigned output_deviceID, unsigned size); + + //some stats + unsigned long long cycles; + unsigned long long conflicts; + unsigned long long out_buffer_full; + unsigned long long out_buffer_util; + unsigned long long in_buffer_full; + unsigned long long in_buffer_util; + unsigned long long packets_num; + +private: + struct Packet{ + Packet(void* m_data, unsigned m_output_deviceID) { + data = m_data; + output_deviceID = m_output_deviceID; + } + void* data; + unsigned output_deviceID; + }; + vector<queue<Packet> > in_buffers; + vector<queue<Packet> > out_buffers; + unsigned _n_shader, _n_mem, total_nodes; + unsigned in_buffer_limit, out_buffer_limit; + unsigned next_node; + unsigned m_id; + enum Interconnect_type router_type; + unsigned active_in_buffers,active_out_buffers; + + friend class LocalInterconnect; + +}; + +class LocalInterconnect { +public: + LocalInterconnect(const struct inct_config& m_localinct_config); + ~LocalInterconnect(); + static LocalInterconnect* New(const struct inct_config& m_inct_config); + void CreateInterconnect(unsigned n_shader, unsigned n_mem); + + //node side functions + void Init(); + void Push(unsigned input_deviceID, unsigned output_deviceID, void* data, unsigned int size); + void* Pop(unsigned ouput_deviceID); + void Advance(); + bool Busy() const; + bool HasBuffer(unsigned deviceID, unsigned int size) const; + void DisplayStats() const; + void DisplayOverallStats() const; + unsigned GetFlitSize() const; + + void DisplayState(FILE* fp) const; + + +protected: + + const inct_config& m_inct_config; + + unsigned n_shader, n_mem; + unsigned n_subnets; + vector<xbar_router *> net; + +}; + +#endif + + diff --git a/src/gpgpu-sim/mem_fetch.cc b/src/gpgpu-sim/mem_fetch.cc index c05a693..a260a35 100644 --- a/src/gpgpu-sim/mem_fetch.cc +++ b/src/gpgpu-sim/mem_fetch.cc @@ -39,9 +39,10 @@ mem_fetch::mem_fetch( const mem_access_t &access, unsigned wid, unsigned sid, unsigned tpc, - const class memory_config *config, + const struct memory_config *config, mem_fetch *m_original_mf, mem_fetch *m_original_wr_mf) + { m_request_uid = sm_next_mf_request_uid++; m_access = access; diff --git a/src/gpgpu-sim/mem_fetch.h b/src/gpgpu-sim/mem_fetch.h index 278cf32..e5efffd 100644 --- a/src/gpgpu-sim/mem_fetch.h +++ b/src/gpgpu-sim/mem_fetch.h @@ -55,7 +55,7 @@ public: unsigned wid, unsigned sid, unsigned tpc, - const class memory_config *config, + const struct memory_config *config, mem_fetch *original_mf = NULL, mem_fetch *original_wr_mf = NULL); ~mem_fetch(); @@ -115,8 +115,10 @@ public: const memory_config *get_mem_config(){return m_mem_config;} unsigned get_num_flits(bool simt_to_mem); - mem_fetch* original_mf; - mem_fetch* original_wr_mf; + + mem_fetch* get_original_mf() { return original_mf; } + mem_fetch* get_original_wr_mf() { return original_wr_mf; } + private: // request source information unsigned m_request_uid; @@ -146,8 +148,12 @@ private: static unsigned sm_next_mf_request_uid; - const class memory_config *m_mem_config; + const struct memory_config *m_mem_config; unsigned icnt_flit_size; + + mem_fetch* original_mf; //this pointer is set up when a request is divided into sector requests at L2 cache (if the req size > L2 sector size), so the pointer refers to the original request + mem_fetch* original_wr_mf; //this pointer refers to the original write req, when fetch-on-write policy is used + }; #endif diff --git a/src/gpgpu-sim/mem_latency_stat.cc b/src/gpgpu-sim/mem_latency_stat.cc index c5452b9..11624f4 100644 --- a/src/gpgpu-sim/mem_latency_stat.cc +++ b/src/gpgpu-sim/mem_latency_stat.cc @@ -129,6 +129,12 @@ memory_stats_t::memory_stats_t( unsigned n_shader, const struct shader_core_conf } } + // AerialVision L2 stats + L2_read_miss = 0; + L2_write_miss = 0; + L2_read_hit = 0; + L2_write_hit = 0; + L2_cbtoL2length = (unsigned int*) calloc(mem_config->m_n_mem, sizeof(unsigned int)); L2_cbtoL2writelength = (unsigned int*) calloc(mem_config->m_n_mem, sizeof(unsigned int)); L2_L2tocblength = (unsigned int*) calloc(mem_config->m_n_mem, sizeof(unsigned int)); @@ -366,7 +372,7 @@ void memory_stats_t::memlatstat_print( unsigned n_mem, unsigned gpu_mem_n_bk ) m = 0; printf("\n"); } - printf("total reads: %d\n", k); + printf("total dram reads = %d\n", k); if (min_bank_accesses) printf("bank skew: %d/%d = %4.2f\n", max_bank_accesses, min_bank_accesses, (float)max_bank_accesses/min_bank_accesses); else @@ -404,7 +410,7 @@ void memory_stats_t::memlatstat_print( unsigned n_mem, unsigned gpu_mem_n_bk ) m = 0; printf("\n"); } - printf("total reads: %d\n", k); + printf("total dram writes = %d\n", k); if (min_bank_accesses) printf("bank skew: %d/%d = %4.2f\n", max_bank_accesses, min_bank_accesses, (float)max_bank_accesses/min_bank_accesses); else diff --git a/src/gpgpu-sim/mem_latency_stat.h b/src/gpgpu-sim/mem_latency_stat.h index 5b89202..982b9ae 100644 --- a/src/gpgpu-sim/mem_latency_stat.h +++ b/src/gpgpu-sim/mem_latency_stat.h @@ -47,6 +47,9 @@ public: void visualizer_print( gzFile visualizer_file ); + // Reset local L2 stats that are aggregated each sampling window + void clear_L2_stats_pw(); + unsigned m_n_shader; const struct shader_core_config *m_shader_config; @@ -84,6 +87,11 @@ public: unsigned ***mem_access_type_stats; // dram access type classification + // AerialVision L2 stats + unsigned L2_read_miss; + unsigned L2_write_miss; + unsigned L2_read_hit; + unsigned L2_write_hit; // L2 cache stats unsigned int *L2_cbtoL2length; diff --git a/src/gpgpu-sim/scoreboard.cc b/src/gpgpu-sim/scoreboard.cc index f412054..ebec891 100644 --- a/src/gpgpu-sim/scoreboard.cc +++ b/src/gpgpu-sim/scoreboard.cc @@ -82,7 +82,7 @@ const bool Scoreboard::islongop (unsigned warp_id,unsigned regnum) { void Scoreboard::reserveRegisters(const class warp_inst_t* inst) { - for( unsigned r=0; r < 4; r++) { + for( unsigned r=0; r < MAX_OUTPUT_VALUES; r++) { if(inst->out[r] > 0) { reserveRegister(inst->warp_id(), inst->out[r]); SHADER_DPRINTF( SCOREBOARD, @@ -100,7 +100,7 @@ void Scoreboard::reserveRegisters(const class warp_inst_t* inst) inst->space.get_type() == param_space_local || inst->space.get_type() == param_space_unclassified || inst->space.get_type() == tex_space)){ - for ( unsigned r=0; r<4; r++) { + for ( unsigned r=0; r<MAX_OUTPUT_VALUES; r++) { if(inst->out[r] > 0) { SHADER_DPRINTF( SCOREBOARD, "New longopreg marked - warp:%d, reg: %d\n", @@ -115,7 +115,7 @@ void Scoreboard::reserveRegisters(const class warp_inst_t* inst) // Release registers for an instruction void Scoreboard::releaseRegisters(const class warp_inst_t *inst) { - for( unsigned r=0; r < 4; r++) { + for( unsigned r=0; r < MAX_OUTPUT_VALUES; r++) { if(inst->out[r] > 0) { SHADER_DPRINTF( SCOREBOARD, "Register Released - warp:%d, reg: %d\n", @@ -138,15 +138,13 @@ bool Scoreboard::checkCollision( unsigned wid, const class inst_t *inst ) const // Get list of all input and output registers std::set<int> inst_regs; - if(inst->out[0] > 0) inst_regs.insert(inst->out[0]); - if(inst->out[1] > 0) inst_regs.insert(inst->out[1]); - if(inst->out[2] > 0) inst_regs.insert(inst->out[2]); - if(inst->out[3] > 0) inst_regs.insert(inst->out[3]); - if(inst->in[0] > 0) inst_regs.insert(inst->in[0]); - if(inst->in[1] > 0) inst_regs.insert(inst->in[1]); - if(inst->in[2] > 0) inst_regs.insert(inst->in[2]); - if(inst->in[3] > 0) inst_regs.insert(inst->in[3]); - if(inst->pred > 0) inst_regs.insert(inst->pred); + for(int iii=0;iii<inst->outcount;iii++) + inst_regs.insert(inst->out[iii]); + + for(int jjj=0;jjj<inst->incount;jjj++) + inst_regs.insert(inst->in[jjj]); + + if(inst->pred > 0) inst_regs.insert(inst->pred); if(inst->ar1 > 0) inst_regs.insert(inst->ar1); if(inst->ar2 > 0) inst_regs.insert(inst->ar2); diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc index d2f40a1..e38eefd 100644 --- a/src/gpgpu-sim/shader.cc +++ b/src/gpgpu-sim/shader.cc @@ -74,7 +74,7 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, shader_core_stats *stats ) : core_t( gpu, NULL, config->warp_size, config->n_thread_per_shader ), m_barriers( this, config->max_warps_per_shader, config->max_cta_per_core, config->max_barriers_per_cta, config->warp_size ), - m_dynamic_warp_id(0) + m_dynamic_warp_id(0), m_active_warps(0) { m_cluster = cluster; m_config = config; @@ -90,6 +90,18 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, for (int j = 0; j<N_PIPELINE_STAGES; j++) { m_pipeline_reg.push_back(register_set(m_config->pipe_widths[j],pipeline_stage_name_decode[j])); } + if(m_config->sub_core_model) { + //in subcore model, each scheduler should has its own issue register, so num scheduler = reg width + assert(m_config->gpgpu_num_sched_per_core == m_pipeline_reg[ID_OC_SP].get_size() ); + assert(m_config->gpgpu_num_sched_per_core == m_pipeline_reg[ID_OC_SFU].get_size() ); + assert(m_config->gpgpu_num_sched_per_core == m_pipeline_reg[ID_OC_MEM].get_size() ); + if(m_config->gpgpu_tensor_core_avail) + assert(m_config->gpgpu_num_sched_per_core == m_pipeline_reg[ID_OC_TENSOR_CORE].get_size() ); + if(m_config->gpgpu_num_dp_units > 0) + assert(m_config->gpgpu_num_sched_per_core == m_pipeline_reg[ID_OC_DP].get_size() ); + if(m_config->gpgpu_num_int_units > 0) + assert(m_config->gpgpu_num_sched_per_core == m_pipeline_reg[ID_OC_INT].get_size() ); + } m_threadState = (thread_ctx_t*) calloc(sizeof(thread_ctx_t), config->n_thread_per_shader); @@ -152,6 +164,8 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, &m_pipeline_reg[ID_OC_SP], &m_pipeline_reg[ID_OC_DP], &m_pipeline_reg[ID_OC_SFU], + &m_pipeline_reg[ID_OC_INT], + &m_pipeline_reg[ID_OC_TENSOR_CORE], &m_pipeline_reg[ID_OC_MEM], i ) @@ -167,6 +181,8 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, &m_pipeline_reg[ID_OC_SP], &m_pipeline_reg[ID_OC_DP], &m_pipeline_reg[ID_OC_SFU], + &m_pipeline_reg[ID_OC_INT], + &m_pipeline_reg[ID_OC_TENSOR_CORE], &m_pipeline_reg[ID_OC_MEM], i, config->gpgpu_scheduler_string @@ -183,6 +199,8 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, &m_pipeline_reg[ID_OC_SP], &m_pipeline_reg[ID_OC_DP], &m_pipeline_reg[ID_OC_SFU], + &m_pipeline_reg[ID_OC_INT], + &m_pipeline_reg[ID_OC_TENSOR_CORE], &m_pipeline_reg[ID_OC_MEM], i ) @@ -198,6 +216,8 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, &m_pipeline_reg[ID_OC_SP], &m_pipeline_reg[ID_OC_DP], &m_pipeline_reg[ID_OC_SFU], + &m_pipeline_reg[ID_OC_INT], + &m_pipeline_reg[ID_OC_TENSOR_CORE], &m_pipeline_reg[ID_OC_MEM], i ) @@ -213,6 +233,8 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, &m_pipeline_reg[ID_OC_SP], &m_pipeline_reg[ID_OC_DP], &m_pipeline_reg[ID_OC_SFU], + &m_pipeline_reg[ID_OC_INT], + &m_pipeline_reg[ID_OC_TENSOR_CORE], &m_pipeline_reg[ID_OC_MEM], i, config->gpgpu_scheduler_string @@ -233,53 +255,16 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, } //op collector configuration - enum { SP_CUS, DP_CUS, SFU_CUS, MEM_CUS, GEN_CUS }; - m_operand_collector.add_cu_set(SP_CUS, m_config->gpgpu_operand_collector_num_units_sp, m_config->gpgpu_operand_collector_num_out_ports_sp); - m_operand_collector.add_cu_set(DP_CUS, m_config->gpgpu_operand_collector_num_units_dp, m_config->gpgpu_operand_collector_num_out_ports_dp); - m_operand_collector.add_cu_set(SFU_CUS, m_config->gpgpu_operand_collector_num_units_sfu, m_config->gpgpu_operand_collector_num_out_ports_sfu); - m_operand_collector.add_cu_set(MEM_CUS, m_config->gpgpu_operand_collector_num_units_mem, m_config->gpgpu_operand_collector_num_out_ports_mem); - m_operand_collector.add_cu_set(GEN_CUS, m_config->gpgpu_operand_collector_num_units_gen, m_config->gpgpu_operand_collector_num_out_ports_gen); - + + enum { SP_CUS, DP_CUS, SFU_CUS, TENSOR_CORE_CUS, INT_CUS, MEM_CUS, GEN_CUS }; + opndcoll_rfu_t::port_vector_t in_ports; opndcoll_rfu_t::port_vector_t out_ports; opndcoll_rfu_t::uint_vector_t cu_sets; - for (unsigned i = 0; i < m_config->gpgpu_operand_collector_num_in_ports_sp; i++) { - in_ports.push_back(&m_pipeline_reg[ID_OC_SP]); - out_ports.push_back(&m_pipeline_reg[OC_EX_SP]); - cu_sets.push_back((unsigned)SP_CUS); - cu_sets.push_back((unsigned)GEN_CUS); - m_operand_collector.add_port(in_ports,out_ports,cu_sets); - in_ports.clear(),out_ports.clear(),cu_sets.clear(); - } - - for (unsigned i = 0; i < m_config->gpgpu_operand_collector_num_in_ports_dp; i++) { - in_ports.push_back(&m_pipeline_reg[ID_OC_DP]); - out_ports.push_back(&m_pipeline_reg[OC_EX_DP]); - cu_sets.push_back((unsigned)DP_CUS); - cu_sets.push_back((unsigned)GEN_CUS); - m_operand_collector.add_port(in_ports,out_ports,cu_sets); - in_ports.clear(),out_ports.clear(),cu_sets.clear(); - } - for (unsigned i = 0; i < m_config->gpgpu_operand_collector_num_in_ports_sfu; i++) { - in_ports.push_back(&m_pipeline_reg[ID_OC_SFU]); - out_ports.push_back(&m_pipeline_reg[OC_EX_SFU]); - cu_sets.push_back((unsigned)SFU_CUS); - cu_sets.push_back((unsigned)GEN_CUS); - m_operand_collector.add_port(in_ports,out_ports,cu_sets); - in_ports.clear(),out_ports.clear(),cu_sets.clear(); - } - - for (unsigned i = 0; i < m_config->gpgpu_operand_collector_num_in_ports_mem; i++) { - in_ports.push_back(&m_pipeline_reg[ID_OC_MEM]); - out_ports.push_back(&m_pipeline_reg[OC_EX_MEM]); - cu_sets.push_back((unsigned)MEM_CUS); - cu_sets.push_back((unsigned)GEN_CUS); - m_operand_collector.add_port(in_ports,out_ports,cu_sets); - in_ports.clear(),out_ports.clear(),cu_sets.clear(); - } - - + //configure generic collectors + m_operand_collector.add_cu_set(GEN_CUS, m_config->gpgpu_operand_collector_num_units_gen, m_config->gpgpu_operand_collector_num_out_ports_gen); + for (unsigned i = 0; i < m_config->gpgpu_operand_collector_num_in_ports_gen; i++) { in_ports.push_back(&m_pipeline_reg[ID_OC_SP]); in_ports.push_back(&m_pipeline_reg[ID_OC_SFU]); @@ -287,15 +272,89 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, out_ports.push_back(&m_pipeline_reg[OC_EX_SP]); out_ports.push_back(&m_pipeline_reg[OC_EX_SFU]); out_ports.push_back(&m_pipeline_reg[OC_EX_MEM]); - cu_sets.push_back((unsigned)GEN_CUS); + if(m_config->gpgpu_tensor_core_avail) { + in_ports.push_back(&m_pipeline_reg[ID_OC_TENSOR_CORE]); + out_ports.push_back(&m_pipeline_reg[OC_EX_TENSOR_CORE]); + } + if(m_config->gpgpu_num_dp_units > 0) { + in_ports.push_back(&m_pipeline_reg[ID_OC_DP]); + out_ports.push_back(&m_pipeline_reg[OC_EX_DP]); + } + if(m_config->gpgpu_num_int_units > 0) { + in_ports.push_back(&m_pipeline_reg[ID_OC_INT]); + out_ports.push_back(&m_pipeline_reg[OC_EX_INT]); + } + cu_sets.push_back((unsigned)GEN_CUS); m_operand_collector.add_port(in_ports,out_ports,cu_sets); in_ports.clear(),out_ports.clear(),cu_sets.clear(); } + + if(m_config->enable_specialized_operand_collector) { + m_operand_collector.add_cu_set(SP_CUS, m_config->gpgpu_operand_collector_num_units_sp, m_config->gpgpu_operand_collector_num_out_ports_sp); + m_operand_collector.add_cu_set(DP_CUS, m_config->gpgpu_operand_collector_num_units_dp, m_config->gpgpu_operand_collector_num_out_ports_dp); + m_operand_collector.add_cu_set(TENSOR_CORE_CUS, config->gpgpu_operand_collector_num_units_tensor_core, config->gpgpu_operand_collector_num_out_ports_tensor_core); + m_operand_collector.add_cu_set(SFU_CUS, m_config->gpgpu_operand_collector_num_units_sfu, m_config->gpgpu_operand_collector_num_out_ports_sfu); + m_operand_collector.add_cu_set(MEM_CUS, m_config->gpgpu_operand_collector_num_units_mem, m_config->gpgpu_operand_collector_num_out_ports_mem); + m_operand_collector.add_cu_set(INT_CUS, m_config->gpgpu_operand_collector_num_units_int, m_config->gpgpu_operand_collector_num_out_ports_int); + + for (unsigned i = 0; i < m_config->gpgpu_operand_collector_num_in_ports_sp; i++) { + in_ports.push_back(&m_pipeline_reg[ID_OC_SP]); + out_ports.push_back(&m_pipeline_reg[OC_EX_SP]); + cu_sets.push_back((unsigned)SP_CUS); + cu_sets.push_back((unsigned)GEN_CUS); + m_operand_collector.add_port(in_ports,out_ports,cu_sets); + in_ports.clear(),out_ports.clear(),cu_sets.clear(); + } + + for (unsigned i = 0; i < m_config->gpgpu_operand_collector_num_in_ports_dp; i++) { + in_ports.push_back(&m_pipeline_reg[ID_OC_DP]); + out_ports.push_back(&m_pipeline_reg[OC_EX_DP]); + cu_sets.push_back((unsigned)DP_CUS); + cu_sets.push_back((unsigned)GEN_CUS); + m_operand_collector.add_port(in_ports,out_ports,cu_sets); + in_ports.clear(),out_ports.clear(),cu_sets.clear(); + } + + for (unsigned i = 0; i < m_config->gpgpu_operand_collector_num_in_ports_sfu; i++) { + in_ports.push_back(&m_pipeline_reg[ID_OC_SFU]); + out_ports.push_back(&m_pipeline_reg[OC_EX_SFU]); + cu_sets.push_back((unsigned)SFU_CUS); + cu_sets.push_back((unsigned)GEN_CUS); + m_operand_collector.add_port(in_ports,out_ports,cu_sets); + in_ports.clear(),out_ports.clear(),cu_sets.clear(); + } + + for (unsigned i = 0; i < config->gpgpu_operand_collector_num_in_ports_tensor_core; i++) { + in_ports.push_back(&m_pipeline_reg[ID_OC_TENSOR_CORE]); + out_ports.push_back(&m_pipeline_reg[OC_EX_TENSOR_CORE]); + cu_sets.push_back((unsigned)TENSOR_CORE_CUS); + cu_sets.push_back((unsigned)GEN_CUS); + m_operand_collector.add_port(in_ports,out_ports,cu_sets); + in_ports.clear(),out_ports.clear(),cu_sets.clear(); + } + + for (unsigned i = 0; i < m_config->gpgpu_operand_collector_num_in_ports_mem; i++) { + in_ports.push_back(&m_pipeline_reg[ID_OC_MEM]); + out_ports.push_back(&m_pipeline_reg[OC_EX_MEM]); + cu_sets.push_back((unsigned)MEM_CUS); + cu_sets.push_back((unsigned)GEN_CUS); + m_operand_collector.add_port(in_ports,out_ports,cu_sets); + in_ports.clear(),out_ports.clear(),cu_sets.clear(); + } + + for (unsigned i = 0; i < m_config->gpgpu_operand_collector_num_in_ports_int; i++) { + in_ports.push_back(&m_pipeline_reg[ID_OC_INT]); + out_ports.push_back(&m_pipeline_reg[OC_EX_INT]); + cu_sets.push_back((unsigned)INT_CUS); + cu_sets.push_back((unsigned)GEN_CUS); + m_operand_collector.add_port(in_ports,out_ports,cu_sets); + in_ports.clear(),out_ports.clear(),cu_sets.clear(); + } + } m_operand_collector.init( m_config->gpgpu_num_reg_banks, this ); - // execute - m_num_function_units = m_config->gpgpu_num_sp_units + m_config->gpgpu_num_dp_units + m_config->gpgpu_num_sfu_units + 1; // sp_unit, sfu, ldst_unit + m_num_function_units = m_config->gpgpu_num_sp_units + m_config->gpgpu_num_dp_units + m_config->gpgpu_num_sfu_units + m_config->gpgpu_num_tensor_core_units + m_config->gpgpu_num_int_units + 1; // sp_unit, sfu, dp, tensor, int, ldst_unit //m_dispatch_port = new enum pipeline_stage_name_t[ m_num_function_units ]; //m_issue_port = new enum pipeline_stage_name_t[ m_num_function_units ]; @@ -312,18 +371,29 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, m_dispatch_port.push_back(ID_OC_DP); m_issue_port.push_back(OC_EX_DP); } + for (int k = 0; k < m_config->gpgpu_num_int_units; k++) { + m_fu.push_back(new int_unit( &m_pipeline_reg[EX_WB], m_config, this )); + m_dispatch_port.push_back(ID_OC_INT); + m_issue_port.push_back(OC_EX_INT); + } for (int k = 0; k < m_config->gpgpu_num_sfu_units; k++) { m_fu.push_back(new sfu( &m_pipeline_reg[EX_WB], m_config, this )); m_dispatch_port.push_back(ID_OC_SFU); m_issue_port.push_back(OC_EX_SFU); } + + for (int k = 0; k < config->gpgpu_num_tensor_core_units; k++) { + m_fu.push_back(new tensor_core( &m_pipeline_reg[EX_WB], m_config, this )); + m_dispatch_port.push_back(ID_OC_TENSOR_CORE); + m_issue_port.push_back(OC_EX_TENSOR_CORE); + } m_ldst_unit = new ldst_unit( m_icnt, m_mem_fetch_allocator, this, &m_operand_collector, m_scoreboard, config, mem_config, stats, shader_id, tpc_id ); m_fu.push_back(m_ldst_unit); m_dispatch_port.push_back(ID_OC_MEM); m_issue_port.push_back(OC_EX_MEM); - + assert(m_num_function_units == m_fu.size() and m_fu.size() == m_dispatch_port.size() and m_fu.size() == m_issue_port.size()); //there are as many result buses as the width of the EX_WB stage @@ -357,6 +427,7 @@ void shader_core_ctx::reinit(unsigned start_thread, unsigned end_thread, bool re m_occupied_ctas = 0; m_occupied_hwtid.reset(); m_occupied_cta_to_hwtid.clear(); + m_active_warps = 0; } for (unsigned i = start_thread; i<end_thread; i++) { @@ -369,11 +440,12 @@ void shader_core_ctx::reinit(unsigned start_thread, unsigned end_thread, bool re } } -void shader_core_ctx::init_warps( unsigned cta_id, unsigned start_thread, unsigned end_thread ) +void shader_core_ctx::init_warps( unsigned cta_id, unsigned start_thread, unsigned end_thread, unsigned ctaid, int cta_size, unsigned kernel_id ) { address_type start_pc = next_pc(start_thread); if (m_config->model == POST_DOMINATOR) { unsigned start_warp = start_thread / m_config->warp_size; + unsigned warp_per_cta = cta_size / m_config->warp_size; unsigned end_warp = end_thread / m_config->warp_size + ((end_thread % m_config->warp_size)? 1 : 0); for (unsigned i = start_warp; i < end_warp; ++i) { unsigned n_active=0; @@ -388,9 +460,25 @@ void shader_core_ctx::init_warps( unsigned cta_id, unsigned start_thread, unsign } } m_simt_stack[i]->launch(start_pc,active_threads); + + if(m_gpu->resume_option==1 && kernel_id==m_gpu->resume_kernel && ctaid>=m_gpu->resume_CTA && ctaid<m_gpu->checkpoint_CTA_t ) + { + char fname[2048]; + snprintf(fname,2048,"checkpoint_files/warp_%d_%d_simt.txt",i%warp_per_cta,ctaid ); + unsigned pc,rpc; + m_simt_stack[i]->resume(fname); + m_simt_stack[i]->get_pdom_stack_top_info(&pc,&rpc); + for (unsigned t = 0; t < m_config->warp_size; t++) { + m_thread[i * m_config->warp_size + t]->set_npc(pc); + m_thread[i * m_config->warp_size + t]->update_pc(); + } + start_pc=pc; + } + m_warp[i].init(start_pc,cta_id,i,active_threads, m_dynamic_warp_id); ++m_dynamic_warp_id; m_not_completed += n_active; + ++m_active_warps; } } } @@ -418,6 +506,18 @@ void shader_core_ctx::get_pdom_stack_top_info( unsigned tid, unsigned *pc, unsig m_simt_stack[warp_id]->get_pdom_stack_top_info(pc,rpc); } +float shader_core_ctx::get_current_occupancy( unsigned long long & active, unsigned long long & total ) const +{ + // To match the achieved_occupancy in nvprof, only SMs that are active are counted toward the occupancy. + if ( m_active_warps > 0 ) { + total += m_warp.size(); + active += m_active_warps; + return float(active) / float(total); + } else { + return 0; + } +} + void shader_core_stats::print( FILE* fout ) const { unsigned long long thread_icount_uarch=0; @@ -441,6 +541,7 @@ void shader_core_stats::print( FILE* fout ) const fprintf(fout, "gpgpu_n_load_insn = %d\n", gpgpu_n_load_insn); fprintf(fout, "gpgpu_n_store_insn = %d\n", gpgpu_n_store_insn); fprintf(fout, "gpgpu_n_shmem_insn = %d\n", gpgpu_n_shmem_insn); + fprintf(fout, "gpgpu_n_sstarr_insn = %d\n", gpgpu_n_sstarr_insn); fprintf(fout, "gpgpu_n_tex_insn = %d\n", gpgpu_n_tex_insn); fprintf(fout, "gpgpu_n_const_mem_insn = %d\n", gpgpu_n_const_insn); fprintf(fout, "gpgpu_n_param_mem_insn = %d\n", gpgpu_n_param_insn); @@ -451,15 +552,15 @@ void shader_core_stats::print( FILE* fout ) const fprintf(fout, "gpgpu_n_intrawarp_mshr_merge = %d\n", gpgpu_n_intrawarp_mshr_merge); fprintf(fout, "gpgpu_n_cmem_portconflict = %d\n", gpgpu_n_cmem_portconflict); - fprintf(fout, "gpgpu_stall_shd_mem[c_mem][bk_conf] = %d\n", gpu_stall_shd_mem_breakdown[C_MEM][BK_CONF]); - fprintf(fout, "gpgpu_stall_shd_mem[c_mem][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[C_MEM][MSHR_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[c_mem][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[C_MEM][ICNT_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[c_mem][data_port_stall] = %d\n", gpu_stall_shd_mem_breakdown[C_MEM][DATA_PORT_STALL]); - fprintf(fout, "gpgpu_stall_shd_mem[t_mem][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[T_MEM][MSHR_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[t_mem][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[T_MEM][ICNT_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[t_mem][data_port_stall] = %d\n", gpu_stall_shd_mem_breakdown[T_MEM][DATA_PORT_STALL]); + fprintf(fout, "gpgpu_stall_shd_mem[c_mem][resource_stall] = %d\n", gpu_stall_shd_mem_breakdown[C_MEM][BK_CONF]); + //fprintf(fout, "gpgpu_stall_shd_mem[c_mem][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[C_MEM][MSHR_RC_FAIL]); + //fprintf(fout, "gpgpu_stall_shd_mem[c_mem][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[C_MEM][ICNT_RC_FAIL]); + //fprintf(fout, "gpgpu_stall_shd_mem[c_mem][data_port_stall] = %d\n", gpu_stall_shd_mem_breakdown[C_MEM][DATA_PORT_STALL]); + //fprintf(fout, "gpgpu_stall_shd_mem[t_mem][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[T_MEM][MSHR_RC_FAIL]); + //fprintf(fout, "gpgpu_stall_shd_mem[t_mem][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[T_MEM][ICNT_RC_FAIL]); + //fprintf(fout, "gpgpu_stall_shd_mem[t_mem][data_port_stall] = %d\n", gpu_stall_shd_mem_breakdown[T_MEM][DATA_PORT_STALL]); fprintf(fout, "gpgpu_stall_shd_mem[s_mem][bk_conf] = %d\n", gpu_stall_shd_mem_breakdown[S_MEM][BK_CONF]); - fprintf(fout, "gpgpu_stall_shd_mem[gl_mem][bk_conf] = %d\n", + fprintf(fout, "gpgpu_stall_shd_mem[gl_mem][resource_stall] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_LD][BK_CONF] + gpu_stall_shd_mem_breakdown[G_MEM_ST][BK_CONF] + gpu_stall_shd_mem_breakdown[L_MEM_LD][BK_CONF] + @@ -477,22 +578,22 @@ void shader_core_stats::print( FILE* fout ) const gpu_stall_shd_mem_breakdown[L_MEM_LD][DATA_PORT_STALL] + gpu_stall_shd_mem_breakdown[L_MEM_ST][DATA_PORT_STALL] ); // data port stall at data cache - fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_LD][MSHR_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_LD][ICNT_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][wb_icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_LD][WB_ICNT_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][wb_rsrv_fail] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_LD][WB_CACHE_RSRV_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[g_mem_st][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_ST][MSHR_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[g_mem_st][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_ST][ICNT_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[g_mem_st][wb_icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_ST][WB_ICNT_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[g_mem_st][wb_rsrv_fail] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_ST][WB_CACHE_RSRV_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_LD][MSHR_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_LD][ICNT_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][wb_icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_LD][WB_ICNT_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][wb_rsrv_fail] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_LD][WB_CACHE_RSRV_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[l_mem_st][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_ST][MSHR_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[l_mem_st][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_ST][ICNT_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][wb_icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_ST][WB_ICNT_RC_FAIL]); - fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][wb_rsrv_fail] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_ST][WB_CACHE_RSRV_FAIL]); + //fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_LD][MSHR_RC_FAIL]); + //fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_LD][ICNT_RC_FAIL]); + //fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][wb_icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_LD][WB_ICNT_RC_FAIL]); + //fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][wb_rsrv_fail] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_LD][WB_CACHE_RSRV_FAIL]); + //fprintf(fout, "gpgpu_stall_shd_mem[g_mem_st][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_ST][MSHR_RC_FAIL]); + //fprintf(fout, "gpgpu_stall_shd_mem[g_mem_st][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_ST][ICNT_RC_FAIL]); + //fprintf(fout, "gpgpu_stall_shd_mem[g_mem_st][wb_icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_ST][WB_ICNT_RC_FAIL]); + //fprintf(fout, "gpgpu_stall_shd_mem[g_mem_st][wb_rsrv_fail] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_ST][WB_CACHE_RSRV_FAIL]); + //fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_LD][MSHR_RC_FAIL]); + //fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_LD][ICNT_RC_FAIL]); + //fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][wb_icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_LD][WB_ICNT_RC_FAIL]); + //fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][wb_rsrv_fail] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_LD][WB_CACHE_RSRV_FAIL]); + //fprintf(fout, "gpgpu_stall_shd_mem[l_mem_st][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_ST][MSHR_RC_FAIL]); + //fprintf(fout, "gpgpu_stall_shd_mem[l_mem_st][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_ST][ICNT_RC_FAIL]); + //fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][wb_icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_ST][WB_ICNT_RC_FAIL]); + //fprintf(fout, "gpgpu_stall_shd_mem[l_mem_ld][wb_rsrv_fail] = %d\n", gpu_stall_shd_mem_breakdown[L_MEM_ST][WB_CACHE_RSRV_FAIL]); fprintf(fout, "gpu_reg_bank_conflict_stalls = %d\n", gpu_reg_bank_conflict_stalls); @@ -692,6 +793,8 @@ void shader_core_ctx::fetch() } if( did_exit ) m_warp[warp_id].set_done_exit(); + --m_active_warps; + assert(m_active_warps >= 0); } // this code fetches instructions from the i-cache or generates memory requests @@ -742,18 +845,21 @@ void shader_core_ctx::func_exec_inst( warp_inst_t &inst ) { execute_warp_inst_t(inst); if( inst.is_load() || inst.is_store() ) - inst.generate_mem_accesses(); + { + inst.generate_mem_accesses(); + //inst.print_m_accessq(); + } } -void shader_core_ctx::issue_warp( register_set& pipe_reg_set, const warp_inst_t* next_inst, const active_mask_t &active_mask, unsigned warp_id ) +void shader_core_ctx::issue_warp( register_set& pipe_reg_set, const warp_inst_t* next_inst, const active_mask_t &active_mask, unsigned warp_id, unsigned sch_id ) { - warp_inst_t** pipe_reg = pipe_reg_set.get_free(); + warp_inst_t** pipe_reg = pipe_reg = pipe_reg_set.get_free(m_config->sub_core_model, sch_id); assert(pipe_reg); m_warp[warp_id].ibuffer_free(); assert(next_inst->valid()); **pipe_reg = *next_inst; // static instruction information - (*pipe_reg)->issue( active_mask, warp_id, gpu_tot_sim_cycle + gpu_sim_cycle, m_warp[warp_id].get_dynamic_warp_id() ); // dynamic instruction information + (*pipe_reg)->issue( active_mask, warp_id, gpu_tot_sim_cycle + gpu_sim_cycle, m_warp[warp_id].get_dynamic_warp_id(), sch_id ); // dynamic instruction information m_stats->shader_cycle_distro[2+(*pipe_reg)->active_count()]++; func_exec_inst( **pipe_reg ); if( next_inst->op == BARRIER_OP ){ @@ -898,8 +1004,8 @@ void scheduler_unit::cycle() unsigned checked=0; unsigned issued=0; exec_unit_type_t previous_issued_inst_exec_type = exec_unit_type_t::NONE; - unsigned max_issue = m_shader->m_config->gpgpu_max_insn_issue_per_warp; - bool diff_exec_units = m_shader->m_config->gpgpu_dual_issue_diff_exec_units; + unsigned max_issue = m_shader->m_config->gpgpu_max_insn_issue_per_warp; + bool diff_exec_units = m_shader->m_config->gpgpu_dual_issue_diff_exec_units; //In tis mode, we only allow dual issue to diff execution units (as in Maxwell and Pascal) while( !warp(warp_id).waiting() && !warp(warp_id).ibuffer_empty() && (checked < max_issue) && (checked <= issued) && (issued < max_issue) ) { const warp_inst_t *pI = warp(warp_id).ibuffer_next_inst(); @@ -933,9 +1039,10 @@ void scheduler_unit::cycle() ready_inst = true; const active_mask_t &active_mask = m_simt_stack[warp_id]->get_active_mask(); assert( warp(warp_id).inst_in_pipeline() ); - if ( (pI->op == LOAD_OP) || (pI->op == STORE_OP) || (pI->op == MEMORY_BARRIER_OP) ) { - if( m_mem_out->has_free() && (!diff_exec_units || previous_issued_inst_exec_type != exec_unit_type_t::MEM)) { - m_shader->issue_warp(*m_mem_out,pI,active_mask,warp_id); + + if ( (pI->op == LOAD_OP) || (pI->op == STORE_OP) || (pI->op == MEMORY_BARRIER_OP)||(pI->op==TENSOR_CORE_LOAD_OP)||(pI->op==TENSOR_CORE_STORE_OP) ) { + if( m_mem_out->has_free(m_shader->m_config->sub_core_model, m_id) && (!diff_exec_units || previous_issued_inst_exec_type != exec_unit_type_t::MEM)) { + m_shader->issue_warp(*m_mem_out,pI,active_mask,warp_id,m_id); issued++; issued_inst=true; warp_inst_issued = true; @@ -943,58 +1050,98 @@ void scheduler_unit::cycle() } } else { - bool sp_pipe_avail = m_sp_out->has_free(); - bool sfu_pipe_avail = m_sfu_out->has_free(); - bool dp_pipe_avail = m_dp_out->has_free(); - if( sp_pipe_avail && (pI->op != SFU_OP && pI->op != DP_OP) && (!diff_exec_units || previous_issued_inst_exec_type != exec_unit_type_t::SP)) { + bool sp_pipe_avail = m_sp_out->has_free(m_shader->m_config->sub_core_model, m_id); + bool sfu_pipe_avail = m_sfu_out->has_free(m_shader->m_config->sub_core_model, m_id); + bool tensor_core_pipe_avail = m_tensor_core_out->has_free(m_shader->m_config->sub_core_model, m_id); + bool dp_pipe_avail = m_dp_out->has_free(m_shader->m_config->sub_core_model, m_id); + bool int_pipe_avail = m_int_out->has_free(m_shader->m_config->sub_core_model, m_id); + + //This code need to be refactored + if(pI->op != TENSOR_CORE_OP && pI->op != SFU_OP && pI->op != DP_OP) { - //Jin: special for CDP api - if(pI->m_is_cdp && !warp(warp_id).m_cdp_dummy) { - assert(warp(warp_id).m_cdp_latency == 0); - - extern unsigned cdp_latency[5]; - if(pI->m_is_cdp == 1) - warp(warp_id).m_cdp_latency = cdp_latency[pI->m_is_cdp - 1]; - else //cudaLaunchDeviceV2 and cudaGetParameterBufferV2 - warp(warp_id).m_cdp_latency = cdp_latency[pI->m_is_cdp - 1] - + cdp_latency[pI->m_is_cdp] * active_mask.count(); - warp(warp_id).m_cdp_dummy = true; - break; - } - else if(pI->m_is_cdp && warp(warp_id).m_cdp_dummy) { - assert(warp(warp_id).m_cdp_latency == 0); - warp(warp_id).m_cdp_dummy = false; - } + bool execute_on_SP = false; + bool execute_on_INT = false; - // always prefer SP pipe for operations that can use both SP and SFU pipelines - m_shader->issue_warp(*m_sp_out,pI,active_mask,warp_id); - issued++; - issued_inst=true; - warp_inst_issued = true; - previous_issued_inst_exec_type = exec_unit_type_t::SP; - } else if ( (m_shader->m_config->gpgpu_num_dp_units != 0) && (pI->op == DP_OP) && (!diff_exec_units || previous_issued_inst_exec_type != exec_unit_type_t::DP)) { + //if INT unit pipline exist, then execute ALU and INT operations on INT unit and SP-FPU on SP unit (like in Volta) + //if INT unit pipline does not exist, then execute all ALU, INT and SP operations on SP unit (as in Fermi, Pascal GPUs) + if(m_shader->m_config->gpgpu_num_int_units > 0 && + int_pipe_avail && + pI->op != SP_OP && + !(diff_exec_units && previous_issued_inst_exec_type == exec_unit_type_t::INT)) + execute_on_INT = true; + else if (sp_pipe_avail && + (m_shader->m_config->gpgpu_num_int_units == 0 || + (m_shader->m_config->gpgpu_num_int_units > 0 && pI->op == SP_OP)) && + !(diff_exec_units && previous_issued_inst_exec_type == exec_unit_type_t::SP) ) + execute_on_SP = true; + + + if(execute_on_INT || execute_on_SP) { + //Jin: special for CDP api + if(pI->m_is_cdp && !warp(warp_id).m_cdp_dummy) { + assert(warp(warp_id).m_cdp_latency == 0); + + extern unsigned cdp_latency[5]; + if(pI->m_is_cdp == 1) + warp(warp_id).m_cdp_latency = cdp_latency[pI->m_is_cdp - 1]; + else //cudaLaunchDeviceV2 and cudaGetParameterBufferV2 + warp(warp_id).m_cdp_latency = cdp_latency[pI->m_is_cdp - 1] + + cdp_latency[pI->m_is_cdp] * active_mask.count(); + warp(warp_id).m_cdp_dummy = true; + break; + } + else if(pI->m_is_cdp && warp(warp_id).m_cdp_dummy) { + assert(warp(warp_id).m_cdp_latency == 0); + warp(warp_id).m_cdp_dummy = false; + } + } + + if(execute_on_SP) { + m_shader->issue_warp(*m_sp_out,pI,active_mask,warp_id,m_id); + issued++; + issued_inst=true; + warp_inst_issued = true; + previous_issued_inst_exec_type = exec_unit_type_t::SP; + } else if (execute_on_INT) { + m_shader->issue_warp(*m_int_out,pI,active_mask,warp_id,m_id); + issued++; + issued_inst=true; + warp_inst_issued = true; + previous_issued_inst_exec_type = exec_unit_type_t::INT; + } + } else if ( (m_shader->m_config->gpgpu_num_dp_units > 0) && (pI->op == DP_OP) && !(diff_exec_units && previous_issued_inst_exec_type == exec_unit_type_t::DP)) { if( dp_pipe_avail ) { - m_shader->issue_warp(*m_dp_out,pI,active_mask,warp_id); + m_shader->issue_warp(*m_dp_out,pI,active_mask,warp_id,m_id); issued++; issued_inst=true; warp_inst_issued = true; previous_issued_inst_exec_type = exec_unit_type_t::DP; } - } //If the DP units = 0 (like in Fermi archi), then change DP inst to SFU inst - else if ( ((m_shader->m_config->gpgpu_num_dp_units == 0 && pI->op == DP_OP) || (pI->op == SFU_OP) || (pI->op == ALU_SFU_OP)) && (!diff_exec_units || previous_issued_inst_exec_type != exec_unit_type_t::SFU)) { + } //If the DP units = 0 (like in Fermi archi), then execute DP inst on SFU unit + else if ( ((m_shader->m_config->gpgpu_num_dp_units == 0 && pI->op == DP_OP) || (pI->op == SFU_OP) || (pI->op == ALU_SFU_OP)) && !(diff_exec_units && previous_issued_inst_exec_type == exec_unit_type_t::SFU)) { if( sfu_pipe_avail ) { - m_shader->issue_warp(*m_sfu_out,pI,active_mask,warp_id); + m_shader->issue_warp(*m_sfu_out,pI,active_mask,warp_id,m_id); issued++; issued_inst=true; warp_inst_issued = true; previous_issued_inst_exec_type = exec_unit_type_t::SFU; } - } - } - } else { + } + else if ( (pI->op == TENSOR_CORE_OP) && !(diff_exec_units && previous_issued_inst_exec_type == exec_unit_type_t::SP) ) { + if( tensor_core_pipe_avail ) { + m_shader->issue_warp(*m_tensor_core_out,pI,active_mask,warp_id,m_id); + issued++; + issued_inst=true; + warp_inst_issued = true; + previous_issued_inst_exec_type = exec_unit_type_t::TENSOR; + } + } + }//end of else + } else { + SCHED_DPRINTF( "Warp (warp_id %u, dynamic_warp_id %u) fails scoreboard\n", (*iter)->get_warp_id(), (*iter)->get_dynamic_warp_id() ); - } + } } } else if( valid ) { // this case can happen after a return instruction in diverged warp @@ -1128,7 +1275,7 @@ void two_level_active_scheduler::order_warps() for ( std::vector< shd_warp_t* >::iterator iter = m_next_cycle_prioritized_warps.begin(); iter != m_next_cycle_prioritized_warps.end(); ) { bool waiting = (*iter)->waiting(); - for (int i=0; i<4; i++){ + for (int i=0; i<MAX_INPUT_VALUES; i++){ const warp_inst_t* inst = (*iter)->ibuffer_next_inst(); //Is the instruction waiting on a long operation? if ( inst && inst->in[i] > 0 && this->m_scoreboard->islongop((*iter)->get_warp_id(), inst->in[i])){ @@ -1174,10 +1321,12 @@ swl_scheduler::swl_scheduler ( shader_core_stats* stats, shader_core_ctx* shader register_set* sp_out, register_set* dp_out, register_set* sfu_out, + register_set* int_out, + register_set* tensor_core_out, register_set* mem_out, int id, char* config_string ) - : scheduler_unit ( stats, shader, scoreboard, simt, warp, sp_out, dp_out, sfu_out, mem_out, id ) + : scheduler_unit ( stats, shader, scoreboard, simt, warp, sp_out, dp_out, sfu_out, int_out, tensor_core_out, mem_out, id ) { unsigned m_prioritization_readin; int ret = sscanf( config_string, @@ -1345,10 +1494,12 @@ void ldst_unit::get_L1T_sub_stats(struct cache_sub_stats &css) const{ void shader_core_ctx::warp_inst_complete(const warp_inst_t &inst) { - #if 0 - printf("[warp_inst_complete] uid=%u core=%u warp=%u pc=%#x @ time=%llu issued@%llu\n", - inst.get_uid(), m_sid, inst.warp_id(), inst.pc, gpu_tot_sim_cycle + gpu_sim_cycle, inst.get_issue_cycle()); - #endif + + #if 0 + printf("[warp_inst_complete] uid=%u core=%u warp=%u pc=%#x @ time=%llu issued@%llu\n", + inst.get_uid(), m_sid, inst.warp_id(), inst.pc, gpu_tot_sim_cycle + gpu_sim_cycle, inst.get_issue_cycle()); + #endif + if(inst.op_pipe==SP__OP) m_stats->m_num_sp_committed[m_sid]++; else if(inst.op_pipe==SFU__OP) @@ -1451,7 +1602,7 @@ ldst_unit::process_cache_access( cache_t* cache, assert( !read_sent ); inst.accessq_pop_back(); if ( inst.is_load() ) { - for ( unsigned r=0; r < 4; r++) + for ( unsigned r=0; r < MAX_OUTPUT_VALUES; r++) if (inst.out[r] > 0) m_pending_writes[inst.warp_id()][inst.out[r]]--; } @@ -1488,6 +1639,111 @@ mem_stage_stall_type ldst_unit::process_memory_access_queue( cache_t *cache, war return process_cache_access( cache, mf->get_addr(), inst, events, mf, status ); } +mem_stage_stall_type ldst_unit::process_memory_access_queue_l1cache( l1_cache *cache, warp_inst_t &inst ) +{ + mem_stage_stall_type result = NO_RC_FAIL; + if( inst.accessq_empty() ) + return result; + + mem_fetch *mf = m_mf_allocator->alloc(inst,inst.accessq_back()); + + if(m_config->m_L1D_config.l1_latency > 0) + { + if((l1_latency_queue[m_config->m_L1D_config.l1_latency-1]) == NULL) + { + l1_latency_queue[m_config->m_L1D_config.l1_latency-1] = mf; + + if( mf->get_inst().is_store() ) { + unsigned inc_ack = (m_config->m_L1D_config.get_mshr_type() == SECTOR_ASSOC)? + (mf->get_data_size()/SECTOR_SIZE) : 1; + + for(unsigned i=0; i< inc_ack; ++i) + m_core->inc_store_req( inst.warp_id() ); + } + + inst.accessq_pop_back(); + } + else + { + result = BK_CONF; + delete mf; + } + if( !inst.accessq_empty() && result !=BK_CONF) + result = COAL_STALL; + return result; + } + else + { + std::list<cache_event> events; + enum cache_request_status status = cache->access(mf->get_addr(),mf,gpu_sim_cycle+gpu_tot_sim_cycle,events); + return process_cache_access( cache, mf->get_addr(), inst, events, mf, status ); + } +} + +void ldst_unit::L1_latency_queue_cycle() +{ + //std::deque< std::pair<mem_fetch*,bool> >::iterator it = m_latency_queue.begin(); + if((l1_latency_queue[0]) != NULL) + { + mem_fetch* mf_next = l1_latency_queue[0]; + std::list<cache_event> events; + enum cache_request_status status = m_L1D->access(mf_next->get_addr(),mf_next,gpu_sim_cycle+gpu_tot_sim_cycle,events); + + bool write_sent = was_write_sent(events); + bool read_sent = was_read_sent(events); + + if ( status == HIT ) { + assert( !read_sent ); + l1_latency_queue[0] = NULL; + if ( mf_next->get_inst().is_load() ) { + for ( unsigned r=0; r < MAX_OUTPUT_VALUES; r++) + if (mf_next->get_inst().out[r] > 0) + { + assert(m_pending_writes[mf_next->get_inst().warp_id()][mf_next->get_inst().out[r]]>0); + unsigned still_pending = --m_pending_writes[mf_next->get_inst().warp_id()][mf_next->get_inst().out[r]]; + if(!still_pending) + { + m_pending_writes[mf_next->get_inst().warp_id()].erase(mf_next->get_inst().out[r]); + m_scoreboard->releaseRegister(mf_next->get_inst().warp_id(),mf_next->get_inst().out[r]); + m_core->warp_inst_complete(mf_next->get_inst()); + } + } + } + + //For write hit in WB policy + if(mf_next->get_inst().is_store() && !write_sent) + { + unsigned dec_ack = (m_config->m_L1D_config.get_mshr_type() == SECTOR_ASSOC)? + (mf_next->get_data_size()/SECTOR_SIZE) : 1; + + mf_next->set_reply(); + + for(unsigned i=0; i< dec_ack; ++i) + m_core->store_ack(mf_next); + } + + if( !write_sent ) + delete mf_next; + + } else if ( status == RESERVATION_FAIL ) { + assert( !read_sent ); + assert( !write_sent ); + } else { + assert( status == MISS || status == HIT_RESERVED ); + l1_latency_queue[0] = NULL; + } + } + + for( unsigned stage = 0; stage<m_config->m_L1D_config.l1_latency-1; ++stage) + if( l1_latency_queue[stage] == NULL) { + l1_latency_queue[stage] = l1_latency_queue[stage+1] ; + l1_latency_queue[stage+1] = NULL; + } + +} + + + bool ldst_unit::constant_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type) { if( inst.empty() || ((inst.space.get_type() != const_space) && (inst.space.get_type() != param_space_kernel)) ) @@ -1537,14 +1793,14 @@ bool ldst_unit::memory_cycle( warp_inst_t &inst, mem_stage_stall_type &stall_rea bypassL1D = true; } else if (inst.space.is_global()) { // global memory access // skip L1 cache if the option is enabled - if (m_core->get_config()->gmem_skip_L1D) + if (m_core->get_config()->gmem_skip_L1D && (CACHE_L1 != inst.cache_op)) bypassL1D = true; } - if( bypassL1D ) { // bypass L1 cache unsigned control_size = inst.is_store() ? WRITE_PACKET_SIZE : READ_PACKET_SIZE; unsigned size = access.get_size() + control_size; + //printf("Interconnect:Addr: %x, size=%d\n",access.get_addr(),size); if( m_icnt->full(size, inst.is_store() || inst.isatomic()) ) { stall_cond = ICNT_RC_FAIL; } else { @@ -1553,7 +1809,7 @@ bool ldst_unit::memory_cycle( warp_inst_t &inst, mem_stage_stall_type &stall_rea inst.accessq_pop_back(); //inst.clear_active( access.get_warp_mask() ); if( inst.is_load() ) { - for( unsigned r=0; r < 4; r++) + for( unsigned r=0; r < MAX_OUTPUT_VALUES; r++) if(inst.out[r] > 0) assert( m_pending_writes[inst.warp_id()][inst.out[r]] > 0 ); } else if( inst.is_store() ) @@ -1561,7 +1817,7 @@ bool ldst_unit::memory_cycle( warp_inst_t &inst, mem_stage_stall_type &stall_rea } } else { assert( CACHE_UNDEFINED != inst.cache_op ); - stall_cond = process_memory_access_queue(m_L1D,inst); + stall_cond = process_memory_access_queue_l1cache(m_L1D,inst); } if( !inst.accessq_empty() && stall_cond == NO_RC_FAIL) stall_cond = COAL_STALL; @@ -1593,6 +1849,11 @@ void ldst_unit::flush(){ m_L1D->flush(); } +void ldst_unit::invalidate(){ + // Flush L1D cache + m_L1D->invalidate(); +} + simd_function_unit::simd_function_unit( const shader_core_config *config ) { m_config=config; @@ -1606,6 +1867,12 @@ sfu:: sfu( register_set* result_port, const shader_core_config *config,shader_c m_name = "SFU"; } +tensor_core:: tensor_core( register_set* result_port, const shader_core_config *config,shader_core_ctx *core ) + : pipelined_simd_unit(result_port,config,config->max_tensor_core_latency,core) +{ + m_name = "TENSOR_CORE"; +} + void sfu::issue( register_set& source_reg ) { warp_inst_t** ready_reg = source_reg.get_ready(); @@ -1616,11 +1883,34 @@ void sfu::issue( register_set& source_reg ) pipelined_simd_unit::issue(source_reg); } +void tensor_core::issue( register_set& source_reg ) +{ + warp_inst_t** ready_reg = source_reg.get_ready(); + //m_core->incexecstat((*ready_reg)); + + (*ready_reg)->op_pipe= TENSOR_CORE__OP; + m_core->incsfu_stat(m_core->get_config()->warp_size,(*ready_reg)->latency); + pipelined_simd_unit::issue(source_reg); +} + +unsigned pipelined_simd_unit::get_active_lanes_in_pipeline(){ + active_mask_t active_lanes; + active_lanes.reset(); + if(m_core->get_gpu()->get_config().g_power_simulation_enabled){ + for( unsigned stage=0; (stage+1)<m_pipeline_depth; stage++ ){ + if( !m_pipeline_reg[stage]->empty() ) + active_lanes|=m_pipeline_reg[stage]->get_active_mask(); + } + } + return active_lanes.count(); +} + void ldst_unit::active_lanes_in_pipeline(){ unsigned active_count=pipelined_simd_unit::get_active_lanes_in_pipeline(); assert(active_count<=m_core->get_config()->warp_size); m_core->incfumemactivelanes_stat(active_count); } + void sp_unit::active_lanes_in_pipeline(){ unsigned active_count=pipelined_simd_unit::get_active_lanes_in_pipeline(); assert(active_count<=m_core->get_config()->warp_size); @@ -1636,6 +1926,13 @@ void dp_unit::active_lanes_in_pipeline(){ m_core->incfumemactivelanes_stat(active_count); } +void int_unit::active_lanes_in_pipeline(){ + unsigned active_count=pipelined_simd_unit::get_active_lanes_in_pipeline(); + assert(active_count<=m_core->get_config()->warp_size); + m_core->incspactivelanes_stat(active_count); + m_core->incfuactivelanes_stat(active_count); + m_core->incfumemactivelanes_stat(active_count); +} void sfu::active_lanes_in_pipeline(){ unsigned active_count=pipelined_simd_unit::get_active_lanes_in_pipeline(); assert(active_count<=m_core->get_config()->warp_size); @@ -1644,6 +1941,15 @@ void sfu::active_lanes_in_pipeline(){ m_core->incfumemactivelanes_stat(active_count); } +void tensor_core::active_lanes_in_pipeline(){ + unsigned active_count=pipelined_simd_unit::get_active_lanes_in_pipeline(); + assert(active_count<=m_core->get_config()->warp_size); + m_core->incsfuactivelanes_stat(active_count); + m_core->incfuactivelanes_stat(active_count); + m_core->incfumemactivelanes_stat(active_count); +} + + sp_unit::sp_unit( register_set* result_port, const shader_core_config *config,shader_core_ctx *core) : pipelined_simd_unit(result_port,config,config->max_sp_latency,core) { @@ -1651,11 +1957,17 @@ sp_unit::sp_unit( register_set* result_port, const shader_core_config *config,sh } dp_unit::dp_unit( register_set* result_port, const shader_core_config *config,shader_core_ctx *core) - : pipelined_simd_unit(result_port,config,config->max_sfu_latency,core) + : pipelined_simd_unit(result_port,config,config->max_dp_latency,core) { m_name = "DP "; } +int_unit::int_unit( register_set* result_port, const shader_core_config *config,shader_core_ctx *core) + : pipelined_simd_unit(result_port,config,config->max_int_latency,core) +{ + m_name = "INT "; +} + void sp_unit :: issue(register_set& source_reg) { warp_inst_t** ready_reg = source_reg.get_ready(); @@ -1674,6 +1986,15 @@ void dp_unit :: issue(register_set& source_reg) pipelined_simd_unit::issue(source_reg); } +void int_unit :: issue(register_set& source_reg) +{ + warp_inst_t** ready_reg = source_reg.get_ready(); + //m_core->incexecstat((*ready_reg)); + (*ready_reg)->op_pipe=INTP__OP; + m_core->incsp_stat(m_core->get_config()->warp_size,(*ready_reg)->latency); + pipelined_simd_unit::issue(source_reg); +} + pipelined_simd_unit::pipelined_simd_unit( register_set* result_port, const shader_core_config *config, unsigned max_latency,shader_core_ctx *core ) : simd_function_unit(config) { @@ -1683,19 +2004,25 @@ pipelined_simd_unit::pipelined_simd_unit( register_set* result_port, const shade for( unsigned i=0; i < m_pipeline_depth; i++ ) m_pipeline_reg[i] = new warp_inst_t( config ); m_core=core; + active_insts_in_pipeline=0; } void pipelined_simd_unit::cycle() { if( !m_pipeline_reg[0]->empty() ){ m_result_port->move_in(m_pipeline_reg[0]); + assert(active_insts_in_pipeline > 0); + active_insts_in_pipeline--; + } + if(active_insts_in_pipeline){ + for( unsigned stage=0; (stage+1)<m_pipeline_depth; stage++ ) + move_warp(m_pipeline_reg[stage], m_pipeline_reg[stage+1]); } - for( unsigned stage=0; (stage+1)<m_pipeline_depth; stage++ ) - move_warp(m_pipeline_reg[stage], m_pipeline_reg[stage+1]); if( !m_dispatch_reg->empty() ) { if( !m_dispatch_reg->dispatch_delay()){ int start_stage = m_dispatch_reg->latency - m_dispatch_reg->initiation_interval; move_warp(m_pipeline_reg[start_stage],m_dispatch_reg); + active_insts_in_pipeline++; } } occupied >>=1; @@ -1766,8 +2093,9 @@ ldst_unit::ldst_unit( mem_fetch_interface *icnt, const memory_config *mem_config, shader_core_stats *stats, unsigned sid, - unsigned tpc ) : pipelined_simd_unit(NULL,config,3,core), m_next_wb(config) + unsigned tpc ) : pipelined_simd_unit(NULL,config,config->smem_latency,core), m_next_wb(config) { + assert(config->smem_latency > 1); init( icnt, mf_allocator, core, @@ -1788,7 +2116,14 @@ ldst_unit::ldst_unit( mem_fetch_interface *icnt, m_icnt, m_mf_allocator, IN_L1D_MISS_QUEUE ); + + if(m_config->m_L1D_config.l1_latency > 0) + { + for(int i=0; i<m_config->m_L1D_config.l1_latency; i++ ) + l1_latency_queue.push_back((mem_fetch*)NULL); + } } + m_name = "MEM "; } ldst_unit::ldst_unit( mem_fetch_interface *icnt, @@ -1825,7 +2160,7 @@ void ldst_unit:: issue( register_set ®_set ) if (inst->is_load() and inst->space.get_type() != shared_space) { unsigned warp_id = inst->warp_id(); unsigned n_accesses = inst->accessq_count(); - for (unsigned r = 0; r < 4; r++) { + for (unsigned r = 0; r < MAX_OUTPUT_VALUES; r++) { unsigned reg_id = inst->out[r]; if (reg_id > 0) { m_pending_writes[warp_id][reg_id] += n_accesses; @@ -1847,7 +2182,7 @@ void ldst_unit::writeback() if( !m_next_wb.empty() ) { if( m_operand_collector->writeback(m_next_wb) ) { bool insn_completed = false; - for( unsigned r=0; r < 4; r++ ) { + for( unsigned r=0; r < MAX_OUTPUT_VALUES; r++ ) { if( m_next_wb.out[r] > 0 ) { if( m_next_wb.space.get_type() != shared_space ) { assert( m_pending_writes[m_next_wb.warp_id()][m_next_wb.out[r]] > 0 ); @@ -1935,7 +2270,11 @@ void ldst_unit::writeback() unsigned ldst_unit::clock_multiplier() const { - return m_config->mem_warp_parts; + //to model multiple read port, we give multiple cycles for the memory units + if(m_config->mem_unit_ports) + return m_config->mem_unit_ports; + else + return m_config->mem_warp_parts; } /* void ldst_unit::issue( register_set ®_set ) @@ -1949,7 +2288,7 @@ void ldst_unit::issue( register_set ®_set ) if (inst->is_load() and inst->space.get_type() != shared_space) { unsigned warp_id = inst->warp_id(); unsigned n_accesses = inst->accessq_count(); - for (unsigned r = 0; r < 4; r++) { + for (unsigned r = 0; r < MAX_OUTPUT_VALUES; r++) { unsigned reg_id = inst->out[r]; if (reg_id > 0) { m_pending_writes[warp_id][reg_id] += n_accesses; @@ -2014,7 +2353,11 @@ void ldst_unit::cycle() m_L1T->cycle(); m_L1C->cycle(); - if( m_L1D ) m_L1D->cycle(); + if( m_L1D ) { + m_L1D->cycle(); + if(m_config->m_L1D_config.l1_latency > 0) + L1_latency_queue_cycle(); + } warp_inst_t &pipe_reg = *m_dispatch_reg; enum mem_stage_stall_type rc_fail = NO_RC_FAIL; @@ -2037,9 +2380,9 @@ void ldst_unit::cycle() unsigned warp_id = pipe_reg.warp_id(); if( pipe_reg.is_load() ) { if( pipe_reg.space.get_type() == shared_space ) { - if( m_pipeline_reg[2]->empty() ) { + if( m_pipeline_reg[m_config->smem_latency-1]->empty() ) { // new shared memory request - move_warp(m_pipeline_reg[2],m_dispatch_reg); + move_warp(m_pipeline_reg[m_config->smem_latency-1],m_dispatch_reg); m_dispatch_reg->clear(); } } else { @@ -2049,7 +2392,7 @@ void ldst_unit::cycle() //} bool pending_requests=false; - for( unsigned r=0; r<4; r++ ) { + for( unsigned r=0; r<MAX_OUTPUT_VALUES; r++ ) { unsigned reg_id = pipe_reg.out[r]; if( reg_id > 0 ) { if( m_pending_writes[warp_id].find(reg_id) != m_pending_writes[warp_id].end() ) { @@ -2199,13 +2542,13 @@ void gpgpu_sim::shader_print_cache_stats( FILE *fout ) const{ m_cluster[i]->get_L1I_sub_stats(css); total_css += css; } - fprintf(fout, "\tL1I_total_cache_accesses = %u\n", total_css.accesses); - fprintf(fout, "\tL1I_total_cache_misses = %u\n", total_css.misses); + fprintf(fout, "\tL1I_total_cache_accesses = %llu\n", total_css.accesses); + fprintf(fout, "\tL1I_total_cache_misses = %llu\n", total_css.misses); if(total_css.accesses > 0){ fprintf(fout, "\tL1I_total_cache_miss_rate = %.4lf\n", (double)total_css.misses / (double)total_css.accesses); } - fprintf(fout, "\tL1I_total_cache_pending_hits = %u\n", total_css.pending_hits); - fprintf(fout, "\tL1I_total_cache_reservation_fails = %u\n", total_css.res_fails); + fprintf(fout, "\tL1I_total_cache_pending_hits = %llu\n", total_css.pending_hits); + fprintf(fout, "\tL1I_total_cache_reservation_fails = %llu\n", total_css.res_fails); } // L1D @@ -2216,18 +2559,18 @@ void gpgpu_sim::shader_print_cache_stats( FILE *fout ) const{ for (unsigned i=0;i<m_shader_config->n_simt_clusters;i++){ m_cluster[i]->get_L1D_sub_stats(css); - fprintf( stdout, "\tL1D_cache_core[%d]: Access = %d, Miss = %d, Miss_rate = %.3lf, Pending_hits = %u, Reservation_fails = %u\n", + fprintf( stdout, "\tL1D_cache_core[%d]: Access = %llu, Miss = %llu, Miss_rate = %.3lf, Pending_hits = %llu, Reservation_fails = %llu\n", i, css.accesses, css.misses, (double)css.misses / (double)css.accesses, css.pending_hits, css.res_fails); total_css += css; } - fprintf(fout, "\tL1D_total_cache_accesses = %u\n", total_css.accesses); - fprintf(fout, "\tL1D_total_cache_misses = %u\n", total_css.misses); + fprintf(fout, "\tL1D_total_cache_accesses = %llu\n", total_css.accesses); + fprintf(fout, "\tL1D_total_cache_misses = %llu\n", total_css.misses); if(total_css.accesses > 0){ fprintf(fout, "\tL1D_total_cache_miss_rate = %.4lf\n", (double)total_css.misses / (double)total_css.accesses); } - fprintf(fout, "\tL1D_total_cache_pending_hits = %u\n", total_css.pending_hits); - fprintf(fout, "\tL1D_total_cache_reservation_fails = %u\n", total_css.res_fails); + fprintf(fout, "\tL1D_total_cache_pending_hits = %llu\n", total_css.pending_hits); + fprintf(fout, "\tL1D_total_cache_reservation_fails = %llu\n", total_css.res_fails); total_css.print_port_stats(fout, "\tL1D_cache"); } @@ -2240,13 +2583,13 @@ void gpgpu_sim::shader_print_cache_stats( FILE *fout ) const{ m_cluster[i]->get_L1C_sub_stats(css); total_css += css; } - fprintf(fout, "\tL1C_total_cache_accesses = %u\n", total_css.accesses); - fprintf(fout, "\tL1C_total_cache_misses = %u\n", total_css.misses); + fprintf(fout, "\tL1C_total_cache_accesses = %llu\n", total_css.accesses); + fprintf(fout, "\tL1C_total_cache_misses = %llu\n", total_css.misses); if(total_css.accesses > 0){ fprintf(fout, "\tL1C_total_cache_miss_rate = %.4lf\n", (double)total_css.misses / (double)total_css.accesses); } - fprintf(fout, "\tL1C_total_cache_pending_hits = %u\n", total_css.pending_hits); - fprintf(fout, "\tL1C_total_cache_reservation_fails = %u\n", total_css.res_fails); + fprintf(fout, "\tL1C_total_cache_pending_hits = %llu\n", total_css.pending_hits); + fprintf(fout, "\tL1C_total_cache_reservation_fails = %llu\n", total_css.res_fails); } // L1T @@ -2258,13 +2601,13 @@ void gpgpu_sim::shader_print_cache_stats( FILE *fout ) const{ m_cluster[i]->get_L1T_sub_stats(css); total_css += css; } - fprintf(fout, "\tL1T_total_cache_accesses = %u\n", total_css.accesses); - fprintf(fout, "\tL1T_total_cache_misses = %u\n", total_css.misses); + fprintf(fout, "\tL1T_total_cache_accesses = %llu\n", total_css.accesses); + fprintf(fout, "\tL1T_total_cache_misses = %llu\n", total_css.misses); if(total_css.accesses > 0){ fprintf(fout, "\tL1T_total_cache_miss_rate = %.4lf\n", (double)total_css.misses / (double)total_css.accesses); } - fprintf(fout, "\tL1T_total_cache_pending_hits = %u\n", total_css.pending_hits); - fprintf(fout, "\tL1T_total_cache_reservation_fails = %u\n", total_css.res_fails); + fprintf(fout, "\tL1T_total_cache_pending_hits = %llu\n", total_css.pending_hits); + fprintf(fout, "\tL1T_total_cache_reservation_fails = %llu\n", total_css.res_fails); } } @@ -2357,7 +2700,7 @@ void shader_core_ctx::incexecstat(warp_inst_t *&inst) switch(inst->sp_op){ case INT__OP: - incialu_stat(inst->active_count(),25); + incialu_stat(inst->active_count(),32); break; case INT_MUL_OP: incimul_stat(inst->active_count(),7.2); @@ -2623,11 +2966,86 @@ unsigned int shader_core_config::max_cta( const kernel_info_t &k ) const abort(); } + if(adaptive_volta_cache_config && !k.volta_cache_config_set) { + //For Volta, we assign the remaining shared memory to L1 cache + //For more info, see https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#shared-memory-7-x + unsigned total_shmed = kernel_info->smem * result; + assert(total_shmed >=0 && total_shmed <= gpgpu_shmem_size); + assert(gpgpu_shmem_size == 98304); //Volta has 96 KB shared + assert(m_L1D_config.get_nset() == 4); //Volta L1 has four sets + if(total_shmed < gpgpu_shmem_size){ + if(total_shmed == 0) + m_L1D_config.set_assoc(256); //L1 is 128KB ans shd=0 + else if(total_shmed > 0 && total_shmed <= 8192) + m_L1D_config.set_assoc(240); //L1 is 120KB ans shd=8KB + else if(total_shmed > 8192 && total_shmed <= 16384) + m_L1D_config.set_assoc(224); //L1 is 112KB ans shd=16KB + else if(total_shmed > 16384 && total_shmed <= 32768) + m_L1D_config.set_assoc(192); //L1 is 96KB ans shd=32KB + else if(total_shmed > 32768 && total_shmed <= 65536) + m_L1D_config.set_assoc(128); //L1 is 64KB ans shd=64KB + else if(total_shmed > 65536 && total_shmed <= gpgpu_shmem_size) + m_L1D_config.set_assoc(64); //L1 is 32KB and shd=96KB + else + assert(0); + + printf ("GPGPU-Sim: Reconfigure L1 cache in Volta Archi to %uKB\n", m_L1D_config.get_total_size_inKB()); + } + + k.volta_cache_config_set = true; + } + return result; } +void shader_core_config::set_pipeline_latency() { + + //calculate the max latency based on the input + + unsigned int_latency[5]; + unsigned fp_latency[5]; + unsigned dp_latency[5]; + unsigned sfu_latency; + unsigned tensor_latency; + + /* + * [0] ADD,SUB + * [1] MAX,Min + * [2] MUL + * [3] MAD + * [4] DIV + */ + sscanf(opcode_latency_int, "%u,%u,%u,%u,%u", + &int_latency[0],&int_latency[1],&int_latency[2], + &int_latency[3],&int_latency[4]); + sscanf(opcode_latency_fp, "%u,%u,%u,%u,%u", + &fp_latency[0],&fp_latency[1],&fp_latency[2], + &fp_latency[3],&fp_latency[4]); + sscanf(opcode_latency_dp, "%u,%u,%u,%u,%u", + &dp_latency[0],&dp_latency[1],&dp_latency[2], + &dp_latency[3],&dp_latency[4]); + sscanf(opcode_latency_sfu, "%u", + &sfu_latency); + sscanf(opcode_latency_tensor, "%u", + &tensor_latency); + + //all div operation are executed on sfu + //assume that the max latency are dp div or normal sfu_latency + max_sfu_latency = std::max(dp_latency[4],sfu_latency); + //assume that the max operation has the max latency + max_sp_latency = fp_latency[1]; + max_int_latency = int_latency[1]; + max_dp_latency = dp_latency[1]; + max_tensor_core_latency = tensor_latency; + +} + void shader_core_ctx::cycle() { + if(!isactive() && get_not_completed() == 0) + return; + + elapsed_cycles_sm_tot++; m_stats->shader_cycles[m_sid]++; writeback(); execute(); @@ -2644,6 +3062,11 @@ void shader_core_ctx::cache_flush() m_ldst_unit->flush(); } +void shader_core_ctx::cache_invalidate() +{ + m_ldst_unit->invalidate(); +} + // modifiers std::list<opndcoll_rfu_t::op_t> opndcoll_rfu_t::arbiter_t::allocate_reads() { @@ -3134,33 +3557,50 @@ void opndcoll_rfu_t::init( unsigned num_banks, shader_core_ctx *shader ) m_bank_warp_shift = (unsigned)(int) (log(m_warp_size+0.5) / log(2.0)); assert( (m_bank_warp_shift == 5) || (m_warp_size != 32) ); + sub_core_model = shader->get_config()->sub_core_model; + m_num_warp_sceds = shader->get_config()->gpgpu_num_sched_per_core; + if(sub_core_model) + assert(num_banks % shader->get_config()->gpgpu_num_sched_per_core == 0); + m_num_banks_per_sched = num_banks / shader->get_config()->gpgpu_num_sched_per_core; + for( unsigned j=0; j<m_cu.size(); j++) { - m_cu[j]->init(j,num_banks,m_bank_warp_shift,shader->get_config(),this); + m_cu[j]->init(j,num_banks,m_bank_warp_shift,shader->get_config(),this, sub_core_model, m_num_banks_per_sched ); } m_initialized=true; + + + + } -int register_bank(int regnum, int wid, unsigned num_banks, unsigned bank_warp_shift) +int register_bank(int regnum, int wid, unsigned num_banks, unsigned bank_warp_shift, bool sub_core_model, unsigned banks_per_sched, unsigned sched_id) { int bank = regnum; if (bank_warp_shift) bank += wid; - return bank % num_banks; + if(sub_core_model) { + unsigned bank_num = (bank % banks_per_sched) + (sched_id * banks_per_sched); + assert(bank_num < num_banks); + return bank_num; + } + else + return bank % num_banks; } -bool opndcoll_rfu_t::writeback( const warp_inst_t &inst ) +bool opndcoll_rfu_t::writeback( warp_inst_t &inst ) { assert( !inst.empty() ); std::list<unsigned> regs = m_shader->get_regs_written(inst); - std::list<unsigned>::iterator r; - unsigned n=0; - for( r=regs.begin(); r!=regs.end();r++,n++ ) { - unsigned reg = *r; - unsigned bank = register_bank(reg,inst.warp_id(),m_num_banks,m_bank_warp_shift); - if( m_arbiter.bank_idle(bank) ) { - m_arbiter.allocate_bank_for_write(bank,op_t(&inst,reg,m_num_banks,m_bank_warp_shift)); - } else { - return false; + for( unsigned op=0; op < MAX_REG_OPERANDS; op++ ) { + int reg_num = inst.arch_reg.dst[op]; // this math needs to match that used in function_info::ptx_decode_inst + if( reg_num >= 0 ){ // valid register + unsigned bank = register_bank(reg_num,inst.warp_id(),m_num_banks,m_bank_warp_shift, sub_core_model, m_num_banks_per_sched, inst.get_schd_id()); + if( m_arbiter.bank_idle(bank) ) { + m_arbiter.allocate_bank_for_write(bank,op_t(&inst,reg_num,m_num_banks,m_bank_warp_shift, sub_core_model, m_num_banks_per_sched, inst.get_schd_id())); + inst.arch_reg.dst[op] = -1; + } else { + return false; + } } } for(unsigned i=0;i<(unsigned)regs.size();i++){ @@ -3242,7 +3682,7 @@ void opndcoll_rfu_t::allocate_reads() const op_t &rr = *r; unsigned reg = rr.get_reg(); unsigned wid = rr.get_wid(); - unsigned bank = register_bank(reg,wid,m_num_banks,m_bank_warp_shift); + unsigned bank = register_bank(reg,wid,m_num_banks,m_bank_warp_shift,sub_core_model, m_num_banks_per_sched, rr.get_sid()); m_arbiter.allocate_for_read(bank,rr); read_ops[bank] = rr; } @@ -3293,7 +3733,9 @@ void opndcoll_rfu_t::collector_unit_t::init( unsigned n, unsigned num_banks, unsigned log2_warp_size, const core_config *config, - opndcoll_rfu_t *rfu ) + opndcoll_rfu_t *rfu, + bool sub_core_model, + unsigned banks_per_sched) { m_rfu=rfu; m_cuid=n; @@ -3301,6 +3743,8 @@ void opndcoll_rfu_t::collector_unit_t::init( unsigned n, assert(m_warp==NULL); m_warp = new warp_inst_t(config); m_bank_warp_shift=log2_warp_size; + m_sub_core_model = sub_core_model; + m_num_banks_per_sched = banks_per_sched; } bool opndcoll_rfu_t::collector_unit_t::allocate( register_set* pipeline_reg_set, register_set* output_reg_set ) @@ -3315,7 +3759,7 @@ bool opndcoll_rfu_t::collector_unit_t::allocate( register_set* pipeline_reg_set, for( unsigned op=0; op < MAX_REG_OPERANDS; op++ ) { int reg_num = (*pipeline_reg)->arch_reg.src[op]; // this math needs to match that used in function_info::ptx_decode_inst if( reg_num >= 0 ) { // valid register - m_src_op[op] = op_t( this, op, reg_num, m_num_banks, m_bank_warp_shift ); + m_src_op[op] = op_t( this, op, reg_num, m_num_banks, m_bank_warp_shift, m_sub_core_model, m_num_banks_per_sched, (*pipeline_reg)->get_schd_id() ); m_not_ready.set(op); } else m_src_op[op] = op_t(); @@ -3398,6 +3842,15 @@ void simt_core_cluster::print_not_completed( FILE *fp ) const } } + +float simt_core_cluster::get_current_occupancy( unsigned long long& active, unsigned long long& total ) const { + float aggregate = 0.f; + for( unsigned i=0; i < m_config->n_simt_cores_per_cluster; i++ ) { + aggregate+=m_core[i]->get_current_occupancy( active, total ); + } + return aggregate / m_config->n_simt_cores_per_cluster; +} + unsigned simt_core_cluster::get_n_active_cta() const { unsigned n=0; @@ -3461,6 +3914,12 @@ void simt_core_cluster::cache_flush() m_core[i]->cache_flush(); } +void simt_core_cluster::cache_invalidate() +{ + for( unsigned i=0; i < m_config->n_simt_cores_per_cluster; i++ ) + m_core[i]->cache_invalidate(); +} + bool simt_core_cluster::icnt_injection_buffer_full(unsigned size, bool write) { unsigned request_size = size; @@ -3478,6 +3937,7 @@ void simt_core_cluster::icnt_inject_request_packet(class mem_fetch *mf) case CONST_ACC_R: m_stats->gpgpu_n_mem_const++; break; case TEXTURE_ACC_R: m_stats->gpgpu_n_mem_texture++; break; case GLOBAL_ACC_R: m_stats->gpgpu_n_mem_read_global++; break; + //case GLOBAL_ACC_R: m_stats->gpgpu_n_mem_read_global++; printf("read_global%d\n",m_stats->gpgpu_n_mem_read_global); break; case GLOBAL_ACC_W: m_stats->gpgpu_n_mem_write_global++; break; case LOCAL_ACC_R: m_stats->gpgpu_n_mem_read_local++; break; case LOCAL_ACC_W: m_stats->gpgpu_n_mem_write_local++; break; diff --git a/src/gpgpu-sim/shader.h b/src/gpgpu-sim/shader.h index ae22eaa..a0c2b63 100644 --- a/src/gpgpu-sim/shader.h +++ b/src/gpgpu-sim/shader.h @@ -55,7 +55,6 @@ #include "traffic_breakdown.h" - #define NO_OP_FLAG 0xFF /* READ_PACKET_SIZE: @@ -76,7 +75,9 @@ enum exec_unit_type_t SP = 1, SFU = 2, MEM = 3, - DP = 4 + DP = 4, + INT = 5, + TENSOR = 6 }; class thread_ctx_t { @@ -291,10 +292,10 @@ inline unsigned wid_from_hw_tid(unsigned tid, unsigned warp_size){return tid/war const unsigned WARP_PER_CTA_MAX = 64; typedef std::bitset<WARP_PER_CTA_MAX> warp_set_t; -int register_bank(int regnum, int wid, unsigned num_banks, unsigned bank_warp_shift); +int register_bank(int regnum, int wid, unsigned num_banks, unsigned bank_warp_shift, bool sub_core_model, unsigned banks_per_sched, unsigned sched_id ); class shader_core_ctx; -class shader_core_config; +struct shader_core_config; class shader_core_stats; enum scheduler_prioritization_type @@ -328,11 +329,13 @@ public: register_set* sp_out, register_set* dp_out, register_set* sfu_out, + register_set* int_out, + register_set* tensor_core_out, register_set* mem_out, int id) : m_supervised_warps(), m_stats(stats), m_shader(shader), m_scoreboard(scoreboard), m_simt_stack(simt), /*m_pipeline_reg(pipe_regs),*/ m_warp(warp), - m_sp_out(sp_out),m_dp_out(dp_out),m_sfu_out(sfu_out),m_mem_out(mem_out), m_id(id){} + m_sp_out(sp_out),m_dp_out(dp_out),m_sfu_out(sfu_out),m_int_out(int_out),m_tensor_core_out(tensor_core_out),m_mem_out(mem_out), m_id(id){} virtual ~scheduler_unit(){} virtual void add_supervised_warp_id(int i) { m_supervised_warps.push_back(&warp(i)); @@ -378,6 +381,8 @@ public: // m_supervised_warps with their scheduling policies virtual void order_warps() = 0; + int get_schd_id() const {return m_id;} + protected: virtual void do_on_warp_issued( unsigned warp_id, unsigned num_issued, @@ -406,6 +411,8 @@ protected: register_set* m_sp_out; register_set* m_dp_out; register_set* m_sfu_out; + register_set* m_int_out; + register_set* m_tensor_core_out; register_set* m_mem_out; int m_id; @@ -419,9 +426,11 @@ public: register_set* sp_out, register_set* dp_out, register_set* sfu_out, + register_set* int_out, + register_set* tensor_core_out, register_set* mem_out, int id ) - : scheduler_unit ( stats, shader, scoreboard, simt, warp, sp_out, dp_out, sfu_out, mem_out, id ){} + : scheduler_unit ( stats, shader, scoreboard, simt, warp, sp_out, dp_out, sfu_out, int_out, tensor_core_out, mem_out, id ){} virtual ~lrr_scheduler () {} virtual void order_warps (); virtual void done_adding_supervised_warps() { @@ -437,9 +446,11 @@ public: register_set* sp_out, register_set* dp_out, register_set* sfu_out, + register_set* int_out, + register_set* tensor_core_out, register_set* mem_out, int id ) - : scheduler_unit ( stats, shader, scoreboard, simt, warp, sp_out, dp_out, sfu_out, mem_out, id ){} + : scheduler_unit ( stats, shader, scoreboard, simt, warp, sp_out, dp_out, sfu_out, int_out, tensor_core_out, mem_out, id ){} virtual ~gto_scheduler () {} virtual void order_warps (); virtual void done_adding_supervised_warps() { @@ -456,9 +467,11 @@ public: register_set* sp_out, register_set* dp_out, register_set* sfu_out, + register_set* int_out, + register_set* tensor_core_out, register_set* mem_out, int id ) - : scheduler_unit ( stats, shader, scoreboard, simt, warp, sp_out, dp_out, sfu_out, mem_out, id ){} + : scheduler_unit ( stats, shader, scoreboard, simt, warp, sp_out, dp_out, sfu_out, int_out, tensor_core_out, mem_out, id ){} virtual ~oldest_scheduler () {} virtual void order_warps (); virtual void done_adding_supervised_warps() { @@ -475,10 +488,12 @@ public: register_set* sp_out, register_set* dp_out, register_set* sfu_out, + register_set* int_out, + register_set* tensor_core_out, register_set* mem_out, int id, char* config_str ) - : scheduler_unit ( stats, shader, scoreboard, simt, warp, sp_out, dp_out, sfu_out, mem_out, id ), + : scheduler_unit ( stats, shader, scoreboard, simt, warp, sp_out, dp_out, sfu_out, int_out, tensor_core_out, mem_out, id ), m_pending_warps() { unsigned inner_level_readin; @@ -526,6 +541,8 @@ public: register_set* sp_out, register_set* dp_out, register_set* sfu_out, + register_set* int_out, + register_set* tensor_core_out, register_set* mem_out, int id, char* config_string ); @@ -558,7 +575,7 @@ public: void init( unsigned num_banks, shader_core_ctx *shader ); // modifiers - bool writeback( const warp_inst_t &warp ); // might cause stall + bool writeback( warp_inst_t &warp ); void step() { @@ -601,23 +618,25 @@ private: public: op_t() { m_valid = false; } - op_t( collector_unit_t *cu, unsigned op, unsigned reg, unsigned num_banks, unsigned bank_warp_shift ) + op_t( collector_unit_t *cu, unsigned op, unsigned reg, unsigned num_banks, unsigned bank_warp_shift, bool sub_core_model, unsigned banks_per_sched, unsigned sched_id ) { m_valid = true; m_warp=NULL; m_cu = cu; m_operand = op; m_register = reg; - m_bank = register_bank(reg,cu->get_warp_id(),num_banks,bank_warp_shift); + m_shced_id = sched_id; + m_bank = register_bank(reg,cu->get_warp_id(),num_banks,bank_warp_shift, sub_core_model, banks_per_sched, sched_id); } - op_t( const warp_inst_t *warp, unsigned reg, unsigned num_banks, unsigned bank_warp_shift ) + op_t( const warp_inst_t *warp, unsigned reg, unsigned num_banks, unsigned bank_warp_shift, bool sub_core_model, unsigned banks_per_sched, unsigned sched_id ) { m_valid=true; m_warp=warp; m_register=reg; m_cu=NULL; m_operand = -1; - m_bank = register_bank(reg,warp->warp_id(),num_banks,bank_warp_shift); + m_shced_id = sched_id; + m_bank = register_bank(reg,warp->warp_id(),num_banks,bank_warp_shift, sub_core_model, banks_per_sched, sched_id); } // accessors @@ -633,6 +652,10 @@ private: else if( m_cu ) return m_cu->get_warp_id(); else abort(); } + unsigned get_sid() const + { + return m_shced_id; + } unsigned get_active_count() const { if( m_warp ) return m_warp->active_count(); @@ -677,6 +700,7 @@ private: unsigned m_operand; // operand offset in instruction. e.g., add r1,r2,r3; r2 is oprd 0, r3 is 1 (r1 is dst) unsigned m_register; unsigned m_bank; + unsigned m_shced_id; //scheduler id that has issued this inst }; enum alloc_t { @@ -697,7 +721,7 @@ private: else if( m_allocation == WRITE_ALLOC ) { fprintf(fp,"wr: "); m_op.dump(fp); } fprintf(fp,"\n"); } - void alloc_read( const op_t &op ) { assert(is_free()); m_allocation=READ_ALLOC; m_op=op; } + void alloc_read( const op_t &op ) { assert(is_free()); m_allocation=READ_ALLOC; m_op=op; } void alloc_write( const op_t &op ) { assert(is_free()); m_allocation=WRITE_ALLOC; m_op=op; } void reset() { m_allocation = NO_ALLOC; } private: @@ -851,7 +875,9 @@ private: unsigned num_banks, unsigned log2_warp_size, const core_config *config, - opndcoll_rfu_t *rfu ); + opndcoll_rfu_t *rfu, + bool m_sub_core_model, + unsigned num_banks_per_sched); bool allocate( register_set* pipeline_reg, register_set* output_reg ); void collect_operand( unsigned op ) @@ -879,6 +905,9 @@ private: unsigned m_bank_warp_shift; opndcoll_rfu_t *m_rfu; + unsigned m_num_banks_per_sched; + bool m_sub_core_model; + }; class dispatch_unit_t { @@ -921,6 +950,10 @@ private: std::vector<collector_unit_t *> m_cu; arbiter_t m_arbiter; + unsigned m_num_banks_per_sched; + unsigned m_num_warp_sceds; + bool sub_core_model; + //unsigned m_num_ports; //std::vector<warp_inst_t**> m_input; //std::vector<warp_inst_t**> m_output; @@ -1000,7 +1033,7 @@ struct ifetch_buffer_t { unsigned m_warp_id; }; -class shader_core_config; +struct shader_core_config; class simd_function_unit { public: @@ -1021,6 +1054,9 @@ public: fprintf(fp,"%s dispatch= ", m_name.c_str() ); m_dispatch_reg->print(fp); } + const char* get_name() { + return m_name.c_str(); + } protected: std::string m_name; const shader_core_config *m_config; @@ -1036,16 +1072,8 @@ public: //modifiers virtual void cycle(); virtual void issue( register_set& source_reg ); - virtual unsigned get_active_lanes_in_pipeline() - { - active_mask_t active_lanes; - active_lanes.reset(); - for( unsigned stage=0; (stage+1)<m_pipeline_depth; stage++ ){ - if( !m_pipeline_reg[stage]->empty() ) - active_lanes|=m_pipeline_reg[stage]->get_active_mask(); - } - return active_lanes.count(); - } + virtual unsigned get_active_lanes_in_pipeline(); + virtual void active_lanes_in_pipeline() = 0; /* virtual void issue( register_set& source_reg ) @@ -1076,6 +1104,9 @@ protected: warp_inst_t **m_pipeline_reg; register_set *m_result_port; class shader_core_ctx *m_core; + + unsigned active_insts_in_pipeline; + }; class sfu : public pipelined_simd_unit @@ -1112,6 +1143,46 @@ public: virtual void issue( register_set& source_reg ); }; +class tensor_core : public pipelined_simd_unit +{ +public: + tensor_core( register_set* result_port, const shader_core_config *config, shader_core_ctx *core ); + virtual bool can_issue( const warp_inst_t &inst ) const + { + switch(inst.op) { + case TENSOR_CORE_OP: break; + default: return false; + } + return pipelined_simd_unit::can_issue(inst); + } + virtual void active_lanes_in_pipeline(); + virtual void issue( register_set& source_reg ); +}; + + +class int_unit : public pipelined_simd_unit +{ +public: + int_unit( register_set* result_port, const shader_core_config *config, shader_core_ctx *core ); + virtual bool can_issue( const warp_inst_t &inst ) const + { + switch(inst.op) { + case SFU_OP: return false; + case LOAD_OP: return false; + case TENSOR_CORE_LOAD_OP: return false; + case STORE_OP: return false; + case TENSOR_CORE_STORE_OP: return false; + case MEMORY_BARRIER_OP: return false; + case SP_OP: return false; + case DP_OP: return false; + default: break; + } + return pipelined_simd_unit::can_issue(inst); + } + virtual void active_lanes_in_pipeline(); + virtual void issue( register_set& source_reg ); +}; + class sp_unit : public pipelined_simd_unit { public: @@ -1121,7 +1192,9 @@ public: switch(inst.op) { case SFU_OP: return false; case LOAD_OP: return false; + case TENSOR_CORE_LOAD_OP: return false; case STORE_OP: return false; + case TENSOR_CORE_STORE_OP: return false; case MEMORY_BARRIER_OP: return false; case DP_OP: return false; default: break; @@ -1155,6 +1228,7 @@ public: void fill( mem_fetch *mf ); void flush(); + void invalidate(); void writeback(); // accessors @@ -1164,7 +1238,9 @@ public: { switch(inst.op) { case LOAD_OP: break; + case TENSOR_CORE_LOAD_OP: break; case STORE_OP: break; + case TENSOR_CORE_STORE_OP: break; case MEMORY_BARRIER_OP: break; default: return false; } @@ -1219,6 +1295,7 @@ protected: mem_fetch *mf, enum cache_request_status status ); mem_stage_stall_type process_memory_access_queue( cache_t *cache, warp_inst_t &inst ); + mem_stage_stall_type process_memory_access_queue_l1cache( l1_cache *cache, warp_inst_t &inst ); const memory_config *m_memory_config; class mem_fetch_interface *m_icnt; @@ -1247,31 +1324,42 @@ protected: // for debugging unsigned long long m_last_inst_gpu_sim_cycle; unsigned long long m_last_inst_gpu_tot_sim_cycle; + + std::deque<mem_fetch* > l1_latency_queue; + void L1_latency_queue_cycle(); }; enum pipeline_stage_name_t { ID_OC_SP=0, ID_OC_DP, + ID_OC_INT, ID_OC_SFU, ID_OC_MEM, OC_EX_SP, OC_EX_DP, + OC_EX_INT, OC_EX_SFU, OC_EX_MEM, EX_WB, + ID_OC_TENSOR_CORE, + OC_EX_TENSOR_CORE, N_PIPELINE_STAGES -}; + }; const char* const pipeline_stage_name_decode[] = { "ID_OC_SP", "ID_OC_DP", + "ID_OC_INT", "ID_OC_SFU", "ID_OC_MEM", "OC_EX_SP", "OC_EX_DP", + "OC_EX_INT", "OC_EX_SFU", "OC_EX_MEM", "EX_WB", + "ID_OC_TENSOR_CORE", + "OC_EX_TENSOR_CORE", "N_PIPELINE_STAGES" }; @@ -1294,16 +1382,24 @@ struct shader_core_config : public core_config char* toks = new char[100]; char* tokd = toks; strcpy(toks,pipeline_widths_string); - + toks = strtok(toks,","); - for (unsigned i = 0; i < N_PIPELINE_STAGES; i++) { + + /* Removing the tensorcore pipeline while reading the config files if the tensor core is not available. + If we won't remove it, old regression will be broken. + So to support the legacy config files it's best to handle in this way. + */ + int num_config_to_read=N_PIPELINE_STAGES-2*(!gpgpu_tensor_core_avail); + + for (unsigned i = 0; i <num_config_to_read; i++) { assert(toks); ntok = sscanf(toks,"%d", &pipe_widths[i]); assert(ntok == 1); toks = strtok(NULL,","); } - delete[] tokd; + delete[] tokd; + if (n_thread_per_shader > MAX_THREAD_PER_SM) { printf("GPGPU-Sim uArch: Error ** increase MAX_THREAD_PER_SM in abstract_hardware_model.h from %u to %u\n", MAX_THREAD_PER_SM, n_thread_per_shader); @@ -1311,9 +1407,10 @@ struct shader_core_config : public core_config } max_warps_per_shader = n_thread_per_shader/warp_size; assert( !(n_thread_per_shader % warp_size) ); - max_sfu_latency = 512; - max_sp_latency = 32; - m_L1I_config.init(m_L1I_config.m_config_string,FuncCachePreferNone); + + set_pipeline_latency(); + + m_L1I_config.init(m_L1I_config.m_config_string,FuncCachePreferNone); m_L1T_config.init(m_L1T_config.m_config_string,FuncCachePreferNone); m_L1C_config.init(m_L1C_config.m_config_string,FuncCachePreferNone); m_L1D_config.init(m_L1D_config.m_config_string,FuncCachePreferNone); @@ -1327,6 +1424,7 @@ struct shader_core_config : public core_config unsigned sid_to_cluster( unsigned sid ) const { return sid / n_simt_cores_per_cluster; } unsigned sid_to_cid( unsigned sid ) const { return sid % n_simt_cores_per_cluster; } unsigned cid_to_sid( unsigned cid, unsigned cluster_id ) const { return cluster_id*n_simt_cores_per_cluster + cid; } + void set_pipeline_latency(); // data char *gpgpu_shader_core_pipeline_opt; @@ -1340,7 +1438,8 @@ struct shader_core_config : public core_config unsigned max_cta_per_core; //Limit on number of concurrent CTAs in shader core unsigned max_barriers_per_cta; char * gpgpu_scheduler_string; - + unsigned gpgpu_shmem_per_block; + unsigned gpgpu_registers_per_block; char* pipeline_widths_string; int pipe_widths[N_PIPELINE_STAGES]; @@ -1356,28 +1455,38 @@ struct shader_core_config : public core_config bool gpgpu_dual_issue_diff_exec_units; //op collector + bool enable_specialized_operand_collector; int gpgpu_operand_collector_num_units_sp; int gpgpu_operand_collector_num_units_dp; int gpgpu_operand_collector_num_units_sfu; + int gpgpu_operand_collector_num_units_tensor_core; int gpgpu_operand_collector_num_units_mem; int gpgpu_operand_collector_num_units_gen; + int gpgpu_operand_collector_num_units_int; unsigned int gpgpu_operand_collector_num_in_ports_sp; unsigned int gpgpu_operand_collector_num_in_ports_dp; unsigned int gpgpu_operand_collector_num_in_ports_sfu; + unsigned int gpgpu_operand_collector_num_in_ports_tensor_core; unsigned int gpgpu_operand_collector_num_in_ports_mem; unsigned int gpgpu_operand_collector_num_in_ports_gen; + unsigned int gpgpu_operand_collector_num_in_ports_int; unsigned int gpgpu_operand_collector_num_out_ports_sp; unsigned int gpgpu_operand_collector_num_out_ports_dp; unsigned int gpgpu_operand_collector_num_out_ports_sfu; + unsigned int gpgpu_operand_collector_num_out_ports_tensor_core; unsigned int gpgpu_operand_collector_num_out_ports_mem; unsigned int gpgpu_operand_collector_num_out_ports_gen; + unsigned int gpgpu_operand_collector_num_out_ports_int; int gpgpu_num_sp_units; + int gpgpu_tensor_core_avail; int gpgpu_num_dp_units; int gpgpu_num_sfu_units; + int gpgpu_num_tensor_core_units; int gpgpu_num_mem_units; + int gpgpu_num_int_units; //Shader core resources unsigned gpgpu_shader_registers; @@ -1387,9 +1496,13 @@ struct shader_core_config : public core_config bool gpgpu_reg_bank_use_warp_id; bool gpgpu_local_mem_map; bool gpgpu_ignore_resources_limitation; + bool sub_core_model; unsigned max_sp_latency; + unsigned max_int_latency; unsigned max_sfu_latency; + unsigned max_dp_latency; + unsigned max_tensor_core_latency; unsigned n_simt_cores_per_cluster; unsigned n_simt_clusters; @@ -1398,15 +1511,20 @@ struct shader_core_config : public core_config int simt_core_sim_order; + unsigned smem_latency; + unsigned mem2device(unsigned memid) const { return memid + n_simt_clusters; } //Jin: concurrent kernel on sm bool gpgpu_concurrent_kernel_sm; + + bool adpative_volta_cache_config; + }; struct shader_core_stats_pod { - void* shader_core_stats_pod_start[]; // DO NOT MOVE FROM THE TOP - spaceless pointer to the start of this structure + void* shader_core_stats_pod_start[0]; // DO NOT MOVE FROM THE TOP - spaceless pointer to the start of this structure unsigned long long *shader_cycles; unsigned *m_num_sim_insn; // number of scalar thread instructions committed by this shader core unsigned *m_num_sim_winsn; // number of warp instructions committed by this shader core @@ -1427,12 +1545,14 @@ struct shader_core_stats_pod { unsigned *m_num_fpdiv_acesses; unsigned *m_num_sp_acesses; unsigned *m_num_sfu_acesses; + unsigned *m_num_tensor_core_acesses; unsigned *m_num_trans_acesses; unsigned *m_num_mem_acesses; unsigned *m_num_sp_committed; unsigned *m_num_tlb_hits; unsigned *m_num_tlb_accesses; unsigned *m_num_sfu_committed; + unsigned *m_num_tensor_core_committed; unsigned *m_num_mem_committed; unsigned *m_read_regfile_acesses; unsigned *m_write_regfile_acesses; @@ -1441,12 +1561,14 @@ struct shader_core_stats_pod { unsigned *m_num_imul32_acesses; unsigned *m_active_sp_lanes; unsigned *m_active_sfu_lanes; + unsigned *m_active_tensor_core_lanes; unsigned *m_active_fu_lanes; unsigned *m_active_fu_mem_lanes; unsigned *m_n_diverge; // number of divergence occurring in this shader unsigned gpgpu_n_load_insn; unsigned gpgpu_n_store_insn; unsigned gpgpu_n_shmem_insn; + unsigned gpgpu_n_sstarr_insn; unsigned gpgpu_n_tex_insn; unsigned gpgpu_n_const_insn; unsigned gpgpu_n_param_insn; @@ -1513,6 +1635,7 @@ public: m_num_fpdiv_acesses= (unsigned*) calloc(config->num_shader(),sizeof(unsigned)); m_num_sp_acesses= (unsigned*) calloc(config->num_shader(),sizeof(unsigned)); m_num_sfu_acesses= (unsigned*) calloc(config->num_shader(),sizeof(unsigned)); + m_num_tensor_core_acesses= (unsigned*) calloc(config->num_shader(),sizeof(unsigned)); m_num_trans_acesses= (unsigned*) calloc(config->num_shader(),sizeof(unsigned)); m_num_mem_acesses= (unsigned*) calloc(config->num_shader(),sizeof(unsigned)); m_num_sp_committed= (unsigned*) calloc(config->num_shader(),sizeof(unsigned)); @@ -1520,9 +1643,11 @@ public: m_num_tlb_accesses=(unsigned*) calloc(config->num_shader(),sizeof(unsigned)); m_active_sp_lanes= (unsigned*) calloc(config->num_shader(),sizeof(unsigned)); m_active_sfu_lanes= (unsigned*) calloc(config->num_shader(),sizeof(unsigned)); + m_active_tensor_core_lanes= (unsigned*) calloc(config->num_shader(),sizeof(unsigned)); m_active_fu_lanes= (unsigned*) calloc(config->num_shader(),sizeof(unsigned)); m_active_fu_mem_lanes= (unsigned*) calloc(config->num_shader(),sizeof(unsigned)); m_num_sfu_committed= (unsigned*) calloc(config->num_shader(),sizeof(unsigned)); + m_num_tensor_core_committed= (unsigned*) calloc(config->num_shader(),sizeof(unsigned)); m_num_mem_committed= (unsigned*) calloc(config->num_shader(),sizeof(unsigned)); m_read_regfile_acesses= (unsigned*) calloc(config->num_shader(),sizeof(unsigned)); m_write_regfile_acesses= (unsigned*) calloc(config->num_shader(),sizeof(unsigned)); @@ -1655,6 +1780,7 @@ public: void issue_block2core( class kernel_info_t &kernel ); void cache_flush(); + void cache_invalidate(); void accept_fetch_response( mem_fetch *mf ); void accept_ldst_unit_response( class mem_fetch * mf ); void broadcast_barrier_reduction(unsigned cta_id, unsigned bar_id,warp_set_t warps); @@ -1683,6 +1809,7 @@ public: // accessors virtual bool warp_waiting_at_barrier( unsigned warp_id ) const; void get_pdom_stack_top_info( unsigned tid, unsigned *pc, unsigned *rpc ) const; + float get_current_occupancy( unsigned long long & active, unsigned long long & total ) const; // used by pipeline timing model components: // modifiers @@ -1825,7 +1952,7 @@ public: } int test_res_bus(int latency); - void init_warps(unsigned cta_id, unsigned start_thread, unsigned end_thread); + void init_warps(unsigned cta_id, unsigned start_thread, unsigned end_thread,unsigned ctaid, int cta_size, unsigned kernel_id); virtual void checkExecutionStatusAndUpdate(warp_inst_t &inst, unsigned t, unsigned tid); address_type next_pc( int tid ) const; void fetch(); @@ -1837,7 +1964,7 @@ public: friend class scheduler_unit; //this is needed to use private issue warp. friend class TwoLevelScheduler; friend class LooseRoundRobbinScheduler; - void issue_warp( register_set& warp, const warp_inst_t *pI, const active_mask_t &active_mask, unsigned warp_id ); + void issue_warp( register_set& warp, const warp_inst_t *pI, const active_mask_t &active_mask, unsigned warp_id, unsigned sch_id ); void func_exec_inst( warp_inst_t &inst ); // Returns numbers of addresses in translated_addrs @@ -1889,6 +2016,7 @@ public: std::vector<register_set> m_pipeline_reg; Scoreboard *m_scoreboard; opndcoll_rfu_t m_operand_collector; + int m_active_warps; //schedule std::vector<scheduler_unit*> schedulers; @@ -1947,6 +2075,7 @@ public: void reinit(); unsigned issue_block2core(); void cache_flush(); + void cache_invalidate(); bool icnt_injection_buffer_full(unsigned size, bool write); void icnt_inject_request_packet(class mem_fetch *mf); @@ -1977,6 +2106,7 @@ public: void get_L1T_sub_stats(struct cache_sub_stats &css) const; void get_icnt_stats(long &n_simt_to_mem, long &n_mem_to_simt) const; + float get_current_occupancy( unsigned long long& active, unsigned long long & total ) const; private: unsigned m_cluster_id; |
