diff options
Diffstat (limited to 'src/gpgpu-sim/shader.cc')
| -rw-r--r-- | src/gpgpu-sim/shader.cc | 1601 |
1 files changed, 166 insertions, 1435 deletions
diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc index 495c4c0..976671a 100644 --- a/src/gpgpu-sim/shader.cc +++ b/src/gpgpu-sim/shader.cc @@ -69,8 +69,6 @@ #include "gpu-sim.h" #include "addrdec.h" #include "dram.h" -#include "dwf.h" -#include "warp_tracker.h" #include "stat-tool.h" #include "gpu-misc.h" #include "../cuda-sim/ptx_sim.h" @@ -308,40 +306,11 @@ unsigned char shader_core_ctx::fq_push(unsigned long long int addr, return(m_gpu->issue_mf_from_fq(mf)); } -inst_t *shader_core_ctx::first_valid_thread( inst_t *warp ) +unsigned shader_core_ctx::first_valid_thread( unsigned stage ) { - for(unsigned t=0; t < m_config->warp_size; t++ ) - if( warp[t].hw_thread_id != -1 ) - return warp+t; - return NULL; + abort(); } -inst_t *shader_core_ctx::first_valid_thread( unsigned stage ) -{ - return first_valid_thread(m_pipeline_reg[stage]); -} - -void shader_core_ctx::move_warp( inst_t *&dst, inst_t *&src ) -{ - - assert( pipeline_regster_empty(dst) ); - inst_t* temp = dst; - dst = src; - src = temp; - for( unsigned t=0; t < m_config->warp_size; t++) - src[t] = inst_t(); -} - -void shader_core_ctx::clear_stage( inst_t *warp ) -{ - for( unsigned t=0; t < m_config->warp_size; t++) - warp[t] = inst_t(); -} - -bool shader_core_ctx::pipeline_regster_empty( inst_t *reg ) -{ - return first_valid_thread(reg) == NULL; -} void shader_core_ctx::L1cache_print( FILE *fp, unsigned &total_accesses, unsigned &total_misses) const { @@ -390,28 +359,14 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, m_config = config; m_stats = stats; unsigned warp_size=config->warp_size; - assert( !((config->model == DWF) && m_config->gpgpu_operand_collector) ); m_name = name; m_sid = shader_id; m_tpc = tpc_id; - m_dwf_RR_k = 0; - m_pipeline_reg = (inst_t**) calloc(N_PIPELINE_STAGES, sizeof(inst_t*)); - for (int j = 0; j<N_PIPELINE_STAGES; j++) { - m_pipeline_reg[j] = (inst_t*) calloc(warp_size, sizeof(inst_t)); - for (unsigned i=0; i<warp_size; i++) - m_pipeline_reg[j][i] = inst_t(); - } + m_pipeline_reg = new warp_inst_t*[N_PIPELINE_STAGES]; + for (int j = 0; j<N_PIPELINE_STAGES; j++) + m_pipeline_reg[j] = new warp_inst_t(warp_size); - if (m_config->gpgpu_pre_mem_stages) { - pre_mem_pipeline = (inst_t**) calloc(m_config->gpgpu_pre_mem_stages+1, sizeof(inst_t*)); - for (unsigned j = 0; j<=m_config->gpgpu_pre_mem_stages; j++) { - pre_mem_pipeline[j] = (inst_t*) calloc(warp_size, sizeof(inst_t)); - for (unsigned i=0; i<warp_size; i++) { - pre_mem_pipeline[j][i] = inst_t(); - } - } - } m_thread = (thread_ctx_t*) calloc(sizeof(thread_ctx_t), config->n_thread_per_shader); m_not_completed = 0; @@ -420,11 +375,8 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, m_n_active_cta = 0; for (unsigned i = 0; i<MAX_CTA_PER_SHADER; i++ ) m_cta_status[i]=0; - m_next_warp = 0; for (unsigned i = 0; i<config->n_thread_per_shader; i++) { m_thread[i].m_functional_model_thread_state = NULL; - m_thread[i].m_avail4fetch = false; - m_thread[i].m_waiting_at_barrier = false; m_thread[i].m_cta_id = -1; } @@ -449,8 +401,6 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, m_pdom_warp = new pdom_warp_ctx_t*[config->max_warps_per_shader]; for (unsigned i = 0; i < config->max_warps_per_shader; ++i) m_pdom_warp[i] = new pdom_warp_ctx_t(i,this); - if (m_config->using_commit_queue) - m_thd_commit_queue = new fifo_pipeline<std::vector<int> >("thd_commit_queue", 0, 0,gpu_sim_cycle); m_shader_memory_new_instruction_processed = false; // Initialize scoreboard @@ -477,27 +427,12 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, // fetch m_last_warp_fetched = 0; m_last_warp_issued = 0; - m_ready_warps = (int*)calloc(m_config->max_warps_per_shader,sizeof(int)); - m_tmp_ready_warps = (int*)calloc(m_config->max_warps_per_shader,sizeof(int)); - m_last_warp=0; - m_last_issued_thread=0; // MIMD - - m_warp_tracker = NULL; - m_thread_pc_tracker = NULL; - if (m_config->gpgpu_no_divg_load) { - m_warp_tracker = new warp_tracker_pool(this); - m_thread_pc_tracker = new thread_pc_tracker(warp_size, config->n_thread_per_shader); - } - m_fetch_tid_out = (int*) malloc(sizeof(int) * warp_size); - m_dwf_rrstage_bank_access_counter = (int*) malloc(sizeof(int) * m_config->gpgpu_dwf_rr_stage_n_reg_banks); } void shader_core_ctx::reinit(unsigned start_thread, unsigned end_thread, bool reset_not_completed ) { if( reset_not_completed ) m_not_completed = 0; - m_next_warp = 0; - m_last_issued_thread=0; for (unsigned i = start_thread; i<end_thread; i++) { m_thread[i].n_insn = 0; m_thread[i].m_cta_id = -1; @@ -508,9 +443,8 @@ void shader_core_ctx::reinit(unsigned start_thread, unsigned end_thread, bool re } } -void shader_core_ctx::init_warps( unsigned start_thread, unsigned end_thread ) +void shader_core_ctx::init_warps( unsigned cta_id, unsigned start_thread, unsigned end_thread ) { - unsigned num_threads = end_thread - start_thread; address_type start_pc = next_pc(start_thread); if (m_config->model == POST_DOMINATOR) { unsigned start_warp = start_thread / m_config->warp_size; @@ -525,45 +459,16 @@ void shader_core_ctx::init_warps( unsigned start_thread, unsigned end_thread ) } } m_pdom_warp[i]->launch(start_pc,initial_active_mask); - m_warp[i].init(start_pc,i,n_active); + m_warp[i].init(start_pc,cta_id,i,n_active); m_not_completed += n_active; } - } else if (m_config->model == DWF) { - dwf_init_CTA(m_sid, start_thread, num_threads, start_pc); - for (unsigned i = start_thread; i<end_thread; i++) - m_thread[i].m_in_scheduler = true; - } - for (unsigned tid=start_thread;tid<end_thread;tid++) { - m_thread[tid].m_avail4fetch = true; - } -} - -// register id for unused register slot in instruction -#define DNA (0) - -unsigned g_next_shader_inst_uid=1; - -bool shader_core_ctx::fetch_stalled() -{ - for (unsigned i=0; i<m_config->warp_size; i++) { - if (m_pipeline_reg[TS_IF][i].hw_thread_id != -1 ) { - return true; // stalled - } } - for (unsigned i=0; i<m_config->warp_size; i++) { - if (m_pipeline_reg[IF_ID][i].hw_thread_id != -1 ) { - return true; // stalled - } - } - - m_new_warp_TS = true; - return false; // not stalled } // initalize the pipeline stage register to nops void shader_core_ctx::clear_stage_reg(int stage) { - clear_stage( m_pipeline_reg[stage] ); + m_pipeline_reg[stage]->clear(); } // return the next pc of a thread @@ -577,186 +482,6 @@ address_type shader_core_ctx::next_pc( int tid ) const return the_thread->get_pc(); // PC should already be updatd to next PC at this point (was set in shader_decode() last time thread ran) } -// issue thread to the warp -// tid - thread id, warp_id - used by PDOM, wlane - position in warp -void shader_core_ctx::shader_issue_thread(int tid, int wlane, unsigned active_mask ) -{ - m_thread[tid].m_functional_model_thread_state->ptx_fetch_inst( m_pipeline_reg[TS_IF][wlane] ); - m_pipeline_reg[TS_IF][wlane].hw_thread_id = tid; - m_pipeline_reg[TS_IF][wlane].wlane = wlane; - m_pipeline_reg[TS_IF][wlane].memreqaddr = 0; - m_pipeline_reg[TS_IF][wlane].uid = g_next_shader_inst_uid++; - m_pipeline_reg[TS_IF][wlane].warp_active_mask = active_mask; - m_pipeline_reg[TS_IF][wlane].issue_cycle = gpu_tot_sim_cycle + gpu_sim_cycle; - - assert( m_thread[tid].m_avail4fetch ); - m_thread[tid].m_avail4fetch = false; - assert( m_warp[wid_from_hw_tid(tid,m_config->warp_size)].get_avail4fetch() > 0 ); - m_warp[wid_from_hw_tid(tid,m_config->warp_size)].dec_avail4fetch(); -} - -int shader_core_ctx::pdom_sched_find_next_warp (int ready_warp_count) -{ - bool found = false; - int selected_warp = m_ready_warps[0]; - switch (m_config->pdom_sched_type) { - case 0: selected_warp = m_ready_warps[0]; found=true; break; // first ok warp found - case 1: selected_warp = m_ready_warps[rand()%ready_warp_count]; found=true; break; //random - case 8: - // "loose" round robin: - // execute the next available warp which is after the warp execued last time - selected_warp = (m_last_warp + 1) % m_config->max_warps_per_shader; - while (!found) { - for (int i=0;i<ready_warp_count;i++) { - if (selected_warp==m_ready_warps[i]) - found=true; - } - if( !found ) - selected_warp = (selected_warp + 1) % m_config->max_warps_per_shader; - } - break; - default: assert(0); - } - if (found) { - if (ready_warp_count==1) - m_stats->n_pdom_sc_single_stat++; - else - m_stats->n_pdom_sc_orig_stat++; - return selected_warp; - } else { - return -1; - } -} - -void shader_core_ctx::fetch_simd_postdominator() -{ - int warp_ok = 0; - bool complete = false; - int tmp_warp; - int warp_id; - - address_type check_pc = -1; - - // First, check to see if entire program is completed, - // if it is, then break out of loop - for (unsigned i=0; i<m_config->n_thread_per_shader; i++) { - if (!ptx_thread_done(i)) { - complete = false; - break; - } else { - complete = true; - } - } - if (complete) - return; - - if (fetch_stalled()) - return; - clear_stage_reg(TS_IF); - - unsigned ready_warp_count = 0; - for (unsigned i=0; i<m_config->max_warps_per_shader; i++) { - m_ready_warps[i]=-1; - m_tmp_ready_warps[i]=-1; - } - - // Finds a warp where all threads in it are available for fetching - // simultaneously(all threads are not yet in pipeline, or, the ones - // that are not available, are completed already - for (unsigned i=0; i<m_config->max_warps_per_shader; i++) { - if( m_warp[m_next_warp].waiting() ) { - // waiting for kernel launch, barrier, membar, atomic - } else if( (m_warp[m_next_warp].get_n_completed()+m_warp[m_next_warp].get_avail4fetch()) < m_config->warp_size) { - // waiting for instruction still in pipeline barrel processing - } else if ( !warp_scoreboard_hazard(m_next_warp) ) { - // this warp is ready and can be issued if selected - m_tmp_ready_warps[ready_warp_count] = m_next_warp; - ready_warp_count++; - } - m_next_warp = (m_next_warp + 1) % m_config->max_warps_per_shader; - } - for (unsigned i=0;i<ready_warp_count;i++) - m_ready_warps[i]=m_tmp_ready_warps[i]; - m_stats->num_warps_issuable[ready_warp_count]++; - m_stats->num_warps_issuable_pershader[m_sid]+= ready_warp_count; - if (ready_warp_count) { - tmp_warp = pdom_sched_find_next_warp (ready_warp_count); - if (tmp_warp != -1) { - m_next_warp = tmp_warp; - warp_ok=1; - } - } - - if (!warp_ok) { - // None of the instructions from inside the warp can be scheduled -> should - // probably just stall, ie nops into pipeline - clear_stage_reg(TS_IF); - m_next_warp = (m_next_warp+1) % m_config->max_warps_per_shader; - return; - } - - /************************************************************/ - // at this point we have a warp to execute which is pointed to by next_warp - - warp_id = m_next_warp; - m_last_warp = warp_id; - int wtid = m_config->warp_size*warp_id; - pdom_warp_ctx_t *scheduled_warp = m_pdom_warp[warp_id]; - - // schedule threads according to active mask on the top of pdom stack - unsigned active_mask = scheduled_warp->get_active_mask(); - - for (unsigned i = 0; i < m_config->warp_size; i++) { - unsigned int mask = (1 << i); - if ((active_mask & mask) == mask) { - assert (!ptx_thread_done(wtid+i)); - shader_issue_thread(wtid+i,i,active_mask); - } - } - m_next_warp = (m_next_warp+1)%m_config->max_warps_per_shader; - - // check if all issued threads have the same pc - for (unsigned i = 0; i < m_config->warp_size; i++) { - if ( m_pipeline_reg[TS_IF][i].hw_thread_id != -1 ) { - if ( check_pc == (unsigned)-1 ) { - check_pc = m_pipeline_reg[TS_IF][i].pc; - } else { - assert( check_pc == m_pipeline_reg[TS_IF][i].pc ); - } - } - } -} - -/** - * check if warp has data hazard - * - * @param warp_id - * - * @return bool : false if hazard exists - */ -bool shader_core_ctx::warp_scoreboard_hazard(int warp_id) -{ - inst_t active_inst; - - // Get an active thread in the warp - int wtid = m_config->warp_size*warp_id; - pdom_warp_ctx_t *scheduled_warp = m_pdom_warp[warp_id]; - thread_ctx_t *active_thread = NULL; - unsigned active_mask = scheduled_warp->get_active_mask(); - for (unsigned i = 0; i < m_config->warp_size; i++) { - unsigned int mask = (1 << i); - if ((active_mask & mask) == mask) { - active_thread = &(m_thread[wtid+i]); - } - } - if(active_thread == NULL) - return false; - - // Decode instruction - active_thread->m_functional_model_thread_state->ptx_fetch_inst( active_inst ); - return m_scoreboard->checkCollision(warp_id, &active_inst); -} - void pdom_warp_ctx_t::pdom_update_warp_mask() { int wtid = m_warp_size*m_warp_id; @@ -892,213 +617,6 @@ void shader_core_ctx::new_cache_window() m_L1C->shd_cache_new_window(); } -void shader_core_ctx::fetch_mimd() -{ - if (fetch_stalled()) - return; - clear_stage_reg(TS_IF); - - for (unsigned i=0, j=0;i<m_config->n_thread_per_shader && j< m_config->warp_size;i++) { - int thd_id = (i + m_last_issued_thread + 1) % m_config->n_thread_per_shader; - if (m_thread[thd_id].m_avail4fetch && !m_thread[thd_id].m_waiting_at_barrier ) { - shader_issue_thread(thd_id, j,(unsigned)-1); - m_last_issued_thread = thd_id; - j++; - } - } -} - -// seperate the incoming warp into multiple warps with seperate pcs -int shader_core_ctx::split_warp_by_pc(int *tid_in, int **tid_split, address_type *pc) -{ - unsigned n_pc = 0; - static int *pc_cnt = NULL; // count the number of threads with the same pc - - assert(tid_in); - assert(tid_split); - assert(pc); - memset(pc,0,sizeof(address_type)*m_config->warp_size); - - if (!pc_cnt) pc_cnt = (int*) malloc(sizeof(int)*m_config->warp_size); - memset(pc_cnt,0,sizeof(int)*m_config->warp_size); - - // go through each thread in the given warp - for (unsigned i=0; i< m_config->warp_size; i++) { - if (tid_in[i] < 0) continue; - int matched = 0; - address_type thd_pc; - thd_pc = next_pc(tid_in[i]); - - // check to see if the pc has occured before - for (unsigned j=0; j<n_pc; j++) { - if (thd_pc == pc[j]) { - tid_split[j][pc_cnt[j]] = tid_in[i]; - pc_cnt[j]++; - matched = 1; - break; - } - } - // if not, put the tid in a seperate warp - if (!matched) { - assert(n_pc < m_config->warp_size); - tid_split[n_pc][0] = tid_in[i]; - pc[n_pc] = thd_pc; - pc_cnt[n_pc] = 1; - n_pc++; - } - } - return n_pc; -} - -// see if this warp just executed the barrier instruction -int shader_core_ctx::warp_reached_barrier(int *tid_in) -{ - int reached_barrier = 0; - for (unsigned i=0; i<m_config->warp_size; i++) { - if (tid_in[i] < 0) continue; - if (m_thread[tid_in[i]].m_reached_barrier) { - reached_barrier = 1; - break; - } - } - return reached_barrier; -} - -// seperate the incoming warp into multiple warps with seperate pcs and cta -int shader_core_ctx::split_warp_by_cta(int *tid_in, int **tid_split, address_type *pc, int *cta) -{ - unsigned n_pc = 0; - static int *pc_cnt = NULL; // count the number of threads with the same pc - - assert(tid_in); - assert(tid_split); - assert(pc); - memset(pc,0,sizeof(address_type)*m_config->warp_size); - - if (!pc_cnt) pc_cnt = (int*) malloc(sizeof(int)*m_config->warp_size); - memset(pc_cnt,0,sizeof(int)*m_config->warp_size); - - // go through each thread in the given warp - for (unsigned i=0; i<m_config->warp_size; i++) { - if (tid_in[i] < 0) continue; - int matched = 0; - address_type thd_pc; - thd_pc = next_pc(tid_in[i]); - - int thd_cta = ptx_thread_get_cta_uid( m_thread[tid_in[i]].m_functional_model_thread_state ); - - // check to see if the pc has occured before - for (unsigned j=0; j<n_pc; j++) { - if (thd_pc == pc[j] && thd_cta == cta[j]) { - tid_split[j][pc_cnt[j]] = tid_in[i]; - pc_cnt[j]++; - matched = 1; - break; - } - } - // if not, put the tid in a seperate warp - if (!matched) { - assert(n_pc < m_config->warp_size); - tid_split[n_pc][0] = tid_in[i]; - pc[n_pc] = thd_pc; - cta[n_pc] = thd_cta; - pc_cnt[n_pc] = 1; - n_pc++; - } - } - return n_pc; -} - -void shader_core_ctx::fetch_simd_dwf() -{ - static int *tid_in = NULL; - static int *tid_out = NULL; - - if (!tid_in) { - tid_in = (int*) malloc(sizeof(int)*m_config->warp_size); - memset(tid_in, -1, sizeof(int)*m_config->warp_size); - } - if (!tid_out) { - tid_out = (int*) malloc(sizeof(int)*m_config->warp_size); - memset(tid_out, -1, sizeof(int)*m_config->warp_size); - } - - - static int **tid_split = NULL; - if (!tid_split) { - tid_split = (int**)malloc(sizeof(int*)*m_config->warp_size); - tid_split[0] = (int*)malloc(sizeof(int)*m_config->warp_size*m_config->warp_size); - for (unsigned i=1; i<m_config->warp_size; i++) { - tid_split[i] = tid_split[0] + m_config->warp_size * i; - } - } - - static address_type *thd_pc = NULL; - if (!thd_pc) thd_pc = (address_type*)malloc(sizeof(address_type)*m_config->warp_size); - static int *thd_cta = NULL; - if (!thd_cta) thd_cta = (int*)malloc(sizeof(int)*m_config->warp_size); - - int warpupdate_bw = 1; - while (!m_thd_commit_queue->empty() && warpupdate_bw > 0) { - // grab a committed warp, split it into multiple BRUs (tid_split) by PC - std::vector<int> *tid_commit = m_thd_commit_queue->pop(gpu_sim_cycle); - memset(tid_split[0], -1, sizeof(int)*m_config->warp_size*m_config->warp_size); - memset(thd_pc, 0, sizeof(address_type)*m_config->warp_size); - memset(thd_cta, -1, sizeof(int)*m_config->warp_size); - - int reached_barrier = warp_reached_barrier(tid_commit->data()); - - unsigned n_warp_update; - if (reached_barrier) { - n_warp_update = split_warp_by_cta(tid_commit->data(), tid_split, thd_pc, thd_cta); - } else { - n_warp_update = split_warp_by_pc(tid_commit->data(), tid_split, thd_pc); - } - - if (n_warp_update > 2) m_stats->gpgpu_commit_pc_beyond_two++; - warpupdate_bw -= n_warp_update; - // put the splitted warp updates into the DWF scheduler - for (unsigned i=0;i<n_warp_update;i++) { - for (unsigned j=0;j<m_config->warp_size;j++) { - if (tid_split[i][j] < 0) continue; - assert(m_thread[tid_split[i][j]].m_avail4fetch); - assert(!m_thread[tid_split[i][j]].m_in_scheduler); - m_thread[tid_split[i][j]].m_in_scheduler = true; - } - dwf_clear_accessed(m_sid); - if (reached_barrier) { - dwf_update_warp_at_barrier(m_sid, tid_split[i], thd_pc[i], thd_cta[i]); - } else { - dwf_update_warp(m_sid, tid_split[i], thd_pc[i]); - } - } - - delete tid_commit; - } - - // Track the #PC right after the warps are input to the scheduler - dwf_update_statistics(m_sid); - dwf_clear_policy_access(m_sid); - - if (fetch_stalled()) { - return; - } - clear_stage_reg(TS_IF); - - address_type scheduled_pc; - dwf_issue_warp(m_sid, tid_out, &scheduled_pc); - - for (unsigned i=0; i<m_config->warp_size; i++) { - int issue_tid = tid_out[i]; - if (issue_tid >= 0) { - shader_issue_thread(issue_tid, i, (unsigned)-1); - m_thread[issue_tid].m_in_scheduler = false; - m_thread[issue_tid].m_reached_barrier = false; - assert(m_pipeline_reg[TS_IF][i].pc == scheduled_pc); - } - } -} - void gpgpu_sim::print_shader_cycle_distro( FILE *fout ) const { fprintf(fout, "Warp Occupancy Distribution:\n"); @@ -1120,11 +638,11 @@ void shader_core_ctx::fetch_new() if( m_inst_fetch_buffer.m_valid ) { // decode 1 or 2 instructions and place them into ibuffer address_type pc = m_inst_fetch_buffer.m_pc; - const inst_t* pI1 = ptx_fetch_inst(pc); + const warp_inst_t* pI1 = ptx_fetch_inst(pc); assert(pI1); m_warp[m_inst_fetch_buffer.m_warp_id].ibuffer_fill(0,pI1); m_warp[m_inst_fetch_buffer.m_warp_id].inc_inst_in_pipeline(); - const inst_t* pI2 = ptx_fetch_inst(pc+pI1->isize); + const warp_inst_t* pI2 = ptx_fetch_inst(pc+pI1->isize); if( pI2 ) { m_warp[m_inst_fetch_buffer.m_warp_id].ibuffer_fill(1,pI2); m_warp[m_inst_fetch_buffer.m_warp_id].inc_inst_in_pipeline(); @@ -1207,60 +725,38 @@ int is_local ( memory_space_t space ) } -void shader_core_ctx::ptx_exec_inst( inst_t &inst ) +void shader_core_ctx::func_exec_inst( warp_inst_t &inst ) { - m_thread[inst.hw_thread_id].m_functional_model_thread_state->ptx_exec_inst(inst); - if( inst.callback.function != NULL ) - m_warp[inst.hw_thread_id/m_config->warp_size].inc_n_atomic(); - if (is_local(inst.space.get_type()) && (is_load(inst) || is_store(inst))) - inst.memreqaddr = translate_local_memaddr(inst.memreqaddr, inst.hw_thread_id, m_gpu->num_shader()); -} - -void shader_core_ctx::issue_warp( const inst_t *pI, unsigned active_mask, inst_t *&warp, unsigned warp_id ) -{ - m_warp[warp_id].ibuffer_free(); - assert(pI->valid()); - unsigned cta_id = (unsigned)-1; for ( unsigned t=0; t < m_config->warp_size; t++ ) { - unsigned tid=m_config->warp_size*warp_id+t; - warp[t] = *pI; - warp[t].warp_active_mask = active_mask; - if( active_mask & (1<<t) ) { - cta_id = m_thread[tid].m_cta_id; - warp[t].hw_thread_id = tid; - warp[t].wlane = t; - warp[t].uid = g_next_shader_inst_uid++; - warp[t].issue_cycle = gpu_tot_sim_cycle + gpu_sim_cycle; - ptx_exec_inst( warp[t] ); + if( inst.active(t) ) { + unsigned tid=m_config->warp_size*inst.warp_id()+t; + m_thread[tid].m_functional_model_thread_state->ptx_exec_inst(inst,t); + if( inst.has_callback(t) ) + m_warp[inst.warp_id()].inc_n_atomic(); + if (is_local(inst.space.get_type()) && (is_load(inst) || is_store(inst))) + inst.set_addr(t, translate_local_memaddr(inst.get_addr(t), tid, m_gpu->num_shader()) ); if ( ptx_thread_done(tid) ) { - m_warp[warp_id].inc_n_completed(); - m_warp[warp_id].ibuffer_flush(); + m_warp[inst.warp_id()].inc_n_completed(); + m_warp[inst.warp_id()].ibuffer_flush(); } } } - assert( cta_id != (unsigned)-1 ); - if( pI->op == BARRIER_OP ) - set_at_barrier(cta_id,warp_id); - else if( pI->op == MEMORY_BARRIER_OP ) +} + +void shader_core_ctx::issue_warp( warp_inst_t *&pipe_reg, const warp_inst_t *next_inst, unsigned active_mask, unsigned warp_id ) +{ + m_warp[warp_id].ibuffer_free(); + assert(next_inst->valid()); + *pipe_reg = *next_inst; // static instruction information + pipe_reg->issue( active_mask, warp_id, gpu_tot_sim_cycle + gpu_sim_cycle ); // dynamic instruction information + func_exec_inst( *pipe_reg ); + if( next_inst->op == BARRIER_OP ) + set_at_barrier(m_warp[warp_id].get_cta_id(),warp_id); + else if( next_inst->op == MEMORY_BARRIER_OP ) set_at_memory_barrier(warp_id); m_pdom_warp[warp_id]->pdom_update_warp_mask(); - m_scoreboard->reserveRegisters(warp_id, pI); - m_warp[warp_id].set_next_pc(pI->pc + pI->isize); - - ///// - memset(m_fetch_tid_out, -1, sizeof(int)*m_config->warp_size); - int n_thd_in_warp = 0; - for (unsigned i=0; i<m_config->warp_size; i++) { - m_fetch_tid_out[i] = warp[i].hw_thread_id; - if (m_fetch_tid_out[i] >= 0) - n_thd_in_warp += 1; - } - - m_new_warp_TS = false; - - // warp tracker keeps track of warps in the pipeline, let it know we are going to issue this warp - assert( n_thd_in_warp > 0 ); - m_warp_tracker->wpt_register_warp(m_fetch_tid_out, pI->pc, n_thd_in_warp,m_config->warp_size); + m_scoreboard->reserveRegisters(warp_id, next_inst); + m_warp[warp_id].set_next_pc(next_inst->pc + next_inst->isize); } void shader_core_ctx::decode_new() @@ -1271,7 +767,7 @@ void shader_core_ctx::decode_new() unsigned issued=0; while( !m_warp[warp_id].waiting() && !m_warp[warp_id].ibuffer_empty() && (checked < 2) && (issued < 2) ) { unsigned active_mask = m_pdom_warp[warp_id]->get_active_mask(); - const inst_t *pI = m_warp[warp_id].ibuffer_next(); + const warp_inst_t *pI = m_warp[warp_id].ibuffer_next(); unsigned pc,rpc; m_pdom_warp[warp_id]->get_pdom_stack_top_info(&pc,&rpc); if( pI ) { @@ -1281,11 +777,11 @@ void shader_core_ctx::decode_new() m_warp[warp_id].ibuffer_flush(); } else if ( !m_scoreboard->checkCollision(warp_id, pI) ) { assert( m_warp[warp_id].inst_in_pipeline() ); - if ( (pI->op != SFU_OP) && pipeline_regster_empty(m_pipeline_reg[ID_OC]) ) { - issue_warp(pI, active_mask, m_pipeline_reg[ID_OC], warp_id); + if ( (pI->op != SFU_OP) && m_pipeline_reg[ID_OC]->empty() ) { + issue_warp(m_pipeline_reg[ID_OC],pI,active_mask,warp_id); issued++; - } else if ( (pI->op == SFU_OP || pI->op == ALU_SFU_OP) && pipeline_regster_empty(m_pipeline_reg[ID_OC_SFU]) ) { - issue_warp(pI, active_mask, m_pipeline_reg[ID_OC_SFU], warp_id); + } else if ( (pI->op == SFU_OP || pI->op == ALU_SFU_OP) && m_pipeline_reg[ID_OC_SFU]->empty() ) { + issue_warp(m_pipeline_reg[ID_OC_SFU],pI,active_mask,warp_id); issued++; } } @@ -1300,92 +796,6 @@ void shader_core_ctx::decode_new() } } -void shader_core_ctx::fetch() -{ - // check if decode stage is stalled - bool decode_stalled = !pipeline_regster_empty( m_pipeline_reg[IF_ID] ); - - // find a ready warp and put it in the TS_IF pipeline register - switch (m_config->model) { - case POST_DOMINATOR: fetch_simd_postdominator(); break; - case DWF: fetch_simd_dwf(); break; - case MIMD: fetch_mimd(); break; - default: fprintf(stderr, "Unknown scheduler: %d\n", m_config->model); assert(0); break; - } - - memset(m_fetch_tid_out, -1, sizeof(int)*m_config->warp_size); - - if (m_config->gpgpu_no_divg_load && m_new_warp_TS && !decode_stalled) { - - // count number of active threads in this warp, determine PC value - // record active threads in tid_out - int n_thd_in_warp = 0; - address_type pc_out = 0xDEADBEEF; - for (unsigned i=0; i<m_config->warp_size; i++) { - m_fetch_tid_out[i] = m_pipeline_reg[TS_IF][i].hw_thread_id; - if (m_fetch_tid_out[i] >= 0) { - n_thd_in_warp += 1; - pc_out = m_pipeline_reg[TS_IF][i].pc; - } - } - - m_new_warp_TS = false; - - // warp tracker keeps track of warps in the pipeline, let it know we are going to issue this warp - if( n_thd_in_warp > 0 ) - m_warp_tracker->wpt_register_warp(m_fetch_tid_out, pc_out, n_thd_in_warp,m_config->warp_size); - - // some statistics collection - if (gpu_runtime_stat_flag & GPU_RSTAT_DWF_MAP) - m_thread_pc_tracker->set_threads_pc( m_fetch_tid_out, pc_out ); - if (gpgpu_cflog_interval != 0) { - insn_warp_occ_log( m_sid, pc_out, n_thd_in_warp); - shader_warp_occ_log( m_sid, n_thd_in_warp); - } - if ( m_config->gpgpu_warpdistro_shader < 0 || m_sid == (unsigned)m_config->gpgpu_warpdistro_shader ) { - m_stats->shader_cycle_distro[n_thd_in_warp + 2] += 1; - if (n_thd_in_warp == 0) - if (m_pending_mem_access == 0) - m_stats->shader_cycle_distro[1]++; - } - } else { - if ( m_config->gpgpu_warpdistro_shader < 0 || m_sid == (unsigned)m_config->gpgpu_warpdistro_shader ) { - m_stats->shader_cycle_distro[0] += 1; - } - } - - if (!decode_stalled) { - for (unsigned i = 0; i < m_config->warp_size; i++) { - int tid_tsif = m_pipeline_reg[TS_IF][i].hw_thread_id; - address_type pc_out = m_pipeline_reg[TS_IF][i].pc; - cflog_update_thread_pc(m_sid, tid_tsif, pc_out); - } - } - - if (enable_ptx_file_line_stats && !decode_stalled) { - int TS_stage_empty = 1; - for (unsigned i = 0; i < m_config->warp_size; i++) { - if (m_pipeline_reg[TS_IF][i].hw_thread_id >= 0) { - TS_stage_empty = 0; - break; - } - } - if (TS_stage_empty) { - if (enable_ptx_file_line_stats) - ptx_file_line_stats_commit_exposed_latency(m_sid, 1); - } - } - - // if not, send the warp part to decode stage - if (!decode_stalled) { - check_stage_pcs(TS_IF); - inst_t *fvi = first_valid_thread(m_pipeline_reg[TS_IF]); - if( fvi ) - m_warp[fvi->hw_thread_id/m_config->warp_size].set_last_fetch(gpu_sim_cycle); - move_warp(m_pipeline_reg[IF_ID],m_pipeline_reg[TS_IF]); - } -} - address_type coalesced_segment(address_type addr, unsigned segment_size_lg2bytes) { return (addr >> segment_size_lg2bytes); @@ -1419,232 +829,16 @@ address_type shader_core_ctx::translate_local_memaddr(address_type localaddr, in ///////////////////////////////////////////////////////////////////////////////////////// -void shader_core_ctx::decode() -{ - op_type op = NO_OP; - unsigned warp_id = -1; - unsigned cta_id = -1; - - address_type regs_regs_PC = 0xDEADBEEF; - address_type warp_current_pc = 0x600DBEEF; - address_type warp_next_pc = 0x600DBEEF; - int warp_diverging = 0; - const int nextstage = (m_config->gpgpu_operand_collector) ? ID_OC : \ - (m_config->m_using_dwf_rrstage ? ID_RR : ID_EX); - - if( !pipeline_regster_empty(m_pipeline_reg[nextstage]) ) - return; - - check_stage_pcs(IF_ID); - - // decode the instruction - int first_valid_thread = -1; - for (unsigned i=0; i<m_config->warp_size;i++) { - if (m_pipeline_reg[IF_ID][i].hw_thread_id == -1 ) - continue; /* bubble or masked off */ - if (first_valid_thread == -1) { - first_valid_thread = i; - op = m_pipeline_reg[IF_ID][i].op; - int tid = m_pipeline_reg[IF_ID][i].hw_thread_id; - warp_id = tid/m_config->warp_size; - assert( !warp_waiting_at_barrier(warp_id) ); - cta_id = m_thread[tid].m_cta_id; - } - } - - // execute the instruction functionally - short last_hw_thread_id = -1; - bool first_thread_in_warp = true; - for (unsigned i=0; i<m_config->warp_size;i++) { - if (m_pipeline_reg[IF_ID][i].hw_thread_id == -1 ) - continue; /* bubble or masked off */ - - if(last_hw_thread_id > -1) - first_thread_in_warp = false; - last_hw_thread_id = m_pipeline_reg[IF_ID][i].hw_thread_id; - - /* get the next instruction to execute from fetch stage */ - int tid = m_pipeline_reg[IF_ID][i].hw_thread_id; - - // Functionally execute instruction - m_thread[tid].m_functional_model_thread_state->ptx_exec_inst( m_pipeline_reg[IF_ID][i] ); - if( m_pipeline_reg[IF_ID][i].callback.function != NULL ) - m_warp[warp_id].inc_n_atomic(); - if (is_local(m_pipeline_reg[IF_ID][i].space) && (is_load(m_pipeline_reg[IF_ID][i]) || is_store(m_pipeline_reg[IF_ID][i]))) - m_pipeline_reg[IF_ID][i].memreqaddr = translate_local_memaddr(m_pipeline_reg[IF_ID][i].memreqaddr, tid, m_gpu->num_shader()); - - // Mark destination registers as write-pending in scoreboard - // Only do this for the first thread in warp - if(first_thread_in_warp) - m_scoreboard->reserveRegisters(warp_id, &(m_pipeline_reg[IF_ID][i])); - warp_current_pc = m_pipeline_reg[IF_ID][i].pc; - regs_regs_PC = next_pc( tid ); - - if ( ptx_thread_at_barrier( m_thread[tid].m_functional_model_thread_state ) ) { - if (m_config->model == DWF) { - m_thread[tid].m_waiting_at_barrier=true; - m_thread[tid].m_reached_barrier=true; // not reset at barrier release, but at the issue after that - m_warp[wid_from_hw_tid(tid,m_config->warp_size)].inc_waiting_at_barrier(); - int cta_uid = ptx_thread_get_cta_uid( m_thread[tid].m_functional_model_thread_state ); - dwf_hit_barrier( m_sid, cta_uid ); - - int release = ptx_thread_all_at_barrier( m_thread[tid].m_functional_model_thread_state ); //test if all threads arrived at the barrier - if ( release ) { //All threads arrived at barrier...releasing - int cta_uid = ptx_thread_get_cta_uid( m_thread[tid].m_functional_model_thread_state ); - for ( unsigned t=0; t < m_config->n_thread_per_shader; ++t ) { - if ( !ptx_thread_at_barrier( m_thread[t].m_functional_model_thread_state ) ) - continue; - int other_cta_uid = ptx_thread_get_cta_uid( m_thread[t].m_functional_model_thread_state ); - if ( other_cta_uid == cta_uid ) { //reseting @barrier tracking info - m_warp[wid_from_hw_tid(t,m_config->warp_size)].clear_waiting_at_barrier(); - m_thread[t].m_waiting_at_barrier=false; - ptx_thread_reset_barrier( m_thread[t].m_functional_model_thread_state ); - } - } - if (m_config->model == DWF) { - dwf_release_barrier( m_sid, cta_uid ); - } - ptx_thread_release_barrier( m_thread[tid].m_functional_model_thread_state ); - } - } - } else { - assert( !m_thread[tid].m_waiting_at_barrier ); - } - - // branch divergence detection - if (warp_next_pc != regs_regs_PC) { - if (warp_next_pc == 0x600DBEEF) { - warp_next_pc = regs_regs_PC; - } else { - warp_diverging = 1; - } - } - } - - move_warp(m_pipeline_reg[nextstage],m_pipeline_reg[IF_ID]); - - if( op == BARRIER_OP ) - set_at_barrier(cta_id,warp_id); - else if( op == MEMORY_BARRIER_OP ) - set_at_memory_barrier(warp_id); - - m_n_diverge += warp_diverging; - if (warp_diverging == 1) { - assert(warp_current_pc != 0x600DBEEF); // guard against empty warp causing warp divergence - ptx_file_line_stats_add_warp_divergence(warp_current_pc, 1); - } -} - -unsigned int n_regconflict_stall = 0; - - -int regfile_hash(signed thread_number, unsigned simd_size, unsigned n_banks) { - if (gpgpu_thread_swizzling) { - signed warp_ID = thread_number / simd_size; - return((thread_number + warp_ID) % n_banks); - } else { - return(thread_number % n_banks); - } -} - -void shader_core_ctx::preexecute() -{ - if( m_config->gpgpu_dwf_reg_bankconflict) { - // Model register bank conflicts as in - // Fung et al. MICRO'07 / ACM TACO'09 papers. - // - // This models conflicts due to moving threads to different SIMD lanes - // (which occur if not using "lane aware" dynamic warp formation). - - inst_t *fvi = first_valid_thread(m_pipeline_reg[RR_EX]); - if( fvi ) { - if (m_dwf_RR_k) { - //stalled due to register access conflict, but can still service a register read - m_dwf_RR_k--; - return; - } - - int n_access_per_cycle = m_config->warp_size / m_config->gpgpu_dwf_rr_stage_n_reg_banks; - int max_reg_bank_acc = 0; - for (unsigned i=0; i<m_config->gpgpu_dwf_rr_stage_n_reg_banks; i++) - m_dwf_rrstage_bank_access_counter[i] = 0; - for (unsigned i=0; i<m_config->warp_size; i++) { - if (m_pipeline_reg[ID_RR][i].hw_thread_id != -1 ) - m_dwf_rrstage_bank_access_counter[regfile_hash(m_pipeline_reg[ID_RR][i].hw_thread_id, - m_config->warp_size, - m_config->gpgpu_dwf_rr_stage_n_reg_banks)]++; - } - for (unsigned i=0; i<m_config->gpgpu_dwf_rr_stage_n_reg_banks; i++) { - if (m_dwf_rrstage_bank_access_counter[i] > max_reg_bank_acc ) - max_reg_bank_acc = m_dwf_rrstage_bank_access_counter[i]; - } - // calculate the number of cycles needed for each register bank to fulfill all accesses - m_dwf_RR_k = (max_reg_bank_acc / n_access_per_cycle) + ((max_reg_bank_acc % n_access_per_cycle)? 1 : 0); - - // if there is more than one access cycle needed at a bank, stall - if (m_dwf_RR_k > 1) { - n_regconflict_stall++; - m_dwf_RR_k--; - return; - } - } - - check_stage_pcs(ID_RR); - m_dwf_RR_k = 0; - } - - if( pipeline_regster_empty(m_pipeline_reg[ID_EX]) ) - move_warp(m_pipeline_reg[ID_EX],m_pipeline_reg[ID_RR]); -} - - void shader_core_ctx::execute_pipe( unsigned pipeline, unsigned next_stage ) { - if (m_config->gpgpu_pre_mem_stages) { - if( !pipeline_regster_empty(pre_mem_pipeline[0]) ) - return; // stalled - } else { - if( !pipeline_regster_empty(m_pipeline_reg[next_stage]) ) - return; // stalled - } - - check_stage_pcs(ID_EX); - - // Check that all threads have the same delay cycles - unsigned cycles = -1; - for (unsigned i=0; i<m_config->warp_size; i++) { - if (m_pipeline_reg[pipeline][i].hw_thread_id == -1 ) - continue; // bubble - if(cycles == (unsigned)-1) - cycles = m_pipeline_reg[pipeline][i].cycles; - else { - if( cycles != m_pipeline_reg[pipeline][i].cycles ) { - printf("Shader %d: threads do not have the same delay cycles.\n", m_sid); - assert(0); - } - } - } - - bool stall_inst_not_done = false; - for (unsigned i=0; i<m_config->warp_size; i++) { - if (m_pipeline_reg[pipeline][i].hw_thread_id == -1 ) - continue; - m_pipeline_reg[pipeline][i].cycles--; - if( m_pipeline_reg[pipeline][i].cycles > 0 ) { - // Stall here to model instruction throughput for different types of instructions - stall_inst_not_done=true; - continue; - } - } - if( stall_inst_not_done ) - return; - if (m_config->gpgpu_pre_mem_stages) { - move_warp(pre_mem_pipeline[0], m_pipeline_reg[pipeline]); - } else { - move_warp(m_pipeline_reg[next_stage],m_pipeline_reg[pipeline]); - // inform memory stage that a new instruction has arrived - m_shader_memory_new_instruction_processed = false; - } + if( !m_pipeline_reg[next_stage]->empty() ) + return; + if( m_pipeline_reg[pipeline]->cycles ) { + m_pipeline_reg[pipeline]->cycles--; + return; + } + move_warp(m_pipeline_reg[next_stage],m_pipeline_reg[pipeline]); + m_shader_memory_new_instruction_processed = false; } void shader_core_ctx::execute() @@ -1653,32 +847,15 @@ void shader_core_ctx::execute() execute_pipe(ID_EX, EX_MM); } -void shader_core_ctx::pre_memory() -{ - // This stage can be used to approximately model a deeper pipeline. - // The main effect this models is the register read-after-write delay. - // We walk through pre-memory stages in reverse order - // (highest number = stage closest to writeback, 0 = stage closest to fetch - if( pipeline_regster_empty(m_pipeline_reg[EX_MM]) ) { - move_warp( m_pipeline_reg[EX_MM], pre_mem_pipeline[m_config->gpgpu_pre_mem_stages] ); - // inform memory stage that a new instruction has arrived - m_shader_memory_new_instruction_processed = false; - } - for (unsigned j = m_config->gpgpu_pre_mem_stages; j > 0; j--) { - if( pipeline_regster_empty(pre_mem_pipeline[j]) ) - move_warp( pre_mem_pipeline[j], pre_mem_pipeline[j-1]); - } -} - -mshr_entry* mshr_shader_unit::add_mshr(mem_access_t &access, inst_t* warp) +mshr_entry* mshr_shader_unit::add_mshr(mem_access_t &access, warp_inst_t* warp) { - //creates an mshr based on the access struct information + // creates an mshr based on the access struct information mshr_entry* mshr = alloc_free_mshr(access.space == tex_space); - mshr->init(access.addr,access.iswrite,access.space,warp->hw_thread_id/m_shader_config->warp_size); + mshr->init(access.addr,access.iswrite,access.space,warp->warp_id()); assert(access.warp_indices.size()); //code assumes at least one instruction attached to mshr. for (unsigned i = 0; i < access.warp_indices.size(); i++) mshr->add_inst(warp[access.warp_indices[i]]); - if (m_shader_config->gpgpu_interwarp_mshr_merge) { + if( m_shader_config->gpgpu_interwarp_mshr_merge ) { mshr_entry* mergehit = m_mshr_lookup.shader_get_mergeable_mshr(mshr); if (mergehit) { mergehit->merge(mshr); @@ -1732,7 +909,7 @@ void shader_core_ctx::get_memory_access_list( bool limit_broadcast, std::vector<mem_access_t> &accessq ) { - const inst_t* insns = m_pipeline_reg[EX_MM]; + const warp_inst_t* insns = m_pipeline_reg[EX_MM]; // Calculates memory accesses generated by this warp // Returns acesses which are "coalesced" // Does not coalesce nor overlap bank accesses across warp "parts". @@ -1768,28 +945,23 @@ void shader_core_ctx::get_memory_access_list( unsigned mem_pipe_size = m_config->warp_size / warp_parts; for (unsigned part = 0; part < m_config->warp_size; part += mem_pipe_size) { for (unsigned i = part; i < part + mem_pipe_size; i++) { - if ( insns[i].hw_thread_id == -1 ) + if ( !insns->active(i) ) continue; - - if( insns[i].space == undefined_space ) { - // Instruction must have been predicated off - continue; - } - - address_type lane_segment_address = tag_func(insns[i].memreqaddr, line_size); + if( insns->space == undefined_space ) + continue; // this happens when thread predicated off + new_addr_type addr = insns->get_addr(i); + address_type lane_segment_address = tag_func(addr, line_size); unsigned quarter = 0; if( line_size>=4 ) - quarter = (insns[i].memreqaddr / (line_size/4)) & 3; - bool isatomic = (insns[i].callback.function != NULL); + quarter = (addr / (line_size/4)) & 3; bool match = false; - if (not isatomic) { //atomics must have own request + if( !insns->isatomic() ) { //atomics must have own request for (unsigned j = qpartbegin; j < accessq.size(); j++) { if (lane_segment_address == accessq[j].addr) { assert( not accessq[j].isatomic ); accessq[j].quarter_count[quarter]++; accessq[j].warp_indices.push_back(i); - if (limit_broadcast) - // two threads access this address, so its a broadcast. + if (limit_broadcast) // two threads access this address, so its a broadcast. accessq[j].order = ++broadcast_order; //do broadcast in its own cycle. match = true; break; @@ -1797,15 +969,15 @@ void shader_core_ctx::get_memory_access_list( } } if (!match) { // does not match an previous request by another thread, so need a new request - assert( insns[i].space != undefined_space ); + assert( insns->space != undefined_space ); accessq.push_back( mem_access_t( lane_segment_address, - insns[i].space, + insns->space, mem_pipe, - isatomic, - is_store(insns[i]), + insns->isatomic(), + is_store(*insns), line_size, quarter, i) ); // Determine Bank Conflicts: - unsigned bank = (this->*bank_func)(insns[i].memreqaddr, line_size); + unsigned bank = (this->*bank_func)(insns->get_addr(i), line_size); // ensure no concurrent bank access accross warp parts. // ie. order will be less than part for all previous loads in previous parts, so: if (bank_accs[bank] < part) @@ -1820,7 +992,6 @@ void shader_core_ctx::get_memory_access_list( std::stable_sort(accessq.begin()+qbegin,accessq.end()); } - void shader_core_ctx::memory_shared_process_warp() { // initial processing of shared memory warps @@ -1835,31 +1006,31 @@ void shader_core_ctx::memory_shared_process_warp() void shader_core_ctx::memory_const_process_warp() { - // initial processing of const memory warps - std::vector<mem_access_t> &accessq = m_memory_queue.constant; - unsigned qbegin = accessq.size(); - get_memory_access_list( - &shader_core_ctx::null_bank_func, - line_size_based_tag_func, - CONSTANT_MEM_PATH, - 1, //warp parts - m_L1C->get_line_sz(), false, //no broadcast limit. - accessq); - //do cache checks here for each request (non-physical), could be done later for more accurate timing of cache accesses, but probably uneccesary; - for (unsigned i = qbegin; i < accessq.size(); i++) { - if ( accessq[i].space == param_space_kernel ) { - accessq[i].cache_hit = true; - } else { - cache_request_status status = m_L1C->access( accessq[i].addr, - 0, //should always be a read - gpu_sim_cycle+gpu_tot_sim_cycle, - NULL/*should never writeback*/); - accessq[i].cache_hit = (status == HIT); - if (m_config->gpgpu_perfect_mem) accessq[i].cache_hit = true; - if (accessq[i].cache_hit) m_stats->L1_const_miss++; - } - accessq[i].cache_checked = true; - } + // initial processing of const memory warps + std::vector<mem_access_t> &accessq = m_memory_queue.constant; + unsigned qbegin = accessq.size(); + get_memory_access_list( &shader_core_ctx::null_bank_func, + line_size_based_tag_func, + CONSTANT_MEM_PATH, + 1, //warp parts + m_L1C->get_line_sz(), false, //no broadcast limit. + accessq); + // do cache checks here for each request (non-physical), could be + // done later for more accurate timing of cache accesses, but probably uneccesary; + for (unsigned i = qbegin; i < accessq.size(); i++) { + if ( accessq[i].space == param_space_kernel ) { + accessq[i].cache_hit = true; + } else { + cache_request_status status = m_L1C->access( accessq[i].addr, + 0, //should always be a read + gpu_sim_cycle+gpu_tot_sim_cycle, + NULL/*should never writeback*/); + accessq[i].cache_hit = (status == HIT); + if (m_config->gpgpu_perfect_mem) accessq[i].cache_hit = true; + if (accessq[i].cache_hit) m_stats->L1_const_miss++; + } + accessq[i].cache_checked = true; + } } void shader_core_ctx::memory_texture_process_warp() @@ -1874,7 +1045,8 @@ void shader_core_ctx::memory_texture_process_warp() m_L1T->get_line_sz(), false, //no broadcast limit. accessq); - //do cache checks here for each request (non-hardware), could be done later for more accurate timing of cache accesses, but probably uneccesary; + // do cache checks here for each request (non-hardware), could be done later + // for more accurate timing of cache accesses, but probably uneccesary; for (unsigned i = qbegin; i < accessq.size(); i++) { cache_request_status status = m_L1T->access( accessq[i].addr, 0, //should always be a read @@ -1896,7 +1068,7 @@ void shader_core_ctx::memory_global_process_warp() if (m_config->gpgpu_coalesce_arch == 13) { warp_parts = 2; if(m_config->gpgpu_no_dl1) { - unsigned data_size = first_valid_thread( m_pipeline_reg[EX_MM] )->data_size; + unsigned data_size = m_pipeline_reg[EX_MM]->data_size; // line size is dependant on instruction; switch (data_size) { case 1: line_size = 32; break; @@ -1940,15 +1112,11 @@ void shader_core_ctx::memory_global_process_warp() } } } - - mem_stage_stall_type shader_core_ctx::send_mem_request(mem_access_t &access) { - //Atempt to send an request/write to memory based on information in access. - - inst_t* warp = m_pipeline_reg[EX_MM]; - inst_t* req_head = warp + access.warp_indices[0]; + // Attempt to send an request/write to memory based on information in access. + warp_inst_t* warp = m_pipeline_reg[EX_MM]; // If the cache told us it needed to write back a dirty line, do this now // It is possible to do this writeback in the same cycle as the access request, this may not be realistic. @@ -1976,7 +1144,7 @@ mem_stage_stall_type shader_core_ctx::send_mem_request(mem_access_t &access) default: assert(0); break; } //reserve mshr - bool requires_mshr = (m_config->model != MIMD) and (not access.iswrite); + bool requires_mshr = (not access.iswrite); if (requires_mshr and not access.reserved_mshr) { if (not m_mshr_unit->has_mshr(1)) return MSHR_RC_FAIL; @@ -2001,46 +1169,34 @@ mem_stage_stall_type shader_core_ctx::send_mem_request(mem_access_t &access) } //send over interconnect partial_write_mask_t write_mask = NO_PARTIAL_WRITE; - unsigned warp_id = req_head->hw_thread_id/m_config->warp_size; + unsigned warp_id = warp->warp_id(); if (access.iswrite) { if (!strcmp("GT200",m_config->pipeline_model) ) m_warp[warp_id].inc_store_req(); for (unsigned i=0;i < access.warp_indices.size();i++) { unsigned w = access.warp_indices[i]; - int data_offset = warp[w].memreqaddr & ((unsigned long long int)access.req_size - 1); - for (unsigned b = data_offset; b < data_offset + warp[w].data_size; b++) write_mask.set(b); + int data_offset = warp->get_addr(w) & ((unsigned long long int)access.req_size - 1); + for (unsigned b = data_offset; b < data_offset + warp->data_size; b++) write_mask.set(b); } if (write_mask.count() != access.req_size) m_stats->gpgpu_n_partial_writes++; } fq_push( access.addr, request_size, access.iswrite, write_mask, warp_id , access.reserved_mshr, - access_type, req_head->pc); - } - - // book keeping for mshr : this request is done (sent/accounted for) - if (requires_mshr) { - for (unsigned i = 0; i < access.warp_indices.size(); i++) { - unsigned o = access.warp_indices[i]; - m_pending_mem_access++; - if (enable_ptx_file_line_stats) - ptx_file_line_stats_add_inflight_memory_insn(m_sid, warp[o].pc); - } - - // Scoreboard addition: do not make cache miss instructions wait for memory, - // let the scoreboard handle stalling of instructions. - // Mark thread as a cache miss - if (not access.iswrite) { - // set the pipeline instructions in this request to noops, they all wait for memory; - for (unsigned i = 0; i < access.warp_indices.size(); i++) { - unsigned o = access.warp_indices[i]; - m_pipeline_reg[EX_MM][o].cache_miss = true; - } - } + access_type, warp->pc ); } return NO_RC_FAIL; } +void shader_core_ctx::writeback() +{ + mshr_entry *m = m_mshr_unit->return_head(); + if( m ) + m_mshr_unit->pop_return_head(); + if( !m_pipeline_reg[MM_WB]->empty() ) + m_scoreboard->releaseRegisters( m_pipeline_reg[MM_WB] ); + move_warp(m_pipeline_reg[WB_RT],m_pipeline_reg[MM_WB]); +} bool shader_core_ctx::memory_shared_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type) { @@ -2184,8 +1340,7 @@ mem_stage_stall_type shader_core_ctx::dcache_check(mem_access_t& access) if (access.isatomic) { if (m_config->gpgpu_perfect_mem) { // complete functional execution of atomic here - dram_callback_t &atom_exec = m_pipeline_reg[EX_MM][access.warp_indices[0]].callback; - atom_exec.function(atom_exec.instruction, atom_exec.thread); + m_pipeline_reg[EX_MM]->do_atomic(); } else { // atomics always go to memory access.cache_hit = false; @@ -2224,11 +1379,10 @@ void shader_core_ctx::memory_queue() // Called once per warp when warp enters memory stage. // Generates a list of memory accesses, but does not perform the memory access. - if( pipeline_regster_empty(m_pipeline_reg[EX_MM]) ) + if( m_pipeline_reg[EX_MM]->empty() ) return; m_gpu->mem_instruction_stats(m_pipeline_reg[EX_MM]); - inst_t *inst = first_valid_thread(m_pipeline_reg[EX_MM]); - switch (inst->space.get_type()) { + switch( m_pipeline_reg[EX_MM]->space.get_type() ) { case shared_space: memory_shared_process_warp(); break; case tex_space: memory_texture_process_warp(); break; case const_space: case param_space_kernel: memory_const_process_warp(); break; @@ -2258,9 +1412,8 @@ void shader_core_ctx::memory() m_stats->gpu_stall_shd_mem_breakdown[type][rc_fail]++; return; } - if( not pipeline_regster_empty( m_pipeline_reg[MM_WB] ) ) + if( not m_pipeline_reg[MM_WB]->empty() ) return; // writeback stalled - check_stage_pcs(EX_MM); move_warp(m_pipeline_reg[MM_WB],m_pipeline_reg[EX_MM]); } @@ -2281,292 +1434,6 @@ void shader_core_ctx::register_cta_thread_exit(int tid ) } } -void obtain_insn_latency_info(insn_latency_info *latinfo, const inst_t *insn) -{ - latinfo->pc = insn->pc; - latinfo->latency = gpu_tot_sim_cycle + gpu_sim_cycle - insn->issue_cycle; -} - -int debug_tid = 0; - -void shader_core_ctx::writeback() -{ - std::vector<inst_t> done_insts; - std::vector<insn_latency_info> unlock_lat_infos; - bool w2rf = false; - memset(m_pl_tid,-1, sizeof(int)*m_config->warp_size); - check_stage_pcs(MM_WB); - - // detect if a valid instruction is in MM_WB - for (unsigned i=0; i<m_config->warp_size; i++) { - w2rf |= (m_pipeline_reg[MM_WB][i].hw_thread_id >= 0); - m_pl_tid[i] = m_pipeline_reg[MM_WB][i].hw_thread_id; - } - - //check mshrs for commit; - unsigned mshr_threads_unlocked = 0; - bool stalled_by_MSHR = false; - - mshr_entry *mshr_head = m_mshr_unit->return_head(); - if (mshr_head && (mshr_threads_unlocked + mshr_head->num_inst() <= m_config->warp_size) ) { - assert (mshr_head->num_inst()); - for (unsigned j = 0; j < mshr_head->num_inst(); j++) { - const inst_t &insn = mshr_head->get_inst(j); - time_vector_update(insn.uid,MR_WRITEBACK,gpu_sim_cycle+gpu_tot_sim_cycle,RD_REQ); - obtain_insn_latency_info(&m_mshr_lat_info[mshr_threads_unlocked], &insn); - if (enable_ptx_file_line_stats) - ptx_file_line_stats_sub_inflight_memory_insn(m_sid, insn.pc); - assert (insn.hw_thread_id >= 0); - m_pending_mem_access--; - mshr_threads_unlocked++; - if (m_config->gpgpu_operand_collector) { - if ( j== 0 ) - m_operand_collector.writeback(insn); - } else - stalled_by_MSHR = true; - } - mshr_head->get_insts(done_insts); - - m_mshr_unit->pop_return_head(); - unlock_lat_infos.resize(mshr_threads_unlocked); - std::copy(m_mshr_lat_info, m_mshr_lat_info + mshr_threads_unlocked, unlock_lat_infos.begin()); - assert(mshr_threads_unlocked); - } - - if ( m_config->gpgpu_operand_collector ) - stalled_by_MSHR = !m_operand_collector.writeback( m_pipeline_reg[MM_WB] ); - - if (!stalled_by_MSHR) { - inst_t inst; - for (unsigned i=0; i<m_config->warp_size; i++) { - op_type op; - if (m_pipeline_reg[MM_WB][i].hw_thread_id > -1) - op = m_pipeline_reg[MM_WB][i].op; - obtain_insn_latency_info(&m_pl_lat_info[i], &m_pipeline_reg[MM_WB][i]); - if (!m_pipeline_reg[MM_WB][i].cache_miss) { // Do not include cache misses for a writeback - if (m_pipeline_reg[MM_WB][i].hw_thread_id > -1) { - done_insts.push_back(m_pipeline_reg[MM_WB][i]); - unlock_lat_infos.push_back(m_pl_lat_info[i]); - } - } - if (m_pl_tid[i] > -1 ) - inst = m_pipeline_reg[MM_WB][i]; - } - - // Unlock the warp for re-fetching (put it in the fixed delay queue) - if (w2rf) // Only need to unlock if this is a valid instruction - queue_warp_unlocking(m_pl_tid, inst); - } else - m_stats->gpu_stall_by_MSHRwb++; - - for (unsigned i=0; i<done_insts.size(); i++) { - inst_t done_inst = done_insts[i]; - call_thread_done(done_inst); - - gpu_sim_insn++; // a (scalar) instruction is done - if ( !is_const(done_inst.space) ) - m_stats->gpu_sim_insn_no_ld_const++; - m_gpu->gpu_sim_insn_last_update = gpu_sim_cycle; - m_gpu->gpu_sim_insn_last_update_sid = m_sid; - m_num_sim_insn++; - m_thread[done_inst.hw_thread_id].n_insn++; - m_thread[done_inst.hw_thread_id].n_insn_ac++; - - if (enable_ptx_file_line_stats) { - unsigned pc = unlock_lat_infos[i].pc; - unsigned long latency = unlock_lat_infos[i].latency; - ptx_file_line_stats_add_latency(pc, latency); - } - } - - if (!stalled_by_MSHR) { - if (!strcmp("GT200",m_config->pipeline_model) ) { - inst_t *fvt=first_valid_thread(m_pipeline_reg[MM_WB]); - if( fvt ) { - unsigned warp_id = fvt->hw_thread_id/m_config->warp_size; - m_warp[warp_id].dec_inst_in_pipeline(); - } - } - move_warp(m_pipeline_reg[WB_RT], m_pipeline_reg[MM_WB]); - } - - process_delay_queue(); -} - -/* - * Queues a warp into fixed delay queue for unlocking - * - * The amount of delay to add is determined by the instruction type. - * - * @param *tid Array of tid in the warp to unlock - * @param space Address space for the current instruction in the warp - * - */ -void shader_core_ctx::queue_warp_unlocking(int *tids, const inst_t &inst ) -{ - // Create a delay queue object and add it to the queue - fixeddelay_queue_warp_t fixeddelay_queue_warp; - - // Set ready_cycle based on instruction space - fixeddelay_queue_warp.inst = inst; - switch(inst.space.get_type()) { - case shared_space: - fixeddelay_queue_warp.ready_cycle = gpu_tot_sim_cycle + gpu_sim_cycle + 5; // Adds 5*4=20 cycles - break; - default: - fixeddelay_queue_warp.ready_cycle = gpu_tot_sim_cycle + gpu_sim_cycle; - break; - } - - // Store threads in delay queue warp object - fixeddelay_queue_warp.tids.resize(m_config->warp_size); - std::copy(tids, tids+m_config->warp_size, fixeddelay_queue_warp.tids.begin()); - m_fixeddelay_queue.insert(fixeddelay_queue_warp); -} - -/* - * Process a delay queue by unlocking warps ready this cycle - * - * @param *shader Pointer to shader core - * - */ -void shader_core_ctx::process_delay_queue() { - shader_core_ctx *shader=this; - // Unlock warps in fixeddelay_queue_warp - std::multiset<fixeddelay_queue_warp_t, fixeddelay_queue_warp_comp>::iterator it; - std::multiset<fixeddelay_queue_warp_t, fixeddelay_queue_warp_comp>::iterator it_last; - for ( it=shader->m_fixeddelay_queue.begin() ; - it != shader->m_fixeddelay_queue.end(); - ) { - if(it->ready_cycle <= gpu_tot_sim_cycle + gpu_sim_cycle) { - if(!m_config->gpgpu_stall_on_use) { - // This disables stall-on-use - // If thread is still in warp_tracker, do not unlock yet - bool skip_unlock = false; - for(unsigned i=0; i<m_config->warp_size; i++) { - int tid = it->tids[i]; - if(tid < 0) continue; - if(m_warp_tracker->wpt_thread_in_wpt(tid)) { - skip_unlock = true; - break; - } - } - if(skip_unlock) { - it_last = it++; - continue; - } - } - - if (!strcmp("GT200",m_config->pipeline_model) ) { - if( it->inst.space == shared_space ) { - for(unsigned i=0; i < m_config->warp_size; i++ ) { - if( it->tids[i]>= 0 ) { - unsigned warp_id = it->tids[i]/m_config->warp_size; - m_scoreboard->releaseRegisters(warp_id,&it->inst); - break; - } - } - } - } - - // Unlock warp - unlock_warp(it->tids); - - // Remove warp information from delay queue - it_last = it++; - shader->m_fixeddelay_queue.erase(it_last); - } else { - break; - } - } -} - -/* - * Unlock a warp - * - * @param tids Vector of tid in the warp to unlock - * - */ -void shader_core_ctx::unlock_warp( std::vector<int> tids ) -{ - assert( tids.size() == m_config->warp_size ); // required by thd_commit_queue usage in fetch_simd_dwf() - int thd_unlocked = 0; - int thd_exited = 0; - int tid; - int valid_tid = -1; - - if (!strcmp("GPGPUSIM_ORIG",m_config->pipeline_model) ) { - // Unlock - for (unsigned i=0; i<m_config->warp_size; i++) { - tid = tids[i]; - if (tid >= 0) { - valid_tid = tid; - // thread completed if it is going to fetching beyond code boundary - if ( ptx_thread_done(tid) ) { - m_not_completed -= 1; - m_stats->gpu_completed_thread += 1; - int warp_id = wid_from_hw_tid(tid,m_config->warp_size); - if (!(m_warp[warp_id].get_n_completed() < m_config->warp_size)) - printf("GPGPU-Sim uArch: shader[%d]->warp[%d].n_completed = %d; warp_size = %d\n", - m_sid,warp_id, m_warp[warp_id].get_n_completed(), m_config->warp_size); - assert( m_warp[warp_id].get_n_completed() < m_config->warp_size ); - m_warp[warp_id].inc_n_completed(); - register_cta_thread_exit( tid ); - thd_exited = 1; - } else { - if (!strcmp("GPGPUSIM_ORIG",m_config->pipeline_model) ) { - assert(!m_thread[tid].m_avail4fetch); - m_thread[tid].m_avail4fetch=true; - assert( m_warp[tid/m_config->warp_size].get_avail4fetch() < m_config->warp_size ); - m_warp[tid/m_config->warp_size].inc_avail4fetch(); - } - thd_unlocked = 1; - } - } - } - } - - if (!strcmp("GPGPUSIM_ORIG",m_config->pipeline_model) ) { - if(thd_unlocked || thd_exited) { - // Update the warp active mask - m_pdom_warp[wid_from_hw_tid(valid_tid,m_config->warp_size)]->pdom_update_warp_mask(); - } - } - - if (m_config->model == POST_DOMINATOR) { - // Do nothing - } else { - // For this case, submit to commit_queue - if (m_config->using_commit_queue && thd_unlocked) - m_thd_commit_queue->push( new std::vector<int>(tids), gpu_sim_cycle ); - } -} - - -/* - * Signals to the warp_tracker that a thread in a warp (for a given pc/instruction) is done - * - * @param *shd Pointer to shader core - * @param done_inst Completed instruction - * - */ -void shader_core_ctx::call_thread_done( inst_t &done_inst ) -{ - if (m_config->gpgpu_no_divg_load) { - // Signal to unlock the thread. If all threads are done, deregister warp - if( m_warp_tracker->wpt_signal_avail(done_inst.hw_thread_id, done_inst.pc) == 1 ) { - // Entire warp has returned - // Deregister warp - m_warp_tracker->wpt_deregister_warp(done_inst.hw_thread_id, done_inst.pc); - - if (! (!strcmp("GT200",m_config->pipeline_model) && (done_inst.space == shared_space)) ) - // Signal scoreboard to release register - m_scoreboard->releaseRegisters( wid_from_hw_tid(done_inst.hw_thread_id, m_config->warp_size), &done_inst ); - } - } -} - - void gpgpu_sim::shader_print_runtime_stat( FILE *fout ) { fprintf(fout, "SHD_INSN: "); @@ -2641,118 +1508,35 @@ void gpgpu_sim::shader_print_l1_miss_stat( FILE *fout ) fprintf(fout, "\n"); } -void shader_core_ctx::print_warp( inst_t *warp, FILE *fout, int print_mem, int mask ) const +void shader_core_ctx::print_warp( warp_inst_t *warp, FILE *fout, int print_mem, int mask ) const { - unsigned i, j, warp_id = (unsigned)-1; - for (i=0; i<m_config->warp_size; i++) { - if (warp[i].hw_thread_id > -1) { - warp_id = warp[i].hw_thread_id / m_config->warp_size; - break; - } - } - i = (i>=m_config->warp_size)? 0 : i; - - if( warp[i].pc != (address_type)-1 ) - fprintf(fout,"0x%04x ", warp[i].pc ); - else - fprintf(fout,"bubble " ); - - if( mask & 2 ) { - fprintf(fout, "(" ); - for (j=0; j<m_config->warp_size; j++) - fprintf(fout, "%03d ", warp[j].hw_thread_id); - fprintf(fout, "): "); - } else { - fprintf(fout, "w%02d[", warp_id); - for (j=0; j<m_config->warp_size; j++) - fprintf(fout, "%c", ((warp[j].hw_thread_id != -1)?'1':'0') ); - fprintf(fout, "]: "); - } - - if( warp_id != (unsigned)-1 && m_config->model == POST_DOMINATOR ) { - unsigned rp = m_pdom_warp[warp_id]->get_rp(); - if( rp == (unsigned)-1 ) { - fprintf(fout," rp:--- "); - } else { - fprintf(fout," rp:0x%03x ", rp ); - } - } - - ptx_print_insn( warp[i].pc, fout ); - - if( mask & 0x10 ) { - if ( (warp[i].op == STORE_OP || - warp[i].op == LOAD_OP) && print_mem ) - fprintf(fout, " mem: 0x%016llx", warp[i].memreqaddr); - } - fprintf(fout, "\n"); + if ( warp->empty() ) { + fprintf(fout,"bubble\n" ); + return; + } else + fprintf(fout,"0x%04x ", warp->pc ); + unsigned warp_id = warp->warp_id(); + fprintf(fout, "w%02d[", warp_id); + for (unsigned j=0; j<m_config->warp_size; j++) + fprintf(fout, "%c", (warp->active(j)?'1':'0') ); + fprintf(fout, "]: "); + if ( m_config->model == POST_DOMINATOR ) { + unsigned rp = m_pdom_warp[warp_id]->get_rp(); + if ( rp == (unsigned)-1 ) { + fprintf(fout," rp:--- "); + } else { + fprintf(fout," rp:0x%03x ", rp ); + } + } + ptx_print_insn( warp->pc, fout ); + fprintf(fout, "\n"); } void shader_core_ctx::print_stage(unsigned int stage, FILE *fout, int print_mem, int mask ) { - inst_t *warp = m_pipeline_reg[stage]; - print_warp(warp,fout,print_mem,mask); + print_warp(m_pipeline_reg[stage],fout,print_mem,mask); } -void shader_core_ctx::print_pre_mem_stages( FILE *fout, int print_mem, int mask ) -{ - unsigned i, j; - int warp_id; - - if (!m_config->gpgpu_pre_mem_stages) return; - - for (unsigned pms = 0; pms <= m_config->gpgpu_pre_mem_stages; pms++) { - fprintf(fout, "PM[%01d] = ", pms); - - warp_id = -1; - - for (i=0; i<m_config->warp_size; i++) { - if (pre_mem_pipeline[pms][i].hw_thread_id > -1) { - warp_id = pre_mem_pipeline[pms][i].hw_thread_id / m_config->warp_size; - break; - } - } - i = (i>=m_config->warp_size)? 0 : i; - - if( pre_mem_pipeline[pms][i].pc != (address_type)-1 ) - fprintf(fout,"0x%04x ", pre_mem_pipeline[pms][i].pc ); - else - fprintf(fout,"bubble " ); - - if( mask & 2 ) { - fprintf(fout, "(" ); - for (j=0; j<m_config->warp_size; j++) - fprintf(fout, "%03d ", pre_mem_pipeline[pms][j].hw_thread_id); - fprintf(fout, "): "); - } else { - fprintf(fout, "w%02d[", warp_id); - for (j=0; j<m_config->warp_size; j++) - fprintf(fout, "%c", ((pre_mem_pipeline[pms][j].hw_thread_id != -1)?'1':'0') ); - fprintf(fout, "]: "); - } - - if( warp_id != -1 && m_config->model == POST_DOMINATOR ) { - unsigned rp = m_pdom_warp[warp_id]->get_rp(); - if( rp == (unsigned)-1 ) { - fprintf(fout," rp:--- "); - } else { - fprintf(fout," rp:0x%03x ", rp ); - } - } - - ptx_print_insn( pre_mem_pipeline[pms][i].pc, fout ); - - if( mask & 0x10 ) { - if ( ( pre_mem_pipeline[pms][i].op == LOAD_OP || - pre_mem_pipeline[pms][i].op == STORE_OP ) && print_mem ) - fprintf(fout, " mem: 0x%016llx", pre_mem_pipeline[pms][i].memreqaddr); - } - fprintf(fout, "\n"); - } -} - -const char * ptx_get_fname( unsigned PC ); - void shader_core_ctx::display_pdom_state(FILE *fout, int mask ) { if ( (mask & 4) && m_config->model == POST_DOMINATOR ) { @@ -2765,7 +1549,7 @@ void shader_core_ctx::display_pdom_state(FILE *fout, int mask ) int done = ptx_thread_done(tid); nactive += (ptx_thread_done(tid)?0:1); if ( done && (mask & 8) ) { - unsigned done_cycle = ptx_thread_donecycle( m_thread[tid].m_functional_model_thread_state ); + unsigned done_cycle = m_thread[tid].m_functional_model_thread_state->donecycle(); if ( done_cycle ) { printf("\n w%02u:t%03u: done @ cycle %u", i, tid, done_cycle ); } @@ -2787,9 +1571,6 @@ void shader_core_ctx::display_pipeline(FILE *fout, int print_mem, int mask ) gpu_tot_sim_cycle, gpu_sim_cycle, m_not_completed); fprintf(fout, "=================================================\n"); - if (!strcmp("GPGPUSIM_ORIG",m_config->pipeline_model) ) - display_pdom_state(fout,mask); - if (!strcmp("GT200",m_config->pipeline_model) ) { dump_istream_state(fout); fprintf(fout,"\n"); @@ -2829,24 +1610,14 @@ void shader_core_ctx::display_pipeline(FILE *fout, int print_mem, int mask ) print_stage(ID_OC_SFU, fout, print_mem, mask); m_operand_collector.dump(fout); } - if (m_config->m_using_dwf_rrstage) { - fprintf(fout, "ID/RR = "); - print_stage(ID_RR, fout, print_mem, mask); - } if (!strcmp("GT200",m_config->pipeline_model) ) fprintf(fout, "ID/EX (SP) = "); - else - fprintf(fout, "ID/EX = "); print_stage(ID_EX, fout, print_mem, mask); if (!strcmp("GT200",m_config->pipeline_model) ) { fprintf(fout, "ID/EX (SFU) = "); print_stage(OC_EX_SFU, fout, print_mem, mask); } - print_pre_mem_stages(fout, print_mem, mask); - if (!m_config->gpgpu_pre_mem_stages) - fprintf(fout, "EX/MEM = "); - else - fprintf(fout, "PM/MEM = "); + fprintf(fout, "EX/MEM = "); print_stage(EX_MM, fout, print_mem, mask); fprintf(fout, "MEM/WB = "); print_stage(MM_WB, fout, print_mem, mask); @@ -2905,7 +1676,7 @@ unsigned int shader_core_ctx::max_cta( class function_info *kernel ) void shader_core_ctx::cycle_gt200() { - clear_stage(m_pipeline_reg[WB_RT]); + m_pipeline_reg[WB_RT]->clear(); writeback(); memory(); execute(); @@ -2914,23 +1685,6 @@ void shader_core_ctx::cycle_gt200() fetch_new(); } -void shader_core_ctx::cycle() -{ - clear_stage(m_pipeline_reg[WB_RT]); - writeback(); - memory(); - if (m_config->gpgpu_pre_mem_stages) // for modeling deeper pipelines - pre_memory(); - execute(); - if (m_config->m_using_dwf_rrstage) { - preexecute(); - } - if (m_config->gpgpu_operand_collector) - m_operand_collector.step(m_pipeline_reg[ID_OC]); - decode(); - fetch(); -} - // Flushes all content of the cache to memory void shader_core_ctx::cache_flush() @@ -3052,7 +1806,6 @@ std::list<opndcoll_rfu_t::op_t> opndcoll_rfu_t::arbiter_t::allocate_reads() return result; } - barrier_set_t::barrier_set_t( unsigned max_warps_per_core, unsigned max_cta_per_core ) { m_max_warps_per_core = max_warps_per_core; @@ -3244,15 +1997,13 @@ bool shd_warp_t::waiting() void shd_warp_t::print( FILE *fout ) const { if ( n_completed < m_warp_size ) { - fprintf( fout, "w%02u npc: 0x%04x, done:%2u a4f:%2u, i:%u s:%u a:%u b:%2u, (done: ", + fprintf( fout, "w%02u npc: 0x%04x, done:%2u i:%u s:%u a:%u (done: ", m_warp_id, m_next_pc, n_completed, - n_avail4fetch, m_inst_in_pipeline, m_stores_outstanding, - m_n_atomic, - n_waiting_at_barrier ); + m_n_atomic ); for (unsigned i = m_warp_id*m_warp_size; i < (m_warp_id+1)*m_warp_size; i++ ) { if ( m_shader->ptx_thread_done(i) ) fprintf(fout,"1"); else fprintf(fout,"0"); @@ -3360,12 +2111,6 @@ void mshr_entry::print(FILE *fp, unsigned mask) const if ( m_mf ) ptx_print_insn( m_mf->get_pc(), fp ); fprintf(fp,"\n"); - if ( mask & 0x200 ) { - for (unsigned i = 0; i < m_insts.size(); i++) { - fprintf(fp,"\tthread: UID:%d HW:%d ReqAddr:0x%llx\n", - m_insts[i].uid, m_insts[i].hw_thread_id, m_insts[i].memreqaddr); - } - } } } @@ -3373,8 +2118,8 @@ void opndcoll_rfu_t::init( unsigned num_collectors_alu, unsigned num_collectors_sfu, unsigned num_banks, shader_core_ctx *shader, - inst_t **alu_port, - inst_t **sfu_port ) + warp_inst_t **alu_port, + warp_inst_t **sfu_port ) { m_num_collectors = num_collectors_alu+num_collectors_sfu; @@ -3409,36 +2154,26 @@ void opndcoll_rfu_t::init( unsigned num_collectors_alu, } } -bool opndcoll_rfu_t::writeback( inst_t *warp ) -{ - // prefer not to stall writeback - inst_t *fvt=m_shader->first_valid_thread(warp); - if (!fvt) - return true; // nothing to do - return writeback(*fvt); -} - -int register_bank(int regnum, int tid, unsigned num_banks, unsigned bank_warp_shift) +int register_bank(int regnum, int wid, unsigned num_banks, unsigned bank_warp_shift) { int bank = regnum; if (bank_warp_shift) - bank += tid >> bank_warp_shift; + bank += wid; return bank % num_banks; } -bool opndcoll_rfu_t::writeback( const inst_t &fvt ) +bool opndcoll_rfu_t::writeback( const warp_inst_t &warp ) { - int tid = fvt.hw_thread_id; - assert( tid >= 0 ); // must be a valid instruction - std::list<unsigned> regs = m_shader->get_regs_written(fvt); + assert( !warp.empty() ); + std::list<unsigned> regs = m_shader->get_regs_written(warp); std::list<unsigned>::iterator r; unsigned last_reg = -1; unsigned n=0; for( r=regs.begin(); r!=regs.end();r++,n++ ) { unsigned reg = *r; - unsigned bank = register_bank(reg,tid,m_num_banks,m_bank_warp_shift); + unsigned bank = register_bank(reg,warp.warp_id(),m_num_banks,m_bank_warp_shift); if( m_arbiter.bank_idle(bank) ) { - m_arbiter.allocate_bank_for_write(bank,op_t(&fvt,reg,m_num_banks,m_bank_warp_shift)); + m_arbiter.allocate_bank_for_write(bank,op_t(&warp,reg,m_num_banks,m_bank_warp_shift)); } else { return false; } @@ -3451,8 +2186,8 @@ void opndcoll_rfu_t::dispatch_ready_cu() { port_to_du_t::iterator p; for( p=m_dispatch_units.begin(); p!=m_dispatch_units.end(); ++p ) { - inst_t **port = p->first; - if( !m_shader->pipeline_regster_empty(*port) ) + warp_inst_t **port = p->first; + if( !(*port)->empty() ) continue; dispatch_unit_t &du = p->second; collector_unit_t *cu = du.find_ready(); @@ -3463,12 +2198,11 @@ void opndcoll_rfu_t::dispatch_ready_cu() } } -void opndcoll_rfu_t::allocate_cu( inst_t *&id_oc_reg ) +void opndcoll_rfu_t::allocate_cu( warp_inst_t *&id_oc_reg ) { - inst_t *fvi = m_shader->first_valid_thread(id_oc_reg); - if( fvi ) { - inst_t **port = NULL; - if( fvi->op == SFU_OP ) + if( !id_oc_reg->empty() ) { + warp_inst_t **port = NULL; + if( id_oc_reg->op == SFU_OP ) port = m_sfu_port; else port = m_alu_port; @@ -3489,8 +2223,8 @@ void opndcoll_rfu_t::allocate_reads() for( std::list<op_t>::iterator r=allocated.begin(); r!=allocated.end(); r++ ) { const op_t &rr = *r; unsigned reg = rr.get_reg(); - unsigned tid = rr.get_tid(); - unsigned bank = register_bank(reg,tid,m_num_banks,m_bank_warp_shift); + unsigned wid = rr.get_wid(); + unsigned bank = register_bank(reg,wid,m_num_banks,m_bank_warp_shift); m_arbiter.allocate_for_read(bank,rr); read_ops[bank] = rr; } @@ -3513,7 +2247,7 @@ void gpgpu_sim::decrement_atomic_count( unsigned sid, unsigned wid ) bool opndcoll_rfu_t::collector_unit_t::ready() const { - return (!m_free) && m_not_ready.none() && m_rfu->shader_core()->pipeline_regster_empty(*m_port); + return (!m_free) && m_not_ready.none() && (*m_port)->empty(); } void opndcoll_rfu_t::collector_unit_t::dump(FILE *fp, const shader_core_ctx *shader ) const @@ -3532,7 +2266,7 @@ void opndcoll_rfu_t::collector_unit_t::dump(FILE *fp, const shader_core_ctx *sha } void opndcoll_rfu_t::collector_unit_t::init( unsigned n, - inst_t **port, + warp_inst_t **port, unsigned num_banks, unsigned log2_warp_size, unsigned warp_size, @@ -3543,36 +2277,33 @@ void opndcoll_rfu_t::collector_unit_t::init( unsigned n, m_port=port; m_num_banks=num_banks; assert(m_warp==NULL); - m_warp = (inst_t*)calloc(sizeof(inst_t),warp_size); - m_rfu->shader_core()->clear_stage(m_warp); + m_warp = new warp_inst_t(warp_size); m_bank_warp_shift=log2_warp_size; } -void opndcoll_rfu_t::collector_unit_t::allocate( inst_t *&pipeline_reg ) +void opndcoll_rfu_t::collector_unit_t::allocate( warp_inst_t *&pipeline_reg ) { assert(m_free); assert(m_not_ready.none()); m_free = false; - inst_t *fvi = m_rfu->shader_core()->first_valid_thread(pipeline_reg); - if( fvi ) { - m_tid = fvi->hw_thread_id; - m_warp_id = m_tid/m_rfu->shader_core()->get_config()->warp_size; + if( !pipeline_reg->empty() ) { + m_warp_id = pipeline_reg->warp_id(); for( unsigned op=0; op < 4; op++ ) { - int reg_num = fvi->arch_reg[4+op]; // this math needs to match that used in function_info::ptx_decode_inst + int reg_num = pipeline_reg->arch_reg[4+op]; // this math needs to match that used in function_info::ptx_decode_inst if( reg_num >= 0 ) { // valid register m_src_op[op] = op_t( this, op, reg_num, m_num_banks, m_bank_warp_shift ); m_not_ready.set(op); } else m_src_op[op] = op_t(); } - m_rfu->shader_core()->move_warp(m_warp,pipeline_reg); + move_warp(m_warp,pipeline_reg); } } void opndcoll_rfu_t::collector_unit_t::dispatch() { assert( m_not_ready.none() ); - m_rfu->shader_core()->move_warp(*m_port,m_warp); + move_warp(*m_port,m_warp); m_free=true; for( unsigned i=0; i<MAX_REG_OPERANDS;i++) m_src_op[i].reset(); |
