ChangeSet 1.1159.170.104, 2005/02/17 18:50:24+00:00, sd386@xxxxxxxxxxxxxxxxx
Extended sedf scheduler (weighted extraqueues), added enhanced
scheduling histogramm
common/sched_sedf.c | 258 +++++++++++++++++++++++++++++++++++++++----------
common/schedule.c | 92 ++++++++++++++++-
include/xen/sched-if.h | 11 +-
3 files changed, 302 insertions(+), 59 deletions(-)
diff -Nru a/xen/common/sched_sedf.c b/xen/common/sched_sedf.c
--- a/xen/common/sched_sedf.c 2005-05-09 14:04:09 -04:00
+++ b/xen/common/sched_sedf.c 2005-05-09 14:04:09 -04:00
@@ -13,14 +13,33 @@
#include <xen/time.h>
#include <xen/slab.h>
+//#include <xen/adv_sched_hist.h>
+
#define SEDFLEVEL 2
#define PRINT(_f, _a...) \
if ((_f)<=SEDFLEVEL) printk(_a );
+//various ways of unblocking domains
+#define UNBLOCK_ISOCHRONOUS_EDF 1
+#define UNBLOCK_EDF 2
+#define UNBLOCK_ATROPOS 3
+#define UNBLOCK_SHORT_RESUME 4
+#define UNBLOCK_BURST 5
+
+#define UNBLOCK UNBLOCK_BURST
+
+//various ways of treating extra-time
+#define EXTRA_OFF 1
+#define EXTRA_ROUNDR 2
+#define EXTRA_SLICE_WEIGHT 3
+#define EXTRA_BLOCK_WEIGHT 4
+
+#define EXTRA EXTRA_OFF
+
+
/*
TODO:
TESTING!
- implement stylish features!
tracing instead of PRINTs
*/
@@ -29,15 +48,16 @@
#define EXTRA_NONE (0)
#define EXTRA_AWARE (1)
#define EXTRA_RUNNING (2)
-#define EXTRA_QUANTUM (MICROSECS(1000))
+#define EXTRA_QUANTUM (MICROSECS(500))
#define WEIGHT_PERIOD (MILLISECS(100))
#define WEIGHT_SAFETY (MILLISECS(5))
+
struct sedf_dom_info
{
struct domain *owner;
struct list_head list;
- struct list_head extralist;
+ struct list_head extralist[2];
//Parameters for EDF
s_time_t period; //=(relative deadline)
@@ -50,14 +70,17 @@
s_time_t latency;
//extra-time status of domain
short extra;
- //weights for "Scheduling for Beginners/ Lazy/ etc."
+ //weights for "Scheduling for beginners/ lazy/ etc."
short weight;
//Bookkeeping
s_time_t absdead;
s_time_t sched_start;
s_time_t cputime;
- s_time_t absblock;
+ s_time_t absblock;
+ s_time_t absunblock; //time the domain unblocked,
used by burst mode to determine unblocking intervals
+ int score[2]; //scores for {util, block
penalty}-weighted extratime distribution
+ s_time_t short_block_lost_tot;
//Statistics
s_time_t block_time_tot;
@@ -109,6 +132,37 @@
return (((EXTRALIST(d))->next != NULL) && (EXTRALIST(d)->next !=
EXTRALIST(d)));
}
+/* adds a domain to the queue of processes which are aware of extra time. List
is sorted by score,
+ where a lower score means higher priority for an extra slice. It also
updates the score, by simply subtracting
+ a fixed value from each entry, in order to avoid overflow. The algorithm
works by simply charging each domain
+ that recieved extratime with an inverse of its weight.
+ */
+static inline void extraq_add_sort_update(struct domain *d, unsigned long sub)
{
+ struct list_head *cur;
+ struct sedf_dom_info *curinf;
+
+ PRINT(3,"Adding domain %i (score= %llu) to
extraq\n",d->id,DOM_INFO(d)->score);
+ //iterate through all elements to find our "hole" and on our way update
all the other scores
+ list_for_each(cur,EXTRAQ(d->processor)){
+ curinf = list_entry(cur,struct sedf_dom_info,extralist);
+ curinf->score -= sub;
+ if (DOM_INFO(d)->score < curinf->score)
+ break;
+ else
+ PRINT(4,"\tbehind domain %i (score=
%llu)\n",curinf->owner->id,curinf->score);
+ }
+ //cur now contains the element, before which we'll enqueue
+ PRINT(3,"\tlist_add to %x\n",cur->prev);
+ list_add(EXTRALIST(d),cur->prev);
+
+ //continue updating the extraq
+ if ((cur != EXTRAQ(d->processor)) && sub)
+ for (cur = cur->next; cur != EXTRAQ(d->processor); cur = cur->
next) {
+ curinf = list_entry(cur,struct
sedf_dom_info,extralist);
+ curinf->score -= sub;
+ PRINT(4,"\tupdating domain %i (score=
%llu)\n",curinf->owner->id,curinf->score);
+ }
+}
static inline void extraq_check(struct domain *d) {
if (extraq_on(d)) {
PRINT(2,"Dom %i is on extraQ\n",d->id);
@@ -120,11 +174,10 @@
PRINT(2,"Dom %i is NOT on extraQ\n",d->id);
if (DOM_INFO(d)->extra != EXTRA_NONE) {
PRINT(2,"Added dom %i to extraQ\n",d->id);
- extraq_add_tail(d);
+ extraq_add_sort_update(d, 0);
}
}
}
-
static inline void __del_from_queue(struct domain *d)
{
struct list_head *list = LIST(d);
@@ -277,29 +330,45 @@
int cpu = current->processor;
struct list_head *runq = RUNQ(cpu);
struct list_head *waitq = WAITQ(cpu);
+ #if (EXTRA > EXTRA_OFF)
struct list_head *extraq = EXTRAQ(cpu);
+ #endif
struct list_head *cur,*tmp;
struct sedf_dom_info *curinf;
task_slice_t ret;
-
+ #if (EXTRA == EXTRA_SLICE_WEIGHT)
+ unsigned long oldscore;
+ #endif
//idle tasks don't need any of the following stuf
if (is_idle_task(inf->owner))
goto check_waitq; //idle task
doesn't get scheduled on the runq
-
+
+ #if (EXTRA > EXTRA_OFF)
if (unlikely(inf->extra == EXTRA_RUNNING)) {
//special treatment of domains running in extra time
inf->extra = EXTRA_AWARE;
inf->cputime=0;
inf->extra_time_tot += now - inf->sched_start;
- extraq_del(current); //remove
extradomain from head of the queue
- if (domain_runnable(inf->owner))
- extraq_add_tail(current); //and add to
the tail if it is runnable => round-robin
+ extraq_del(current);
//remove extradomain from head of the queue
+
+ #if (EXTRA == EXTRA_ROUNDR)
+ if (domain_runnable(current))
+ extraq_add_tail(current); //and
add to the tail if it is runnable => round-robin
+ #elif (EXTRA == EXTRA_SLICE_WEIGHT)
+ oldscore = inf->score;
//update the score
+ inf->score = (inf->period << 10) / inf->slice; //use
fixed point arithmetic with 10 bits
+
+ if (domain_runnable(current))
+ extraq_add_sort_update(current, oldscore); //add
according to score: weighted round robin
+ #endif
else
- __del_from_queue(inf->owner); //if domain
blocked in extratime remove it from waitq(/runq) as well
+ __del_from_queue(inf->owner); //if
domain blocked in extratime remove it from waitq(/runq) as well
}
- else {
+ else
+ #endif
+ {
//current domain is running in real time mode
//update the domains cputime
inf->cputime += now - inf->sched_start;
@@ -315,13 +384,18 @@
inf->cputime -= inf->slice;
if (inf->period < inf->period_orig) {
- //this domain runs in latency scaling mode
- inf->period *= 2;
- inf->slice *= 2;
- if ((inf->period > inf->period_orig) ||
(inf->slice > inf->slice_orig)) {
- //now switch back to standard timing
- inf->period = inf->period_orig;
- inf->slice = inf->slice_orig;
+ //this domain runs in latency scaling or burst
mode
+ #if (UNBLOCK == UNBLOCK_BURST)
+ if (now - inf->absunblock >= 2 * inf->period)
+ #endif
+ {
+ inf->period *= 2;
+ inf->slice *= 2;
+ if ((inf->period > inf->period_orig) ||
(inf->slice > inf->slice_orig)) {
+ //now switch back to standard
timing
+ inf->period = inf->period_orig;
+ inf->slice = inf->slice_orig;
+ }
}
}
inf->absdead += inf->period; //set next
deadline
@@ -333,9 +407,11 @@
__add_to_waitqueue_sort(inf->owner);
else {
//we have a blocked realtime task
- inf->absblock=now;
+ inf->absblock = now;
+ #if (EXTRA > EXTRA_OFF)
if (inf->extra == EXTRA_AWARE)
extraq_del(inf->owner); //remove a
blocked domain from the extraq aswell
+ #endif
}
}
check_waitq:
@@ -393,13 +469,16 @@
if (!list_empty(waitq)) {
waitinf = list_entry(waitq->next,struct
sedf_dom_info,list);
//we could not find any suitable domain => look for
domains that are aware of extratime
+ #if (EXTRA > EXTRA_OFF)
if (!list_empty(extraq) && (PERIOD_BEGIN(waitinf) - now
>= EXTRA_QUANTUM)) {
runinf = list_entry(extraq->next,struct
sedf_dom_info,extralist);
runinf->extra = EXTRA_RUNNING;
ret.task = runinf->owner;
ret.time = EXTRA_QUANTUM;
}
- else {
+ else
+ #endif
+ {
//we have an empty run- and extraqueue or too
less time => idle task!
ret.task = IDLETASK(cpu);
ret.time = PERIOD_BEGIN(waitinf) - now;
@@ -420,13 +499,19 @@
static void sedf_sleep(struct domain *d) {
PRINT(2,"sedf_sleep was called, domain-id %i\n",d->id);
- if ( test_bit(DF_RUNNING, &d->flags) )
+ if ( test_bit(DF_RUNNING, &d->flags) ) {
+#ifdef ADV_SCHED_HISTO
+ adv_sched_hist_start(d->processor);
+#endif
cpu_raise_softirq(d->processor, SCHEDULE_SOFTIRQ);
+ }
else {
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|