/* * gpu-sim.c * * Copyright (c) 2009 by Tor M. Aamodt, Wilson W. L. Fung, Ali Bakhoda, * George L. Yuan, Ivan Sham, Henry Wong, Dan O'Connor and the * University of British Columbia * Vancouver, BC V6T 1Z4 * All Rights Reserved. * * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE * TERMS AND CONDITIONS. * * 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 OWNERS 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. * * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda * (property of NVIDIA). The files benchmarks/BlackScholes/ and * benchmarks/template/ are derived from the CUDA SDK available from * http://www.nvidia.com/cuda (also property of NVIDIA). The files from * src/intersim/ are derived from Booksim (a simulator provided with the * textbook "Principles and Practices of Interconnection Networks" available * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by * the corresponding legal terms and conditions set forth separately (original * copyright notices are left in files from these sources and where we have * modified a file our copyright notice appears before the original copyright * notice). * * Using this version of GPGPU-Sim requires a complete installation of CUDA * which is distributed seperately by NVIDIA under separate terms and * conditions. To use this version of GPGPU-Sim with OpenCL requires a * recent version of NVIDIA's drivers which support OpenCL. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. 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. * * 3. 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. * * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only. * * 5. No nonprofit user may place any restrictions on the use of this software, * including as modified by the user, by any other authorized user. * * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung, * Ali Bakhoda, George L. Yuan, at the University of British Columbia, * Vancouver, BC V6T 1Z4 */ #include "gpu-sim.h" #include #include "gpu-cache.h" #include "gpu-misc.h" #include "delayqueue.h" #include "shader.h" #include "icnt_wrapper.h" #include "dram.h" #include "addrdec.h" #include "dwf.h" #include "warp_tracker.h" #include "cflogger.h" #include "l2cache.h" #include "../cuda-sim/ptx-stats.h" #include "../intersim/statwraper.h" #include "../abstract_hardware_model.h" #include #include #define MAX(a,b) (((a)>(b))?(a):(b)) extern unsigned L2_write_miss; extern unsigned L2_write_hit; extern unsigned L2_read_hit; extern unsigned L2_read_miss; unsigned made_read_mfs = 0; unsigned made_write_mfs = 0; unsigned freed_read_mfs = 0; unsigned freed_L1write_mfs = 0; unsigned freed_L2write_mfs = 0; unsigned freed_dummy_read_mfs = 0; unsigned long long gpu_sim_cycle = 0; unsigned long long gpu_sim_insn = 0; unsigned long long gpu_sim_insn_no_ld_const = 0; unsigned long long gpu_sim_prev_insn = 0; unsigned long long gpu_sim_insn_last_update = 0; unsigned long long gpu_tot_sim_cycle = 0; unsigned long long gpu_tot_sim_insn = 0; unsigned long long gpu_last_sim_cycle = 0; unsigned long long gpu_completed_thread = 0; unsigned long long gpu_tot_issued_cta = 0; unsigned long long gpu_tot_completed_thread = 0; unsigned int **concurrent_row_access; //concurrent_row_access[dram chip id][bank id] unsigned int **num_activates; //num_activates[dram chip id][bank id] unsigned int **row_access; //row_access[dram chip id][bank id] unsigned int **max_conc_access2samerow; //max_conc_access2samerow[dram chip id][bank id] unsigned int **max_servicetime2samerow; //max_servicetime2samerow[dram chip id][bank id] unsigned int mergemiss = 0; unsigned int L1_read_miss = 0; unsigned int L1_write_miss = 0; unsigned int L1_write_hit_on_miss = 0; unsigned int L1_writeback = 0; unsigned int L1_texture_miss = 0; unsigned int L1_const_miss = 0; unsigned int gpgpu_n_sent_writes = 0; unsigned int gpgpu_n_processed_writes = 0; unsigned int *max_return_queue_length; // performance counter for stalls due to congestion. unsigned int gpu_stall_shd_mem = 0; unsigned int gpu_stall_wr_back = 0; unsigned int gpu_stall_dramfull = 0; unsigned int gpu_stall_icnt2sh = 0; unsigned int gpu_stall_by_MSHRwb = 0; //shader cannot send to icnt because icnt buffer is full //Note: it is accumulative for all shaders and is never reset //so it might increase 8 times in a cycle if we have 8 shaders unsigned int gpu_stall_sh2icnt = 0; // performance counters to account for instruction distribution extern unsigned int gpgpu_n_load_insn; extern unsigned int gpgpu_n_store_insn; extern unsigned int gpgpu_n_shmem_insn; extern unsigned int gpgpu_n_tex_insn; extern unsigned int gpgpu_n_const_insn; extern unsigned int gpgpu_multi_unq_fetches; char *gpgpu_runtime_stat; int gpu_stat_sample_freq = 10000; int gpu_runtime_stat_flag = 0; extern int gpgpu_warpdistro_shader; // GPGPU options unsigned long long gpu_max_cycle = 0; unsigned long long gpu_max_insn = 0; int gpu_max_cycle_opt = 0; int gpu_max_insn_opt = 0; int gpu_max_cta_opt = 0; int gpu_deadlock_detect = 0; int gpu_deadlock = 0; static unsigned long long last_gpu_sim_insn = 0; int gpgpu_dram_scheduler = DRAM_FIFO; int g_save_embedded_ptx = 0; int gpgpu_simd_model = 0; int gpgpu_no_dl1 = 0; char *gpgpu_cache_texl1_opt; char *gpgpu_cache_constl1_opt; char *gpgpu_cache_dl1_opt; char *gpgpu_cache_dl2_opt; extern int gpgpu_l2_readoverwrite; int gpgpu_partial_write_mask = 0; bool gpgpu_perfect_mem = false; char *gpgpu_shader_core_pipeline_opt; extern unsigned int *requests_by_warp; unsigned int gpgpu_dram_buswidth = 4; unsigned int gpgpu_dram_burst_length = 4; int gpgpu_dram_sched_queue_size = 0; char * gpgpu_dram_timing_opt; int gpgpu_flush_cache = 0; int gpgpu_mem_address_mask = 0; unsigned int recent_dram_util = 0; int gpgpu_cflog_interval = 0; unsigned int finished_trace = 0; unsigned g_next_request_uid = 1; extern struct regs_t regs; extern long int gpu_reads; void ptx_dump_regs( void *thd ); int g_nthreads_issued; int g_total_cta_left; unsigned ptx_kernel_program_size(); void visualizer_printstat(); void time_vector_create(int ld_size,int st_size); void time_vector_print(void); void time_vector_update(unsigned int uid,int slot ,long int cycle,int type); void check_time_vector_update(unsigned int uid,int slot ,long int latency,int type); void node_req_hist_clear(void *p); void node_req_hist_dump(void *p); void node_req_hist_update(void * p,int node, long long cycle); /* functionally simulated memory */ extern struct mem_t *mem; /* Defining Clock Domains basically just the ratio is important */ #define CORE 0x01 #define L2 0x02 #define DRAM 0x04 #define ICNT 0x08 double core_time=0; double icnt_time=0; double dram_time=0; double l2_time=0; #define MhZ *1000000 double core_freq=2 MhZ; double icnt_freq=2 MhZ; double dram_freq=2 MhZ; double l2_freq=2 MhZ; double core_period = 1 /( 2 MhZ); double icnt_period = 1 /( 2 MhZ); double dram_period = 1 /( 2 MhZ); double l2_period = 1 / (2 MhZ); char * gpgpu_clock_domains; /* GPU uArch parameters */ unsigned int gpu_n_mem = 8; unsigned int gpu_mem_n_bk = 4; unsigned int gpu_n_mem_per_ctrlr = 1; unsigned int gpu_n_shader = 8; int gpu_concentration = 1; int gpu_n_tpc = 8; unsigned int gpu_n_mshr_per_shader; unsigned int gpu_n_thread_per_shader = 128; unsigned int gpu_n_warp_per_shader; unsigned int gpu_n_mshr_per_thread = 1; extern int gpgpu_interwarp_mshr_merge ; extern unsigned int gpgpu_shmem_size; extern unsigned int gpgpu_shader_registers; extern unsigned int gpgpu_shader_cta; extern int gpgpu_shmem_bkconflict; extern int gpgpu_cache_bkconflict; extern int gpgpu_n_cache_bank; extern unsigned int warp_size; extern int pipe_simd_width; extern unsigned int gpgpu_dwf_heuristic; extern unsigned int gpgpu_dwf_regbk; bool gpgpu_reg_bankconflict = false; extern int gpgpu_shmem_port_per_bank; extern int gpgpu_cache_port_per_bank; extern int gpgpu_const_port_per_bank; extern int gpgpu_shmem_pipe_speedup; extern int gpgpu_reg_bank_conflict_model; extern int gpgpu_num_reg_banks; extern unsigned int gpu_max_cta_per_shader; extern unsigned int gpu_padded_cta_size; extern int gpgpu_local_mem_map; unsigned int gpgpu_pre_mem_stages = 0; unsigned int gpgpu_no_divg_load = 0; char *gpgpu_dwf_hw_opt; unsigned int gpgpu_thread_swizzling = 0; unsigned int gpgpu_strict_simd_wrbk = 0; int pdom_sched_type = 0; int n_pdom_sc_orig_stat = 0; //the selected pdom schedular is used int n_pdom_sc_single_stat = 0; //only a single warp is ready to go in that cycle. int *num_warps_issuable; int *num_warps_issuable_pershader; // Thread Dispatching Unit option int gpgpu_cuda_sim = 1; int gpgpu_spread_blocks_across_cores = 1; /* GPU uArch structures */ shader_core_ctx_t **sc; dram_t **dram; unsigned int common_clock = 0; unsigned int more_thread = 1; extern unsigned int n_regconflict_stall; unsigned int warp_conflict_at_writeback = 0; unsigned int gpgpu_commit_pc_beyond_two = 0; extern int g_network_mode; int gpgpu_cache_wt_through = 0; //memory access classification int gpgpu_n_mem_read_local = 0; int gpgpu_n_mem_write_local = 0; int gpgpu_n_mem_texture = 0; int gpgpu_n_mem_const = 0; int gpgpu_n_mem_read_global = 0; int gpgpu_n_mem_write_global = 0; #define MEM_LATENCY_STAT_IMPL #include "mem_latency_stat.h" unsigned char fq_has_buffer(unsigned long long int addr, int bsize, bool write, int sid ); unsigned char fq_push(unsigned long long int addr, int bsize, unsigned char write, partial_write_mask_t partial_write_mask, int sid, int wid, mshr_entry* mshr, int cache_hits_waiting, enum mem_access_type mem_acc, address_type pc); int issue_mf_from_fq(mem_fetch_t *mf); unsigned char single_check_icnt_has_buffer(int chip, int sid, unsigned char is_write ); unsigned char fq_pop(int tpc_id); void fill_shd_L1_with_new_line(shader_core_ctx_t * sc, mem_fetch_t * mf); void set_option_gpgpu_spread_blocks_across_cores(int option); void set_param_gpgpu_num_shaders(int num_shaders); unsigned ptx_sim_grid_size(); void icnt_init_grid(); void interconnect_stats(); void icnt_overal_stat(); unsigned ptx_sim_cta_size(); unsigned ptx_sim_init_thread( ptx_thread_info** thread_info, int sid, unsigned tid,unsigned threads_left,unsigned num_threads, core_t *core, unsigned hw_cta_id, unsigned hw_warp_id ); void gpu_sim_loop( int grid_num ); void print_shader_cycle_distro( FILE *fout ) ; void find_reconvergence_points(); void dwf_process_reconv_pts(); extern int gpgpu_ptx_instruction_classification ; extern int g_ptx_sim_mode; extern int gpgpu_coalesce_arch; #define CREATELOG 111 #define SAMPLELOG 222 #define DUMPLOG 333 void L2c_log(int task); void dram_log(int task); void visualizer_options(option_parser_t opp); void gpu_reg_options(option_parser_t opp) { option_parser_register(opp, "-save_embedded_ptx", OPT_BOOL, &g_save_embedded_ptx, "saves ptx files embedded in binary as .ptx", "0"); option_parser_register(opp, "-gpgpu_simd_model", OPT_INT32, &gpgpu_simd_model, "0 = no recombination, 1 = post-dominator, 2 = MIMD, 3 = dynamic warp formation", "0"); option_parser_register(opp, "-gpgpu_dram_scheduler", OPT_INT32, &gpgpu_dram_scheduler, "0 = fifo (default), 1 = fast ideal", "0"); option_parser_register(opp, "-gpgpu_max_cycle", OPT_INT32, &gpu_max_cycle_opt, "terminates gpu simulation early (0 = no limit)", "0"); option_parser_register(opp, "-gpgpu_max_insn", OPT_INT32, &gpu_max_insn_opt, "terminates gpu simulation early (0 = no limit)", "0"); option_parser_register(opp, "-gpgpu_max_cta", OPT_INT32, &gpu_max_cta_opt, "terminates gpu simulation early (0 = no limit)", "0"); option_parser_register(opp, "-gpgpu_tex_cache:l1", OPT_CSTR, &gpgpu_cache_texl1_opt, "per-shader L1 texture cache (READ-ONLY) config, i.e., {:::|none}", "512:64:2:L"); option_parser_register(opp, "-gpgpu_const_cache:l1", OPT_CSTR, &gpgpu_cache_constl1_opt, "per-shader L1 constant memory cache (READ-ONLY) config, i.e., {:::|none}", "64:64:2:L"); option_parser_register(opp, "-gpgpu_no_dl1", OPT_BOOL, &gpgpu_no_dl1, "no dl1 cache (voids -gpgpu_cache:dl1 option)", "0"); option_parser_register(opp, "-gpgpu_cache:dl1", OPT_CSTR, &gpgpu_cache_dl1_opt, "shader L1 data cache config, i.e., {:::|none}", "256:128:1:L"); option_parser_register(opp, "-gpgpu_cache:dl2", OPT_CSTR, &gpgpu_cache_dl2_opt, "unified banked L2 data cache config, i.e., {:::|none}; disabled by default", NULL); option_parser_register(opp, "-gpgpu_perfect_mem", OPT_BOOL, &gpgpu_perfect_mem, "enable perfect memory mode (no cache miss)", "0"); option_parser_register(opp, "-gpgpu_shader_core_pipeline", OPT_CSTR, &gpgpu_shader_core_pipeline_opt, "shader core pipeline config, i.e., {::}", "256:32:32"); 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_shader_cta", OPT_UINT32, &gpgpu_shader_cta, "Maximum number of concurrent CTAs in shader (default 8)", "8"); option_parser_register(opp, "-gpgpu_n_shader", OPT_UINT32, &gpu_n_shader, "number of shaders in gpu", "8"); option_parser_register(opp, "-gpgpu_n_mem", OPT_UINT32, &gpu_n_mem, "number of memory modules (e.g. memory controllers) in gpu", "8"); option_parser_register(opp, "-gpgpu_n_mem_per_ctrlr", OPT_UINT32, &gpu_n_mem_per_ctrlr, "number of memory chips per memory controller", "1"); option_parser_register(opp, "-gpgpu_runtime_stat", OPT_CSTR, &gpgpu_runtime_stat, "display runtime statistics such as dram utilization {:}", "10000:0"); option_parser_register(opp, "-gpgpu_dwf_heuristic", OPT_UINT32, &gpgpu_dwf_heuristic, "DWF scheduling heuristic: 0 = majority, 1 = minority, 2 = timestamp, 3 = pdom priority, 4 = pc-based, 5 = max-heap", "0"); option_parser_register(opp, "-gpgpu_reg_bankconflict", OPT_BOOL, &gpgpu_reg_bankconflict, "Check for bank conflict in the pipeline", "0"); option_parser_register(opp, "-gpgpu_dwf_regbk", OPT_BOOL, (int*)&gpgpu_dwf_regbk, "Have dwf scheduler to avoid bank conflict", "1"); option_parser_register(opp, "-gpgpu_memlatency_stat", OPT_INT32, &gpgpu_memlatency_stat, "track and display latency statistics 0x2 enables MC, 0x4 enables queue logs", "0"); option_parser_register(opp, "-gpu_n_mshr_per_shader", OPT_UINT32, &gpu_n_mshr_per_shader, "Number of MSHRs per shader", "64"); option_parser_register(opp, "-gpgpu_interwarp_mshr_merge", OPT_INT32, &gpgpu_interwarp_mshr_merge, "interwarp coalescing", "0"); option_parser_register(opp, "-gpgpu_dram_sched_queue_size", OPT_INT32, &gpgpu_dram_sched_queue_size, "0 = unlimited (default); # entries per chip", "0"); option_parser_register(opp, "-gpgpu_dram_buswidth", OPT_UINT32, &gpgpu_dram_buswidth, "default = 4 bytes (8 bytes per cycle at DDR)", "4"); option_parser_register(opp, "-gpgpu_dram_burst_length", OPT_UINT32, &gpgpu_dram_burst_length, "Burst length of each DRAM request (default = 4 DDR cycle)", "4"); option_parser_register(opp, "-gpgpu_dram_timing_opt", OPT_CSTR, &gpgpu_dram_timing_opt, "DRAM timing parameters = {nbk:tCCD:tRRD:tRCD:tRAS:tRP:tRC:CL:WL:tWTR}", "4:2:8:12:21:13:34:9:4:5"); option_parser_register(opp, "-gpgpu_mem_address_mask", OPT_INT32, &gpgpu_mem_address_mask, "0 = old addressing mask, 1 = new addressing mask, 2 = new add. mask + flipped bank sel and chip sel bits", "0"); option_parser_register(opp, "-gpgpu_flush_cache", OPT_BOOL, &gpgpu_flush_cache, "Flush cache at the end of each kernel call", "0"); option_parser_register(opp, "-gpgpu_pre_mem_stages", OPT_UINT32, &gpgpu_pre_mem_stages, "default = 0 pre-memory pipeline stages", "0"); option_parser_register(opp, "-gpgpu_no_divg_load", OPT_BOOL, (int*)&gpgpu_no_divg_load, "Don't allow divergence on load", "0"); option_parser_register(opp, "-gpgpu_dwf_hw", OPT_CSTR, &gpgpu_dwf_hw_opt, "dynamic warp formation hw config, i.e., {<#LUT_entries>:|none}", "32:2"); option_parser_register(opp, "-gpgpu_thread_swizzling", OPT_BOOL, (int*)&gpgpu_thread_swizzling, "Thread Swizzling (1=on, 0=off)", "0"); option_parser_register(opp, "-gpgpu_strict_simd_wrbk", OPT_BOOL, (int*)&gpgpu_strict_simd_wrbk, "Applying Strick SIMD WriteBack Stage (1=on, 0=off)", "0"); 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_bkconflict", OPT_BOOL, &gpgpu_shmem_bkconflict, "Turn on bank conflict check for shared memory", "0"); option_parser_register(opp, "-gpgpu_shmem_pipe_speedup", OPT_INT32, &gpgpu_shmem_pipe_speedup, "Number of groups each warp is divided for shared memory bank conflict check", "2"); option_parser_register(opp, "-gpgpu_cache_wt_through", OPT_BOOL, &gpgpu_cache_wt_through, "L1 cache become write through (1=on, 0=off)", "0"); option_parser_register(opp, "-gpgpu_deadlock_detect", OPT_BOOL, &gpu_deadlock_detect, "Stop the simulation at deadlock (1=on (default), 0=off)", "1"); option_parser_register(opp, "-gpgpu_cache_bkconflict", OPT_BOOL, &gpgpu_cache_bkconflict, "Turn on bank conflict check for L1 cache access", "0"); option_parser_register(opp, "-gpgpu_n_cache_bank", OPT_INT32, &gpgpu_n_cache_bank, "Number of banks in L1 cache, also for memory coalescing stall", "1"); option_parser_register(opp, "-gpgpu_warpdistro_shader", OPT_INT32, &gpgpu_warpdistro_shader, "Specify which shader core to collect the warp size distribution from", "-1"); option_parser_register(opp, "-gpgpu_pdom_sched_type", OPT_INT32, &pdom_sched_type, "0 = first ready warp found, 1 = random, 8 = loose round robin", "8"); option_parser_register(opp, "-gpgpu_spread_blocks_across_cores", OPT_BOOL, &gpgpu_spread_blocks_across_cores, "Spread block-issuing across all cores instead of filling up core by core (do NOT disable)", "1"); option_parser_register(opp, "-gpgpu_cuda_sim", OPT_BOOL, &gpgpu_cuda_sim, "use PTX instruction set", "1"); option_parser_register(opp, "-gpgpu_ptx_instruction_classification", OPT_INT32, &gpgpu_ptx_instruction_classification, "if enabled will classify ptx instruction types per kernel (Max 255 kernels now)", "0"); option_parser_register(opp, "-gpgpu_ptx_sim_mode", OPT_INT32, &g_ptx_sim_mode, "Select between Performance (default) or Functional simulation (1)", "0"); option_parser_register(opp, "-gpgpu_clock_domains", OPT_CSTR, &gpgpu_clock_domains, "Clock Domain Frequencies in MhZ {:::}", "500.0:2000.0:2000.0:2000.0"); option_parser_register(opp, "-gpgpu_shmem_port_per_bank", OPT_INT32, &gpgpu_shmem_port_per_bank, "Number of access processed by a shared memory bank per cycle (default = 2)", "2"); option_parser_register(opp, "-gpgpu_cache_port_per_bank", OPT_INT32, &gpgpu_cache_port_per_bank, "Number of access processed by a cache bank per cycle (default = 2)", "2"); option_parser_register(opp, "-gpgpu_const_port_per_bank", OPT_INT32, &gpgpu_const_port_per_bank, "Number of access processed by a constant cache bank per cycle (default = 2)", "2"); option_parser_register(opp, "-gpgpu_cflog_interval", OPT_INT32, &gpgpu_cflog_interval, "Interval between each snapshot in control flow logger", "0"); option_parser_register(opp, "-gpgpu_partial_write_mask", OPT_INT32, &gpgpu_partial_write_mask, "use partial write mask to filter memory requests <1>No extra reads(use this!)<2>extra reads generated for partial chunks", "0"); option_parser_register(opp, "-gpu_concentration", OPT_INT32, &gpu_concentration, "Number of shader cores per interconnection port (default = 1)", "1"); option_parser_register(opp, "-gpgpu_local_mem_map", OPT_INT32, &gpgpu_local_mem_map, "Mapping from local memory space address to simulated GPU physical address space (default = 1)", "1"); option_parser_register(opp, "-gpgpu_reg_bank_conflict_model", OPT_BOOL, &gpgpu_reg_bank_conflict_model, "Turn on register bank conflict model (default = off)", "0"); option_parser_register(opp, "-gpgpu_num_reg_banks", OPT_INT32, &gpgpu_num_reg_banks, "Number of register banks (default = 8)", "8"); option_parser_register(opp, "-gpgpu_coalesce_arch", OPT_INT32, &gpgpu_coalesce_arch, "Coalescing arch (default = 13, anything else is off for now)", "13"); addrdec_setoption(opp); L2c_options(opp); visualizer_options(opp); ptx_file_line_stats_options(opp); } ///////////////////////////////////////////////////////////////////////////// inline int mem2device(int memid) { return memid + gpu_n_tpc; } ///////////////////////////////////////////////////////////////////////////// /* Allocate memory for uArch structures */ void init_gpu () { int i; gpu_max_cycle = gpu_max_cycle_opt; gpu_max_insn = gpu_max_insn_opt; i = sscanf(gpgpu_shader_core_pipeline_opt,"%d:%d:%d", &gpu_n_thread_per_shader, &warp_size, &pipe_simd_width); gpu_n_warp_per_shader = gpu_n_thread_per_shader / warp_size; num_warps_issuable = (int*) calloc(gpu_n_warp_per_shader+1, sizeof(int)); num_warps_issuable_pershader = (int*) calloc(gpu_n_shader, sizeof(int)); if (i == 2) { pipe_simd_width = warp_size; } else if (i == 3) { assert(warp_size % pipe_simd_width == 0); } sscanf(gpgpu_runtime_stat, "%d:%x", &gpu_stat_sample_freq, &gpu_runtime_stat_flag); sc = (shader_core_ctx_t**) calloc(gpu_n_shader, sizeof(shader_core_ctx_t*)); int mshr_que = gpu_n_mshr_per_thread; for (i=0;(unsigned)inot_completed = 0; shader_reinit(sc[i],0,sc[i]->n_threads); } if (gpu_max_cta_opt != 0) { g_total_cta_left = gpu_max_cta_opt; } else { g_total_cta_left = ptx_sim_grid_size(); } if (gpu_max_cta_opt != 0) { // the maximum number of CTA has been reached, stop any further simulation if (gpu_tot_issued_cta >= (unsigned)gpu_max_cta_opt) { return 0; } } if (gpu_max_cycle && (gpu_tot_sim_cycle + gpu_sim_cycle) >= gpu_max_cycle) { return gpu_sim_cycle; } if (gpu_max_insn && (gpu_tot_sim_insn + gpu_sim_insn) >= gpu_max_insn) { return gpu_sim_cycle; } // refind the diverge/reconvergence pairs dwf_reset_reconv_pt(); find_reconvergence_points(); dwf_process_reconv_pts(); dwf_reinit_schedulers(gpu_n_shader); // initialize the control-flow, memory access, memory latency logger create_thread_CFlogger( gpu_n_shader, gpu_n_thread_per_shader, ptx_kernel_program_size(), 0, gpgpu_cflog_interval ); shader_CTA_count_create( gpu_n_shader, gpgpu_cflog_interval); if (gpgpu_cflog_interval != 0) { insn_warp_occ_create( gpu_n_shader, warp_size, ptx_kernel_program_size() ); shader_warp_occ_create( gpu_n_shader, warp_size, gpgpu_cflog_interval); shader_mem_acc_create( gpu_n_shader, gpu_n_mem, 4, gpgpu_cflog_interval); shader_mem_lat_create( gpu_n_shader, gpgpu_cflog_interval); shader_cache_access_create( gpu_n_shader, 3, gpgpu_cflog_interval); set_spill_interval (gpgpu_cflog_interval * 40); } // calcaulte the max cta count and cta size for local memory address mapping gpu_max_cta_per_shader = max_cta_per_shader(sc[0]); //gpu_max_cta_per_shader is limited by number of CTAs if not enough if (ptx_sim_grid_size() < gpu_max_cta_per_shader*gpu_n_shader) { gpu_max_cta_per_shader = (ptx_sim_grid_size() / gpu_n_shader); if (ptx_sim_grid_size() % gpu_n_shader) gpu_max_cta_per_shader++; } unsigned int gpu_cta_size = ptx_sim_cta_size(); gpu_padded_cta_size = (gpu_cta_size%32) ? 32*((gpu_cta_size/32)+1) : gpu_cta_size; if (g_network_mode) { icnt_init_grid(); } last_gpu_sim_insn = 0; // add this condition as well? (gpgpu_n_processed_writes < gpgpu_n_sent_writes) while (not_completed || mem_busy || icnt2mem_busy) { gpu_sim_loop(grid_num); not_completed = 0; for (unsigned i=0;inot_completed; } // dram_busy just check the request queue length into the dram // to make sure all the memory requests (esp the writes) are done mem_busy = 0; for (unsigned i=0;i= gpu_max_cycle) { break; } if (gpu_max_insn && (gpu_tot_sim_insn + gpu_sim_insn) >= gpu_max_insn) { break; } if (gpu_deadlock_detect && gpu_deadlock) { break; } } memlatstat_lat_pw(); gpu_tot_sim_cycle += gpu_sim_cycle; gpu_tot_sim_insn += gpu_sim_insn; gpu_tot_completed_thread += gpu_completed_thread; ptx_file_line_stats_write_file(); printf("stats for grid: %d\n", grid_num); gpu_print_stat(); if (g_network_mode) { interconnect_stats(); printf("----------------------------Interconnect-DETAILS---------------------------------" ); icnt_overal_stat(); printf("----------------------------END-of-Interconnect-DETAILS-------------------------" ); } if (gpgpu_memlatency_stat & GPU_MEMLATSTAT_QUEUELOGS ) { dramqueue_latency_log_dump(); dram_log(DUMPLOG); if (gpgpu_cache_dl2_opt) { L2c_log(DUMPLOG); L2c_latency_log_dump(); } } #define DEADLOCK 0 if (gpu_deadlock_detect && gpu_deadlock) { fflush(stdout); printf("GPGPU-Sim uArch: ERROR ** deadlock detected: last writeback @ gpu_sim_cycle %u (+ gpu_tot_sim_cycle %u) (%u cycles ago)\n", (unsigned) gpu_sim_insn_last_update, (unsigned) (gpu_tot_sim_cycle-gpu_sim_cycle), (unsigned) (gpu_sim_cycle - gpu_sim_insn_last_update )); fflush(stdout); assert(DEADLOCK); } return gpu_sim_cycle; } extern void ** g_inst_classification_stat; extern void ** g_inst_op_classification_stat; extern int g_ptx_kernel_count; // used for classification stat collection purposes extern unsigned get_max_mshr_used(shader_core_ctx_t* shader); void gpu_print_stat() { unsigned i; int j,k; printf("gpu_sim_cycle = %lld\n", gpu_sim_cycle); printf("gpu_sim_insn = %lld\n", gpu_sim_insn); printf("gpu_sim_no_ld_const_insn = %lld\n", gpu_sim_insn_no_ld_const); printf("gpu_ipc = %12.4f\n", (float)gpu_sim_insn / gpu_sim_cycle); printf("gpu_completed_thread = %lld\n", gpu_completed_thread); printf("gpu_tot_sim_cycle = %lld\n", gpu_tot_sim_cycle); printf("gpu_tot_sim_insn = %lld\n", gpu_tot_sim_insn); printf("gpu_tot_ipc = %12.4f\n", (float)gpu_tot_sim_insn / gpu_tot_sim_cycle); printf("gpu_tot_completed_thread = %lld\n", gpu_tot_completed_thread); printf("gpu_tot_issued_cta = %lld\n", gpu_tot_issued_cta); printf("gpgpu_n_sent_writes = %d\n", gpgpu_n_sent_writes); printf("gpgpu_n_processed_writes = %d\n", gpgpu_n_processed_writes); // performance counter for stalls due to congestion. printf("gpu_stall_by_MSHRwb= %d\n", gpu_stall_by_MSHRwb); printf("gpu_stall_shd_mem = %d\n", gpu_stall_shd_mem ); printf("gpu_stall_wr_back = %d\n", gpu_stall_wr_back ); printf("gpu_stall_dramfull = %d\n", gpu_stall_dramfull); printf("gpu_stall_icnt2sh = %d\n", gpu_stall_icnt2sh ); printf("gpu_stall_sh2icnt = %d\n", gpu_stall_sh2icnt ); // performance counter that are not local to one shader shader_print_accstats(stdout); memlatstat_print(); printf("max return queue length = "); for (unsigned i=0;iL1cache,stdout); j+=sc[i]->L1cache->miss; k+=sc[i]->L1cache->access; } printf("L1 Data Cache Total Miss Rate = %0.3f\n", (float)j/k); for (i=0,j=0,k=0;iL1texcache,stdout); j+=sc[i]->L1texcache->miss; k+=sc[i]->L1texcache->access; } printf("L1 Texture Cache Total Miss Rate = %0.3f\n", (float)j/k); for (i=0,j=0,k=0;iL1constcache,stdout); j+=sc[i]->L1constcache->miss; k+=sc[i]->L1constcache->access; } printf("L1 Const Cache Total Miss Rate = %0.3f\n", (float)j/k); if (gpgpu_cache_dl2_opt) { L2c_print_cache_stat(); } printf("n_regconflict_stall = %d\n", n_regconflict_stall); if (gpgpu_simd_model == DWF) { dwf_print_stat(stdout); } if (gpgpu_simd_model == POST_DOMINATOR) { printf("num_warps_issuable:"); for (unsigned i=0;i<(gpu_n_warp_per_shader+1);i++) { printf("%d ", num_warps_issuable[i]); } printf("\n"); } if (gpgpu_strict_simd_wrbk) { printf("warp_conflict_at_writeback = %d\n", warp_conflict_at_writeback); } printf("gpgpu_commit_pc_beyond_two = %d\n", gpgpu_commit_pc_beyond_two); print_shader_cycle_distro( stdout ); print_thread_pc_histogram( stdout ); if (gpgpu_cflog_interval != 0) { spill_log_to_file (stdout, 1, gpu_sim_cycle); insn_warp_occ_print(stdout); } if ( gpgpu_ptx_instruction_classification ) { StatDisp( g_inst_classification_stat[g_ptx_kernel_count]); StatDisp( g_inst_op_classification_stat[g_ptx_kernel_count]); } time_vector_print(); fflush(stdout); } //////////////////////////////////////////////////////////////////////////////////// // Wrapper function for shader cores' memory system: //////////////////////////////////////////////////////////////////////////////////// // a hack to make the size of a packet discrete multiples of the interconnect's flit_size. static inline unsigned int fill_to_next_flit(unsigned int size) { assert (g_network_mode == INTERSIM); return size; } unsigned char check_icnt_has_buffer(unsigned long long int *addr, int *bsize, int n_addr, int sid ) { addrdec_t tlx; static unsigned int *req_buffer = NULL; //the req_buf size can be equal to gpu_n_mem ; gpu_n_shader is added to make it compatible //with the case where a mem controller is sending to shd if (!req_buffer) req_buffer = (unsigned int*)malloc((gpu_n_mem+gpu_n_tpc)*sizeof(unsigned int)); memset(req_buffer, 0, (gpu_n_mem+gpu_n_tpc)*sizeof(unsigned int)); // aggregate all buffer requirement of all memory accesses by dram chips for (int i=0; i< n_addr; i++) { addrdec_tlx(addr[i],&tlx); req_buffer[tlx.chip] += fill_to_next_flit(bsize[i]); } int tpc_id = sid / gpu_concentration; return icnt_has_buffer(tpc_id, req_buffer); } unsigned char single_check_icnt_has_buffer(int chip, int sid, unsigned char is_write ) { static unsigned int *req_buffer = NULL; //the req_buf size can be equal to gpu_n_mem ; gpu_n_shader is added to make it compatible //with the case where a mem controller is sending to shd if (!req_buffer) req_buffer = (unsigned int*)malloc((gpu_n_mem+gpu_n_tpc)*sizeof(unsigned int)); memset(req_buffer, 0, (gpu_n_mem+gpu_n_tpc)*sizeof(unsigned int)); // aggregate all buffer requirement of all memory accesses by dram chips int b_size; if (is_write) b_size = sc[sid]->L1cache->line_sz; else b_size = READ_PACKET_SIZE; req_buffer[chip] += fill_to_next_flit(b_size); int tpc_id = sid / gpu_concentration; return icnt_has_buffer(tpc_id, req_buffer); } int max_n_addr = 0; // Check the memory system for buffer availability unsigned char fq_has_buffer(unsigned long long int addr, int bsize, bool write, int sid ) { //requests should be single always now int rsize = bsize; //maintain similar functionality with fq_push, if its a read, bsize is the load size, not the request's size if (!write) { rsize = READ_PACKET_SIZE; } return check_icnt_has_buffer(&addr, &rsize, 1, sid); } // Takes in memory address and their parameters and pushes to the fetch queue unsigned char fq_push(unsigned long long int addr, int bsize, unsigned char write, partial_write_mask_t partial_write_mask, int sid, int wid, mshr_entry* mshr, int cache_hits_waiting, enum mem_access_type mem_acc, address_type pc) { mem_fetch_t *mf; mf = (mem_fetch_t*) calloc(1,sizeof(mem_fetch_t)); mf->request_uid = g_next_request_uid++; mf->addr = addr; mf->nbytes_L1 = bsize; mf->sid = sid; mf->source_node = sid / gpu_concentration; mf->wid = wid; mf->cache_hits_waiting = cache_hits_waiting; mf->txbytes_L1 = 0; mf->rxbytes_L1 = 0; mf->mshr = mshr; if (mshr) mshr->mf = (void*)mf; // for debugging mf->write = write; if (write) made_write_mfs++; else made_read_mfs++; memlatstat_start(mf); addrdec_tlx(addr,&mf->tlx); mf->bank = mf->tlx.bk; mf->chip = mf->tlx.chip; if (gpgpu_cache_dl2_opt) mf->nbytes_L2 = L2c_get_linesize( dram[mf->tlx.chip] ); else mf->nbytes_L2 = 0; mf->txbytes_L2 = 0; mf->rxbytes_L2 = 0; mf->write_mask = partial_write_mask; if (!write) assert(partial_write_mask == NO_PARTIAL_WRITE); // stat collection codes mf->mem_acc = mem_acc; mf->pc = pc; switch (mem_acc) { case CONST_ACC_R: gpgpu_n_mem_const++; break; case TEXTURE_ACC_R: gpgpu_n_mem_texture++; break; case GLOBAL_ACC_R: gpgpu_n_mem_read_global++; break; case GLOBAL_ACC_W: gpgpu_n_mem_write_global++; break; case LOCAL_ACC_R: gpgpu_n_mem_read_local++; break; case LOCAL_ACC_W: gpgpu_n_mem_write_local++; break; default: assert(0); } return(issue_mf_from_fq(mf)); } int issue_mf_from_fq(mem_fetch_t *mf){ int destination; // where is the next level of memory? destination = mf->tlx.chip; int tpc_id = mf->sid / gpu_concentration; if (mf->mshr) mshr_update_status(mf->mshr,IN_ICNT2MEM); if (!mf->write) { mf->type = RD_REQ; assert( mf->timestamp == (gpu_sim_cycle+gpu_tot_sim_cycle) ); time_vector_update(mf->mshr->insts[0].uid, MR_ICNT_PUSHED, gpu_sim_cycle+gpu_tot_sim_cycle, mf->type ); icnt_push(tpc_id, mem2device(destination), (void*)mf, READ_PACKET_SIZE); } else { mf->type = WT_REQ; icnt_push(tpc_id, mem2device(destination), (void*)mf, mf->nbytes_L1); gpgpu_n_sent_writes++; assert( mf->timestamp == (gpu_sim_cycle+gpu_tot_sim_cycle) ); time_vector_update(mf->request_uid, MR_ICNT_PUSHED, gpu_sim_cycle+gpu_tot_sim_cycle, mf->type ) ; } return 0; } extern void mshr_return_from_mem(shader_core_ctx_t * shader, mshr_entry_t* mshr); inline void fill_shd_L1_with_new_line(shader_core_ctx_t * sc, mem_fetch_t * mf) { unsigned long long int repl_addr = -1; // When the data arrives, it flags all the appropriate MSHR // entries accordingly (by checking the address in each entry ) memlatstat_read_done(mf); mshr_return_from_mem(sc, mf->mshr); if (mf->mshr->istexture) { shd_cache_fill(sc->L1texcache,mf->addr,sc->gpu_cycle); repl_addr = -1; } else if (mf->mshr->isconst) { shd_cache_fill(sc->L1constcache,mf->addr,sc->gpu_cycle); repl_addr = -1; } else { if (!gpgpu_no_dl1) { //if we are doing a writeback cache we may have marked off a mask in the mshr //only write into the cache unmasked bytes. //since this doesn't affect timing we don't actually do it. repl_addr = shd_cache_fill(sc->L1cache,mf->addr,sc->gpu_cycle); } } freed_read_mfs++; free(mf); } unsigned char fq_pop(int tpc_id) { mem_fetch_t *mf; mf = (mem_fetch_t*) icnt_pop(tpc_id); // if there is a memory fetch request coming back, forward it to the proper shader core if (mf) { assert(mf->type == REPLY_DATA); time_vector_update(mf->mshr->insts[0].uid ,MR_2SH_FQ_POP,gpu_sim_cycle+gpu_tot_sim_cycle, mf->type ) ; fill_shd_L1_with_new_line(sc[mf->sid], mf); } return 0; } //////////////////////////////////////////////////////////////////////////////////////////////// int issue_block2core( shader_core_ctx_t *shdr, int grid_num ) { int tid, nthreads_2beissued, more_threads; int nthreads_in_block= 0; int start_thread = 0; int end_thread = shdr->n_threads; int cta_id=-1; int cta_size=0; int padded_cta_size; cta_size = ptx_sim_cta_size(); padded_cta_size = cta_size; assert(gpgpu_spread_blocks_across_cores); //should be if muliple CTA per shader supported for (unsigned i=0;icta_status[i]==0) { // cta_id=i; break; } } assert( cta_id!=-1);//must have found a CTA to run if (padded_cta_size%warp_size) { padded_cta_size = ((padded_cta_size/warp_size)+1)*(warp_size); } start_thread = cta_id * padded_cta_size; end_thread = start_thread + cta_size; shader_reinit(shdr,start_thread, end_thread); // issue threads in blocks (if it is specified) warp_set_t warps; for (int i = start_thread; ithread[i].cta_id = cta_id; nthreads_in_block += ptx_sim_init_thread(&shdr->thread[i].ptx_thd_info,shdr->sid,i,cta_size-(i-start_thread),shdr->n_threads/*cta_size*/,shdr,cta_id,warp_id); warps.set( warp_id ); } shdr->allocate_barrier( cta_id, warps ); shader_init_CTA(shdr, start_thread, end_thread); nthreads_2beissued = nthreads_in_block; shdr->cta_status[cta_id]+=nthreads_2beissued; assert( nthreads_2beissued ); //we should have not reached this point if there is no more thread to - assert( (unsigned) nthreads_2beissued <= shdr->n_threads); //confirm threads to be issued is less than or equal to number of threads supported by microarchitecture int n_cta_issued= nthreads_2beissued/cta_size ;//+ nthreads_2beissued%cta_size; shdr->n_active_cta += n_cta_issued; shader_CTA_count_log(shdr->sid, n_cta_issued); g_total_cta_left-= n_cta_issued; more_threads = 1; if (gpgpu_spread_blocks_across_cores) { nthreads_2beissued += start_thread; } printf("GPGPU-Sim uArch: Shader %d initializing CTA #%d with hw tids from %d to %d @(%lld,%lld)", shdr->sid, cta_id, start_thread, nthreads_2beissued, gpu_sim_cycle, gpu_tot_sim_cycle ); printf(" shdr->not_completed = %d\n", shdr->not_completed); for (tid=start_thread;tidnot_completed += 1; assert( shdr->warp[tid/warp_size].n_completed > 0 ); assert( shdr->warp[tid/warp_size].n_completed <= warp_size); shdr->warp[tid/warp_size].n_completed--; // set avail4fetch flag to ready shdr->thread[tid].avail4fetch = 1; assert( shdr->warp[tid/warp_size].n_avail4fetch < warp_size ); shdr->warp[tid/warp_size].n_avail4fetch++; g_nthreads_issued++; } if (!nthreads_in_block) more_threads = 0; return more_threads; //if there are no more threads to be issued, return 0 } /////////////////////////////////////////////////////////////////////////////////////////// // wrapper code to to create an illusion of a memory controller with L2 cache. // int mem_ctrl_full( int mc_id ) { if (gpgpu_cache_dl2_opt) { return L2c_full( dram[mc_id] ); } else { return( gpgpu_dram_sched_queue_size && dram_full(dram[mc_id]) ); } } //#define DEBUG_PARTIAL_WRITES void mem_ctrl_push( int mc_id, mem_fetch_t* mf ) { if (gpgpu_cache_dl2_opt) { L2c_push(dram[mc_id], mf); } else { addrdec_t tlx; addrdec_tlx(mf->addr, &tlx); #if 0 //old chunking no longer valid. if (gpgpu_partial_write_mask && mf->write) { assert( gpgpu_no_dl1 ); // gpgpu_partial_write_mask is not supported with caches for now } #endif //#if 0 //old chunking no longer valid dram_push(dram[mc_id], tlx.bk, tlx.row, tlx.col, mf->nbytes_L1, mf->write, mf->wid, mf->sid, mf->cache_hits_waiting, mf->addr, mf); memlatstat_dram_access(mf, mc_id, tlx.bk); if (mf->mshr) mshr_update_status(mf->mshr,IN_DRAM_REQ_QUEUE); } } void* mem_ctrl_pop( int mc_id ) { mem_fetch_t* mf; if (gpgpu_cache_dl2_opt) { mf = L2c_pop(dram[mc_id]); if (mf && mf->mshr && mf->mshr->insts[0].callback.function) { dram_callback_t* cb = &(mf->mshr->insts[0].callback); cb->function(cb->instruction, cb->thread); } return mf; } else { mf = static_cast (dq_pop(dram[mc_id]->returnq)); //dram_pop(dram[mc_id]); if (mf) mf->type = REPLY_DATA; if (mf && mf->mshr && mf->mshr->insts[0].callback.function) { dram_callback_t* cb = &(mf->mshr->insts[0].callback); cb->function(cb->instruction, cb->thread); } return mf; } } void* mem_ctrl_top( int mc_id ) { mem_fetch_t* mf; if (gpgpu_cache_dl2_opt) { return L2c_top(dram[mc_id]); } else { mf = static_cast (dq_top(dram[mc_id]->returnq));//dram_top(dram[mc_id]); if (mf) mf->type = REPLY_DATA; return mf ;//dram_top(dram[mc_id]); } } void get_dram_output ( dram_t* dram_p ) { mem_fetch_t* mf; mem_fetch_t* mf_top; mf_top = (mem_fetch_t*) dram_top(dram_p); //test if (mf_top) { if (mf_top->type == DUMMY_READ) { dram_pop(dram_p); free(mf_top); freed_dummy_read_mfs++; return; } } if (gpgpu_cache_dl2_opt) { L2c_get_dram_output( dram_p ); } else { if ( dq_full(dram_p->returnq) ) return; mf = (mem_fetch_t*) dram_pop(dram_p); assert (mf_top==mf ); if (mf) { dq_push(dram_p->returnq, mf); if (mf->mshr) mshr_update_status(mf->mshr,IN_DRAMRETURN_Q); } } } void dram_log (int task ) { static void ** mrqq_Dist; //memory request queue inside DRAM if (task == CREATELOG) { mrqq_Dist = (void **) calloc(gpu_n_mem,sizeof(void*)); for (unsigned i=0;iqueue_limit) mrqq_Dist[i] = StatCreate("mrqq_length",1,dram[i]->queue_limit); else //queue length is unlimited; mrqq_Dist[i] = StatCreate("mrqq_length",1,64); //track up to 64 entries } } else if (task == SAMPLELOG) { for (unsigned i=0;imrqq->lat_stat); printf ("(LOGB2)Latency DRAM[%d] ",i);StatDisp(dram[i]->rwq->lat_stat); } } //Find next clock domain and increment its time inline int next_clock_domain(void) { double smallest = min3(core_time,icnt_time,dram_time); int mask = 0x00; if (gpgpu_cache_dl2_opt //when no-L2 it will never be L2's turn && ( l2_time <= smallest) ) { smallest = l2_time; mask |= L2 ; l2_time += l2_period; } if ( icnt_time <= smallest ) { mask |= ICNT; icnt_time += icnt_period; } if ( dram_time <= smallest ) { mask |= DRAM; dram_time += dram_period; } if ( core_time <= smallest ) { mask |= CORE; core_time += core_period; } return mask; } extern time_t simulation_starttime; void gpu_sim_loop( int grid_num ) { int clock_mask = next_clock_domain(); // shader core loading (pop from ICNT into shader core) follows CORE clock if (clock_mask & CORE ) { for (int i=0;isource_node = mem2device(i); assert( mf->type != RD_REQ && mf->type != WT_REQ ); // never should a request come out from L2 or dram if (!mf->write) { int return_dev = -1; return_dev = mf->sid / gpu_concentration; assert(return_dev != -1); // check icnt resource for READ data return rt_size[return_dev] = mf->nbytes_L1; if ( icnt_has_buffer( mem2device(i), rt_size) ) { if (mf->mshr) mshr_update_status(mf->mshr,IN_ICNT2SHADER); memlatstat_icnt2sh_push(mf); time_vector_update(mf->mshr->insts[0].uid ,MR_2SH_ICNT_PUSHED,gpu_sim_cycle+gpu_tot_sim_cycle,RD_REQ); icnt_push( mem2device(i), return_dev, mf, mf->nbytes_L1); mem_ctrl_pop(i); } else { gpu_stall_icnt2sh++; } rt_size[return_dev] = 0; // clean up for the next dram_pop } else { time_vector_update(mf->request_uid ,MR_2SH_ICNT_PUSHED,gpu_sim_cycle+gpu_tot_sim_cycle,WT_REQ ) ; mem_ctrl_pop(i); free(mf); freed_L1write_mfs++; gpgpu_n_processed_writes++; } } } } if (clock_mask & DRAM) { for (unsigned i=0;itype==RD_REQ) { time_vector_update(mf->mshr->insts[0].uid ,MR_DRAMQ,gpu_sim_cycle+gpu_tot_sim_cycle,mf->type ) ; } else { time_vector_update(mf->request_uid ,MR_DRAMQ,gpu_sim_cycle+gpu_tot_sim_cycle,mf->type ) ; } memlatstat_icnt2mem_pop(mf); mem_ctrl_push( i, mf ); } } icnt_transfer( ); } if (clock_mask & CORE) { // L1 cache + shader core pipeline stages for (unsigned i=0;inot_completed || more_thread) shader_cycle(sc[i], i, grid_num); sc[i]->gpu_cycle++; } gpu_sim_cycle++; for (unsigned i=0;in_active_cta + cta_issue_count) <= max_cta_per_shader(sc[i]) ) && g_total_cta_left ) { int j; for (j=0;j -1 ); } } else { if (!(sc[i]->not_completed)) more_thread = issue_block2core(sc[i], grid_num); } } // Flush the caches once all of threads are completed. if (gpgpu_flush_cache) { int all_threads_complete = 1 ; for (unsigned i=0;inot_completed == 0) { shader_cache_flush(sc[i]); } else { all_threads_complete = 0 ; } } if (all_threads_complete) { printf("Flushed L1 caches...\n"); if (gpgpu_cache_dl2_opt) { int dlc = 0; for (unsigned i=0;i= gpu_n_shader ) { printf("shader %u is out of range\n",sid); return; } if ( tid >= gpu_n_thread_per_shader ) { printf("thread %u is out of range\n",tid); return; } shader_core_ctx_t *s = sc[sid]; ptx_dump_regs( s->thread[tid].ptx_thd_info ); } int ptx_thread_done( void *thr ); void shader_dump_istream_state(shader_core_ctx_t *shader, FILE *fout ) { fprintf( fout, "\n"); for (unsigned t=0; t < gpu_n_thread_per_shader/warp_size; t++ ) { int tid = t*warp_size; if ( shader->warp[t].n_completed < warp_size ) { fprintf( fout, " %u:%3u (w%02u) fetch state = c:%u a4f:%u bw:%u (completed: ", shader->sid, tid, t, shader->warp[t].n_completed, shader->warp[t].n_avail4fetch, shader->warp[t].n_waiting_at_barrier ); for (unsigned i = tid; i < (t+1)*warp_size; i++ ) { if ( ptx_thread_done(shader->thread[i].ptx_thd_info) ) { fprintf(fout,"1"); } else { fprintf(fout,"0"); } if ( (((i+1)%4) == 0) && (i+1) < (t+1)*warp_size ) { fprintf(fout,","); } } fprintf(fout,")\n"); } } } void dump_pipeline_impl( int mask, int s, int m ) { /* You may want to use this function while running GPGPU-Sim in gdb. One way to do that is add the following to your .gdbinit file: define dp call dump_pipeline_impl((0x40|0x4|0x1),$arg0,0) end Then, typing "dp 3" will show the contents of the pipeline for shader core 3. */ printf("Dumping pipeline state...\n"); if(!mask) mask = 0xFFFFFFFF; for (unsigned i=0;i