diff --git a/api/boinc_api.C b/api/boinc_api.C index 056e38192a..0ec32f88ec 100644 --- a/api/boinc_api.C +++ b/api/boinc_api.C @@ -58,12 +58,24 @@ using namespace std; #include "app_ipc.h" #include "boinc_api.h" -static APP_INIT_DATA aid; -APP_CLIENT_SHM *app_client_shm; +// The BOINC API communicates CPU time and fraction done to the core client. +// Currently this is done using a timer. +// Remember that the processing of a result can be divided +// into multiple "episodes" (executions of the app), +// each of which resumes from the checkpointed state of the previous episode. +// Unless otherwise noted, "CPU time" refers to the sum over all episodes +// (not counting the part after the last checkpoint in an episode). -static double timer_period = 1.0/50.0; // 50 Hz timer +static APP_INIT_DATA aid; +APP_CLIENT_SHM *app_client_shm; +static double timer_period = 1.0; // period of API timer + // This determines the resolution of fraction done and CPU time reporting + // to the core client, and of checkpoint enabling. + // It doesn't influence graphics, so 1 sec is enough. static double time_until_checkpoint; + // countdown timer until enable checkpoint static double time_until_fraction_done_update; + // countdown timer until report fraction done to core static double fraction_done; static double last_checkpoint_cpu_time; static bool ready_to_checkpoint = false; @@ -84,24 +96,16 @@ HANDLE worker_thread_handle; MMRESULT timer_id; #endif - -// -// Forward declare implementation functions. -// -static void setup_shared_mem(); +static int setup_shared_mem(); static void cleanup_shared_mem(); -static int update_app_progress(double frac_done, double cpu_t, double cp_cpu_t, double ws_t); +static int update_app_progress(double cpu_t, double cp_cpu_t, double ws_t); static int set_timer(double period); -// Standard BOINC APIs -// - int boinc_init(bool standalone_ /* = false */) { FILE* f; int retval; #ifdef _WIN32 - DuplicateHandle( GetCurrentProcess(), GetCurrentThread(), @@ -111,29 +115,30 @@ int boinc_init(bool standalone_ /* = false */) { FALSE, DUPLICATE_SAME_ACCESS ); - #endif - // Store startup mode for later use. standalone = standalone_; - // Parse initial data file. retval = boinc_parse_init_data_file(); if (retval) return retval; + retval = setup_shared_mem(); + if (retval) { + standalone = true; + } + // copy the WU CPU time to a separate var, // since we may reread the structure again later. // initial_wu_cpu_time = aid.wu_cpu_time; - if (boinc_file_exists(FD_INIT_FILE)) { - f = boinc_fopen(FD_INIT_FILE, "r"); - if (f) { - parse_fd_init_file(f); - fclose(f); - } + f = boinc_fopen(FD_INIT_FILE, "r"); + if (f) { + parse_fd_init_file(f); + fclose(f); } + fraction_done = -1; time_until_checkpoint = aid.checkpoint_period; last_checkpoint_cpu_time = aid.wu_cpu_time; time_until_fraction_done_update = aid.fraction_done_update_period; @@ -141,7 +146,6 @@ int boinc_init(bool standalone_ /* = false */) { last_wu_cpu_time = aid.wu_cpu_time; set_timer(timer_period); - setup_shared_mem(); return 0; } @@ -152,7 +156,7 @@ int boinc_finish(int status) { boinc_thread_cpu_time(last_checkpoint_cpu_time, cur_mem); last_checkpoint_cpu_time += aid.wu_cpu_time; - update_app_progress(fraction_done, last_checkpoint_cpu_time, last_checkpoint_cpu_time, cur_mem); + update_app_progress(last_checkpoint_cpu_time, last_checkpoint_cpu_time, cur_mem); #ifdef _WIN32 // Stop the timer timeKillEvent(timer_id); @@ -220,19 +224,23 @@ int boinc_parse_init_data_file() { // the current CPU time and fraction done // static int update_app_progress( - double frac_done, double cpu_t, double cp_cpu_t, double ws_t + double cpu_t, double cp_cpu_t, double ws_t ) { - char msg_buf[SHM_SEG_SIZE]; + char msg_buf[SHM_SEG_SIZE], buf[256]; if (!app_client_shm) return 0; sprintf(msg_buf, - "%2.8f\n" "%10.4f\n" "%.15e\n" "%f\n", - frac_done, cpu_t, cp_cpu_t, ws_t + cpu_t, cp_cpu_t, ws_t ); + if (fraction_done >= 0) { + sprintf(buf, "%2.8f\n", fraction_done); + strcat(msg_buf, buf); + } + if (have_new_trickle_up) { strcat(msg_buf, "\n"); have_new_trickle_up = false; @@ -338,7 +346,7 @@ static void on_timer(int a) { double cur_mem; boinc_worker_thread_cpu_time(cur_cpu, cur_mem); last_wu_cpu_time = cur_cpu + initial_wu_cpu_time; - update_app_progress(fraction_done, last_wu_cpu_time, last_checkpoint_cpu_time, cur_mem); + update_app_progress(last_wu_cpu_time, last_checkpoint_cpu_time, cur_mem); time_until_fraction_done_update = aid.fraction_done_update_period; } } @@ -387,10 +395,10 @@ static int set_timer(double period) { return retval; } -static void setup_shared_mem() { +static int setup_shared_mem() { if (standalone) { fprintf(stderr, "Standalone mode, so not using shared memory.\n"); - return; + return 0; } app_client_shm = new APP_CLIENT_SHM; @@ -402,16 +410,14 @@ static void setup_shared_mem() { delete app_client_shm; app_client_shm = NULL; } -#endif - -#ifdef HAVE_SYS_SHM_H -#ifdef HAVE_SYS_IPC_H +#else if (attach_shmem(aid.shm_key, (void**)&app_client_shm->shm)) { delete app_client_shm; app_client_shm = NULL; } #endif -#endif + if (app_client_shm == NULL) return -1; + return 0; } static void cleanup_shared_mem() { @@ -419,18 +425,13 @@ static void cleanup_shared_mem() { #ifdef _WIN32 detach_shmem(hSharedMem, app_client_shm->shm); -#endif - -#ifdef HAVE_SYS_SHM_H -#ifdef HAVE_SYS_IPC_H +#else detach_shmem(app_client_shm->shm); -#endif #endif delete app_client_shm; app_client_shm = NULL; } - int boinc_send_trickle_up(char* p) { FILE* f = boinc_fopen(TRICKLE_UP_FILENAME, "wb"); if (!f) return ERR_FOPEN; @@ -441,8 +442,6 @@ int boinc_send_trickle_up(char* p) { return 0; } - - bool boinc_time_to_checkpoint() { #ifdef _WIN32 DWORD eventState; @@ -471,7 +470,7 @@ int boinc_checkpoint_completed() { boinc_thread_cpu_time(cur_cpu, cur_mem); last_wu_cpu_time = cur_cpu + aid.wu_cpu_time; last_checkpoint_cpu_time = last_wu_cpu_time; - update_app_progress(fraction_done, last_checkpoint_cpu_time, last_checkpoint_cpu_time, cur_mem); + update_app_progress(last_checkpoint_cpu_time, last_checkpoint_cpu_time, cur_mem); ready_to_checkpoint = false; time_until_checkpoint = aid.checkpoint_period; diff --git a/checkin_notes b/checkin_notes index 82dbba83b1..357bf498ad 100755 --- a/checkin_notes +++ b/checkin_notes @@ -12441,8 +12441,30 @@ David May 20 2004 cs_benchmark.C David May 21 2004 - - changed variable names in app.C: + - API: changed timer period from 50 Hz to 1 Hz. + This timer is used only for reporting progress and CPU, + not for doing graphics, to 1 Hz is enough + - API: if setup_shared_mem() returns error, set standalone = true. + This means that if you run an app standalone, + it will be detected automatically, + so no need for command-line args or even + standalone argument to boinc_init() + (but leave that arg in for now) + - API: initialize fraction_done to -1, + and only report it to core client if >= 0 + (i.e. don't report it unless app specifies it) + - API: removed + #ifdef HAVE_SYS_SHM_H + #ifdef HAVE_SYS_IPC_H + around calls to attach_shmem in non-Win case. + This not an appropriate place for these ifdefs. + - core client: ACTIVE_TASK_SET::check_app_exited(): + skip tasks in state PROCESS_IN_LIMBO. + This avoid core client spinning when apps misbehave. + - core client: changed variable names in app.C: starting_cpu_time -> episode_start_cpu_time + api/ + boinc_api.C client/ app.C,h diff --git a/client/app.C b/client/app.C index 26a1378109..a78b3a797c 100644 --- a/client/app.C +++ b/client/app.C @@ -662,6 +662,7 @@ bool ACTIVE_TASK_SET::check_app_exited() { for (i=0; istate == PROCESS_IN_LIMBO) continue; if (GetExitCodeProcess(atp->pid_handle, &exit_code)) { if (exit_code != STILL_ACTIVE) { scope_messages.printf("ACTIVE_TASK_SET::check_app_exited(): Process exited with code %d\n", exit_code);