# HG changeset patch
# User Emmanuel Ackaouy <ack@xxxxxxxxxxxxx>
# Node ID 360eb996fa38319867a74bf581c734a80bf6839d
# Parent c79f9d7882046074d30f58f769aadce5950357d9
[XEN] Improve scheduler cap mechanism
Somewhat unbastardize the scheduler cap mechanism. We now cleanly
pause and unpause running VCPUs of capped out domains instead of
using sub-idle priorities. This also improves the precision of
caps a bit.
Signed-off-by: Emmanuel Ackaouy <ack@xxxxxxxxxxxxx>
---
xen/common/domain.c | 19 +++++++++---
xen/common/sched_credit.c | 71 +++++++++++++++++++++++++++++++++-------------
xen/include/xen/sched.h | 1
3 files changed, 67 insertions(+), 24 deletions(-)
diff -r c79f9d788204 -r 360eb996fa38 xen/common/domain.c
--- a/xen/common/domain.c Wed Dec 13 10:20:20 2006 -0500
+++ b/xen/common/domain.c Wed Dec 13 16:13:26 2006 +0000
@@ -350,16 +350,25 @@ void domain_destroy(struct domain *d)
send_guest_global_virq(dom0, VIRQ_DOM_EXC);
}
-void vcpu_pause(struct vcpu *v)
-{
- ASSERT(v != current);
-
+static void vcpu_pause_setup(struct vcpu *v)
+{
spin_lock(&v->pause_lock);
if ( v->pause_count++ == 0 )
set_bit(_VCPUF_paused, &v->vcpu_flags);
spin_unlock(&v->pause_lock);
-
+}
+
+void vcpu_pause(struct vcpu *v)
+{
+ ASSERT(v != current);
+ vcpu_pause_setup(v);
vcpu_sleep_sync(v);
+}
+
+void vcpu_pause_nosync(struct vcpu *v)
+{
+ vcpu_pause_setup(v);
+ vcpu_sleep_nosync(v);
}
void vcpu_unpause(struct vcpu *v)
diff -r c79f9d788204 -r 360eb996fa38 xen/common/sched_credit.c
--- a/xen/common/sched_credit.c Wed Dec 13 10:20:20 2006 -0500
+++ b/xen/common/sched_credit.c Wed Dec 13 16:13:26 2006 +0000
@@ -56,7 +56,12 @@
#define CSCHED_PRI_TS_UNDER -1 /* time-share w/ credits */
#define CSCHED_PRI_TS_OVER -2 /* time-share w/o credits */
#define CSCHED_PRI_IDLE -64 /* idle */
-#define CSCHED_PRI_TS_PARKED -65 /* time-share w/ capped credits */
+
+
+/*
+ * Flags
+ */
+#define CSCHED_FLAG_VCPU_PARKED 0x0001 /* VCPU over capped credits */
/*
@@ -100,6 +105,8 @@
_MACRO(vcpu_wake_onrunq) \
_MACRO(vcpu_wake_runnable) \
_MACRO(vcpu_wake_not_runnable) \
+ _MACRO(vcpu_park) \
+ _MACRO(vcpu_unpark) \
_MACRO(tickle_local_idler) \
_MACRO(tickle_local_over) \
_MACRO(tickle_local_under) \
@@ -190,6 +197,7 @@ struct csched_vcpu {
struct csched_dom *sdom;
struct vcpu *vcpu;
atomic_t credit;
+ uint16_t flags;
int16_t pri;
#ifdef CSCHED_STATS
struct {
@@ -579,12 +587,11 @@ csched_vcpu_init(struct vcpu *vc)
svc->sdom = sdom;
svc->vcpu = vc;
atomic_set(&svc->credit, 0);
+ svc->flags = 0U;
svc->pri = is_idle_domain(dom) ? CSCHED_PRI_IDLE : CSCHED_PRI_TS_UNDER;
CSCHED_VCPU_STATS_RESET(svc);
vc->sched_priv = svc;
- CSCHED_VCPU_CHECK(vc);
-
/* Allocate per-PCPU info */
if ( unlikely(!CSCHED_PCPU(vc->processor)) )
{
@@ -593,7 +600,6 @@ csched_vcpu_init(struct vcpu *vc)
}
CSCHED_VCPU_CHECK(vc);
-
return 0;
}
@@ -673,9 +679,16 @@ csched_vcpu_wake(struct vcpu *vc)
* This allows wake-to-run latency sensitive VCPUs to preempt
* more CPU resource intensive VCPUs without impacting overall
* system fairness.
- */
- if ( svc->pri == CSCHED_PRI_TS_UNDER )
+ *
+ * The one exception is for VCPUs of capped domains unpausing
+ * after earning credits they had overspent. We don't boost
+ * those.
+ */
+ if ( svc->pri == CSCHED_PRI_TS_UNDER &&
+ !(svc->flags & CSCHED_FLAG_VCPU_PARKED) )
+ {
svc->pri = CSCHED_PRI_TS_BOOST;
+ }
/* Put the VCPU on the runq and tickle CPUs */
__runq_insert(cpu, svc);
@@ -749,11 +762,8 @@ static void
static void
csched_dom_destroy(struct domain *dom)
{
- struct csched_dom * const sdom = CSCHED_DOM(dom);
-
CSCHED_STAT_CRANK(dom_destroy);
-
- xfree(sdom);
+ xfree(CSCHED_DOM(dom));
}
/*
@@ -942,11 +952,19 @@ csched_acct(void)
*/
if ( credit < 0 )
{
- if ( sdom->cap != 0U && credit < -credit_cap )
- svc->pri = CSCHED_PRI_TS_PARKED;
- else
- svc->pri = CSCHED_PRI_TS_OVER;
-
+ svc->pri = CSCHED_PRI_TS_OVER;
+
+ /* Park running VCPUs of capped-out domains */
+ if ( sdom->cap != 0U &&
+ credit < -credit_cap &&
+ !(svc->flags & CSCHED_FLAG_VCPU_PARKED) )
+ {
+ CSCHED_STAT_CRANK(vcpu_park);
+ vcpu_pause_nosync(svc->vcpu);
+ svc->flags |= CSCHED_FLAG_VCPU_PARKED;
+ }
+
+ /* Lower bound on credits */
if ( credit < -CSCHED_CREDITS_PER_TSLICE )
{
CSCHED_STAT_CRANK(acct_min_credit);
@@ -958,6 +976,20 @@ csched_acct(void)
{
svc->pri = CSCHED_PRI_TS_UNDER;
+ /* Unpark any capped domains whose credits go positive */
+ if ( svc->flags & CSCHED_FLAG_VCPU_PARKED)
+ {
+ /*
+ * It's important to unset the flag AFTER the unpause()
+ * call to make sure the VCPU's priority is not boosted
+ * if it is woken up here.
+ */
+ CSCHED_STAT_CRANK(vcpu_unpark);
+ vcpu_unpause(svc->vcpu);
+ svc->flags &= ~CSCHED_FLAG_VCPU_PARKED;
+ }
+
+ /* Upper bound on credits means VCPU stops earning */
if ( credit > CSCHED_CREDITS_PER_TSLICE )
{
__csched_vcpu_acct_stop_locked(svc);
@@ -1031,10 +1063,10 @@ csched_runq_steal(int peer_cpu, int cpu,
speer = __runq_elem(iter);
/*
- * If next available VCPU here is not of higher priority
- * than ours, this PCPU is useless to us.
+ * If next available VCPU here is not of strictly higher
+ * priority than ours, this PCPU is useless to us.
*/
- if ( speer->pri <= CSCHED_PRI_IDLE || speer->pri <= pri )
+ if ( speer->pri <= pri )
break;
/* Is this VCPU is runnable on our PCPU? */
@@ -1181,10 +1213,11 @@ csched_dump_vcpu(struct csched_vcpu *svc
{
struct csched_dom * const sdom = svc->sdom;
- printk("[%i.%i] pri=%i cpu=%i",
+ printk("[%i.%i] pri=%i flags=%x cpu=%i",
svc->vcpu->domain->domain_id,
svc->vcpu->vcpu_id,
svc->pri,
+ svc->flags,
svc->vcpu->processor);
if ( sdom )
diff -r c79f9d788204 -r 360eb996fa38 xen/include/xen/sched.h
--- a/xen/include/xen/sched.h Wed Dec 13 10:20:20 2006 -0500
+++ b/xen/include/xen/sched.h Wed Dec 13 16:13:26 2006 +0000
@@ -437,6 +437,7 @@ static inline int vcpu_runnable(struct v
}
void vcpu_pause(struct vcpu *v);
+void vcpu_pause_nosync(struct vcpu *v);
void domain_pause(struct domain *d);
void vcpu_unpause(struct vcpu *v);
void domain_unpause(struct domain *d);
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|