// This file is part of BOINC. // http://boinc.berkeley.edu // Copyright (C) 2009 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License // as published by the Free Software Foundation, // either version 3 of the License, or (at your option) any later version. // // BOINC is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with BOINC. If not, see . // client-specific GPU code. Mostly GPU detection #define USE_CHILD_PROCESS_TO_DETECT_GPUS 1 #include "cpp.h" #ifdef _WIN32 #include "boinc_win.h" #ifdef _MSC_VER #define snprintf _snprintf #define chdir _chdir #endif #else #include "config.h" #include #include #endif #include "coproc.h" #include "file_names.h" #include "util.h" #include "str_replace.h" #include "client_msgs.h" #include "client_state.h" using std::string; using std::vector; #ifndef _WIN32 jmp_buf resume; void segv_handler(int) { longjmp(resume, 1); } #endif vector ati_gpus; vector nvidia_gpus; vector intel_gpus; vector ati_opencls; vector nvidia_opencls; vector intel_gpu_opencls; vector cpu_opencls; static char* client_path; static char client_dir[MAXPATHLEN]; void COPROCS::get( bool use_all, vector&descs, vector&warnings, IGNORE_GPU_INSTANCE& ignore_gpu_instance ) { #if USE_CHILD_PROCESS_TO_DETECT_GPUS int retval = 0; char buf[256]; retval = launch_child_process_to_detect_gpus(); if (retval) { snprintf(buf, sizeof(buf), "launch_child_process_to_detect_gpus() returned error %d", retval ); warnings.push_back(buf); } retval = read_coproc_info_file(warnings); if (retval) { snprintf(buf, sizeof(buf), "read_coproc_info_file() returned error %d", retval ); warnings.push_back(buf); } #else detect_gpus(warnings); #endif correlate_gpus(use_all, descs, ignore_gpu_instance); } void COPROCS::detect_gpus(std::vector &warnings) { #ifdef _WIN32 try { nvidia.get(warnings); } catch (...) { warnings.push_back("Caught SIGSEGV in NVIDIA GPU detection"); } try { ati.get(warnings); } catch (...) { warnings.push_back("Caught SIGSEGV in ATI GPU detection"); } try { intel_gpu.get(warnings); } catch (...) { warnings.push_back("Caught SIGSEGV in INTEL GPU detection"); } try { // OpenCL detection must come last get_opencl(warnings); } catch (...) { warnings.push_back("Caught SIGSEGV in OpenCL detection"); } #else void (*old_sig)(int) = signal(SIGSEGV, segv_handler); if (setjmp(resume)) { warnings.push_back("Caught SIGSEGV in NVIDIA GPU detection"); } else { nvidia.get(warnings); } #ifndef __APPLE__ // ATI does not yet support CAL on Macs if (setjmp(resume)) { warnings.push_back("Caught SIGSEGV in ATI GPU detection"); } else { ati.get(warnings); } #endif if (setjmp(resume)) { warnings.push_back("Caught SIGSEGV in INTEL GPU detection"); } else { intel_gpu.get(warnings); } if (setjmp(resume)) { warnings.push_back("Caught SIGSEGV in OpenCL detection"); } else { // OpenCL detection must come last get_opencl(warnings); } signal(SIGSEGV, old_sig); #endif } void COPROCS::correlate_gpus( bool use_all, std::vector &descs, IGNORE_GPU_INSTANCE &ignore_gpu_instance ) { unsigned int i; char buf[256], buf2[256]; nvidia.correlate(use_all, ignore_gpu_instance[PROC_TYPE_NVIDIA_GPU]); ati.correlate(use_all, ignore_gpu_instance[PROC_TYPE_AMD_GPU]); intel_gpu.correlate(use_all, ignore_gpu_instance[PROC_TYPE_AMD_GPU]); correlate_opencl(use_all, ignore_gpu_instance); // NOTE: OpenCL can report a max of only 4GB. for (i=0; i &warnings) { MIOFILE mf; unsigned int i, temp; FILE* f; f = boinc_fopen(COPROC_INFO_FILENAME, "wb"); if (!f) return ERR_FOPEN; mf.init_file(f); mf.printf(" \n"); for (i=0; i%s\n", warnings[i].c_str()); } mf.printf(" \n"); fclose(f); return 0; } int COPROCS::read_coproc_info_file(vector &warnings) { MIOFILE mf; int retval; FILE* f; string s; COPROC_ATI my_ati_gpu; COPROC_NVIDIA my_nvidia_gpu; COPROC_INTEL my_intel_gpu; OPENCL_DEVICE_PROP ati_opencl; OPENCL_DEVICE_PROP nvidia_opencl; OPENCL_DEVICE_PROP intel_gpu_opencl; OPENCL_CPU_PROP cpu_opencl; ati_gpus.clear(); nvidia_gpus.clear(); intel_gpus.clear(); ati_opencls.clear(); nvidia_opencls.clear(); intel_gpu_opencls.clear(); cpu_opencls.clear(); f = boinc_fopen(COPROC_INFO_FILENAME, "r"); if (!f) return ERR_FOPEN; XML_PARSER xp(&mf); mf.init_file(f); if (!xp.parse_start("coprocs")) { fclose(f); return ERR_XML_PARSE; } while (!xp.get_tag()) { if (xp.match_tag("/coprocs")) { fclose(f); return 0; } if (xp.match_tag("coproc_ati")) { retval = my_ati_gpu.parse(xp); if (retval) { my_ati_gpu.clear(); } else { my_ati_gpu.device_num = ati_gpus.size(); ati_gpus.push_back(my_ati_gpu); } continue; } if (xp.match_tag("coproc_cuda")) { retval = my_nvidia_gpu.parse(xp); if (retval) { my_nvidia_gpu.clear(); } else { my_nvidia_gpu.device_num = nvidia_gpus.size(); my_nvidia_gpu.pci_info = my_nvidia_gpu.pci_infos[0]; memset(&my_nvidia_gpu.pci_infos[0], 0, sizeof(struct PCI_INFO)); nvidia_gpus.push_back(my_nvidia_gpu); } continue; } if (xp.match_tag("coproc_intel_gpu")) { retval = my_intel_gpu.parse(xp); if (retval) { my_intel_gpu.clear(); } else { my_intel_gpu.device_num = intel_gpus.size(); intel_gpus.push_back(my_intel_gpu); } continue; } if (xp.match_tag("ati_opencl")) { memset(&ati_opencl, 0, sizeof(ati_opencl)); retval = ati_opencl.parse(xp, "/ati_opencl"); if (retval) { memset(&ati_opencl, 0, sizeof(ati_opencl)); } else { ati_opencl.is_used = COPROC_IGNORED; ati_opencls.push_back(ati_opencl); } continue; } if (xp.match_tag("nvidia_opencl")) { memset(&nvidia_opencl, 0, sizeof(nvidia_opencl)); retval = nvidia_opencl.parse(xp, "/nvidia_opencl"); if (retval) { memset(&nvidia_opencl, 0, sizeof(nvidia_opencl)); } else { nvidia_opencl.is_used = COPROC_IGNORED; nvidia_opencls.push_back(nvidia_opencl); } continue; } if (xp.match_tag("intel_gpu_opencl")) { memset(&intel_gpu_opencl, 0, sizeof(intel_gpu_opencl)); retval = intel_gpu_opencl.parse(xp, "/intel_gpu_opencl"); if (retval) { memset(&intel_gpu_opencl, 0, sizeof(intel_gpu_opencl)); } else { intel_gpu_opencl.is_used = COPROC_IGNORED; intel_gpu_opencls.push_back(intel_gpu_opencl); } continue; } if (xp.match_tag("opencl_cpu_prop")) { memset(&cpu_opencl, 0, sizeof(cpu_opencl)); retval = cpu_opencl.parse(xp); if (retval) { memset(&cpu_opencl, 0, sizeof(cpu_opencl)); } else { cpu_opencl.opencl_prop.is_used = COPROC_IGNORED; cpu_opencls.push_back(cpu_opencl); } continue; } if (xp.parse_string("warning", s)) { warnings.push_back(s); continue; } // TODO: parse OpenCL info for CPU when implemented: // gstate.host_info.have_cpu_opencl // gstate.host_info.cpu_opencl_prop } fclose(f); return ERR_XML_PARSE; } int COPROCS::launch_child_process_to_detect_gpus() { #ifdef _WIN32 HANDLE prog; #else int prog; #endif char quotedDataDir[MAXPATHLEN+2]; char dataDir[MAXPATHLEN]; int retval = 0; retval = boinc_delete_file(COPROC_INFO_FILENAME); if (retval) { msg_printf(0, MSG_INFO, "Failed to delete old %s. error code %d", COPROC_INFO_FILENAME, retval ); } else { for (;;) { if (!boinc_file_exists(COPROC_INFO_FILENAME)) break; boinc_sleep(0.01); } } boinc_getcwd(dataDir); #ifdef _WIN32 strlcpy(quotedDataDir, "\"", sizeof(quotedDataDir)); strlcat(quotedDataDir, dataDir, sizeof(quotedDataDir)); strlcat(quotedDataDir, "\"", sizeof(quotedDataDir)); #else strlcpy(quotedDataDir, dataDir, sizeof(quotedDataDir)); #endif if (log_flags.coproc_debug) { msg_printf(0, MSG_INFO, "[coproc] launching child process at %s", client_path ); msg_printf(0, MSG_INFO, "[coproc] relative to directory %s", client_dir ); msg_printf(0, MSG_INFO, "[coproc] with data directory %s", quotedDataDir ); } int argc = 4; char* const argv[5] = { const_cast("boinc"), const_cast("--detect_gpus"), const_cast("--dir"), const_cast(quotedDataDir), NULL }; chdir(client_dir); retval = run_program( client_dir, client_path, argc, argv, 0, prog ); chdir(dataDir); if (retval) { if (log_flags.coproc_debug) { msg_printf(0, MSG_INFO, "[coproc] run_program of child process returned error %d", retval ); } return retval; } retval = get_exit_status(prog); if (retval) { msg_printf(0, MSG_INFO, "GPU detection failed. error code %d", retval ); } return 0; }