summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libcuda/cuda_runtime_api.cc237
-rw-r--r--src/cuda-sim/ptx_loader.cc147
-rw-r--r--src/cuda-sim/ptx_loader.h1
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 );