mirror of https://github.com/BOINC/boinc.git
Added comments throughout code.
svn path=/trunk/boinc/; revision=202
This commit is contained in:
parent
27f57f30b7
commit
0801522cb0
108
client/app.C
108
client/app.C
|
@ -49,16 +49,17 @@
|
|||
#if HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
#if HAVE_SIGNAL_H
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "client_types.h"
|
||||
#include "client_state.h"
|
||||
#include "client_types.h"
|
||||
#include "filesys.h"
|
||||
#include "file_names.h"
|
||||
#include "log_flags.h"
|
||||
|
@ -67,19 +68,23 @@
|
|||
#include "app.h"
|
||||
#include "api.h"
|
||||
|
||||
// take a string containing some words.
|
||||
// take a string containing some space separated words.
|
||||
// return an array of pointers to the null-terminated words.
|
||||
// Modifies the string arg.
|
||||
//
|
||||
void parse_command_line(char* p, char** argv) {
|
||||
// TODO: use strtok here
|
||||
int parse_command_line(char* p, char** argv) {
|
||||
char** pp = argv;
|
||||
bool space = true;
|
||||
|
||||
if(p==NULL) {
|
||||
fprintf(stderr, "error: parse_command_line: unexpected NULL pointer p\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
if(argv==NULL) {
|
||||
fprintf(stderr, "error: parse_command_line: unexpected NULL pointer argv\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
|
||||
while (*p) {
|
||||
if (isspace(*p)) {
|
||||
*p = 0;
|
||||
|
@ -93,40 +98,59 @@ void parse_command_line(char* p, char** argv) {
|
|||
p++;
|
||||
}
|
||||
*pp++ = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_argv(char** argv) {
|
||||
// Goes through an array of strings, and prints each string
|
||||
//
|
||||
static int print_argv(char** argv) {
|
||||
int i;
|
||||
|
||||
if(argv==NULL) {
|
||||
fprintf(stderr, "error: print_argv: unexpected NULL pointer argv\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
for (i=0; argv[i]; i++) {
|
||||
fprintf(stderr, "argv[%d]: %s\n", i, argv[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Initialize the ACTIVE_TASK object members to null
|
||||
//
|
||||
ACTIVE_TASK::ACTIVE_TASK() {
|
||||
result = NULL;
|
||||
wup = NULL;
|
||||
app_version = NULL;
|
||||
pid = 0;
|
||||
slot = 0;
|
||||
state = PROCESS_UNINITIALIZED;
|
||||
exit_status = 0;
|
||||
signal = 0;
|
||||
strcpy(dirname, "");
|
||||
prev_cpu_time = 0;
|
||||
}
|
||||
|
||||
// Initialize active task with a specific result requirement
|
||||
//
|
||||
int ACTIVE_TASK::init(RESULT* rp) {
|
||||
if(rp==NULL) {
|
||||
fprintf(stderr, "error: ACTIVE_TASK.init: unexpected NULL pointer rp\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
|
||||
result = rp;
|
||||
wup = rp->wup;
|
||||
app_version = wup->avp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Start a task in a slot directory. This includes setting up soft links,
|
||||
// passing preferences, and starting the actual process for computation
|
||||
//
|
||||
int ACTIVE_TASK::start(bool first_time) {
|
||||
char exec_name[256], file_path[256], link_path[256],temp[256];
|
||||
char* argv[100];
|
||||
|
@ -139,37 +163,42 @@ int ACTIVE_TASK::start(bool first_time) {
|
|||
APP_IN app_prefs;
|
||||
|
||||
prev_cpu_time = 0;
|
||||
// These should be chosen in a better manner
|
||||
// These should be chosen in a better manner (user specifiable)
|
||||
app_prefs.graphics.xsize = 640;
|
||||
app_prefs.graphics.ysize = 480;
|
||||
app_prefs.graphics.refresh_period = 5;
|
||||
app_prefs.checkpoint_period = 5;
|
||||
app_prefs.poll_period = 5;
|
||||
|
||||
// Write out the app prefs
|
||||
// Write out the app prefs. This has everything in the APP_IN
|
||||
// struct, including graphics prefs and checkpoint/poll prefs
|
||||
sprintf( prefs_path, "%s/%s", dirname, CORE_TO_APP_FILE );
|
||||
prefs_fd = fopen( prefs_path, "wb" );
|
||||
if( !prefs_fd ) {
|
||||
if( log_flags.task_debug ) {
|
||||
printf( "Failed to open core to app prefs file %s.\n", prefs_path );
|
||||
}
|
||||
return -1;
|
||||
return ERR_FOPEN;
|
||||
}
|
||||
rewind( prefs_fd );
|
||||
write_core_file( prefs_fd,app_prefs );
|
||||
fclose(prefs_fd);
|
||||
|
||||
// Open the init file. This file contains initialization
|
||||
// information regarding tasks that can only be performed in
|
||||
// the app, such as redirecting file descriptors
|
||||
//
|
||||
sprintf( init_path, "%s/%s", dirname, BOINC_INIT_FILE );
|
||||
init_file = fopen( init_path, "wb" );
|
||||
if( !init_file ) {
|
||||
if( log_flags.task_debug ) {
|
||||
printf( "Failed to open init file %s.\n", init_path );
|
||||
}
|
||||
return -1;
|
||||
return ERR_FOPEN;
|
||||
}
|
||||
rewind( init_file );
|
||||
|
||||
// make a link to the executable
|
||||
// make a soft link to the executable(s)
|
||||
//
|
||||
for (i=0; i<app_version->app_files.size(); i++) {
|
||||
fip = app_version->app_files[i].file_info;
|
||||
|
@ -217,7 +246,7 @@ int ACTIVE_TASK::start(bool first_time) {
|
|||
}
|
||||
}
|
||||
|
||||
// hook up the output files
|
||||
// hook up the output files using BOINC soft links
|
||||
//
|
||||
for (i=0; i<result->output_files.size(); i++) {
|
||||
file_ref = result->output_files[i];
|
||||
|
@ -326,15 +355,15 @@ int ACTIVE_TASK::start(bool first_time) {
|
|||
}
|
||||
pid_handle = process_info.hProcess;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef macintosh
|
||||
#endif
|
||||
|
||||
state = PROCESS_RUNNING;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Sends a request to the process of this active task to exit. If it
|
||||
// doesn't exist within a set time (seconds), the process is terminated
|
||||
//
|
||||
void ACTIVE_TASK::request_exit(int seconds) {
|
||||
int retval;
|
||||
if(seconds<0) {
|
||||
|
@ -355,6 +384,8 @@ void ACTIVE_TASK::request_exit(int seconds) {
|
|||
#endif
|
||||
}
|
||||
|
||||
// Inserts an active task into the ACTIVE_TASK_SET and starts it up
|
||||
//
|
||||
int ACTIVE_TASK_SET::insert(ACTIVE_TASK* atp) {
|
||||
int retval;
|
||||
if(atp==NULL) {
|
||||
|
@ -369,7 +400,7 @@ int ACTIVE_TASK_SET::insert(ACTIVE_TASK* atp) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// check for child process exit
|
||||
// Checks if any child processes have exited and records their final CPU time
|
||||
//
|
||||
bool ACTIVE_TASK_SET::poll() {
|
||||
int stat;
|
||||
|
@ -388,7 +419,6 @@ bool ACTIVE_TASK_SET::poll() {
|
|||
atp = active_tasks[i];
|
||||
if( GetExitCodeProcess( atp->pid_handle,&exit_code ) ) {
|
||||
// Get the elapsed CPU time
|
||||
// Factor this into the equivalent of a S@H etime function?
|
||||
if( GetProcessTimes( atp->pid_handle, &creation_time, &exit_time, &kernel_time, &user_time ) ) {
|
||||
tKernel.LowPart = kernel_time.dwLowDateTime;
|
||||
tKernel.HighPart = kernel_time.dwHighDateTime;
|
||||
|
@ -401,6 +431,7 @@ bool ACTIVE_TASK_SET::poll() {
|
|||
|
||||
atp->result->cpu_time = (totTime / 10000000.0);
|
||||
} else {
|
||||
// This probably isn't correct
|
||||
atp->result->cpu_time = ((double)clock())/CLOCKS_PER_SEC;
|
||||
}
|
||||
if( exit_code != STILL_ACTIVE ) {
|
||||
|
@ -465,20 +496,24 @@ bool ACTIVE_TASK_SET::poll() {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Find the ACTIVE_TASK in the current set with the matching PID
|
||||
//
|
||||
ACTIVE_TASK* ACTIVE_TASK_SET::lookup_pid(int pid) {
|
||||
unsigned int i;
|
||||
ACTIVE_TASK* atp;
|
||||
if(pid<0) {
|
||||
fprintf(stderr, "error: ACTIVE_TASK_SET.lookup_pid: negatvie pid\n");
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
for (i=0; i<active_tasks.size(); i++) {
|
||||
atp = active_tasks[i];
|
||||
if (atp->pid == pid) return atp;
|
||||
}
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Sends a suspend request to all currently running computation processes
|
||||
//
|
||||
void ACTIVE_TASK_SET::suspend_all() {
|
||||
unsigned int i;
|
||||
ACTIVE_TASK* atp;
|
||||
|
@ -488,6 +523,8 @@ void ACTIVE_TASK_SET::suspend_all() {
|
|||
}
|
||||
}
|
||||
|
||||
// Sends a resume signal to all currently running computation processes
|
||||
//
|
||||
void ACTIVE_TASK_SET::unsuspend_all() {
|
||||
unsigned int i;
|
||||
ACTIVE_TASK* atp;
|
||||
|
@ -497,6 +534,9 @@ void ACTIVE_TASK_SET::unsuspend_all() {
|
|||
}
|
||||
}
|
||||
|
||||
// Attempts to exit all currently running computation processes, either
|
||||
// via exit request or termination
|
||||
//
|
||||
void ACTIVE_TASK_SET::exit_tasks() {
|
||||
unsigned int i;
|
||||
ACTIVE_TASK *atp;
|
||||
|
@ -508,26 +548,37 @@ void ACTIVE_TASK_SET::exit_tasks() {
|
|||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Send a suspend request to the ACTIVE_TASK
|
||||
//
|
||||
void ACTIVE_TASK::suspend() {
|
||||
prev_cpu_time = cpu_time;
|
||||
// figure out a way to do this, perhaps via trigger file?
|
||||
//kill(atp->pid, SIGSTOP);
|
||||
}
|
||||
|
||||
// Send a resume request to the ACTIVE_TASK
|
||||
//
|
||||
void ACTIVE_TASK::unsuspend() {
|
||||
// figure out a way to do this, perhaps via trigger file?
|
||||
//kill(atp->pid, SIGCONT);
|
||||
}
|
||||
#else
|
||||
// Send a suspend request to the ACTIVE_TASK
|
||||
//
|
||||
void ACTIVE_TASK::suspend() {
|
||||
kill(this->pid, SIGSTOP);
|
||||
kill(this->pid, SIGSTOP);
|
||||
}
|
||||
|
||||
// Send a resume request to the ACTIVE_TASK
|
||||
//
|
||||
void ACTIVE_TASK::unsuspend() {
|
||||
kill(this->pid, SIGCONT);
|
||||
kill(this->pid, SIGCONT);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Remove an ACTIVE_TASK from the set, assumes that the task has
|
||||
// already been shut down via request_exit or similar means
|
||||
//
|
||||
int ACTIVE_TASK_SET::remove(ACTIVE_TASK* atp) {
|
||||
vector<ACTIVE_TASK*>::iterator iter;
|
||||
if(atp==NULL) {
|
||||
|
@ -546,6 +597,8 @@ int ACTIVE_TASK_SET::remove(ACTIVE_TASK* atp) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// Restart active tasks without wiping and reinitializing slot directories
|
||||
//
|
||||
int ACTIVE_TASK_SET::restart_tasks() {
|
||||
vector<ACTIVE_TASK*>::iterator iter;
|
||||
ACTIVE_TASK* atp;
|
||||
|
@ -569,6 +622,9 @@ int ACTIVE_TASK_SET::restart_tasks() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Update the CPU time accounting based on the APP_TO_CORE_FILE passed to
|
||||
// us by the application
|
||||
//
|
||||
bool ACTIVE_TASK::update_time() {
|
||||
FILE* app_fp;
|
||||
char app_path[256];
|
||||
|
@ -584,6 +640,8 @@ bool ACTIVE_TASK::update_time() {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Poll each of the currently running tasks and get their CPU time
|
||||
//
|
||||
bool ACTIVE_TASK_SET::poll_time() {
|
||||
ACTIVE_TASK* atp;
|
||||
unsigned int i;
|
||||
|
@ -595,6 +653,8 @@ bool ACTIVE_TASK_SET::poll_time() {
|
|||
return updated;
|
||||
}
|
||||
|
||||
// Write XML data about this ACTIVE_TASK
|
||||
//
|
||||
int ACTIVE_TASK::write(FILE* fout) {
|
||||
if(fout==NULL) {
|
||||
fprintf(stderr, "error: ACTIVE_TASK.write: unexpected NULL pointer fout\n");
|
||||
|
@ -617,6 +677,8 @@ int ACTIVE_TASK::write(FILE* fout) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Parse XML information about an active task
|
||||
//
|
||||
int ACTIVE_TASK::parse(FILE* fin, CLIENT_STATE* cs) {
|
||||
char buf[256], result_name[256], project_master_url[256];
|
||||
int app_version_num=0;
|
||||
|
@ -666,6 +728,8 @@ int ACTIVE_TASK::parse(FILE* fin, CLIENT_STATE* cs) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
// Write XML information about this active task set
|
||||
//
|
||||
int ACTIVE_TASK_SET::write(FILE* fout) {
|
||||
unsigned int i;
|
||||
if(fout==NULL) {
|
||||
|
@ -680,6 +744,8 @@ int ACTIVE_TASK_SET::write(FILE* fout) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Parse XML information about an active task set
|
||||
//
|
||||
int ACTIVE_TASK_SET::parse(FILE* fin, CLIENT_STATE* cs) {
|
||||
ACTIVE_TASK* atp;
|
||||
char buf[256];
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#ifndef _TASK_
|
||||
#define _TASK_
|
||||
|
||||
// Possible states of a process in an ACTIVE_TASK
|
||||
#define PROCESS_UNINITIALIZED 0
|
||||
#define PROCESS_RUNNING 1
|
||||
#define PROCESS_EXITED 2
|
||||
#define PROCESS_WAS_SIGNALED 3
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#define SECONDS_IN_MONTH 2592000
|
||||
|
||||
// Global CLIENT_STATE object
|
||||
CLIENT_STATE gstate;
|
||||
|
||||
CLIENT_STATE::CLIENT_STATE() {
|
||||
|
@ -74,6 +75,9 @@ int CLIENT_STATE::init(PREFS* p) {
|
|||
if (log_flags.state_debug) {
|
||||
print_counts();
|
||||
}
|
||||
|
||||
// Finally, set up the project and slot directories
|
||||
//
|
||||
make_project_dirs();
|
||||
make_slot_dirs();
|
||||
|
||||
|
@ -81,6 +85,8 @@ int CLIENT_STATE::init(PREFS* p) {
|
|||
}
|
||||
|
||||
// Returns true if time tests should be run
|
||||
// This is determined by seeing if the user passed the "-no_time_test"
|
||||
// flag or if it's been a month since we last checked time stats
|
||||
//
|
||||
bool CLIENT_STATE::run_time_tests() {
|
||||
return (run_time_test && (
|
||||
|
@ -88,7 +94,7 @@ bool CLIENT_STATE::run_time_tests() {
|
|||
));
|
||||
}
|
||||
|
||||
// Updates computer statistics once per month
|
||||
// Updates computer statistics (roughly once a month)
|
||||
//
|
||||
int CLIENT_STATE::time_tests() {
|
||||
get_host_info(host_info); // this is platform dependent
|
||||
|
@ -124,6 +130,9 @@ int CLIENT_STATE::check_suspend_activities() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// do_something is where all the action happens. This is part of the
|
||||
// finite state machine abstraction of the client. Each of the key
|
||||
// elements of the client is given a chance to perform work here.
|
||||
// return true if something happened
|
||||
//
|
||||
bool CLIENT_STATE::do_something() {
|
||||
|
@ -150,6 +159,8 @@ bool CLIENT_STATE::do_something() {
|
|||
return action;
|
||||
}
|
||||
|
||||
// Parse the client_state.xml file
|
||||
//
|
||||
int CLIENT_STATE::parse_state_file() {
|
||||
char buf[256];
|
||||
FILE* f = fopen(STATE_FILE_NAME, "r");
|
||||
|
@ -245,6 +256,9 @@ int CLIENT_STATE::parse_state_file() {
|
|||
return ERR_XML_PARSE;
|
||||
}
|
||||
|
||||
// Make a directory for each of the projects present
|
||||
// in the client state
|
||||
//
|
||||
int CLIENT_STATE::make_project_dirs() {
|
||||
unsigned int i;
|
||||
for (i=0; i<projects.size(); i++) {
|
||||
|
@ -253,6 +267,9 @@ int CLIENT_STATE::make_project_dirs() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Make a directory for each of the available slots specified
|
||||
// in the client state
|
||||
//
|
||||
int CLIENT_STATE::make_slot_dirs() {
|
||||
unsigned int i;
|
||||
for (i=0; i<nslots; i++) {
|
||||
|
@ -261,6 +278,10 @@ int CLIENT_STATE::make_slot_dirs() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Perform a graceful shutdown of the client, including quitting
|
||||
// all applications, checking their final status, and writing
|
||||
// the client_state.xml file
|
||||
//
|
||||
int CLIENT_STATE::exit_tasks() {
|
||||
int retval;
|
||||
active_tasks.exit_tasks();
|
||||
|
@ -273,6 +294,8 @@ int CLIENT_STATE::exit_tasks() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Writes the client_state.xml file
|
||||
//
|
||||
int CLIENT_STATE::write_state_file() {
|
||||
unsigned int i, j;
|
||||
FILE* f = fopen(STATE_FILE_TEMP, "wb");
|
||||
|
@ -327,6 +350,10 @@ int CLIENT_STATE::write_state_file() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// See if the project specified by master_url already exists
|
||||
// in the client state record.
|
||||
// TODO: make this smarter (i.e. www.project.com is the same as project.com)
|
||||
//
|
||||
PROJECT* CLIENT_STATE::lookup_project(char* master_url) {
|
||||
if(master_url==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.lookup_project: unexpected NULL pointer master_url\n");
|
||||
|
@ -340,6 +367,9 @@ PROJECT* CLIENT_STATE::lookup_project(char* master_url) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// See if the application (name) associated with project p is
|
||||
// around here
|
||||
//
|
||||
APP* CLIENT_STATE::lookup_app(PROJECT* p, char* name) {
|
||||
if(p==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.lookup_app: unexpected NULL pointer p\n");
|
||||
|
@ -356,6 +386,9 @@ APP* CLIENT_STATE::lookup_app(PROJECT* p, char* name) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// See if the result (name) associated with project p is
|
||||
// around here
|
||||
//
|
||||
RESULT* CLIENT_STATE::lookup_result(PROJECT* p, char* name) {
|
||||
if(p==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.lookup_result: unexpected NULL pointer p\n");
|
||||
|
@ -372,6 +405,9 @@ RESULT* CLIENT_STATE::lookup_result(PROJECT* p, char* name) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// See if the workunit (name) associated with project p is
|
||||
// around here
|
||||
//
|
||||
WORKUNIT* CLIENT_STATE::lookup_workunit(PROJECT* p, char* name) {
|
||||
if(p==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.lookup_workunit: unexpected NULL pointer p\n");
|
||||
|
@ -388,6 +424,9 @@ WORKUNIT* CLIENT_STATE::lookup_workunit(PROJECT* p, char* name) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// See if the app_version (name) associated with project p is
|
||||
// around here
|
||||
//
|
||||
APP_VERSION* CLIENT_STATE::lookup_app_version(APP* app, int version_num) {
|
||||
if(app==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.lookup_app_version: unexpected NULL pointer app\n");
|
||||
|
@ -406,6 +445,9 @@ APP_VERSION* CLIENT_STATE::lookup_app_version(APP* app, int version_num) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// See if the file info (name) associated with project p is
|
||||
// around here
|
||||
//
|
||||
FILE_INFO* CLIENT_STATE::lookup_file_info(PROJECT* p, char* name) {
|
||||
if(p==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.lookup_file_info: unexpected NULL pointer p\n");
|
||||
|
@ -580,6 +622,9 @@ int CLIENT_STATE::link_result(PROJECT* p, RESULT* rp) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Print debugging information about how many projects/files/etc
|
||||
// are currently in the client state record
|
||||
//
|
||||
void CLIENT_STATE::print_counts() {
|
||||
if (log_flags.state_debug) {
|
||||
printf(
|
||||
|
@ -696,6 +741,12 @@ int CLIENT_STATE::write_state_file_if_needed() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Parse the command line arguments passed to the client for specific flags:
|
||||
// -exit_when_idle: the client will exit when it has no more work to do
|
||||
// -no_time_test: the client will skip the speed and host information checks
|
||||
// -exit_after: the client will exit after X iterations of the do_something loop
|
||||
// (usually about X seconds)
|
||||
//
|
||||
void CLIENT_STATE::parse_cmdline(int argc, char** argv) {
|
||||
int i;
|
||||
if(argc<0) {
|
||||
|
@ -720,6 +771,8 @@ void CLIENT_STATE::parse_cmdline(int argc, char** argv) {
|
|||
}
|
||||
}
|
||||
|
||||
// Returns true if the core client should exit
|
||||
//
|
||||
bool CLIENT_STATE::time_to_exit() {
|
||||
if (!exit_when_idle && (exit_after != 0)) return false;
|
||||
if (results.size() == 0 && contacted_sched_server) return true;
|
||||
|
|
|
@ -27,10 +27,26 @@
|
|||
#include "client_types.h"
|
||||
|
||||
PROJECT::PROJECT() {
|
||||
project_specific_prefs = 0;
|
||||
code_sign_key = 0;
|
||||
strcpy(master_url,"");
|
||||
strcpy(authenticator,"");
|
||||
project_specific_prefs = NULL;
|
||||
resource_share = 0;
|
||||
strcpy(project_name,"");
|
||||
strcpy(user_name,"");
|
||||
rpc_seqno = 0;
|
||||
hostid = 0;
|
||||
exp_avg_cpu = 0;
|
||||
exp_avg_mod_time = 0;
|
||||
code_sign_key = NULL;
|
||||
nrpc_failures = 0;
|
||||
min_rpc_time = 0;
|
||||
resource_debt = 0;
|
||||
debt_order = 0;
|
||||
master_url_fetch_pending = 0;
|
||||
}
|
||||
|
||||
// Destroy this project object
|
||||
//
|
||||
PROJECT::~PROJECT() {
|
||||
if (project_specific_prefs) free(project_specific_prefs);
|
||||
if (code_sign_key) free(code_sign_key);
|
||||
|
@ -103,6 +119,8 @@ int PROJECT::parse_state(FILE* in) {
|
|||
return ERR_XML_PARSE;
|
||||
}
|
||||
|
||||
// Write the project information to prefs.xml
|
||||
//
|
||||
int PROJECT::write_state(FILE* out) {
|
||||
unsigned int i;
|
||||
if(out==NULL) {
|
||||
|
@ -172,6 +190,8 @@ void PROJECT::copy_prefs_fields(PROJECT& p) {
|
|||
resource_share = p.resource_share;
|
||||
}
|
||||
|
||||
// Parse application XML information, usually found in client_state.xml
|
||||
//
|
||||
int APP::parse(FILE* in) {
|
||||
char buf[256];
|
||||
if(in==NULL) {
|
||||
|
@ -189,6 +209,8 @@ int APP::parse(FILE* in) {
|
|||
return ERR_XML_PARSE;
|
||||
}
|
||||
|
||||
// Write application XML information, usually to client_state.xml
|
||||
//
|
||||
int APP::write(FILE* out) {
|
||||
if(out==NULL) {
|
||||
fprintf(stderr, "error: APP.write: unexpected NULL pointer out\n");
|
||||
|
@ -208,6 +230,8 @@ int APP::write(FILE* out) {
|
|||
FILE_INFO::FILE_INFO() {
|
||||
}
|
||||
|
||||
// TODO: Determine what (if anything) needs to be done when destroying FILE_INFO
|
||||
//
|
||||
FILE_INFO::~FILE_INFO() {
|
||||
}
|
||||
|
||||
|
@ -223,8 +247,8 @@ int FILE_INFO::parse(FILE* in, bool from_server) {
|
|||
}
|
||||
strcpy(name, "");
|
||||
strcpy(md5_cksum, "");
|
||||
nbytes = 0;
|
||||
max_nbytes = 0;
|
||||
nbytes = 0;
|
||||
generated_locally = false;
|
||||
file_present = false;
|
||||
executable = false;
|
||||
|
@ -232,15 +256,17 @@ int FILE_INFO::parse(FILE* in, bool from_server) {
|
|||
upload_when_present = false;
|
||||
sticky = false;
|
||||
signature_required = false;
|
||||
project = NULL;
|
||||
file_xfer = NULL;
|
||||
result = NULL;
|
||||
project = NULL;
|
||||
urls.clear();
|
||||
if (from_server) {
|
||||
signed_xml = strdup("");
|
||||
} else {
|
||||
signed_xml = 0;
|
||||
signed_xml = NULL;
|
||||
}
|
||||
xml_signature = 0;
|
||||
xml_signature = NULL;
|
||||
file_signature = NULL;
|
||||
while (fgets(buf, 256, in)) {
|
||||
if (match_tag(buf, "</file_info>")) return 0;
|
||||
else if (match_tag(buf, "<xml_signature>")) {
|
||||
|
@ -279,6 +305,8 @@ int FILE_INFO::parse(FILE* in, bool from_server) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// Write out XML based file info
|
||||
//
|
||||
int FILE_INFO::write(FILE* out, bool to_server) {
|
||||
unsigned int i;
|
||||
if(out==NULL) {
|
||||
|
@ -317,7 +345,7 @@ int FILE_INFO::write(FILE* out, bool to_server) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// delete underlying file
|
||||
// delete physical underlying file associated with FILE_INFO
|
||||
//
|
||||
int FILE_INFO::delete_file() {
|
||||
char path[256];
|
||||
|
@ -326,6 +354,8 @@ int FILE_INFO::delete_file() {
|
|||
return file_delete(path);
|
||||
}
|
||||
|
||||
// Parse XML based app_version information, usually from client_state.xml
|
||||
//
|
||||
int APP_VERSION::parse(FILE* in) {
|
||||
char buf[256];
|
||||
FILE_REF file_ref;
|
||||
|
@ -351,6 +381,8 @@ int APP_VERSION::parse(FILE* in) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// Write XML based app_version information, usually to client_state.xml
|
||||
//
|
||||
int APP_VERSION::write(FILE* out) {
|
||||
unsigned int i;
|
||||
if(out==NULL) {
|
||||
|
@ -373,6 +405,8 @@ int APP_VERSION::write(FILE* out) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Parse XML based file_ref information, usually from client_state.xml
|
||||
//
|
||||
int FILE_REF::parse(FILE* in) {
|
||||
char buf[256];
|
||||
if(in==NULL) {
|
||||
|
@ -394,19 +428,21 @@ int FILE_REF::parse(FILE* in) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// Write XML based file_ref information, usually to client_state.xml
|
||||
//
|
||||
int FILE_REF::write(FILE* out) {
|
||||
if(out==NULL) {
|
||||
fprintf(stderr, "error: FILE_REF.write: unexpected NULL pointer out\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
if (strlen(open_name)) {
|
||||
fprintf(out, " <open_name>%s</open_name>\n", open_name);
|
||||
}
|
||||
fprintf(out,
|
||||
" <file_ref>\n"
|
||||
" <file_name>%s</file_name>\n",
|
||||
file_name
|
||||
);
|
||||
if (strlen(open_name)) {
|
||||
fprintf(out, " <open_name>%s</open_name>\n", open_name);
|
||||
}
|
||||
if (fd >= 0) {
|
||||
fprintf(out, " <fd>%d</fd>\n", fd);
|
||||
}
|
||||
|
@ -417,6 +453,8 @@ int FILE_REF::write(FILE* out) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Parse XML based workunit information, usually from client_state.xml
|
||||
//
|
||||
int WORKUNIT::parse(FILE* in) {
|
||||
char buf[256];
|
||||
FILE_REF file_ref;
|
||||
|
@ -450,6 +488,8 @@ int WORKUNIT::parse(FILE* in) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// Write XML based workunit information, usually to client_state.xml
|
||||
//
|
||||
int WORKUNIT::write(FILE* out) {
|
||||
unsigned int i;
|
||||
if(out==NULL) {
|
||||
|
@ -612,6 +652,8 @@ int RESULT::write(FILE* out, bool to_server) {
|
|||
}
|
||||
|
||||
// this is called only after is_compute_done is true.
|
||||
// returns true if the result and it's associated files
|
||||
// were successfully uploaded
|
||||
//
|
||||
bool RESULT::is_upload_done() {
|
||||
unsigned int i;
|
||||
|
|
|
@ -1505,7 +1505,7 @@ EOF
|
|||
|
||||
fi
|
||||
|
||||
for ac_hdr in fcntl.h sys/time.h unistd.h sys/select.h sys/statvfs.h sys/swap.h sys/systeminfo.h sys/types.h dirent.h sys/utsname.h netdb.h netinet/in.h arpa/inet.h sys/resource.h signal.h sys/wait.h
|
||||
for ac_hdr in fcntl.h sys/time.h unistd.h sys/select.h sys/statvfs.h sys/swap.h sys/systeminfo.h sys/socket.h sys/types.h dirent.h sys/utsname.h netdb.h netinet/in.h netinet/tcp.h arpa/inet.h sys/resource.h signal.h sys/wait.h
|
||||
do
|
||||
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
|
||||
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
|
||||
|
|
|
@ -37,7 +37,7 @@ AC_CHECK_LIB(stdc++, cerr)
|
|||
dnl Checks for header files.
|
||||
AC_HEADER_DIRENT
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS(fcntl.h sys/time.h unistd.h sys/select.h sys/statvfs.h sys/swap.h sys/systeminfo.h sys/types.h dirent.h sys/utsname.h netdb.h netinet/in.h arpa/inet.h sys/resource.h signal.h sys/wait.h)
|
||||
AC_CHECK_HEADERS(fcntl.h sys/time.h unistd.h sys/select.h sys/statvfs.h sys/swap.h sys/systeminfo.h sys/socket.h sys/types.h dirent.h sys/utsname.h netdb.h netinet/in.h netinet/tcp.h arpa/inet.h sys/resource.h signal.h sys/wait.h)
|
||||
|
||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
|
|
|
@ -54,7 +54,7 @@ int CLIENT_STATE::app_finished(ACTIVE_TASK& at) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// poll and clean up after existing apps
|
||||
// poll status of existing apps and and clean up after them
|
||||
//
|
||||
bool CLIENT_STATE::handle_running_apps() {
|
||||
unsigned int i;
|
||||
|
@ -80,6 +80,9 @@ bool CLIENT_STATE::handle_running_apps() {
|
|||
return action;
|
||||
}
|
||||
|
||||
// Returns true if all the input files for a result are available
|
||||
// locally, false otherwise
|
||||
//
|
||||
bool CLIENT_STATE::input_files_available(RESULT* rp) {
|
||||
if(rp==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.input_files_available: unexpected NULL pointer rp\n");
|
||||
|
@ -111,6 +114,8 @@ bool CLIENT_STATE::start_apps() {
|
|||
bool action = false;
|
||||
|
||||
for (i=0; i<results.size(); i++) {
|
||||
// If all the app slots are already used, we can't start
|
||||
// a new app
|
||||
if (active_tasks.active_tasks.size() == nslots) {
|
||||
if (log_flags.task_debug) {
|
||||
printf("start_apps(): all slots full\n");
|
||||
|
@ -118,6 +123,10 @@ bool CLIENT_STATE::start_apps() {
|
|||
return 0;
|
||||
}
|
||||
rp = results[i];
|
||||
// Start the application to compute a result if the result
|
||||
// isn't done yet, the application isn't currently computing
|
||||
// the result, and all the input files for the result are
|
||||
// locally available
|
||||
if (!rp->is_compute_done && !rp->is_active && input_files_available(rp)) {
|
||||
if (log_flags.task_debug) {
|
||||
printf("starting application for result %s\n", rp->name);
|
||||
|
@ -133,7 +142,7 @@ bool CLIENT_STATE::start_apps() {
|
|||
return action;
|
||||
}
|
||||
|
||||
// This is called on initialization.
|
||||
// This is called when the client is initialized.
|
||||
// Try to restart any tasks that were running when we last shut down.
|
||||
//
|
||||
int CLIENT_STATE::restart_tasks() {
|
||||
|
|
|
@ -39,6 +39,9 @@
|
|||
#include "client_state.h"
|
||||
#include "error_numbers.h"
|
||||
|
||||
// Verify the validity of a downloaded file, through MD5 checksum
|
||||
// or an RSA signature
|
||||
//
|
||||
int verify_downloaded_file(char* pathname, FILE_INFO& file_info) {
|
||||
char cksum[64];
|
||||
PROJECT* project;
|
||||
|
@ -77,6 +80,10 @@ int verify_downloaded_file(char* pathname, FILE_INFO& file_info) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// scan all FILE_INFOs.
|
||||
// start downloads and uploads as needed.
|
||||
// check for completion of existing transfers
|
||||
//
|
||||
bool CLIENT_STATE::start_file_xfers() {
|
||||
unsigned int i;
|
||||
FILE_INFO* fip;
|
||||
|
@ -85,10 +92,6 @@ bool CLIENT_STATE::start_file_xfers() {
|
|||
int retval;
|
||||
bool action = false;
|
||||
|
||||
// scan all FILE_INFOs.
|
||||
// start downloads and uploads as needed.
|
||||
// check for completion of existing transfers
|
||||
//
|
||||
for (i=0; i<file_infos.size(); i++) {
|
||||
fip = file_infos[i];
|
||||
fxp = fip->file_xfer;
|
||||
|
|
|
@ -158,6 +158,10 @@ PROJECT* CLIENT_STATE::choose_project() {
|
|||
}
|
||||
#endif
|
||||
|
||||
// Compute the "resource debt" of each project. This is used
|
||||
// to determine what project we will focus on next, based on
|
||||
// the user specified resource share
|
||||
//
|
||||
void CLIENT_STATE::compute_resource_debts() {
|
||||
unsigned int i, j;
|
||||
PROJECT* p, *pbest;
|
||||
|
@ -190,6 +194,10 @@ void CLIENT_STATE::compute_resource_debts() {
|
|||
}
|
||||
}
|
||||
|
||||
// Prepare the scheduler request. This writes the request in XML to a
|
||||
// file (SCHED_OP_REQUEST_FILE) which is later sent to the scheduling
|
||||
// server
|
||||
//
|
||||
int CLIENT_STATE::make_scheduler_request(PROJECT* p, double work_req) {
|
||||
FILE* f = fopen(SCHED_OP_REQUEST_FILE, "wb");
|
||||
unsigned int i;
|
||||
|
@ -371,15 +379,19 @@ bool CLIENT_STATE::get_work() {
|
|||
}
|
||||
#endif
|
||||
|
||||
// see whether a new preferences set, obtained from
|
||||
// the given project, looks "reasonable".
|
||||
// see whether a new preferences set, obtained from the given
|
||||
// project, looks "reasonable". This is to prevent accidental or
|
||||
// intentional preferences corruption
|
||||
// Currently this is primitive: just make sure there's at least 1 project
|
||||
//
|
||||
// TODO: figure out what else to look for here
|
||||
bool PREFS::looks_reasonable(PROJECT& project) {
|
||||
if (projects.size() > 0) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse the reply from a scheduler and configure internal structures
|
||||
// appropriately
|
||||
//
|
||||
void CLIENT_STATE::handle_scheduler_reply(
|
||||
PROJECT* project, char* scheduler_url
|
||||
) {
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
#include "file_names.h"
|
||||
#include "error_numbers.h"
|
||||
|
||||
// Converts a character string of a decimal number to hexadecimal string
|
||||
//
|
||||
static void c2x(char *what) {
|
||||
char buf[3];
|
||||
char num = atoi(what);
|
||||
|
@ -50,6 +52,9 @@ static void c2x(char *what) {
|
|||
strcpy(what, buf);
|
||||
}
|
||||
|
||||
// Escape a URL, converting the non alphanumeric characters to
|
||||
// %XY where XY is their hexadecimal equivalent
|
||||
//
|
||||
static void escape_url(char *in, char* out) {
|
||||
int x, y;
|
||||
if(in==NULL) {
|
||||
|
@ -77,6 +82,8 @@ static void escape_url(char *in, char* out) {
|
|||
out[y] = 0;
|
||||
}
|
||||
|
||||
// Gets the pathname of a file
|
||||
//
|
||||
void get_pathname(FILE_INFO* fip, char* path) {
|
||||
if(fip==NULL) {
|
||||
fprintf(stderr, "error: get_pathname: unexpected NULL pointer fip\n");
|
||||
|
@ -97,6 +104,8 @@ void get_pathname(FILE_INFO* fip, char* path) {
|
|||
}
|
||||
}
|
||||
|
||||
// Returns the location of a numbered slot directory
|
||||
//
|
||||
void get_slot_dir(int slot, char* path) {
|
||||
if(path==NULL) {
|
||||
fprintf(stderr, "error: get_slot_dir: unexpected NULL pointer path\n");
|
||||
|
@ -119,6 +128,8 @@ int make_project_dir(PROJECT& p) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Returns the location of a numbered slot directory
|
||||
//
|
||||
int make_slot_dir(int slot) {
|
||||
if(slot<0) {
|
||||
fprintf(stderr, "error: make_slot_dir: negative slot\n");
|
||||
|
@ -133,6 +144,8 @@ int make_slot_dir(int slot) {
|
|||
|
||||
#else
|
||||
|
||||
// Create the directory for the project p
|
||||
//
|
||||
int make_project_dir(PROJECT& p) {
|
||||
char buf[256];
|
||||
|
||||
|
@ -141,6 +154,8 @@ int make_project_dir(PROJECT& p) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Create the slot directory for the specified slot #
|
||||
//
|
||||
int make_slot_dir(int slot) {
|
||||
char buf[256];
|
||||
if(slot<0) {
|
||||
|
@ -153,6 +168,8 @@ int make_slot_dir(int slot) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Returns a filename used for prefs backup
|
||||
//
|
||||
int make_prefs_backup_name(PREFS& prefs, char* name) {
|
||||
if(name==NULL) {
|
||||
fprintf(stderr, "error: make_prefs_backup_name: unexpected NULL pointer name\n");
|
||||
|
|
|
@ -28,12 +28,21 @@
|
|||
FILE_XFER::FILE_XFER() {
|
||||
file_xfer_done = false;
|
||||
file_xfer_retval = 0;
|
||||
start_time = 0;
|
||||
end_time = 0;
|
||||
fip = NULL;
|
||||
strcpy(pathname,"");
|
||||
strcpy(header,"");
|
||||
//state = ?
|
||||
}
|
||||
|
||||
// Do we need to do anything special when destroying the FILE_XFER object?
|
||||
//
|
||||
FILE_XFER::~FILE_XFER() {
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Is there any reason to keep this around?
|
||||
int FILE_XFER::init_download(char* url, char* outfile) {
|
||||
if(url==NULL) {
|
||||
fprintf(stderr, "error: FILE_XFER.init_download: unexpected NULL pointer url\n");
|
||||
|
@ -46,6 +55,7 @@ int FILE_XFER::init_download(char* url, char* outfile) {
|
|||
return HTTP_OP::init_get(url, outfile);
|
||||
}
|
||||
|
||||
// Is there any reason to keep this around?
|
||||
int FILE_XFER::init_upload(char* url, char* infile) {
|
||||
if(url==NULL) {
|
||||
fprintf(stderr, "error: FILE_XFER.init_upload: unexpected NULL pointer url\n");
|
||||
|
@ -89,10 +99,14 @@ int FILE_XFER::init_upload(FILE_INFO& file_info) {
|
|||
return HTTP_OP::init_post2((char*)(&fip->urls[0]), header, pathname, 0);
|
||||
}
|
||||
|
||||
// Returns the total time that the file xfer has taken
|
||||
//
|
||||
double FILE_XFER::elapsed_time() {
|
||||
return end_time - start_time;
|
||||
}
|
||||
|
||||
// Create a new empty FILE_XFER_SET
|
||||
//
|
||||
FILE_XFER_SET::FILE_XFER_SET(HTTP_OP_SET* p) {
|
||||
if(p==NULL) {
|
||||
fprintf(stderr, "error: FILE_XFER_SET: unexpected NULL pointer p\n");
|
||||
|
@ -100,6 +114,8 @@ FILE_XFER_SET::FILE_XFER_SET(HTTP_OP_SET* p) {
|
|||
http_ops = p;
|
||||
}
|
||||
|
||||
// Insert a FILE_XFER object into the set
|
||||
//
|
||||
int FILE_XFER_SET::insert(FILE_XFER* fxp) {
|
||||
int retval;
|
||||
if(fxp==NULL) {
|
||||
|
@ -117,6 +133,8 @@ int FILE_XFER_SET::insert(FILE_XFER* fxp) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Remove a FILE_XFER object from the set
|
||||
//
|
||||
int FILE_XFER_SET::remove(FILE_XFER* fxp) {
|
||||
vector<FILE_XFER*>::iterator iter;
|
||||
if(fxp==NULL) {
|
||||
|
@ -138,6 +156,9 @@ int FILE_XFER_SET::remove(FILE_XFER* fxp) {
|
|||
|
||||
}
|
||||
|
||||
// Run through the FILE_XFER_SET and determine if any of the file
|
||||
// transfers are complete or had an error
|
||||
//
|
||||
bool FILE_XFER_SET::poll() {
|
||||
unsigned int i;
|
||||
FILE_XFER* fxp;
|
||||
|
|
|
@ -73,6 +73,7 @@ char failed_file[256];
|
|||
|
||||
// routines for enumerating the entries in a directory
|
||||
|
||||
// Open a directory
|
||||
int dir_open(char* p) {
|
||||
if(p==NULL) {
|
||||
fprintf(stderr, "error: dir_open: unexpected NULL pointer p\n");
|
||||
|
@ -87,6 +88,7 @@ int dir_open(char* p) {
|
|||
strcat(path, "\\*");
|
||||
first = 1;
|
||||
handle = INVALID_HANDLE_VALUE;
|
||||
// This is probably incomplete
|
||||
#endif
|
||||
#ifdef macintosh
|
||||
SayErr("\pdir_open called (empty function)"); /* CAF Temp */
|
||||
|
@ -94,6 +96,8 @@ int dir_open(char* p) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Scan through a directory and return the next file name in it
|
||||
//
|
||||
int dir_scan(char* p) {
|
||||
if(p==NULL) {
|
||||
fprintf(stderr, "error: dir_scan: unexpected NULL pointer p\n");
|
||||
|
@ -145,6 +149,8 @@ int dir_scan(char* p) {
|
|||
#endif
|
||||
}
|
||||
|
||||
// Close a directory
|
||||
//
|
||||
void dir_close() {
|
||||
#ifdef HAVE_DIRENT_H
|
||||
if (dirp) {
|
||||
|
@ -163,6 +169,8 @@ void dir_close() {
|
|||
#endif
|
||||
}
|
||||
|
||||
// Delete the file located at path
|
||||
//
|
||||
int file_delete(char* path) {
|
||||
int retval,i;
|
||||
if(path==NULL) {
|
||||
|
@ -200,8 +208,8 @@ int file_size(char* path, int& size) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* boinc_link creates a file (new) which contains an XML
|
||||
reference to existing. */
|
||||
/* boinc_link creates a file (new_link) which contains an XML
|
||||
reference (soft link) to existing. */
|
||||
|
||||
int boinc_link( char *existing, char *new_link ) {
|
||||
FILE *fp;
|
||||
|
@ -222,6 +230,8 @@ int boinc_link( char *existing, char *new_link ) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Goes through directory specified by dirpath and removes all files from it
|
||||
//
|
||||
int clean_out_dir(char* dirpath) {
|
||||
char filename[256], path[256];
|
||||
int retval;
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include "hostinfo.h"
|
||||
#include "error_numbers.h"
|
||||
|
||||
// Parse the host information, usually from the client state XML file
|
||||
//
|
||||
int HOST_INFO::parse(FILE* in) {
|
||||
char buf[256];
|
||||
if(in==NULL) {
|
||||
|
@ -55,6 +57,8 @@ int HOST_INFO::parse(FILE* in) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Write the host information, usually to the client state XML file
|
||||
//
|
||||
int HOST_INFO::write(FILE* out) {
|
||||
if(out==NULL) {
|
||||
fprintf(stderr, "error: HOST_INFO.write: unexpected NULL pointer out\n");
|
||||
|
|
|
@ -61,6 +61,9 @@
|
|||
|
||||
// functions to get name/addr of local host
|
||||
|
||||
// Returns the domain of the local host
|
||||
// TODO: Should the 256 be MAXHOSTNAMELEN instead?
|
||||
//
|
||||
int get_local_domain_name(char* p) {
|
||||
char buf[256];
|
||||
if(p==NULL) {
|
||||
|
@ -73,6 +76,8 @@ int get_local_domain_name(char* p) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Gets the ip address of the local host
|
||||
//
|
||||
int get_local_ip_addr(int& p) {
|
||||
char buf[256];
|
||||
struct in_addr addr;
|
||||
|
@ -85,6 +90,9 @@ int get_local_ip_addr(int& p) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Returns the name of the local host
|
||||
// TODO: Should the 256 be MAXHOSTNAMELEN instead?
|
||||
//
|
||||
int get_local_ip_addr_str(char* p) {
|
||||
char buf[256];
|
||||
if(p==NULL) {
|
||||
|
@ -101,6 +109,8 @@ int get_local_ip_addr_str(char* p) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Converts a int ip address to a string representation (i.e. "66.218.71.198")
|
||||
//
|
||||
char* ip_addr_string(int ip_addr) {
|
||||
in_addr ia;
|
||||
|
||||
|
@ -108,7 +118,8 @@ char* ip_addr_string(int ip_addr) {
|
|||
return inet_ntoa(ia);
|
||||
}
|
||||
|
||||
|
||||
// What does this return? # of seconds from GMT?
|
||||
//
|
||||
void get_timezone(int& tz) {
|
||||
tzset();
|
||||
|
||||
|
@ -120,6 +131,9 @@ void get_timezone(int& tz) {
|
|||
#endif
|
||||
}
|
||||
|
||||
// Returns true if the host is currently running off battery power
|
||||
// TODO: port this to other platforms (Windows, Mac OS X, others?)
|
||||
//
|
||||
bool host_is_running_on_batteries() {
|
||||
float x1, x2;
|
||||
int i1, i2;
|
||||
|
@ -139,6 +153,8 @@ bool host_is_running_on_batteries() {
|
|||
|
||||
#ifdef linux
|
||||
|
||||
// Determine the memory specifications for this host, including RAM and swap space
|
||||
//
|
||||
void parse_meminfo(HOST_INFO& host) {
|
||||
char buf[256];
|
||||
FILE* f = fopen("/proc/meminfo", "r");
|
||||
|
@ -157,7 +173,7 @@ void parse_meminfo(HOST_INFO& host) {
|
|||
// Unfortunately the format of /proc/cpuinfo is not standardized.
|
||||
// See http://people.nl.linux.org/~hch/cpuinfo/ for some examples.
|
||||
// The following is for Redhat Linux 2.2.14.
|
||||
//
|
||||
// TODO: get this to work on all platforms
|
||||
void parse_cpuinfo(HOST_INFO& host) {
|
||||
char buf[256];
|
||||
int n;
|
||||
|
@ -182,6 +198,8 @@ void parse_cpuinfo(HOST_INFO& host) {
|
|||
#endif
|
||||
|
||||
#if HAVE_SYS_UTSNAME_H
|
||||
// Puts the operating system name and version into the HOST_INFO structure
|
||||
//
|
||||
void get_osinfo(HOST_INFO& host) {
|
||||
struct utsname u;
|
||||
uname(&u);
|
||||
|
@ -190,6 +208,8 @@ void get_osinfo(HOST_INFO& host) {
|
|||
}
|
||||
#endif
|
||||
|
||||
// General function to get all relevant host information
|
||||
//
|
||||
int get_host_info(HOST_INFO& host) {
|
||||
host.m_nbytes = 0;
|
||||
host.m_cache = 0;
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
extern int get_local_domain_name(char* p);
|
||||
extern int get_local_ip_addr_str(char* p);
|
||||
|
||||
// Gets windows specific host information (not complete)
|
||||
//
|
||||
int get_host_info(HOST_INFO& host) {
|
||||
OSVERSIONINFO OSVersionInfo;
|
||||
memset( &OSVersionInfo, NULL, sizeof( OSVersionInfo ) );
|
||||
|
|
|
@ -36,6 +36,10 @@
|
|||
|
||||
#define HTTP_BLOCKSIZE 4096
|
||||
|
||||
// Breaks a url down into its server and file path components
|
||||
// TODO: deal with alternate protocols (ftp, gopher, etc) or disallow
|
||||
// them and parse accordingly
|
||||
//
|
||||
static void parse_url(char* url, char* host, char* file) {
|
||||
char* p;
|
||||
char buf[256];
|
||||
|
@ -64,6 +68,8 @@ static void parse_url(char* url, char* host, char* file) {
|
|||
// We use 1.0 so we don't have to count bytes.
|
||||
//
|
||||
|
||||
// Prints an HTTP 1.0 GET request header into buf
|
||||
//
|
||||
static void http_get_request_header(
|
||||
char* buf, char* host, char* file, int offset
|
||||
) {
|
||||
|
@ -102,6 +108,8 @@ static void http_get_request_header(
|
|||
}
|
||||
}
|
||||
|
||||
// Prints an HTTP 1.0 HEAD request header into buf
|
||||
//
|
||||
static void http_head_request_header(char* buf, char* host, char* file) {
|
||||
if(buf==NULL) {
|
||||
fprintf(stderr, "error: http_head_request_header: unexpected NULL pointer buf\n");
|
||||
|
@ -122,6 +130,8 @@ static void http_head_request_header(char* buf, char* host, char* file) {
|
|||
);
|
||||
}
|
||||
|
||||
// Prints an HTTP 1.0 POST request header into buf
|
||||
//
|
||||
static void http_post_request_header(
|
||||
char* buf, char* host, char* file, int size
|
||||
) {
|
||||
|
@ -150,6 +160,8 @@ static void http_post_request_header(
|
|||
}
|
||||
|
||||
#if 0
|
||||
// Do we still need this?
|
||||
//
|
||||
void http_put_request_header(
|
||||
char* buf, char* host, char* file, int size, int offset
|
||||
) {
|
||||
|
@ -196,6 +208,8 @@ void http_put_request_header(
|
|||
}
|
||||
#endif
|
||||
|
||||
// Parse an http reply header into the header struct
|
||||
//
|
||||
int read_http_reply_header(int socket, HTTP_REPLY_HEADER& header) {
|
||||
int i, n;
|
||||
char buf[1024], *p;
|
||||
|
@ -224,6 +238,8 @@ int read_http_reply_header(int socket, HTTP_REPLY_HEADER& header) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// Read the contents of the socket into buf
|
||||
//
|
||||
static int read_reply(int socket, char* buf, int len) {
|
||||
int i, n;
|
||||
if(socket<0) {
|
||||
|
@ -248,11 +264,24 @@ static int read_reply(int socket, char* buf, int len) {
|
|||
|
||||
HTTP_OP::HTTP_OP() {
|
||||
http_op_state = HTTP_STATE_IDLE;
|
||||
strcpy(hostname,"");
|
||||
strcpy(filename,"");
|
||||
req1 = NULL;
|
||||
strcpy(infile,"");
|
||||
strcpy(outfile,"");
|
||||
content_length = 0;
|
||||
file_offset = 0;
|
||||
strcpy(request_header,"");
|
||||
http_op_state = HTTP_STATE_IDLE;
|
||||
http_op_type = HTTP_OP_NONE;
|
||||
http_op_retval = 0;
|
||||
}
|
||||
|
||||
HTTP_OP::~HTTP_OP() {
|
||||
}
|
||||
|
||||
// Initialize HTTP HEAD operation to url
|
||||
//
|
||||
int HTTP_OP::init_head(char* url) {
|
||||
if(url==NULL) {
|
||||
fprintf(stderr, "error: HTTP_OP.init_head: unexpected NULL pointer url\n");
|
||||
|
@ -266,6 +295,8 @@ int HTTP_OP::init_head(char* url) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Initialize HTTP GET operation to url
|
||||
//
|
||||
int HTTP_OP::init_get(char* url, char* out, int off) {
|
||||
if(url==NULL) {
|
||||
fprintf(stderr, "error: HTTP_OP.init_get: unexpected NULL pointer url\n");
|
||||
|
@ -289,6 +320,8 @@ int HTTP_OP::init_get(char* url, char* out, int off) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Initialize HTTP POST operation to url
|
||||
//
|
||||
int HTTP_OP::init_post(char* url, char* in, char* out) {
|
||||
int retval;
|
||||
if(url==NULL) {
|
||||
|
@ -317,6 +350,8 @@ int HTTP_OP::init_post(char* url, char* in, char* out) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Initialize HTTP POST operation to url including file offset
|
||||
//
|
||||
int HTTP_OP::init_post2(
|
||||
char* url, char* r1, char* in, double offset
|
||||
) {
|
||||
|
@ -355,6 +390,7 @@ int HTTP_OP::init_post2(
|
|||
}
|
||||
|
||||
#if 0
|
||||
// Is this still needed?
|
||||
int HTTP_OP::init_put(char* url, char* in, int off) {
|
||||
int retval;
|
||||
|
||||
|
@ -373,6 +409,8 @@ int HTTP_OP::init_put(char* url, char* in, int off) {
|
|||
}
|
||||
#endif
|
||||
|
||||
// Returns true if the HTTP operation is complete
|
||||
//
|
||||
bool HTTP_OP::http_op_done() {
|
||||
return (http_op_state == HTTP_STATE_DONE);
|
||||
}
|
||||
|
@ -384,6 +422,8 @@ HTTP_OP_SET::HTTP_OP_SET(NET_XFER_SET* p) {
|
|||
net_xfers = p;
|
||||
}
|
||||
|
||||
// Inserts an hTTP_OP into the set
|
||||
//
|
||||
int HTTP_OP_SET::insert(HTTP_OP* ho) {
|
||||
int retval;
|
||||
if(ho==NULL) {
|
||||
|
@ -396,6 +436,10 @@ int HTTP_OP_SET::insert(HTTP_OP* ho) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Runs through the set of HTTP_OP objects in the set and decides
|
||||
// what operation is appropriate for each. This section needs more
|
||||
// thorough documentation, as it is fairly complex
|
||||
//
|
||||
bool HTTP_OP_SET::poll() {
|
||||
unsigned int i;
|
||||
HTTP_OP* htp;
|
||||
|
@ -406,6 +450,8 @@ bool HTTP_OP_SET::poll() {
|
|||
htp = http_ops[i];
|
||||
switch(htp->http_op_state) {
|
||||
case HTTP_STATE_CONNECTING:
|
||||
// If the op is in the connecting state, and we notice it is done
|
||||
// connecting, move it to the HTTP_STATE_REQUEST_HEADER state
|
||||
if (htp->is_connected) {
|
||||
htp->http_op_state = HTTP_STATE_REQUEST_HEADER;
|
||||
htp->want_upload = true;
|
||||
|
@ -547,6 +593,8 @@ bool HTTP_OP_SET::poll() {
|
|||
return action;
|
||||
}
|
||||
|
||||
// Remove an HTTP_OP from the set
|
||||
//
|
||||
int HTTP_OP_SET::remove(HTTP_OP* p) {
|
||||
vector<HTTP_OP*>::iterator iter;
|
||||
if(p==NULL) {
|
||||
|
@ -567,6 +615,8 @@ int HTTP_OP_SET::remove(HTTP_OP* p) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// Returns the size of the set of HTTP_OP objects
|
||||
//
|
||||
int HTTP_OP_SET::size() {
|
||||
return http_ops.size();
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ struct HTTP_REPLY_HEADER {
|
|||
int content_length;
|
||||
};
|
||||
|
||||
#define HTTP_OP_NONE 0
|
||||
// For the first 4, data source/sink are files
|
||||
#define HTTP_OP_GET 1
|
||||
#define HTTP_OP_POST 2
|
||||
|
|
|
@ -28,9 +28,13 @@
|
|||
LOG_FLAGS log_flags;
|
||||
|
||||
LOG_FLAGS::LOG_FLAGS() {
|
||||
memset(this, 0, sizeof(LOG_FLAGS));
|
||||
task = file_xfer = sched_ops = state_debug = false;
|
||||
task_debug = file_xfer_debug = sched_op_debug = false;
|
||||
http_debug = time_debug = net_xfer_debug = false;
|
||||
}
|
||||
|
||||
// Parse log flag preferences
|
||||
//
|
||||
int LOG_FLAGS::parse(FILE* in) {
|
||||
char buf[256];
|
||||
if(in==NULL) {
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
#include "prefs.h"
|
||||
#include "util.h"
|
||||
|
||||
// Display a message to the user. Depending on the priority, the
|
||||
// message may be more or less obtrusive
|
||||
//
|
||||
void show_message(char* message, char* priority) {
|
||||
if(message==NULL) {
|
||||
fprintf(stderr, "error: show_message: unexpected NULL pointer message\n");
|
||||
|
@ -46,6 +49,7 @@ void show_message(char* message, char* priority) {
|
|||
|
||||
// Prompt user for project URL and authenticator,
|
||||
// and create a prototype prefs file
|
||||
// TODO: use better input method here, backspace doesn't always seem to work
|
||||
//
|
||||
int initialize_prefs() {
|
||||
char master_url[256];
|
||||
|
@ -73,14 +77,19 @@ int main(int argc, char** argv) {
|
|||
FILE* f;
|
||||
int retval;
|
||||
|
||||
// Set the stdout buffer to 0, such that stdout output
|
||||
// immediately gets written out
|
||||
setbuf(stdout, 0);
|
||||
|
||||
// Read any log flags preferences, used mainly for debugging
|
||||
f = fopen(LOG_FLAGS_FILE, "r");
|
||||
if (f) {
|
||||
log_flags.parse(f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
// Read the user preferences file, if it exists. If it doesn't,
|
||||
// prompt user for project URL via initialize_prefs()
|
||||
prefs = new PREFS;
|
||||
retval = prefs->parse_file();
|
||||
if (retval) {
|
||||
|
@ -96,23 +105,34 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
}
|
||||
|
||||
// Initialize the client state with the preferences
|
||||
gstate.init(prefs);
|
||||
// Parse command line arguments
|
||||
gstate.parse_cmdline(argc, argv);
|
||||
// Run the time tests and host information check if needed
|
||||
// TODO: break time tests and host information check into two
|
||||
// separate functions?
|
||||
if(gstate.run_time_tests()) {
|
||||
gstate.time_tests();
|
||||
}
|
||||
// Restart any tasks that were running when we last quit the client
|
||||
gstate.restart_tasks();
|
||||
while (1) {
|
||||
// do_something is where the meat of the clients work is done
|
||||
// it will return false if it had nothing to do, in which case
|
||||
// client will go to sleep for a second
|
||||
if (!gstate.do_something()) {
|
||||
if (log_flags.time_debug) printf("SLEEP 1 SECOND\n");
|
||||
fflush(stdout);
|
||||
boinc_sleep(1);
|
||||
}
|
||||
// If it's time to exit, break out of the while loop
|
||||
if (gstate.time_to_exit()) {
|
||||
printf("time to exit\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Clean everything up and gracefully exit
|
||||
gstate.exit_tasks();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "error_numbers.h"
|
||||
#include "net_stats.h"
|
||||
|
||||
// Is this a reasonable cutoff?
|
||||
#define SMALL_FILE_CUTOFF 32000
|
||||
|
||||
NET_STATS::NET_STATS() {
|
||||
|
@ -35,6 +36,7 @@ NET_STATS::NET_STATS() {
|
|||
bwdown = 0;
|
||||
}
|
||||
|
||||
// Update network statistics
|
||||
void NET_STATS::update(bool is_upload, double nbytes, double nsecs) {
|
||||
double w1, w2, bw;
|
||||
|
||||
|
@ -66,6 +68,8 @@ void NET_STATS::update(bool is_upload, double nbytes, double nsecs) {
|
|||
}
|
||||
}
|
||||
|
||||
// Write XML based network statistics
|
||||
//
|
||||
int NET_STATS::write(FILE* out, bool to_server) {
|
||||
if(out==NULL) {
|
||||
fprintf(stderr, "error: NET_STATS.write: unexpected NULL pointer out\n");
|
||||
|
@ -89,6 +93,8 @@ int NET_STATS::write(FILE* out, bool to_server) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Read XML based network statistics
|
||||
//
|
||||
int NET_STATS::parse(FILE* in) {
|
||||
char buf[256];
|
||||
if(in==NULL) {
|
||||
|
|
|
@ -23,22 +23,38 @@
|
|||
|
||||
#ifdef _WIN32
|
||||
#include "winsock.h"
|
||||
#else
|
||||
#endif
|
||||
|
||||
#if HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#if HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#if HAVE_SYS_SELECT_H
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
#if HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#if HAVE_NETINET_TCP_H
|
||||
#include <netinet/tcp.h>
|
||||
#endif
|
||||
#if HAVE_NETDB_H
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#if HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
//#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "error_numbers.h"
|
||||
|
@ -54,7 +70,8 @@
|
|||
#define socklen_t size_t
|
||||
#endif
|
||||
|
||||
|
||||
// Attempt to open a nonblocking socket to a server
|
||||
//
|
||||
int NET_XFER::open_server() {
|
||||
sockaddr_in addr;
|
||||
hostent* hep;
|
||||
|
@ -108,18 +125,23 @@ int NET_XFER::open_server() {
|
|||
|
||||
|
||||
void NET_XFER::init(char* host, int p, int b) {
|
||||
strcpy(hostname, host);
|
||||
port = p;
|
||||
// net_xfer_state = ?
|
||||
socket = -1;
|
||||
is_connected = false;
|
||||
want_download = false;
|
||||
want_upload = false;
|
||||
do_file_io = false;
|
||||
io_done = false;
|
||||
file = NULL;
|
||||
io_ready = false;
|
||||
error = 0;
|
||||
strcpy(hostname, host);
|
||||
port = p;
|
||||
blocksize = b;
|
||||
}
|
||||
|
||||
// Insert a NET_XFER object into the set
|
||||
//
|
||||
int NET_XFER_SET::insert(NET_XFER* nxp) {
|
||||
int retval = nxp->open_server();
|
||||
if (retval) return retval;
|
||||
|
@ -127,6 +149,8 @@ int NET_XFER_SET::insert(NET_XFER* nxp) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Remove a NET_XFER object from the set
|
||||
//
|
||||
int NET_XFER_SET::remove(NET_XFER* nxp) {
|
||||
vector<NET_XFER*>::iterator iter;
|
||||
|
||||
|
@ -150,7 +174,7 @@ int NET_XFER_SET::remove(NET_XFER* nxp) {
|
|||
|
||||
// transfer data to/from a list of active streams
|
||||
// transfer at most max_bytes bytes.
|
||||
//
|
||||
// TODO: implement other bandwidth constraints (ul/dl ratio, time of day)
|
||||
int NET_XFER_SET::poll(int max_bytes, int& bytes_transferred) {
|
||||
int n, retval;
|
||||
|
||||
|
@ -252,6 +276,8 @@ int NET_XFER_SET::do_select(int max_bytes, int& bytes_transferred) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Return the NET_XFER object whose socket matches fd
|
||||
//
|
||||
NET_XFER* NET_XFER_SET::lookup_fd(int fd) {
|
||||
for (unsigned int i=0; i<net_xfers.size(); i++) {
|
||||
if (net_xfers[i]->socket == fd) {
|
||||
|
|
|
@ -42,6 +42,8 @@ PREFS::PREFS() {
|
|||
disk_min_free_gb = 0;
|
||||
};
|
||||
|
||||
// Parse XML based prefs, usually from prefs.xml
|
||||
//
|
||||
int PREFS::parse(FILE* in) {
|
||||
char buf[256];
|
||||
PROJECT* project;
|
||||
|
@ -76,6 +78,8 @@ int PREFS::parse(FILE* in) {
|
|||
return ERR_XML_PARSE;
|
||||
}
|
||||
|
||||
// Parse prefs.xml for user preferences
|
||||
//
|
||||
int PREFS::parse_file() {
|
||||
FILE* f;
|
||||
int retval;
|
||||
|
@ -87,6 +91,8 @@ int PREFS::parse_file() {
|
|||
return retval;
|
||||
}
|
||||
|
||||
// Write the default preference set for a project
|
||||
// TODO: should mod_time really be 1?
|
||||
int write_initial_prefs(char* master_url, char* authenticator) {
|
||||
FILE* f = fopen(PREFS_FILE_NAME, "w");
|
||||
if (!f) return ERR_FOPEN;
|
||||
|
|
|
@ -6,9 +6,10 @@
|
|||
#include "speed_stats.h"
|
||||
#include "error_numbers.h"
|
||||
|
||||
#define D_FLOP_ITERS 1
|
||||
#define I_OP_ITERS 1
|
||||
#define BANDWIDTH_ITERS 1
|
||||
// # of iterations of each test to run for initial timing purposes
|
||||
#define D_FLOP_ITERS 100
|
||||
#define I_OP_ITERS 100
|
||||
#define BANDWIDTH_ITERS 5
|
||||
|
||||
//#define RUN_TEST
|
||||
|
||||
|
@ -24,6 +25,29 @@ int main( void ) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void run_test_suite( double num_secs_per_test ) {
|
||||
if(num_secs_per_test<0) {
|
||||
fprintf(stderr, "error: run_test_suite: negative num_seconds_per_test\n");
|
||||
}
|
||||
printf(
|
||||
"Running tests. This will take about %.1lf seconds.\n\n",
|
||||
num_secs_per_test*3
|
||||
);
|
||||
|
||||
printf(
|
||||
"Speed: %.5lf million flops/sec\n\n",
|
||||
run_double_prec_test(num_secs_per_test)/1000000
|
||||
);
|
||||
printf(
|
||||
"Speed: %.5lf million integer ops/sec\n\n",
|
||||
run_int_test(num_secs_per_test)/1000000
|
||||
);
|
||||
printf(
|
||||
"Speed: %.5lf MB/sec\n\n",
|
||||
12*sizeof(double)*run_mem_bandwidth_test(num_secs_per_test)/1000000
|
||||
);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int check_cache_size( int mem_size ) {
|
||||
|
@ -163,6 +187,8 @@ int check_cache_size( int mem_size ) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Run the test of double precision math speed for about num_secs seconds
|
||||
//
|
||||
double run_double_prec_test( double num_secs ) {
|
||||
int df_test_time, df_iters;
|
||||
double df_secs;
|
||||
|
@ -178,7 +204,7 @@ double run_double_prec_test( double num_secs ) {
|
|||
// Calculate the # of iterations based on these tests
|
||||
df_iters = (int)(D_FLOP_ITERS*num_secs/df_secs);
|
||||
|
||||
if( df_iters > D_FLOP_ITERS ) { // no need to redo test
|
||||
if( df_iters > D_FLOP_ITERS ) { // no need to redo test if we already got enough
|
||||
df_test_time = (int)double_flop_test( df_iters, 0 );
|
||||
} else {
|
||||
df_iters = D_FLOP_ITERS;
|
||||
|
@ -189,6 +215,8 @@ double run_double_prec_test( double num_secs ) {
|
|||
return 1000000*df_iters/df_secs;
|
||||
}
|
||||
|
||||
// Run the test of integer math speed for about num_secs seconds
|
||||
//
|
||||
double run_int_test( double num_secs ) {
|
||||
int int_test_time, int_iters;
|
||||
double int_secs;
|
||||
|
@ -215,6 +243,8 @@ double run_int_test( double num_secs ) {
|
|||
return 1000000*int_iters/int_secs;
|
||||
}
|
||||
|
||||
// Run the test of memory bandwidth speed for about num_secs seconds
|
||||
//
|
||||
double run_mem_bandwidth_test( double num_secs ) {
|
||||
int bw_test_time;
|
||||
double bw_secs;
|
||||
|
@ -241,29 +271,6 @@ double run_mem_bandwidth_test( double num_secs ) {
|
|||
return 1000000*bw_iters/bw_secs;
|
||||
}
|
||||
|
||||
void run_test_suite( double num_secs_per_test ) {
|
||||
if(num_secs_per_test<0) {
|
||||
fprintf(stderr, "error: run_test_suite: negative num_seconds_per_test\n");
|
||||
}
|
||||
printf(
|
||||
"Running tests. This will take about %.1lf seconds.\n\n",
|
||||
num_secs_per_test*3
|
||||
);
|
||||
|
||||
printf(
|
||||
"Speed: %.5lf million flops/sec\n\n",
|
||||
run_double_prec_test(num_secs_per_test)/1000000
|
||||
);
|
||||
printf(
|
||||
"Speed: %.5lf million integer ops/sec\n\n",
|
||||
run_int_test(num_secs_per_test)/1000000
|
||||
);
|
||||
printf(
|
||||
"Speed: %.5lf MB/sec\n\n",
|
||||
12*sizeof(double)*run_mem_bandwidth_test(num_secs_per_test)/1000000
|
||||
);
|
||||
}
|
||||
|
||||
// One iteration == D_LOOP_ITERS (1,000,000) floating point operations
|
||||
// If time_total is negative, there was an error in the calculation,
|
||||
// meaning there is probably something wrong with the CPU
|
||||
|
@ -289,9 +296,10 @@ clock_t double_flop_test( int iterations, int print_debug ) {
|
|||
for( j=0;j<D_LOOP_ITERS;j+=((NUM_DOUBLES-1)*5) ) {
|
||||
temp = 1;
|
||||
t1 = a[0];
|
||||
// These tests do a pretty good job of breaking the processor pipeline,
|
||||
// These tests do a pretty good job of preventing optimization
|
||||
// since the result from all but one of the lines is required for the
|
||||
// next line.
|
||||
// next line. At the end of each iteration through the for loop,
|
||||
// the array should be the same as when it started
|
||||
|
||||
for( k=0;k<NUM_DOUBLES-1;k++ ) {
|
||||
t2 = a[k+1];
|
||||
|
@ -306,11 +314,20 @@ clock_t double_flop_test( int iterations, int print_debug ) {
|
|||
}
|
||||
}
|
||||
|
||||
time_total = clock()-time_start;
|
||||
// Stop the clock
|
||||
time_total = clock();
|
||||
|
||||
// Accomodate for the possibility of clock wraparound
|
||||
if( time_total > time_start ) {
|
||||
time_total -= time_start;
|
||||
} else {
|
||||
time_total = 0; // this is just a kludge
|
||||
}
|
||||
|
||||
|
||||
calc_error = 0;
|
||||
temp = 1;
|
||||
// Check to make sure all the values are the same
|
||||
// Check to make sure all the values are the same as when we started
|
||||
for( i=0;i<NUM_DOUBLES;i++ ) {
|
||||
if( (float)a[i] != (float)temp ) {
|
||||
calc_error = 1;
|
||||
|
@ -351,6 +368,10 @@ clock_t int_op_test( int iterations, int print_debug ) {
|
|||
|
||||
time_start = clock();
|
||||
for( i=0;i<iterations;i++ ) {
|
||||
// The contents of the array "a" should be the same at the
|
||||
// beginning and end of each loop iteration. Most compilers will
|
||||
// partially unroll the individual loops within this one, so
|
||||
// those integer operations (incrementing k) are not counted
|
||||
for( j=0;j<I_LOOP_ITERS/(NUM_INTS*9);j++ ) {
|
||||
for( k=0;k<NUM_INTS;k++ ) {
|
||||
a[k] *= 3; // 1 int ops
|
||||
|
@ -380,11 +401,19 @@ clock_t int_op_test( int iterations, int print_debug ) {
|
|||
}
|
||||
}
|
||||
|
||||
time_total = clock()-time_start;
|
||||
// Stop the clock
|
||||
time_total = clock();
|
||||
|
||||
// Accomodate for the possibility of clock wraparound
|
||||
if( time_total > time_start ) {
|
||||
time_total -= time_start;
|
||||
} else {
|
||||
time_total = 0; // this is just a kludge
|
||||
}
|
||||
|
||||
calc_error = 0;
|
||||
temp = 1;
|
||||
// Check to make sure all the values are the same
|
||||
// Check to make sure all the values are the same as when we started
|
||||
for( i=0;i<NUM_INTS;i++ ) {
|
||||
if( a[i] != temp ) {
|
||||
calc_error = 1;
|
||||
|
@ -406,7 +435,7 @@ clock_t int_op_test( int iterations, int print_debug ) {
|
|||
return time_total;
|
||||
}
|
||||
|
||||
// One iteration == Read of 6M*sizeof(double), Write of 6M*sizeof(double)
|
||||
// One iteration == Read of 6,000,000*sizeof(double), Write of 6,000,000*sizeof(double)
|
||||
// If time_total is negative, there was an error in the copying,
|
||||
// meaning there is probably something wrong with the CPU
|
||||
|
||||
|
@ -458,7 +487,7 @@ clock_t bandwidth_test( int iterations, int print_debug ) {
|
|||
if( time_total > time_start ) {
|
||||
time_total -= time_start;
|
||||
} else {
|
||||
time_total -= time_start;
|
||||
time_total = 0; // this is just a kludge
|
||||
}
|
||||
|
||||
copy_error = 0;
|
||||
|
|
|
@ -33,13 +33,15 @@
|
|||
#define ALPHA (3600.*24*7*30)
|
||||
|
||||
TIME_STATS::TIME_STATS() {
|
||||
first = true;
|
||||
last_update = 0;
|
||||
first = true;
|
||||
on_frac = 1;
|
||||
connected_frac = 1;
|
||||
active_frac = 1;
|
||||
}
|
||||
|
||||
// Update time statistics based on current activities
|
||||
//
|
||||
void TIME_STATS::update(bool is_connected, bool is_active) {
|
||||
int now = time(0), dt;
|
||||
double w1, w2;
|
||||
|
@ -78,6 +80,8 @@ void TIME_STATS::update(bool is_connected, bool is_active) {
|
|||
}
|
||||
}
|
||||
|
||||
// Write XML based time statistics
|
||||
//
|
||||
int TIME_STATS::write(FILE* out, bool to_server) {
|
||||
fprintf(out,
|
||||
"<time_stats>\n"
|
||||
|
@ -98,6 +102,8 @@ int TIME_STATS::write(FILE* out, bool to_server) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Parse XML based time statistics, usually from client_state.xml
|
||||
//
|
||||
int TIME_STATS::parse(FILE* in) {
|
||||
char buf[256];
|
||||
if(in==NULL) {
|
||||
|
|
|
@ -53,6 +53,8 @@ double dtime() {
|
|||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Goes to sleep for a specified number of seconds
|
||||
// TODO: allow for fractional second sleep times?
|
||||
void boinc_sleep( int seconds ) {
|
||||
if(seconds<0) {
|
||||
fprintf(stderr, "error: boinc_sleep: negative seconds\n");
|
||||
|
@ -63,6 +65,8 @@ void boinc_sleep( int seconds ) {
|
|||
|
||||
#else
|
||||
|
||||
// Goes to sleep for a specified number of seconds
|
||||
// TODO: allow for fractional second sleep times?
|
||||
void boinc_sleep( int seconds ) {
|
||||
if(seconds<0) {
|
||||
fprintf(stderr,"error: boinc_sleep: negative seconds\n");
|
||||
|
|
Loading…
Reference in New Issue