// This file is part of BOINC. // http://boinc.berkeley.edu // Copyright (C) 2008 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 . // // This file contains functions that can be customized to // implement project-specific scheduling policies. // The functions are: // // wu_is_infeasible_custom() // Decide whether host can run a job using a particular app version. // In addition it can: // - set the app version's resource usage and/or FLOPS rate estimate // (by assigning to bav.host_usage) // - modify command-line args // (by assigning to bav.host_usage.cmdline) // - set the job's FLOPS count // (by assigning to wu.rsc_fpops_est) // // app_plan() // Decide whether host can use an app version, // and if so what resources it will use // // app_plan_uses_gpu(): // Which plan classes use GPUs // // JOB::get_score(): // Determine the value of sending a particular job to host; // (used only by "matchmaker" scheduling) // // WARNING: if you modify this file, you must prevent it from // being overwritten the next time you update BOINC source code. // You can either: // 1) write-protect this file, or // 2) put this in a differently-named file and change the Makefile.am // (and write-protect that) // In either case, put your version under source-code control, e.g. SVN #include "config.h" #include using std::string; #include "str_util.h" #include "util.h" #include "sched_check.h" #include "sched_config.h" #include "sched_main.h" #include "sched_msgs.h" #include "sched_send.h" #include "sched_score.h" #include "sched_shmem.h" #include "sched_version.h" #include "sched_customize.h" #include "plan_class_spec.h" #ifndef ATI_MIN_RAM #define ATI_MIN_RAM 256*MEGA #endif #ifndef OPENCL_ATI_MIN_RAM #define OPENCL_ATI_MIN_RAM 256*MEGA #endif #ifndef OPENCL_INTEL_GPU_MIN_RAM #define OPENCL_INTEL_GPU_MIN_RAM 256*MEGA #endif #ifndef CUDA_MIN_RAM #define CUDA_MIN_RAM 256*MEGA #endif #ifndef CUDAFERMI_MIN_RAM #define CUDAFERMI_MIN_RAM 384*MEGA #endif #ifndef CUDA23_MIN_RAM #define CUDA23_MIN_RAM 384*MEGA #endif #ifndef OPENCL_NVIDIA_MIN_RAM #define OPENCL_NVIDIA_MIN_RAM CUDA_MIN_RAM #endif GPU_REQUIREMENTS gpu_requirements[NPROC_TYPES]; bool wu_is_infeasible_custom(WORKUNIT& wu, APP& app, BEST_APP_VERSION& bav) { #if 0 // example: if WU name contains "_v1", don't use GPU apps. // Note: this is slightly suboptimal. // If the host is able to accept both GPU and CPU jobs, // we'll skip this job rather than send it for the CPU. // Fixing this would require a big architectural change. // if (strstr(wu.name, "_v1") && bav.host_usage.uses_gpu()) { return true; } #endif #if 0 // example: for NVIDIA GPU app, // wu.batch is the minimum number of GPU processors. // Don't send if #procs is less than this. // if (!strcmp(app.name, "foobar") && bav.host_usage.proc_type == PROC_TYPE_NVIDIA_GPU) { int n = g_request->coprocs.nvidia.prop.multiProcessorCount; if (n < wu.batch) { return true; } } #endif #if defined(SETIATHOME) bool infeasible=false; static bool send_vlar_to_gpu=false; static bool sah_config_checked=false; char buff[256]; // check the projects app config whether to send vlar wus to gpus if (!sah_config_checked) { MIOFILE mf; XML_PARSER xp(&mf); #ifndef _USING_FCGI_ FILE *f=fopen(config.project_path("sah_config.xml"),"r"); #else FCGI_FILE *f=FCGI::fopen(config.project_path("sah_config.xml"),"r"); #endif if (f) { mf.init_file(f); if (xp.parse_start("sah") && xp.parse_start("config")) { while (!xp.get_tag()) { if (!xp.is_tag) continue; if (xp.parse_bool("send_vlar_to_gpu",send_vlar_to_gpu)) continue; if (xp.match_tag("/config")) break; xp.skip_unexpected(false, "wu_is_infeasible_custom"); } } fclose(f); } sah_config_checked=true; } // example: if CUDA app and WU name contains ".vlar", don't send // to NVIDIA, INTEL or older ATI cards // if (bav.host_usage.uses_gpu() && strstr(wu.name, ".vlar")) { if (send_vlar_to_gpu) { if (bav.host_usage.proc_type == PROC_TYPE_AMD_GPU) { // ATI GPUs older than HD7870 COPROC_ATI &cp = g_request->coprocs.ati; if (cp.count && (cp.attribs.target < 15)) { infeasible=true; } } else if (bav.host_usage.proc_type == PROC_TYPE_NVIDIA_GPU) { COPROC_NVIDIA &cp = g_request->coprocs.nvidia; if (cp.count) { int v = (cp.prop.major)*100 + cp.prop.minor; if (v < 300) { infeasible=true; } } } else { // all other GPUS infeasible=true; } } else { infeasible=true; } } if (infeasible && config.debug_version_select) { log_messages.printf(MSG_NORMAL, "[version] [setiathome] VLAR workunit is infeasible on this GPU\n" ); } return infeasible; #endif return false; } #ifndef isnum #define isnum(x) (((x)>='0') && ((x)<='9')) #endif #ifndef isnumorx #define isnumorx(x) (isnum(x) || ((x=='X') || (x=='x'))) #endif // the following is for an app that can use anywhere from 1 to 64 threads // static inline bool app_plan_mt(SCHEDULER_REQUEST&, HOST_USAGE& hu) { double ncpus = g_wreq->effective_ncpus; // number of usable CPUs, taking user prefs into account if (ncpus < 2) return false; int nthreads = (int)ncpus; if (nthreads > 64) nthreads = 64; hu.avg_ncpus = nthreads; hu.max_ncpus = nthreads; sprintf(hu.cmdline, "--nthreads %d", nthreads); hu.projected_flops = capped_host_fpops()*hu.avg_ncpus*.99; // the .99 ensures that on uniprocessors a sequential app // will be used in preferences to this hu.peak_flops = capped_host_fpops()*hu.avg_ncpus; if (config.debug_version_select) { log_messages.printf(MSG_NORMAL, "[version] Multi-thread app projected %.2fGS\n", hu.projected_flops/1e9 ); } return true; } static bool ati_check(COPROC_ATI& c, HOST_USAGE& hu, int min_driver_version, bool need_amd_libs, double min_ram, double ndevs, // # of GPUs used; can be fractional double cpu_frac, // fraction of FLOPS performed by CPU double flops_scale, int min_hd_model=0 ) { if (c.version_num) { gpu_requirements[PROC_TYPE_AMD_GPU].update(min_driver_version, min_ram); } if (min_hd_model) { char *p=strcasestr(c.name,"hd"); if (p) { p+=2; while (p && !isnum(*p)) p++; char modelnum[64]; int i=0; while ((i<63) && p[i] && isnumorx(p[i])) { modelnum[i]=p[i]; if ((modelnum[i]=='x') || (modelnum[i]=='X')) { modelnum[i]='0'; } i++; } modelnum[i]=0; i=atoi(modelnum); if (i%f.\n", min_ram, c.available_ram ); } return false; } hu.gpu_ram = min_ram; hu.proc_type = PROC_TYPE_AMD_GPU; hu.gpu_usage = ndevs; coproc_perf( capped_host_fpops(), flops_scale * hu.gpu_usage*c.peak_flops, cpu_frac, hu.projected_flops, hu.avg_ncpus ); hu.peak_flops = hu.gpu_usage*c.peak_flops + hu.avg_ncpus*capped_host_fpops(); hu.max_ncpus = hu.avg_ncpus; return true; } static inline bool app_plan_ati( SCHEDULER_REQUEST& sreq, char* plan_class, HOST_USAGE& hu ) { COPROC_ATI& c = sreq.coprocs.ati; if (!c.count) { if (config.debug_version_select) { log_messages.printf(MSG_NORMAL,"[version] Host has no ATI GPUs\n"); } return false; } if (!strcmp(plan_class, "ati")) { if (!ati_check(c, hu, ati_version_int(1, 0, 0), true, ATI_MIN_RAM, 1, .01, .20 )) { return false; } } if (!strcmp(plan_class, "ati13amd")) { if (!ati_check(c, hu, ati_version_int(1, 3, 0), true, ATI_MIN_RAM, 1, .01, .21 )) { return false; } } if (!strcmp(plan_class, "ati13ati")) { if (!ati_check(c, hu, ati_version_int(1, 3, 186), false, ATI_MIN_RAM, 1, .01, .22 )) { return false; } } if (!strcmp(plan_class, "ati14")) { if (!ati_check(c, hu, ati_version_int(1, 4, 0), false, ATI_MIN_RAM, 1, .01, .23 )) { return false; } } #ifdef SETIATHOME // ati_opencl_ plan classes are for running // opencl ati apps on pre-v7 boinc core clients if (!strcmp(plan_class, "ati_opencl_100")) { if (!ati_check(c, hu, ati_version_int(1, 4, 1386), false, OPENCL_ATI_MIN_RAM, 1, .01, .14, 4600 )) { return false; } } #endif if (config.debug_version_select) { log_messages.printf(MSG_NORMAL, "[version] %s ATI app projected %.2fG peak %.2fG %.3f CPUs\n", plan_class, hu.projected_flops/1e9, hu.peak_flops/1e9, hu.avg_ncpus ); } return true; } // Change values for these parameters in shed_customize.h! #ifndef CUDA_MIN_DRIVER_VERSION #define CUDA_MIN_DRIVER_VERSION 17700 #endif #ifndef CUDA23_MIN_CUDA_VERSION #define CUDA23_MIN_CUDA_VERSION 2030 #endif #ifndef CUDA23_MIN_DRIVER_VERSION #define CUDA23_MIN_DRIVER_VERSION 19038 #endif #ifndef CUDA3_MIN_CUDA_VERSION #define CUDA3_MIN_CUDA_VERSION 3000 #endif #ifndef CUDA3_MIN_DRIVER_VERSION #define CUDA3_MIN_DRIVER_VERSION 19500 #endif #ifndef CUDA_OPENCL_MIN_DRIVER_VERSION #define CUDA_OPENCL_MIN_DRIVER_VERSION 19713 #endif #ifndef CUDA_OPENCL_101_MIN_DRIVER_VERSION #define CUDA_OPENCL_101_MIN_DRIVER_VERSION 28013 #endif static bool cuda_check(COPROC_NVIDIA& c, HOST_USAGE& hu, int min_cc, int max_cc, int min_cuda_version, int min_driver_version, double min_ram, double ndevs, // # of GPUs used; can be fractional double cpu_frac, // fraction of FLOPS performed by CPU double flops_scale ) { int cc = c.prop.major*100 + c.prop.minor; if (min_cc && (cc < min_cc)) { if (config.debug_version_select) { log_messages.printf(MSG_NORMAL, "[version] App requires compute capability > %d.%d (has %d.%d).\n", min_cc/100,min_cc%100, c.prop.major,c.prop.minor ); } return false; } if (max_cc && cc >= max_cc) { if (config.debug_version_select) { log_messages.printf(MSG_NORMAL, "[version] App requires compute capability <= %d.%d (has %d.%d).\n", max_cc/100,max_cc%100, c.prop.major,c.prop.minor ); } return false; } if (c.display_driver_version) { gpu_requirements[PROC_TYPE_NVIDIA_GPU].update(min_driver_version, min_ram); } // Old BOINC clients report display driver version; // newer ones report CUDA RT version. // Some Linux doesn't return either. // if (!c.cuda_version && !c.display_driver_version) { if (config.debug_version_select) { log_messages.printf(MSG_NORMAL, "[version] Client did not provide cuda or driver version.\n" ); } return false; } if (c.cuda_version) { if (min_cuda_version && (c.cuda_version < min_cuda_version)) { if (config.debug_version_select) { double app_version=(double)(min_cuda_version/1000)+(double)(min_cuda_version%100)/100.0; double client_version=(double)(c.cuda_version/1000)+(double)(c.cuda_version%100)/100.0; log_messages.printf(MSG_NORMAL, "[version] Bad CUDA version %f>%f.\n", app_version, client_version ); } return false; } } if (c.display_driver_version) { if (min_driver_version && (c.display_driver_version < min_driver_version)) { if (config.debug_version_select) { double app_version=(double)(min_driver_version)/100.0; double client_version=(double)(c.display_driver_version)/100.0; log_messages.printf(MSG_NORMAL, "[version] Bad display driver revision %f>%f.\n", app_version, client_version ); } return false; } } if (c.available_ram < min_ram) { if (config.debug_version_select) { log_messages.printf(MSG_NORMAL, "[version] Insufficient GPU RAM %f>%f.\n", min_ram, c.available_ram ); } return false; } hu.gpu_ram = min_ram; hu.proc_type = PROC_TYPE_NVIDIA_GPU; hu.gpu_usage = ndevs; coproc_perf( capped_host_fpops(), flops_scale * hu.gpu_usage*c.peak_flops, cpu_frac, hu.projected_flops, hu.avg_ncpus ); hu.peak_flops = hu.gpu_usage*c.peak_flops + hu.avg_ncpus*capped_host_fpops(); hu.max_ncpus = hu.avg_ncpus; return true; } // the following is for an app that uses an NVIDIA GPU // static inline bool app_plan_nvidia( SCHEDULER_REQUEST& sreq, char* plan_class, HOST_USAGE& hu ) { COPROC_NVIDIA& c = sreq.coprocs.nvidia; if (!c.count) { if (config.debug_version_select) { log_messages.printf(MSG_NORMAL, "[version] Host has no NVIDIA GPUs.\n"); } return false; } // Macs require 6.10.28 // if (strstr(sreq.host.os_name, "Darwin") && (sreq.core_client_version < 61028)) { if (config.debug_version_select) { log_messages.printf(MSG_NORMAL, "[version] CUDA on MacOS requires BOINC 6.10.28 or higher.\n"); } return false; } // for CUDA 2.3, we need to check the CUDA RT version. // Old BOINC clients report display driver version; // newer ones report CUDA RT version #ifdef SETIATHOME // cuda_opencl_ plan classes are for running opencl apps on // pre-boinc-v7 core clients. May be useful for other projects // if (!strcmp(plan_class, "cuda_opencl_100")) { if (!cuda_check(c, hu, 100, 0, 0,CUDA_OPENCL_MIN_DRIVER_VERSION, CUDA_MIN_RAM, 1, .01, 0.14 )) { return false; } } else if (!strcmp(plan_class, "cuda_opencl_101")) { if (!cuda_check(c, hu, 200, 0, 0,CUDA_OPENCL_101_MIN_DRIVER_VERSION, CUDA_MIN_RAM, 1, .01, 0.14 )) { return false; } } else #endif // SETIATHOME if (!strcmp(plan_class, "cuda_fermi")) { if (!cuda_check(c, hu, 200, 0, CUDA3_MIN_CUDA_VERSION, CUDA3_MIN_DRIVER_VERSION, CUDAFERMI_MIN_RAM, 1, .01, .22 )) { return false; } } else if (!strcmp(plan_class, "cuda23")) { if (!cuda_check(c, hu, 100, 200, // change to zero if app is compiled to byte code CUDA23_MIN_CUDA_VERSION, CUDA23_MIN_DRIVER_VERSION, CUDA23_MIN_RAM, 1, .01, .21 )) { return false; } } else if (!strcmp(plan_class, "cuda")) { if (!cuda_check(c, hu, 100, 200, // change to zero if app is compiled to byte code 0, CUDA_MIN_DRIVER_VERSION, CUDA_MIN_RAM, 1, .01, .20 )) { return false; } } else { log_messages.printf(MSG_CRITICAL, "UNKNOWN PLAN CLASS %s\n", plan_class ); return false; } if (config.debug_version_select) { log_messages.printf(MSG_NORMAL, "[version] %s app projected %.2fG peak %.2fG %.3f CPUs\n", plan_class, hu.projected_flops/1e9, hu.peak_flops/1e9, hu.avg_ncpus ); } return true; } // The following is for a non-CPU-intensive application. // Say that we'll use 1% of a CPU. // This will cause the client (6.7+) to run it at non-idle priority // static inline bool app_plan_nci(SCHEDULER_REQUEST&, HOST_USAGE& hu) { hu.avg_ncpus = .01; hu.max_ncpus = .01; hu.projected_flops = capped_host_fpops()*1.01; // The *1.01 is needed to ensure that we'll send this app // version rather than a non-plan-class one hu.peak_flops = capped_host_fpops()*.01; return true; } // the following is for an app version that requires a processor with SSE3, // and will run 10% faster than the non-SSE3 version // static inline bool app_plan_sse3( SCHEDULER_REQUEST& sreq, HOST_USAGE& hu ) { downcase_string(sreq.host.p_features); if (!strstr(sreq.host.p_features, "sse3")) { // Pre-6.x clients report CPU features in p_model // if (!strstr(sreq.host.p_model, "sse3")) { //add_no_work_message("Your CPU lacks SSE3"); return false; } } hu.avg_ncpus = 1; hu.max_ncpus = 1; hu.projected_flops = 1.1*capped_host_fpops(); hu.peak_flops = capped_host_fpops(); return true; } static inline bool opencl_check( COPROC& cp, HOST_USAGE& hu, int min_opencl_device_version, double min_global_mem_size, double ndevs, double cpu_frac, double flops_scale ) { if (cp.opencl_prop.opencl_device_version_int < min_opencl_device_version) { if (config.debug_version_select) { log_messages.printf(MSG_NORMAL, "[version] [opencl_check] App requires OpenCL verion >= %d (has %d).\n", min_opencl_device_version, cp.opencl_prop.opencl_device_version_int ); } return false; } #ifdef SETIATHOME // fix for ATI drivers that report zero or negative global memory size // on some cards. Probably no longer necessary. if (cp.opencl_prop.global_mem_size < cp.opencl_prop.local_mem_size) { cp.opencl_prop.global_mem_size=cp.opencl_prop.local_mem_size; } #endif if (cp.opencl_prop.global_mem_size && (cp.opencl_prop.global_mem_size < min_global_mem_size)) { if (config.debug_version_select) { log_messages.printf(MSG_NORMAL, "[version] [opencl_check] Insufficient GPU RAM %f>%ld.\n", min_global_mem_size, cp.opencl_prop.global_mem_size ); } return false; } hu.gpu_ram = min_global_mem_size; if (!strcmp(cp.type, proc_type_name_xml(PROC_TYPE_NVIDIA_GPU))) { hu.proc_type = PROC_TYPE_NVIDIA_GPU; hu.gpu_usage = ndevs; } else if (!strcmp(cp.type, proc_type_name_xml(PROC_TYPE_AMD_GPU))) { hu.proc_type = PROC_TYPE_AMD_GPU; hu.gpu_usage = ndevs; } else if (!strcmp(cp.type, proc_type_name_xml(PROC_TYPE_INTEL_GPU))) { hu.proc_type = PROC_TYPE_INTEL_GPU; hu.gpu_usage = ndevs; } coproc_perf( capped_host_fpops(), flops_scale * ndevs * cp.peak_flops, cpu_frac, hu.projected_flops, hu.avg_ncpus ); hu.peak_flops = ndevs*cp.peak_flops + hu.avg_ncpus*capped_host_fpops(); hu.max_ncpus = hu.avg_ncpus; return true; } static inline bool app_plan_opencl( SCHEDULER_REQUEST& sreq, const char* plan_class, HOST_USAGE& hu ) { // opencl_*_ plan classes check for a trailing integer which is // used as the opencl version number. This is compatible with the old // opencl_nvidia_101 and opencl_ati_101 plan classes, but doens't require // modifications if someone wants a opencl_nvidia_102 plan class. const char *p=plan_class+strlen(plan_class); while (isnum(p[-1])) { p--; } int ver=atoi(p); if (config.debug_version_select) { log_messages.printf(MSG_NORMAL, "[version] plan_class %s uses OpenCl version %d\n", plan_class, ver ); } if (strstr(plan_class, "nvidia")) { COPROC_NVIDIA& c = sreq.coprocs.nvidia; if (!c.count) return false; if (!c.have_opencl) return false; if (strstr(plan_class,"opencl_nvidia") == plan_class) { return opencl_check( c, hu, ver, OPENCL_NVIDIA_MIN_RAM, 1, .01, .14 ); } else { log_messages.printf(MSG_CRITICAL, "Unknown plan class: %s\n", plan_class ); return false; } } else if (strstr(plan_class, "ati")) { COPROC_ATI& c = sreq.coprocs.ati; if (!c.count) { if (config.debug_version_select) { log_messages.printf(MSG_NORMAL, "[version] [opencl] HOST has no ATI/AMD GPUs\n" ); } return false; } if (!c.have_opencl) { if (config.debug_version_select) { log_messages.printf(MSG_NORMAL, "[version] [opencl] GPU/Driver/BOINC revision doesn not support OpenCL\n" ); } return false; } if (strstr(plan_class,"opencl_ati") == plan_class) { return opencl_check( c, hu, ver, OPENCL_ATI_MIN_RAM, 1, .01, .14 ); } else { log_messages.printf(MSG_CRITICAL, "[version] [opencl] Unknown plan class: %s\n", plan_class ); return false; } } else if (strstr(plan_class, "intel_gpu")) { COPROC_INTEL& c = sreq.coprocs.intel_gpu; if (!c.count) { if (config.debug_version_select) { log_messages.printf(MSG_NORMAL, "[version] [opencl] HOST has no INTEL GPUs\n" ); } return false; } if (!c.have_opencl) { if (config.debug_version_select) { log_messages.printf(MSG_NORMAL, "[version] [opencl] GPU/Driver/BOINC revision doesn not support OpenCL\n" ); } return false; } if (strstr(plan_class,"opencl_intel_gpu") == plan_class) { return opencl_check( c, hu, ver, OPENCL_INTEL_GPU_MIN_RAM, 1, .1, .2 ); } else { log_messages.printf(MSG_CRITICAL, "[version] [opencl] Unknown plan class: %s\n", plan_class ); return false; } // maybe add a clause for multicore CPU } else { log_messages.printf(MSG_CRITICAL, "[version] [opencl] Unknown plan class: %s\n", plan_class ); return false; } } // handles vbox_[32|64][_mt] // "mt" is tailored to the needs of CERN: // use 1 or 2 CPUs static inline bool app_plan_vbox( SCHEDULER_REQUEST& sreq, char* plan_class, HOST_USAGE& hu ) { bool can_use_multicore = true; // 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) || (maj < 3) || (maj == 3 and min < 2)) { add_no_work_message("VirtualBox version 3.2 or later is required"); return false; } // host must have VM acceleration in order to run multi-core jobs // if (strstr(plan_class, "mt")) { 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 (!strstr(plan_class, "64")) return false; } else { if (strstr(plan_class, "64")) return false; } double flops_scale = 1; hu.avg_ncpus = 1; hu.max_ncpus = 1; if (strstr(plan_class, "mt")) { if (can_use_multicore) { // Use number of usable CPUs, taking user prefs into account double ncpus = g_wreq->effective_ncpus; // CernVM on average uses between 25%-50% of a second core // Total on a dual-core machine is between 65%-75% if (ncpus > 1.5) ncpus = 1.5; hu.avg_ncpus = ncpus; hu.max_ncpus = 2.0; sprintf(hu.cmdline, "--nthreads %f", ncpus); } // use the non-mt version rather than the mt version with 1 CPU // flops_scale = .99; } hu.projected_flops = flops_scale * capped_host_fpops()*hu.avg_ncpus; hu.peak_flops = capped_host_fpops()*hu.max_ncpus; if (config.debug_version_select) { log_messages.printf(MSG_NORMAL, "[version] %s app projected %.2fG\n", plan_class, hu.projected_flops/1e9 ); } return true; } PLAN_CLASS_SPECS plan_class_specs; // app planning function. // See http://boinc.berkeley.edu/trac/wiki/AppPlan // bool app_plan(SCHEDULER_REQUEST& sreq, char* plan_class, HOST_USAGE& hu) { char buf[256]; static bool check_plan_class_spec = true; static bool have_plan_class_spec = false; static bool bad_plan_class_spec = false; if (config.debug_version_select) { log_messages.printf(MSG_NORMAL, "[version] Checking plan class '%s'\n", plan_class ); } if (check_plan_class_spec) { check_plan_class_spec = false; safe_strcpy(buf, config.project_dir); safe_strcat(buf, "/plan_class_spec.xml"); int retval = plan_class_specs.parse_file(buf); if (retval == ERR_FOPEN) { if (config.debug_version_select) { log_messages.printf(MSG_NORMAL, "[version] Couldn't open plan class spec file '%s'\n", buf ); } have_plan_class_spec = false; } else if (retval) { log_messages.printf(MSG_CRITICAL, "Error parsing plan class spec file '%s'\n", buf ); bad_plan_class_spec = true; } else { if (config.debug_version_select) { log_messages.printf(MSG_NORMAL, "[version] reading plan classes from file '%s'\n", buf ); } have_plan_class_spec = true; } } if (bad_plan_class_spec) { return false; } if (have_plan_class_spec) { return plan_class_specs.check(sreq, plan_class, hu); } if (!strcmp(plan_class, "mt")) { return app_plan_mt(sreq, hu); } else if (strstr(plan_class, "opencl") == plan_class) { return app_plan_opencl(sreq, plan_class, hu); } else if (strstr(plan_class, "ati") == plan_class) { return app_plan_ati(sreq, plan_class, hu); } else if (strstr(plan_class, "cuda")) { return app_plan_nvidia(sreq, plan_class, hu); } else if (!strcmp(plan_class, "nci")) { return app_plan_nci(sreq, hu); } else if (!strcmp(plan_class, "sse3")) { return app_plan_sse3(sreq, hu); } else if (strstr(plan_class, "vbox")) { return app_plan_vbox(sreq, plan_class, hu); } log_messages.printf(MSG_CRITICAL, "Unknown plan class: %s\n", plan_class ); return false; } #ifndef NEW_SCORE // compute a "score" for sending this job to this host. // Return false if the WU is infeasible. // Otherwise set est_time and disk_usage. // bool JOB::get_score() { WORKUNIT wu; int retval; WU_RESULT& wu_result = ssp->wu_results[index]; wu = wu_result.workunit; app = ssp->lookup_app(wu.appid); if (app->non_cpu_intensive) return false; score = 0; // Find the best app version to use. // bavp = get_app_version(wu, true, false); if (!bavp) return false; retval = wu_is_infeasible_fast( wu, wu_result.res_server_state, wu_result.res_priority, wu_result.res_report_deadline, *app, *bavp ); if (retval) { if (config.debug_send) { log_messages.printf(MSG_NORMAL, "[send] [HOST#%d] [WU#%d %s] WU is infeasible: %s\n", g_reply->host.id, wu.id, wu.name, infeasible_string(retval) ); } return false; } score = 1; #if 0 // example: for CUDA app, wu.batch is the minimum number of processors. // add min/actual to score // (this favors sending jobs that need lots of procs to GPUs that have them) // IF YOU USE THIS, USE THE PART IN wu_is_infeasible_custom() ALSO // if (!strcmp(app->name, "foobar") && bavp->host_usage.ncudas) { int n = g_request->coproc_cuda->prop.multiProcessorCount; score += ((double)wu.batch)/n; } #endif // check if user has selected apps, // and send beta work to beta users // if (app->beta && !config.distinct_beta_apps) { if (g_wreq->allow_beta_work) { score += 1; } else { return false; } } else { if (app_not_selected(wu)) { if (!g_wreq->allow_non_preferred_apps) { return false; } else { // Allow work to be sent, but it will not get a bump in its score } } else { score += 1; } } // if job needs to get done fast, send to fast/reliable host // if (bavp->reliable && (wu_result.need_reliable)) { score += 1; } // if job already committed to an HR class, // try to send to host in that class // if (wu_result.infeasible_count) { score += 1; } // Favor jobs that will run fast // score += bavp->host_usage.projected_flops/1e9; // match large jobs to fast hosts // if (config.job_size_matching) { double host_stdev = (capped_host_fpops() - ssp->perf_info.host_fpops_mean)/ ssp->perf_info.host_fpops_stddev; double diff = host_stdev - wu_result.fpops_size; score -= diff*diff; } // TODO: If user has selected some apps but will accept jobs from others, // try to send them jobs from the selected apps // est_time = estimate_duration(wu, *bavp); disk_usage = wu.rsc_disk_bound; return true; } #endif void handle_file_xfer_results() { for (unsigned int i=0; ifile_xfer_results.size(); i++) { RESULT& r = g_request->file_xfer_results[i]; log_messages.printf(MSG_NORMAL, "completed file xfer %s\n", r.name ); g_reply->result_acks.push_back(string(r.name)); } }