summaryrefslogtreecommitdiff
path: root/src/gpgpu-sim/gpu-sim.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/gpgpu-sim/gpu-sim.cc')
-rw-r--r--src/gpgpu-sim/gpu-sim.cc1752
1 files changed, 1752 insertions, 0 deletions
diff --git a/src/gpgpu-sim/gpu-sim.cc b/src/gpgpu-sim/gpu-sim.cc
new file mode 100644
index 0000000..6ae7430
--- /dev/null
+++ b/src/gpgpu-sim/gpu-sim.cc
@@ -0,0 +1,1752 @@
+/*
+ * 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 <time.h>
+#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 <stdio.h>
+#include <string.h>
+#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;
+
+int 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;
+int 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( void** 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 <n>.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., {<nsets>:<linesize>:<assoc>:<repl>|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., {<nsets>:<linesize>:<assoc>:<repl>|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., {<nsets>:<bsize>:<assoc>:<repl>|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., {<nsets>:<bsize>:<assoc>:<repl>|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., {<nthread>:<warpsize>:<pipe_simd_width>}",
+ "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 {<freq>:<flag>}",
+ "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>:<associativity>|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 {<Core Clock>:<ICNT Clock>:<L2 Clock>:<DRAM Clock>}",
+ "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)i<gpu_n_shader;i++) {
+ sc[i] = shader_create("sh", i, /* shader id*/
+ gpu_n_thread_per_shader, /* number of threads */
+ mshr_que, /* number of MSHR per threads */
+ fq_push, fq_has_buffer, gpgpu_simd_model);
+ }
+
+ ptx_file_line_stats_create_exposed_latency_tracker(gpu_n_shader);
+
+ // initialize dynamic warp formation scheduler
+ int dwf_lut_size, dwf_lut_assoc;
+ sscanf(gpgpu_dwf_hw_opt,"%d:%d", &dwf_lut_size, &dwf_lut_assoc);
+ char *dwf_hw_policy_opt = strchr(gpgpu_dwf_hw_opt, ';');
+ int insn_size = 1; // for cuda-sim
+ create_dwf_schedulers(gpu_n_shader, dwf_lut_size, dwf_lut_assoc,
+ warp_size, pipe_simd_width,
+ gpu_n_thread_per_shader, insn_size,
+ gpgpu_dwf_heuristic, dwf_hw_policy_opt );
+
+ gpgpu_no_divg_load = gpgpu_no_divg_load && (gpgpu_simd_model == DWF);
+ // always use no diverge on load for PDOM and NAIVE
+ gpgpu_no_divg_load = gpgpu_no_divg_load || (gpgpu_simd_model == POST_DOMINATOR || gpgpu_simd_model == NO_RECONVERGE);
+ if (gpgpu_no_divg_load)
+ init_warp_tracker();
+
+ assert(gpu_n_shader % gpu_concentration == 0);
+ gpu_n_tpc = gpu_n_shader / gpu_concentration;
+
+ dram = (dram_t**) calloc(gpu_n_mem, sizeof(dram_t*));
+ // L2request = (mem_fetch_t**) calloc(gpu_n_mem, sizeof(mem_fetch_t*));
+ addrdec_setnchip(gpu_n_mem);
+ unsigned int nbk,tCCD,tRRD,tRCD,tRAS,tRP,tRC,CL,WL,tWTR;
+ sscanf(gpgpu_dram_timing_opt,"%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",&nbk,&tCCD,&tRRD,&tRCD,&tRAS,&tRP,&tRC,&CL,&WL,&tWTR);
+ gpu_mem_n_bk = nbk;
+ for (i=0;(unsigned)i<gpu_n_mem;i++) {
+ dram[i] = dram_create(i, nbk, tCCD, tRRD, tRCD, tRAS, tRP, tRC,
+ CL, WL, gpgpu_dram_burst_length/*BL*/, tWTR, gpgpu_dram_buswidth/*busW*/,
+ gpgpu_dram_sched_queue_size, gpgpu_dram_scheduler);
+ if (gpgpu_cache_dl2_opt)
+ L2c_create(dram[i], gpgpu_cache_dl2_opt);
+ }
+ dram_log(CREATELOG);
+ if (gpgpu_cache_dl2_opt && 1) {
+ L2c_log(CREATELOG);
+ }
+ concurrent_row_access = (unsigned int**) calloc(gpu_n_mem, sizeof(unsigned int*));
+ num_activates = (unsigned int**) calloc(gpu_n_mem, sizeof(unsigned int*));
+ row_access = (unsigned int**) calloc(gpu_n_mem, sizeof(unsigned int*));
+ max_conc_access2samerow = (unsigned int**) calloc(gpu_n_mem, sizeof(unsigned int*));
+ max_servicetime2samerow = (unsigned int**) calloc(gpu_n_mem, sizeof(unsigned int*));
+
+ for (i=0;(unsigned)i<gpu_n_mem ;i++ ) {
+ concurrent_row_access[i] = (unsigned int*) calloc(gpu_mem_n_bk, sizeof(unsigned int));
+ row_access[i] = (unsigned int*) calloc(gpu_mem_n_bk, sizeof(unsigned int));
+ num_activates[i] = (unsigned int*) calloc(gpu_mem_n_bk, sizeof(unsigned int));
+ max_conc_access2samerow[i] = (unsigned int*) calloc(gpu_mem_n_bk, sizeof(unsigned int));
+ max_servicetime2samerow[i] = (unsigned int*) calloc(gpu_mem_n_bk, sizeof(unsigned int));
+ }
+
+ memlatstat_init();
+
+ L2c_init_stat();
+ max_return_queue_length = (unsigned int*) calloc(gpu_n_shader, sizeof(unsigned int));
+ icnt_init(gpu_n_tpc, gpu_n_mem);
+
+ common_clock = 0;
+
+ time_vector_create(NUM_MEM_REQ_STAT,MR_2SH_ICNT_INJECTED);
+}
+
+
+
+void gpu_print_stat();
+
+void init_clock_domains(void ) {
+ sscanf(gpgpu_clock_domains,"%lf:%lf:%lf:%lf",
+ &core_freq, &icnt_freq, &l2_freq, &dram_freq);
+ core_freq = core_freq MhZ;
+ icnt_freq = icnt_freq MhZ;
+ l2_freq = l2_freq MhZ;
+ dram_freq = dram_freq MhZ;
+ core_period = 1/core_freq;
+ icnt_period = 1/icnt_freq;
+ dram_period = 1/dram_freq;
+ l2_period = 1/l2_freq;
+ core_time = 0 ;
+ dram_time = 0 ;
+ icnt_time = 0;
+ l2_time = 0;
+ printf("GPGPU-Sim uArch: clock freqs: %lf:%lf:%lf:%lf\n",core_freq,icnt_freq,l2_freq,dram_freq);
+ printf("GPGPU-Sim uArch: clock periods: %.20lf:%.20lf:%.20lf:%.20lf\n",core_period,icnt_period,l2_period,dram_period);
+}
+
+void reinit_clock_domains(void)
+{
+ core_time = 0 ;
+ dram_time = 0 ;
+ icnt_time = 0;
+ l2_time = 0;
+}
+
+void init_once(void ) {
+ init_clock_domains();
+}
+
+// return the number of cycle required to run all the trace on the gpu
+unsigned int run_gpu_sim(int grid_num)
+{
+
+ int not_completed;
+ int mem_busy;
+ int icnt2mem_busy;
+
+ gpu_sim_cycle = 0;
+ not_completed = 1;
+ mem_busy = 1;
+ icnt2mem_busy = 1;
+ finished_trace = 0;
+ g_next_request_uid = 1;
+ more_thread = 1;
+ gpu_sim_insn = 0;
+ gpu_sim_insn_no_ld_const = 0;
+
+ gpu_completed_thread = 0;
+
+ g_nthreads_issued = 0;
+
+ static int one_time_inits_done = 0 ;
+ if (!one_time_inits_done ) {
+ init_once();
+ }
+ reinit_clock_domains();
+ assert(gpgpu_spread_blocks_across_cores); // this seems to be required, so let's make it explicit
+ set_option_gpgpu_spread_blocks_across_cores(gpgpu_spread_blocks_across_cores);
+ set_param_gpgpu_num_shaders(gpu_n_shader);
+ for (unsigned i=0;i<gpu_n_shader;i++) {
+ sc[i]->not_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;i<gpu_n_shader;i++) {
+ not_completed += sc[i]->not_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_n_mem;i++) {
+ mem_busy += dram_busy(dram[i]);
+ }
+ // icnt to the memory should clean of any pending tranfers as well
+ icnt2mem_busy = icnt_busy( );
+
+ if (gpu_max_cycle && (gpu_tot_sim_cycle + gpu_sim_cycle) >= 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("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;i<gpu_n_shader;i++) {
+ printf("%d ", max_return_queue_length[i]);
+ }
+ printf("\n");
+ // merge misses
+ printf("merge misses = %d\n", mergemiss);
+ printf("L1 read misses = %d\n", L1_read_miss);
+ printf("L1 write misses = %d\n", L1_write_miss);
+ printf("L1 write hit on misses = %d\n", L1_write_hit_on_miss);
+ printf("L1 writebacks = %d\n", L1_writeback);
+ printf("L1 texture misses = %d\n", L1_texture_miss);
+ printf("L1 const misses = %d\n", L1_const_miss);
+ printf("L2_write_miss = %d\n", L2_write_miss);
+ printf("L2_write_hit = %d\n", L2_write_hit);
+ printf("L2_read_miss = %d\n", L2_read_miss);
+ printf("L2_read_hit = %d\n", L2_read_hit);
+ printf("made_read_mfs = %d\n", made_read_mfs);
+ printf("made_write_mfs = %d\n", made_write_mfs);
+ printf("freed_read_mfs = %d\n", freed_read_mfs);
+ printf("freed_L1write_mfs = %d\n", freed_L1write_mfs);
+ printf("freed_L2write_mfs = %d\n", freed_L2write_mfs);
+ printf("freed_dummy_read_mfs = %d\n", freed_dummy_read_mfs);
+
+ printf("gpgpu_n_mem_read_local = %d\n", gpgpu_n_mem_read_local);
+ printf("gpgpu_n_mem_write_local = %d\n", gpgpu_n_mem_write_local);
+ printf("gpgpu_n_mem_read_global = %d\n", gpgpu_n_mem_read_global);
+ printf("gpgpu_n_mem_write_global = %d\n", gpgpu_n_mem_write_global);
+ printf("gpgpu_n_mem_texture = %d\n", gpgpu_n_mem_texture);
+ printf("gpgpu_n_mem_const = %d\n", gpgpu_n_mem_const);
+
+ printf("max_n_mshr_used = ");
+ for (unsigned i=0; i< gpu_n_shader; i++) printf("%d ", get_max_mshr_used(sc[i]));
+ printf("\n");
+
+ if (gpgpu_cache_dl2_opt) {
+ L2c_print_stat( );
+ }
+ for (unsigned i=0;i<gpu_n_mem;i++) {
+ dram_print(dram[i],stdout);
+ }
+
+ for (i=0, j=0, k=0;i<gpu_n_shader;i++) {
+ shd_cache_print(sc[i]->L1cache,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;i<gpu_n_shader;i++) {
+ shd_cache_print(sc[i]->L1texcache,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;i<gpu_n_shader;i++) {
+ shd_cache_print(sc[i]->L1constcache,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;i<max_cta_per_shader(shdr);i++ ) { //try to find next empty cta slot
+ if (shdr->cta_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; i<end_thread; i++) { //setup the block
+ unsigned warp_id = i/warp_size;
+ shdr->thread[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("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;tid<nthreads_2beissued;tid++) {
+
+ // reset complete flag for stream
+ shdr->not_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<mem_fetch_t*> (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<mem_fetch_t*> (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;i<gpu_n_mem;i++) {
+ if (dram[i]->queue_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;i<gpu_n_mem;i++) {
+ StatAddSample(mrqq_Dist[i], dram_que_length(dram[i]));
+ }
+ } else if (task == DUMPLOG) {
+ for (unsigned i=0;i<gpu_n_mem;i++) {
+ printf ("Queue Length DRAM[%d] ",i);StatDisp(mrqq_Dist[i]);
+ }
+ }
+}
+
+void dramqueue_latency_log_dump()
+{
+ for (unsigned i=0;i<gpu_n_mem;i++) {
+ printf ("(LOGB2)Latency DRAM[%d] ",i);StatDisp(dram[i]->mrqq->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;i<gpu_n_tpc;i++) {
+ fq_pop(i);
+ }
+ }
+
+ if (clock_mask & ICNT) {
+ // pop from memory controller to interconnect
+ static unsigned int *rt_size = NULL;
+ if (!rt_size) rt_size = (unsigned int*) malloc ((gpu_n_tpc+gpu_n_mem)*sizeof(unsigned int));
+ memset(rt_size, 0, (gpu_n_tpc+gpu_n_mem)*sizeof(unsigned int));
+
+ for (unsigned i=0;i<gpu_n_mem;i++) {
+
+ mem_fetch_t* mf;
+
+ mf = (mem_fetch_t*) mem_ctrl_top(i); //(returns L2_top or DRAM returnq top)
+
+ if (mf) {
+ mf->source_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;i<gpu_n_mem;i++) {
+ get_dram_output ( dram[i] );
+ }
+ // Issue the dram command (scheduler + delay model)
+ for (unsigned i=0;i<gpu_n_mem;i++) {
+ dram_issueCMD(dram[i]);
+ }
+ dram_log(SAMPLELOG);
+ }
+
+ // L2 operations follow L2 clock domain
+ if (clock_mask & L2) {
+ for (unsigned i=0;i<gpu_n_mem;i++) {
+ L2c_process_dram_output ( dram[i], i ); // pop from dram
+ L2c_push_miss_to_dram ( dram[i] ); //push to dram
+ L2c_service_mem_req ( dram[i], i ); // pop(push) from(to) icnt2l2(l2toicnt) queues; service l2 requests
+ }
+ if (gpgpu_cache_dl2_opt) { // L2 cache enabled
+ for (unsigned i=0;i<gpu_n_mem;i++) {
+ L2c_update_stat( dram[i] );
+ }
+ }
+ if (gpgpu_cache_dl2_opt) { //take a sample of l2c queue lengths
+ L2c_log(SAMPLELOG);
+ }
+ }
+
+ if (clock_mask & ICNT) {
+ // pop memory request from ICNT and
+ // push it to the proper memory controller (L2 or DRAM controller)
+ for (unsigned i=0;i<gpu_n_mem;i++) {
+
+ if ( mem_ctrl_full(i) ) {
+ gpu_stall_dramfull++;
+ continue;
+ }
+
+ mem_fetch_t* mf;
+ mf = (mem_fetch_t*) icnt_pop( mem2device(i) );
+
+ if (mf) {
+ if (mf->type==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;i<gpu_n_shader;i++) {
+ if (sc[i]->not_completed || more_thread)
+ shader_cycle(sc[i], i, grid_num);
+ sc[i]->gpu_cycle++;
+ }
+ gpu_sim_cycle++;
+
+ for (unsigned i=0;i<gpu_n_shader && more_thread;i++) {
+ if (gpgpu_spread_blocks_across_cores) {
+ int cta_issue_count = 1;
+ if ( ( (unsigned) (sc[i]->n_active_cta + cta_issue_count) <= max_cta_per_shader(sc[i]) )
+ && g_total_cta_left ) {
+ int j;
+ for (j=0;j<cta_issue_count;j++) {
+ issue_block2core(sc[i], grid_num);
+ }
+ if (!g_total_cta_left) {
+ more_thread = 0;
+ }
+ assert( g_total_cta_left > -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;i<gpu_n_shader;i++) {
+ if (sc[i]->not_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_mem;i++) {
+ dlc = L2c_cache_flush(dram[i]);
+ printf("Dirty lines flushed from L2 %d is %d \n", i, dlc );
+ }
+ }
+ }
+ }
+
+ if (!(gpu_sim_cycle % 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 - simulation_starttime, 1);
+ 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));
+ printf("cycles: %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,
+ (double)gpu_sim_insn/(double)gpu_sim_cycle,
+ (unsigned)((gpu_tot_sim_insn+gpu_sim_insn) / elapsed_time),
+ (unsigned)days,(unsigned)hrs,(unsigned)minutes,(unsigned)sec,
+ ctime(&curr_time));
+ fflush(stdout);
+ memlatstat_lat_pw();
+ visualizer_printstat();
+ if (gpgpu_runtime_stat && (gpu_runtime_stat_flag != 0) ) {
+ if (gpu_runtime_stat_flag & GPU_RSTAT_BW_STAT) {
+ for (unsigned i=0;i<gpu_n_mem;i++) {
+ dram_print_stat(dram[i],stdout);
+ }
+ printf("maxmrqlatency = %d \n", max_mrq_latency);
+ printf("maxmflatency = %d \n", max_mf_latency);
+ }
+ if (gpu_runtime_stat_flag & GPU_RSTAT_DWF_MAP) {
+ printf("DWF_MS: ");
+ for (unsigned i=0;i<gpu_n_shader;i++) {
+ printf("%u ",acc_dyn_pcs[i]);
+ }
+ printf("\n");
+ print_thread_pc( stdout );
+ }
+ if (gpu_runtime_stat_flag & GPU_RSTAT_SHD_INFO) {
+ shader_print_runtime_stat( stdout );
+ }
+ if (gpu_runtime_stat_flag & GPU_RSTAT_WARP_DIS) {
+ print_shader_cycle_distro( stdout );
+ }
+ if (gpu_runtime_stat_flag & GPU_RSTAT_L1MISS) {
+ shader_print_l1_miss_stat( stdout );
+ }
+ if (gpu_runtime_stat_flag & GPU_RSTAT_PDOM ) {
+ if (pdom_sched_type) {
+ printf ("pdom_original_warps_count %d \n",n_pdom_sc_orig_stat );
+ printf ("pdom_single_warps_count %d \n",n_pdom_sc_single_stat );
+ }
+ }
+ if (gpu_runtime_stat_flag & GPU_RSTAT_SCHED ) {
+ printf("Average Num. Warps Issuable per Shader:\n");
+ for (unsigned i=0;i<gpu_n_shader;i++) {
+ printf("%2.2f ", (float) num_warps_issuable_pershader[i]/ gpu_stat_sample_freq);
+ num_warps_issuable_pershader[i] = 0;
+ }
+ printf("\n");
+ }
+ }
+ }
+
+ for (unsigned i=0;i<gpu_n_mem;i++) {
+ acc_mrq_length[i] += dram_que_length(dram[i]);
+ }
+ if (!(gpu_sim_cycle % 20000)) {
+ // deadlock detection
+ if (gpu_deadlock_detect && gpu_sim_insn == last_gpu_sim_insn) {
+ gpu_deadlock = 1;
+ } else {
+ last_gpu_sim_insn = gpu_sim_insn;
+ }
+ }
+ try_snap_shot(gpu_sim_cycle);
+ spill_log_to_file (stdout, 0, gpu_sim_cycle);
+ }
+}
+
+void dump_regs(unsigned sid, unsigned tid)
+{
+ if ( sid >= 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 fetch state = c:%u a4f:%u bw:%u (completed: ", shader->sid, tid,
+ 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<gpu_n_shader;i++) {
+ if(s != -1) {
+ i = s;
+ }
+ if(mask&1) shader_display_pipeline(sc[i], stdout, 1, mask & 0x2E );
+ if(mask&0x40) shader_dump_istream_state(sc[i], stdout);
+ if(mask&0x100) mshr_print(stdout, sc[i]);
+ if(s != -1) {
+ break;
+ }
+ }
+ if(mask&0x10000) {
+ for (unsigned i=0;i<gpu_n_mem;i++) {
+ if(m != -1) {
+ i=m;
+ }
+ printf("DRAM / memory controller %u:\n", i);
+ if(mask&0x100000) dram_print_stat(dram[i],stdout);
+ if(mask&0x1000000) dram_visualize( dram[i] );
+ if(m != -1) {
+ break;
+ }
+ }
+ }
+ fflush(stdout);
+}
+
+void dump_pipeline()
+{
+ dump_pipeline_impl(0,-1,-1);
+}