- scheduler: add <max_ncpus> config option.

Use this with N=1 if your application primarily uses a coprocessor

svn path=/trunk/boinc/; revision=14772
This commit is contained in:
David Anderson 2008-02-21 20:10:10 +00:00
parent 3ce02d1a2b
commit 79f6720547
6 changed files with 87 additions and 53 deletions

View File

@ -1543,3 +1543,10 @@ Rom Feb 21 2008
curl/ curl/
<Various Files> <Various Files>
David Feb 21 2008
- scheduler: add <max_ncpus> config option.
Use this with N=1 if your application primarily uses a coprocessor
sched/
sched_config.C,h
sched_send.C

View File

@ -21,6 +21,7 @@ $spoken_languages = array(
'English', 'English',
'French', 'French',
'German', 'German',
'Greek',
'Gujarati', 'Gujarati',
'Hausa', 'Hausa',
'Hindi', 'Hindi',

View File

@ -4,23 +4,28 @@ require_once("../inc/bolt_db.inc");
require_once("../inc/util_ops.inc"); require_once("../inc/util_ops.inc");
function show_course($course) { function show_course($course) {
echo "<tr> $x = "<b>$course->name</b>
<td>Name: $course->name<br>Description: $course->description<br>Created: ".date_str($course->create_time)."</td> <br>Description: $course->description
<td>$course->doc_file</td> <br>Created: ".date_str($course->create_time)."
<td> <br>Course document: $course->doc_file
"; ";
$y = "<a href=bolt_map.php?course_id=$course->id>Course map</a>
<br><a href=bolt_compare.php?course_id=$course->id>Lesson compare</a>
<br>
";
row2_init($x, $y);
if ($course->hidden) { if ($course->hidden) {
show_button("bolt_admin.php?action=unhide&course_id=$course->id", "Unhide", "Unhide this course"); show_button("bolt_admin.php?action=unhide&course_id=$course->id", "Unhide", "Unhide this course");
} else { } else {
show_button("bolt_admin.php?action=hide&course_id=$course->id", "Hide", "Hide this course"); show_button("bolt_admin.php?action=hide&course_id=$course->id", "Hide", "Hide this course");
} }
echo "</td></tr>";
} }
function show_courses() { function show_courses() {
$courses = BoltCourse::enum(); $courses = BoltCourse::enum();
start_table(); start_table();
row1("Existing courses", 3); table_header("Course", "Tools");
table_header("Name/description", "Course document", "");
foreach ($courses as $course) { foreach ($courses as $course) {
show_course($course); show_course($course);
} }
@ -30,14 +35,15 @@ function show_courses() {
function add_course_form() { function add_course_form() {
echo " echo "
<form action=bolt_admin.php method=get> <form action=bolt_admin.php method=get>
<input type=hidden name=action value=add_course>
"; ";
start_table(); start_table();
row1("Add course"); row1("Add course");
row2("Name<span class=note><br>Visible to users</span>", "<input name=course_name>"); row2("Course name<span class=note><br>Visible to users</span>", "<input name=course_name>");
row2("Internal name<span class=note><br>Not visible to users; used as a directory name, so no spaces or special chars</span>", "<input name=short_name>"); row2("Internal name<span class=note><br>Not visible to users; used as a directory name, so no spaces or special chars</span>", "<input name=short_name>");
row2("Description<span class=note><br>Visible to users</span>", "<textarea name=description cols=60></textarea>"); row2("Description<span class=note><br>Visible to users</span>", "<textarea name=description cols=60></textarea>");
row2("Course document", "<input name=doc_file>"); row2("Course document", "<input name=doc_file>");
row2("", "<input type=submit name=submit value=\"Create course\">"); row2("", "<input type=submit name=submit value=\"Add course\">");
end_table(); end_table();
echo "</form>"; echo "</form>";
} }
@ -45,14 +51,16 @@ function add_course_form() {
function user_settings() { function user_settings() {
global $user; global $user;
$flags = $user->bolt->flags; $flags = $user->bolt->flags;
echo "<form action=bolt_admin.php method=get>"; echo "<form action=bolt_admin.php method=get>
<input type=hidden name=action value=update_user>
";
start_table(); start_table();
row1("User settings"); row1("User settings");
$x = ($flags&BOLT_FLAGS_SHOW_ALL)?"checked":""; $x = ($flags&BOLT_FLAGS_SHOW_ALL)?"checked":"";
row2("Show hidden courses?", "<input type=checkbox name=show_all $x>"); row2("Show hidden courses?", "<input type=checkbox name=show_all $x>");
$x = ($flags&BOLT_FLAGS_DEBUG)?"checked":""; $x = ($flags&BOLT_FLAGS_DEBUG)?"checked":"";
row2("Show debugging output?", "<input type=checkbox name=debug $x>"); row2("Show debugging output?", "<input type=checkbox name=debug $x>");
row2("", "<input type=submit name=submit value=\"Update user\">"); row2("", "<input type=submit name=submit value=\"Update settings\">");
end_table(); end_table();
echo "</form>"; echo "</form>";
} }
@ -60,18 +68,27 @@ function user_settings() {
function show_all() { function show_all() {
admin_page_head("Bolt course administration"); admin_page_head("Bolt course administration");
show_courses(); show_courses();
echo "<p>"; echo "<p>
add_course_form(); <a href=bolt_admin.php?action=add_course_form>Add course</a>
echo "<p>"; <p>
user_settings(); <a href=bolt_admin.php?action=update_user_form>User settings</a>
";
admin_page_tail(); admin_page_tail();
} }
$user = get_logged_in_user(); $user = get_logged_in_user();
BoltUser::lookup($user); BoltUser::lookup($user);
$course_id = get_int('course_id', true);
if ($course_id) $course = BoltCourse::lookup_id($course_id);
$submit = get_str('submit', true); $action = get_str('action', true);
if ($submit == 'Create course') { switch ($action) {
case 'add_course_form':
admin_page_head("Add course");
add_course_form();
admin_page_tail();
break;
case 'add_course':
$short_name = BoltDb::escape_string(get_str('short_name')); $short_name = BoltDb::escape_string(get_str('short_name'));
$name = BoltDb::escape_string(get_str('course_name')); $name = BoltDb::escape_string(get_str('course_name'));
$description = BoltDb::escape_string(get_str('description')); $description = BoltDb::escape_string(get_str('description'));
@ -79,36 +96,36 @@ if ($submit == 'Create course') {
$now = time(); $now = time();
BoltCourse::insert("(create_time, short_name, name, description, doc_file) values ($now, '$short_name', '$name', '$description', '$doc_file')"); BoltCourse::insert("(create_time, short_name, name, description, doc_file) values ($now, '$short_name', '$name', '$description', '$doc_file')");
Header('Location: bolt_admin.php'); Header('Location: bolt_admin.php');
exit(); break;
} else if ($submit == 'Update user') { case 'update_user_form':
admin_page_head("Bolt user settings");
user_settings();
admin_page_tail();
break;
case 'update_user':
$flags = 0; $flags = 0;
if (get_str('show_all', true)) $flags |= BOLT_FLAGS_SHOW_ALL; if (get_str('show_all', true)) $flags |= BOLT_FLAGS_SHOW_ALL;
if (get_str('debug', true)) $flags |= BOLT_FLAGS_DEBUG; if (get_str('debug', true)) $flags |= BOLT_FLAGS_DEBUG;
$user->bolt->update("flags=$flags"); $user->bolt->update("flags=$flags");
$user->bolt->flags = $flags; $user->bolt->flags = $flags;
Header('Location: bolt_admin.php'); Header('Location: bolt_admin.php');
exit(); break;
} else { case 'hide':
$action = get_str('action', true); if (!$course) error_page("no such course");
if ($action) { $course->update("hidden=1");
$course_id = get_int('course_id'); Header('Location: bolt_admin.php');
$course = BoltCourse::lookup_id($course_id); break;
if (!$course) error_page("no such course"); case 'unhide':
switch ($action) { if (!$course) error_page("no such course");
case 'hide': $course->update("hidden=0");
$course->update("hidden=1"); Header('Location: bolt_admin.php');
break; break;
case 'unhide': case '':
$course->update("hidden=0"); show_all();
break; break;
default: default:
error_page("unknown action $action"); error_page("unknown action $action");
}
Header('Location: bolt_admin.php');
exit();
}
} }
show_all();
?> ?>

View File

@ -36,6 +36,10 @@
const char* CONFIG_FILE = "config.xml"; const char* CONFIG_FILE = "config.xml";
const int MAX_NCPUS = 8;
// max multiplier for daily_result_quota and max_wus_in_progress;
// need to change as multicore processors expand
int SCHED_CONFIG::parse(FILE* f) { int SCHED_CONFIG::parse(FILE* f) {
char tag[1024], temp[1024]; char tag[1024], temp[1024];
bool is_tag; bool is_tag;
@ -51,7 +55,7 @@ int SCHED_CONFIG::parse(FILE* f) {
sched_debug_level = SCHED_MSG_LOG::MSG_NORMAL; sched_debug_level = SCHED_MSG_LOG::MSG_NORMAL;
fuh_debug_level = SCHED_MSG_LOG::MSG_NORMAL; fuh_debug_level = SCHED_MSG_LOG::MSG_NORMAL;
strcpy(httpd_user, "apache"); strcpy(httpd_user, "apache");
max_ncpus = MAX_NCPUS;
if (!xp.parse_start("boinc")) return ERR_XML_PARSE; if (!xp.parse_start("boinc")) return ERR_XML_PARSE;
if (!xp.parse_start("config")) return ERR_XML_PARSE; if (!xp.parse_start("config")) return ERR_XML_PARSE;
@ -141,6 +145,7 @@ int SCHED_CONFIG::parse(FILE* f) {
if (xp.parse_int(tag, "file_deletion_strategy", file_deletion_strategy)) continue; if (xp.parse_int(tag, "file_deletion_strategy", file_deletion_strategy)) continue;
if (xp.parse_bool(tag, "request_time_stats_log", request_time_stats_log)) continue; if (xp.parse_bool(tag, "request_time_stats_log", request_time_stats_log)) continue;
if (xp.parse_bool(tag, "enable_assignment", enable_assignment)) continue; if (xp.parse_bool(tag, "enable_assignment", enable_assignment)) continue;
if (xp.parse_int(tag, "max_ncpus", max_ncpus)) continue;
// don't complain about unparsed XML; // don't complain about unparsed XML;
// there are lots of tags the scheduler doesn't know about // there are lots of tags the scheduler doesn't know about

View File

@ -111,6 +111,7 @@ public:
// select method of automatically deleting files from host // select method of automatically deleting files from host
bool request_time_stats_log; bool request_time_stats_log;
bool enable_assignment; bool enable_assignment;
int max_ncpus;
int parse(FILE*); int parse(FILE*);
int parse_file(const char* dir="."); int parse_file(const char* dir=".");

View File

@ -72,9 +72,13 @@ const char* infeasible_string(int code) {
const int MIN_SECONDS_TO_SEND = 0; const int MIN_SECONDS_TO_SEND = 0;
const int MAX_SECONDS_TO_SEND = (28*SECONDS_IN_DAY); const int MAX_SECONDS_TO_SEND = (28*SECONDS_IN_DAY);
const int MAX_CPUS = 8;
// max multiplier for daily_result_quota and max_wus_in_progress; inline int effective_ncpus(HOST& host) {
// need to change as multicore processors expand int ncpus = host.p_ncpus;
if (ncpus > config.max_ncpus) ncpus = config.max_ncpus;
if (ncpus < 1) ncpus = 1;
return ncpus;
}
const double DEFAULT_RAM_SIZE = 64000000; const double DEFAULT_RAM_SIZE = 64000000;
// if host sends us an impossible RAM size, use this instead // if host sends us an impossible RAM size, use this instead
@ -297,6 +301,9 @@ static int get_host_info(SCHEDULER_REPLY& reply) {
double avg_turnaround = reply.host.avg_turnaround; double avg_turnaround = reply.host.avg_turnaround;
update_average(0, 0, CREDIT_HALF_LIFE, expavg_credit, expavg_time); update_average(0, 0, CREDIT_HALF_LIFE, expavg_credit, expavg_time);
double credit_scale, turnaround_scale; double credit_scale, turnaround_scale;
// TODO: is the following still needed? Why?
//
if (strstr(reply.host.os_name,"Windows") || strstr(reply.host.os_name,"Linux") if (strstr(reply.host.os_name,"Windows") || strstr(reply.host.os_name,"Linux")
) { ) {
credit_scale = 1; credit_scale = 1;
@ -306,7 +313,8 @@ static int get_host_info(SCHEDULER_REPLY& reply) {
turnaround_scale = 1.25; turnaround_scale = 1.25;
} }
if (((expavg_credit/reply.host.p_ncpus) > config.reliable_min_avg_credit*credit_scale || config.reliable_min_avg_credit == 0) int ncpus = effective_ncpus(reply.host);
if (((expavg_credit/ncpus) > config.reliable_min_avg_credit*credit_scale || config.reliable_min_avg_credit == 0)
&& (avg_turnaround < config.reliable_max_avg_turnaround*turnaround_scale || config.reliable_max_avg_turnaround == 0) && (avg_turnaround < config.reliable_max_avg_turnaround*turnaround_scale || config.reliable_max_avg_turnaround == 0)
){ ){
reply.wreq.host_info.reliable = true; reply.wreq.host_info.reliable = true;
@ -481,7 +489,7 @@ int wu_is_infeasible(
double est_cpu = estimate_cpu_duration(wu, reply); double est_cpu = estimate_cpu_duration(wu, reply);
IP_RESULT candidate("", wu.delay_bound, est_cpu); IP_RESULT candidate("", wu.delay_bound, est_cpu);
strcpy(candidate.name, wu.name); strcpy(candidate.name, wu.name);
if (check_candidate(candidate, reply.host.p_ncpus, request.ip_results)) { if (check_candidate(candidate, effective_ncpus(reply.host), request.ip_results)) {
// it passed the feasibility test, // it passed the feasibility test,
// but don't add it the the workload yet; // but don't add it the the workload yet;
// wait until we commit to sending it // wait until we commit to sending it
@ -719,12 +727,7 @@ bool SCHEDULER_REPLY::work_needed(bool locality_sched) {
} }
if (wreq.nresults >= config.max_wus_to_send) return false; if (wreq.nresults >= config.max_wus_to_send) return false;
// daily quota and max jobs per host are scaled by #CPUs, int ncpus = effective_ncpus(host);
// but only up to MAX_CPUs (currently 8)
//
int ncpus = host.p_ncpus;
if (ncpus > MAX_CPUS) ncpus = MAX_CPUS;
if (ncpus < 1) ncpus = 1;
// host.max_results_day is between 1 and config.daily_result_quota inclusive // host.max_results_day is between 1 and config.daily_result_quota inclusive
// wreq.daily_result_quota is between ncpus // wreq.daily_result_quota is between ncpus
@ -892,7 +895,7 @@ int add_result_to_reply(
} }
reply.insert_result(result); reply.insert_result(result);
reply.wreq.seconds_to_fill -= wu_seconds_filled; reply.wreq.seconds_to_fill -= wu_seconds_filled;
request.estimated_delay += wu_seconds_filled/reply.host.p_ncpus; request.estimated_delay += wu_seconds_filled/effective_ncpus(reply.host);
reply.wreq.nresults++; reply.wreq.nresults++;
reply.wreq.nresults_on_host++; reply.wreq.nresults_on_host++;
if (!resent_result) reply.host.nresults_today++; if (!resent_result) reply.host.nresults_today++;
@ -965,7 +968,7 @@ void send_work(
if (config.workload_sim && sreq.have_other_results_list) { if (config.workload_sim && sreq.have_other_results_list) {
init_ip_results( init_ip_results(
sreq.global_prefs.work_buf_min(), reply.host.p_ncpus, sreq.ip_results sreq.global_prefs.work_buf_min(), effective_ncpus(reply.host), sreq.ip_results
); );
} }