// This file is part of BOINC.
// http://boinc.berkeley.edu
// Copyright (C) 2012 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 .
// Support for plan classes defined using an XML file.
// See https://boinc.berkeley.edu/trac/wiki/AppPlanSpec
#include
#include "util.h"
#include "coproc.h"
#include "sched_config.h"
#include "sched_customize.h"
#include "plan_class_spec.h"
using std::string;
// return a numerical OS version for Darwin/OSX and Windows,
// letting us define numerical ranges for these OS versions
//
static double os_version_num(HOST h) {
unsigned int a, b, c, d;
if (strstr(h.os_name, "Darwin")) {
if (sscanf(h.os_version, "%u.%u.%u", &a, &b, &c) == 3) {
return 10000.0*a + 100.0*b + c;
}
} else if (strstr(h.os_name, "Windows")) {
// example: "Enterprise Server Edition, Service Pack 1, (06.01.7601.00)"
//
char *p = strrchr(h.os_version,'(');
if (p && (sscanf(p, "(%u.%u.%u.%u)", &a, &b, &c, &d) == 4)) {
return 100000000.0*a + 1000000.0*b + 100.0*c +d;
}
} else if (strstr(h.os_name, "Android")) {
// examples:
// 3.0.31-g6fb96c9
// 2.6.36.3
// 3.4.0
//
if (sscanf(h.os_version, "%u.%u.%u", &a, &b, &c) == 3) {
return 10000.*a + 100.*b + c;
}
} else if (strstr(h.os_name, "Linux")) {
// os_name seems to always contain "Linux".
// os_version is pretty diverse:
//
// Linux Mint 19 Tara [4.18.12-041812-generic|libc 2.27 (Ubuntu GLIBC 2.27-3ubuntu1)]
// CentOS Linux 7 (Core) [3.10.0-862.14.4.el7.x86_64|libc 2.17 (GNU libc)]
// Ubuntu 18.04.1 LTS [4.15.0-36-generic|libc 2.27 (Ubuntu GLIBC 2.27-3ubuntu1)]
// 3.13.0-103-generic
// 4.9.0-8-amd64
// Manjaro Linux [4.19.42-1-MANJARO|libc 2.29 (GNU libc)]
char* p = strchr(h.os_version, '[');
if (p) {
p++;
} else {
p = h.os_version;
}
if (sscanf(p, "%u.%u.%u", &a, &b, &c) == 3) {
return 10000.*a + 100.*b + c;
}
}
// could not determine numerical OS version
//
return 0;
}
// parse version# from "(Android 4.3.1)" or "(Android 4.3)" or "(Android 4)"
//
static int android_version_num(HOST h) {
int maj, min, rel;
char* p = strstr(h.os_version, "(Android ");
if (!p) return 0;
p += strlen("(Android ");
int n = sscanf(p, "%d.%d.%d", &maj, &min, &rel);
if (n == 3) {
return maj*10000 + min*100 + rel;
}
n = sscanf(p, "%d.%d", &maj, &min);
if (n == 2) {
return maj*10000 + min*100;
}
n = sscanf(p, "%d", &maj);
if (n == 1) {
return maj*10000;
}
return 0;
}
static bool wu_is_infeasible_for_plan_class(
const PLAN_CLASS_SPEC* pc, const WORKUNIT* wu
) {
if (pc->min_wu_id && wu->id < pc->min_wu_id) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] WU#%ld too old for plan class '%s' (%ld)\n",
wu->id, pc->name, pc->min_wu_id
);
}
return true;
}
if (pc->max_wu_id && wu->id > pc->max_wu_id) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] WU#%ld too new for plan class '%s' (%ld)\n",
wu->id, pc->name, pc->max_wu_id
);
}
return true;
}
if (pc->min_batch && wu->batch < pc->min_batch) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] batch#%d too old for plan class '%s' (%ld)\n",
wu->batch, pc->name, pc->min_batch
);
}
return true;
}
if (pc->max_batch && wu->batch > pc->max_batch) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] batch#%d too new for plan class '%s' (%ld)\n",
wu->batch, pc->name, pc->max_batch
);
}
return true;
}
return false;
}
int PLAN_CLASS_SPECS::parse_file(const char* path) {
#ifndef _USING_FCGI_
FILE* f = fopen(path, "r");
#else
FCGI_FILE *f = FCGI::fopen(path, "r");
#endif
if (!f) return ERR_FOPEN;
int retval = parse_specs(f);
fclose(f);
return retval;
}
bool PLAN_CLASS_SPEC::opencl_check(OPENCL_DEVICE_PROP& opencl_prop) {
if (min_opencl_version && opencl_prop.opencl_device_version_int
&& min_opencl_version > opencl_prop.opencl_device_version_int
) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] OpenCL device version required min: %d, supplied: %d\n",
min_opencl_version, opencl_prop.opencl_device_version_int
);
}
return false;
}
if (max_opencl_version && opencl_prop.opencl_device_version_int
&& max_opencl_version < opencl_prop.opencl_device_version_int
) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] OpenCL device version required max: %d, supplied: %d\n",
max_opencl_version, opencl_prop.opencl_device_version_int
);
}
return false;
}
if (min_opencl_driver_revision && opencl_prop.opencl_device_version_int
&& min_opencl_driver_revision > opencl_prop.opencl_driver_revision
) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] OpenCL driver revision required min: %d, supplied: %d\n",
min_opencl_driver_revision, opencl_prop.opencl_driver_revision
);
}
return false;
}
if (max_opencl_driver_revision && opencl_prop.opencl_device_version_int
&& max_opencl_driver_revision < opencl_prop.opencl_driver_revision
) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] OpenCL driver revision required max: %d, supplied: %d\n",
max_opencl_driver_revision, opencl_prop.opencl_driver_revision
);
}
return false;
}
if (double_precision_fp && (opencl_prop.double_fp_config == 0)) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] device (or driver) doesn't support double precision fp math\n"
);
}
return false;
}
return true;
}
// See whether the given host/user can be sent this plan class.
// If so return the resource usage and estimated FLOPS in hu.
//
bool PLAN_CLASS_SPEC::check(
SCHEDULER_REQUEST& sreq, HOST_USAGE& hu, const WORKUNIT* wu
) {
COPROC* cpp = NULL;
bool can_use_multicore = true;
string msg;
if (infeasible_random && drand()effective_ncpus < min_ncpus) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: not enough CPUs: %d < %f\n",
g_wreq->effective_ncpus, min_ncpus
);
}
return false;
}
// host summary
//
if (have_host_summary_regex
&& regexec(&(host_summary_regex), g_reply->host.serialnum, 0, NULL, 0)
) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: host summary '%s' didn't match regexp\n",
g_reply->host.serialnum
);
}
return false;
}
// OS version
//
if (have_os_regex && regexec(&(os_regex), sreq.host.os_version, 0, NULL, 0)) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: OS version '%s' didn't match regexp\n",
sreq.host.os_version
);
}
return false;
}
if (min_os_version || max_os_version) {
double host_os_version_num = os_version_num(sreq.host);
if (!host_os_version_num) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: Can't determine numerical OS version '%s'\n",
sreq.host.os_version
);
}
return false;
}
if (min_os_version && (host_os_version_num < min_os_version)) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: OS version '%s' too low (%.0f / %.0f)\n",
sreq.host.os_version, host_os_version_num, min_os_version
);
}
return false;
}
if (max_os_version && (host_os_version_num > max_os_version)) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: OS version '%s' too high (%.0f / %.0f)\n",
sreq.host.os_version, host_os_version_num, max_os_version
);
}
return false;
}
}
if (min_android_version || max_android_version) {
if (strcasecmp(sreq.host.os_name, "android")) return false;
int host_android_version = android_version_num(sreq.host);
if (!host_android_version) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: Can't determine numerical Android version '%s'\n",
sreq.host.os_version
);
}
if (min_android_version>0) return false;
}
if (min_android_version && (host_android_version < min_android_version)) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: Android version '%s' too low (%d / %d)\n",
sreq.host.os_version, host_android_version, min_android_version
);
}
return false;
}
if (max_android_version && (host_android_version > max_android_version)) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: Android version '%s' too high (%d / %d)\n",
sreq.host.os_version, host_android_version, max_android_version
);
}
return false;
}
}
// CPU vendor and model
//
if (have_cpu_vendor_regex && regexec(&(cpu_vendor_regex), sreq.host.p_vendor, 0, NULL, 0)) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: CPU vendor '%s' didn't match regexp\n",
sreq.host.p_vendor
);
}
return false;
}
if (have_cpu_model_regex && regexec(&(cpu_model_regex), sreq.host.p_model, 0, NULL, 0)) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: CPU model '%s' didn't match regexp\n",
sreq.host.p_model
);
}
return false;
}
// BOINC versions
//
if (min_core_client_version && sreq.core_client_version < min_core_client_version) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: Need newer BOINC core client: %d < %d\n",
sreq.core_client_version, min_core_client_version
);
}
add_no_work_message("A newer BOINC may be required for some tasks.");
return false;
}
if (max_core_client_version && sreq.core_client_version > max_core_client_version) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: Need older BOINC core client: %d > %d\n",
sreq.core_client_version, max_core_client_version
);
}
return false;
}
if (virtualbox) {
// host must run 7.0+ client
//
if (sreq.core_client_major_version < 7) {
add_no_work_message("BOINC client 7.0+ required for Virtualbox jobs");
return false;
}
// host must have VirtualBox 3.2 or later
//
if (strlen(sreq.host.virtualbox_version) == 0) {
add_no_work_message("VirtualBox is not installed");
return false;
}
int n, maj, min, rel;
n = sscanf(sreq.host.virtualbox_version, "%d.%d.%d", &maj, &min, &rel);
if (n != 3) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: can't parse vbox version\n"
);
}
return false;
}
int v = maj*10000 + min*100 + rel;
if (min_vbox_version && v < min_vbox_version) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: vbox version too low: %d < %d\n",
v, min_vbox_version
);
}
return false;
}
if (max_vbox_version && v > max_vbox_version) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: vbox version too high: %d > %d\n",
v, max_vbox_version
);
}
return false;
}
if (in_vector(v, exclude_vbox_version)) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: vbox version %d excluded\n", v
);
}
return false;
}
if (vm_accel_required) {
if ((!strstr(sreq.host.p_features, "vmx") && !strstr(sreq.host.p_features, "svm"))
|| sreq.host.p_vm_extensions_disabled
) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: missing VM HW acceleration\n"
);
}
return false;
}
}
// host must have VM acceleration in order to run multi-core jobs
//
if (max_threads > 1) {
if ((!strstr(sreq.host.p_features, "vmx") && !strstr(sreq.host.p_features, "svm"))
|| sreq.host.p_vm_extensions_disabled
) {
can_use_multicore = false;
}
}
// only send the version for host's primary platform.
// A Win64 host can't run a 32-bit VM app:
// it will look in the 32-bit half of the registry and fail
//
PLATFORM* p = g_request->platforms.list[0];
if (is_64b_platform(p->name)) {
if (!is64bit) return false;
} else {
if (is64bit) return false;
}
}
// project-specific preference
//
if (have_project_prefs_regex && strlen(project_prefs_tag)) {
char tag[256], value[256];
char buf[65536];
extract_venue(g_reply->user.project_prefs, g_reply->host.venue, buf, sizeof(buf));
sprintf(tag,"<%s>",project_prefs_tag);
bool p = parse_str(buf, tag, value, sizeof(value));
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: parsed project prefs setting '%s' : %s\n",
project_prefs_tag, p?"true":"false"
);
}
if (p ? regexec(&(project_prefs_regex), value, 0, NULL, 0) : !project_prefs_default_true) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: project prefs setting '%s' value='%s' prevents using plan class.\n",
project_prefs_tag, p ? value : "(tag missing)"
);
}
return false;
}
}
double gpu_ram = 0;
int driver_version = 0;
double gpu_utilization = 1.0;
// user defined gpu_utilization
//
if (strlen(gpu_utilization_tag)) {
char tag[256];
char buf[65536];
double v = 0;
extract_venue(g_reply->user.project_prefs, g_reply->host.venue, buf, sizeof(buf));
sprintf(tag,"<%s>",gpu_utilization_tag);
bool p = parse_double(buf, tag, v);
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: parsed project prefs setting '%s' : %s : %f\n",
gpu_utilization_tag, p?"true":"false", v
);
}
if (v) {
gpu_utilization = v;
}
}
// AMD
//
if (!strcmp(gpu_type, "amd") || !strcmp(gpu_type, "ati")) {
COPROC_ATI& cp = sreq.coprocs.ati;
cpp = &cp;
if (!cp.count) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: No AMD GPUs found\n"
);
}
return false;
}
if (min_gpu_ram_mb) {
gpu_requirements[PROC_TYPE_AMD_GPU].update(0, min_gpu_ram_mb * MEGA);
}
if (min_driver_version) {
gpu_requirements[PROC_TYPE_AMD_GPU].update(abs(min_driver_version), 0);
}
if (need_ati_libs) {
if (!cp.atirt_detected) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: ATI libraries not found\n"
);
}
return false;
}
} else {
if (need_amd_libs && !cp.amdrt_detected) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: AMD libraries not found\n"
);
}
return false;
}
}
if (without_opencl) {
if (cp.have_opencl) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: OpenCL detected. Plan restricted to CAL only GPUs\n"
);
}
return false;
}
}
if (min_cal_target && cp.attribs.target < min_cal_target) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: CAL target less than minimum (%d < %d)\n",
cp.attribs.target, min_cal_target
);
}
return false;
}
if (max_cal_target && cp.attribs.target > max_cal_target) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: CAL target greater than maximum (%d > %d)\n",
cp.attribs.target, max_cal_target
);
}
return false;
}
if (cp.bad_gpu_peak_flops("AMD", msg)) {
log_messages.printf(MSG_NORMAL, "%s\n", msg.c_str());
}
gpu_ram = cp.opencl_prop.global_mem_size;
driver_version = 0;
if (cp.have_cal) {
int major, minor, release, scanned;
scanned = sscanf(cp.version, "%d.%d.%d", &major, &minor, &release);
if (scanned != 3) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: driver version '%s' couldn't be parsed\n",
cp.version
);
}
return false;
} else {
driver_version = ati_version_int(major,minor,release);
}
} else {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: no CAL, driver version couldn't be determined\n"
);
}
}
// NVIDIA
//
} else if (!strcmp(gpu_type, "nvidia")) {
COPROC_NVIDIA& cp = sreq.coprocs.nvidia;
cpp = &cp;
if (!cp.count) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: No NVIDIA GPUs found\n"
);
}
return false;
}
// in analogy to ATI/AMD
driver_version=cp.display_driver_version;
if (min_gpu_ram_mb) {
gpu_requirements[PROC_TYPE_NVIDIA_GPU].update(0, min_gpu_ram_mb * MEGA);
}
if (min_driver_version) {
gpu_requirements[PROC_TYPE_NVIDIA_GPU].update(abs(min_driver_version), 0);
}
// compute capability
int v = (cp.prop.major)*100 + cp.prop.minor;
if (min_nvidia_compcap && min_nvidia_compcap > v) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: NVIDIA compute capability required min: %d, supplied: %d\n",
min_nvidia_compcap, v
);
}
return false;
}
if (max_nvidia_compcap && max_nvidia_compcap < v) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: CUDA compute capability required max: %d, supplied: %d\n",
max_nvidia_compcap, v
);
}
return false;
}
if (cuda) {
// CUDA version
if (min_cuda_version && min_cuda_version > cp.cuda_version) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: CUDA version required min: %d, supplied: %d\n",
min_cuda_version, cp.cuda_version
);
}
return false;
}
if (max_cuda_version && max_cuda_version < cp.cuda_version) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: CUDA version required max: %d, supplied: %d\n",
max_cuda_version, cp.cuda_version
);
}
return false;
}
}
gpu_ram = cp.prop.totalGlobalMem;
if (cp.bad_gpu_peak_flops("NVIDIA", msg)) {
log_messages.printf(MSG_NORMAL, "%s\n", msg.c_str());
}
// Intel GPU
//
} else if (strstr(gpu_type, "intel") == gpu_type) {
COPROC& cp = sreq.coprocs.intel_gpu;
cpp = &cp;
if (!cp.count) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: No Intel GPUs found\n"
);
}
return false;
}
if (min_gpu_ram_mb) {
gpu_requirements[PROC_TYPE_INTEL_GPU].update(0, min_gpu_ram_mb * MEGA);
}
if (cp.bad_gpu_peak_flops("Intel GPU", msg)) {
log_messages.printf(MSG_NORMAL, "%s\n", msg.c_str());
}
// custom GPU type
//
} else if (strlen(gpu_type)) {
cpp = sreq.coprocs.lookup_type(gpu_type);
if (!cpp) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: No %s found\n", gpu_type
);
}
return false;
}
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: Custom coproc %s found\n", gpu_type
);
}
if (cpp->bad_gpu_peak_flops("Custom GPU", msg)) {
log_messages.printf(MSG_NORMAL, "%s\n", msg.c_str());
}
}
if (opencl) {
if (cpp) {
if (!cpp->have_opencl) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] GPU doesn't support OpenCL\n"
);
}
return false;
}
if (!opencl_check(cpp->opencl_prop)) {
return false;
}
gpu_ram = cpp->opencl_prop.global_mem_size;
} else {
// OpenCL CPU app version.
// The host may have several OpenCL CPU libraries.
// See if any of them works.
// TODO: there should be a way of saying which library
// the app version requires,
// or a way of conveying to the app which one to use.
//
bool found = false;
for (int i=0; i gpu_ram) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: GPU RAM required min: %f, supplied: %f\n",
min_gpu_ram_mb * MEGA, gpu_ram
);
}
return false;
}
// display driver version
//
if (min_driver_version && driver_version) {
if (min_driver_version > driver_version) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: driver version required min: %d, supplied: %d\n",
abs(min_driver_version), driver_version
);
}
return false;
}
}
if (max_driver_version && driver_version) {
if (max_driver_version < driver_version) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: driver version required max: %d, supplied: %d\n",
abs(max_driver_version), driver_version
);
}
return false;
}
}
hu.gpu_ram = (gpu_ram_used_mb?gpu_ram_used_mb:min_gpu_ram_mb) * MEGA;
double gpu_usage;
// if ngpus < 0, set gpu_usage by the fraction of the total
// video RAM a tasks would take
// i.e. fill the device memory with tasks
//
if (ngpus < 0) {
gpu_usage = (floor(gpu_ram/ hu.gpu_ram) * hu.gpu_ram) / gpu_ram ;
} else if (ngpus > 0) {
gpu_usage = ngpus * gpu_utilization;
} else {
gpu_usage = gpu_utilization;
}
// if we don't know GPU peak flops, treat it like a CPU app
//
if (cpp->peak_flops == 0) {
strcpy(hu.custom_coproc_type, gpu_type);
hu.avg_ncpus = cpu_frac;
hu.gpu_usage = gpu_usage;
} else {
if (min_gpu_peak_flops && cpp->peak_flops < min_gpu_peak_flops) {
return false;
}
if (max_gpu_peak_flops && cpp->peak_flops > max_gpu_peak_flops) {
return false;
}
coproc_perf(
capped_host_fpops(),
gpu_peak_flops_scale * gpu_usage * cpp->peak_flops,
cpu_frac,
hu.projected_flops,
hu.avg_ncpus
);
hu.projected_flops *= projected_flops_scale;
if (avg_ncpus) {
hu.avg_ncpus = avg_ncpus;
}
// I believe the first term here is just hu.projected_flops,
// but I'm leaving it spelled out to match GPU scheduling
// code in sched_customize.cpp
//
hu.peak_flops = gpu_peak_flops_scale*gpu_usage*cpp->peak_flops
+ hu.avg_ncpus*capped_host_fpops()
;
}
if (!strcmp(gpu_type, "amd") || !strcmp(gpu_type, "ati")) {
hu.proc_type = PROC_TYPE_AMD_GPU;
hu.gpu_usage = gpu_usage;
} else if (!strcmp(gpu_type, "nvidia")) {
hu.proc_type = PROC_TYPE_NVIDIA_GPU;
hu.gpu_usage = gpu_usage;
} else if (strstr(gpu_type, "intel")==gpu_type) {
hu.proc_type = PROC_TYPE_INTEL_GPU;
hu.gpu_usage = gpu_usage;
} else if (!strcmp(gpu_type, "miner_asic")) {
hu.proc_type = PROC_TYPE_MINER_ASIC;
hu.gpu_usage = gpu_usage;
} else {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: unknown GPU supplied: %s\n",
gpu_type
);
}
}
} else {
// CPU only
//
if (avg_ncpus) {
hu.avg_ncpus = avg_ncpus;
} else {
if (can_use_multicore) {
if (max_threads > g_wreq->effective_ncpus) {
hu.avg_ncpus = g_wreq->effective_ncpus;
} else {
hu.avg_ncpus = max_threads;
}
// if per-CPU mem usage given
//
if (mem_usage_per_cpu) {
if (!min_ncpus) min_ncpus = 1;
double mem_usage_seq = mem_usage_base + min_ncpus*mem_usage_per_cpu;
// see if client has enough memory to run at all
//
if (mem_usage_seq > g_wreq->usable_ram) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: insufficient multicore RAM; %f < %f",
g_wreq->usable_ram, mem_usage_seq
);
}
return false;
}
// see how many CPUs we could use given memory usage
//
int n = (g_wreq->usable_ram - mem_usage_base)/mem_usage_per_cpu;
// don't use more than this many
//
if (n < hu.avg_ncpus) {
hu.avg_ncpus = n;
}
// compute memory usage; overrides wu.rsc_memory_bound
//
hu.mem_usage = mem_usage_base + hu.avg_ncpus*mem_usage_per_cpu;
char buf[256];
sprintf(buf, " --memory_size_mb %.0f", hu.mem_usage/MEGA);
strcat(hu.cmdline, buf);
}
} else {
hu.avg_ncpus = 1;
}
}
if (nthreads_cmdline) {
char buf[256];
sprintf(buf, " --nthreads %d", (int)hu.avg_ncpus);
strcat(hu.cmdline, buf);
}
hu.peak_flops = capped_host_fpops() * hu.avg_ncpus;
hu.projected_flops = capped_host_fpops() * hu.avg_ncpus * projected_flops_scale;
// end CPU case
}
#if 0
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] plan_class_spec: host_flops: %e, \tscale: %.2f, \tprojected_flops: %e, \tpeak_flops: %e\n",
sreq.host.p_fpops, projected_flops_scale, hu.projected_flops,
hu.peak_flops
);
}
#endif
return true;
}
bool PLAN_CLASS_SPECS::check(
SCHEDULER_REQUEST& sreq, char* plan_class, HOST_USAGE& hu,
const WORKUNIT* wu
) {
for (unsigned int i=0; ieffective_ncpus = 4;
if (1) {
sreq.coprocs.nvidia.fake(18000, 512*MEGA, 490*MEGA, 1);
sreq.coprocs.nvidia.opencl_prop.opencl_device_version_int = 0;
} else {
sreq.coprocs.nvidia.count = 0;
}
if (1) {
sreq.coprocs.ati.fake(512*MEGA, 256*MEGA, 1);
sreq.coprocs.ati.have_cal = true;
sreq.coprocs.ati.opencl_prop.opencl_device_version_int = 0;
} else {
sreq.coprocs.ati.count = 0;
}
for (unsigned int i=0; i