mirror of https://github.com/BOINC/boinc.git
- API, Unix: call getrusage() from the timer thread,
not the worker signal handler. There's no reason to call it from the signal handler - it returns the CPU for the entire process, not the calling thread. And it may be asynch-signal-handler-unsafe. - API: comment out checks for bad CPU times. I don't think this is needed now, and in some cases it's wrong (multi-threaded apps can accumulate CPU faster than real time) - API, Unix: in boinc_calling_thread_cpu_time(), don't retry getrusage(). - Bossa: switch to better class structure (suggested by Nicolas Alvarez). Haven't switched to mysqli yet, but will later. Also various other Bossa fixes svn path=/trunk/boinc/; revision=13855
This commit is contained in:
parent
92509b6d4b
commit
b079d40cb9
|
@ -191,15 +191,10 @@ static int setup_shared_mem() {
|
|||
}
|
||||
|
||||
// Return CPU time of worker thread (and optionally others)
|
||||
// This may be called from other threads
|
||||
// This may be called from any thread
|
||||
//
|
||||
double boinc_worker_thread_cpu_time() {
|
||||
static double last_cpu=0;
|
||||
// last value returned by this func
|
||||
static time_t last_time=0;
|
||||
// when it was returned
|
||||
time_t now = time(0);
|
||||
double cpu, time_diff = (double)(now - last_time);
|
||||
double cpu;
|
||||
#ifdef _WIN32
|
||||
int retval;
|
||||
if (options.all_threads_cpu_time) {
|
||||
|
@ -216,6 +211,18 @@ double boinc_worker_thread_cpu_time() {
|
|||
cpu += (double)worker_thread_ru.ru_stime.tv_sec
|
||||
+ (((double)worker_thread_ru.ru_stime.tv_usec)/1000000.0);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// The following paranoia is (I hope) not needed anymore.
|
||||
// In any case, the check for CPU incrementing faster than real time
|
||||
// is misguided - it assumes no multi-threading.
|
||||
//
|
||||
static double last_cpu=0;
|
||||
// last value returned by this func
|
||||
static time_t last_time=0;
|
||||
// when it was returned
|
||||
time_t now = time(0);
|
||||
double time_diff = (double)(now - last_time);
|
||||
if (!finite(cpu)) {
|
||||
fprintf(stderr, "CPU time infinite or NaN\n");
|
||||
last_time = now;
|
||||
|
@ -228,11 +235,12 @@ double boinc_worker_thread_cpu_time() {
|
|||
return last_cpu;
|
||||
}
|
||||
if (cpu_diff>(time_diff + 1)) {
|
||||
// fprintf(stderr, "CPU time incrementing faster than real time. Correcting.\n");
|
||||
fprintf(stderr, "CPU time incrementing faster than real time. Correcting.\n");
|
||||
cpu = last_cpu + time_diff + 1; // allow catch-up
|
||||
}
|
||||
last_cpu = cpu;
|
||||
last_time = now;
|
||||
#endif
|
||||
return cpu;
|
||||
}
|
||||
|
||||
|
@ -923,6 +931,7 @@ void* timer_thread(void*) {
|
|||
block_sigalrm();
|
||||
while(1) {
|
||||
boinc_sleep(TIMER_PERIOD);
|
||||
getrusage(RUSAGE_SELF, &worker_thread_ru);
|
||||
timer_handler();
|
||||
}
|
||||
return 0;
|
||||
|
@ -933,7 +942,6 @@ void* timer_thread(void*) {
|
|||
// It must call only signal-safe functions, and must not do FP math
|
||||
//
|
||||
void worker_signal_handler(int) {
|
||||
getrusage(RUSAGE_SELF, &worker_thread_ru);
|
||||
if (options.direct_process_action) {
|
||||
while (boinc_status.suspended && !in_critical_section) {
|
||||
sleep(1); // don't use boinc_sleep() because it does FP math
|
||||
|
|
|
@ -9556,3 +9556,34 @@ Rom 16 Oct 2007
|
|||
boinc_tray.h (Added)
|
||||
boinc_tray.rc (Added)
|
||||
tray_win.cpp, .h (Added)
|
||||
|
||||
David 16 Oct 2007
|
||||
- API, Unix: call getrusage() from the timer thread,
|
||||
not the worker signal handler.
|
||||
There's no reason to call it from the signal handler -
|
||||
it returns the CPU for the entire process, not the calling thread.
|
||||
And it may be asynch-signal-handler-unsafe.
|
||||
- API: comment out checks for bad CPU times.
|
||||
I don't think this is needed now, and in some cases it's wrong
|
||||
(multi-threaded apps can accumulate CPU faster than real time)
|
||||
- API, Unix: in boinc_calling_thread_cpu_time(), don't retry getrusage().
|
||||
- Bossa: switch to better class structure (suggested by Nicolas Alvarez).
|
||||
Haven't switched to mysqli yet, but will later.
|
||||
Also various other Bossa fixes
|
||||
|
||||
api/
|
||||
boinc_api.C
|
||||
db/
|
||||
bossa_constraints.sal
|
||||
bossa_schema.sql
|
||||
html/
|
||||
inc/
|
||||
bossa_db.inc
|
||||
ops/
|
||||
bossa_make_jobs_example.php
|
||||
bossa_setup_example.php
|
||||
user/
|
||||
bossa_example.php (new)
|
||||
bossa_get_job.php
|
||||
lib/
|
||||
util.C
|
||||
|
|
|
@ -2,5 +2,9 @@ alter table bossa_app
|
|||
add unique(name);
|
||||
|
||||
alter table bossa_job
|
||||
add unique(name)
|
||||
add index bj_more_needed(more_needed);
|
||||
add unique(name),
|
||||
add index bj_more_needed(app, more_needed);
|
||||
|
||||
alter table bossa_job_inst
|
||||
add index bji_job(job_id),
|
||||
add index bji_user(user_id);
|
||||
|
|
|
@ -5,7 +5,6 @@ create table bossa_app (
|
|||
user_friendly_name varchar(255) not null,
|
||||
long_jobs tinyint not null,
|
||||
start_url varchar(255) not null,
|
||||
finish_url varchar(255) not null,
|
||||
deprecated tinyint not null,
|
||||
beta tinyint not null,
|
||||
primary key(id)
|
||||
|
@ -33,5 +32,6 @@ create table bossa_job_inst (
|
|||
job_id integer not null,
|
||||
user_id integer not null,
|
||||
finish_time integer not null,
|
||||
info varchar(255) not null,
|
||||
primary key(id)
|
||||
);
|
||||
|
|
|
@ -1,18 +1,25 @@
|
|||
<?php
|
||||
|
||||
class Bossa {
|
||||
function insert_app(&$app) {
|
||||
if (!$app->long_jobs) $app->long_jobs = 0;
|
||||
function bossa_lookup($id, $table) {
|
||||
$result = mysql_query("select * from $table where id='$id'");
|
||||
if (!$result) return null;
|
||||
$obj = mysql_fetch_object($result);
|
||||
mysql_free_result($result);
|
||||
return $obj;
|
||||
}
|
||||
|
||||
class BossaApp {
|
||||
function insert() {
|
||||
if (!$this->long_jobs) $this->long_jobs = 0;
|
||||
$now = time();
|
||||
$query = "insert into bossa_app (create_time, name, user_friendly_name, long_jobs, start_url, finish_url) values ($now, '$app->name', '$app->user_friendly_name', $app->long_jobs, '$app->start_url', '$app->finish_url')";
|
||||
echo $query;
|
||||
$query = "insert into bossa_app (create_time, name, user_friendly_name, long_jobs, start_url) values ($now, '$this->name', '$this->user_friendly_name', $this->long_jobs, '$this->start_url')";
|
||||
$result = mysql_query($query);
|
||||
if (!$result) return false;
|
||||
$app->id = mysql_insert_id();
|
||||
$this->id = mysql_insert_id();
|
||||
return true;
|
||||
}
|
||||
|
||||
function app_lookup_name($name) {
|
||||
static function lookup_name($name) {
|
||||
$result = mysql_query("select * from bossa_app where name='$name'");
|
||||
if (!$result) return null;
|
||||
$app = mysql_fetch_object($result);
|
||||
|
@ -20,42 +27,56 @@ class Bossa {
|
|||
return $app;
|
||||
}
|
||||
|
||||
function app_lookup_id($id) {
|
||||
$result = mysql_query("select * from bossa_app where id='$id'");
|
||||
if (!$result) return null;
|
||||
$app = mysql_fetch_object($result);
|
||||
mysql_free_result($result);
|
||||
return $app;
|
||||
static function lookup_id($id) {
|
||||
return bossa_lookup($id, 'bossa_app');
|
||||
}
|
||||
}
|
||||
|
||||
function insert_job(&$job) {
|
||||
class BossaJob {
|
||||
function insert() {
|
||||
$now = time();
|
||||
$query = "insert into bossa_job (create_time, name, app_id, info, batch, time_estimate, time_limit, more_needed, npending, nsuccess, nsuccess_needed) values ($now, '$job->name', $job->app_id, '$job->info', $job->batch, $job->time_estimate, $job->time_limit, 1, 0, 0, $job->nsuccess_needed)";
|
||||
$query = "insert into bossa_job (create_time, name, app_id, info, batch, time_estimate, time_limit, more_needed, npending, nsuccess, nsuccess_needed) values ($now, '$this->name', $this->app_id, '$this->info', $this->batch, $this->time_estimate, $this->time_limit, 1, 0, 0, $this->nsuccess_needed)";
|
||||
$result = mysql_query($query);
|
||||
if (!$result) {
|
||||
echo "$query\n";
|
||||
return false;
|
||||
}
|
||||
$job->id = mysql_insert_id();
|
||||
$this->id = mysql_insert_id();
|
||||
return true;
|
||||
}
|
||||
function update($clause) {
|
||||
return mysql_query("update bossa_job set $clause where id=$this->id");
|
||||
}
|
||||
static function lookup_id($id) {
|
||||
return bossa_lookup($id, 'bossa_job');
|
||||
}
|
||||
}
|
||||
|
||||
function insert_job_inst(&$ji) {
|
||||
class BossaJobInst {
|
||||
function insert() {
|
||||
$now = time();
|
||||
$query = "insert into bossa_job_inst (create_time, job_id, user_id) values ($now, $ji->job_id, $ji->user_id)";
|
||||
$query = "insert into bossa_job_inst (create_time, job_id, user_id) values ($now, $this->job_id, $this->user_id)";
|
||||
$result = mysql_query($query);
|
||||
if (!$result) {
|
||||
echo "$query\n";
|
||||
return false;
|
||||
}
|
||||
$ji->id = mysql_insert_id();
|
||||
$this->id = mysql_insert_id();
|
||||
return true;
|
||||
}
|
||||
|
||||
static function lookup_id($id) {
|
||||
return bossa_lookup($id, 'bossa_job_inst');
|
||||
}
|
||||
|
||||
function update($clause) {
|
||||
return mysql_query("update bossa_job_inst set $clause where id=$this->id");
|
||||
}
|
||||
|
||||
// Assign a job from the given app to the given user.
|
||||
// Returns the job instance or NULL.
|
||||
//
|
||||
function assign_job($app, $user) {
|
||||
static function assign($app, $user) {
|
||||
// this query skips jobs for which this user
|
||||
// has already been assigned an instance
|
||||
//
|
||||
|
@ -69,15 +90,36 @@ class Bossa {
|
|||
echo "<hr>";
|
||||
print_r($job);
|
||||
echo "<hr>";
|
||||
$ji = new BossaJobInst();
|
||||
$ji->user_id = $user->id;
|
||||
$ji->job_id = $job->id;
|
||||
|
||||
if (!Bossa::insert_job_inst($ji)) {
|
||||
if (!$ji->insert()) {
|
||||
echo mysql_error();
|
||||
return null;
|
||||
}
|
||||
return $ji;
|
||||
}
|
||||
|
||||
// The given job instance has completed
|
||||
//
|
||||
function completed($job) {
|
||||
$this->finish_time = time();
|
||||
$this->update("finish_time=$this->finish_time, info='$this->info'");
|
||||
|
||||
$job->npending--;
|
||||
$job->nsuccess++;
|
||||
$job->more_needed = ($job->npending+$job->nsuccess < $job->nsuccess_needed);
|
||||
return BossaJob::update("npending=$job->npending, nsuccess=$job->nsuccess, more_needed=$job->more_needed");
|
||||
}
|
||||
|
||||
// The given job instance has timed out.
|
||||
//
|
||||
function timed_out($job) {
|
||||
$job->npending--;
|
||||
$job->more_needed = ($job->npending+$job->nsuccess < $job->nsuccess_needed);
|
||||
return BossaJob::update("npending=$job->npending, more_needed=$job->more_needed");
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
|
@ -1,31 +1,35 @@
|
|||
<?php
|
||||
|
||||
require_once("../bossa_inc/bossa_db.inc");
|
||||
require_once("../inc/bossa_db.inc");
|
||||
require_once("../inc/db.inc");
|
||||
|
||||
db_init();
|
||||
|
||||
function make_jobs() {
|
||||
$app = Bossa::app_lookup_name('bossa_test');
|
||||
$appname = 'bossa_test';
|
||||
$app = BossaApp::lookup_name($appname);
|
||||
if (!$app) {
|
||||
echo "No app\n";
|
||||
echo "Application $appname not found\n";
|
||||
exit(1);
|
||||
}
|
||||
$job = new BossaJob;
|
||||
$job->app_id = $app->id;
|
||||
$job->batch = 0;
|
||||
$job->time_estimate = 30;
|
||||
$job->time_limit = 600;
|
||||
$job->nsuccess_needed = 3;
|
||||
for ($i=0; $i<10; $i++) {
|
||||
$j = $i % 2;
|
||||
$job->name = "job_$i";
|
||||
$job->job_info = "$i";
|
||||
if (!Bossa::insert_job($job)) {
|
||||
echo "failed: ", mysql_error();
|
||||
$job->info = "$j";
|
||||
if (!$job->insert()) {
|
||||
echo "BossaJob::insert failed: ", mysql_error(), "\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
make_jobs();
|
||||
echo "All done.\n";
|
||||
|
||||
?>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
require_once("../bossa_inc/bossa_db.inc");
|
||||
require_once("../inc/bossa_db.inc");
|
||||
require_once("../inc/db.inc");
|
||||
|
||||
db_init();
|
||||
|
@ -8,14 +8,15 @@ db_init();
|
|||
// Set up Bossa applications.
|
||||
// Customize and rename this file.
|
||||
|
||||
$ba = new BossaApp();
|
||||
$ba->name = 'bossa_test';
|
||||
$ba->user_friendly_name = 'Simple pattern recognition';
|
||||
$ba->start_url = 'test_start.php';
|
||||
$ba->start_url = 'bossa_example.php';
|
||||
|
||||
if (Bossa::insert_app($ba)) {
|
||||
echo "success\n";
|
||||
if ($ba->insert($ba)) {
|
||||
echo "Added application '$ba->name'\n";
|
||||
} else {
|
||||
echo "failed ", mysql_error();
|
||||
echo "Couldn't add '$ba->name': ", mysql_error(), "\n";
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
require_once("../inc/util.inc");
|
||||
require_once("../inc/bossa_db.inc");
|
||||
|
||||
db_init();
|
||||
|
||||
// Bossa example.
|
||||
// Show the user an image and ask them whether it's a zero or one.
|
||||
|
||||
function show_job($bj, $bji) {
|
||||
if ($bji->finish_time) {
|
||||
error_page("You already finished this job");
|
||||
}
|
||||
$i = $bj->info;
|
||||
$img_url = "http://boinc.berkeley.edu/images/number_$i.jpg";
|
||||
echo "
|
||||
<form method=get action=bossa_example.php>
|
||||
<input type=hidden name=bji value=$bji->id>
|
||||
<img src=$img_url>
|
||||
<br>
|
||||
The picture shows a
|
||||
<br><input type=radio name=response value=0> zero
|
||||
<br><input type=radio name=response value=1> one
|
||||
<br><input type=radio name=response value=2 checked> not sure
|
||||
<br><br><input type=submit name=submit value=OK>
|
||||
</form>
|
||||
";
|
||||
}
|
||||
|
||||
function handle_job_completion($bj, $bji) {
|
||||
$response = get_int('response');
|
||||
print_r($bji);
|
||||
$bji->info = "response=$response";
|
||||
$bji->completed($bj);
|
||||
|
||||
// show another job immediately
|
||||
//
|
||||
$url = "bossa_get_job.php?bossa_app_id=$bj->app_id";
|
||||
Header("Location: $url");
|
||||
}
|
||||
|
||||
$user = get_logged_in_user();
|
||||
$bji = BossaJobInst::lookup_id(get_int('bji'));
|
||||
if (!$bji) {
|
||||
error_page("No such job instance");
|
||||
}
|
||||
if ($bji->user_id != $user->id) {
|
||||
error_page("Bad user ID");
|
||||
}
|
||||
$bj = BossaJob::lookup_id($bji->job_id);
|
||||
if (!$bj) {
|
||||
error_page("No such job");
|
||||
}
|
||||
|
||||
if ($_GET['submit']) {
|
||||
handle_job_completion($bj, $bji);
|
||||
} else {
|
||||
show_job($bj, $bji);
|
||||
}
|
||||
|
||||
?>
|
|
@ -2,27 +2,27 @@
|
|||
|
||||
require_once("../inc/util.inc");
|
||||
require_once("../inc/db.inc");
|
||||
require_once("../bossa_inc/bossa_db.inc");
|
||||
require_once("../inc/bossa_db.inc");
|
||||
|
||||
db_init();
|
||||
|
||||
$user = get_logged_in_user();
|
||||
|
||||
$bossa_app_id = get_int('bossa_app_id');
|
||||
$app = Bossa::app_lookup_id($bossa_app_id);
|
||||
$app = BossaApp::lookup_id(get_int('bossa_app_id'));
|
||||
|
||||
if (!$app) {
|
||||
error_page("no such app: $bossa_app_id");
|
||||
}
|
||||
|
||||
$ji = Bossa::assign_job($app, $user);
|
||||
$ji = BossaJobInst::assign($app, $user);
|
||||
if ($ji) {
|
||||
$url = $app->start_url."&job_info=".$job->job_info;
|
||||
$url = $app->start_url."?bji=$ji->id";
|
||||
Header("Location: $url");
|
||||
} else {
|
||||
page_head("No jobs available");
|
||||
echo "
|
||||
Sorry, no jobs are available right not.
|
||||
Sorry, no more jobs are available right now.
|
||||
<p>
|
||||
Please try again later.
|
||||
";
|
||||
page_tail();
|
||||
|
|
22
lib/util.C
22
lib/util.C
|
@ -191,26 +191,16 @@ int boinc_calling_thread_cpu_time(double& cpu) {
|
|||
|
||||
#else
|
||||
|
||||
// Unix: pthreads doesn't seem to provide an API for getting
|
||||
// per-thread CPU time. So just get the process's CPU time
|
||||
// Unix: pthreads doesn't provide an API for getting per-thread CPU time,
|
||||
// so just get the process's CPU time
|
||||
//
|
||||
int boinc_calling_thread_cpu_time(double &cpu_t) {
|
||||
int retval=1;
|
||||
struct rusage ru;
|
||||
|
||||
// getrusage can return an error, so try a few times if it returns an error.
|
||||
//
|
||||
for (int i=0; i<10; i++) {
|
||||
retval = getrusage(RUSAGE_SELF, &ru);
|
||||
if (!retval) break;
|
||||
}
|
||||
if (retval) {
|
||||
return ERR_GETRUSAGE;
|
||||
}
|
||||
// Sum the user and system time
|
||||
//
|
||||
cpu_t = (double)ru.ru_utime.tv_sec + (((double)ru.ru_utime.tv_usec) / ((double)1000000.0));
|
||||
cpu_t += (double)ru.ru_stime.tv_sec + (((double)ru.ru_stime.tv_usec) / ((double)1000000.0));
|
||||
int retval = getrusage(RUSAGE_SELF, &ru);
|
||||
if (retval) return ERR_GETRUSAGE;
|
||||
cpu_t = (double)ru.ru_utime.tv_sec + ((double)ru.ru_utime.tv_usec) / 1e6;
|
||||
cpu_t += (double)ru.ru_stime.tv_sec + ((double)ru.ru_stime.tv_usec) / 1e6;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue