mirror of https://github.com/BOINC/boinc.git
- 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:
parent
6511e1f8e8
commit
81973a9fff
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
232
lib/notice.cpp
232
lib/notice.cpp
|
@ -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, "");
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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$";
|
||||
|
|
Loading…
Reference in New Issue