diff options
Diffstat (limited to 'src/cuda-sim/cuda-sim.cc')
| -rw-r--r-- | src/cuda-sim/cuda-sim.cc | 2195 |
1 files changed, 2195 insertions, 0 deletions
diff --git a/src/cuda-sim/cuda-sim.cc b/src/cuda-sim/cuda-sim.cc new file mode 100644 index 0000000..d691a64 --- /dev/null +++ b/src/cuda-sim/cuda-sim.cc @@ -0,0 +1,2195 @@ +/* + * Copyright (c) 2009 by Tor M. Aamodt, Ali Bakhoda, Wilson W. L. Fung, + * George L. Yuan, Henry Wong, Dan O'Connor, Zev Weiss 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 "instructions.h" +#include "ptx_ir.h" +#include "ptx_sim.h" +#include <stdio.h> +#include <dirent.h> + +#include "opcodes.h" +#include "../intersim/statwraper.h" +#include "dram_callback.h" +#include <set> +#include <map> +#include "../util.h" +#include "memory.h" +#include "ptx-stats.h" + + +int gpgpu_ptx_instruction_classification=0; +void ** g_inst_classification_stat = NULL; +void ** g_inst_op_classification_stat= NULL; +int g_ptx_kernel_count = -1; // used for classification stat collection purposes +extern "C" int ptx_parse(); +extern "C" int ptx__scan_string(const char*); +extern "C" int ptx_debug; +extern "C" FILE *ptx_in; + +extern "C" const char *g_ptxinfo_filename = NULL; +extern "C" int ptxinfo_parse(); +extern "C" int ptxinfo_debug; +extern "C" FILE *ptxinfo_in; + +int g_debug_execution = 0; +int g_debug_thread_uid = 0; +addr_t g_debug_pc = 0xBEEF1518; +int g_override_embedded_ptx = false; + +const char *g_filename; +bool g_debug_ir_generation = false; +unsigned g_ptx_sim_num_insn = 0; + +extern memory_space *g_global_mem; +extern memory_space *g_param_mem; +extern memory_space *g_tex_mem; +extern memory_space *g_surf_mem; + +std::map<const struct textureReference*,const struct cudaArray*> TextureToArrayMap; // texture bindings +std::map<const struct textureReference*, const struct textureInfo*> TextureToInfoMap; +std::map<std::string, const struct textureReference*> NameToTextureMap; +unsigned int g_texcache_linesize; +int gpgpu_option_spread_blocks_across_cores = 0; +unsigned gpgpu_param_num_shaders = 0; + +void gpgpu_ptx_sim_bindNameToTexture(const char* name, const struct textureReference* texref) +{ + std::string texname(name); + NameToTextureMap[texname] = texref; +} + +const struct textureReference* gpgpu_ptx_sim_accessTextureofName(const char* name) { + std::string texname(name); + return NameToTextureMap[texname]; +} + +const char* gpgpu_ptx_sim_findNamefromTexture(const struct textureReference* texref) +{ + std::map<std::string, const struct textureReference*>::iterator itr = NameToTextureMap.begin(); + while (itr != NameToTextureMap.end()) { + if ((*itr).second == texref) { + const char *p = ((*itr).first).c_str(); + return p; + } + itr++; + } + return NULL; +} + +unsigned int intLOGB2( unsigned int v ) { + unsigned int shift; + unsigned int r; + + r = 0; + + shift = (( v & 0xFFFF0000) != 0 ) << 4; v >>= shift; r |= shift; + shift = (( v & 0xFF00 ) != 0 ) << 3; v >>= shift; r |= shift; + shift = (( v & 0xF0 ) != 0 ) << 2; v >>= shift; r |= shift; + shift = (( v & 0xC ) != 0 ) << 1; v >>= shift; r |= shift; + shift = (( v & 0x2 ) != 0 ) << 0; v >>= shift; r |= shift; + + return r; +} + +void gpgpu_ptx_sim_bindTextureToArray(const struct textureReference* texref, const struct cudaArray* array) +{ + TextureToArrayMap[texref] = array; + unsigned int texel_size_bits = array->desc.w + array->desc.x + array->desc.y + array->desc.z; + unsigned int texel_size = texel_size_bits/8; + unsigned int Tx, Ty; + int r; + + printf("GPGPU-Sim PTX: texel size = %d\n", texel_size); + printf("GPGPU-Sim PTX: texture cache linesize = %d\n", g_texcache_linesize); + //first determine base Tx size for given linesize + switch (g_texcache_linesize) { + case 16: + Tx = 4; + break; + case 32: + Tx = 8; + break; + case 64: + Tx = 8; + break; + case 128: + Tx = 16; + break; + case 256: + Tx = 16; + break; + default: + printf("GPGPU-Sim PTX: Line size of %d bytes currently not supported.\n", g_texcache_linesize); + assert(0); + break; + } + r = texel_size >> 2; + //modify base Tx size to take into account size of each texel in bytes + while (r != 0) { + Tx = Tx >> 1; + r = r >> 2; + } + //by now, got the correct Tx size, calculate correct Ty size + Ty = g_texcache_linesize/(Tx*texel_size); + + printf("GPGPU-Sim PTX: Tx = %d; Ty = %d, Tx_numbits = %d, Ty_numbits = %d\n", Tx, Ty, intLOGB2(Tx), intLOGB2(Ty)); + printf("GPGPU-Sim PTX: Texel size = %d bytes; texel_size_numbits = %d\n", texel_size, intLOGB2(texel_size)); + printf("GPGPU-Sim PTX: Binding texture to array starting at devPtr32 = 0x%x\n", array->devPtr32); + printf("GPGPU-Sim PTX: Texel size = %d bytes\n", texel_size); + struct textureInfo* texInfo = (struct textureInfo*) malloc(sizeof(struct textureInfo)); + texInfo->Tx = Tx; + texInfo->Ty = Ty; + texInfo->Tx_numbits = intLOGB2(Tx); + texInfo->Ty_numbits = intLOGB2(Ty); + texInfo->texel_size = texel_size; + texInfo->texel_size_numbits = intLOGB2(texel_size); + TextureToInfoMap[texref] = texInfo; +} + +const struct cudaArray* gpgpu_ptx_sim_accessArrayofTexture(struct textureReference* texref) { + return TextureToArrayMap[texref]; +} + +int gpgpu_ptx_sim_sizeofTexture(const char* name) +{ + std::string texname(name); + const struct textureReference* texref = NameToTextureMap[texname]; + const struct cudaArray* array = TextureToArrayMap[texref]; + return array->size; +} + +extern unsigned int warp_size; + +int g_warn_literal_operands_two_type_inst; + +std::list<operand_info> check_operands( int opcode, + const std::list<int> &scalar_type, + const std::list<operand_info> &operands ) +{ + if( (opcode == CVT_OP) || (opcode == SET_OP) || (opcode == SLCT_OP) || (opcode == TEX_OP) ) { + // just make sure these do not have have const operands... + if( !g_warn_literal_operands_two_type_inst ) { + std::list<operand_info>::const_iterator o; + for( o = operands.begin(); o != operands.end(); o++ ) { + const operand_info &op = *o; + if( op.is_literal() ) { + printf("GPGPU-Sim PTX: PTX uses two scalar type intruction with literal operand.\n"); + g_warn_literal_operands_two_type_inst = 1; + } + } + } + } else { + assert( scalar_type.size() < 2 ); + if( scalar_type.size() == 1 ) { + std::list<operand_info> result; + int inst_type = scalar_type.front(); + std::list<operand_info>::const_iterator o; + for( o = operands.begin(); o != operands.end(); o++ ) { + const operand_info &op = *o; + if( op.is_literal() ) { + if( (op.get_type() == double_op_t) && (inst_type == F32_TYPE) ) { + ptx_reg_t v = op.get_literal_value(); + float u = (float)v.f64; + operand_info n(u); + result.push_back(n); + } else { + result.push_back(op); + } + } else { + result.push_back(op); + } + } + return result; + } + } + return operands; +} + +ptx_instruction::ptx_instruction( int opcode, + const symbol *pred, + int neg_pred, + symbol *label, + const std::list<operand_info> &operands, + const operand_info &return_var, + const std::list<int> &options, + const std::list<int> &scalar_type, + int space_spec, + const char *file, + unsigned line, + const char *source ) +{ + m_uid = ++g_num_ptx_inst_uid; + m_PC = 0; + m_opcode = opcode; + m_pred = pred; + m_neg_pred = neg_pred; + m_label = label; + const std::list<operand_info> checked_operands = check_operands(opcode,scalar_type,operands); + m_operands.insert(m_operands.begin(), checked_operands.begin(), checked_operands.end() ); + m_return_var = return_var; + m_options = options; + m_wide = false; + m_hi = false; + m_lo = false; + m_uni = false; + m_rounding_mode = RN_OPTION; + m_compare_op = -1; + m_saturation_mode = 0; + m_geom_spec = 0; + m_vector_spec = 0; + m_atomic_spec = 0; + m_warp_size = ::warp_size; + m_membar_level = 0; + + std::list<int>::const_iterator i; + unsigned n=1; + for ( i=options.begin(); i!= options.end(); i++, n++ ) { + int last_ptx_inst_option = *i; + switch ( last_ptx_inst_option ) { + case EQU_OPTION: + case NEU_OPTION: + case LTU_OPTION: + case LEU_OPTION: + case GTU_OPTION: + case GEU_OPTION: + case EQ_OPTION: + case NE_OPTION: + case LT_OPTION: + case LE_OPTION: + case GT_OPTION: + case GE_OPTION: + case LS_OPTION: + case HS_OPTION: + m_compare_op = last_ptx_inst_option; + break; + case NUM_OPTION: + case NAN_OPTION: + m_compare_op = last_ptx_inst_option; + // assert(0); // finish this + break; + case SAT_OPTION: + m_saturation_mode = 1; + break; + case RNI_OPTION: + case RZI_OPTION: + case RMI_OPTION: + case RPI_OPTION: + case RN_OPTION: + case RZ_OPTION: + case RM_OPTION: + case RP_OPTION: + m_rounding_mode = last_ptx_inst_option; + break; + case HI_OPTION: + m_compare_op = last_ptx_inst_option; + m_hi = true; + assert( !m_lo ); + assert( !m_wide ); + break; + case LO_OPTION: + m_compare_op = last_ptx_inst_option; + m_lo = true; + assert( !m_hi ); + assert( !m_wide ); + break; + case WIDE_OPTION: + m_wide = true; + assert( !m_lo ); + assert( !m_hi ); + break; + case UNI_OPTION: + m_uni = true; // don't care... < now we DO care when constructing flowgraph> + break; + case GEOM_MODIFIER_1D: + case GEOM_MODIFIER_2D: + case GEOM_MODIFIER_3D: + m_geom_spec = last_ptx_inst_option; + break; + case V2_TYPE: + case V3_TYPE: + case V4_TYPE: + m_vector_spec = last_ptx_inst_option; + break; + case ATOMIC_AND: + case ATOMIC_OR: + case ATOMIC_XOR: + case ATOMIC_CAS: + case ATOMIC_EXCH: + case ATOMIC_ADD: + case ATOMIC_INC: + case ATOMIC_DEC: + case ATOMIC_MIN: + case ATOMIC_MAX: + m_atomic_spec = last_ptx_inst_option; + break; + case APPROX_OPTION: + break; + case FULL_OPTION: + break; + case ANY_OPTION: + m_vote_mode = vote_any; + break; + case ALL_OPTION: + m_vote_mode = vote_all; + break; + case GLOBAL_OPTION: + m_membar_level = GLOBAL_OPTION; + break; + case CTA_OPTION: + m_membar_level = CTA_OPTION; + break; + case FTZ_OPTION: + break; + + default: + assert(0); + break; + } + } + m_scalar_type = scalar_type; + m_space_spec = space_spec; + m_source_file = file?file:"<unknown>"; + m_source_line = line; + m_source = source; +} + +void ptx_instruction::print_insn() const +{ + print_insn(stdout); + fflush(stdout); +} + +void ptx_instruction::print_insn( FILE *fp ) const +{ + char buf[1024], *p; + snprintf(buf,1024,"%s", m_source.c_str()); + p = strtok(buf,";"); + if( !is_label() ) + fprintf(fp,"PC=%3u [idx=%3u] ", m_PC, m_instr_mem_index ); + else + fprintf(fp," " ); + fprintf(fp,"(%s:%u) %s", m_source_file.c_str(), m_source_line, p ); +} + +unsigned g_assemble_code_next_pc=1; +std::map<unsigned,function_info*> g_pc_to_finfo; +std::vector<ptx_instruction*> function_info::s_g_pc_to_insn; + +void function_info::print_insn( unsigned pc, FILE * fp ) const +{ + unsigned index = pc - m_start_PC; + fprintf(fp,"FUNC[%s]",m_name.c_str() ); + if ( index >= m_instr_mem_size ) { + fprintf(fp, "<past last instruction (max pc=%u)>", m_start_PC + m_instr_mem_size - 1 ); + } else { + if ( m_instr_mem[index] != NULL ) + m_instr_mem[index]->print_insn(fp); + else + fprintf(fp, "<no instruction at pc = %u>", pc ); + } +} + +void function_info::ptx_assemble() +{ + if( m_assembled ) { + return; + } + + // get the instructions into instruction memory... + unsigned num_inst = m_instructions.size(); + m_instr_mem = new ptx_instruction*[ num_inst ]; + m_instr_mem_size = num_inst; + + printf("GPGPU-Sim PTX: instruction assembly for function \'%s\'... ", m_name.c_str() ); + fflush(stdout); + std::list<ptx_instruction*>::iterator i; + addr_t n=0; // offset in m_instr_mem + addr_t PC = g_assemble_code_next_pc; // globally unique address (across functions) + m_start_PC = PC; + s_g_pc_to_insn.reserve(s_g_pc_to_insn.size() + m_instructions.size()); + for ( i=m_instructions.begin(); i != m_instructions.end(); i++ ) { + ptx_instruction *pI = *i; + if ( pI->is_label() ) { + const symbol *l = pI->get_label(); + labels[l->name()] = n; + } else { + g_pc_to_finfo[PC] = this; + m_instr_mem[n] = pI; + s_g_pc_to_insn.push_back(pI); + assert(pI == s_g_pc_to_insn[PC - 1]); + pI->set_m_instr_mem_index(n); + pI->set_PC(PC); + n++; + PC++; + } + } + g_assemble_code_next_pc=PC; + for ( unsigned ii=0; ii < n; ii++ ) { // handle branch instructions + ptx_instruction *pI = m_instr_mem[ii]; + if ( pI->get_opcode() == BRA_OP ) { + operand_info &target = pI->dst(); //get operand, e.g. target name + if ( labels.find(target.name()) == labels.end() ) { + printf("GPGPU-Sim PTX: Loader error (%s:%u): Branch label \"%s\" does not appear in assembly code.", + pI->source_file(),pI->source_line(), target.name().c_str() ); + abort(); + } + unsigned index = labels[ target.name() ]; //determine address from name + unsigned PC = m_instr_mem[index]->get_PC(); + g_current_symbol_table->set_label_address( target.get_symbol(), PC ); + target.set_type(label_t); + } + } + printf(" done.\n"); + fflush(stdout); + + create_basic_blocks(); + connect_basic_blocks(); + if ( g_debug_execution>=2 ) { + print_basic_blocks(); + print_basic_block_links(); + print_basic_block_dot(); + } + find_postdominators(); + find_ipostdominators(); + if ( g_debug_execution>=2 ) { + print_postdominators(); + print_ipostdominators(); + } + m_assembled = true; +} + + + +void gpgpu_ptx_sim_init_memory() +{ + static bool initialized = false; + if ( !initialized ) { + g_global_mem = new memory_space_impl<8192>("global",64*1024); + g_param_mem = new memory_space_impl<64>("param",64*1024); + g_tex_mem = new memory_space_impl<8192>("tex",64*1024); + g_surf_mem = new memory_space_impl<8192>("surf",64*1024); + initialized = true; + } +} + +int load_static_globals( symbol_table *symtab, unsigned min_gaddr, unsigned max_gaddr) +{ + printf( "GPGPU-Sim PTX: loading global with explicit initializers... " ); + fflush(stdout); + int ng_bytes=0; + symbol_table::iterator g=symtab->global_iterator_begin(); + bool below_image=true; + + for ( ; g!=symtab->global_iterator_end(); g++) { + symbol *global = *g; + if ( global->has_initializer() ) { + std::list<operand_info> init_list = global->get_initializer(); + for ( std::list<operand_info>::iterator i=init_list.begin(); i!=init_list.end(); i++ ) { + operand_info op = *i; + ptx_reg_t value = op.get_literal_value(); + int nbytes = 0; + switch ( op.get_type() ) { + case int_t: nbytes = 4; break; + case float_op_t: nbytes = 4; break; + case double_op_t: nbytes = 8; break; + default: + abort(); + } + unsigned addr=global->get_address(); + + assert( below_image && addr+nbytes < min_gaddr ); // min_gaddr is start of "heap" for cudaMalloc + + g_global_mem->write(addr,nbytes,&value); + ng_bytes+=nbytes; + } + } + } + printf( " done.\n"); + fflush(stdout); + return ng_bytes; +} + +int load_constants( symbol_table *symtab ) +{ + printf( "GPGPU-Sim PTX: loading constants with explicit initializers... " ); + fflush(stdout); + int nc_bytes = 0; + symbol_table::iterator g=symtab->const_iterator_begin(); + + for ( ; g!=symtab->const_iterator_end(); g++) { + symbol *constant = *g; + if ( constant->is_const() && constant->has_initializer() ) { + + // get the constant element data size + int basic_type; + size_t num_bits; + type_decode(constant->type()->get_key().scalar_type(),num_bits,basic_type); + + std::list<operand_info> init_list = constant->get_initializer(); + int nbytes_written = 0; + for ( std::list<operand_info>::iterator i=init_list.begin(); i!=init_list.end(); i++ ) { + operand_info op = *i; + ptx_reg_t value = op.get_literal_value(); + int nbytes = num_bits/8; + switch ( op.get_type() ) { + case int_t: assert(nbytes >= 1); break; + case float_op_t: assert(nbytes == 4); break; + case double_op_t: assert(nbytes >= 4); break; // account for double DEMOTING + default: + abort(); + } + unsigned addr=constant->get_address() + nbytes_written; + + g_global_mem->write(addr,nbytes,&value); // assume little endian (so u8 is the first byte in u32) + nc_bytes+=nbytes; + nbytes_written += nbytes; + } + } + } + printf( " done.\n"); + fflush(stdout); + return nc_bytes; +} + +unsigned long long g_dev_malloc=0x10000000; // start allocating from this address (lower values used for allocating globals in .ptx file) + +void* gpgpu_ptx_sim_malloc( size_t size ) +{ + unsigned long long result = g_dev_malloc; + printf("GPGPU-Sim PTX: allocating %zu bytes on GPU starting at address 0x%Lx\n", size, g_dev_malloc ); + fflush(stdout); + g_dev_malloc += size; + if (size%64) g_dev_malloc += (64 - size%64); //align to 64 byte boundaries + return(void*) result; +} + +void* gpgpu_ptx_sim_mallocarray( size_t size ) +{ + unsigned long long result = g_dev_malloc; + printf("GPGPU-Sim PTX: allocating %zu bytes on GPU starting at address 0x%Lx\n", size, g_dev_malloc ); + fflush(stdout); + g_dev_malloc += size; + if (size%64) g_dev_malloc += (64 - size%64); //align to 64 byte boundaries + return(void*) result; +} + + +void gpgpu_ptx_sim_memcpy_to_gpu( size_t dst_start_addr, const void *src, size_t count ) +{ + printf("GPGPU-Sim PTX: copying %zu bytes from CPU[0x%Lx] to GPU[0x%Lx] ... ", count, (unsigned long long) src, (unsigned long long) dst_start_addr ); + fflush(stdout); + char *src_data = (char*)src; + for (unsigned n=0; n < count; n ++ ) + g_global_mem->write(dst_start_addr+n,1, src_data+n); + printf( " done.\n"); + fflush(stdout); +} + +void gpgpu_ptx_sim_memcpy_from_gpu( void *dst, size_t src_start_addr, size_t count ) +{ + printf("GPGPU-Sim PTX: copying %zu bytes from GPU[0x%Lx] to CPU[0x%Lx] ...", count, (unsigned long long) src_start_addr, (unsigned long long) dst ); + fflush(stdout); + unsigned char *dst_data = (unsigned char*)dst; + for (unsigned n=0; n < count; n ++ ) + g_global_mem->read(src_start_addr+n,1,dst_data+n); + printf( " done.\n"); + fflush(stdout); +} + +void gpgpu_ptx_sim_memcpy_gpu_to_gpu( size_t dst, size_t src, size_t count ) +{ + printf("GPGPU-Sim PTX: copying %zu bytes from GPU[0x%Lx] to GPU[0x%Lx] ...", count, + (unsigned long long) src, (unsigned long long) dst ); + fflush(stdout); + for (unsigned n=0; n < count; n ++ ) { + unsigned char tmp; + g_global_mem->read(src+n,1,&tmp); + g_global_mem->write(dst+n,1, &tmp); + } + printf( " done.\n"); + fflush(stdout); +} + +void gpgpu_ptx_sim_memset( size_t dst_start_addr, int c, size_t count ) +{ + printf("GPGPU-Sim PTX: setting %zu bytes of memory to 0x%x starting at 0x%Lx... ", + count, (unsigned char) c, (unsigned long long) dst_start_addr ); + fflush(stdout); + unsigned char c_value = (unsigned char)c; + for (unsigned n=0; n < count; n ++ ) + g_global_mem->write(dst_start_addr+n,1,&c_value); + printf( " done.\n"); + fflush(stdout); +} + +int ptx_thread_done( void *thd ) +{ + ptx_thread_info *the_thread = (ptx_thread_info *) thd; + int result = 0; + result = (the_thread==NULL) || the_thread->is_done(); + return result; +} + +const char * ptx_get_fname( unsigned PC ) +{ + static const char *null_ptr = "<null finfo ptr>"; + std::map<unsigned,function_info*>::iterator f=g_pc_to_finfo.find(PC); + if( f== g_pc_to_finfo.end() ) + return null_ptr; + return f->second->get_name().c_str(); +} + +unsigned ptx_thread_donecycle( void *thr ) +{ + ptx_thread_info *the_thread = (ptx_thread_info *) thr; + if( the_thread == NULL ) + return 0; + return the_thread->donecycle(); +} + +int ptx_thread_get_next_pc( void *thd ) +{ + ptx_thread_info *the_thread = (ptx_thread_info *) thd; + if ( the_thread == NULL ) + return -1; + 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) +} + +void* ptx_thread_get_next_finfo( void *thd ) +{ + ptx_thread_info *the_thread = (ptx_thread_info *) thd; + if ( the_thread == NULL ) + return NULL; + return the_thread->get_finfo(); // finfo should already be updatd to next PC at this point (was set in shader_decode() last time thread ran) +} + +int ptx_thread_at_barrier( void *thd ) +{ + ptx_thread_info *the_thread = (ptx_thread_info *) thd; + if ( the_thread == NULL ) + return 0; + return the_thread->is_at_barrier(); +} + +int ptx_thread_all_at_barrier( void *thd ) +{ + ptx_thread_info *the_thread = (ptx_thread_info *) thd; + if ( the_thread == NULL ) + return 0; + return the_thread->all_at_barrier()?1:0; +} + +unsigned long long ptx_thread_get_cta_uid( void *thd ) +{ + ptx_thread_info *the_thread = (ptx_thread_info *) thd; + if ( the_thread == NULL ) + return 0; + return the_thread->get_cta_uid(); +} + +void ptx_thread_reset_barrier( void *thd ) +{ + ptx_thread_info *the_thread = (ptx_thread_info *) thd; + if ( the_thread == NULL ) + return; + the_thread->clear_barrier(); +} + +void ptx_thread_release_barrier( void *thd ) +{ + ptx_thread_info *the_thread = (ptx_thread_info *) thd; + if ( the_thread == NULL ) + return; + the_thread->release_barrier(); +} + +void ptx_print_insn( address_type pc, FILE *fp ) +{ + std::map<unsigned,function_info*>::iterator f = g_pc_to_finfo.find(pc); + if( f == g_pc_to_finfo.end() ) { + fprintf(fp,"<no instruction at address 0x%x (%u)>", pc, pc ); + return; + } + function_info *finfo = f->second; + assert( finfo ); + finfo->print_insn(pc,fp); +} + +void function_info::ptx_decode_inst( ptx_thread_info *thread, + unsigned *op_type, + int *i1, int *i2, int *i3, int *i4, + int *o1, int *o2, int *o3, int *o4, + int *vectorin, + int *vectorout, + int *arch_reg ) +{ + addr_t pc = thread->get_pc(); + unsigned index = pc - m_start_PC; + assert( index < m_instr_mem_size ); + ptx_instruction *pI = m_instr_mem[index]; //get instruction from m_instr_mem[PC] + + bool has_dst = false ; + int opcode = pI->get_opcode(); //determine the opcode + + switch ( pI->get_opcode() ) { +#define OP_DEF(OP,FUNC,STR,DST,CLASSIFICATION) case OP: has_dst = (DST!=0); break; +#include "opcodes.def" +#undef OP_DEF + default: + printf( "Execution error: Invalid opcode (0x%x)\n", pI->get_opcode() ); + break; + } + + *op_type = ALU_OP; + if ( opcode == LD_OP ) { + *op_type = LOAD_OP; + } else if ( opcode == ST_OP ) { + *op_type = STORE_OP; + } else if ( opcode == BRA_OP ) { + *op_type = BRANCH_OP; + } else if ( opcode == TEX_OP ) { + *op_type = LOAD_OP; + } else if ( opcode == ATOM_OP ) { + *op_type = LOAD_OP; // make atomics behave more like a load. + } else if ( opcode == BAR_OP ) { + *op_type = BARRIER_OP; + } + + int n=0,m=0; + ptx_instruction::const_iterator op=pI->op_iter_begin(); + for ( ; op != pI->op_iter_end(); op++, n++ ) { //process operands + + const operand_info &o = *op; + if ( has_dst && n==0 ) { + if ( o.is_reg() ) { //but is destination an actual register? (seems like it fails if it's a vector) + *o1 = o.reg_num(); + arch_reg[0] = o.arch_reg_num(); + } else if ( o.is_vector() ) { //but is destination an actual register? (seems like it fails if it's a vector) + *vectorin = 1; + *o1 = o.reg1_num(); + *o2 = o.reg2_num(); + *o3 = o.reg3_num(); + *o4 = o.reg4_num(); + for (int i = 0; i < 4; i++) + arch_reg[i] = o.arch_reg_num(i); + } + } else { + if ( o.is_reg() ) { + int reg_num = o.reg_num(); + arch_reg[m + 4] = o.arch_reg_num(); + switch ( m ) { + case 0: *i1 = reg_num; break; + case 1: *i2 = reg_num; break; + case 2: *i3 = reg_num; break; + default: + break; + } + m++; + } else if ( o.is_vector() ) { + assert(m == 0); //only support 1 vector operand (for textures) right now + *vectorout = 1; + *i1 = o.reg1_num(); + *i2 = o.reg2_num(); + *i3 = o.reg3_num(); + *i4 = o.reg4_num(); + for (int i = 0; i < 4; i++) + arch_reg[i + 4] = o.arch_reg_num(i); + m+=4; + } + } + } +} + +unsigned function_info::ptx_get_inst_op( ptx_thread_info *thread ) +{ + addr_t pc = thread->get_pc(); + unsigned index = pc - m_start_PC; + assert( index < m_instr_mem_size ); + ptx_instruction *pI = m_instr_mem[index]; //get instruction from m_instr_mem[PC] + + int opcode = pI->get_opcode(); //determine the opcode + + if ( opcode == LD_OP ) { + if ( pI->get_space() != SHARED_DIRECTIVE ) //treat shared memory access as generic instruction (e.g. no bank conflicts) + return LOAD_OP; + } else if ( opcode == ST_OP ) { + if ( pI->get_space() != SHARED_DIRECTIVE ) + return STORE_OP; + } else if ( opcode == BRA_OP ) { + return BRANCH_OP; + } else if ( opcode == TEX_OP ) { + return LOAD_OP; + } + return ALU_OP; +} + +void function_info::add_param_name_and_type( unsigned index, std::string name, int type ) +{ + unsigned parsed_index; + char buffer[2048]; + snprintf(buffer,2048,"%s_param_%%u", m_name.c_str() ); + int ntokens = sscanf(name.c_str(),buffer,&parsed_index); + if( ntokens == 1 ) { + assert( m_ptx_param_info.find(parsed_index) == m_ptx_param_info.end() ); + m_ptx_param_info[parsed_index] = param_info(parsed_index,name,type); + } else { + assert( m_ptx_param_info.find(index) == m_ptx_param_info.end() ); + m_ptx_param_info[index] = param_info(index,name,type); + } +} + +void function_info::add_param_data( unsigned argn, struct gpgpu_ptx_sim_arg *args ) +{ + const void *data = args->m_start; + param_t tmp; + + if( data ) { + memcpy(&tmp.data,data,args->m_nbytes); + std::map<unsigned,param_info>::iterator i=m_ptx_param_info.find(argn); + if( i != m_ptx_param_info.end()) { + i->second.add_data(tmp); + } else { + // This should only happen for OpenCL: + // + // The LLVM PTX compiler in NVIDIA's driver (version 190.29) + // does not generate an argument in the function declaration + // for __constant arguments. + // + // The associated constant memory space can be allocated in two + // ways. It can be explicitly initialized in the .ptx file where + // it is declared. Or, it can be allocated using the clCreateBuffer + // on the host. In this later case, the .ptx file will contain + // a global declaration of the parameter, but it will have an unknown + // array size. Thus, the symbol's address will not be set and we need + // to set it here before executing the PTX. + + char buffer[2048]; + snprintf(buffer,2048,"%s_param_%u",m_name.c_str(),argn); + + symbol *p = m_symtab->lookup(buffer); + if( p == NULL ) + printf("GPGPU-Sim PTX: ERROR ** could not locate symbol for \'%s\' : cannot bind buffer\n", buffer); + p->set_address((addr_t)*(size_t*)data); + } + } else { + // This should only happen for OpenCL, but doesn't cause problems + } +} + +int ptx_branch_taken( void *thd ) +{ + ptx_thread_info *thread = (ptx_thread_info *) thd; + return (thread != NULL) && thread->branch_taken(); +} + +template<int activate_level> +bool ptx_debug_exec_dump_cond(int thd_uid, addr_t pc) +{ + if (g_debug_execution >= activate_level) { + // check each type of debug dump constraint to filter out dumps + if ( (g_debug_thread_uid != 0) && (thd_uid != (unsigned)g_debug_thread_uid) ) { + return false; + } + if ( (g_debug_pc != 0xBEEF1518) && (pc != g_debug_pc) ) { + return false; + } + + return true; + } + + return false; +} + +unsigned datatype2size( unsigned data_type ) +{ + unsigned data_size; + switch ( data_type ) { + case B8_TYPE: + case S8_TYPE: + case U8_TYPE: + data_size = 1; break; + case B16_TYPE: + case S16_TYPE: + case U16_TYPE: + case F16_TYPE: + data_size = 2; break; + case B32_TYPE: + case S32_TYPE: + case U32_TYPE: + case F32_TYPE: + data_size = 4; break; + case B64_TYPE: + case S64_TYPE: + case U64_TYPE: + case F64_TYPE: + data_size = 8; break; + default: assert(0); break; + } + return data_size; +} + +extern unsigned long long gpu_sim_cycle; +unsigned g_warp_active_mask; + +void function_info::ptx_exec_inst( ptx_thread_info *thread, + addr_t *addr, + unsigned *space, + unsigned *data_size, + dram_callback_t* callback, + unsigned warp_active_mask ) +{ + bool skip = false; + int op_classification = 0; + addr_t pc = thread->next_instr(); + unsigned index = pc - m_start_PC; + assert( index < m_instr_mem_size ); + ptx_instruction *pI = m_instr_mem[index]; + g_current_symbol_table = thread->get_finfo()->get_symtab(); + thread->clearRPC(); + thread->m_last_set_operand_value.u64 = 0; + *space = -1; + *addr = 0xFEEBDAED; + + thread->clear_modifiedregs(); + if( pI->has_pred() ) { + const operand_info &pred = pI->get_pred(); + ptx_reg_t pred_value = thread->get_operand_value(pred); + skip = !pred_value.pred ^ pI->get_pred_neg(); + } + g_warp_active_mask = warp_active_mask; + if( !skip ) { + switch ( pI->get_opcode() ) { +#define OP_DEF(OP,FUNC,STR,DST,CLASSIFICATION) case OP: FUNC(pI,thread); op_classification = CLASSIFICATION; break; +#include "opcodes.def" +#undef OP_DEF + default: + printf( "Execution error: Invalid opcode (0x%x)\n", pI->get_opcode() ); + break; + } + } + + if ( ptx_debug_exec_dump_cond<5>(thread->get_uid(), pc) ) { + dim3 ctaid = thread->get_ctaid(); + dim3 tid = thread->get_tid(); + printf("%u [cyc=%u][thd=%u][i=%u] : ctaid=(%u,%u,%u) tid=(%u,%u,%u) icount=%u [pc=%u] (%s:%u - %s) [0x%llx]\n", + g_ptx_sim_num_insn, + (unsigned)gpu_sim_cycle, + thread->get_uid(), + pI->uid(), ctaid.x,ctaid.y,ctaid.z,tid.x,tid.y,tid.z, + thread->get_icount(), + pc, pI->source_file(), pI->source_line(), pI->get_source(), + thread->m_last_set_operand_value.u64 ); + fflush(stdout); + } + + *data_size = 0; + if ( (pI->get_opcode() == LD_OP || pI->get_opcode() == ST_OP) ) { + *addr = thread->last_eaddr(); + *space = thread->last_space(); + + unsigned to_type = pI->get_type(); + *data_size = datatype2size(to_type); + } + + if ( pI->get_opcode() == ATOM_OP ) { + *addr = thread->last_eaddr(); + *space = thread->last_space(); + callback->function = thread->last_callback().function; + callback->instruction = thread->last_callback().instruction; + callback->thread = thread; + + unsigned to_type = pI->get_type(); + *data_size = datatype2size(to_type); + } else { + // make sure that the callback isn't set + callback->function = NULL; + callback->instruction = NULL; + } + + if (pI->get_opcode() == TEX_OP) { + *addr = thread->last_eaddr(); + *space = thread->last_space(); + + unsigned to_type = pI->get_type(); + *data_size = datatype2size(to_type); + } + + if ( g_debug_execution >= 6 ) { + if ( ptx_debug_exec_dump_cond<6>(thread->get_uid(), pc) ) + thread->dump_modifiedregs(); + } else if ( g_debug_execution >= 10 ) { + if ( ptx_debug_exec_dump_cond<10>(thread->get_uid(), pc) ) + thread->dump_regs(); + } + thread->update_pc(); + g_ptx_sim_num_insn++; + ptx_file_line_stats_add_exec_count(pI); + if ( gpgpu_ptx_instruction_classification ) { + unsigned space = pI->get_space(); + switch ( space ) { + case GLOBAL_DIRECTIVE: space = 10; break; + case LOCAL_DIRECTIVE: space = 11; break; + case TEX_DIRECTIVE: space = 12; break; + case SURF_DIRECTIVE: space = 13; break; + case PARAM_DIRECTIVE: space = 14; break; + case SHARED_DIRECTIVE: space = 15; break; + case CONST_DIRECTIVE: space = 16; break; + default: + space = 0 ; + break; + } + StatAddSample( g_inst_classification_stat[g_ptx_kernel_count], op_classification); + if (space) StatAddSample( g_inst_classification_stat[g_ptx_kernel_count], ( int )space); + StatAddSample( g_inst_op_classification_stat[g_ptx_kernel_count], (int) pI->get_opcode() ); + } + if ( (g_ptx_sim_num_insn % 100000) == 0 ) { + dim3 ctaid = thread->get_ctaid(); + dim3 tid = thread->get_tid(); + printf("%u instructions simulated : ctaid=(%u,%u,%u) tid=(%u,%u,%u)\n", + g_ptx_sim_num_insn, ctaid.x,ctaid.y,ctaid.z,tid.x,tid.y,tid.z ); + fflush(stdout); + } +} + +unsigned g_gx, g_gy, g_gz; + +dim3 g_cudaGridDim, g_cudaBlockDim; + +unsigned g_cta_launch_sid; +std::list<ptx_thread_info *> g_active_threads; +std::map<unsigned,unsigned> g_sm_idx_offset_next; +unsigned g_sm_next_index; +std::map<unsigned,memory_space*> g_shared_memory_lookup; +std::map<unsigned,ptx_cta_info*> g_ptx_cta_lookup; +std::map<unsigned,std::map<unsigned,memory_space*> > g_local_memory_lookup; + +// return number of blocks in grid +unsigned ptx_sim_grid_size() +{ + return g_cudaGridDim.x * g_cudaGridDim.y * g_cudaGridDim.z; +} + +void set_option_gpgpu_spread_blocks_across_cores(int option) +{ + gpgpu_option_spread_blocks_across_cores = option; +} + +void set_param_gpgpu_num_shaders(int num_shaders) +{ + gpgpu_param_num_shaders = num_shaders; +} + +unsigned ptx_sim_cta_size() +{ + return g_cudaBlockDim.x * g_cudaBlockDim.y * g_cudaBlockDim.z; +} + +const struct gpgpu_ptx_sim_kernel_info* ptx_sim_kernel_info() { + return g_entrypoint_func_info->get_kernel_info(); +} + +void ptx_sim_free_sm( void** thread_info ) +{ +} + +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 ) +{ + if ( *thread_info != NULL ) { + ptx_thread_info *thd = *((ptx_thread_info**)thread_info); + assert( thd->is_done() ); + if ( g_debug_execution==-1 ) { + dim3 ctaid = thd->get_ctaid(); + dim3 tid = thd->get_tid(); + printf("GPGPU-Sim PTX simulator: thread exiting ctaid=(%u,%u,%u) tid=(%u,%u,%u) @ 0x%Lx\n", + ctaid.x,ctaid.y,ctaid.z,tid.x,tid.y,tid.z, (unsigned long long)*((void**)thread_info) ); + fflush(stdout); + } + thd->m_cta_info->assert_barrier_empty(); + thd->m_cta_info->register_deleted_thread(thd); + delete thd; + *((ptx_thread_info**)thread_info) = NULL; + } + + if ( !g_active_threads.empty() ) { //if g_active_threads not empty... + assert( g_active_threads.size() <= threads_left ); + if ( g_cta_launch_sid == (unsigned)-1 ) + g_cta_launch_sid = sid; + assert( g_cta_launch_sid == (unsigned)sid ); + ptx_thread_info *thd = g_active_threads.front(); + g_active_threads.pop_front(); + *((ptx_thread_info**)thread_info) = thd; + thd->set_hw_tid(tid); + thd->set_hw_wid(hw_warp_id); + thd->set_hw_ctaid(hw_cta_id); + thd->set_core(core); + thd->set_hw_sid(sid); + return 1; + } + + if ( g_gx >= g_cudaGridDim.x || g_gy >= g_cudaGridDim.y || g_gz >= g_cudaGridDim.z ) { + return 0; //finished! + } + + if ( threads_left < ptx_sim_cta_size() ) { + return 0; + } + + if ( g_debug_execution==-1 ) { + printf("GPGPU-Sim PTX simulator: STARTING THREAD ALLOCATION --> \n"); + fflush(stdout); + } + + //initializing new CTA + ptx_cta_info *cta_info = NULL; + memory_space *shared_mem = NULL; + + unsigned cta_size = ptx_sim_cta_size(); //blocksize + unsigned sm_offset = g_sm_idx_offset_next[sid]; + unsigned max_cta_per_sm = num_threads/cta_size; // e.g., 256 / 48 = 5 + assert( max_cta_per_sm > 0 ); + + //following sm_idx calculation assumes shaders being filled up depth-first? + unsigned sm_idx = sid*max_cta_per_sm + sm_offset; /* Is this assuming non-even block distribution? */ + sm_idx = max_cta_per_sm*sid + tid/cta_size; + + + if (!gpgpu_option_spread_blocks_across_cores) { + // update offset... + if ( (sm_offset + 1) >= max_cta_per_sm ) { + sm_offset = 0; + } else { + sm_offset++; + } + g_sm_idx_offset_next[sid] = sm_offset; + } else { + sm_idx = (tid/cta_size)*gpgpu_param_num_shaders + sid; + } + + if ( g_shared_memory_lookup.find(sm_idx) == g_shared_memory_lookup.end() ) { + if ( g_debug_execution >= 1 ) { + printf(" <CTA alloc> : sm_idx=%u sid=%u sm_offset=%u max_cta_per_sm=%u\n", + sm_idx, sid, sm_offset, max_cta_per_sm ); + } + char buf[512]; + snprintf(buf,512,"shared_%u", sid); + shared_mem = new memory_space_impl<16*1024>(buf,4); + g_shared_memory_lookup[sm_idx] = shared_mem; + cta_info = new ptx_cta_info(sm_idx); + g_ptx_cta_lookup[sm_idx] = cta_info; + } else { + if ( g_debug_execution >= 1 ) { + printf(" <CTA realloc> : sm_idx=%u sid=%u sm_offset=%u max_cta_per_sm=%u\n", + sm_idx, sid, sm_offset, max_cta_per_sm ); + } + shared_mem = g_shared_memory_lookup[sm_idx]; + cta_info = g_ptx_cta_lookup[sm_idx]; + cta_info->check_cta_thread_status_and_reset(); + } + + std::map<unsigned,memory_space*> &local_mem_lookup = g_local_memory_lookup[sid]; + unsigned new_tid; + for ( unsigned tz=0; tz < g_cudaBlockDim.z; tz++ ) { + for ( unsigned ty=0; ty < g_cudaBlockDim.y; ty++ ) { + for ( unsigned tx=0; tx < g_cudaBlockDim.x; tx++ ) { + new_tid = tx + g_cudaBlockDim.x*ty + g_cudaBlockDim.x*g_cudaBlockDim.y*tz; //unique id but only to a BLOCK + new_tid += tid; + ptx_thread_info *thd = new ptx_thread_info(); + + memory_space *local_mem = NULL; + std::map<unsigned,memory_space*>::iterator l = local_mem_lookup.find(new_tid); + if ( l != local_mem_lookup.end() ) { + local_mem = l->second; + } else { + char buf[512]; + snprintf(buf,512,"local_%u_%u", sid, new_tid); + local_mem = new memory_space_impl<32>(buf,32); + local_mem_lookup[new_tid] = local_mem; + } + thd->set_info(g_entrypoint_symbol_table,g_entrypoint_func_info); + thd->set_nctaid(g_cudaGridDim.x,g_cudaGridDim.y,g_cudaGridDim.z); + thd->set_ntid(g_cudaBlockDim.x,g_cudaBlockDim.y,g_cudaBlockDim.z); + thd->set_ctaid(g_gx,g_gy,g_gz); + thd->set_tid(tx,ty,tz); + thd->set_hw_tid((unsigned)-1); + thd->set_hw_wid((unsigned)-1); + thd->set_hw_ctaid((unsigned)-1); + thd->set_core(NULL); + thd->set_hw_sid((unsigned)-1); + thd->set_valid(); + thd->m_shared_mem = shared_mem; + thd->m_cta_info = cta_info; + cta_info->add_thread(thd); + thd->m_local_mem = local_mem; + if ( g_debug_execution==-1 ) { + printf("GPGPU-Sim PTX simulator: allocating thread ctaid=(%u,%u,%u) tid=(%u,%u,%u) @ 0x%Lx\n", + g_gx,g_gy,g_gz,tx,ty,tz, (unsigned long long)thd ); + fflush(stdout); + } + g_active_threads.push_back(thd); + } + } + } + if ( g_debug_execution==-1 ) { + printf("GPGPU-Sim PTX simulator: <-- FINISHING THREAD ALLOCATION\n"); + fflush(stdout); + } + + g_gx++; + if ( g_gx >= g_cudaGridDim.x ) { + g_gx = 0; + g_gy++; + if ( g_gy >= g_cudaGridDim.y ) { + g_gy = 0; + g_gz++; + } + } + + g_cta_launch_sid = -1; + + assert( g_active_threads.size() <= threads_left ); + + g_cta_launch_sid = sid; + *((ptx_thread_info**)thread_info) = g_active_threads.front(); + (*((ptx_thread_info**)thread_info) )->set_hw_tid(tid); + (*((ptx_thread_info**)thread_info) )->set_hw_wid(hw_warp_id); + (*((ptx_thread_info**)thread_info) )->set_hw_ctaid(hw_cta_id); + (*((ptx_thread_info**)thread_info) )->set_core(core); + (*((ptx_thread_info**)thread_info) )->set_hw_sid(sid); + g_active_threads.pop_front(); + + return 1; +} + +void init_inst_classification_stat() { + char kernelname[256] =""; +#define MAX_CLASS_KER 256 + if (!g_inst_classification_stat) g_inst_classification_stat = (void**)calloc(MAX_CLASS_KER, sizeof(void*)); + snprintf(kernelname, MAX_CLASS_KER, "Kernel %d Classification\n",g_ptx_kernel_count ); + assert( g_ptx_kernel_count < MAX_CLASS_KER ) ; // a static limit on number of kernels increase it if it fails! + g_inst_classification_stat[g_ptx_kernel_count] = StatCreate(kernelname,1,20); + if (!g_inst_op_classification_stat) g_inst_op_classification_stat = (void**)calloc(MAX_CLASS_KER, sizeof(void*)); + snprintf(kernelname, MAX_CLASS_KER, "Kernel %d OP Classification\n",g_ptx_kernel_count ); + g_inst_op_classification_stat[g_ptx_kernel_count] = StatCreate(kernelname,1,100); +} + +unsigned g_max_regs_per_thread = 0; + +std::map<std::string,function_info*> *g_kernel_name_to_function_lookup=NULL; +std::map<std::string,symbol_table*> g_kernel_name_to_symtab_lookup; +std::map<const void*,std::string> *g_host_to_kernel_entrypoint_name_lookup=NULL; +extern unsigned g_ptx_thread_info_uid_next; + +void gpgpu_ptx_sim_init_grid( const char *kernel_key, struct gpgpu_ptx_sim_arg* args, + struct dim3 gridDim, struct dim3 blockDim ) +{ + g_gx=0; + g_gy=0; + g_gz=0; + g_cudaGridDim = gridDim; + g_cudaBlockDim = blockDim; + g_sm_idx_offset_next.clear(); + g_sm_next_index = 0; + + if ( g_host_to_kernel_entrypoint_name_lookup->find(kernel_key) == + g_host_to_kernel_entrypoint_name_lookup->end() ) { + printf("GPGPU-Sim PTX: ERROR ** cannot locate PTX entry point\n" ); + abort(); + } else { + std::string kname = (*g_host_to_kernel_entrypoint_name_lookup)[kernel_key]; + printf("GPGPU-Sim PTX: Launching kernel \'%s\' gridDim= (%u,%u,%u) blockDim = (%u,%u,%u); ntuid=%u\n", + kname.c_str(), g_cudaGridDim.x,g_cudaGridDim.y,g_cudaGridDim.z,g_cudaBlockDim.x,g_cudaBlockDim.y,g_cudaBlockDim.z, + g_ptx_thread_info_uid_next ); + + if ( g_kernel_name_to_function_lookup->find(kname) == + g_kernel_name_to_function_lookup->end() ) { + printf("GPGPU-Sim PTX: ERROR ** function \'%s\' not found in ptx file\n", kname.c_str() ); + abort(); + } + g_entrypoint_func_info = g_func_info = (*g_kernel_name_to_function_lookup)[kname]; + g_entrypoint_symbol_table = g_current_symbol_table = g_kernel_name_to_symtab_lookup[kname]; + } + + unsigned argcount=0; + struct gpgpu_ptx_sim_arg *tmparg = args; + while (tmparg) { + tmparg = tmparg->m_next; + argcount++; + } + + unsigned argn=1; + while (args) { + g_func_info->add_param_data(argcount-argn,args); + args = args->m_next; + argn++; + } + g_func_info->finalize(g_param_mem,g_current_symbol_table); + g_ptx_kernel_count++; + if ( gpgpu_ptx_instruction_classification ) { + init_inst_classification_stat(); + } + fflush(stdout); +} + +const char *g_gpgpusim_version_string = "2.1.1b (beta)"; + +void print_splash() +{ + static int splash_printed=0; + if ( !splash_printed ) { + fprintf(stdout, "\n\n *** GPGPU-Sim version %s ***\n\n\n", g_gpgpusim_version_string ); + splash_printed=1; + } +} + +void gpgpu_ptx_sim_register_kernel(const char *hostFun, const char *deviceFun) +{ + const void* key=hostFun; + print_splash(); + if ( g_host_to_kernel_entrypoint_name_lookup == NULL ) + g_host_to_kernel_entrypoint_name_lookup = new std::map<const void*,std::string>; + if( g_kernel_name_to_function_lookup == NULL ) + g_kernel_name_to_function_lookup = new std::map<std::string,function_info*>; + if ( g_host_to_kernel_entrypoint_name_lookup->find(key) != + g_host_to_kernel_entrypoint_name_lookup->end() ) { + printf("GPGPU-Sim Loader error: Don't know how to identify PTX kernels during cudaLaunch\n" + " for this application.\n"); + abort(); + } + (*g_host_to_kernel_entrypoint_name_lookup)[key] = deviceFun; + if( g_kernel_name_to_function_lookup->find(deviceFun) == + g_kernel_name_to_function_lookup->end() ) { + (*g_kernel_name_to_function_lookup)[deviceFun] = NULL; // we set this later, set keys now for error checking + } + + printf("GPGPU-Sim PTX: __cudaRegisterFunction %s : 0x%Lx\n", deviceFun, (unsigned long long)hostFun); +} + +extern int ptx_lineno; + +void register_ptx_function( const char *name, function_info *impl, symbol_table *symtab ) +{ + printf("GPGPU-Sim PTX: parsing function %s\n", name ); + if( g_kernel_name_to_function_lookup == NULL ) + g_kernel_name_to_function_lookup = new std::map<std::string,function_info*>; + + std::map<std::string,function_info*>::iterator i_kernel = g_kernel_name_to_function_lookup->find(name); + if (i_kernel != g_kernel_name_to_function_lookup->end() && i_kernel->second != NULL) { + printf("GPGPU-Sim PTX: WARNING: Function already parsed once. Overwriting.\n"); + } + (*g_kernel_name_to_function_lookup)[name] = impl; + g_kernel_name_to_symtab_lookup[name] = symtab; +} + +std::map<const void*,std::string> g_const_name_lookup; // indexed by hostVar +std::map<const void*,std::string> g_global_name_lookup; // indexed by hostVar +std::set<std::string> g_globals; +std::set<std::string> g_constants; +extern std::map<std::string,symbol_table*> g_sym_name_to_symbol_table; + +void gpgpu_ptx_sim_register_const_variable(void *hostVar, const char *deviceName, size_t size ) +{ + printf("GPGPU-Sim PTX registering constant %s (%zu bytes) to name mapping\n", deviceName, size ); + g_const_name_lookup[hostVar] = deviceName; + //assert( g_current_symbol_table != NULL ); + //g_sym_name_to_symbol_table[deviceName] = g_current_symbol_table; +} + +void gpgpu_ptx_sim_register_global_variable(void *hostVar, const char *deviceName, size_t size ) +{ + printf("GPGPU-Sim PTX registering global %s hostVar to name mapping\n", deviceName ); + g_global_name_lookup[hostVar] = deviceName; + //assert( g_current_symbol_table != NULL ); + //g_sym_name_to_symbol_table[deviceName] = g_current_symbol_table; +} + +void gpgpu_ptx_sim_memcpy_symbol(const char *hostVar, const void *src, size_t count, size_t offset, int to ) +{ + printf("GPGPU-Sim PTX: starting gpgpu_ptx_sim_memcpy_symbol with hostVar 0x%p\n", hostVar); + bool found_sym = false; + int mem_region = 0; + std::string sym_name; + + std::map<const void*,std::string>::iterator c=g_const_name_lookup.find(hostVar); + if ( c!=g_const_name_lookup.end() ) { + found_sym = true; + sym_name = c->second; + mem_region = CONST_DIRECTIVE; + } + std::map<const void*,std::string>::iterator g=g_global_name_lookup.find(hostVar); + if ( g!=g_global_name_lookup.end() ) { + if ( found_sym ) { + printf("Execution error: PTX symbol \"%s\" w/ hostVar=0x%Lx is declared both const and global?\n", + sym_name.c_str(), (unsigned long long)hostVar ); + abort(); + } + found_sym = true; + sym_name = g->second; + mem_region = GLOBAL_DIRECTIVE; + } + if( g_globals.find(hostVar) != g_globals.end() ) { + found_sym = true; + sym_name = hostVar; + mem_region = GLOBAL_DIRECTIVE; + } + if( g_constants.find(hostVar) != g_constants.end() ) { + found_sym = true; + sym_name = hostVar; + mem_region = CONST_DIRECTIVE; + } + + if ( !found_sym ) { + printf("Execution error: No information for PTX symbol w/ hostVar=0x%Lx\n", (unsigned long long)hostVar ); + abort(); + } else printf("GPGPU-Sim PTX: gpgpu_ptx_sim_memcpy_symbol: Found PTX symbol w/ hostVar=0x%Lx\n", (unsigned long long)hostVar ); + const char *mem_name = NULL; + memory_space *mem = NULL; + + std::map<std::string,symbol_table*>::iterator st = g_sym_name_to_symbol_table.find(sym_name.c_str()); + if( st != g_sym_name_to_symbol_table.end() ) { + g_current_symbol_table = st->second; + } + + symbol *sym = g_current_symbol_table->lookup(sym_name.c_str()); + assert(sym); + unsigned dst = sym->get_address() + offset; + switch (mem_region) { + case CONST_DIRECTIVE: + mem = g_global_mem; + mem_name = "global"; + break; + case GLOBAL_DIRECTIVE: + mem = g_global_mem; + mem_name = "global"; + break; + default: + abort(); + } + printf("GPGPU-Sim PTX: gpgpu_ptx_sim_memcpy_symbol: copying %zu bytes %s symbol %s+%zu @0x%x ...\n", + count, (to?" to ":"from"), sym_name.c_str(), offset, dst ); + for ( unsigned n=0; n < count; n++ ) { + if( to ) mem->write(dst+n,1,((char*)src)+n); + else mem->read(dst+n,1,((char*)src)+n); + } + fflush(stdout); +} + +int g_ptx_sim_mode=0; +// used by libcuda.a if non-zer cudaLaunch() will call gpgpu_ptx_sim_main_func() +// if zero it calls gpgpu_ptx_sim_main_perf() + +#if defined(__APPLE__) +int ptx_file_filter(struct dirent *de ) +#else +int ptx_file_filter(const struct dirent *de ) +#endif +{ + const char *tmp = strstr(de->d_name,".ptx"); + if ( tmp != NULL && tmp[4] == 0 ) { + return 1; + } + return 0; +} + +void read_environment_variables() +{ + ptx_debug = 0; + g_debug_execution = 0; + g_debug_ir_generation = false; + + char *mode = getenv("PTX_SIM_MODE_FUNC"); + if ( mode ) + sscanf(mode,"%u", &g_ptx_sim_mode); + printf("GPGPU-Sim PTX: simulation mode %d (can change with PTX_SIM_MODE_FUNC environment variable:\n", g_ptx_sim_mode); + printf(" 1=functional simulation only, 0=detailed performance simulator)\n"); + g_filename = getenv("PTX_SIM_KERNELFILE"); + char *dbg_level = getenv("PTX_SIM_DEBUG"); + if ( dbg_level && strlen(dbg_level) ) { + printf("GPGPU-Sim PTX: setting debug level to %s\n", dbg_level ); + fflush(stdout); + sscanf(dbg_level,"%d", &g_debug_execution); + } + char *dbg_thread = getenv("PTX_SIM_DEBUG_THREAD_UID"); + if ( dbg_thread && strlen(dbg_thread) ) { + printf("GPGPU-Sim PTX: printing debug information for thread uid %s\n", dbg_thread ); + fflush(stdout); + sscanf(dbg_thread,"%d", &g_debug_thread_uid); + } + char *dbg_pc = getenv("PTX_SIM_DEBUG_PC"); + if ( dbg_pc && strlen(dbg_pc) ) { + printf("GPGPU-Sim PTX: printing debug information for instruction with PC = %s\n", dbg_pc ); + fflush(stdout); + sscanf(dbg_pc,"%d", &g_debug_pc); + } + +#if CUDART_VERSION > 1010 + g_override_embedded_ptx = false; + char *usefile = getenv("PTX_SIM_USE_PTX_FILE"); + if (usefile && strlen(usefile)) { + printf("GPGPU-Sim PTX: overriding embedded ptx with ptx file (PTX_SIM_USE_PTX_FILE is set)\n"); + fflush(stdout); + g_override_embedded_ptx = true; + } +#else + g_override_embedded_ptx = true; +#endif + + if ( g_debug_execution >= 40 ) { + ptx_debug = 1; + } + if ( g_debug_execution >= 30 ) { + g_debug_ir_generation = true; + } +} + +static FILE *open_ptxinfo (const char* ptx_filename) +{ + const int ptx_fnamelen = strlen(ptx_filename); + char *ptxi_fname = new char[ptx_fnamelen+5]; + strcpy (ptxi_fname, ptx_filename); + strcpy (ptxi_fname+ptx_fnamelen, "info"); + + //ptxinfo_debug=1; + g_ptxinfo_filename = ptxi_fname; + FILE *f = fopen (ptxi_fname, "rt"); + return f; +} + +struct ptx_info_t { + char *str; + ptx_info_t *next; +}; + +ptx_info_t *g_ptx_source_array = NULL; +unsigned g_used_embedded_ptx_files; +extern double g_ptx_version; + +void gpgpu_ptx_sim_add_ptxstring( const char *ptx_string ) +{ + ptx_info_t *t = new ptx_info_t; + t->next = NULL; + t->str = strdup(ptx_string); + + // put ptx source into a fifo + if (g_ptx_source_array == NULL) { + // first ptx source + g_ptx_source_array = t; + } else { + // insert subsequent ptx source at the end of queue + ptx_info_t *l_ptx_source = g_ptx_source_array; + while (l_ptx_source->next != NULL) { + l_ptx_source = l_ptx_source->next; + } + l_ptx_source->next = t; + } +} + +const ptx_instruction *ptx_instruction_lookup( const char *filename, unsigned linenumber ); + +void print_ptx_file( const char *p, unsigned source_num, const char *filename ) +{ + printf("\nGPGPU-Sim PTX: file _%u.ptx contents:\n\n", source_num ); + char *s = strdup(p); + char *t = s; + unsigned n=1; + while ( *t != '\0' ) { + char *u = t; + while ( (*u != '\n') && (*u != '\0') ) u++; + unsigned last = (*u == '\0'); + *u = '\0'; + const ptx_instruction *pI = ptx_instruction_lookup(filename,n); + char pc[64]; + if( pI && pI->get_PC() ) + snprintf(pc,64,"%4u", pI->get_PC() ); + else + snprintf(pc,64," "); + printf(" _%u.ptx %4u (pc=%s): %s\n", source_num, n, pc, t ); + if ( last ) break; + t = u+1; + n++; + } + free(s); + fflush(stdout); +} + +extern int g_save_embedded_ptx; + +void gpgpu_ptx_sim_load_ptx_from_string( const char *p, unsigned source_num ) +{ + char buf[1024]; + snprintf(buf,1024,"_%u.ptx", source_num ); + if( g_save_embedded_ptx ) { + FILE *fp = fopen(buf,"w"); + fprintf(fp,"%s",p); + fclose(fp); + } + g_filename = strdup(buf); + init_parser(); + ptx__scan_string(p); + int errors = ptx_parse (); + if ( errors ) { + char fname[1024]; + snprintf(fname,1024,"_ptx_XXXXXX"); + int fd=mkstemp(fname); + close(fd); + printf("GPGPU-Sim PTX: parser error detected, exiting... but first extracting .ptx to \"%s\"\n", fname); + FILE *ptxfile = fopen(fname,"w"); + fprintf(ptxfile,"%s", p ); + fclose(ptxfile); + abort(); + exit(40); + } + + if ( g_debug_execution >= 1 ) + print_ptx_file(p,source_num,g_filename); + + printf("GPGPU-Sim PTX: finished parsing EMBEDDED .ptx file %s\n",g_filename); + + char fname[1024]; + snprintf(fname,1024,"_ptx_XXXXXX"); + int fd=mkstemp(fname); + close(fd); + + printf("GPGPU-Sim PTX: extracting embedded .ptx to temporary file \"%s\"\n", fname); + FILE *ptxfile = fopen(fname,"w"); + fprintf(ptxfile,"%s",p); + fclose(ptxfile); + + char fname2[1024]; + snprintf(fname2,1024,"_ptx2_XXXXXX"); + fd=mkstemp(fname2); + close(fd); + char commandline2[4096]; + snprintf(commandline2,4096,"cat %s | sed 's/.version 1.5/.version 1.4/' | sed 's/, texmode_independent//' | sed 's/\\(\\.extern \\.const\\[1\\] .b8 \\w\\+\\)\\[\\]/\\1\\[1\\]/' | sed 's/const\\[.\\]/const\\[0\\]/g' > %s", fname, fname2); + int result = system(commandline2); + if( result != 0 ) { + printf("GPGPU-Sim PTX: ERROR ** while loading PTX (a) %d\n", result); + printf(" Ensure you have write access to simulation directory\n"); + printf(" and have \'cat\' and \'sed\' in your path.\n"); + exit(1); + } + + char tempfile_ptxinfo[1024]; + snprintf(tempfile_ptxinfo,1024,"%sinfo",fname); + char commandline[1024]; + snprintf(commandline,1024,"ptxas -v %s --output-file /dev/null 2> %s", fname2, tempfile_ptxinfo); + printf("GPGPU-Sim PTX: generating ptxinfo using \"%s\"\n", commandline); + result = system(commandline); + if( result != 0 ) { + printf("GPGPU-Sim PTX: ERROR ** while loading PTX (b) %d\n", result); + printf(" Ensure ptxas is in your path.\n"); + exit(1); + } + + ptxinfo_in = fopen(tempfile_ptxinfo,"r"); + g_ptxinfo_filename = tempfile_ptxinfo; + ptxinfo_parse(); + snprintf(commandline,1024,"rm -f %s %s %s", fname, fname2, tempfile_ptxinfo); + printf("GPGPU-Sim PTX: removing ptxinfo using \"%s\"\n", commandline); + result = system(commandline); + if( result != 0 ) { + printf("GPGPU-Sim PTX: ERROR ** while loading PTX (c) %d\n", result); + exit(1); + } + g_filename = NULL; +} + +void gpgpu_ptx_assemble( std::string kname, void *kinfo ) +{ + function_info *func_info = (function_info *)kinfo; + g_func_info = func_info; + g_current_symbol_table = g_kernel_name_to_symtab_lookup[ kname ]; + if( g_current_symbol_table == NULL ) { + printf("\nGPGPU-Sim PTX: ERROR no information for kernel \'%s\'\n" + " this can happen for kernels contained in CUDA\n" + " libraries (such as CUBLAS, CUFFT, or CUDPP)\n", kname.c_str() ); + exit(1); + } + + func_info->ptx_assemble(); +} + +void gpgpu_ptx_sim_load_gpu_kernels() +{ + ptx_in = NULL; + if ( g_filename ) + ptx_in = fopen( g_filename, "r" ); + static unsigned source_num = 0; + gpgpu_ptx_sim_init_memory(); + if (ptx_in) { + init_parser(); + ptx_parse(); + ptxinfo_in = open_ptxinfo(g_filename); + ptxinfo_parse(); + load_static_globals(g_global_symbol_table,0x10000000,0xFFFFFFFF); + load_constants(g_global_symbol_table); + } else { + if (!g_override_embedded_ptx) { + g_used_embedded_ptx_files=1; + printf("GPGPU-Sim PTX: USING EMBEDDED .ptx files...\n"); + ptx_info_t *s; + for ( s=g_ptx_source_array; s!=NULL; s=s->next ) { + gpgpu_ptx_sim_load_ptx_from_string(s->str, ++source_num); + load_static_globals(g_global_symbol_table,0x10000000,0xFFFFFFFF); + load_constants(g_global_symbol_table); + } + } else { + g_filename = NULL; + struct dirent **namelist; + int n; + + n = scandir(".", &namelist, ptx_file_filter, alphasort); + if (n < 0) + perror("scandir"); + else { + while (n--) { + if ( g_filename != NULL ) { + printf("Loader error: support for multiple .ptx files not yet enabled\n"); + abort(); + } + g_filename = strdup(namelist[n]->d_name); + printf("Parsing %s..\n", g_filename); + ptx_in = fopen( g_filename, "r" ); + free(namelist[n]); + init_parser(); + ptx_parse (); + ptxinfo_in = open_ptxinfo(g_filename); + ptxinfo_parse(); + g_filename = NULL; + load_static_globals(g_global_symbol_table,0x10000000,0xFFFFFFFF); + load_constants(g_global_symbol_table); + } + free(namelist); + } + } + } + + if ( ptx_in == NULL && g_override_embedded_ptx ) { + printf("GPGPU-Sim PTX Simulator error: Could find/open .ptx file for reading\n"); + printf(" This means there are no .ptx files in the current directory.\n"); + printf(" Either place a .ptx file in the current directory, or ensure\n" ); + printf(" the PTX_SIM_KERNELFILE environment variable points to .ptx file.\n"); + printf(" PTX_SIM_KERNELFILE=\"%s\"\n", g_filename ); + exit(1); + } + + if ( g_error_detected ) { + printf( "GPGPU-Sim PTX: Program parsing completed: Errors detected.\n" ); + exit(1); + } else { + printf( "GPGPU-Sim PTX: Program parsing completed (max %u registers used per thread).\n", g_max_regs_per_thread ); + } + + if ( g_kernel_name_to_function_lookup ) { + for ( std::map<std::string,function_info*>::iterator f=g_kernel_name_to_function_lookup->begin(); + f != g_kernel_name_to_function_lookup->end(); f++ ) { + gpgpu_ptx_assemble(f->first,f->second); + } + } +} + +extern time_t simulation_starttime; + +ptx_cta_info *g_func_cta_info = NULL; + +#define MAX(a,b) (((a)>(b))?(a):(b)) + +void gpgpu_ptx_sim_main_func( const char *kernel_key, dim3 gridDim, dim3 blockDim, struct gpgpu_ptx_sim_arg *args) +{ + printf("GPGPU-Sim: Performing Functional Simulation...\n"); + + printf("ERROR: Need to derived core_t for functional simulation, functional simulation no longer operational\n"); + // also: need PDOM stack, etc... for functional simulation + exit(1); + + time_t end_time, elapsed_time, days, hrs, minutes, sec; + int i1, i2, i3, i4, o1, o2, o3, o4; + int vectorin, vectorout; + + gpgpu_ptx_sim_init_grid(kernel_key, args,gridDim,blockDim); + + memory_space *shared_mem = new memory_space_impl<16*1024>("shared",4); + + std::map<unsigned,memory_space*> lm_lookup; + + if ( g_func_cta_info == NULL ) + g_func_cta_info = new ptx_cta_info(0); + + for ( unsigned gx=0; gx < gridDim.x; gx++ ) { + for ( unsigned gy=0; gy < gridDim.y; gy++ ) { + for ( unsigned gz=0; gz < gridDim.z; gz++ ) { + std::list<ptx_thread_info *> active_threads; + std::list<ptx_thread_info *> blocked_threads; + + g_func_cta_info->check_cta_thread_status_and_reset(); + + for ( unsigned tx=0; tx < blockDim.x; tx++ ) { + for ( unsigned ty=0; ty < blockDim.y; ty++ ) { + for ( unsigned tz=0; tz < blockDim.z; tz++ ) { + memory_space *local_mem = NULL; + ptx_thread_info *thd = new ptx_thread_info(); + + unsigned lm_idx = blockDim.x*blockDim.y*tz + blockDim.x * ty + tx; + std::map<unsigned,memory_space*>::iterator lm=lm_lookup.find(lm_idx); + if ( lm == lm_lookup.end() ) { + char buf[1024]; + snprintf(buf,1024,"local_(%u,%u,%u)", tx, ty, tz ); + local_mem = new memory_space_impl<32>(buf,32); + lm_lookup[lm_idx] = local_mem; + } else { + local_mem = lm->second; + } + + + thd->set_info(g_current_symbol_table,g_func_info); + thd->set_nctaid(gridDim.x,gridDim.y,gridDim.z); + thd->set_ntid(blockDim.x, blockDim.y, blockDim.z); + thd->set_ctaid(gx,gy,gz); + thd->set_tid(tx,ty,tz); + thd->set_valid(); + thd->m_shared_mem = shared_mem; + thd->m_local_mem = local_mem; + thd->m_cta_info = g_func_cta_info; + g_func_cta_info->add_thread(thd); + active_threads.push_back(thd); + } + } + } + + while ( !(active_threads.empty() && blocked_threads.empty()) ) { + // while there are still threads left to execute in this CTA + ptx_thread_info *thread = NULL; + + if ( !active_threads.empty() ) { + thread = active_threads.front(); + active_threads.pop_front(); + } else { + active_threads = blocked_threads; + blocked_threads.clear(); + std::list<ptx_thread_info *>::iterator a=active_threads.begin(); + for ( ; a != active_threads.end(); a++ ) { + ptx_thread_info *thd = *a; + thd->clear_barrier(); + } + g_func_cta_info->release_barrier(); + } + + while ( thread != NULL ) { + if ( thread->is_at_barrier() ) { + blocked_threads.push_back(thread); + thread = NULL; + break; + } + if ( thread->is_done() ) { + thread->m_cta_info->register_deleted_thread(thread); + delete thread; + thread = NULL; + break; + } + + unsigned op_type; + addr_t addr; + unsigned space; + int arch_reg[MAX_REG_OPERANDS] = { -1 }; + unsigned data_size; + dram_callback_t callback; + unsigned warp_active_mask = (unsigned)-1; // vote instruction with diverged warps won't execute correctly + // in functional simulation mode + + g_func_info->ptx_decode_inst( thread, &op_type, &i1, &i2, &i3, &i4, &o1, &o2, &o3, &o4, &vectorin, &vectorout, arch_reg ); + g_func_info->ptx_exec_inst( thread, &addr, &space, &data_size, &callback, warp_active_mask ); + } + } + } + } + } + printf( "GPGPU-Sim: Done functional simulation (%u instructions simulated).\n", g_ptx_sim_num_insn ); + if ( gpgpu_ptx_instruction_classification ) { + StatDisp( g_inst_classification_stat[g_ptx_kernel_count]); + StatDisp ( g_inst_op_classification_stat[g_ptx_kernel_count]); + } + end_time = time((time_t *)NULL); + elapsed_time = MAX(end_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)); + + fflush(stderr); + printf("\n\ngpgpu_simulation_time = %u days, %u hrs, %u min, %u sec (%u sec)\n", + (unsigned)days, (unsigned)hrs, (unsigned)minutes, (unsigned)sec, (unsigned)elapsed_time ); + printf("gpgpu_simulation_rate = %u (inst/sec)\n", (unsigned)(g_ptx_sim_num_insn / elapsed_time) ); + fflush(stdout); +} + +void ptx_decode_inst( void *thd, unsigned *op, int *i1, int *i2, int *i3, int *i4, int *o1, int *o2, int *o3, int *o4, int *vectorin, int *vectorout, int *arch_reg ) +{ + *op = NO_OP; + *o1 = 0; + *o2 = 0; + *o3 = 0; + *o4 = 0; + *i1 = 0; + *i2 = 0; + *i3 = 0; + *i4 = 0; + *vectorin = 0; + *vectorout = 0; + std::fill_n(arch_reg, MAX_REG_OPERANDS, -1); + + if ( thd == NULL ) + return; + + ptx_thread_info *thread = (ptx_thread_info *) thd; + g_func_info = thread->func_info(); + g_func_info->ptx_decode_inst(thread,op,i1,i2,i3,i4,o1,o2,o3,o4,vectorin,vectorout,arch_reg); +} + +unsigned ptx_get_inst_op( void *thd) +{ + if ( thd == NULL ) + return NO_OP; + + ptx_thread_info *thread = (ptx_thread_info *) thd; + return(thread->func_info())->ptx_get_inst_op(thread); +} + +void ptx_exec_inst( void *thd, address_type *addr, unsigned *space, unsigned *data_size, dram_callback_t* callback, unsigned warp_active_mask ) +{ + if ( thd == NULL ) + return; + ptx_thread_info *thread = (ptx_thread_info *) thd; + g_func_info = thread->func_info(); + g_func_info->ptx_exec_inst( thread, addr, space, data_size, callback, warp_active_mask ); +} + +void ptx_dump_regs( void *thd ) +{ + if ( thd == NULL ) + return; + ptx_thread_info *t = (ptx_thread_info *) thd; + t->dump_regs(); +} + +unsigned ptx_set_tex_cache_linesize(unsigned linesize) +{ + g_texcache_linesize = linesize; + return 0; +} + +unsigned ptx_kernel_program_size() +{ + return g_func_info->get_function_size(); +} + +unsigned translate_pc_to_ptxlineno(unsigned pc) +{ + // this function assumes that the kernel fits inside a single PTX file + // function_info *pFunc = g_func_info; // assume that the current kernel is the one in query + const ptx_instruction *pInsn = function_info::pc_to_instruction(pc); + unsigned ptx_line_number = pInsn->source_line(); + + return ptx_line_number; +} + +int g_ptxinfo_error_detected; + + +static char *g_ptxinfo_kname = NULL; +static struct gpgpu_ptx_sim_kernel_info g_ptxinfo_kinfo; + +extern "C" void ptxinfo_function(const char *fname ) +{ + g_ptxinfo_kinfo.regs=0; + g_ptxinfo_kinfo.lmem=0; + g_ptxinfo_kinfo.smem=0; + g_ptxinfo_kinfo.cmem=0; + g_ptxinfo_kname = strdup(fname); +} + +extern "C" void ptxinfo_regs( unsigned nregs ) +{ + g_ptxinfo_kinfo.regs=nregs; +} + +extern "C" void ptxinfo_lmem( unsigned declared, unsigned system ) +{ + g_ptxinfo_kinfo.lmem=declared+system; +} + +extern "C" void ptxinfo_smem( unsigned declared, unsigned system ) +{ + g_ptxinfo_kinfo.smem=declared+system; +} + +extern "C" void ptxinfo_cmem( unsigned nbytes, unsigned bank ) +{ + g_ptxinfo_kinfo.cmem+=nbytes; +} + +extern "C" void ptxinfo_addinfo() +{ + if ( g_kernel_name_to_function_lookup ) { + std::map<std::string,function_info*>::iterator i=g_kernel_name_to_function_lookup->find(g_ptxinfo_kname); + if ( (g_kernel_name_to_function_lookup == NULL) || (i == g_kernel_name_to_function_lookup->end()) ) { + printf ("GPGPU-Sim PTX: Kernel '%s' in %s not found. Ignoring.\n", g_ptxinfo_kname, g_filename); + } else { + printf ("GPGPU-Sim PTX: Kernel %s\n", g_ptxinfo_kname); + function_info *fi = i->second; + fi->set_kernel_info(&g_ptxinfo_kinfo); + } + } else { + printf ("GPGPU-Sim PTX: Kernel '%s' in %s not found (no kernels registered).\n", g_ptxinfo_kname, g_filename); + } + + free(g_ptxinfo_kname); + g_ptxinfo_kname=NULL; + g_ptxinfo_kinfo.regs=0; + g_ptxinfo_kinfo.lmem=0; + g_ptxinfo_kinfo.smem=0; + g_ptxinfo_kinfo.cmem=0; +} + +void dwf_insert_reconv_pt(address_type pc); + +struct rec_pts { + gpgpu_recon_t *s_kernel_recon_points; + int s_num_recon; +}; + +struct std::map<function_info*,rec_pts> g_rpts; + +struct rec_pts find_reconvergence_points( function_info *finfo ) +{ + rec_pts tmp; + std::map<function_info*,rec_pts>::iterator r=g_rpts.find(finfo); + + if( r==g_rpts.end() ) { + int num_recon = finfo->get_num_reconvergence_pairs(); + + gpgpu_recon_t *kernel_recon_points = (struct gpgpu_recon_t*) calloc(num_recon, sizeof(struct gpgpu_recon_t)); + finfo->get_reconvergence_pairs(kernel_recon_points); + printf("Reconvergence Pairs for %s\n", finfo->get_name().c_str() ); + for (int i=0;i<num_recon;i++) + printf("%d\t%d\n", kernel_recon_points[i].source_pc, kernel_recon_points[i].target_pc); + tmp.s_kernel_recon_points = kernel_recon_points; + tmp.s_num_recon = num_recon; + g_rpts[finfo] = tmp; + } else { + tmp = r->second; + } + return tmp; +} + +unsigned int get_converge_point( unsigned int pc, void *thd ) +{ + // the branch could encode the reconvergence point and/or a bit that indicates the + // reconvergence point is the return PC on the call stack in the case the branch has + // no immediate postdominator in the function (i.e., due to multiple return points). + + std::map<unsigned,function_info*>::iterator f=g_pc_to_finfo.find(pc); + assert( f != g_pc_to_finfo.end() ); + function_info *finfo = f->second; + rec_pts tmp = find_reconvergence_points(finfo); + + int i=0; + for (; i < tmp.s_num_recon; ++i) { + if (tmp.s_kernel_recon_points[i].source_pc == pc) { + if( tmp.s_kernel_recon_points[i].target_pc == (unsigned) -2 ) { + // function call return + ptx_thread_info *the_thread = (ptx_thread_info*)thd; + assert( the_thread != NULL ); + return the_thread->get_return_PC(); + } else { + return tmp.s_kernel_recon_points[i].target_pc; + } + } + } + assert(i < tmp.s_num_recon); + abort(); // returning garbage! +} + +void find_reconvergence_points() +{ + find_reconvergence_points(g_func_info); +} + +void dwf_process_reconv_pts() +{ + rec_pts tmp = find_reconvergence_points(g_func_info); + for (int i = 0; i < tmp.s_num_recon; ++i) { + dwf_insert_reconv_pt(tmp.s_kernel_recon_points[i].target_pc); + } +} + +void *gpgpusim_opencl_getkernel_Object( const char *kernel_name ) +{ + std::map<std::string,function_info*>::iterator i=g_kernel_name_to_function_lookup->find(kernel_name); + + if( i == g_kernel_name_to_function_lookup->end() ) { + abort(); + return NULL; + } + return i->second; +} |
