// 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 #endif #else #include "config.h" #include #include #endif #include "coproc.h" #include "file_names.h" #include "util.h" #include "str_replace.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; static char* client_path; 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); 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()); } // TODO: write OpenCL info for CPU when implemented: // gstate.host_info.have_cpu_opencl // gstate.host_info.cpu_opencl_prop 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 ati_gpu; COPROC_NVIDIA nvidia_gpu; COPROC_INTEL intel_gpu; OPENCL_DEVICE_PROP ati_opencl; OPENCL_DEVICE_PROP nvidia_opencl; OPENCL_DEVICE_PROP intel_gpu_opencl; ati_gpus.clear(); nvidia_gpus.clear(); intel_gpus.clear(); ati_opencls.clear(); nvidia_opencls.clear(); intel_gpu_opencls.clear(); f = 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 = ati_gpu.parse(xp); if (retval) { ati_gpu.clear(); } else { ati_gpu.device_num = ati_gpus.size(); ati_gpus.push_back(ati_gpu); } continue; } if (xp.match_tag("coproc_cuda")) { retval = nvidia_gpu.parse(xp); if (retval) { nvidia_gpu.clear(); } else { nvidia_gpu.device_num = nvidia_gpus.size(); nvidia_gpu.pci_info = nvidia_gpu.pci_infos[0]; memset(&nvidia_gpu.pci_infos[0], 0, sizeof(struct PCI_INFO)); nvidia_gpus.push_back(nvidia_gpu); } continue; } if (xp.match_tag("coproc_intel_gpu")) { retval = intel_gpu.parse(xp); if (retval) { intel_gpu.clear(); } else { intel_gpu.device_num = nvidia_gpus.size(); intel_gpus.push_back(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.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 dir[MAXPATHLEN]; int i; int retval = 0; boinc_delete_file(COPROC_INFO_FILENAME); boinc_getcwd(dir); int argc = 3; char* const argv[3] = { const_cast("boinc"), const_cast("--detect_gpus"), const_cast("") }; retval = run_program( dir, client_path, argc, argv, 0, prog ); if (retval) return retval; // Wait for child to run and exit for (i=0; i<300; ++i) { if (process_exists(prog)) break; if (boinc_file_exists(COPROC_INFO_FILENAME)) break; boinc_sleep(0.01); } for (i=0; i<300; ++i) { if (!process_exists(prog)) break; boinc_sleep(0.01); } return 0; }