diff options
| -rw-r--r-- | libcuda/cuda_runtime_api.cc | 237 | ||||
| -rw-r--r-- | src/cuda-sim/ptx_loader.cc | 147 | ||||
| -rw-r--r-- | src/cuda-sim/ptx_loader.h | 1 |
3 files changed, 246 insertions, 139 deletions
diff --git a/libcuda/cuda_runtime_api.cc b/libcuda/cuda_runtime_api.cc index 948d81d..f74c4eb 100644 --- a/libcuda/cuda_runtime_api.cc +++ b/libcuda/cuda_runtime_api.cc @@ -145,6 +145,8 @@ #include <mach-o/dyld.h> #endif +int no_of_ptx=0; + extern void synchronize(); extern void exit_simulation(); @@ -1394,6 +1396,26 @@ std::string get_app_binary(){ return self_exe_path; } +//above func gives abs path whereas this give just the name of application. +char* get_app_binary_name(std::string abs_path){ + char *self_exe_path; +#ifdef __APPLE__ + //TODO: get apple device and check the result. + printf("WARNING: not tested for Apple-mac devices \n"); + abort(); +#else + char* buf = strdup(abs_path.c_str()); + char *token = strtok(buf, "/"); + while(token !=NULL){ + self_exe_path = token; + token = strtok(NULL,"/"); + } +#endif + self_exe_path = strtok(self_exe_path, "."); + printf("self exe links to: %s\n", self_exe_path); + return self_exe_path; +} + //! Call cuobjdump to extract everything (-elf -sass -ptx) /*! * This Function extract the whole PTX (for all the files) using cuobjdump @@ -1402,114 +1424,152 @@ std::string get_app_binary(){ * It is also responsible for extracting the libraries linked to the binary if the option is * enabled * */ - void extract_code_using_cuobjdump(){ CUctx_st *context = GPGPUSim_Context(); + unsigned forced_max_capability = context->get_device()->get_gpgpu()->get_config().get_forced_max_capability(); + //prevent the dumping by cuobjdump everytime we execute the code! const char *override_cuobjdump = getenv("CUOBJDUMP_SIM_FILE"); - + char command[1000], ptx_file[1000]; + std::string app_binary = get_app_binary(); + //Running cuobjdump using dynamic link to current process + snprintf(command,1000,"md5sum %s ", app_binary.c_str()); + printf("Running md5sum using \"%s\"\n", command); + system(command); + // Running cuobjdump using dynamic link to current process + // Needs the option '-all' to extract PTX from CDP-enabled binary + extern bool g_cdp_enabled; + + //dump ptx for all individial ptx files into sepearte files which is later used by ptxas. + char fname2[1024]; + snprintf(fname2,1024,"_cuobjdump_list_ptx_XXXXXX"); + int fd2=mkstemp(fname2); + close(fd2); + snprintf(command,1000,"$CUDA_INSTALL_PATH/bin/cuobjdump -lptx -arch=sm_%u %s > %s", forced_max_capability, app_binary.c_str(), fname2); + int result = system(command); + if( result != 0 ) { + printf("WARNING: Failed to execute cuobjdump to get list of ptx files \n"); + exit(0); + } else { + /* + as we got list of ptx files, we need to extract one by one into seperate files so that ptxas can understand it. + In this way, the duplicate definitions in a single embedded file can be prevented. + No of lines in the file is equal to no of ptx fileis available. + */ + FILE *fp = fopen(fname2,"r"); + if (fp==NULL) { + printf("WARNING: cuobjdump file error! Could not open file %s \n", fname2); + exit(0); + } else { + for (char c = getc(fp); c != EOF; c = getc(fp)) + if (c == '\n') + no_of_ptx = no_of_ptx + 1; + fclose(fp); + } + } + //based on the list above, dump ptx files individually. Format of dumped ptx file is prog_name.unique_no.sm_<>.ptx + for (int index=1; index<= no_of_ptx; index++){ + snprintf(ptx_file, 1000, "%s.%d.sm_%u.ptx", get_app_binary_name(app_binary), index, forced_max_capability); + printf("Extracting specific PTX file named %s \n",ptx_file); + snprintf(command,1000,"$CUDA_INSTALL_PATH/bin/cuobjdump -arch=sm_%u -xptx %s %s", forced_max_capability, ptx_file, app_binary.c_str()); + if (system(command)!=0) { + printf("ERROR: command: %s failed \n",command); + exit(0); + } + } + //TODO: redundant to dump twice. how can it be prevented? + //dump only for specific arch char fname[1024]; if ((override_cuobjdump == NULL) || (strlen(override_cuobjdump)==0)) { - char command[1000]; - std::string app_binary = get_app_binary(); - snprintf(fname,1024,"_cuobjdump_complete_output_XXXXXX"); int fd=mkstemp(fname); close(fd); - // Running cuobjdump using dynamic link to current process - snprintf(command,1000,"md5sum %s ", app_binary.c_str()); - printf("Running md5sum using \"%s\"\n", command); - system(command); - // Running cuobjdump using dynamic link to current process - // Needs the option '-all' to extract PTX from CDP-enabled binary - extern bool g_cdp_enabled; - //dump only for specific arch - TODO: will it save memory? if(!g_cdp_enabled) - snprintf(command,1000,"$CUDA_INSTALL_PATH/bin/cuobjdump -ptx -elf -sass -arch=sm_60 %s > %s", app_binary.c_str(), fname); + snprintf(command,1000,"$CUDA_INSTALL_PATH/bin/cuobjdump -ptx -elf -sass -arch=sm_%u %s > %s", forced_max_capability, app_binary.c_str(), fname); else - snprintf(command,1000,"$CUDA_INSTALL_PATH/bin/cuobjdump -ptx -elf -sass -arch=sm_60 -all %s > %s", app_binary.c_str(), fname); + snprintf(command,1000,"$CUDA_INSTALL_PATH/bin/cuobjdump -ptx -elf -sass -arch=sm_%u -all %s > %s", forced_max_capability, app_binary.c_str(), fname); bool parse_output = true; - int result = system(command); + result = system(command); if(result) { - if (context->get_device()->get_gpgpu()->get_config().experimental_lib_support() && (result == 65280)) { - // Some CUDA application may exclusively use kernels provided by CUDA - // libraries (e.g. CUBLAS). Skipping cuobjdump extraction from the - // executable for this case. - // 65280 is the return code from cuobjdump denoting the specific error (tested on CUDA 4.0/4.1/4.2) - printf("WARNING: Failed to execute: %s\n", command); - printf(" Executable binary does not contain any GPU kernel.\n"); - parse_output = false; - } else { - printf("ERROR: Failed to execute: %s\n", command); - exit(1); - } - } + if (context->get_device()->get_gpgpu()->get_config().experimental_lib_support() && (result == 65280)) { + // Some CUDA application may exclusively use kernels provided by CUDA + // libraries (e.g. CUBLAS). Skipping cuobjdump extraction from the + // executable for this case. + // 65280 is the return code from cuobjdump denoting the specific error (tested on CUDA 4.0/4.1/4.2) + printf("WARNING: Failed to execute: %s\n", command); + printf(" Executable binary does not contain any GPU kernel.\n"); + parse_output = false; + } else { + printf("ERROR: Failed to execute: %s\n", command); + exit(1); + } + } - if (parse_output) { - printf("Parsing file %s\n", fname); - cuobjdump_in = fopen(fname, "r"); + if (parse_output) { + printf("Parsing file %s\n", fname); + cuobjdump_in = fopen(fname, "r"); - cuobjdump_parse(); - fclose(cuobjdump_in); - printf("Done parsing!!!\n"); - } else { - printf("Parsing skipped for %s\n", fname); - } + cuobjdump_parse(); + fclose(cuobjdump_in); + printf("Done parsing!!!\n"); + } else { + printf("Parsing skipped for %s\n", fname); + } - if (context->get_device()->get_gpgpu()->get_config().experimental_lib_support()){ - //Experimental library support - //Currently only for cufft + if (context->get_device()->get_gpgpu()->get_config().experimental_lib_support()){ + //Experimental library support + //Currently only for cufft - std::stringstream cmd; - cmd << "ldd " << app_binary << " | grep $CUDA_INSTALL_PATH | awk \'{print $3}\' > _tempfile_.txt"; - int result = system(cmd.str().c_str()); - if(result){ - std::cout << "Failed to execute: " << cmd << std::endl; - exit(1); - } - std::ifstream libsf; - libsf.open("_tempfile_.txt"); - if(!libsf.is_open()) { - std::cout << "Failed to open: _tempfile_.txt" << std::endl; - exit(1); - } + std::stringstream cmd; + cmd << "ldd " << app_binary << " | grep $CUDA_INSTALL_PATH | awk \'{print $3}\' > _tempfile_.txt"; + int result = system(cmd.str().c_str()); + if(result){ + std::cout << "Failed to execute: " << cmd << std::endl; + exit(1); + } + std::ifstream libsf; + libsf.open("_tempfile_.txt"); + if(!libsf.is_open()) { + std::cout << "Failed to open: _tempfile_.txt" << std::endl; + exit(1); + } - //Save the original section list - std::list<cuobjdumpSection*> tmpsl = cuobjdumpSectionList; - cuobjdumpSectionList.clear(); + //Save the original section list + std::list<cuobjdumpSection*> tmpsl = cuobjdumpSectionList; + cuobjdumpSectionList.clear(); - std::string line; - std::getline(libsf, line); - std::cout << "DOING: " << line << std::endl; - int cnt=1; - while(libsf.good()){ - std::stringstream libcodfn; - libcodfn << "_cuobjdump_complete_lib_" << cnt << "_"; - cmd.str(""); //resetting - cmd << "$CUDA_INSTALL_PATH/bin/cuobjdump -ptx -elf -sass "; - cmd << line; - cmd << " > "; - cmd << libcodfn.str(); - std::cout << "Running cuobjdump on " << line << std::endl; - std::cout << "Using command: " << cmd.str() << std::endl; - result = system(cmd.str().c_str()); - if(result) {printf("ERROR: Failed to execute: %s\n", command); exit(1);} - std::cout << "Done" << std::endl; + std::string line; + std::getline(libsf, line); + std::cout << "DOING: " << line << std::endl; + int cnt=1; + while(libsf.good()){ + std::stringstream libcodfn; + libcodfn << "_cuobjdump_complete_lib_" << cnt << "_"; + cmd.str(""); //resetting + cmd << "$CUDA_INSTALL_PATH/bin/cuobjdump -ptx -elf -sass "; + cmd << line; + cmd << " > "; + cmd << libcodfn.str(); + std::cout << "Running cuobjdump on " << line << std::endl; + std::cout << "Using command: " << cmd.str() << std::endl; + result = system(cmd.str().c_str()); + if(result) {printf("ERROR: Failed to execute: %s\n", command); exit(1);} + std::cout << "Done" << std::endl; - std::cout << "Trying to parse " << libcodfn << std::endl; - cuobjdump_in = fopen(libcodfn.str().c_str(), "r"); - cuobjdump_parse(); - fclose(cuobjdump_in); - std::getline(libsf, line); - } - libSectionList = cuobjdumpSectionList; + std::cout << "Trying to parse " << libcodfn << std::endl; + cuobjdump_in = fopen(libcodfn.str().c_str(), "r"); + cuobjdump_parse(); + fclose(cuobjdump_in); + std::getline(libsf, line); + } + libSectionList = cuobjdumpSectionList; - //Restore the original section list - cuobjdumpSectionList = tmpsl; - } + //Restore the original section list + cuobjdumpSectionList = tmpsl; + } } else { - printf("GPGPU-Sim PTX: overriding cuobjdump with '%s' (CUOBJDUMP_SIM_FILE is set)\n", override_cuobjdump); - snprintf(fname,1024,override_cuobjdump); + printf("GPGPU-Sim PTX: overriding cuobjdump with '%s' (CUOBJDUMP_SIM_FILE is set)\n", override_cuobjdump); + snprintf(fname,1024, "%s",override_cuobjdump); } } @@ -1772,6 +1832,8 @@ void cuobjdumpParseBinary(unsigned int handle){ return; } + //Why to search for capability value if we can directly find it in device info? + #if 0 unsigned max_capability = 0; for ( std::list<cuobjdumpSection*>::iterator iter = cuobjdumpSectionList.begin(); iter != cuobjdumpSectionList.end(); @@ -1780,6 +1842,8 @@ void cuobjdumpParseBinary(unsigned int handle){ if (capability > max_capability) max_capability = capability; } if (max_capability > 20) printf("WARNING: No guarantee that PTX will be parsed for SM version %u\n", max_capability); + #endif + unsigned max_capability = context->get_device()->get_gpgpu()->get_config().get_forced_max_capability(); cuobjdumpPTXSection* ptx = NULL; const char* pre_load = getenv("CUOBJDUMP_SIM_FILE"); @@ -1926,6 +1990,7 @@ void** CUDARTAPI __cudaRegisterFatBinary( void *fatCubin ) return (void**)fat_cubin_handle; } #endif + return 0; } void __cudaUnregisterFatBinary(void **fatCubinHandle) diff --git a/src/cuda-sim/ptx_loader.cc b/src/cuda-sim/ptx_loader.cc index 6c1b595..d98ca07 100644 --- a/src/cuda-sim/ptx_loader.cc +++ b/src/cuda-sim/ptx_loader.cc @@ -32,6 +32,7 @@ #include <unistd.h> #include <dirent.h> #include <fstream> +#include <sstream> /// globals @@ -287,56 +288,87 @@ void fix_duplicate_errors(char fname2[1024]) { } } +//we need the application name here too. +char* get_app_binary_name(){ + char exe_path[1025]; + char *self_exe_path; +#ifdef __APPLE__ + //AMRUTH: get apple device and check the result. + printf("WARNING: not tested for Apple-mac devices \n"); + abort(); +#else + std::stringstream exec_link; + exec_link << "/proc/self/exe"; + ssize_t path_length = readlink(exec_link.str().c_str(), exe_path, 1024); + assert(path_length != -1); + exe_path[path_length] = '\0'; + + char *token = strtok(exe_path, "/"); + while(token !=NULL){ + self_exe_path = token; + token = strtok(NULL,"/"); + } +#endif + self_exe_path = strtok(self_exe_path, "."); + printf("self exe links to: %s\n", self_exe_path); + return self_exe_path; +} + void gpgpu_ptxinfo_load_from_string( const char *p_for_info, unsigned source_num, unsigned sm_version ) { - 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_for_info); - fclose(ptxfile); + //do ptxas for individual files instead of one big embedded ptx. This prevents the duplicate defs and declarations. + char ptx_file[1000]; + char *name=get_app_binary_name(); + char commandline[4096], fname[1024], fname2[1024]; + for (int index=1; index <= no_of_ptx; index++){ + snprintf(ptx_file, 1000, "%s.%d.sm_%u.ptx", name, index, sm_version); + snprintf(fname,1024,"_ptx_XXXXXX"); + int fd=mkstemp(fname); + close(fd); - 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); - printf("Running: %s\n", commandline2); - 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); - } + printf("GPGPU-Sim PTX: extracting embedded .ptx to temporary file \"%s\"\n", fname); + snprintf(commandline,4096,"cat %s > %s",ptx_file, fname); + if (system(commandline) !=0) { + printf("ERROR: %s command failed\n", commandline); + exit(0); + } + + 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); + printf("Running: %s\n", commandline2); + 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]; - char extra_flags[1024]; - extra_flags[0]=0; + char tempfile_ptxinfo[1024]; + snprintf(tempfile_ptxinfo,1024,"%sinfo",fname); + char extra_flags[1024]; + extra_flags[0]=0; -#if CUDART_VERSION >= 3000 - if (sm_version == 0) sm_version = 20; - extern bool g_cdp_enabled; - if(!g_cdp_enabled) - snprintf(extra_flags,1024,"--gpu-name=sm_%u",sm_version); - else - snprintf(extra_flags,1024,"--compile-only --gpu-name=sm_%u",sm_version); -#endif + #if CUDART_VERSION >= 3000 + if (sm_version == 0) sm_version = 20; + extern bool g_cdp_enabled; + if(!g_cdp_enabled) + snprintf(extra_flags,1024,"--gpu-name=sm_%u",sm_version); + else + snprintf(extra_flags,1024,"--compile-only --gpu-name=sm_%u",sm_version); + #endif - snprintf(commandline,1024,"$CUDA_INSTALL_PATH/bin/ptxas %s -v %s --output-file /dev/null 2> %s", + snprintf(commandline,1024,"$CUDA_INSTALL_PATH/bin/ptxas %s -v %s --output-file /dev/null 2> %s", extra_flags, fname2, tempfile_ptxinfo); - printf("GPGPU-Sim PTX: generating ptxinfo using \"%s\"\n", commandline); - result = system(commandline); - if( result != 0 ) { - // 65280 = duplicate errors - if (result == 65280) { - ptxinfo_in = fopen(tempfile_ptxinfo,"r"); + printf("GPGPU-Sim PTX: generating ptxinfo using \"%s\"\n", commandline); + result = system(commandline); + if( result != 0 ) { + // 65280 = duplicate errors + if (result == 65280) { + ptxinfo_in = fopen(tempfile_ptxinfo,"r"); g_ptxinfo_filename = tempfile_ptxinfo; ptxinfo_parse(); @@ -345,26 +377,35 @@ void gpgpu_ptxinfo_load_from_string( const char *p_for_info, unsigned source_num extra_flags, fname2, tempfile_ptxinfo); printf("GPGPU-Sim PTX: regenerating ptxinfo using \"%s\"\n", commandline); result = system(commandline); - } - if (result != 0) { + } + 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); - } + } + } } + //Now that we got resource usage per kernel in a ptx file, we dump all into one file and pass it to rest of the code as usual. + char commandline3[4096]; + char final_tempfile_ptxinfo[1024]; + snprintf(final_tempfile_ptxinfo,1024,"f_tempfile_ptx"); + snprintf(commandline3,4096, "cat *info > %s", final_tempfile_ptxinfo); + if (system(commandline3)!=0) { + printf("ERROR: Either we dont have info files or cat is not working \n"); + printf("ERROR: %s command failed\n",commandline3); + exit(1); + } - ptxinfo_in = fopen(tempfile_ptxinfo,"r"); - g_ptxinfo_filename = tempfile_ptxinfo; + ptxinfo_in = fopen(final_tempfile_ptxinfo,"r"); + g_ptxinfo_filename = final_tempfile_ptxinfo; ptxinfo_parse(); if( ! g_save_embedded_ptx ) { - snprintf(commandline,1024,"rm -f %s %s %s", fname, fname2, tempfile_ptxinfo); + snprintf(commandline,1024,"rm -f %s %s %s *info", fname, fname2, final_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); + if( system(commandline) != 0 ) { + printf("GPGPU-Sim PTX: ERROR ** while removing temporary files\n"); exit(1); } } } - diff --git a/src/cuda-sim/ptx_loader.h b/src/cuda-sim/ptx_loader.h index d3d0c92..a8ecda3 100644 --- a/src/cuda-sim/ptx_loader.h +++ b/src/cuda-sim/ptx_loader.h @@ -30,6 +30,7 @@ #include <string> extern bool g_override_embedded_ptx; +extern int no_of_ptx; //counter to track number of ptx files to be extracted in an application. class symbol_table *gpgpu_ptx_sim_load_ptx_from_string( const char *p, unsigned source_num ); void gpgpu_ptxinfo_load_from_string( const char *p_for_info, unsigned source_num, unsigned sm_version=20 ); |
