mirror of https://github.com/BOINC/boinc.git
- web: remote job submission:
- add fields to batch table, extend APIs accordingly - require that example web interface run on BOINC server (this makes many things easier; an actual remote interface would require a bit more work) svn path=/trunk/boinc/; revision=23881
This commit is contained in:
parent
17e947f543
commit
6e5acbbe60
|
@ -4376,3 +4376,25 @@ David 26 July 2011
|
|||
forum_thread.php
|
||||
submit_example.php
|
||||
submit.php
|
||||
|
||||
David 26 July 2011
|
||||
- web: remote job submission:
|
||||
- add fields to batch table, extend APIs accordingly
|
||||
- require that example web interface run on BOINC server
|
||||
(this makes many things easier;
|
||||
an actual remote interface would require a bit more work)
|
||||
|
||||
db/
|
||||
boinc_db.h
|
||||
schema.sql
|
||||
html/
|
||||
ops/
|
||||
db_update.php
|
||||
inc/
|
||||
submit_db.inc
|
||||
submit.inc
|
||||
util.inc
|
||||
result.inc
|
||||
user/
|
||||
submit_example.php
|
||||
submit.php
|
||||
|
|
|
@ -563,6 +563,48 @@ struct RESULT {
|
|||
void clear();
|
||||
};
|
||||
|
||||
struct BATCH {
|
||||
int id;
|
||||
int user_id;
|
||||
// submitter
|
||||
int create_time;
|
||||
double logical_start_time;
|
||||
double logical_end_time;
|
||||
double est_completion_time;
|
||||
// current estimate of completion time
|
||||
int njobs;
|
||||
// # of workunits
|
||||
double fraction_done;
|
||||
// based on workunits completed
|
||||
int nerror_jobs;
|
||||
// # of workunits with error
|
||||
int state;
|
||||
// see below
|
||||
double completion_time;
|
||||
// when state became >= COMPLETE
|
||||
double credit_estimate;
|
||||
// initial estimate of required credit, counting replicas
|
||||
double credit_canonical;
|
||||
// the sum of credits of canonical results
|
||||
double credit_total;
|
||||
// the sum of credits of all results
|
||||
char name[256];
|
||||
// user-assigned name; need not be unique
|
||||
int app_id;
|
||||
}
|
||||
|
||||
// values of batch.state
|
||||
//
|
||||
#define BATCH_STATE_INIT 0
|
||||
#define BATCH_STATE_IN_PROGRESS 1
|
||||
#define BATCH_STATE_COMPLETE 2
|
||||
// "complete" means all workunits have either
|
||||
// a canonical result or an error
|
||||
#define BATCH_STATE_ABORTED 3
|
||||
#define BATCH_STATE_CLEANED_UP 4
|
||||
// input/output files can be deleted,
|
||||
// result and workunit records can be purged.
|
||||
|
||||
struct MSG_FROM_HOST {
|
||||
int id;
|
||||
int create_time;
|
||||
|
|
|
@ -282,6 +282,42 @@ create table result (
|
|||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
-- see boinc_db.h for doc
|
||||
create table batch (
|
||||
id serial primary key,
|
||||
user_id integer not null,
|
||||
create_time integer not null,
|
||||
logical_start_time double not null,
|
||||
logical_end_time double not null,
|
||||
est_completion_time double not null,
|
||||
njobs integer not null,
|
||||
fraction_done double not null,
|
||||
nerror_jobs integer not null,
|
||||
state integer not null,
|
||||
completion_time double not null,
|
||||
credit_estimate double not null,
|
||||
credit_canonical double not null,
|
||||
credit_total double not null,
|
||||
name varchar(255) not null,
|
||||
app_id integer not null
|
||||
) engine = InnoDB;
|
||||
|
||||
-- permissions for job submission
|
||||
--
|
||||
create table user_submit (
|
||||
user_id integer not null,
|
||||
quota double not null,
|
||||
logical_start_time double not null,
|
||||
all_apps tinyint not null
|
||||
) engine = InnoDB;
|
||||
|
||||
-- (user, app) submit permissions
|
||||
--
|
||||
create table user_submit_app (
|
||||
user_id integer not null,
|
||||
app_id integer not null
|
||||
) engine = InnoDB;
|
||||
|
||||
-- the following are used to implement trickle messages
|
||||
|
||||
create table msg_from_host (
|
||||
|
@ -638,29 +674,3 @@ create table notify (
|
|||
opaque integer not null
|
||||
-- some other ID, e.g. that of the thread, user or PM record
|
||||
);
|
||||
|
||||
create table batch (
|
||||
id serial primary key,
|
||||
user_id integer not null,
|
||||
create_time integer not null,
|
||||
logical_start_time double not null,
|
||||
logical_end_time double not null,
|
||||
est_completion_time double not null,
|
||||
njobs integer not null
|
||||
) engine = InnoDB;
|
||||
|
||||
-- permissions for job submission
|
||||
--
|
||||
create table user_submit (
|
||||
user_id integer not null,
|
||||
quota double not null,
|
||||
logical_start_time double not null,
|
||||
all_apps tinyint not null
|
||||
) engine = InnoDB;
|
||||
|
||||
-- (user, app) submit permissions
|
||||
--
|
||||
create table user_submit_app (
|
||||
user_id integer not null,
|
||||
app_id integer not null
|
||||
) engine = InnoDB;
|
||||
|
|
|
@ -567,7 +567,7 @@ function get_outfile_paths($result) {
|
|||
|
||||
function abort_workunit($wu) {
|
||||
BoincResult::update_aux(
|
||||
"server_state=5, outcome=5 where server_state=2 and workunit=$wu->id"
|
||||
"server_state=5, outcome=5 where server_state=2 and workunitid=$wu->id"
|
||||
);
|
||||
$wu->update("error_mask=error_mask|16");
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ function req_to_xml($req, $op) {
|
|||
<authenticator>$req->authenticator</authenticator>
|
||||
<batch>
|
||||
<app_name>$req->app_name</app_name>
|
||||
<batch_name>$req->batch_name</batch_name>
|
||||
";
|
||||
foreach ($req->jobs as $job) {
|
||||
$x .= " <job>
|
||||
|
@ -107,6 +108,24 @@ function boinc_submit_batch($req) {
|
|||
}
|
||||
}
|
||||
|
||||
function batch_xml_to_object($batch) {
|
||||
$b = null;
|
||||
$b->id = (int)($batch->id);
|
||||
$b->create_time = (double)($batch->create_time);
|
||||
$b->est_completion_time = (double)($batch->est_completion_time);
|
||||
$b->njobs = (int)($batch->njobs);
|
||||
$b->fraction_done = (double) $batch->fraction_done;
|
||||
$b->nerror_jobs = (int)($batch->nerror_jobs);
|
||||
$b->state = (int)($batch->state);
|
||||
$b->completion_time = (double)($batch->completion_time);
|
||||
$b->credit_estimate = (double)($batch->credit_estimate);
|
||||
$b->credit_canonical = (double)($batch->credit_canonical);
|
||||
$b->credit_total = (double)($batch->credit_total);
|
||||
$b->name = (string)($batch->name);
|
||||
$b->app_name = (string)($batch->app_name);
|
||||
return $b;
|
||||
}
|
||||
|
||||
function boinc_query_batches($req) {
|
||||
$req_xml = "<query_batches>
|
||||
<authenticator>$req->authenticator</authenticator>
|
||||
|
@ -116,14 +135,7 @@ function boinc_query_batches($req) {
|
|||
if ($errmsg) return array(null, $errmsg);
|
||||
$batches = array();
|
||||
foreach ($reply->batch as $batch) {
|
||||
$b = null;
|
||||
$b->id = (int)($batch->id);
|
||||
$b->completed = (int)($batch->completed);
|
||||
$b->njobs = (int)($batch->njobs);
|
||||
$b->create_time = (double)($batch->create_time);
|
||||
if (!$b->completed) {
|
||||
$b->fraction_done = (double) $batch->fraction_done;
|
||||
}
|
||||
$b = batch_xml_to_object($batch);
|
||||
$batches[] = $b;
|
||||
}
|
||||
return array($batches, null);
|
||||
|
@ -144,11 +156,7 @@ function boinc_query_batch($req) {
|
|||
$j->canonical_instance_id = (int)($job->canonical_instance_id);
|
||||
$jobs[] = $j;
|
||||
}
|
||||
$r = null;
|
||||
$r->fraction_done = (double)($reply->fraction_done);
|
||||
$r->completed = (int)($reply->completed);
|
||||
$r->create_time = (double)($reply->create_time);
|
||||
$r->est_completion_time = (double)($reply->est_completion_time);
|
||||
$r = batch_xml_to_object($reply);
|
||||
$r->jobs = $jobs;
|
||||
return array($r, null);
|
||||
}
|
||||
|
@ -208,11 +216,11 @@ function boinc_get_output_files($req) {
|
|||
return $req->project."/get_output.php?batch_id=$batch_id&auth_str=$auth_str";
|
||||
}
|
||||
|
||||
function boinc_cleanup_batch($req) {
|
||||
$req_xml = "<cleanup_batch>
|
||||
function boinc_retire_batch($req) {
|
||||
$req_xml = "<retire_batch>
|
||||
<authenticator>$req->authenticator</authenticator>
|
||||
<batch_id>$req->batch_id</batch_id>
|
||||
</cleanup_batch>
|
||||
</retire_batch>
|
||||
";
|
||||
list($reply, $errmsg) = do_http_op($req->project, $req_xml);
|
||||
if ($errmsg) return $errmsg;
|
||||
|
@ -223,6 +231,17 @@ function boinc_cleanup_batch($req) {
|
|||
return null;
|
||||
}
|
||||
|
||||
function batch_state_string($state) {
|
||||
switch ($state) {
|
||||
case BATCH_STATE_INIT: return "New";
|
||||
case BATCH_STATE_IN_PROGRESS: return "In progress";
|
||||
case BATCH_STATE_COMPLETE: return "Completed";
|
||||
case BATCH_STATE_ABORTED: return "Aborted";
|
||||
case BATCH_STATE_RETIRED: return "Retired";
|
||||
}
|
||||
return "Unknown state $state";
|
||||
}
|
||||
|
||||
//// example usage follows
|
||||
|
||||
$req->project = "http://isaac.ssl.berkeley.edu/test/";
|
||||
|
|
|
@ -33,8 +33,20 @@ class BoincBatch {
|
|||
if (!$ret) return $ret;
|
||||
return $db->insert_id();
|
||||
}
|
||||
function update($clause) {
|
||||
$db = BoincDb::get();
|
||||
return $db->update($this, 'batch', $clause);
|
||||
}
|
||||
}
|
||||
|
||||
// see db/boinc_db.h
|
||||
//
|
||||
define('BATCH_STATE_INIT', 0);
|
||||
define('BATCH_STATE_IN_PROGRESS', 1);
|
||||
define('BATCH_STATE_COMPLETE', 2);
|
||||
define('BATCH_STATE_ABORTED', 3);
|
||||
define('BATCH_STATE_RETIRED', 4);
|
||||
|
||||
class BoincUserSubmit {
|
||||
static function enum($clause) {
|
||||
$db = BoincDb::get();
|
||||
|
|
|
@ -32,8 +32,6 @@ if (array_key_exists("PATH_INFO", $_SERVER)) {
|
|||
|
||||
ini_set("memory_limit", "64M");
|
||||
|
||||
date_default_timezone_set("UTC");
|
||||
|
||||
if (!defined('SECURE_URL_BASE')) {
|
||||
define('SECURE_URL_BASE', URL_BASE);
|
||||
}
|
||||
|
@ -261,6 +259,11 @@ function time_str($x) {
|
|||
return gmdate('j M Y | G:i:s', $x) . " UTC";
|
||||
}
|
||||
|
||||
function local_time_str($x) {
|
||||
if ($x == 0) return "---";
|
||||
return date('j M Y | H:i:s', $x);
|
||||
}
|
||||
|
||||
function pretty_time_str($x) {
|
||||
return time_str($x);
|
||||
}
|
||||
|
|
|
@ -751,6 +751,21 @@ create table user_submit_app (
|
|||
) engine = InnoDB");
|
||||
}
|
||||
|
||||
function update_7_26_2011() {
|
||||
do_query("
|
||||
alter table batch
|
||||
add fraction_done double not null,
|
||||
add nerror_jobs integer not null,
|
||||
add state integer not null,
|
||||
add completion_time double not null,
|
||||
add credit_estimate double not null,
|
||||
add credit_canonical double not null,
|
||||
add credit_total double not null,
|
||||
add name varchar(255) not null,
|
||||
add app_id integer not null
|
||||
");
|
||||
}
|
||||
|
||||
// Updates are done automatically if you use "upgrade".
|
||||
//
|
||||
// If you need to do updates manually,
|
||||
|
@ -770,6 +785,7 @@ $db_updates = array (
|
|||
array(21728, "update_6_10_2010"),
|
||||
array(23635, "update_6_3_2011"),
|
||||
array(23762, "update_6_20_2011"),
|
||||
array(23881, "update_7_26_2011"),
|
||||
);
|
||||
|
||||
?>
|
||||
|
|
|
@ -73,13 +73,17 @@ function project_flops() {
|
|||
return $y;
|
||||
}
|
||||
|
||||
function est_elapsed_time($r) {
|
||||
// crude estimate: batch FLOPs / project FLOPS
|
||||
//
|
||||
return batch_flop_count($r) / project_flops();
|
||||
}
|
||||
|
||||
function estimate_batch($r) {
|
||||
$app = get_app($r);
|
||||
list($user, $user_submit) = authenticate_user($r, $app);
|
||||
|
||||
// crude estimate: batch FLOPs / project FLOPS
|
||||
//
|
||||
$e = batch_flop_count($r) / project_flops();
|
||||
$e = est_elapsed_time($r);
|
||||
echo "<estimate>\n<seconds>$e</seconds>\n</estimate>\n";
|
||||
}
|
||||
|
||||
|
@ -142,49 +146,84 @@ function submit_batch($r) {
|
|||
stage_files($r, $template);
|
||||
$njobs = count($r->batch->job);
|
||||
$now = time();
|
||||
$batch_name = (string)($r->batch->batch_name);
|
||||
$batch_id = BoincBatch::insert(
|
||||
"(user_id, create_time, njobs) values ($user->id, $now, $njobs)"
|
||||
"(user_id, create_time, njobs, name, app_id) values ($user->id, $now, $njobs, '$batch_name', $app->id)"
|
||||
);
|
||||
$i = 0;
|
||||
foreach($r->batch->job as $job) {
|
||||
submit_job($job, $template, $app, $batch_id, $i++);
|
||||
}
|
||||
$batch = BoincBatch::lookup_id($batch_id);
|
||||
$batch->update("state=".BATCH_STATE_IN_PROGRESS);
|
||||
echo "<batch_id>$batch_id</batch_id>\n";
|
||||
}
|
||||
|
||||
function fraction_done($batch) {
|
||||
$wus = BoincWorkunit::enum("batch = $batch->id");
|
||||
// compute and update params of a batch
|
||||
// NOTE: eventually this should be done by server components
|
||||
// (transitioner, validator etc.) as jobs complete or time out
|
||||
//
|
||||
// TODO: update est_completion_time
|
||||
//
|
||||
function get_batch_params($batch, $wus) {
|
||||
if ($batch->state > BATCH_STATE_IN_PROGRESS) return $batch;
|
||||
$fp_total = 0;
|
||||
$fp_done = 0;
|
||||
$completed = 1;
|
||||
$completed = true;
|
||||
$nerror_jobs = 0;
|
||||
$credit_canonical = 0;
|
||||
foreach ($wus as $wu) {
|
||||
$fp_total += $wu->rsc_fpops_est;
|
||||
if ($wu->canonical_resultid) {
|
||||
$fp_done += $wu->rsc_fpops_est;
|
||||
$credit_canonical += $wu->canonical_credit;
|
||||
} else if ($wu->error_mask) {
|
||||
$nerror_jobs++;
|
||||
} else {
|
||||
$completed = 0;
|
||||
$completed = false;
|
||||
}
|
||||
}
|
||||
if (!$fp_total) return array(1, true);;
|
||||
$fd= $fp_done / $fp_total;
|
||||
return array($fd, $completed);
|
||||
if ($fp_total) {
|
||||
$batch->fraction_done = $fp_done / $fp_total;
|
||||
}
|
||||
if ($completed && $batch->state < BATCH_STATE_COMPLETE) {
|
||||
$batch->state = BATCH_STATE_COMPLETE;
|
||||
$batch->completion_time = time();
|
||||
}
|
||||
$batch->nerror_jobs = $nerror_jobs;
|
||||
$batch->update("fraction_done = $batch->fraction_done, nerror_jobs = $batch->nerror_jobs, state=$batch->state, completion_time = $batch->completion_time, credit_canonical = $batch->credit_canonical");
|
||||
return $batch;
|
||||
}
|
||||
|
||||
function print_batch_params($batch) {
|
||||
$app = BoincApp::lookup_id($batch->app_id);
|
||||
echo "
|
||||
<id>$batch->id</id>
|
||||
<create_time>$batch->create_time</create_time>
|
||||
<est_completion_time>$batch->est_completion_time</est_completion_time>
|
||||
<njobs>$batch->njobs</njobs>
|
||||
<fraction_done>$batch->fraction_done</fraction_done>
|
||||
<nerror_jobs>$batch->nerror_jobs</nerror_jobs>
|
||||
<state>$batch->state</state>
|
||||
<completion_time>$batch->completion_time</completion_time>
|
||||
<credit_estimate>$batch->credit_estimate</credit_estimate>
|
||||
<credit_canonical>$batch->credit_canonical</credit_canonical>
|
||||
<credit_total>$batch->credit_total</credit_total>
|
||||
<name>$batch->name</name>
|
||||
<app_name>$app->name</app_name>
|
||||
";
|
||||
}
|
||||
|
||||
function query_batches($r) {
|
||||
list($user, $user_submit) = authenticate_user($r, null);
|
||||
$batches = BoincBatch::enum("user_id = $user->id");
|
||||
echo "<batches>\n";
|
||||
foreach ($batches as $b) {
|
||||
list($fd, $completed) = fraction_done($b);
|
||||
echo " <batch>
|
||||
<id>$b->id</id>
|
||||
<fraction_done>$fd</fraction_done>
|
||||
<completed>$completed</completed>
|
||||
<create_time>$b->create_time</create_time>
|
||||
<est_completion_time>$b->est_completion_time</est_completion_time>
|
||||
<njobs>$b->njobs</njobs>
|
||||
</batch>
|
||||
";
|
||||
foreach ($batches as $batch) {
|
||||
$wus = BoincWorkunit::enum("batch = $batch->id");
|
||||
$batch = get_batch_params($batch, $wus);
|
||||
echo " <batch>\n";
|
||||
print_batch_params($batch);
|
||||
echo " </batch>\n";
|
||||
}
|
||||
echo "</batches>\n";
|
||||
}
|
||||
|
@ -199,23 +238,23 @@ function query_batch($r) {
|
|||
list($user, $user_submit) = authenticate_user($r, null);
|
||||
$batch_id = (int)($r->batch_id);
|
||||
$batch = BoincBatch::lookup_id($batch_id);
|
||||
if (!$batch) {
|
||||
error("no such batch");
|
||||
}
|
||||
if ($batch->user_id != $user->id) {
|
||||
error("not owner");
|
||||
}
|
||||
echo "<batch>\n";
|
||||
list($fd, $completed) = fraction_done($batch);
|
||||
echo "
|
||||
<fraction_done>$fd</fraction_done>
|
||||
<completed>$completed</completed>
|
||||
<create_time>$b->create_time</create_time>
|
||||
<est_completion_time>$b->est_completion_time</est_completion_time>
|
||||
";
|
||||
|
||||
$wus = BoincWorkunit::enum("batch = $batch_id");
|
||||
$batch = get_batch_params($batch, $wus);
|
||||
echo "<batch>\n";
|
||||
print_batch_params($batch);
|
||||
$n_outfiles = n_outfiles($wus[0]);
|
||||
foreach ($wus as $wu) {
|
||||
echo " <job>
|
||||
<id>$wu->id</id>
|
||||
<canonical_instance_id>$wu->canonical_resultid</canonical_instance_id>
|
||||
<n_outfiles>".n_outfiles($wu)."</n_outfiles>
|
||||
<n_outfiles>$n_outfiles</n_outfiles>
|
||||
</job>
|
||||
";
|
||||
}
|
||||
|
@ -267,10 +306,11 @@ function abort_batch($r) {
|
|||
foreach ($wus as $wu) {
|
||||
abort_workunit($wu);
|
||||
}
|
||||
$batch->update("state=".BATCH_STATE_ABORTED);
|
||||
echo "<success>1</success>";
|
||||
}
|
||||
|
||||
function cleanup_batch($r) {
|
||||
function retire_batch($r) {
|
||||
list($user, $user_submit) = authenticate_user($r, null);
|
||||
$batch_id = (int)($r->batch_id);
|
||||
$batch = BoincBatch::lookup_id($batch_id);
|
||||
|
@ -282,6 +322,7 @@ function cleanup_batch($r) {
|
|||
foreach ($wus as $wu) {
|
||||
$wu->update("assimilate_state=2, transition_time=$now");
|
||||
}
|
||||
$batch->update("state=".BATCH_STATE_RETIRED);
|
||||
echo "<success>1</success>";
|
||||
}
|
||||
|
||||
|
@ -309,7 +350,7 @@ switch ($r->getName()) {
|
|||
case 'query_batch': query_batch($r); break;
|
||||
case 'query_job': query_job($r); break;
|
||||
case 'abort_batch': abort_batch($r); break;
|
||||
case 'cleanup_batch': cleanup_batch($r); break;
|
||||
case 'retire_batch': retire_batch($r); break;
|
||||
default: error("bad command");
|
||||
}
|
||||
|
||||
|
|
|
@ -20,28 +20,30 @@
|
|||
// example of a web interface to remote job submission
|
||||
//
|
||||
// Notes:
|
||||
// - You'll need to adapt/extend this considerably;
|
||||
// e.g. the project URL, app name and user authenticator are hardwired here.
|
||||
// - This can run on any host, not just the project server
|
||||
// (that's the "remote" part).
|
||||
// - You'll need to adapt/extend this considerably,
|
||||
// especially if you want to run this
|
||||
// on a server other than the BOINC project serve.
|
||||
// - For convenience, this uses some functions from BOINC
|
||||
// (page_head() etc.).
|
||||
// When you adapt this to your own purposes,
|
||||
// you can strip out this stuff if the web site doesn't use BOINC
|
||||
|
||||
require_once("../inc/submit.inc");
|
||||
require_once("../inc/submit_db.inc");
|
||||
require_once("../inc/util.inc");
|
||||
require_once("../project/project.inc");
|
||||
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', true);
|
||||
ini_set('display_startup_errors', true);
|
||||
|
||||
$project = "http://isaac.ssl.berkeley.edu/test/";
|
||||
$auth = "157f96a018b0b2f2b466e2ce3c7f54db";
|
||||
$app_name = "uppercase";
|
||||
|
||||
$project = $master_url; // from project.inc
|
||||
$user = get_logged_in_user();
|
||||
$auth = $user->authenticator;
|
||||
|
||||
function handle_main() {
|
||||
global $project, $auth, $app_name;
|
||||
global $project, $auth;
|
||||
$req->project = $project;
|
||||
$req->authenticator = $auth;
|
||||
list($batches, $errmsg) = boinc_query_batches($req);
|
||||
|
@ -49,52 +51,119 @@ function handle_main() {
|
|||
|
||||
page_head("Job submission and control");
|
||||
|
||||
echo date("F j, Y, g:i a");
|
||||
show_button("submit_example.php?action=create_form", "Create new batch");
|
||||
|
||||
echo "<h2>Batches in progress</h2>\n";
|
||||
start_table();
|
||||
table_header("ID", "# jobs", "progress", "submitted");
|
||||
$first = true;
|
||||
foreach ($batches as $batch) {
|
||||
if ($batch->completed) continue;
|
||||
if ($batch->state != BATCH_STATE_IN_PROGRESS) continue;
|
||||
if ($first) {
|
||||
$first = false;
|
||||
echo "<h2>In progress</h2>\n";
|
||||
start_table();
|
||||
table_header("name", "ID", "app", "# jobs", "progress", "submitted");
|
||||
}
|
||||
$pct_done = (int)($batch->fraction_done*100);
|
||||
table_row(
|
||||
"<a href=submit_example.php?action=query_batch&batch_id=$batch->id>$batch->name</a>",
|
||||
"<a href=submit_example.php?action=query_batch&batch_id=$batch->id>$batch->id</a>",
|
||||
$batch->app_name,
|
||||
$batch->njobs,
|
||||
"$pct_done%",
|
||||
time_str($batch->create_time)
|
||||
local_time_str($batch->create_time)
|
||||
);
|
||||
}
|
||||
end_table();
|
||||
if (!$first) {
|
||||
end_table();
|
||||
}
|
||||
|
||||
echo "<h2>Batches completed</h2>\n";
|
||||
start_table();
|
||||
table_header("ID", "# jobs", "submitted");
|
||||
$first = true;
|
||||
foreach ($batches as $batch) {
|
||||
if (!$batch->completed) continue;
|
||||
if ($batch->state != BATCH_STATE_COMPLETE) continue;
|
||||
if ($first) {
|
||||
$first = false;
|
||||
echo "<h2>Completed</h2>\n";
|
||||
start_table();
|
||||
table_header("name", "ID", "# jobs", "submitted");
|
||||
}
|
||||
table_row(
|
||||
"<a href=submit_example.php?action=query_batch&batch_id=$batch->id>$batch->name</a>",
|
||||
"<a href=submit_example.php?action=query_batch&batch_id=$batch->id>$batch->id</a>",
|
||||
$batch->njobs,
|
||||
time_str($batch->create_time)
|
||||
local_time_str($batch->create_time)
|
||||
);
|
||||
}
|
||||
end_table();
|
||||
if (!$first) {
|
||||
end_table();
|
||||
}
|
||||
|
||||
$first = true;
|
||||
foreach ($batches as $batch) {
|
||||
if ($batch->state != BATCH_STATE_ABORTED) continue;
|
||||
if ($first) {
|
||||
$first = false;
|
||||
echo "<h2>Aborted</h2>\n";
|
||||
start_table();
|
||||
table_header("name", "ID", "# jobs", "submitted");
|
||||
}
|
||||
table_row(
|
||||
"<a href=submit_example.php?action=query_batch&batch_id=$batch->id>$batch->name</a>",
|
||||
"<a href=submit_example.php?action=query_batch&batch_id=$batch->id>$batch->id</a>",
|
||||
$batch->njobs,
|
||||
local_time_str($batch->create_time)
|
||||
);
|
||||
}
|
||||
if (!$first) {
|
||||
end_table();
|
||||
}
|
||||
|
||||
page_tail();
|
||||
}
|
||||
|
||||
function handle_create_form() {
|
||||
global $project, $auth, $app_name;
|
||||
function eligible_apps() {
|
||||
global $user;
|
||||
$apps = BoincApp::enum("deprecated = 0");
|
||||
$user_submit = BoincUserSubmit::lookup_userid($user->id);
|
||||
if (!$user_submit) return null;
|
||||
$a = array();
|
||||
foreach($apps as $app) {
|
||||
if ($user_submit->all_apps) {
|
||||
$a[] = $app;
|
||||
} else {
|
||||
if (BoincUserSubmitApp::lookup("user_id=$user->id and app_id=$app->id")) {
|
||||
$a[] = $app;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $a;
|
||||
}
|
||||
|
||||
function app_select($apps) {
|
||||
$x = "<select name=app_name>\n";
|
||||
foreach ($apps as $app) {
|
||||
$x .= "<option value=$app->name>$app->user_friendly_name</option>\n";
|
||||
}
|
||||
$x .= "</select>\n";
|
||||
return $x;
|
||||
}
|
||||
|
||||
function handle_create_form() {
|
||||
global $project, $auth;
|
||||
|
||||
$apps = eligible_apps();
|
||||
if (!$apps) error_page("You are not allowed to submit jobs");
|
||||
page_head("Create batch");
|
||||
echo "
|
||||
<form action=submit_example.php>
|
||||
<input type=hidden name=action value=create_action>
|
||||
";
|
||||
start_table();
|
||||
row2("Input file URL", "<input name=input_url size=60>");
|
||||
row2("Parameter low value", "<input name=param_lo>");
|
||||
row2("Parameter high value", "<input name=param_hi>");
|
||||
row2("Parameter increment", "<input name=param_inc>");
|
||||
row2("Name", "<input name=batch_name value=\"enter name\">");
|
||||
row2("Application", app_select($apps));
|
||||
row2("Input file URL", "<input name=input_url size=60 value=\"http://google.com/\">");
|
||||
row2("Parameter low value", "<input name=param_lo value=10>");
|
||||
row2("Parameter high value", "<input name=param_hi value=20>");
|
||||
row2("Parameter increment", "<input name=param_inc value=1>");
|
||||
row2("",
|
||||
"<input type=submit name=get_estimate value=\"Get completion time estimate\">"
|
||||
);
|
||||
|
@ -109,27 +178,30 @@ function handle_create_form() {
|
|||
// build a request object for boinc_*_batch() from form variables
|
||||
//
|
||||
function form_to_request() {
|
||||
global $project, $auth, $app_name;
|
||||
global $project, $auth;
|
||||
|
||||
$input_url = get_str('input_url');
|
||||
if (!$input_url) error_page("missing input URL");
|
||||
$param_lo = get_str('param_lo');
|
||||
if (!$param_lo) error_page("missing param lo");
|
||||
$param_hi = get_str('param_hi');
|
||||
if (!$param_hi) error_page("missing param hi");
|
||||
$param_inc = get_str('param_inc');
|
||||
if (!$param_inc) error_page("missing param inc");
|
||||
$param_lo = (double)get_str('param_lo');
|
||||
if ($param_lo<0 || $param_lo>60) error_page("param lo must be in 0..60");
|
||||
$param_hi = (double)get_str('param_hi');
|
||||
if ($param_hi<0 || $param_hi>60 || $param_hi <= $param_lo) {
|
||||
error_page("param hi must be in 0..60 and > param lo");
|
||||
}
|
||||
$param_inc = (double)get_str('param_inc');
|
||||
if ($param_inc < 1) error_page("param inc must be >= 1");
|
||||
|
||||
$req->project = $project;
|
||||
$req->authenticator = $auth;
|
||||
$req->app_name = $app_name;
|
||||
$req->app_name = get_str('app_name');
|
||||
$req->batch_name = get_str('batch_name');
|
||||
$req->jobs = Array();
|
||||
|
||||
$f->source = $input_url;
|
||||
$f->name = "in";
|
||||
$job->input_files = Array($f);
|
||||
|
||||
for ($x=(double)$param_lo; $x<(double)$param_hi; $x += (double)$param_inc) {
|
||||
for ($x=$param_lo; $x<$param_hi; $x += $param_inc) {
|
||||
$job->rsc_fpops_est = $x*1e9;
|
||||
$job->command_line = "--t $x";
|
||||
$req->jobs[] = $job;
|
||||
|
@ -139,7 +211,7 @@ function form_to_request() {
|
|||
}
|
||||
|
||||
function handle_create_action() {
|
||||
global $project, $auth, $app_name;
|
||||
global $project, $auth;
|
||||
|
||||
$get_estimate = get_str('get_estimate', true);
|
||||
if ($get_estimate) {
|
||||
|
@ -147,47 +219,68 @@ function handle_create_action() {
|
|||
list($e, $errmsg) = boinc_estimate_batch($req);
|
||||
if ($errmsg) error_page($errmsg);
|
||||
page_head("Batch estimate");
|
||||
echo "Estimate: $e seconds";
|
||||
echo sprintf("Estimate: %.0f seconds", $e);
|
||||
page_tail();
|
||||
} else {
|
||||
$req = form_to_request($project, $auth);
|
||||
list($id, $errmsg) = boinc_submit_batch($req);
|
||||
if ($errmsg) error_page($errmsg);
|
||||
page_head("Batch submitted");
|
||||
echo "Batch ID: $id";
|
||||
echo "Batch created, ID: $id
|
||||
<p>
|
||||
<a href=submit_example.php>Return to job control page</a>
|
||||
";
|
||||
page_tail();
|
||||
}
|
||||
}
|
||||
|
||||
function handle_query_batch() {
|
||||
global $project, $auth, $app_name;
|
||||
global $project, $auth;
|
||||
$req->project = $project;
|
||||
$req->authenticator = $auth;
|
||||
$req->batch_id = get_int('batch_id');
|
||||
list($reply, $errmsg) = boinc_query_batch($req);
|
||||
list($batch, $errmsg) = boinc_query_batch($req);
|
||||
if ($errmsg) error_page($errmsg);
|
||||
|
||||
page_head("Batch $req->batch_id");
|
||||
$url = boinc_get_output_files($req);
|
||||
show_button($url, "Get zipped output files");
|
||||
if ($reply->completed) {
|
||||
echo "<br>";
|
||||
show_button(
|
||||
"submit_example.php?action=cleanup_batch_confirm&batch_id=$req->batch_id",
|
||||
"Delete batch"
|
||||
);
|
||||
} else {
|
||||
start_table();
|
||||
row2("name", $batch->name);
|
||||
row2("application", $batch->app_name);
|
||||
row2("state", batch_state_string($batch->state));
|
||||
row2("# jobs", $batch->njobs);
|
||||
row2("# error jobs", $batch->nerror_jobs);
|
||||
row2("progress", sprintf("%.0f%%", $batch->fraction_done*100));
|
||||
if ($batch->completion_time) {
|
||||
row2("completed", local_time_str($batch->completion_time));
|
||||
}
|
||||
row2("Credit, estimated", $batch->credit_estimate);
|
||||
row2("Credit, canonical instances", $batch->credit_canonical);
|
||||
row2("Credit, total", $batch->credit_total);
|
||||
end_table();
|
||||
switch ($batch->state) {
|
||||
case BATCH_STATE_IN_PROGRESS:
|
||||
echo "<br>";
|
||||
show_button(
|
||||
"submit_example.php?action=abort_batch_confirm&batch_id=$req->batch_id",
|
||||
"Abort batch"
|
||||
);
|
||||
break;
|
||||
case BATCH_STATE_COMPLETE:
|
||||
case BATCH_STATE_ABORTED:
|
||||
echo "<br>";
|
||||
show_button(
|
||||
"submit_example.php?action=retire_batch_confirm&batch_id=$req->batch_id",
|
||||
"Retire batch"
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
echo "<h2>Jobs</h2>\n";
|
||||
start_table();
|
||||
table_header("Job ID", "Canonical instance");
|
||||
foreach($reply->jobs as $job) {
|
||||
foreach($batch->jobs as $job) {
|
||||
$id = (int)$job->id;
|
||||
$resultid = (int)$job->canonical_instance_id;
|
||||
if ($resultid) {
|
||||
|
@ -206,7 +299,7 @@ function handle_query_batch() {
|
|||
}
|
||||
|
||||
function handle_query_job() {
|
||||
global $project, $auth, $app_name;
|
||||
global $project, $auth;
|
||||
$req->project = $project;
|
||||
$req->authenticator = $auth;
|
||||
$req->job_id = get_int('job_id');
|
||||
|
@ -252,7 +345,7 @@ function handle_abort_batch_confirm() {
|
|||
}
|
||||
|
||||
function handle_abort_batch() {
|
||||
global $project, $auth, $app_name;
|
||||
global $project, $auth;
|
||||
$req->project = $project;
|
||||
$req->authenticator = $auth;
|
||||
$req->batch_id = get_int('batch_id');
|
||||
|
@ -265,29 +358,29 @@ function handle_abort_batch() {
|
|||
page_tail();
|
||||
}
|
||||
|
||||
function handle_cleanup_batch_confirm() {
|
||||
function handle_retire_batch_confirm() {
|
||||
$batch_id = get_int('batch_id');
|
||||
page_head("Confirm delete batch");
|
||||
page_head("Confirm retire batch");
|
||||
echo "
|
||||
Deleting a batch will remove all of its output files.
|
||||
Retiring a batch will remove all of its output files.
|
||||
Are you sure you want to do this?
|
||||
<p>
|
||||
";
|
||||
show_button(
|
||||
"submit_example.php?action=cleanup_batch&batch_id=$batch_id",
|
||||
"Yes - delete batch"
|
||||
"submit_example.php?action=retire_batch&batch_id=$batch_id",
|
||||
"Yes - retire batch"
|
||||
);
|
||||
page_tail();
|
||||
}
|
||||
|
||||
function handle_cleanup_batch() {
|
||||
global $project, $auth, $app_name;
|
||||
function handle_retire_batch() {
|
||||
global $project, $auth;
|
||||
$req->project = $project;
|
||||
$req->authenticator = $auth;
|
||||
$req->batch_id = get_int('batch_id');
|
||||
$errmsg = boinc_cleanup_batch($req);
|
||||
$errmsg = boinc_retire_batch($req);
|
||||
if ($errmsg) error_page($errmsg);
|
||||
page_head("Batch deleted");
|
||||
page_head("Batch retired");
|
||||
echo "
|
||||
<a href=submit_example.php>Return to job control page</a>.
|
||||
";
|
||||
|
@ -318,11 +411,11 @@ case 'abort_batch_confirm':
|
|||
case 'abort_batch':
|
||||
handle_abort_batch();
|
||||
break;
|
||||
case 'cleanup_batch_confirm':
|
||||
handle_cleanup_batch_confirm();
|
||||
case 'retire_batch_confirm':
|
||||
handle_retire_batch_confirm();
|
||||
break;
|
||||
case 'cleanup_batch':
|
||||
handle_cleanup_batch();
|
||||
case 'retire_batch':
|
||||
handle_retire_batch();
|
||||
break;
|
||||
default:
|
||||
error_page('no such action');
|
||||
|
|
Loading…
Reference in New Issue