.
// web interface to client simulator
//
// to use this, symlink to it from the html/user dir of a BOINC project,
// create an apache-writable dir called "scenarios" there,
// and symlink from html/inc to sim_util.inc
require_once("../inc/util.inc");
require_once("../inc/sim_util.inc");
ini_set ("memory_limit", "1G");
set_time_limit(0);
function get_comments($dir) {
$d = "$dir/comments";
if (!is_dir($d)) return null;
$dd = opendir($d);
$x = "";
while (false !== ($f = readdir($dd))) {
if ($f == ".") continue;
if ($f == "..") continue;
if (strlen($x)) $x .= "
\n";
$userid = (int)file_get_contents("$d/$f/userid");
$user = BoincUser::lookup_id($userid);
$comment = file_get_contents("$d/$f/comment");
$date = date_str(filemtime("$d/$f/comment"));
$x .= "By $user->name ($date): $comment\n";
}
return $x;
}
function nsims($scen) {
$d = opendir("scenarios/$scen/simulations");
$n = 0;
while (false !== ($f = readdir($d))) {
if ($f == ".") continue;
if ($f == "..") continue;
$n++;
}
return $n;
}
function show_scenario_summary($f) {
$desc = file_get_contents("scenarios/$f/description");
$userid = (int)file_get_contents("scenarios/$f/userid");
$user = BoincUser::lookup_id($userid);
$date = date_str(filemtime("scenarios/$f"));
$nsims = nsims($f);
echo "
$f
$user->name
$date
$nsims
$desc
";
}
// show existing scenarios, "create scenario" button
//
function show_scenarios() {
page_head("The BOINC Client Emulator");
echo "
The BOINC Client Emulator (BCE)
emulates a BOINC client attached to one or more projects.
It predicts, in a few seconds,
what the latest BOINC client will do over a period of day or months.
By reporting problem situations to BOINC developers,
you can help us fix bugs and improve performance.
Scenarios
The inputs to BCE, called scenarios ,
describe a particular computer and the project to which it's attached.
A scenario consists of:
client_state.xml : describes the host and projects.
Any projects that don't currently have tasks are ignored.
global_prefs.xml and global_prefs_override.xml :
computing preferences (optional).
cc_config.xml : options such as GPU exclusions
You create a scenario by uploading these files
using the Create a scenario button below.
You can use the files from a running BOINC client
to emulate that client.
You can modify these files, or create new ones,
to study hypothetical scenarios
(e.g. hosts with a large number of CPUs,
hosts attached to a large number of projects,
projects with very short or long jobs, and so on).
See The
BCE documentation for details.
Simulations
You can run simulations based on existing scenarios
(including scenarios created by other people).
The parameters of a simulation include
The duration and time resolution of the simulation.
Log flags
The outputs of a simulation include
A 'time line' showing CPU and GPU usage.
The client's message log
graphs of scheduling-related data (REC).
A summary of several figures of merit , including
idle fraction: the fraction of processing power that was unused
wasted fraction: the fraction of processing power
that was 'wasted' on jobs that missed their deadline
resource share violation: a measure [0..1] of the extent
to which resource shares were disobeyed.
monotony: a measure [0..1] of the extent to which
the client ran jobs of a single project for long periods
Comments and reports
When you examine the results of a simulation,
you may find places where the BOINC client
made bad scheduling or work-fetch decisions.
Or you find may places where the simulator doesn't
seem to be working correctly.
In such cases, please add a comment to the simulation,
indicating the nature of the problem
and the simulation time when it occurred.
Please post to the boinc_dev email list if
a simulation reveals a bug or bad scheduling decision
you have problems using BCE
BCE doesn't do more or less the same thing as your client
you have suggestions for new features.
";
show_button(
"sim_web.php?action=create_scenario_form",
"Create a scenario", "Create a new scenario"
);
echo "
Existing scenarios
";
start_table();
echo "
IDClick to see simulations
Who
When
# Simulations
Description
";
$d = opendir("scenarios");
$dirs = array();
while (false !== ($f = readdir($d))) {
if ($f === ".") continue;
if ($f === "..") continue;
$dirs[] = $f;
}
rsort($dirs);
foreach ($dirs as $f) {
show_scenario_summary($f);
}
echo "\n";
page_tail();
}
// show form for creating a scenario
//
function create_scenario_form() {
get_logged_in_user();
page_head("Create a scenario");
echo "
To create a scenario:
choose the input files,
enter a short description, and click OK
(items with * are required).
";
page_tail();
}
// create a subdir $dir/N for the first available N
//
function create_dir_seqno($dir) {
$i = -1;
$d = opendir($dir);
while (false !== ($f = readdir($d))) {
$j = -1;
$n = sscanf($f, "%d", $j);
if ($n == 1 && $j >= 0) {
if ($j > $i) {
$i = $j;
}
}
}
$i++;
$p = "$dir/$i";
mkdir($p);
return "$i";
}
// choose scenario name
// create dir, put files there
// create meta-data file
// redirect to show scenario
//
function create_scenario() {
$user = get_logged_in_user();
$csname = $_FILES['client_state']['tmp_name'];
if (!is_uploaded_file($csname)) {
error_page("You must specify a client_state.xml file.");
}
$desc = post_str("description", true);
if (!strlen($desc)) {
error_page("You must supply a description.");
}
$desc = strip_tags($desc);
$sname = create_dir_seqno("scenarios");
$d = "scenarios/$sname";
move_uploaded_file($csname, "$d/client_state.xml");
$gp = $_FILES['global_prefs']['tmp_name'];
if (is_uploaded_file($gp)) {
move_uploaded_file($gp, "$d/global_prefs.xml");
}
$gpo = $_FILES['global_prefs_override']['tmp_name'];
if (is_uploaded_file($gpo)) {
move_uploaded_file($gpo, "$d/global_prefs_override.xml");
}
$ccc = $_FILES['cc_config']['tmp_name'];
if (is_uploaded_file($ccc)) {
move_uploaded_file($ccc, "$d/cc_config.xml");
}
file_put_contents("$d/userid", "$user->id");
file_put_contents("$d/description", $desc);
mkdir("$d/simulations");
header("Location: sim_web.php?action=show_scenario&name=$sname");
}
function show_simulation_summary($scen, $sim) {
$dir = "scenarios/$scen/simulations/$sim";
$userid = (int)file_get_contents("$dir/userid");
$user = BoincUser::lookup_id($userid);
$date = date_str(filemtime($dir));
echo "
$sim
$user->name
$date
".file_get_contents("$dir/inputs.txt")."
".file_get_contents("$dir/results.txt")."
".get_comments($dir)."
";
}
// show:
// links to files
// list of existing simulations
// link for new simulation
//
function show_scenario() {
$name = get_str("name");
$d = "scenarios/$name";
if (!is_dir($d)) {
error_page("No such scenario");
}
page_head("Scenario $name");
$desc = file_get_contents("scenarios/$name/description");
$userid = (int)file_get_contents("scenarios/$name/userid");
$user = BoincUser::lookup_id($userid);
$date = date_str(filemtime("scenarios/$name"));
start_table();
row2("Creator", $user->name);
row2("When", $date);
row2("Description", $desc);
$x = "client_state.xml ";
if (file_exists("$d/global_prefs.xml")) {
$x .= "global_prefs.xml \n";
}
if (file_exists("$d/global_prefs_override.xml")) {
$x .= "global_prefs_override.xml \n";
}
if (file_exists("$d/cc_config.xml")) {
$x .= "cc_config.xml \n";
}
row2("Input files", $x);
end_table();
show_button("sim_web.php?action=simulation_form&scen=$name",
"Do new simulation",
"Do new simulation"
);
echo "Simulations ";
start_table();
echo "
IDClick for details
Who
When
Parameters
Results
Comments
";
$dirs = array();
$s = opendir("$d/simulations");
while (false !== ($f = readdir($s))) {
if (!is_numeric($f)) continue;
$dirs[] = $f;
}
rsort($dirs);
foreach ($dirs as $f) {
show_simulation_summary($name, $f);
}
end_table();
page_tail();
}
function log_flag_boxes() {
return "
CPU scheduling debug
Round-robin simulation info
Round-robin simulation details
Work fetch debug
";
}
function simulation_form() {
$scen = get_str("scen");
$detail = get_str("detail", true);
page_head("Do simulation");
start_table();
echo "
";
row2("Duration", " seconds");
row2("Time step", " seconds");
if ($detail) {
row2("Half life of average-credit decay",
" days"
);
row2("Existing jobs only?
If checked, simulate only the
jobs in the client state file.
Otherwise, simulate an infinite stream of jobs
modeled after those in the state file.",
" "
);
row2("Scheduler does detailed deadline check?
If checked, the scheduler's deadline
decisions will use a detailed EDF simulation
rather than an approximation. ",
" "
);
row2("Client uses pure Round-robin?
If checked, job scheduling will
use a simple round-robin policy. ",
" "
);
row2("Include projects without apps",
" "
);
} else {
row2("", "More options ");
}
row2("Log flags", log_flag_boxes());
row2("", " ");
echo " \n";
end_table();
page_tail();
}
// create directory for simulation,
// run simulation,
// redirect to simulation page
//
function simulation_action() {
$user = get_logged_in_user();
$scen = post_str("scen");
if (!is_dir("scenarios/$scen")) {
error_page("no such scenario");
}
$sim_dir = "scenarios/$scen/simulations";
$sim_name = create_dir_seqno($sim_dir);
$sim_path = "$sim_dir/$sim_name";
$policy = new POLICY("");
$policy->duration = (double)post_str("duration");
$policy->delta = (double)post_str("delta");
$policy->rec_half_life = (double)post_str("rec_half_life_days")*86400;
$policy->existing_jobs_only = post_str("existing_jobs_only", true);
$policy->cpu_sched_rr_only = post_str("cpu_sched_rr_only", true);
$policy->include_empty_projects = post_str("include_empty_projects", true);
$policy->server_uses_workload = post_str("server_uses_workload", true);
file_put_contents("$sim_path/userid", "$user->id");
$x = "\n";
if (post_str("cpu_sched_debug", true)) {
$x .= " \n";
}
if (post_str("rr_simulation", true)) {
$x .= " \n";
}
if (post_str("rrsim_detail", true)) {
$x .= " \n";
}
if (post_str("work_fetch_debug", true)) {
$x .= " \n";
}
$x .= " \n";
file_put_contents("$sim_path/log_flags.xml", $x);
do_sim("scenarios/$scen", $sim_path, $policy);
header("Location: sim_web.php?action=show_simulation&scen=$scen&sim=$sim_name");
}
// show links to files in simulation directory
//
function show_simulation() {
$scen = get_str("scen");
$sim = get_str("sim");
$dir = "scenarios/$scen/simulations/$sim";
if (!is_dir($dir)) {
error_page("No such simulation");
}
page_head("Simulation $sim");
start_table();
$userid = (int)file_get_contents("$dir/userid");
$user = BoincUser::lookup_id($userid);
$date = date_str(filemtime($dir));
row2("Scenario", "$scen ");
row2("Who", $user->name);
row2("When", $date);
row2("Parameters", "".file_get_contents("$dir/inputs.txt")." ");
row2("Results", "".file_get_contents("$dir/results.txt")." ");
$x = file_get_contents("$dir/index.html");
$x = str_replace("Output files ", "", $x);
$x = str_replace("href=", "href=scenarios/$scen/simulations/$sim/", $x);
row2("Output files", $x);
$x = get_comments($dir);
if ($x) {
row2("Comments", $x);
}
echo "
";
row2(" ",
" "
);
echo " ";
end_table();
page_tail();
}
function add_comment() {
$user = get_logged_in_user();
$scen = get_str("scen");
$sim = get_str("sim");
$dir = "scenarios/$scen/simulations/$sim";
if (!is_dir($dir)) {
error_page("No such simulation");
}
$cdir = "$dir/comments";
@mkdir($cdir);
$c = create_dir_seqno($cdir);
$p = "$cdir/$c";
file_put_contents("$p/userid", "$user->id");
file_put_contents("$p/comment", get_str("comment"));
header("Location: sim_web.php?action=show_simulation&scen=$scen&sim=$sim");
}
$action = get_str("action", true);
if (!$action) $action = post_str("action", true);
switch ($action) {
case "create_scenario_form":
create_scenario_form();
break;
case "create_scenario":
create_scenario();
break;
case "show_scenario":
show_scenario();
break;
case "simulation_form":
simulation_form();
break;
case "simulation_action":
simulation_action();
break;
case "show_simulation":
show_simulation();
break;
case "add_comment":
add_comment();
break;
case null:
show_scenarios();
break;
default:
die("unknown action $action");
}
?>