- scheduler: fix structural problems with sending user messages.

Old: various redundant and/or misleading messages were sent.
    New:
        - if host w/ no GPU contacts a GPU-only project,
            send high-pri message saying they need a GPU
        - if host w/ GPU has driver too old for all versions,
            send high-pri message saying to update driver
        - if host w/ GPU has driver too old for some versions,
            send low-pri message saying to update driver
        - if host has GPU but too little RAM for any app,
            send low-pri message saying so
- scheduler: revamp GPU plan class functions

svn path=/trunk/boinc/; revision=21760
This commit is contained in:
David Anderson 2010-06-16 22:07:19 +00:00
parent 6511e1f8e8
commit 81973a9fff
10 changed files with 484 additions and 437 deletions

View File

@ -4274,11 +4274,11 @@ David 14 Jun 2010
handle_request.cpp
David 15 Jun 2010
- client: call curl_global_cleanup() on exit
- client: call curl_global_cleanup() on exit
(minor memory leak)
client/
http_curl.cpp
client/
http_curl.cpp
David 15 Jun 2010
- scheduler: restore scaling of daily quota by # processors
@ -4299,16 +4299,41 @@ Charlie 15 Jun 2010
procinfo_mac.cpp
David 16 Jun 2010
- client: let fake CUDA specify driver version
- client: restore call to diagnostics_finish() on exit.
(should print mem info, but doesn't)
- manager: notices display tweak
- client: let fake CUDA specify driver version
- client: restore call to diagnostics_finish() on exit.
(should print mem info, but doesn't)
- manager: notices display tweak
client/
client_state.cpp
coproc_detect.cpp
main.cpp
clientgui/
ViewNotices.cpp
lib/
coproc.h
client/
client_state.cpp
coproc_detect.cpp
main.cpp
clientgui/
ViewNotices.cpp
lib/
coproc.h
David 16 Jun 2010
- scheduler: fix structural problems with sending user messages.
Old: various redundant and/or misleading messages were sent.
New:
- if host w/ no GPU contacts a GPU-only project,
send high-pri message saying they need a GPU
- if host w/ GPU has driver too old for all versions,
send high-pri message saying to update driver
- if host w/ GPU has driver too old for some versions,
send low-pri message saying to update driver
- if host has GPU but too little RAM for any app,
send low-pri message saying so
- scheduler: revamp GPU plan class functions
client/
cs_notices.h
lib/
coproc.cpp,h
notice.cpp
sched/
handle_request.cpp
sched_array.cpp
sched_customize.cpp,h
sched_send.cpp

View File

@ -51,10 +51,11 @@
// There's also a merged list "rss_feeds" where seqno is stored.
//
// files:
// notices/feeds.xml feed list
// notices/feeds_PROJ_URL.xml list of project feeds
// notices/archive_RSS_URL.xml item archive for a feed
// notices/out_RSS_URL.xml result of last fetch for a feed
// notices/feeds.xml feed list
// notices/feeds_PROJ_URL.xml list of project feeds
// notices/archive_RSS_URL.xml item archive for a feed
// notices/out_RSS_URL.xml result of last fetch for a feed
// notices/archive.xml non-RSS messages
#include <deque>
#include <vector>

View File

@ -397,7 +397,12 @@ int COPROC_ATI::parse(MIOFILE& fin) {
clear();
while (fin.fgets(buf, sizeof(buf))) {
if (strstr(buf, "</coproc_ati>")) return 0;
if (strstr(buf, "</coproc_ati>")) {
int major, minor, release;
sscanf(version, "%d.%d.%d", &major, &minor, &release);
version_num = major*1000000 + minor*1000 + release;
return 0;
}
if (parse_int(buf, "<count>", count)) continue;
if (parse_str(buf, "<name>", name, sizeof(name))) continue;
if (parse_double(buf, "<req_secs>", req_secs)) continue;

View File

@ -252,6 +252,7 @@ enum CUdevice_attribute_enum {
struct COPROC_ATI : public COPROC {
char name[256];
char version[50];
int version_num;
bool atirt_detected;
bool amdrt_detected;
CALdeviceattribs attribs;

View File

@ -1,116 +1,116 @@
// 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 <http://www.gnu.org/licenses/>.
#if defined(_WIN32) && !defined(__STDWX_H__)
#include "boinc_win.h"
#elif defined(_WIN32) && defined(__STDWX_H__)
#include "stdwx.h"
#endif
#include "error_numbers.h"
#include "notice.h"
NOTICE::NOTICE() {
clear();
}
NOTICE::~NOTICE() {
clear();
}
// This is to parse our own XML.
// parse_rss() parses an RSS feed item.
//
int NOTICE::parse(XML_PARSER& xp) {
char tag[1024];
bool is_tag;
// memset(this, 0, sizeof(*this));
clear();
while (!xp.get(tag, sizeof(tag), is_tag)) {
if (!is_tag) continue;
if (!strcmp(tag, "/notice")) {
return 0;
}
if (xp.parse_int(tag, "seqno", seqno)) continue;
if (xp.parse_str(tag, "title", title, sizeof(title))) continue;
if (xp.parse_string(tag, "description", description)) continue;
if (xp.parse_double(tag, "create_time", create_time)) continue;
if (xp.parse_double(tag, "arrival_time", arrival_time)) continue;
if (xp.parse_bool(tag, "is_private", is_private)) continue;
if (xp.parse_str(tag, "category", category, sizeof(category))) continue;
if (xp.parse_str(tag, "link", link, sizeof(link))) continue;
if (xp.parse_str(tag, "project_name", project_name, sizeof(project_name))) continue;
if (xp.parse_str(tag, "guid", guid, sizeof(guid))) continue;
if (xp.parse_str(tag, "feed_url", feed_url, sizeof(feed_url))) continue;
}
return ERR_XML_PARSE;
}
void NOTICE::write(MIOFILE& f, bool for_gui) {
f.printf(
"<notice>\n"
" <title>%s</title>\n"
" <description><![CDATA[\n%s\n]]></description>\n"
" <create_time>%f</create_time>\n"
" <arrival_time>%f</arrival_time>\n"
" <is_private>%d</is_private>\n"
" <project_name>%s</project_name>"
" <category>%s</category>\n"
" <link>%s</link>\n",
title,
description.c_str(),
create_time,
arrival_time,
is_private?1:0,
project_name,
category,
link
);
if (!for_gui) {
f.printf(
" <guid>%s</guid>\n", guid
);
} else {
f.printf(
" <seqno>%d</seqno>\n", seqno
);
}
f.printf(
"</notice>\n"
);
}
void NOTICE::clear() {
seqno = 0;
strcpy(title, "");
description = "";
create_time = 0;
arrival_time = 0;
is_private = 0;
strcpy(category, "");
strcpy(link, "");
strcpy(project_name, "");
strcpy(guid, "");
strcpy(feed_url, "");
}
// 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 <http://www.gnu.org/licenses/>.
#if defined(_WIN32) && !defined(__STDWX_H__)
#include "boinc_win.h"
#elif defined(_WIN32) && defined(__STDWX_H__)
#include "stdwx.h"
#endif
#include "error_numbers.h"
#include "notice.h"
NOTICE::NOTICE() {
clear();
}
NOTICE::~NOTICE() {
clear();
}
// This is to parse our own XML.
// parse_rss() parses an RSS feed item.
//
int NOTICE::parse(XML_PARSER& xp) {
char tag[1024];
bool is_tag;
// memset(this, 0, sizeof(*this));
clear();
while (!xp.get(tag, sizeof(tag), is_tag)) {
if (!is_tag) continue;
if (!strcmp(tag, "/notice")) {
return 0;
}
if (xp.parse_int(tag, "seqno", seqno)) continue;
if (xp.parse_str(tag, "title", title, sizeof(title))) continue;
if (xp.parse_string(tag, "description", description)) continue;
if (xp.parse_double(tag, "create_time", create_time)) continue;
if (xp.parse_double(tag, "arrival_time", arrival_time)) continue;
if (xp.parse_bool(tag, "is_private", is_private)) continue;
if (xp.parse_str(tag, "category", category, sizeof(category))) continue;
if (xp.parse_str(tag, "link", link, sizeof(link))) continue;
if (xp.parse_str(tag, "project_name", project_name, sizeof(project_name))) continue;
if (xp.parse_str(tag, "guid", guid, sizeof(guid))) continue;
if (xp.parse_str(tag, "feed_url", feed_url, sizeof(feed_url))) continue;
}
return ERR_XML_PARSE;
}
void NOTICE::write(MIOFILE& f, bool for_gui) {
f.printf(
"<notice>\n"
" <title>%s</title>\n"
" <description><![CDATA[\n%s\n]]></description>\n"
" <create_time>%f</create_time>\n"
" <arrival_time>%f</arrival_time>\n"
" <is_private>%d</is_private>\n"
" <project_name>%s</project_name>"
" <category>%s</category>\n"
" <link>%s</link>\n",
title,
description.c_str(),
create_time,
arrival_time,
is_private?1:0,
project_name,
category,
link
);
if (!for_gui) {
f.printf(
" <guid>%s</guid>\n", guid
);
} else {
f.printf(
" <seqno>%d</seqno>\n", seqno
);
}
f.printf(
"</notice>\n"
);
}
void NOTICE::clear() {
seqno = 0;
strcpy(title, "");
description = "";
create_time = 0;
arrival_time = 0;
is_private = 0;
strcpy(category, "");
strcpy(link, "");
strcpy(project_name, "");
strcpy(guid, "");
strcpy(feed_url, "");
}

View File

@ -1278,7 +1278,7 @@ void process_request(char* code_sign_key) {
}
}
if (g_wreq->no_jobs_available) {
g_reply->insert_message("Project has no jobs available", "low");
g_reply->insert_message("Project has no tasks available", "low");
}
}

View File

@ -49,11 +49,14 @@ static bool quick_check(
if (wu_result.state != WR_STATE_PRESENT && wu_result.state != g_pid) {
return false;
}
app = ssp->lookup_app(wu_result.workunit.appid);
if (app == NULL) {
return false; // this should never happen
}
g_wreq->no_jobs_available = false;
// If we're looking for beta jobs and this isn't one, skip it
//
if (g_wreq->beta_only) {
@ -72,8 +75,6 @@ static bool quick_check(
}
}
g_wreq->no_jobs_available = false;
// If this is a reliable host and we are checking for results that
// need a reliable host, then continue if the result is a normal result
// skip if the app is beta (beta apps don't use the reliable mechanism)
@ -347,7 +348,6 @@ static bool scan_work_array() {
// This has been superceded by send_work_matchmaker()
//
void send_work_old() {
if (!work_needed(false)) return;
g_wreq->beta_only = false;
g_wreq->user_apps_only = true;
g_wreq->infeasible_only = false;

View File

@ -141,111 +141,104 @@ static inline bool app_plan_mt(
return true;
}
GPU_REQUIREMENTS ati_requirements;
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
) {
ati_requirements.update(min_driver_version, min_ram);
if (need_amd_libs) {
if (!c.amdrt_detected) {
return false;
}
} else {
if (!c.atirt_detected) {
return false;
}
}
if (c.version_num < min_driver_version) {
return false;
}
if (c.attribs.localRAM*MEGA < min_ram) {
return false;
}
hu.gpu_ram = min_ram;
hu.ncudas = ndevs;
coproc_perf(
g_request->host.p_fpops,
hu.natis*c.peak_flops(),
cpu_frac,
hu.projected_flops,
hu.avg_ncpus
);
hu.peak_flops = hu.natis*c.peak_flops() + hu.avg_ncpus*g_request->host.p_fpops;
hu.max_ncpus = hu.avg_ncpus;
hu.projected_flops *= flops_scale;
return true;
}
#define ATI_MIN_RAM 250*MEGA
static inline bool app_plan_ati(
SCHEDULER_REQUEST& sreq, char* plan_class, HOST_USAGE& hu
) {
char buf[256];
COPROC_ATI* cp = &sreq.coprocs.ati;
if (!cp->count) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] Host lacks ATI GPU for plan class ati\n"
);
}
//add_no_work_message("Your computer has no ATI GPU");
COPROC_ATI& c = sreq.coprocs.ati;
if (!c.count) {
return false;
}
int major, minor, release;
sscanf(cp->version, "%d.%d.%d", &major, &minor, &release);
int vers = major*1000000 + minor*1000 + release;
double min_ram = 250*MEGA;
if (!strcmp(plan_class, "ati")) {
if (vers < 1000000) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] host has CAL version %s, need 1.0+\n",
cp->version
);
}
//add_no_work_message("ATI Catalyst 8.12+ needed to use GPU");
return false;
}
if (!cp->amdrt_detected) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] ati libs found, need amd\n"
);
}
//add_no_work_message("Need libraries named amd* to use ATI GPU");
if (!ati_check(c, hu,
1000000,
true,
ATI_MIN_RAM,
1, .01,
1
)) {
return false;
}
}
if (!strcmp(plan_class, "ati13amd")) {
if (vers < 1003000) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] host has CAL version %s, need 1.3.0 to 1.3.186\n",
cp->version
);
}
//add_no_work_message("ATI Catalyst 9.1+ needed to use GPU");
return false;
}
if (!cp->amdrt_detected) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] ati libs found, need amd\n"
);
}
//add_no_work_message("Need libraries named amd* to use ATI GPU");
if (!ati_check(c, hu,
1003000,
true,
ATI_MIN_RAM,
1, .01,
1.01
)) {
return false;
}
}
if (!strcmp(plan_class, "ati13ati")) {
if (vers < 1003186) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] host has CAL version %s, need 1.3.186+\n",
cp->version
);
}
//add_no_work_message("ATI Catalyst 9.2+ needed to use GPU");
return false;
}
if (!cp->atirt_detected) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] amd libs found, need ati\n"
);
}
//add_no_work_message("Need libraries named ati* to use ATI GPU");
if (!ati_check(c, hu,
1003186,
false,
ATI_MIN_RAM,
1, .01,
1.02
)) {
return false;
}
}
if (!strcmp(plan_class, "ati14")) {
if (vers < 1004000) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] host has CAL version %s, need 1.4+\n",
cp->version
);
}
//add_no_work_message("ATI Catalyst 9.7+ needed to use GPU");
return false;
}
if (!cp->atirt_detected) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] amd libs found, need ati\n"
);
}
//add_no_work_message("Need libraries named ati* to use ATI GPU");
if (!ati_check(c, hu,
1004000,
false,
ATI_MIN_RAM,
1, .01,
1.03
)) {
return false;
}
}
@ -254,57 +247,6 @@ static inline bool app_plan_ati(
return false;
}
if (cp->attribs.localRAM*MEGA < min_ram) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] ATI mem %dMB < %d\n",
cp->attribs.localRAM, (int)(min_ram/MEGA)
);
}
#if 0
sprintf(buf,
"Your ATI GPU has insufficient memory (need %.0fMB)",
min_ram/MEGA
);
add_no_work_message(buf);
#endif
return false;
}
hu.gpu_ram = 200*MEGA;
hu.natis = 1;
//hu.natis = .5; // you can use a fractional GPU if you want
// the fraction of the app's FLOPS that are performed by the CPU
//
double cpu_frac = .01; // an app that runs 99% on the GPU
//double cpu_frac = .75; // for SETI@home Astropulse
coproc_perf(
sreq.host.p_fpops,
hu.natis*cp->peak_flops(),
cpu_frac,
hu.projected_flops,
hu.avg_ncpus
);
hu.peak_flops = hu.natis*cp->peak_flops() + hu.avg_ncpus*sreq.host.p_fpops;
hu.max_ncpus = hu.avg_ncpus;
// determine priority among variants of ATI
// 1. ati14
// 2. ati13ati
// 3. ati13amd
// 4. ati
if (!strcmp(plan_class, "ati13amd")) {
hu.projected_flops *= 1.01;
}
if (!strcmp(plan_class, "ati13ati")) {
hu.projected_flops *= 1.02;
}
if (!strcmp(plan_class, "ati14")) {
hu.projected_flops *= 1.03;
}
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] %s ATI app projected %.2fG peak %.2fG %.3f CPUs\n",
@ -317,11 +259,65 @@ static inline bool app_plan_ati(
return true;
}
#define CUDA_MIN_DRIVER_VERSION 17700
#define CUDA23_MIN_DRIVER_VERSION 19038
#define CUDA_OPENCL_MIN_DRIVER_VERSION 19713
#define CUDA_MIN_RAM (254.*1024*1024)
#define CUDA23_MIN_RAM (384.*1024*1024)
GPU_REQUIREMENTS cuda_requirements;
#define CUDA_MIN_DRIVER_VERSION 17700
#define CUDA23_MIN_CUDA_VERSION 2030
#define CUDA23_MIN_DRIVER_VERSION 19038
#define CUDA3_MIN_CUDA_VERSION 3000
#define CUDA3_MIN_DRIVER_VERSION 19500
#define CUDA_OPENCL_MIN_DRIVER_VERSION 19713
static bool cuda_check(COPROC_CUDA& 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 (cc < min_cc) return false;
if (max_cc && cc >= max_cc) return false;
cuda_requirements.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) {
return false;
}
if (c.cuda_version) {
if (min_cuda_version && (c.cuda_version < min_cuda_version)) {
return false;
}
}
if (c.display_driver_version) {
if (min_driver_version && (c.display_driver_version < min_driver_version)) {
return false;
}
}
if (c.prop.dtotalGlobalMem < min_ram) {
return false;
}
hu.gpu_ram = min_ram;
hu.ncudas = ndevs;
coproc_perf(
g_request->host.p_fpops,
hu.ncudas*c.peak_flops(),
cpu_frac,
hu.projected_flops,
hu.avg_ncpus
);
hu.peak_flops = hu.ncudas*c.peak_flops() + hu.avg_ncpus*g_request->host.p_fpops;
hu.max_ncpus = hu.avg_ncpus;
hu.projected_flops *= flops_scale;
return true;
}
// the following is for an app that uses an NVIDIA GPU
//
@ -329,47 +325,16 @@ static inline bool app_plan_cuda(
SCHEDULER_REQUEST& sreq, char* plan_class, HOST_USAGE& hu
) {
char buf[256];
COPROC_CUDA* cp = &sreq.coprocs.cuda;
if (!cp->count) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] Host lacks CUDA coprocessor for plan class %s\n",
plan_class
);
}
//add_no_work_message("Your computer has no NVIDIA GPU");
COPROC_CUDA& c = sreq.coprocs.cuda;
if (!c.count) {
return false;
}
// Macs require 6.10.28
//
if (strstr(sreq.host.os_name, "Darwin")) {
if (sreq.core_client_version < 61028) {
#if 0
add_no_work_message(
"NVIDIA GPU apps require BOINC version 6.10.28+"
);
#endif
return false;
}
}
// check compute capability
//
int compute_capability = cp->prop.major*100 + cp->prop.minor;
if (compute_capability < 100) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] Compute capability %d < 1.0\n", compute_capability
);
}
#if 0
add_no_work_message(
"Your NVIDIA GPU lacks the needed compute capability"
);
#endif
if (strstr(sreq.host.os_name, "Darwin") && (sreq.core_client_version < 61028)) {
return false;
}
}
double min_ram;
@ -378,75 +343,43 @@ static inline bool app_plan_cuda(
// newer ones report CUDA RT version
//
if (!strcmp(plan_class, "cuda_fermi")) {
if (compute_capability < 200) {
//add_no_work_message("Fermi-class GPU needed");
if (!cuda_check(c, hu,
200, 0,
CUDA3_MIN_CUDA_VERSION, CUDA3_MIN_DRIVER_VERSION,
384*MEGA,
1, .01, 1.02
)) {
return false;
}
if (cp->cuda_version < 3000) {
//add_no_work_message("CUDA version 3.0 needed");
return false;
}
min_ram = CUDA23_MIN_RAM;
} else if (!strcmp(plan_class, "cuda23")) {
if (compute_capability >= 200) { // temp
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,
384*MEGA,
1, .01, 1.01
)) {
return false;
}
if (cp->cuda_version) {
if (cp->cuda_version < 2030) {
//add_no_work_message("CUDA version 2.3 needed");
return false;
}
} else if (cp->display_driver_version) {
if (cp->display_driver_version < CUDA23_MIN_DRIVER_VERSION) {
#if 0
sprintf(buf, "NVIDIA display driver %d or later needed",
CUDA23_MIN_DRIVER_VERSION
);
add_no_work_message(buf);
#endif
return false;
}
} else {
// pre-6.10 Linux clients report neither CUDA nor driver
// version; they'll end up here
//
//add_no_work_message("CUDA version 2.3 needed");
return false;
}
min_ram = CUDA23_MIN_RAM;
} else if (!strcmp(plan_class, "cuda_opencl")) {
if (!cp->display_driver_version
|| cp->display_driver_version < CUDA23_MIN_DRIVER_VERSION
) {
#if 0
sprintf(buf, "NVIDIA display driver %d or later needed",
CUDA_OPENCL_MIN_DRIVER_VERSION
);
add_no_work_message(buf);
#endif
if (!cuda_check(c, hu,
100, 0,
0, CUDA_OPENCL_MIN_DRIVER_VERSION,
384*MEGA,
1, .01, 1
)) {
return false;
}
min_ram = CUDA23_MIN_RAM;
} else if (!strcmp(plan_class, "cuda")) {
if (compute_capability >= 200) { // temp
if (!cuda_check(c, hu,
100,
200, // change to zero if app is compiled to byte code
0, CUDA_MIN_DRIVER_VERSION,
254*MEGA,
1, .01, 1
)) {
return false;
}
if (cp->display_driver_version && cp->display_driver_version < CUDA_MIN_DRIVER_VERSION) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] NVIDIA driver version %d < CUDA_MIN_DRIVER_VERSION\n",
cp->display_driver_version
);
}
#if 0
sprintf(buf, "NVIDIA driver version %d or later needed",
CUDA_MIN_DRIVER_VERSION
);
add_no_work_message(buf);
#endif
return false;
}
min_ram = CUDA_MIN_RAM;
} else {
log_messages.printf(MSG_CRITICAL,
"UNKNOWN PLAN CLASS %s\n", plan_class
@ -454,48 +387,6 @@ static inline bool app_plan_cuda(
return false;
}
if (cp->prop.dtotalGlobalMem < min_ram) {
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] CUDA mem %.0fMB < %.0fMB\n",
cp->prop.dtotalGlobalMem/MEGA, min_ram/MEGA
);
}
#if 0
sprintf(buf,
"Your NVIDIA GPU has insufficient memory (need %.0fMB)",
min_ram/MEGA
);
add_no_work_message(buf);
#endif
return false;
}
hu.gpu_ram = 200*MEGA;
hu.ncudas = 1;
//hu.ncudas = .5; // you can use a fractional GPU if you want
// the fraction of the app's FLOPS that are performed by the CPU
//
double cpu_frac = .01; // an app that runs 99% on the GPU
// double cpu_frac = .75; // for SETI@home Astropulse
coproc_perf(
sreq.host.p_fpops,
hu.ncudas*cp->peak_flops(),
cpu_frac,
hu.projected_flops,
hu.avg_ncpus
);
hu.peak_flops = hu.ncudas*cp->peak_flops() + hu.avg_ncpus*sreq.host.p_fpops;
hu.max_ncpus = hu.avg_ncpus;
if (!strcmp(plan_class, "cuda23")) {
hu.projected_flops *= 1.01;
} else if (!strcmp(plan_class, "cuda_fermi")) {
hu.projected_flops *= 1.02;
}
if (config.debug_version_select) {
log_messages.printf(MSG_NORMAL,
"[version] %s app projected %.2fG peak %.2fG %.3f CPUs\n",

View File

@ -18,6 +18,43 @@
#include "boinc_db.h"
#include "sched_types.h"
struct GPU_REQUIREMENTS {
double min_ram;
double opt_ram;
int min_driver_version;
int opt_driver_version;
void clear() {
min_ram = opt_ram = 0;
min_driver_version = opt_driver_version = 0;
}
void update(int version, double ram) {
if (min_driver_version) {
if (version < min_driver_version) {
min_driver_version = version;
}
} else {
min_driver_version = version;
}
if (version > opt_driver_version) {
opt_driver_version = version;
}
if (min_ram) {
if (ram < min_ram) {
min_ram = ram;
}
} else {
min_ram = ram;
}
if (ram > opt_ram) {
opt_ram = ram;
}
}
};
extern GPU_REQUIREMENTS cuda_requirements;
extern GPU_REQUIREMENTS ati_requirements;
extern bool wu_is_infeasible_custom(WORKUNIT&, APP&, BEST_APP_VERSION&);
extern bool app_plan(SCHEDULER_REQUEST&, char* plan_class, HOST_USAGE&);
extern bool app_plan_uses_gpu(const char* plan_class);

View File

@ -1208,13 +1208,104 @@ int add_result_to_reply(
return 0;
}
// send messages to user about why jobs were or weren't sent
// Send high-priority messages about things the user can change easily
// (namely the driver version)
// and low-priority messages about things that can't easily be changed,
// but which may be interfering with getting tasks or latest apps
//
static void explain_to_user() {
static void send_gpu_messages(
GPU_REQUIREMENTS& req, double ram, int version, char* rsc_name
) {
char buf[256];
if (ram < req.min_ram) {
sprintf(buf,
"A minimum of %d MB (preferably %d MB) of video RAM is needed to process tasks using your computer's %s",
(int) (req.min_ram/MEGA),
(int) (req.opt_ram/MEGA),
rsc_name
);
g_reply->insert_message(buf, "low");
} else {
if (version) {
if (version < req.min_driver_version) {
sprintf(buf,
"Upgrade to the latest %s driver to process tasks using your computer's %s",
rsc_name, rsc_name
);
g_reply->insert_message(buf, "high");
} else if (version < req.opt_driver_version) {
sprintf(buf,
"Upgrade to the latest %s driver to use all of this project's GPU applications",
rsc_name
);
g_reply->insert_message(buf, "low");
}
}
}
}
// send messages to user about why jobs were or weren't sent,
// recommendations for GPU driver upgrades, etc.
//
static void send_user_messages() {
char buf[512];
unsigned int i;
int j;
// Mac client with GPU but too-old client
//
if (g_request->coprocs.cuda.count
&& ssp->have_cuda_apps
&& strstr(g_request->host.os_name, "Darwin")
&& g_request->core_client_version < 61028
) {
g_reply->insert_message(
"A newer version of BOINC is needed to use your NVIDIA GPU; please upgrade to the current version",
"high"
);
}
// GPU-only project, client lacks GPU
//
bool usable_gpu = (ssp->have_cuda_apps && g_request->coprocs.cuda.count)
|| (ssp->have_ati_apps && g_request->coprocs.ati.count);
if (!ssp->have_cpu_apps && !usable_gpu) {
if (ssp->have_cuda_apps) {
if (ssp->have_ati_apps) {
g_reply->insert_message(
"An NVIDIA or ATI GPU is required to run tasks for this project",
"high"
);
} else {
g_reply->insert_message(
"An NVIDIA GPU is required to run tasks for this project",
"high"
);
}
} else if (ssp->have_ati_apps) {
g_reply->insert_message(
"An ATI GPU is required to run tasks for this project",
"high"
);
}
}
if (g_request->coprocs.cuda.count && ssp->have_cuda_apps) {
send_gpu_messages(cuda_requirements,
g_request->coprocs.cuda.prop.dtotalGlobalMem,
g_request->coprocs.cuda.display_driver_version,
"NVIDIA GPU"
);
}
if (g_request->coprocs.ati.count && ssp->have_ati_apps) {
send_gpu_messages(ati_requirements,
g_request->coprocs.ati.attribs.localRAM*MEGA,
g_request->coprocs.ati.version_num,
"ATI GPU"
);
}
// If work was sent from apps the user did not select, explain.
// NOTE: this will have to be done differently with matchmaker scheduling
//
@ -1295,12 +1386,12 @@ static void explain_to_user() {
if (g_wreq->speed.insufficient) {
if (g_request->core_client_version>41900) {
sprintf(buf,
"Jobs won't finish in time: BOINC runs %.1f%% of the time; computation is enabled %.1f%% of that",
"Tasks won't finish in time: BOINC runs %.1f%% of the time; computation is enabled %.1f%% of that",
100*g_reply->host.on_frac, 100*g_reply->host.active_frac
);
} else {
sprintf(buf,
"Jobs won't finish in time: Computer available %.1f%% of the time",
"Tasks won't finish in time: Computer available %.1f%% of the time",
100*g_reply->host.on_frac
);
}
@ -1320,7 +1411,7 @@ static void explain_to_user() {
}
if (g_wreq->outdated_client) {
g_reply->insert_message(
"Newer client version required; please install current version",
"Newer BOINC version required; please install current version",
"high"
);
g_reply->set_delay(DELAY_NO_WORK_PERM);
@ -1357,7 +1448,7 @@ static void explain_to_user() {
struct tm *rpc_time_tm;
int delay_time;
sprintf(buf, "(reached daily quota of %d tasks)",
sprintf(buf, "This computer has finished a daily quota of %d tasks)",
havp->max_jobs_per_day
);
g_reply->insert_message(buf, "low");
@ -1367,18 +1458,11 @@ static void explain_to_user() {
);
g_reply->set_delay(DELAY_NO_WORK_CACHE);
}
if (g_wreq->max_jobs_on_host_exceeded) {
sprintf(buf, "(reached limit of tasks in progress)");
g_reply->insert_message(buf, "low");
g_reply->set_delay(DELAY_NO_WORK_CACHE);
}
if (g_wreq->max_jobs_on_host_cpu_exceeded) {
sprintf(buf, "(reached limit of CPU tasks in progress)");
g_reply->insert_message(buf, "low");
g_reply->set_delay(DELAY_NO_WORK_CACHE);
}
if (g_wreq->max_jobs_on_host_gpu_exceeded) {
sprintf(buf, "(reached limit of GPU tasks in progress)");
if (g_wreq->max_jobs_on_host_exceeded
|| g_wreq->max_jobs_on_host_cpu_exceeded
|| g_wreq->max_jobs_on_host_gpu_exceeded
) {
sprintf(buf, "This computer has reached a limit on tasks in progress");
g_reply->insert_message(buf, "low");
g_reply->set_delay(DELAY_NO_WORK_CACHE);
}
@ -1405,6 +1489,8 @@ void send_work_setup() {
if (g_wreq->anonymous_platform) {
estimate_flops_anon_platform();
}
cuda_requirements.clear();
ati_requirements.clear();
g_wreq->disk_available = max_allowable_disk();
get_mem_sizes();
@ -1564,6 +1650,12 @@ int update_host_app_versions(vector<RESULT>& results, int hostid) {
void send_work() {
int retval;
if (!work_needed(false)) {
send_user_messages();
return;
}
g_wreq->no_jobs_available = true;
if (!g_wreq->rsc_spec_request && g_wreq->seconds_to_fill == 0) {
return;
}
@ -1600,11 +1692,6 @@ void send_work() {
);
}
// assume no jobs are available to send;
// if this turns out not to be the case, clear this flag
//
g_wreq->no_jobs_available = true;
if (config.locality_scheduler_fraction > 0) {
if (drand() < config.locality_scheduler_fraction) {
if (config.debug_locality) {
@ -1648,7 +1735,7 @@ done:
"update_host_app_versions() failed: %d\n", retval
);
}
explain_to_user();
send_user_messages();
}
const char *BOINC_RCSID_32dcd335e7 = "$Id$";