mirror of https://github.com/BOINC/boinc.git
309 lines
9.3 KiB
C++
309 lines
9.3 KiB
C++
|
// 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 <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
#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 <cstdio>
|
||
|
#endif
|
||
|
#include <cstring>
|
||
|
#include <cstdlib>
|
||
|
#include <cmath>
|
||
|
#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"
|
||
|
" <name>%s</name>\n"
|
||
|
" <vendor>%s</vendor>\n"
|
||
|
" <vendor_id>%lu</vendor_id>\n"
|
||
|
" <available>%d</available>\n"
|
||
|
" <half_fp_config>%llu</half_fp_config>\n"
|
||
|
" <single_fp_config>%llu</single_fp_config>\n"
|
||
|
" <double_fp_config>%llu</double_fp_config>\n"
|
||
|
" <endian_little>%d</endian_little>\n"
|
||
|
" <execution_capabilities>%llu</execution_capabilities>\n"
|
||
|
" <extensions>%s</extensions>\n"
|
||
|
" <global_mem_size>%llu</global_mem_size>\n"
|
||
|
" <local_mem_size>%llu</local_mem_size>\n"
|
||
|
" <max_clock_frequency>%lu</max_clock_frequency>\n"
|
||
|
" <max_compute_units>%lu</max_compute_units>\n"
|
||
|
" <opencl_platform_version>%s</opencl_platform_version>\n"
|
||
|
" <opencl_device_version>%s</opencl_device_version>\n"
|
||
|
" <opencl_driver_version>%s</opencl_driver_version>\n",
|
||
|
tag,
|
||
|
name,
|
||
|
vendor,
|
||
|
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,
|
||
|
max_clock_frequency,
|
||
|
max_compute_units,
|
||
|
opencl_platform_version,
|
||
|
opencl_device_version,
|
||
|
opencl_driver_version
|
||
|
);
|
||
|
if (temp_file) {
|
||
|
f.printf(
|
||
|
" <is_used>%d</is_used>\n"
|
||
|
" <device_num>%d</device_num>\n"
|
||
|
" <peak_flops>%f</peak_flops>\n"
|
||
|
" <opencl_available_ram>%f</opencl_available_ram>\n"
|
||
|
" <opencl_device_index>%d</opencl_device_index>\n",
|
||
|
is_used,
|
||
|
device_num,
|
||
|
peak_flops,
|
||
|
opencl_available_ram,
|
||
|
opencl_device_index
|
||
|
);
|
||
|
}
|
||
|
f.printf(" </%s>\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_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("is_used", n)) {
|
||
|
is_used = (COPROC_USAGE)n;
|
||
|
continue;
|
||
|
}
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
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(
|
||
|
"<opencl_cpu_prop>\n"
|
||
|
" <platform_vendor>%s</platform_vendor>\n",
|
||
|
platform_vendor
|
||
|
);
|
||
|
opencl_prop.write_xml(f, "opencl_cpu_info");
|
||
|
f.printf("</opencl_cpu_prop>\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;
|
||
|
}
|
||
|
|