- 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/
<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',
'French',
'German',
'Greek',
'Gujarati',
'Hausa',
'Hindi',

View File

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

View File

@ -36,6 +36,10 @@
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) {
char tag[1024], temp[1024];
bool is_tag;
@ -51,7 +55,7 @@ int SCHED_CONFIG::parse(FILE* f) {
sched_debug_level = SCHED_MSG_LOG::MSG_NORMAL;
fuh_debug_level = SCHED_MSG_LOG::MSG_NORMAL;
strcpy(httpd_user, "apache");
max_ncpus = MAX_NCPUS;
if (!xp.parse_start("boinc")) 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_bool(tag, "request_time_stats_log", request_time_stats_log)) 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;
// 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
bool request_time_stats_log;
bool enable_assignment;
int max_ncpus;
int parse(FILE*);
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 MAX_SECONDS_TO_SEND = (28*SECONDS_IN_DAY);
const int MAX_CPUS = 8;
// max multiplier for daily_result_quota and max_wus_in_progress;
// need to change as multicore processors expand
inline int effective_ncpus(HOST& host) {
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;
// 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;
update_average(0, 0, CREDIT_HALF_LIFE, expavg_credit, expavg_time);
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")
) {
credit_scale = 1;
@ -306,7 +313,8 @@ static int get_host_info(SCHEDULER_REPLY& reply) {
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)
){
reply.wreq.host_info.reliable = true;
@ -481,7 +489,7 @@ int wu_is_infeasible(
double est_cpu = estimate_cpu_duration(wu, reply);
IP_RESULT candidate("", wu.delay_bound, est_cpu);
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,
// but don't add it the the workload yet;
// 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;
// daily quota and max jobs per host are scaled by #CPUs,
// 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;
int ncpus = effective_ncpus(host);
// host.max_results_day is between 1 and config.daily_result_quota inclusive
// wreq.daily_result_quota is between ncpus
@ -892,7 +895,7 @@ int add_result_to_reply(
}
reply.insert_result(result);
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_on_host++;
if (!resent_result) reply.host.nresults_today++;
@ -965,7 +968,7 @@ void send_work(
if (config.workload_sim && sreq.have_other_results_list) {
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
);
}