mirror of https://github.com/BOINC/boinc.git
*** empty log message ***
svn path=/trunk/boinc/; revision=11119
This commit is contained in:
parent
6709910d1c
commit
04ebc6cd30
|
@ -9901,3 +9901,9 @@ David 6 Sept 2006
|
||||||
|
|
||||||
client/
|
client/
|
||||||
client_types.C,h
|
client_types.C,h
|
||||||
|
|
||||||
|
David 6 Sept 2006
|
||||||
|
- added program to test rr_simulation()
|
||||||
|
|
||||||
|
client/
|
||||||
|
rrsim_test.C
|
||||||
|
|
|
@ -0,0 +1,429 @@
|
||||||
|
// This is a test framework for the rr_simulation() function.
|
||||||
|
// To use it:
|
||||||
|
// - cut and paste the current code from cpu_sched.C (see below)
|
||||||
|
// - edit main() to set up your test case
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <cstdarg>
|
||||||
|
|
||||||
|
using std::vector;
|
||||||
|
|
||||||
|
#define CPU_PESSIMISM_FACTOR 1.0
|
||||||
|
#define SECONDS_PER_DAY 86400
|
||||||
|
|
||||||
|
struct RESULT;
|
||||||
|
|
||||||
|
struct PROJECT {
|
||||||
|
char name[256];
|
||||||
|
double resource_share;
|
||||||
|
bool non_cpu_intensive;
|
||||||
|
vector<RESULT*>active;
|
||||||
|
vector<RESULT*>pending;
|
||||||
|
double cpu_shortfall;
|
||||||
|
double rrsim_proc_rate;
|
||||||
|
int rr_sim_deadlines_missed;
|
||||||
|
PROJECT(char* n, double rs) {
|
||||||
|
strcpy(name, n);
|
||||||
|
resource_share = rs;
|
||||||
|
non_cpu_intensive = false;
|
||||||
|
}
|
||||||
|
char* get_project_name() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
void set_rrsim_proc_rate(double);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RESULT {
|
||||||
|
char name[256];
|
||||||
|
double ectr;
|
||||||
|
double estimated_cpu_time_remaining() {
|
||||||
|
return ectr;
|
||||||
|
}
|
||||||
|
double rrsim_finish_delay;
|
||||||
|
double rrsim_cpu_left;
|
||||||
|
double report_deadline;
|
||||||
|
bool rr_sim_misses_deadline;
|
||||||
|
bool last_rr_sim_missed_deadline;
|
||||||
|
PROJECT* project;
|
||||||
|
RESULT(PROJECT* p, char* n, double e, double rd) {
|
||||||
|
project = p;
|
||||||
|
strcpy(name, n);
|
||||||
|
ectr = e;
|
||||||
|
report_deadline = rd;
|
||||||
|
}
|
||||||
|
bool nearly_runnable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
double computation_deadline();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FLAGS {
|
||||||
|
bool rr_simulation;
|
||||||
|
};
|
||||||
|
|
||||||
|
FLAGS log_flags;
|
||||||
|
|
||||||
|
struct PREFS {
|
||||||
|
double work_buf_min_days;
|
||||||
|
double cpu_scheduling_period_minutes;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CLIENT_STATE {
|
||||||
|
double nearly_runnable_resource_share();
|
||||||
|
double total_resource_share();
|
||||||
|
double now;
|
||||||
|
int ncpus;
|
||||||
|
vector<RESULT*>results;
|
||||||
|
vector<PROJECT*>projects;
|
||||||
|
PREFS global_prefs;
|
||||||
|
double cpu_shortfall;
|
||||||
|
double overall_cpu_frac() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
bool rr_simulation();
|
||||||
|
double work_buf_min() {
|
||||||
|
return global_prefs.work_buf_min_days*86400;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CLIENT_STATE gstate;
|
||||||
|
|
||||||
|
double CLIENT_STATE::nearly_runnable_resource_share() {
|
||||||
|
double x=0;
|
||||||
|
for (unsigned int i=0; i<projects.size(); i++) {
|
||||||
|
x += projects[i]->resource_share;
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
double CLIENT_STATE::total_resource_share() {
|
||||||
|
return nearly_runnable_resource_share();
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MSG_INFO 0
|
||||||
|
|
||||||
|
void msg_printf(PROJECT* p, int, const char* fmt, ...) {
|
||||||
|
char buf[8192];
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vsprintf(buf, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
printf("%s: %s\n", p?p->name:"BOINC", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////// CUT AND PASTE FROM CPU_SCHED.C //////////////
|
||||||
|
|
||||||
|
double RESULT::computation_deadline() {
|
||||||
|
return report_deadline - (
|
||||||
|
gstate.global_prefs.work_buf_min_days * SECONDS_PER_DAY
|
||||||
|
// Seconds that the host will not be connected to the Internet
|
||||||
|
+ gstate.global_prefs.cpu_scheduling_period_minutes * 60
|
||||||
|
// Seconds that the CPU may be busy with some other result
|
||||||
|
+ SECONDS_PER_DAY
|
||||||
|
// Deadline cusion
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PROJECT::set_rrsim_proc_rate(double rrs) {
|
||||||
|
int nactive = (int)active.size();
|
||||||
|
if (nactive == 0) return;
|
||||||
|
double x;
|
||||||
|
|
||||||
|
if (rrs) {
|
||||||
|
x = resource_share/rrs;
|
||||||
|
} else {
|
||||||
|
x = 1; // pathological case; maybe should be 1/# runnable projects
|
||||||
|
}
|
||||||
|
|
||||||
|
// if this project has fewer active results than CPUs,
|
||||||
|
// scale up its share to reflect this
|
||||||
|
//
|
||||||
|
if (nactive < gstate.ncpus) {
|
||||||
|
x *= ((double)gstate.ncpus)/nactive;
|
||||||
|
}
|
||||||
|
|
||||||
|
// But its rate on a given CPU can't exceed 1
|
||||||
|
//
|
||||||
|
if (x>1) {
|
||||||
|
x = 1;
|
||||||
|
}
|
||||||
|
rrsim_proc_rate = x*gstate.overall_cpu_frac();
|
||||||
|
if (log_flags.rr_simulation) {
|
||||||
|
msg_printf(this, MSG_INFO,
|
||||||
|
"set_rrsim_proc_rate: %f (rrs %f, rs %f, nactive %d, ocf %f",
|
||||||
|
rrsim_proc_rate, rrs, resource_share, nactive, gstate.overall_cpu_frac()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool CLIENT_STATE::rr_simulation() {
|
||||||
|
double rrs = nearly_runnable_resource_share();
|
||||||
|
double trs = total_resource_share();
|
||||||
|
PROJECT* p, *pbest;
|
||||||
|
RESULT* rp, *rpbest;
|
||||||
|
vector<RESULT*> active;
|
||||||
|
unsigned int i;
|
||||||
|
double x;
|
||||||
|
vector<RESULT*>::iterator it;
|
||||||
|
bool rval = false;
|
||||||
|
|
||||||
|
if (log_flags.rr_simulation) {
|
||||||
|
msg_printf(0, MSG_INFO,
|
||||||
|
"rr_sim start: work_buf_min %f rrs %f trs %f",
|
||||||
|
work_buf_min(), rrs, trs
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize result lists for each project:
|
||||||
|
// "active" is what's currently running (in the simulation)
|
||||||
|
// "pending" is what's queued
|
||||||
|
//
|
||||||
|
for (i=0; i<projects.size(); i++) {
|
||||||
|
p = projects[i];
|
||||||
|
p->active.clear();
|
||||||
|
p->pending.clear();
|
||||||
|
p->rr_sim_deadlines_missed = 0;
|
||||||
|
p->cpu_shortfall = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0; i<results.size(); i++) {
|
||||||
|
rp = results[i];
|
||||||
|
if (!rp->nearly_runnable()) continue;
|
||||||
|
if (rp->project->non_cpu_intensive) continue;
|
||||||
|
rp->rrsim_cpu_left = rp->estimated_cpu_time_remaining();
|
||||||
|
p = rp->project;
|
||||||
|
if (p->active.size() < (unsigned int)ncpus) {
|
||||||
|
active.push_back(rp);
|
||||||
|
p->active.push_back(rp);
|
||||||
|
} else {
|
||||||
|
p->pending.push_back(rp);
|
||||||
|
}
|
||||||
|
rp->last_rr_sim_missed_deadline = rp->rr_sim_misses_deadline;
|
||||||
|
rp->rr_sim_misses_deadline = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0; i<projects.size(); i++) {
|
||||||
|
p = projects[i];
|
||||||
|
p->set_rrsim_proc_rate(rrs);
|
||||||
|
// if there are no results for a project,
|
||||||
|
// the shortfall is its entire share.
|
||||||
|
//
|
||||||
|
if (!p->active.size()) {
|
||||||
|
double rsf = trs ? p->resource_share/trs : 1;
|
||||||
|
p->cpu_shortfall = work_buf_min() * overall_cpu_frac() * ncpus * rsf;
|
||||||
|
if (log_flags.rr_simulation) {
|
||||||
|
msg_printf(p, MSG_INFO,
|
||||||
|
"no results; shortfall %f wbm %f ocf %f rsf %f",
|
||||||
|
p->cpu_shortfall, work_buf_min(), overall_cpu_frac(), rsf
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double buf_end = now + work_buf_min();
|
||||||
|
|
||||||
|
// Simulation loop. Keep going until work done
|
||||||
|
//
|
||||||
|
double sim_now = now;
|
||||||
|
cpu_shortfall = 0;
|
||||||
|
while (active.size()) {
|
||||||
|
|
||||||
|
// compute finish times and see which result finishes first
|
||||||
|
//
|
||||||
|
rpbest = NULL;
|
||||||
|
for (i=0; i<active.size(); i++) {
|
||||||
|
rp = active[i];
|
||||||
|
p = rp->project;
|
||||||
|
rp->rrsim_finish_delay = rp->rrsim_cpu_left/p->rrsim_proc_rate;
|
||||||
|
if (!rpbest || rp->rrsim_finish_delay < rpbest->rrsim_finish_delay) {
|
||||||
|
rpbest = rp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pbest = rpbest->project;
|
||||||
|
|
||||||
|
if (log_flags.rr_simulation) {
|
||||||
|
msg_printf(pbest, MSG_INFO,
|
||||||
|
"rr_sim: result %s finishes after %f (%f/%f)",
|
||||||
|
rpbest->name, rpbest->rrsim_finish_delay, rpbest->rrsim_cpu_left, pbest->rrsim_proc_rate
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// "rpbest" is first result to finish. Does it miss its deadline?
|
||||||
|
//
|
||||||
|
double diff = sim_now + rpbest->rrsim_finish_delay - ((rpbest->computation_deadline()-now)*CPU_PESSIMISM_FACTOR + now);
|
||||||
|
if (diff > 0) {
|
||||||
|
rpbest->rr_sim_misses_deadline = true;
|
||||||
|
pbest->rr_sim_deadlines_missed++;
|
||||||
|
rval = true;
|
||||||
|
if (log_flags.rr_simulation) {
|
||||||
|
msg_printf(0, MSG_INFO,
|
||||||
|
"rr_sim: result %s misses deadline by %f",
|
||||||
|
rpbest->name, diff
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int last_active_size = active.size();
|
||||||
|
int last_proj_active_size = pbest->active.size();
|
||||||
|
|
||||||
|
// remove *rpbest from active set,
|
||||||
|
// and adjust CPU time left for other results
|
||||||
|
//
|
||||||
|
it = active.begin();
|
||||||
|
while (it != active.end()) {
|
||||||
|
rp = *it;
|
||||||
|
if (rp == rpbest) {
|
||||||
|
it = active.erase(it);
|
||||||
|
} else {
|
||||||
|
x = rp->project->rrsim_proc_rate*rpbest->rrsim_finish_delay;
|
||||||
|
rp->rrsim_cpu_left -= x;
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove *rpbest from its project's active set
|
||||||
|
//
|
||||||
|
it = pbest->active.begin();
|
||||||
|
while (it != pbest->active.end()) {
|
||||||
|
rp = *it;
|
||||||
|
if (rp == rpbest) {
|
||||||
|
it = pbest->active.erase(it);
|
||||||
|
} else {
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If project has more results, add one to active set.
|
||||||
|
//
|
||||||
|
if (pbest->pending.size()) {
|
||||||
|
rp = pbest->pending[0];
|
||||||
|
pbest->pending.erase(pbest->pending.begin());
|
||||||
|
active.push_back(rp);
|
||||||
|
pbest->active.push_back(rp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If all work done for a project, subtract that project's share
|
||||||
|
// and recompute processing rates
|
||||||
|
//
|
||||||
|
if (pbest->active.size() == 0) {
|
||||||
|
rrs -= pbest->resource_share;
|
||||||
|
if (log_flags.rr_simulation) {
|
||||||
|
msg_printf(pbest, MSG_INFO,
|
||||||
|
"rr_sim: decr rrs by %f, new value %f",
|
||||||
|
pbest->resource_share, rrs
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for (i=0; i<projects.size(); i++) {
|
||||||
|
p = projects[i];
|
||||||
|
p->set_rrsim_proc_rate(rrs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// increment CPU shortfalls if necessary
|
||||||
|
//
|
||||||
|
if (sim_now < buf_end) {
|
||||||
|
double end_time = sim_now + rpbest->rrsim_finish_delay;
|
||||||
|
if (end_time > buf_end) end_time = buf_end;
|
||||||
|
double d_time = end_time - sim_now;
|
||||||
|
int nidle_cpus = ncpus - last_active_size;
|
||||||
|
if (nidle_cpus<0) nidle_cpus = 0;
|
||||||
|
if (nidle_cpus > 0) cpu_shortfall += d_time*nidle_cpus;
|
||||||
|
|
||||||
|
double rsf = trs?pbest->resource_share/trs:1;
|
||||||
|
double proj_cpu_share = ncpus*rsf;
|
||||||
|
|
||||||
|
if (last_proj_active_size < proj_cpu_share) {
|
||||||
|
pbest->cpu_shortfall += d_time*(proj_cpu_share - last_proj_active_size);
|
||||||
|
if (log_flags.rr_simulation) {
|
||||||
|
msg_printf(pbest, MSG_INFO,
|
||||||
|
"rr_sim: new shortfall %f d_time %f proj_cpu_share %f lpas %d",
|
||||||
|
pbest->cpu_shortfall, d_time, proj_cpu_share, last_proj_active_size
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end_time < buf_end) {
|
||||||
|
d_time = buf_end - end_time;
|
||||||
|
// if this is the last result for this project, account for the tail
|
||||||
|
if (!pbest->active.size()) {
|
||||||
|
pbest->cpu_shortfall += d_time * proj_cpu_share;
|
||||||
|
if (log_flags.rr_simulation) {
|
||||||
|
msg_printf(pbest, MSG_INFO, "rr_sim proj out of work; shortfall %f d %f pcs %f",
|
||||||
|
pbest->cpu_shortfall, d_time, proj_cpu_share
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (log_flags.rr_simulation) {
|
||||||
|
msg_printf(0, MSG_INFO,
|
||||||
|
"rr_sim total: idle cpus %d, last active %d, active %d, shortfall %f",
|
||||||
|
nidle_cpus, last_active_size, (int)active.size(), cpu_shortfall
|
||||||
|
|
||||||
|
);
|
||||||
|
msg_printf(0, MSG_INFO,
|
||||||
|
"rr_sim proj %s: last active %d, active %d, shortfall %f",
|
||||||
|
pbest->get_project_name(), last_proj_active_size, (int)pbest->active.size(),
|
||||||
|
pbest->cpu_shortfall
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sim_now += rpbest->rrsim_finish_delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sim_now < buf_end) {
|
||||||
|
cpu_shortfall += (buf_end - sim_now) * ncpus;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (log_flags.rr_simulation) {
|
||||||
|
for (i=0; i<projects.size(); i++) {
|
||||||
|
p = projects[i];
|
||||||
|
if (p->cpu_shortfall) {
|
||||||
|
msg_printf(p, MSG_INFO,
|
||||||
|
"rr_sim: shortfall %f\n", p->cpu_shortfall
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
msg_printf(NULL, MSG_INFO,
|
||||||
|
"rr_simulation: end; returning %s; total shortfall %f\n",
|
||||||
|
rval?"true":"false",
|
||||||
|
cpu_shortfall
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////// END CUT AND PASTE ////////////////
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
PROJECT* p;
|
||||||
|
RESULT* r;
|
||||||
|
log_flags.rr_simulation = true;
|
||||||
|
|
||||||
|
gstate.global_prefs.work_buf_min_days = 1;
|
||||||
|
gstate.global_prefs.cpu_scheduling_period_minutes = 60;
|
||||||
|
gstate.ncpus = 1;
|
||||||
|
gstate.now = 0;
|
||||||
|
|
||||||
|
p = new PROJECT("project A", 33.);
|
||||||
|
gstate.projects.push_back(p);
|
||||||
|
|
||||||
|
r = new RESULT(p, "result 1", 9, 1e6);
|
||||||
|
gstate.results.push_back(r);
|
||||||
|
r = new RESULT(p, "result 2", 9, 1e6);
|
||||||
|
gstate.results.push_back(r);
|
||||||
|
r = new RESULT(p, "result 3", 9, 1e6);
|
||||||
|
gstate.results.push_back(r);
|
||||||
|
|
||||||
|
p = new PROJECT("project B", 33.);
|
||||||
|
gstate.projects.push_back(p);
|
||||||
|
r = new RESULT(p, "result 4", 20, 1e6);
|
||||||
|
gstate.results.push_back(r);
|
||||||
|
|
||||||
|
p = new PROJECT("project C", 33.);
|
||||||
|
gstate.projects.push_back(p);
|
||||||
|
r = new RESULT(p, "result 5", 30, 1e6);
|
||||||
|
gstate.results.push_back(r);
|
||||||
|
|
||||||
|
gstate.rr_simulation();
|
||||||
|
}
|
Loading…
Reference in New Issue