// This file is part of BOINC. // http://boinc.berkeley.edu // Copyright (C) 2013 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 . #if defined(_WIN32) && !defined(__STDWX_H__) #include "boinc_win.h" #elif defined(_WIN32) && defined(__STDWX_H__) #include "stdwx.h" #else #ifdef _USING_FCGI_ #include "boinc_fcgi.h" #else #include #endif #include #include #include #endif #ifdef _WIN32 #include "win_util.h" #ifdef _MSC_VER #define snprintf _snprintf #endif #endif #include "miofile.h" #include "parse.h" #include "str_replace.h" #include "util.h" #include "opencl_boinc.h" void OPENCL_DEVICE_PROP::write_xml(MIOFILE& f, const char* tag, bool temp_file) { f.printf( " <%s>\n" " %s\n" " %s\n" " %lu\n" " %d\n" " %llu\n" " %llu\n" " %llu\n" " %d\n" " %llu\n" " %s\n" " %llu\n" " %llu\n" " %lu\n" " %lu\n" " %lu\n" " %lu\n" " %lu\n" " %lu\n" " %lu\n" " %s\n" " %s\n" " %s\n", tag, name, vendor, (unsigned long)vendor_id, available ? 1 : 0, half_fp_config, single_fp_config, double_fp_config, endian_little ? 1 : 0, execution_capabilities, extensions, global_mem_size, local_mem_size, (unsigned long)max_clock_frequency, (unsigned long)max_compute_units, (unsigned long)nv_compute_capability_major, (unsigned long)nv_compute_capability_minor, (unsigned long)amd_simd_per_compute_unit, (unsigned long)amd_simd_width, (unsigned long)amd_simd_instruction_width, opencl_platform_version, opencl_device_version, opencl_driver_version ); if (temp_file) { f.printf( " %d\n" " %f\n" " %f\n" " %d\n" " %d\n", device_num, peak_flops, opencl_available_ram, opencl_device_index, warn_bad_cuda ); } f.printf(" \n", tag); } int OPENCL_DEVICE_PROP::parse(XML_PARSER& xp, const char* end_tag) { int n; unsigned long long ull; while (!xp.get_tag()) { if (xp.match_tag(end_tag)) { get_device_version_int(); get_opencl_driver_revision(); return 0; } if (xp.parse_str("name", name, sizeof(name))) continue; if (xp.parse_str("vendor", vendor, sizeof(vendor))) continue; if (xp.parse_ulonglong("vendor_id", ull)) { vendor_id = ull; continue; } if (xp.parse_int("available", n)) { available = n; continue; } if (xp.parse_ulonglong("half_fp_config", ull)) { half_fp_config = ull; continue; } if (xp.parse_ulonglong("single_fp_config", ull)) { single_fp_config = ull; continue; } if (xp.parse_ulonglong("double_fp_config", ull)) { double_fp_config = ull; continue; } if (xp.parse_int("endian_little", n)) { endian_little = n; continue; } if (xp.parse_ulonglong("execution_capabilities", ull)) { execution_capabilities = ull; continue; } if (xp.parse_str("extensions", extensions, sizeof(extensions) )) { continue; } if (xp.parse_ulonglong("global_mem_size", ull)) { global_mem_size = ull; continue; } if (xp.parse_ulonglong("local_mem_size", ull)) { local_mem_size = ull; continue; } if (xp.parse_int("max_clock_frequency", n)) { max_clock_frequency = n; continue; } if (xp.parse_int("max_compute_units", n)) { max_compute_units = n; continue; } if (xp.parse_int("nv_compute_capability_major", n)) { nv_compute_capability_major = n; continue; } if (xp.parse_int("nv_compute_capability_minor", n)) { nv_compute_capability_minor = n; continue; } if (xp.parse_int("amd_simd_per_compute_unit", n)) { amd_simd_per_compute_unit = n; continue; } if (xp.parse_int("amd_simd_width", n)) { amd_simd_width = n; continue; } if (xp.parse_int("amd_simd_instruction_width", n)) { amd_simd_instruction_width = n; continue; } if (xp.parse_str("opencl_platform_version", opencl_platform_version, sizeof(opencl_platform_version) )) { continue; } if (xp.parse_str("opencl_device_version", opencl_device_version, sizeof(opencl_device_version) )) { continue; } if (xp.parse_str("opencl_driver_version", opencl_driver_version, sizeof(opencl_driver_version) )) { continue; } // The following are used only in the // COPROC_INFO_FILENAME temporary file if (xp.parse_int("device_num", n)) { device_num = n; continue; } if (xp.parse_double("peak_flops", peak_flops)) continue; if (xp.parse_double("opencl_available_ram", opencl_available_ram)) continue; if (xp.parse_int("opencl_device_index", n)) { opencl_device_index = n; continue; } if (xp.parse_bool("warn_bad_cuda", warn_bad_cuda)) continue; } return ERR_XML_PARSE; } int OPENCL_DEVICE_PROP::get_device_version_int() { int maj, min; int n = sscanf( opencl_device_version, "OpenCL %d.%d", &maj, &min ); if (n != 2) { return ERR_NOT_FOUND; } opencl_device_version_int = 100*maj + min; return 0; } int OPENCL_DEVICE_PROP::get_opencl_driver_revision() { // gets the OpenCL runtime revision // Thus far this is only necessary for ATI/AMD because there are bad // driver sets only distinguisable by the runtime library version. // Fortunately this info is in the opencl_device_version string. float rev=0; char *p=opencl_device_version+sizeof(opencl_device_version)-1; // find the last opening bracket while ((p > opencl_device_version) && (*p!='(')) p--; if (p!=opencl_device_version) { int n=sscanf( p, "(%f", &rev ); // I don't care about errors because for non-ATI GPUs this should // be zero. if (n!=1) { rev=0; } } opencl_driver_revision=floor(rev*100+0.5); return 0; } void OPENCL_DEVICE_PROP::description(char* buf, int buflen, const char* type) { char s1[256], s2[256]; int n; // openCL_device_version may have a trailing space strlcpy(s1, opencl_device_version, sizeof(s1)); n = (int)strlen(s1) - 1; if ((n > 0) && (s1[n] == ' ')) s1[n] = '\0'; snprintf(s2, sizeof(s2), "%s (driver version %s, device version %s, %.0fMB, %.0fMB available, %.0f GFLOPS peak)", name, opencl_driver_version, s1, global_mem_size/MEGA, opencl_available_ram/MEGA, peak_flops/1.e9 ); switch(is_used) { case COPROC_IGNORED: snprintf(buf, buflen, "OpenCL: %s %d (ignored by config): %s", type, device_num, s2 ); break; case COPROC_USED: snprintf(buf, buflen, "OpenCL: %s %d: %s", type, device_num, s2 ); break; case COPROC_UNUSED: default: snprintf(buf, buflen, "OpenCL: %s %d (not used): %s", type, device_num, s2 ); break; } } ////////////////// OPENCL CPU STARTS HERE ///////////////// // CPU OpenCL does not really describe a coprocessor but // this is here to take advantage of the other OpenCL code. void OPENCL_CPU_PROP::clear() { platform_vendor[0] = 0; memset(&opencl_prop, 0, sizeof(opencl_prop)); } void OPENCL_CPU_PROP::write_xml(MIOFILE& f) { f.printf( "\n" " %s\n", platform_vendor ); opencl_prop.write_xml(f, "opencl_cpu_info"); f.printf("\n"); } int OPENCL_CPU_PROP::parse(XML_PARSER& xp) { int retval; clear(); while (!xp.get_tag()) { if (xp.match_tag("/opencl_cpu_prop")) { if (!strlen(platform_vendor)) return ERR_XML_PARSE; return 0; } if (xp.parse_str("platform_vendor", platform_vendor, sizeof(platform_vendor))) continue; if (xp.match_tag("opencl_cpu_info")) { retval = opencl_prop.parse(xp, "/opencl_cpu_info"); if (retval) return retval; continue; } } return ERR_XML_PARSE; } void OPENCL_CPU_PROP::description(char* buf, int buflen) { char s1[256]; int n; // openCL_device_version may have a trailing space strlcpy(s1, opencl_prop.opencl_device_version, sizeof(s1)); n = (int)strlen(s1) - 1; if ((n > 0) && (s1[n] == ' ')) s1[n] = '\0'; snprintf(buf, buflen, "OpenCL CPU: %s (OpenCL driver vendor: %s, driver version %s, device version %s)", opencl_prop.name, platform_vendor, opencl_prop.opencl_driver_version, s1 ); }