- client simulator: updates. Fix web interface.

svn path=/trunk/boinc/; revision=22476
This commit is contained in:
David Anderson 2010-10-07 21:41:31 +00:00
parent 65b942c799
commit a20e7d5837
10 changed files with 193 additions and 261 deletions

View File

@ -7187,3 +7187,15 @@ David 7 Oct 2010
network.cpp
client/
boinc_cmd.cpp
David 7 Oct 2010
- client simulator: updates. Fix web interface.
client/
client_state.h
cpu_sched.cpp
cs_prefs.cpp
cs_statefile.cpp
log_flags.cpp,h
sim.cpp
work_fetch.cpp

View File

@ -34,6 +34,7 @@ using std::vector;
#include "app.h"
#include "client_types.h"
#include "file_xfer.h"
#include "file_names.h"
#include "gui_rpc_server.h"
#include "gui_http.h"
#include "hostinfo.h"
@ -366,7 +367,10 @@ struct CLIENT_STATE {
int allowed_project_disk_usage(double&);
int suspend_tasks(int reason);
int resume_tasks(int reason=0);
void read_global_prefs();
void read_global_prefs(
const char* fname = GLOBAL_PREFS_FILE_NAME,
const char* override_fname = GLOBAL_PREFS_OVERRIDE_FILE
);
int save_global_prefs(char* prefs, char* url, char* sched);
double available_ram();
double max_available_ram();
@ -398,6 +402,7 @@ struct CLIENT_STATE {
// --------------- cs_statefile.cpp:
void set_client_state_dirty(const char*);
int parse_state_file();
int parse_state_file_aux(const char*);
int write_state(MIOFILE&);
int write_state_file();
int write_state_file_if_needed();
@ -460,9 +465,9 @@ struct CLIENT_STATE {
double connection_interval;
// don't connect more often than this
void html_start(bool);
void html_start();
void html_rec();
void html_end(bool);
void html_end();
std::string html_msg;
double share_violation();
double monotony();

View File

@ -1872,16 +1872,6 @@ void CLIENT_STATE::set_ncpus() {
//
void PROJECT::update_duration_correction_factor(ACTIVE_TASK* atp) {
RESULT* rp = atp->result;
#ifdef SIM
if (dcf_dont_use) {
duration_correction_factor = 1.0;
return;
}
if (dcf_stats) {
update_dcf_stats(rp);
return;
}
#endif
double raw_ratio = atp->elapsed_time/rp->estimated_duration_uncorrected();
double adj_ratio = atp->elapsed_time/rp->estimated_duration(false);
double old_dcf = duration_correction_factor;

View File

@ -371,23 +371,27 @@ int PROJECT::parse_preferences_for_user_files() {
// - on completion of a scheduler or AMS RPC, if they sent prefs
// - in response to read_global_prefs_override GUI RPC
//
void CLIENT_STATE::read_global_prefs() {
void CLIENT_STATE::read_global_prefs(
const char* fname, const char* override_fname
) {
bool found_venue;
bool venue_specified_in_override = false;
int retval;
FILE* f;
string foo;
retval = read_file_string(GLOBAL_PREFS_OVERRIDE_FILE, foo);
if (!retval) {
parse_str(foo.c_str(), "<host_venue>", main_host_venue, sizeof(main_host_venue));
if (strlen(main_host_venue)) {
venue_specified_in_override = true;
if (override_fname) {
retval = read_file_string(override_fname, foo);
if (!retval) {
parse_str(foo.c_str(), "<host_venue>", main_host_venue, sizeof(main_host_venue));
if (strlen(main_host_venue)) {
venue_specified_in_override = true;
}
}
}
retval = global_prefs.parse_file(
GLOBAL_PREFS_FILE_NAME, main_host_venue, found_venue
fname, main_host_venue, found_venue
);
if (retval) {
if (retval == ERR_FOPEN) {
@ -398,7 +402,7 @@ void CLIENT_STATE::read_global_prefs() {
msg_printf(NULL, MSG_INFO,
"Couldn't parse preferences file - using BOINC defaults"
);
boinc_delete_file(GLOBAL_PREFS_FILE_NAME);
boinc_delete_file(fname);
}
global_prefs.init();
} else {
@ -410,7 +414,7 @@ void CLIENT_STATE::read_global_prefs() {
PROJECT* p = global_prefs_source_project();
if (p && strcmp(main_host_venue, p->host_venue)) {
strcpy(main_host_venue, p->host_venue);
global_prefs.parse_file(GLOBAL_PREFS_FILE_NAME, main_host_venue, found_venue);
global_prefs.parse_file(fname, main_host_venue, found_venue);
}
}
show_global_prefs_source(found_venue);
@ -418,15 +422,17 @@ void CLIENT_STATE::read_global_prefs() {
// read the override file
//
f = fopen(GLOBAL_PREFS_OVERRIDE_FILE, "r");
if (f) {
MIOFILE mf;
GLOBAL_PREFS_MASK mask;
mf.init_file(f);
XML_PARSER xp(&mf);
global_prefs.parse_override(xp, "", found_venue, mask);
msg_printf(NULL, MSG_INFO, "Reading preferences override file");
fclose(f);
if (override_fname) {
f = fopen(override_fname, "r");
if (f) {
MIOFILE mf;
GLOBAL_PREFS_MASK mask;
mf.init_file(f);
XML_PARSER xp(&mf);
global_prefs.parse_override(xp, "", found_venue, mask);
msg_printf(NULL, MSG_INFO, "Reading preferences override file");
fclose(f);
}
}
msg_printf(NULL, MSG_INFO, "Preferences:");

View File

@ -82,10 +82,6 @@ static inline bool arrived_first(RESULT* r0, RESULT* r1) {
// Parse the client_state.xml file
//
int CLIENT_STATE::parse_state_file() {
PROJECT *project=NULL;
char buf[256];
int retval=0;
int failnum;
const char *fname;
// Look for a valid state file:
@ -111,6 +107,14 @@ int CLIENT_STATE::parse_state_file() {
old_release = BOINC_RELEASE;
return ERR_FOPEN;
}
return parse_state_file_aux(fname);
}
int CLIENT_STATE::parse_state_file_aux(const char* fname) {
PROJECT *project=NULL;
char buf[256];
int retval=0;
int failnum;
FILE* f = fopen(fname, "r");
MIOFILE mf;

View File

@ -479,14 +479,12 @@ int CONFIG::parse(FILE* f) {
return ERR_XML_PARSE;
}
int read_config_file(bool init) {
FILE* f;
int read_config_file(bool init, const char* fname) {
if (!init) {
msg_printf(NULL, MSG_INFO, "Re-reading cc_config.xml");
msg_printf(NULL, MSG_INFO, "Re-reading %s", fname);
config.clear();
}
f = boinc_fopen(CONFIG_FILE, "r");
FILE* f = boinc_fopen(fname, "r");
if (!f) return ERR_FOPEN;
config.parse(f);
fclose(f);

View File

@ -31,6 +31,8 @@
#include <cstdio>
#endif
#include "file_names.h"
#define MAX_FILE_XFERS_PER_PROJECT 2
#define MAX_FILE_XFERS 8
// kind of arbitrary
@ -163,6 +165,6 @@ struct CONFIG {
extern LOG_FLAGS log_flags;
extern CONFIG config;
extern int read_config_file(bool init);
extern int read_config_file(bool init, const char* fname=CONFIG_FILE);
#endif

View File

@ -17,23 +17,35 @@
// BOINC client simulator.
//
// usage:
// sim [--duration x] [--delta x] [--dirs dir ...]
// duration = simulation duration (default 86400)
// delta = simulation time step (default 10)
// usage: sim options
//
// If no dirs are specified:
// reads input files
// sim_projects.xml, sim_host.xml, sim_prefs.xml, cc_config.xml
// and does simulation, generating output files
// sim_log.txt, sim_out.html
// Input files:
// [--state_file filename]
// name of main input file; default client_state.xml
// [--prefs_file filename]
// name of prefs file; default global_prefs.xml
// [--config_file filename]
// name of config file; default cc_config.xml
//
// If dirs are specified, chdir into each directory in sequence,
// do the above for each one, and write summary info to stdout
#ifdef _MSC_VER
#define chdir _chdir
#endif
// Output files:
// [--timeline_file filename]
// name of timeline file (default sim_timeline.html)
// [--log_file filename]
// name of log file (default sim_log.txt)
// [--summary_file filename]
// name of summary file (default sim_summary.xml)
//
// Simulation params:
// [--duration x]
// simulation duration (default 86400)
// [--delta x]
// delta = simulation time step (default 10)
//
// Policy options:
// [--server_uses_workload]
// simulate use of EDF sim by scheduler
// [--cpu_sched_rr_only]
// use only RR scheduling
#include "error_numbers.h"
#include "str_util.h"
@ -48,11 +60,13 @@
#define SCHED_RETRY_DELAY_MIN 60 // 1 minute
#define SCHED_RETRY_DELAY_MAX (60*60*4) // 4 hours
#ifdef _WIN32
#define SIM_EXEC "..\\boincsim"
#else
#define SIM_EXEC "../sim"
#endif
const char* state_fname = STATE_FILE_NAME;
const char* prefs_fname = GLOBAL_PREFS_FILE_NAME;
const char* config_fname = CONFIG_FILE;
const char* timeline_fname = "sim_timeline.html";
const char* log_fname = "sim_log.txt";
const char* summary_fname = "sim_summary.xml";
bool user_active;
double duration = 86400, delta = 60;
@ -60,32 +74,19 @@ FILE* logfile;
bool running;
double running_time = 0;
bool server_uses_workload = false;
bool dcf_dont_use;
bool dcf_stats;
bool dual_dcf;
bool cpu_sched_rr_only;
bool work_fetch_old;
int line_limit = 1000000;
SIM_RESULTS sim_results;
void PROJECT::update_dcf_stats(RESULT* rp) {
double raw_ratio = rp->final_cpu_time/rp->estimated_duration_uncorrected();
// see http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Algorithm_III
++completed_task_count;
double delta = raw_ratio - completions_ratio_mean;
completions_ratio_mean += delta / completed_task_count;
completions_ratio_s += delta * ( raw_ratio - completions_ratio_mean);
if (completed_task_count > 1) {
completions_ratio_stdev = sqrt(completions_ratio_s / (completed_task_count - 1));
double required_stdev = (raw_ratio - completions_ratio_mean) / completions_ratio_stdev;
if (required_stdev > completions_required_stdevs) {
completions_required_stdevs = std::min(required_stdev, 7.0);
}
}
duration_correction_factor = completions_ratio_mean +
completions_required_stdevs * completions_ratio_stdev;
return;
void usage(char* prog) {
fprintf(stderr, "usage: %s\n"
"[--duration X]\n"
"[--delta X]\n"
"[--server_uses_workload]\n"
"[--cpu_sched_rr_only]\n",
prog
);
exit(1);
}
APP* choose_app(vector<APP*>& apps) {
@ -599,8 +600,6 @@ const char* colors[] = {
"#ffdddd",
};
static int outfile_num=0;
bool uses_coproc(RESULT*, COPROC*) {
// TODO
return false;
@ -649,30 +648,23 @@ void gpu_on_aux(COPROC* cp) {
}
}
}
void gpu_on() {
gpu_on_aux(&gstate.host_info.coprocs.cuda);
gpu_on_aux(&gstate.host_info.coprocs.ati);
}
void CLIENT_STATE::html_start(bool show_prev) {
void CLIENT_STATE::html_start() {
char buf[256];
sprintf(buf, "sim_out_%d.html", outfile_num++);
html_out = fopen(buf, "w");
html_out = fopen(timeline_fname, "w");
if (!html_out) {
fprintf(stderr, "can't open %s for writing\n", buf);
fprintf(stderr, "can't open %s for writing\n", timeline_fname);
exit(1);
}
setbuf(html_out, 0);
fprintf(html_out, "<h2>Simulator output</h2>\n");
if (show_prev) {
fprintf(html_out,
"<a href=sim_out_%d.html>Previous file</a><p>\n",
outfile_num-2
);
}
fprintf(html_out,
"<a href=sim_log.txt>message log</a><p>"
"<table border=1><tr><th>Time</th>\n"
);
for (int i=0; i<ncpus; i++) {
@ -719,37 +711,15 @@ void CLIENT_STATE::html_rec() {
"<td><font size=-2>%s</font></td></tr>\n", html_msg.c_str()
);
html_msg = "";
if (++line_num == line_limit) {
line_num = 0;
html_end(true);
html_start(true);
}
}
void CLIENT_STATE::html_end(bool show_next) {
void CLIENT_STATE::html_end() {
fprintf(html_out, "</table>");
if (show_next) {
fprintf(html_out,
"<p><a href=sim_out_%d.html>Next file</a>\n",
outfile_num
);
} else {
fprintf(html_out, "<pre>\n");
sim_results.compute();
sim_results.print(html_out);
print_project_results(html_out);
fprintf(html_out, "</pre>\n");
}
if (show_next) {
fprintf(html_out, "<p><a href=sim_out_last.html>Last file</a>\n");
} else {
char buf[256];
sprintf(buf, "sim_out_%d.html", outfile_num-1);
#ifndef _WIN32
symlink(buf, "sim_out_last.html");
#endif
}
fprintf(html_out, "<pre>\n");
sim_results.compute();
sim_results.print(html_out);
print_project_results(html_out);
fprintf(html_out, "</pre>\n");
fclose(html_out);
}
@ -757,7 +727,7 @@ void CLIENT_STATE::simulate() {
bool action;
double start = START_TIME;
now = start;
html_start(false);
html_start();
msg_printf(0, MSG_INFO,
"starting simulation. delta %f duration %f", delta, duration
);
@ -785,7 +755,7 @@ void CLIENT_STATE::simulate() {
html_rec();
if (now > start + duration) break;
}
html_end(false);
html_end();
}
void parse_error(char* file, int retval) {
@ -793,26 +763,10 @@ void parse_error(char* file, int retval) {
exit(1);
}
void help(char* prog) {
fprintf(stderr, "usage: %s\n"
"[--duration X]\n"
"[--delta X]\n"
"[--server_uses_workload]\n"
"[--dcf_dont_user]\n"
"[--dcf_stats]\n"
"[--dual_dcf]\n"
"[--cpu_sched_rr_only]\n"
"[--work_fetch_old]\n"
"[--dirs ...]\n",
prog
);
exit(1);
}
char* next_arg(int argc, char** argv, int& i) {
if (i >= argc) {
fprintf(stderr, "Missing command-line argument\n");
help(argv[0]);
usage(argv[0]);
}
return argv[i++];
}
@ -899,17 +853,14 @@ void cull_projects() {
}
}
#define SUMMARY_FILE "sim_summary.txt"
#define LOG_FILE "sim_log.txt"
void CLIENT_STATE::do_client_simulation() {
msg_printf(0, MSG_INFO, "SIMULATION START");
read_config_file(true);
read_config_file(true, config_fname);
config.show();
add_platform("client simulator");
parse_state_file();
read_global_prefs();
parse_state_file_aux(state_fname);
read_global_prefs(prefs_fname);
cull_projects();
int j=0;
for (unsigned int i=0; i<projects.size(); i++) {
@ -941,92 +892,49 @@ void CLIENT_STATE::do_client_simulation() {
int main(int argc, char** argv) {
int i, retval;
vector<std::string> dirs;
logfile = fopen("sim_log.txt", "w");
if (!logfile) {
fprintf(stderr, "Can't open sim_log.txt\n");
exit(1);
}
setbuf(logfile, 0);
sim_results.clear();
for (i=1; i<argc;) {
char* opt = argv[i++];
if (!strcmp(opt, "--duration")) {
if (!strcmp(opt, "--state_file")) {
state_fname = argv[i++];
} else if (!strcmp(opt, "--prefs_file")) {
prefs_fname = argv[i++];
} else if (!strcmp(opt, "--config_file")) {
config_fname = argv[i++];
} else if (!strcmp(opt, "--timeline_file")) {
timeline_fname = argv[i++];
} else if (!strcmp(opt, "--log_file")) {
log_fname = argv[i++];
} else if (!strcmp(opt, "--summary_file")) {
summary_fname = argv[i++];
} else if (!strcmp(opt, "--duration")) {
duration = atof(next_arg(argc, argv, i));
} else if (!strcmp(opt, "--delta")) {
delta = atof(next_arg(argc, argv, i));
} else if (!strcmp(opt, "--dirs")) {
while (i<argc) {
dirs.push_back(argv[i++]);
}
} else if (!strcmp(opt, "--server_uses_workload")) {
server_uses_workload = true;
} else if (!strcmp(opt, "--dcf_dont_use")) {
dcf_dont_use = true;
} else if (!strcmp(opt, "--dcf_stats")) {
dcf_stats = true;
} else if (!strcmp(opt, "--dual_dcf")) {
dual_dcf = true;
dcf_stats = true;
} else if (!strcmp(opt, "--cpu_sched_rr_only")) {
cpu_sched_rr_only = true;
} else if (!strcmp(opt, "--work_fetch_old")) {
work_fetch_old = true;
} else if (!strcmp(opt, "--line_limit")) {
line_limit = atoi(next_arg(argc, argv, i));
} else {
help(argv[0]);
usage(argv[0]);
}
}
if (duration <= 0) {
printf("non-pos duration\n");
fprintf(stderr, "non-pos duration\n");
exit(1);
}
if (delta <= 0) {
printf("non-pos delta\n");
fprintf(stderr, "non-pos delta\n");
exit(1);
}
if (dirs.size()) {
// If we need to do several simulations,
// use system() to do each one in a separate process,
// because there are lots of static variables and we need to ensure
// that they start off with the right initial values
//
unsigned int i;
SIM_RESULTS total_results;
total_results.clear();
for (i=0; i<dirs.size(); i++) {
std::string dir = dirs[i];
retval = chdir(dir.c_str());
if (retval) {
fprintf(stderr, "can't chdir into %s: ", dir.c_str());
perror("chdir");
continue;
}
char buf[256];
sprintf(
buf, "%s --duration %f --delta %f > %s",
SIM_EXEC, duration, delta, SUMMARY_FILE
);
retval = system(buf);
if (retval) {
printf("simulation in %s failed\n", dir.c_str());
exit(1);
}
FILE* f = fopen(SUMMARY_FILE, "r");
sim_results.parse(f);
fclose(f);
sim_results.print(stdout, dir.c_str());
total_results.add(sim_results);
chdir("..");
}
total_results.divide((int)(dirs.size()));
total_results.print(stdout, "Total");
} else {
gstate.do_client_simulation();
logfile = fopen(log_fname, "w");
if (!logfile) {
fprintf(stderr, "Can't open %s\n", log_fname);
exit(1);
}
setbuf(logfile, 0);
gstate.do_client_simulation();
}

View File

@ -1305,18 +1305,9 @@ double RESULT::estimated_duration_uncorrected() {
// estimate how long a result will take on this host
//
#ifdef SIM
double RESULT::estimated_duration(bool for_work_fetch) {
if (dual_dcf && for_work_fetch && project->completions_ratio_mean) {
return estimated_duration_uncorrected()*project->completions_ratio_mean;
}
return estimated_duration_uncorrected()*project->duration_correction_factor;
}
#else
double RESULT::estimated_duration(bool) {
return estimated_duration_uncorrected()*project->duration_correction_factor;
}
#endif
double RESULT::estimated_time_remaining(bool for_work_fetch) {
if (computing_done()) return 0;

View File

@ -33,8 +33,7 @@ function show_form() {
<p>
<b>
The following controls enable various experimental policies.
The standard policy (as of 5.10.13) is no checkboxes enabled,
and the 'Normal' DCF policy.
The standard policy is no checkboxes enabled.
</b>
<p>
@ -42,33 +41,46 @@ function show_form() {
<p>
Client uses Round-Robin (old-style) CPU scheduling? <input type=checkbox name=rr_only>
<p>
Client uses old work fetch policy? <input type=checkbox name=work_fetch_old>
<p>
Duration correction factor: <input type=radio name=dcf value=normal checked> Normal
: <input type=radio name=dcf value=stats> Stats
: <input type=radio name=dcf value=dual> Dual
: <input type=radio name=dcf value=none> None
<p>
HTML output lines per file: <input name=line_limit>
<p>
<input type=submit name=submit value=\"Run simulation\">
</form>
";
}
// ?? the actual function doesn't seem to work here
function file_put_contents_aux($fname, $str) {
$f = fopen($fname, "w");
if (!$f) die("fopen");
$x = fwrite($f, $str);
if (!$x) die("fwrite");
fclose($f);
}
if ($_POST['submit']) {
chdir("sim");
if (!file_put_contents("client_state.xml", $_POST['client_state'])) {
echo "Can't write client_state.xml - check permissions\n"; exit();
$x = $_POST['client_state'];
if (!strlen($x)) {
die("missing state");
}
if (!file_put_contents("global_prefs.xml", $_POST['global_prefs'])) {
echo "Can't write global_prefs.xml - check permissions\n"; exit();
$state_fname = tempnam("/tmp", "sim");
file_put_contents_aux($state_fname, $x);
$prefs_name = null;
$config_name = null;
$x = $_POST['global_prefs'];
if (strlen($x)) {
$prefs_fname = tempnam("/tmp", "sim");
file_put_contents_aux($prefs_fname, $x);
}
if (!file_put_contents("cc_config.xml", $_POST['cc_config'])) {
echo "Can't write cc_config.xml - check permissions\n"; exit();
$x = $_POST['cc_config'];
if (strlen($x)) {
$config_fname = tempnam("/tmp", "sim");
file_put_contents_aux($config_fname, $x);
}
$duration = $_POST['duration'];
$delta = $_POST['delta'];
@ -91,31 +103,35 @@ if ($_POST['submit']) {
if ($_POST['rr_only']) {
$rr_only = '--cpu_sched_rr_only';
}
$work_fetch_old = '';
if ($_POST['work_fetch_old']) {
$work_fetch_old = '--work_fetch_old';
}
$dcfflag = "";
$dcf = ($_POST['dcf']);
if ($dcf == "stats") {
$dcfflag = '--dcf_stats';
} else if ($dcf == 'none') {
$dcfflag = '--dcf_dont_use';
} else if ($dcf == 'dual') {
$dcfflag = '--dual_dcf';
}
$timeline_fname = tempnam("/tmp", "sim");
$log_fname = tempnam("/tmp", "sim");
$summary_fname = tempnam("/tmp", "sim");
$llflag = '';
$line_limit = $_POST['line_limit'];
if ($line_limit) {
$llflag = "--line_limit $line_limit";
$cmd = "./sim --duration $duration --delta $delta $suw --state_file $state_fname --timeline_file $timeline_fname --log_file $log_fname --summary_file $summary_fname $rr_only $llflag";
if ($prefs_fname) {
$cmd .= " --prefs_file $prefs_fname";
}
if ($config_fname) {
$cmd .= " --config_file $config_fname";
}
echo "cmd: $cmd\n";
Header("Location: sim/sim_out_0.html");
$cmd = "./sim --duration $duration --delta $delta $suw $dcfflag $rr_only $work_fetch_old $llflag";
system("/bin/rm sim_log.txt sim_out_*.html");
system($cmd);
$x = system($cmd);
echo $x;
readfile($timeline_fname);
echo "\n<pre>\n";
readfile($log_fname);
echo "\n</pre>\n";
readfile($summary_fname);
unlink($state_fname);
unlink($prefs_fname);
unlink($config_fname);
unlink($timeline_fname);
unlink($log_fname);
unlink($summary_fname);
} else {
page_head("BOINC client simulator");
echo "