diff options
| author | WilliamMTK <[email protected]> | 2024-12-11 16:52:40 -0500 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-12-11 21:52:40 +0000 |
| commit | 752d4e5bf622b0d7c730e3eb2f1b3e3cf91e81fa (patch) | |
| tree | c21658a59c854d8251706796570ce80e34a6ef7b /src/gpgpu-sim | |
| parent | 667834cfe5214523edd7769aeab77f91b7137686 (diff) | |
Add SST integration into gpgpusim (#44)
* Add accommodations to run gpgpusim with SST simulation framework through balar
* Output setup_environment options when sourcing
* Add SST directive check when creating sim thread
* Add sst side test for jenkins
* sst-integration: update Jenkinsfile with offical sst-elements repo and fix bugs in pipeline script
* sst-integration: direct jenkins to rebuild gpgpusim before testing for sst
* sst-integration: fix bugs in sst repos config
* sst-integration: let Jenkins rebuilds simulator
Since the simulator needs to be configured with both normal mode and sst mode, need to rebuild make target to clean prior runs.
* sst-integration: Update Jenkinsfile to source env vars when running balar test
* sst-integration: refactor code to remove __SST__ flag
* sst-integration: fix a bug that init cluster twice for sst
* sst-integration: fix a bug of not sending mem packets to SST
* sst-integration: remove sst flags from makefiles and setup_env
* sst-integration: add comments to SST changes
* sst-integration: remove rebuilding simulator in jenkins when testing for SST
* sst-integration: revert simulator build script
* Add a function to support querying function argument info for SST
* sst-integration: add version detection for vanadis binary
* Automated Format
* add version detection support for gcc 10+
* sst-integration: add cudaMallocHost for SST
* sst-integration: fix a compilation bug
* sst-integration: add sst balar unittest CI
* sst-integration: specify GPU_ARCH for CI test
* sst-integration: use bash for github actions
* sst-integration: use https links for sst repos
* sst-integration: add SST dependencies to CI config
* sst-integration: remove sudo
* sst-integration: default to yes for apt install
* sst-integration: add manual trigger for github action
* sst-integration: remove wrong on event
* sst-integration: limit CPU usage for compilation
* sst-integration: fix wrong path
* sst-integration: use personal repo for testing
* sst-integration: remove sst-core source in CI to free space
* sst-integration: SST_Cycle use print stats with stream id
* Automated Format
* sst-integration: check for diskspace and try to clean it
* sst-integration: move out of docker image
* sst-integration: testing for ci path
* sst-integration: fix syntax
* sst-integration: pass env vars
* sst-integration: set env properly
* sst-integration: merge LLVM build and test into same job
* sst-integration: fix step order
* sst-integration: checkout correct branch for env-setup
* sst-integration: remove resourcing gpu apps
* sst-integration: revert back to docker github action
* sst-integration: enable debug trace for sst testing
* sst-integration: resourcing gpu app for env vars
* sst-integration: use GPUAPPS_ROOT for path for gpu app
* sst-integration: use GPUAPPS_ROOT for path for gpu app
* sst-integration: enable parallel ci tests and fix not returning with cudaMallocHostSST
* sst-integration: using debug flag for CI run
* sst-integration: revert debug ci run
* sst-integration: CI skips cuda sdk download and launch multiple jobs
* sst-integration: reenable parallel tests
* sst-integration: reduce concurrent test thread count
* sst-integration: skip long test for github runner
* sst-integration: try running CI with single core
* sst-integrtion: add callback to SST to check thread sync is done in SST_Cycle()
* sst-integration: ignore lookup if already found and add callbacks to SST
* Automated Format
* sst-integration: add support for indirect texture access
* Automated Format
* sste-integration: fix up for PR
* Automated Format
---------
Co-authored-by: purdue-jenkins <[email protected]>
Diffstat (limited to 'src/gpgpu-sim')
| -rw-r--r-- | src/gpgpu-sim/gpu-cache.cc | 1 | ||||
| -rw-r--r-- | src/gpgpu-sim/gpu-sim.cc | 200 | ||||
| -rw-r--r-- | src/gpgpu-sim/gpu-sim.h | 139 | ||||
| -rw-r--r-- | src/gpgpu-sim/mem_fetch.cc | 12 | ||||
| -rw-r--r-- | src/gpgpu-sim/mem_latency_stat.cc | 17 | ||||
| -rw-r--r-- | src/gpgpu-sim/shader.cc | 135 | ||||
| -rw-r--r-- | src/gpgpu-sim/shader.h | 101 |
7 files changed, 568 insertions, 37 deletions
diff --git a/src/gpgpu-sim/gpu-cache.cc b/src/gpgpu-sim/gpu-cache.cc index cd3c880..0ea9ff6 100644 --- a/src/gpgpu-sim/gpu-cache.cc +++ b/src/gpgpu-sim/gpu-cache.cc @@ -2062,6 +2062,7 @@ enum cache_request_status tex_cache::access(new_addr_type addr, mem_fetch *mf, void tex_cache::cycle() { // send next request to lower level of memory + // TODO: Use different full() for sst_mem_interface? if (!m_request_fifo.empty()) { mem_fetch *mf = m_request_fifo.peek(); if (!m_memport->full(mf->get_ctrl_size(), false)) { diff --git a/src/gpgpu-sim/gpu-sim.cc b/src/gpgpu-sim/gpu-sim.cc index 5bd4180..b92494b 100644 --- a/src/gpgpu-sim/gpu-sim.cc +++ b/src/gpgpu-sim/gpu-sim.cc @@ -319,6 +319,9 @@ void memory_config::reg_options(class OptionParser *opp) { "elimnate_rw_turnaround i.e set tWTR and tRTW = 0", "0"); option_parser_register(opp, "-icnt_flit_size", OPT_UINT32, &icnt_flit_size, "icnt_flit_size", "32"); + // SST mode activate + option_parser_register(opp, "-SST_mode", OPT_BOOL, &SST_mode, "SST mode", + "0"); m_address_mapping.addrdec_setoption(opp); } @@ -955,6 +958,16 @@ void exec_gpgpu_sim::createSIMTCluster() { m_shader_stats, m_memory_stats); } +// SST get its own simt_cluster +void sst_gpgpu_sim::createSIMTCluster() { + m_cluster = new simt_core_cluster *[m_shader_config->n_simt_clusters]; + for (unsigned i = 0; i < m_shader_config->n_simt_clusters; i++) + m_cluster[i] = + new sst_simt_core_cluster(this, i, m_shader_config, m_memory_config, + m_shader_stats, m_memory_stats); + SST_gpgpu_reply_buffer.resize(m_shader_config->n_simt_clusters); +} + gpgpu_sim::gpgpu_sim(const gpgpu_sim_config &config, gpgpu_context *ctx) : gpgpu_t(config, ctx), m_config(config) { gpgpu_ctx = ctx; @@ -999,26 +1012,29 @@ gpgpu_sim::gpgpu_sim(const gpgpu_sim_config &config, gpgpu_context *ctx) gpu_kernel_time.clear(); - m_memory_partition_unit = - new memory_partition_unit *[m_memory_config->m_n_mem]; - m_memory_sub_partition = - new memory_sub_partition *[m_memory_config->m_n_mem_sub_partition]; - for (unsigned i = 0; i < m_memory_config->m_n_mem; i++) { - m_memory_partition_unit[i] = - new memory_partition_unit(i, m_memory_config, m_memory_stats, this); - for (unsigned p = 0; - p < m_memory_config->m_n_sub_partition_per_memory_channel; p++) { - unsigned submpid = - i * m_memory_config->m_n_sub_partition_per_memory_channel + p; - m_memory_sub_partition[submpid] = - m_memory_partition_unit[i]->get_sub_partition(p); + // TODO: somehow move this logic to the sst_gpgpu_sim constructor? + if (!m_config.is_SST_mode()) { + // Init memory if not in SST mode + m_memory_partition_unit = + new memory_partition_unit *[m_memory_config->m_n_mem]; + m_memory_sub_partition = + new memory_sub_partition *[m_memory_config->m_n_mem_sub_partition]; + for (unsigned i = 0; i < m_memory_config->m_n_mem; i++) { + m_memory_partition_unit[i] = + new memory_partition_unit(i, m_memory_config, m_memory_stats, this); + for (unsigned p = 0; + p < m_memory_config->m_n_sub_partition_per_memory_channel; p++) { + unsigned submpid = + i * m_memory_config->m_n_sub_partition_per_memory_channel + p; + m_memory_sub_partition[submpid] = + m_memory_partition_unit[i]->get_sub_partition(p); + } } - } - - icnt_wrapper_init(); - icnt_create(m_shader_config->n_simt_clusters, - m_memory_config->m_n_mem_sub_partition); + icnt_wrapper_init(); + icnt_create(m_shader_config->n_simt_clusters, + m_memory_config->m_n_mem_sub_partition); + } time_vector_create(NUM_MEM_REQ_STAT); fprintf(stdout, "GPGPU-Sim uArch: performance model initialization complete.\n"); @@ -1037,6 +1053,22 @@ gpgpu_sim::gpgpu_sim(const gpgpu_sim_config &config, gpgpu_context *ctx) m_functional_sim_kernel = NULL; } +void sst_gpgpu_sim::SST_receive_mem_reply(unsigned core_id, void *mem_req) { + assert(core_id < m_shader_config->n_simt_clusters); + mem_fetch *mf = (mem_fetch *)mem_req; + + (SST_gpgpu_reply_buffer[core_id]).push_back(mf); +} + +mem_fetch *sst_gpgpu_sim::SST_pop_mem_reply(unsigned core_id) { + if (SST_gpgpu_reply_buffer[core_id].size() > 0) { + mem_fetch *temp = SST_gpgpu_reply_buffer[core_id].front(); + SST_gpgpu_reply_buffer[core_id].pop_front(); + return temp; + } else + return NULL; +} + int gpgpu_sim::shared_mem_size() const { return m_shader_config->gpgpu_shmem_size; } @@ -1132,6 +1164,26 @@ bool gpgpu_sim::active() { return false; } +bool sst_gpgpu_sim::active() { + if (m_config.gpu_max_cycle_opt && + (gpu_tot_sim_cycle + gpu_sim_cycle) >= m_config.gpu_max_cycle_opt) + return false; + if (m_config.gpu_max_insn_opt && + (gpu_tot_sim_insn + gpu_sim_insn) >= m_config.gpu_max_insn_opt) + return false; + if (m_config.gpu_max_cta_opt && + (gpu_tot_issued_cta >= m_config.gpu_max_cta_opt)) + return false; + if (m_config.gpu_max_completed_cta_opt && + (gpu_completed_cta >= m_config.gpu_max_completed_cta_opt)) + return false; + if (m_config.gpu_deadlock_detect && gpu_deadlock) return false; + for (unsigned i = 0; i < m_shader_config->n_simt_clusters; i++) + if (m_cluster[i]->get_not_completed() > 0) return true; + if (get_more_cta_left()) return true; + return false; +} + void gpgpu_sim::init() { // run a CUDA grid on the GPU microarchitecture simulator gpu_sim_cycle = 0; @@ -2157,6 +2209,11 @@ void gpgpu_sim::cycle() { } } +void sst_gpgpu_sim::cycle() { + SST_cycle(); + return; +} + void shader_core_ctx::dump_warp_state(FILE *fout) const { fprintf(fout, "\n"); fprintf(fout, "per warp functional simulation status:\n"); @@ -2236,3 +2293,110 @@ const shader_core_config *gpgpu_sim::getShaderCoreConfig() { const memory_config *gpgpu_sim::getMemoryConfig() { return m_memory_config; } simt_core_cluster *gpgpu_sim::getSIMTCluster() { return *m_cluster; } + +void sst_gpgpu_sim::SST_gpgpusim_numcores_equal_check(unsigned sst_numcores) { + if (m_shader_config->n_simt_clusters != sst_numcores) { + assert( + "\nSST core is not equal the GPGPU-sim cores. Open gpgpu-sim.config " + "file and ensure n_simt_clusters" + "is the same as SST gpu cores.\n" && + 0); + } else { + printf("\nSST GPU core is equal the GPGPU-sim cores = %d\n", sst_numcores); + } +} + +void sst_gpgpu_sim::SST_cycle() { + // shader core loading (pop from ICNT into core) follows CORE clock + for (unsigned i = 0; i < m_shader_config->n_simt_clusters; i++) + static_cast<sst_simt_core_cluster *>(m_cluster[i])->icnt_cycle_SST(); + + // L1 cache + shader core pipeline stages + m_power_stats->pwr_mem_stat->core_cache_stats[CURRENT_STAT_IDX].clear(); + for (unsigned i = 0; i < m_shader_config->n_simt_clusters; i++) { + if (m_cluster[i]->get_not_completed() || get_more_cta_left()) { + m_cluster[i]->core_cycle(); + *active_sms += m_cluster[i]->get_n_active_sms(); + } + // 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]); + } + float temp = 0; + for (unsigned i = 0; i < m_shader_config->num_shader(); i++) { + temp += m_shader_stats->m_pipeline_duty_cycle[i]; + } + temp = temp / m_shader_config->num_shader(); + *average_pipeline_duty_cycle = ((*average_pipeline_duty_cycle) + temp); + // cout<<"Average pipeline duty cycle: "<<*average_pipeline_duty_cycle<<endl; + + if (g_single_step && ((gpu_sim_cycle + gpu_tot_sim_cycle) >= g_single_step)) { + asm("int $03"); + } + gpu_sim_cycle++; + if (g_interactive_debugger_enabled) gpgpu_debug(); + + // McPAT main cycle (interface with McPAT) +#ifdef GPGPUSIM_POWER_MODEL + if (m_config.g_power_simulation_enabled) { + mcpat_cycle(m_config, getShaderCoreConfig(), m_gpgpusim_wrapper, + m_power_stats, m_config.gpu_stat_sample_freq, gpu_tot_sim_cycle, + gpu_sim_cycle, gpu_tot_sim_insn, gpu_sim_insn, + m_config.g_dvfs_enabled); + } +#endif + + issue_block2core(); + + if (!(gpu_sim_cycle % m_config.gpu_stat_sample_freq)) { + time_t days, hrs, minutes, sec; + time_t curr_time; + time(&curr_time); + unsigned long long elapsed_time = + MAX(curr_time - gpgpu_ctx->the_gpgpusim->g_simulation_starttime, 1); + if ((elapsed_time - last_liveness_message_time) >= + m_config.liveness_message_freq) { + 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)); + + last_liveness_message_time = elapsed_time; + } + visualizer_printstat(); + m_memory_stats->memlatstat_lat_pw(); + if (m_config.gpgpu_runtime_stat && (m_config.gpu_runtime_stat_flag != 0)) { + if (m_config.gpu_runtime_stat_flag & GPU_RSTAT_BW_STAT) { + for (unsigned i = 0; i < m_memory_config->m_n_mem; i++) + m_memory_partition_unit[i]->print_stat(stdout); + printf("maxmrqlatency = %d \n", m_memory_stats->max_mrq_latency); + printf("maxmflatency = %d \n", m_memory_stats->max_mf_latency); + } + if (m_config.gpu_runtime_stat_flag & GPU_RSTAT_SHD_INFO) + shader_print_runtime_stat(stdout); + if (m_config.gpu_runtime_stat_flag & GPU_RSTAT_L1MISS) + shader_print_l1_miss_stat(stdout); + if (m_config.gpu_runtime_stat_flag & GPU_RSTAT_SCHED) + shader_print_scheduler_stat(stdout, false); + } + } + + if (!(gpu_sim_cycle % 20000)) { + // deadlock detection + if (m_config.gpu_deadlock_detect && gpu_sim_insn == last_gpu_sim_insn) { + gpu_deadlock = true; + } else { + last_gpu_sim_insn = gpu_sim_insn; + } + } + try_snap_shot(gpu_sim_cycle); + spill_log_to_file(stdout, 0, gpu_sim_cycle); + +#if (CUDART_VERSION >= 5000) + // launch device kernel + gpgpu_ctx->device_runtime->launch_one_device_kernel(); +#endif +} diff --git a/src/gpgpu-sim/gpu-sim.h b/src/gpgpu-sim/gpu-sim.h index 8e81451..d0c2a17 100644 --- a/src/gpgpu-sim/gpu-sim.h +++ b/src/gpgpu-sim/gpu-sim.h @@ -69,6 +69,38 @@ class gpgpu_context; extern tr1_hash_map<new_addr_type, unsigned> address_random_interleaving; +// SST communication functions +/** + * @brief Check if SST requests buffer is full + * + * @param core_id + * @return true + * @return false + */ +extern bool is_SST_buffer_full(unsigned core_id); + +/** + * @brief Send loads to SST memory backend + * + * @param core_id + * @param address + * @param size + * @param mem_req + */ +extern void send_read_request_SST(unsigned core_id, uint64_t address, + size_t size, void *mem_req); + +/** + * @brief Send stores to SST memory backend + * + * @param core_id + * @param address + * @param size + * @param mem_req + */ +extern void send_write_request_SST(unsigned core_id, uint64_t address, + size_t size, void *mem_req); + enum dram_ctrl_t { DRAM_FIFO = 0, DRAM_FRFCFS = 1 }; enum hw_perf_t { @@ -274,6 +306,14 @@ class memory_config { } void reg_options(class OptionParser *opp); + /** + * @brief Check if the config script is in SST mode + * + * @return true + * @return false + */ + bool is_SST_mode() const { return SST_mode; } + bool m_valid; mutable l2_cache_config m_L2_config; bool m_L2_texure_only; @@ -351,7 +391,7 @@ class memory_config { unsigned write_low_watermark; bool m_perf_sim_memcpy; bool simple_dram_model; - + bool SST_mode; gpgpu_context *gpgpu_ctx; }; @@ -398,6 +438,15 @@ class gpgpu_sim_config : public power_config, 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; } + + /** + * @brief Check if we are in SST mode + * + * @return true + * @return false + */ + bool is_SST_mode() const { return m_memory_config.SST_mode; } + unsigned checkpoint_option; size_t stack_limit() const { return stack_size_limit; } @@ -462,6 +511,7 @@ class gpgpu_sim_config : public power_config, unsigned long long liveness_message_freq; friend class gpgpu_sim; + friend class sst_gpgpu_sim; }; struct occupancy_stats { @@ -600,10 +650,18 @@ class gpgpu_sim : public gpgpu_t { void hit_watchpoint(unsigned watchpoint_num, ptx_thread_info *thd, const ptx_instruction *pI); + /** + * @brief Check if we are in SST mode + * + * @return true + * @return false + */ + bool is_SST_mode() { return m_config.is_SST_mode(); } + // backward pointer class gpgpu_context *gpgpu_ctx; - private: + protected: // clocks void reinit_clock_domains(void); int next_clock_domain(void); @@ -715,7 +773,7 @@ class gpgpu_sim : public gpgpu_t { void set_cache_config(std::string kernel_name); // Jin: functional simulation for CDP - private: + protected: // set by stream operation every time a functoinal simulation is done bool m_functional_sim; kernel_info_t *m_functional_sim_kernel; @@ -748,4 +806,79 @@ class exec_gpgpu_sim : public gpgpu_sim { virtual void createSIMTCluster(); }; +/** + * @brief A GPGPUSim class customized to SST Balar interfacing + * + */ +class sst_gpgpu_sim : public gpgpu_sim { + public: + sst_gpgpu_sim(const gpgpu_sim_config &config, gpgpu_context *ctx) + : gpgpu_sim(config, ctx) { + createSIMTCluster(); + } + + // SST memory handling + std::vector<std::deque<mem_fetch *>> + SST_gpgpu_reply_buffer; /** SST mem response queue */ + + /** + * @brief Receive mem request's response from SST and put + * it in a buffer (SST_gpgpu_reply_buffer) + * + * @param core_id + * @param mem_req + */ + void SST_receive_mem_reply(unsigned core_id, void *mem_req); + + /** + * @brief Pop the head of the buffer queue to get the + * memory response + * + * @param core_id + * @return mem_fetch* + */ + mem_fetch *SST_pop_mem_reply(unsigned core_id); + + virtual void createSIMTCluster(); + + // SST Balar interfacing + /** + * @brief Advance core and collect stats + * + */ + void SST_cycle(); + + /** + * @brief Wrapper of SST_cycle() + * + */ + void cycle(); + + /** + * @brief Whether the GPU is active, removed test for + * memory system since that is handled in SST + * + * @return true + * @return false + */ + bool active(); + + /** + * @brief SST mode use SST memory system instead, so the memcpy + * is empty here + * + * @param dst_start_addr + * @param count + */ + void perf_memcpy_to_gpu(size_t dst_start_addr, size_t count){}; + + /** + * @brief Check if the SST config matches up with the + * gpgpusim.config in core number + * + * @param sst_numcores SST core count + */ + void SST_gpgpusim_numcores_equal_check(unsigned sst_numcores); +}; + #endif diff --git a/src/gpgpu-sim/mem_fetch.cc b/src/gpgpu-sim/mem_fetch.cc index 7211a7d..809c920 100644 --- a/src/gpgpu-sim/mem_fetch.cc +++ b/src/gpgpu-sim/mem_fetch.cc @@ -54,9 +54,15 @@ mem_fetch::mem_fetch(const mem_access_t &access, const warp_inst_t *inst, m_sid = sid; m_tpc = tpc; m_wid = wid; - config->m_address_mapping.addrdec_tlx(access.get_addr(), &m_raw_addr); - m_partition_addr = - config->m_address_mapping.partition_address(access.get_addr()); + + if (!config->is_SST_mode()) { + // In SST memory model, the SST memory hierarchy is + // responsible to generate the correct address mapping + config->m_address_mapping.addrdec_tlx(access.get_addr(), &m_raw_addr); + m_partition_addr = + config->m_address_mapping.partition_address(access.get_addr()); + } + m_type = m_access.is_write() ? WRITE_REQUEST : READ_REQUEST; m_timestamp = cycle; m_timestamp2 = 0; diff --git a/src/gpgpu-sim/mem_latency_stat.cc b/src/gpgpu-sim/mem_latency_stat.cc index 63d7ee8..c77a686 100644 --- a/src/gpgpu-sim/mem_latency_stat.cc +++ b/src/gpgpu-sim/mem_latency_stat.cc @@ -203,7 +203,15 @@ unsigned memory_stats_t::memlatstat_done(mem_fetch *mf) { } void memory_stats_t::memlatstat_read_done(mem_fetch *mf) { - if (m_memory_config->gpgpu_memlatency_stat) { + if (m_memory_config->SST_mode) { + // in SST mode, we just calculate mem latency + unsigned mf_latency; + mf_latency = + (m_gpu->gpu_sim_cycle + m_gpu->gpu_tot_sim_cycle) - mf->get_timestamp(); + num_mfs++; + mf_total_lat += mf_latency; + if (mf_latency > max_mf_latency) max_mf_latency = mf_latency; + } else if (m_memory_config->gpgpu_memlatency_stat) { unsigned mf_latency = memlatstat_done(mf); if (mf_latency > mf_max_lat_table[mf->get_tlx_addr().chip][mf->get_tlx_addr().bk]) @@ -273,7 +281,12 @@ void memory_stats_t::memlatstat_print(unsigned n_mem, unsigned gpu_mem_n_bk) { unsigned max_bank_accesses, min_bank_accesses, max_chip_accesses, min_chip_accesses; - if (m_memory_config->gpgpu_memlatency_stat) { + if (m_memory_config->SST_mode) { + // in SST mode, we just calculate mem latency + printf("max_mem_SST_latency = %d \n", max_mf_latency); + if (num_mfs) + printf("average_mf_SST_latency = %lld \n", mf_total_lat / num_mfs); + } else if (m_memory_config->gpgpu_memlatency_stat) { printf("maxmflatency = %d \n", max_mf_latency); printf("max_icnt2mem_latency = %d \n", max_icnt2mem_latency); printf("maxmrqlatency = %d \n", max_mrq_latency); diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc index 4d4f112..7482e0e 100644 --- a/src/gpgpu-sim/shader.cc +++ b/src/gpgpu-sim/shader.cc @@ -162,7 +162,10 @@ void shader_core_ctx::create_front_pipeline() { } // m_icnt = new shader_memory_interface(this,cluster); - if (m_config->gpgpu_perfect_mem) { + if (m_memory_config->SST_mode) { + m_icnt = new sst_memory_interface( + this, static_cast<sst_simt_core_cluster *>(m_cluster)); + } else if (m_config->gpgpu_perfect_mem) { m_icnt = new perfect_memory_interface(this, m_cluster); } else { m_icnt = new shader_memory_interface(this, m_cluster); @@ -2281,7 +2284,15 @@ bool ldst_unit::memory_cycle(warp_inst_t &inst, 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())) { + if (m_memory_config->SST_mode && + (static_cast<sst_memory_interface *>(m_icnt)->full( + size, inst.is_store() || inst.isatomic(), access.get_type()))) { + // SST need mf type here + // Cast it to sst_memory_interface pointer first as this full() method + // is not a virtual method in parent class + stall_cond = ICNT_RC_FAIL; + } else if (!m_memory_config->SST_mode && + (m_icnt->full(size, inst.is_store() || inst.isatomic()))) { stall_cond = ICNT_RC_FAIL; } else { mem_fetch *mf = @@ -2846,7 +2857,10 @@ void ldst_unit::cycle() { } } else { if (mf->get_type() == WRITE_ACK || - (m_config->gpgpu_perfect_mem && mf->get_is_write())) { + ((m_config->gpgpu_perfect_mem || m_memory_config->SST_mode) && + mf->get_is_write())) { + // SST memory is handled by SST mem hierarchy + // Perfect mem m_core->store_ack(mf); m_response_fifo.pop_front(); delete mf; @@ -4020,7 +4034,8 @@ void shader_core_ctx::accept_ldst_unit_response(mem_fetch *mf) { void shader_core_ctx::store_ack(class mem_fetch *mf) { assert(mf->get_type() == WRITE_ACK || - (m_config->gpgpu_perfect_mem && mf->get_is_write())); + ((m_config->gpgpu_perfect_mem || m_memory_config->SST_mode) && + mf->get_is_write())); unsigned warp_id = mf->get_wid(); m_warp[warp_id]->dec_store_req(); } @@ -4573,7 +4588,46 @@ bool simt_core_cluster::icnt_injection_buffer_full(unsigned size, bool write) { return !::icnt_has_buffer(m_cluster_id, request_size); } +bool sst_simt_core_cluster::SST_injection_buffer_full(unsigned size, bool write, + mem_access_type type) { + switch (type) { + case CONST_ACC_R: + case INST_ACC_R: { + return response_queue_full(); + break; + } + default: { + return ::is_SST_buffer_full(m_cluster_id); + break; + } + } +} + void simt_core_cluster::icnt_inject_request_packet(class mem_fetch *mf) { + // Update stats based on mf type + update_icnt_stats(mf); + + // The packet size varies depending on the type of request: + // - For write request and atomic request, the packet contains the data + // - For read request (i.e. not write nor atomic), the packet only has control + // metadata + unsigned int packet_size = mf->size(); + if (!mf->get_is_write() && !mf->isatomic()) { + packet_size = mf->get_ctrl_size(); + } + m_stats->m_outgoing_traffic_stats->record_traffic(mf, packet_size); + unsigned destination = mf->get_sub_partition_id(); + mf->set_status(IN_ICNT_TO_MEM, + m_gpu->gpu_sim_cycle + m_gpu->gpu_tot_sim_cycle); + if (!mf->get_is_write() && !mf->isatomic()) + ::icnt_push(m_cluster_id, m_config->mem2device(destination), (void *)mf, + mf->get_ctrl_size()); + else + ::icnt_push(m_cluster_id, m_config->mem2device(destination), (void *)mf, + mf->size()); +} + +void simt_core_cluster::update_icnt_stats(class mem_fetch *mf) { // stats if (mf->get_is_write()) m_stats->made_write_mfs++; @@ -4618,6 +4672,12 @@ void simt_core_cluster::icnt_inject_request_packet(class mem_fetch *mf) { default: assert(0); } +} + +void sst_simt_core_cluster::icnt_inject_request_packet_to_SST( + class mem_fetch *mf) { + // Update stats + update_icnt_stats(mf); // The packet size varies depending on the type of request: // - For write request and atomic request, the packet contains the data @@ -4628,15 +4688,25 @@ void simt_core_cluster::icnt_inject_request_packet(class mem_fetch *mf) { packet_size = mf->get_ctrl_size(); } m_stats->m_outgoing_traffic_stats->record_traffic(mf, packet_size); - unsigned destination = mf->get_sub_partition_id(); mf->set_status(IN_ICNT_TO_MEM, m_gpu->gpu_sim_cycle + m_gpu->gpu_tot_sim_cycle); - if (!mf->get_is_write() && !mf->isatomic()) - ::icnt_push(m_cluster_id, m_config->mem2device(destination), (void *)mf, - mf->get_ctrl_size()); - else - ::icnt_push(m_cluster_id, m_config->mem2device(destination), (void *)mf, - mf->size()); + switch (mf->get_access_type()) { + case CONST_ACC_R: + case INST_ACC_R: { + push_response_fifo(mf); + break; + } + default: { + if (!mf->get_is_write() && !mf->isatomic()) + ::send_read_request_SST(m_cluster_id, mf->get_addr(), + mf->get_data_size(), (void *)mf); + else + ::send_write_request_SST(m_cluster_id, mf->get_addr(), + mf->get_data_size(), (void *)mf); + + break; + } + } } void simt_core_cluster::icnt_cycle() { @@ -4678,6 +4748,49 @@ void simt_core_cluster::icnt_cycle() { } } +void sst_simt_core_cluster::icnt_cycle_SST() { + if (!m_response_fifo.empty()) { + mem_fetch *mf = m_response_fifo.front(); + unsigned cid = m_config->sid_to_cid(mf->get_sid()); + if (mf->get_access_type() == INST_ACC_R) { + // instruction fetch response + if (!m_core[cid]->fetch_unit_response_buffer_full()) { + m_response_fifo.pop_front(); + m_core[cid]->accept_fetch_response(mf); + } + } else { + // data response + if (!m_core[cid]->ldst_unit_response_buffer_full()) { + m_response_fifo.pop_front(); + m_memory_stats->memlatstat_read_done(mf); + m_core[cid]->accept_ldst_unit_response(mf); + } + } + } + + // pop from SST buffers + if (m_response_fifo.size() < m_config->n_simt_ejection_buffer_size) { + mem_fetch *mf = (mem_fetch *)(static_cast<sst_gpgpu_sim *>(get_gpu()) + ->SST_pop_mem_reply(m_cluster_id)); + if (!mf) return; + assert(mf->get_tpc() == m_cluster_id); + + // do atomic here + // For now, we execute atomic when the mem reply comes back + // This needs to be validated + if (mf && mf->isatomic()) mf->do_atomic(); + + unsigned int packet_size = + (mf->get_is_write()) ? mf->get_ctrl_size() : mf->size(); + m_stats->m_incoming_traffic_stats->record_traffic(mf, packet_size); + mf->set_status(IN_CLUSTER_TO_SHADER_QUEUE, + m_gpu->gpu_sim_cycle + m_gpu->gpu_tot_sim_cycle); + // m_memory_stats->memlatstat_read_done(mf,m_shader_config->max_warps_per_shader); + m_response_fifo.push_back(mf); + m_stats->n_mem_to_simt[m_cluster_id] += mf->get_num_flits(false); + } +} + void simt_core_cluster::get_pdom_stack_top_info(unsigned sid, unsigned tid, unsigned *pc, unsigned *rpc) const { diff --git a/src/gpgpu-sim/shader.h b/src/gpgpu-sim/shader.h index e658a14..ee10af6 100644 --- a/src/gpgpu-sim/shader.h +++ b/src/gpgpu-sim/shader.h @@ -2015,6 +2015,7 @@ class shader_core_stats : public shader_core_stats_pod { friend class shader_core_ctx; friend class ldst_unit; friend class simt_core_cluster; + friend class sst_simt_core_cluster; friend class scheduler_unit; friend class TwoLevelScheduler; friend class LooseRoundRobbinScheduler; @@ -2624,6 +2625,7 @@ class simt_core_cluster { void cache_invalidate(); bool icnt_injection_buffer_full(unsigned size, bool write); void icnt_inject_request_packet(class mem_fetch *mf); + void update_icnt_stats(class mem_fetch *mf); // for perfect memory interface bool response_queue_full() { @@ -2685,6 +2687,50 @@ class exec_simt_core_cluster : public simt_core_cluster { virtual void create_shader_core_ctx(); }; +/** + * @brief SST cluster class + * + */ +class sst_simt_core_cluster : public exec_simt_core_cluster { + public: + sst_simt_core_cluster(class gpgpu_sim *gpu, unsigned cluster_id, + const shader_core_config *config, + const memory_config *mem_config, + class shader_core_stats *stats, + class memory_stats_t *mstats) + : exec_simt_core_cluster(gpu, cluster_id, config, mem_config, stats, + mstats) {} + + /** + * @brief Check if SST memory request injection + * buffer is full by using extern + * function is_SST_buffer_full() + * defined in Balar + * + * @param size + * @param write + * @param type + * @return true + * @return false + */ + bool SST_injection_buffer_full(unsigned size, bool write, + mem_access_type type); + + /** + * @brief Send memory request packets to SST + * memory + * + * @param mf + */ + void icnt_inject_request_packet_to_SST(class mem_fetch *mf); + + /** + * @brief Advance ICNT between core and SST + * + */ + void icnt_cycle_SST(); +}; + class shader_memory_interface : public mem_fetch_interface { public: shader_memory_interface(shader_core_ctx *core, simt_core_cluster *cluster) { @@ -2725,6 +2771,61 @@ class perfect_memory_interface : public mem_fetch_interface { simt_core_cluster *m_cluster; }; +/** + * @brief SST memory interface + * + */ +class sst_memory_interface : public mem_fetch_interface { + public: + sst_memory_interface(shader_core_ctx *core, sst_simt_core_cluster *cluster) { + m_core = core; + m_cluster = cluster; + } + /** + * @brief For constant, inst, tex cache access + * + * @param size + * @param write + * @return true + * @return false + */ + virtual bool full(unsigned size, bool write) const { + assert(false && "Use the full() method with access type instead!"); + return true; + } + + /** + * @brief With SST, the core will direct all mem access except for + * constant, tex, and inst reads to SST mem system + * (i.e. not modeling constant mem right now), thus + * requiring the mem_access_type information to be passed in + * + * @param size + * @param write + * @param type + * @return true + * @return false + */ + bool full(unsigned size, bool write, mem_access_type type) const { + return m_cluster->SST_injection_buffer_full(size, write, type); + } + + /** + * @brief Push memory request to SST memory system and + * update stats + * + * @param mf + */ + virtual void push(mem_fetch *mf) { + m_core->inc_simt_to_mem(mf->get_num_flits(true)); + m_cluster->icnt_inject_request_packet_to_SST(mf); + } + + private: + shader_core_ctx *m_core; + sst_simt_core_cluster *m_cluster; +}; + inline int scheduler_unit::get_sid() const { return m_shader->get_sid(); } #endif /* SHADER_H */ |
