diff options
Diffstat (limited to 'src/cuda-sim/ptx_sim.cc')
| -rw-r--r-- | src/cuda-sim/ptx_sim.cc | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/src/cuda-sim/ptx_sim.cc b/src/cuda-sim/ptx_sim.cc new file mode 100644 index 0000000..8ec60df --- /dev/null +++ b/src/cuda-sim/ptx_sim.cc @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2009 by Tor M. Aamodt, Ali Bakhoda, George L. Yuan, + * 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 "ptx_sim.h" +#include <string> +#include "ptx_ir.h" + +std::set<unsigned long long> g_ptx_cta_info_sm_idx_used; +unsigned long long g_ptx_cta_info_uid = 1; +extern int gpgpu_option_spread_blocks_across_cores; + +ptx_cta_info::ptx_cta_info( unsigned sm_idx ) +{ + assert( g_ptx_cta_info_sm_idx_used.find(sm_idx) == g_ptx_cta_info_sm_idx_used.end() ); + g_ptx_cta_info_sm_idx_used.insert(sm_idx); + + m_sm_idx = sm_idx; + m_uid = g_ptx_cta_info_uid++; +} + +void ptx_cta_info::add_thread( ptx_thread_info *thd ) +{ + m_threads_in_cta.insert(thd); +} + +void ptx_cta_info::add_to_barrier( ptx_thread_info *thd ) +{ + m_threads_waiting_at_barrier.insert(thd); +} + +void ptx_cta_info::release_barrier() +{ + assert( m_threads_waiting_at_barrier.size() == m_threads_in_cta.size() ); + m_threads_waiting_at_barrier.clear(); +} + +bool ptx_cta_info::all_at_barrier() const +{ + return(m_threads_waiting_at_barrier.size() == m_threads_in_cta.size()); +} + +unsigned ptx_cta_info::num_threads() const +{ + return m_threads_in_cta.size(); +} + +void ptx_cta_info::check_cta_thread_status_and_reset() +{ + bool fail = false; + if ( m_threads_that_have_exited.size() != m_threads_in_cta.size() ) { + printf("\n\n"); + printf("Execution error: Some threads still running in CTA during CTA reallocation! (1)\n"); + printf(" CTA uid = %Lu (sm_idx = %u) : %lu running out of %zu total\n", + m_uid, + m_sm_idx, + (m_threads_in_cta.size() - m_threads_that_have_exited.size()), m_threads_in_cta.size() ); + printf(" These are the threads that are still running:\n"); + std::set<ptx_thread_info*>::iterator t_iter; + for ( t_iter=m_threads_in_cta.begin(); t_iter != m_threads_in_cta.end(); ++t_iter ) { + ptx_thread_info *t = *t_iter; + if ( m_threads_that_have_exited.find(t) == m_threads_that_have_exited.end() ) { + if ( m_dangling_pointers.find(t) != m_dangling_pointers.end() ) { + printf(" <thread deleted>\n"); + } else { + printf(" [done=%c] : ", (t->is_done()?'Y':'N') ); + t->print_insn( t->get_pc(), stdout ); + printf("\n"); + } + } + } + printf("\n\n"); + fail = true; + } + assert_barrier_empty(true); + if ( fail ) { + abort(); + } + + bool fail2 = false; + std::set<ptx_thread_info*>::iterator t_iter; + for ( t_iter=m_threads_in_cta.begin(); t_iter != m_threads_in_cta.end(); ++t_iter ) { + ptx_thread_info *t = *t_iter; + if ( m_dangling_pointers.find(t) == m_dangling_pointers.end() ) { + if ( !t->is_done() ) { + if ( !fail2 ) { + printf("Execution error: Some threads still running in CTA during CTA reallocation! (2)\n"); + printf(" CTA uid = %Lu (sm_idx = %u) :\n", m_uid, m_sm_idx ); + fail2 = true; + } + printf(" "); + t->print_insn( t->get_pc(), stdout ); + printf("\n"); + } + } + } + if ( fail2 ) { + abort(); + } + m_threads_in_cta.clear(); + m_threads_that_have_exited.clear(); + m_dangling_pointers.clear(); +} + +void ptx_cta_info::assert_barrier_empty( bool called_from_delete_threads ) const +{ + if ( !m_threads_waiting_at_barrier.empty() ) { + printf( "\n\n" ); + printf( "Execution error: Some threads at barrier at %s:\n", + (called_from_delete_threads?"CTA re-init":"thread exit") ); + printf( " CTA uid = %Lu (sm_idx = %u)\n", m_uid, m_sm_idx ); + std::set<ptx_thread_info*>::iterator b; + for ( b=m_threads_waiting_at_barrier.begin(); b != m_threads_waiting_at_barrier.end(); ++b ) { + ptx_thread_info *t = *b; + if ( m_dangling_pointers.find(t) != m_dangling_pointers.end() ) { + printf(" <thread deleted>\n"); + } else { + printf(" "); + t->print_insn( t->get_pc(), stdout ); + printf("\n"); + } + } + printf("\n\n"); + abort(); + } +} + +void ptx_cta_info::register_thread_exit( ptx_thread_info *thd ) +{ + assert( m_threads_that_have_exited.find(thd) == m_threads_that_have_exited.end() ); + m_threads_that_have_exited.insert(thd); +} + +void ptx_cta_info::register_deleted_thread( ptx_thread_info *thd ) +{ + m_dangling_pointers.insert(thd); +} + +unsigned ptx_cta_info::get_sm_idx() const +{ + return m_sm_idx; +} + +unsigned g_ptx_thread_info_uid_next=1; +unsigned g_ptx_thread_info_delete_count=0; + +ptx_thread_info::~ptx_thread_info() +{ + g_ptx_thread_info_delete_count++; +} + +ptx_thread_info::ptx_thread_info() +{ + m_uid = g_ptx_thread_info_uid_next++; + m_core = NULL; + m_barrier_num = -1; + m_at_barrier = false; + m_valid = false; + m_gridid = 0; + m_thread_done = false; + m_cycle_done = 0; + m_PC=0; + m_icount = 0; + m_last_effective_address = 0; + m_last_memory_space = 0; + m_branch_taken = 0; + m_shared_mem = NULL; + m_cta_info = NULL; + m_local_mem = NULL; + m_symbol_table = NULL; + m_func_info = NULL; + m_hw_tid = -1; + m_hw_wid = -1; + m_hw_sid = -1; + m_last_dram_callback.function = NULL; + m_last_dram_callback.instruction = NULL; + m_regs.push_back( std::map<std::string,ptx_reg_t>() ); + m_debug_trace_regs_modified.push_back( std::map<std::string,ptx_reg_t>() ); + m_callstack.push_back( stack_entry() ); + m_RPC = -1; + m_RPC_updated = false; + m_last_was_call = false; +} + +extern unsigned long long gpu_sim_cycle; + +void ptx_thread_info::set_done() +{ + assert( !m_at_barrier ); + m_thread_done = true; + m_cycle_done = gpu_sim_cycle; +} + +extern unsigned long long gpu_sim_cycle; +extern signed long long gpu_tot_sim_cycle; + +unsigned ptx_thread_info::get_builtin( int builtin_id, unsigned dim_mod ) +{ + assert( m_valid ); + switch (builtin_id) { + case NTID_ID: + assert( dim_mod < 3 ); + return m_ntid[dim_mod]; + case CLOCK_ID: + return gpu_sim_cycle + gpu_tot_sim_cycle; + case CTA_ID: + assert( dim_mod < 3 ); + return m_ctaid[dim_mod]; + case GRIDID_ID: + return m_gridid; + case NCTAID_ID: + assert( dim_mod < 3 ); + return m_nctaid[dim_mod]; + case TID_ID: + assert( dim_mod < 3 ); + return m_tid[dim_mod]; + default: + assert(0); + } + return 0; +} + +void ptx_thread_info::set_info( symbol_table *symtab, function_info *func ) +{ + m_symbol_table = symtab; + m_func_info = func; + m_PC = func->get_start_PC(); +} + +void ptx_thread_info::print_insn( unsigned pc, FILE * fp ) const +{ + m_func_info->print_insn(pc,fp); +} + +static void print_reg( std::string name, ptx_reg_t value ) +{ + const symbol *sym = g_current_symbol_table->lookup(name.c_str()); + printf(" %8s ", name.c_str() ); + if( sym == NULL ) { + printf("<unknown type> 0x%llx\n", (unsigned long long ) value.u64 ); + return; + } + const type_info *t = sym->type(); + type_info_key ti = t->get_key(); + + switch ( ti.scalar_type() ) { + case S8_TYPE: printf(".s8 %d\n", value.s8 ); break; + case S16_TYPE: printf(".s16 %d\n", value.s16 ); break; + case S32_TYPE: printf(".s32 %d\n", value.s32 ); break; + case S64_TYPE: printf(".s64 %Ld\n", value.s64 ); break; + case U8_TYPE: printf(".u8 0x%02x\n", (unsigned) value.u8 ); break; + case U16_TYPE: printf(".u16 0x%04x\n", (unsigned) value.u16 ); break; + case U32_TYPE: printf(".u32 0x%08x\n", (unsigned) value.u32 ); break; + case U64_TYPE: printf(".u64 0x%llx\n", value.u64 ); break; + case F16_TYPE: printf(".f16 %f [0x%04x]\n", value.f16, (unsigned) value.u16 ); break; + case F32_TYPE: printf(".f32 %.15lf [0x%08x]\n", value.f32, value.u32 ); break; + case F64_TYPE: printf(".f64 %.15le [0x%016llx]\n", value.f64, value.u64 ); break; + case B8_TYPE: printf(".b8 0x%02x\n", (unsigned) value.u8 ); break; + case B16_TYPE: printf(".b16 0x%04x\n", (unsigned) value.u16 ); break; + case B32_TYPE: printf(".b32 0x%08x\n", (unsigned) value.u32 ); break; + case B64_TYPE: printf(".b64 0x%llx\n", (unsigned long long ) value.u64 ); break; + case PRED_TYPE: printf(".pred %u\n", (unsigned) value.pred ); break; + default: + printf( "non-scalar type\n" ); + break; + } +} + +void ptx_thread_info::callstack_push( unsigned pc, unsigned rpc, const symbol *return_var_src, const symbol *return_var_dst, unsigned call_uid ) +{ + m_RPC = -1; + m_RPC_updated = true; + m_last_was_call = true; + m_callstack.push_back( stack_entry(m_symbol_table,m_func_info,pc,rpc,return_var_src,return_var_dst,call_uid) ); + m_regs.push_back( std::map<std::string,ptx_reg_t>() ); + m_debug_trace_regs_modified.push_back( std::map<std::string,ptx_reg_t>() ); +} + +#define POST_DOMINATOR 1 /* must match definition in shader.h */ +extern int gpgpu_simd_model; +extern ptx_reg_t get_operand_value( const symbol *reg ); +extern void set_operand_value( const symbol *dst, const ptx_reg_t &data ); + +bool ptx_thread_info::callstack_pop() +{ + assert( !m_callstack.empty() ); + m_func_info = m_callstack.back().m_func_info; + m_symbol_table = m_callstack.back().m_symbol_table; + m_NPC = m_callstack.back().m_PC; + m_RPC_updated = true; + m_last_was_call = false; + m_RPC = m_callstack.back().m_RPC; + const symbol *rv_src = m_callstack.back().m_return_var_src; + const symbol *rv_dst = m_callstack.back().m_return_var_dst; + assert( !((rv_src != NULL) ^ (rv_dst != NULL)) ); + ptx_reg_t rval; + if( rv_src != NULL ) + rval = get_operand_value(rv_src); + m_callstack.pop_back(); + m_regs.pop_back(); + m_debug_trace_regs_modified.pop_back(); + if( rv_dst != NULL ) + set_operand_value(rv_dst,rval); + return m_callstack.empty(); +} + +void ptx_thread_info::dump_callstack() const +{ + std::list<stack_entry>::const_iterator c=m_callstack.begin(); + std::list<std::map<std::string,ptx_reg_t> >::const_iterator r=m_regs.begin(); + + printf("\n\n"); + printf("Call stack for thread uid = %u (sc=%u, hwtid=%u)\n", m_uid, m_hw_sid, m_hw_tid ); + while( c != m_callstack.end() && r != m_regs.end() ) { + const stack_entry &c_e = *c; + const std::map<std::string,ptx_reg_t> ®s = *r; + if( !c_e.m_valid ) { + printf(" <entry> #regs = %zu\n", regs.size() ); + } else { + printf(" %20s PC=%3u RV= (callee=\'%s\',caller=\'%s\') #regs = %zu\n", + c_e.m_func_info->get_name().c_str(), c_e.m_PC, + c_e.m_return_var_src->name().c_str(), + c_e.m_return_var_dst->name().c_str(), + regs.size() ); + } + c++; + r++; + } + if( c != m_callstack.end() || r != m_regs.end() ) { + printf(" *** mismatch in m_regs and m_callstack sizes ***\n" ); + } + printf("\n\n"); +} + +std::string ptx_thread_info::get_location() const +{ + const ptx_instruction *pI = m_func_info->get_instruction(m_PC); + char buf[1024]; + snprintf(buf,1024,"%s:%u", pI->source_file(), pI->source_line() ); + return std::string(buf); +} + +void ptx_thread_info::dump_regs() +{ + printf("Register File Contents:\n"); + std::map<std::string,ptx_reg_t>::const_iterator r; + for ( r=m_regs.back().begin(); r != m_regs.back().end(); ++r ) { + std::string name = r->first; + ptx_reg_t value = r->second; + print_reg(name,value); + + } +} + +void ptx_thread_info::dump_modifiedregs() +{ + if( m_debug_trace_regs_modified.empty() ) + return; + printf("Modified Registers:\n"); + std::map<std::string,ptx_reg_t>::const_iterator r; + for ( r=m_debug_trace_regs_modified.back().begin(); r != m_debug_trace_regs_modified.back().end(); ++r ) { + std::string name = r->first; + ptx_reg_t value = r->second; + print_reg(name,value); + } +} + +void ptx_thread_info::set_npc( const function_info *f ) +{ + m_NPC = f->get_start_PC(); + m_func_info = const_cast<function_info*>( f ); + m_symbol_table = m_func_info->get_symtab(); +} |
