struct {
unsigned int vcpuid:16, domid:16;
int credit_start, credit_end;
- unsigned int multiplier;
} *r = (typeof(r))ri->d;
printf(" %s csched2:reset_credits d%uv%u, "
- "credit_start = %d, credit_end = %d, mult = %u\n",
+ "credit_start = %d, credit_end = %d\n",
ri->dump_header, r->domid, r->vcpuid,
- r->credit_start, r->credit_end, r->multiplier);
+ r->credit_start, r->credit_end);
}
break;
case TRC_SCHED_CLASS_EVT(CSCHED2, 8): /* SCHED_TASKLET */
* before a reset event.
*/
#define CSCHED2_CREDIT_INIT MILLISECS(10)
+/*
+ * Minimum amount of credits VMs can have. Ideally, no VM would get
+ * close to this (unless a vCPU manages to execute for really long
+ * time uninterrupted). In case it happens, it makes no sense to
+ * track even deeper undershoots.
+ *
+ * NOTE: If making this smaller than -CSCHED2_CREDIT_INIT, adjust
+ * reset_credit() accordingly.
+ */
+#define CSCHED2_CREDIT_MIN (-CSCHED2_CREDIT_INIT)
/*
* Amount of credit the idle units have. It never changes, as idle
* units does not consume credits, and it must be lower than whatever
* amount of credit 'regular' unit would end up with.
*/
-#define CSCHED2_IDLE_CREDIT (-(1U<<30))
+#define CSCHED2_IDLE_CREDIT (CSCHED2_CREDIT_MIN-1)
/*
* Carryover: How much "extra" credit may be carried over after
* a reset.
static void t2c_update(const struct csched2_runqueue_data *rqd, s_time_t time,
struct csched2_unit *svc)
{
- uint64_t val = time * rqd->max_weight + svc->residual;
+ int64_t val = time * rqd->max_weight + svc->residual;
svc->residual = do_div(val, svc->weight);
- svc->credit -= val;
+ /* Getting to lower credit than CSCHED2_CREDIT_MIN makes no sense. */
+ val = svc->credit - val;
+ if ( unlikely(val < CSCHED2_CREDIT_MIN) )
+ svc->credit = CSCHED2_CREDIT_MIN;
+ else
+ svc->credit = val;
}
static s_time_t c2t(const struct csched2_runqueue_data *rqd, s_time_t credit,
{
struct csched2_runqueue_data *rqd = c2rqd(cpu);
struct list_head *iter;
- int m;
+ int reset = CSCHED2_CREDIT_INIT;
/*
* Under normal circumstances, snext->credit should never be less
* than -CSCHED2_MIN_TIMER. However, under some circumstances, an
* unit with low credits may be allowed to run long enough that
- * its credits are actually less than -CSCHED2_CREDIT_INIT.
+ * its credits are actually much lower than that.
* (Instances have been observed, for example, where an unit with
* 200us of credit was allowed to run for 11ms, giving it -10.8ms
* of credit. Thus it was still negative even after the reset.)
*
* If this is the case for snext, we simply want to keep moving
- * everyone up until it is in the black again. This fair because
- * none of the other units want to run at the moment.
- *
- * Rather than looping, however, we just calculate a multiplier,
- * avoiding an integer division and multiplication in the common
- * case.
+ * everyone up until it is in the black again. This means that,
+ * since CSCHED2_CREDIT_MIN is -CSCHED2_CREDIT_INIT, we need to
+ * actually add 2*CSCHED2_CREDIT_INIT.
*/
- m = 1;
- if ( snext->credit < -CSCHED2_CREDIT_INIT )
- m += (-snext->credit) / CSCHED2_CREDIT_INIT;
+ ASSERT(snext->credit >= CSCHED2_CREDIT_MIN);
+ if ( unlikely(snext->credit == CSCHED2_CREDIT_MIN) )
+ reset += CSCHED2_CREDIT_INIT;
list_for_each( iter, &rqd->svc )
{
}
start_credit = svc->credit;
-
- /*
- * Add INIT * m, avoiding integer multiplication in the common case.
- */
- if ( likely(m==1) )
- svc->credit += CSCHED2_CREDIT_INIT;
- else
- svc->credit += m * CSCHED2_CREDIT_INIT;
-
+ svc->credit += reset;
/* "Clip" credits to max carryover */
if ( svc->credit > CSCHED2_CREDIT_INIT + CSCHED2_CARRYOVER_MAX )
svc->credit = CSCHED2_CREDIT_INIT + CSCHED2_CARRYOVER_MAX;
struct {
unsigned unit:16, dom:16;
int credit_start, credit_end;
- unsigned multiplier;
} d;
d.dom = svc->unit->domain->domain_id;
d.unit = svc->unit->unit_id;
d.credit_start = start_credit;
d.credit_end = svc->credit;
- d.multiplier = m;
__trace_var(TRC_CSCHED2_CREDIT_RESET, 1,
sizeof(d),
(unsigned char *)&d);
}
}
+ ASSERT(snext->credit > 0);
SCHED_STAT_CRANK(credit_reset);
/* No need to resort runqueue, as everyone's order should be the same. */