Back to home page

Quest Cross Reference

 
 

    


0001 % -*- Mode: LaTeX; TeX-PDF-mode: t -*-
0002 \documentclass[twocolumn,10pt]{article}
0003 \usepackage{amsmath,proof,amsthm,listings,algorithm}
0004 \usepackage[noend]{algorithmic}
0005 \renewcommand\algorithmiccomment[1]{ {\tt /*} #1 {\tt */}}
0006 \newcommand\paren[1]{\left( {#1} \right)}
0007 \newcommand\set[1]{\left\{ {#1} \right\}}
0008 \newcommand\len[1]{\left| {#1} \right|}
0009 % \newcommand\sched{\overset{s}{\mapsto}}
0010 % \newcommand\wake[1]{\overset{w_{#1}}{\mapsto}}
0011 \newcommand\sched{\xrightarrow{s}}
0012 \newcommand\msched{\sched^{\!{\raisebox{-1.5ex}{*}}}}
0013 \newcommand\wake[1]{\xrightarrow{w_{#1}}}
0014 \newcommand\vcpu[1]{\paren{#1}}
0015 \newcommand\pcpu[1]{\paren{#1}}
0016 \newcommand\running[1]{\ensuremath{{running}\paren{#1}}}
0017 \newcommand\runnable[1]{\ensuremath{{runnable}\paren{#1}}}
0018 \newtheorem{thm}{Theorem}
0019 \newtheorem{lma}{Lemma}
0020 \newtheorem{prop}{Property}
0021 % \numberwithin{equation}{subsection}
0022 % \renewcommand{\theequation}{\thesubsection\arabic{equation}}
0023 \lstset{language=C}
0024 
0025 \begin{document}
0026 
0027 \paragraph{Terminology} $\tau$ denotes a task, $Q$ denotes the quantum
0028 (in time units), $n$ denotes remaining time, $\sched$ denotes {\tt
0029   schedule}, and $\wake{\tau}$ denotes {\tt wakeup} on task $\tau$.
0030 VCPUs are represented as a tuple $\vcpu{\tau, n, \tau, \ldots}$
0031 containing the current task, the remaining quantum, and the tasks in
0032 the runqueue.  For convenience, assume that the runqueue entries are
0033 filled with the idle task $\tau_0$ whenever needed.  VCPUs are denoted
0034 with $V$.  $V_{\tau}$ is the VCPU associated with task $\tau$.  $0$
0035 denotes idle or empty activity.  PCPUs are represented as a tuple
0036 $\pcpu{V, V', \ldots}$ where $V$ is the current VCPU and $V',\ldots$
0037 are in the VCPU queue.
0038 
0039 \section{Round-Robin/Round-Robin Scheduling}
0040 
0041 \subsection{First level scheduling}
0042 
0043 \begin{subequations}
0044   \begin{equation}
0045     \label{pcpu:s1}
0046     \infer{\pcpu{V,V',\ldots}\sched\pcpu{V'',\ldots}}{
0047       V'\sched V'' & V''=(\tau, n, 0)
0048     }
0049   \end{equation}
0050   \begin{equation}
0051     \label{pcpu:s2}
0052     \infer{\pcpu{V,V',\ldots}\sched\pcpu{V'',V'',\ldots}}{
0053       V'\sched V'' & V''=(\tau, n, \tau', \ldots)
0054     }
0055   \end{equation}
0056   \begin{equation}
0057     \label{pcpu:s3}
0058     \infer{\pcpu{V,0}\sched\pcpu{0,0}}{}
0059   \end{equation}
0060   \begin{equation}
0061     \label{pcpu:w1}
0062     \infer{\pcpu{V,\ldots}\wake{\tau}\pcpu{V,\ldots,V'_{\tau}}}{
0063       V_{\tau}\wake{\tau}V'_{\tau} & V_{\tau} \not\in \set{\ldots}
0064     }
0065   \end{equation}
0066   \begin{equation}
0067     \label{pcpu:w2}
0068     \infer{\pcpu{V,\ldots,V_{\tau},\ldots}\wake{\tau}\pcpu{V,\ldots,V'_{\tau},\ldots}}{
0069       V_{\tau}\wake{\tau}V'_{\tau} &
0070     }
0071   \end{equation}
0072 \end{subequations}
0073 Rule~\ref{pcpu:s1} takes a VCPU $V'$ off the queue, transitions it to
0074 $V''$ (with an empty runqueue) and then makes it the current VCPU.
0075 Rule~\ref{pcpu:s2} applies when the VCPU has a non-empty runqueue.
0076 Rule~\ref{pcpu:s3} handles the empty queue case.  Rule~\ref{pcpu:w1}
0077 shows that both the task and the VCPU are placed on their respective
0078 queues during wakeup, and rule~\ref{pcpu:w2} indicates idempotency of
0079 VCPU {\tt wakeup}.
0080 
0081 \subsection{Second level scheduling}
0082 
0083 \begin{subequations}
0084   \begin{flalign}
0085     \vcpu{\tau, 0, \tau', \ldots} &\sched \vcpu{\tau', Q, \ldots} \label{vcpu:s1}\\
0086     \vcpu{\tau, n, \ldots, \tau, \ldots} &\sched \vcpu{\tau, n, \ldots}\quad\text{where }n > 0 \label{vcpu:s2}\\
0087     \vcpu{\tau, n, \tau', \ldots} &\sched \vcpu{\tau', n, \ldots}\quad\text{where }n > 0, \tau\neq\tau' \label{vcpu:s3}\\
0088     \vcpu{\tau, n, \ldots} &\wake{\tau'} \vcpu{\tau, n, \ldots, \tau'}\quad\text{where }\tau'\not\in\set{\ldots}\label{vcpu:w1} \\
0089     \vcpu{\tau, n, \ldots, \tau', \ldots} &\wake{\tau'} \vcpu{\tau,
0090       n, \ldots, \tau', \ldots} \label{vcpu:w2}
0091   \end{flalign}
0092 \end{subequations}
0093 
0094 Transition~\ref{vcpu:s1} occurs when the quantum expires.
0095 Transition~\ref{vcpu:s2} occurs when the quantum has not expired and
0096 the current task also appears on the runqueue.
0097 Transition~\ref{vcpu:s3} is the remaining case for when the quantum
0098 has not expired but the task is not runnable.
0099 Transition~\ref{vcpu:w1} shows how tasks are added to the runqueue.
0100 Transition~\ref{vcpu:w2} indicates idempotency of task {\tt wakeup}.
0101 
0102 \section{Properties}
0103 
0104 \begin{prop}
0105   \begin{subequations}
0106     \begin{equation}
0107       \label{eq:runningP}
0108       \infer{\running{\tau,(V,\ldots)}}{\running{\tau,V}}
0109     \end{equation}
0110     \begin{equation}
0111       \label{eq:runningV}
0112       \infer{\running{\tau,(\tau',n,\ldots)}}{\tau=\tau'}
0113     \end{equation}
0114   \end{subequations}
0115 \end{prop}
0116 \begin{prop}
0117   \begin{subequations}
0118     \begin{equation}
0119       \label{eq:runnableP}
0120       \infer{\runnable{\tau,(V,V_1,V_2,\ldots,V_m)}}{
0121         \exists_{j\in\set{1,\ldots,m}}\runnable{\tau,V_j}
0122       }
0123     \end{equation}
0124     \begin{equation}
0125       \label{eq:runnableV}
0126       \infer{\runnable{\tau,(\tau',n,\ldots,\tau'',\ldots)}}{\tau=\tau''}
0127     \end{equation}
0128   \end{subequations}
0129 \end{prop}
0130 
0131 \begin{prop}[Multiple step {\tt schedule}]
0132   \begin{subequations}
0133     \begin{equation}
0134       \label{msched:refl}
0135       \infer{P\msched P}{}
0136     \end{equation}
0137     \begin{equation}
0138       \label{msched:trans}
0139       \infer{P\msched P''}{P\sched P' & P'\msched P''}
0140     \end{equation}
0141   \end{subequations}
0142 \end{prop}
0143 
0144 \begin{lma}\label{lma:wakerun}
0145   If $P\wake{\tau} P'$ then \runnable{\tau,P'}.
0146 \end{lma}
0147 \begin{proof}
0148   Inversion on rules (\ref{pcpu:w1}) or (\ref{pcpu:w2}) gives
0149   $V_{\tau}\wake{\tau}V'_{\tau}$ and
0150   $P'=\pcpu{V,\ldots,V'_{\tau},\ldots}$.  Inversion on
0151   $V_{\tau}\wake{\tau}V'_{\tau}$ by (\ref{vcpu:w1}) or (\ref{vcpu:w2})
0152   says that $V'_{\tau}=\vcpu{\tau',n,\ldots,\tau,\ldots}$.  Therefore,
0153   \[
0154   \infer{\runnable{\tau, P'}}{
0155     \infer{\runnable{\tau,\pcpu{V,\ldots,V'_{\tau},\ldots}}}{
0156       \infer{\runnable{\tau,V'_{\tau}}}{
0157         \infer{\runnable{\tau,(\tau',n,\ldots,\tau,\ldots)}}{\tau=\tau}
0158       }
0159     }
0160   }
0161   \]
0162 \end{proof}
0163 
0164 \begin{lma}\label{lma:preservV}
0165   If \runnable{\tau,V} and $V\sched V'$ then either \runnable{\tau,V'}
0166   or \running {\tau,V'}.
0167 \end{lma}
0168 \begin{proof}
0169   In the case of rule~(\ref{vcpu:s1}) or rule~(\ref{vcpu:s3}), if
0170   $\tau$ is first on queue then it will start running.  If $\tau$ is
0171   not first in queue, then it remains runnable.
0172 
0173   In the case of rule~(\ref{vcpu:s2}), if $\tau$ is currently running
0174   then it will continue running.  If $\tau$ is on queue but not
0175   running, it will remain runnable.
0176 \end{proof}
0177 
0178 \begin{thm}[Preservation]\label{thm:preserv}
0179   If \runnable{\tau,P} and $P\sched P'$ then either \runnable{\tau,P'}
0180   or \running{\tau, P'}.
0181 \end{thm}
0182 \begin{proof}
0183   Consider the case of rule~(\ref{pcpu:s1})
0184   \begin{equation*}
0185     \infer{\pcpu{V,V',\ldots}\sched\pcpu{V'',\ldots}}{
0186       V'\sched V'' & V''=(\tau, n, 0)
0187     }
0188   \end{equation*}
0189   If $V_{\tau}\neq V'$ then it is still on queue and still runnable.
0190   Suppose instead that $V_{\tau}=V'$, then by lemma~\ref{lma:preservV}
0191   we know that either \runnable{\tau,V''} or \running{\tau,V''}.  But
0192   since $V''=\vcpu{\tau,n,0}$ we know $V''$ has an empty runqueue,
0193   therefore it must be the case that we have $\running{\tau,V''}$
0194   which implies $\running{\tau,P'}$.
0195 
0196   The other possible case is rule~(\ref{pcpu:s2})
0197   \begin{equation*}
0198     \infer{\pcpu{V,V',\ldots}\sched\pcpu{V'',V'',\ldots}}{
0199       V'\sched V'' & V''=(\tau, n, \tau', \ldots)
0200     }
0201   \end{equation*}
0202   This case is similar to the previous one except that $V''$ does not
0203   have an empty runqueue.  Therefore we must consider the subcase when
0204   $\runnable{\tau,V''}$.  Since $V''$ appears on the queue of $P'$,
0205   property~(\ref{eq:runnableP}) applies and \runnable{\tau,P'} can be derived.
0206 \end{proof}
0207 
0208 \newcommand\metric[1]{\ensuremath{\text{metric}\paren{#1}}}
0209 \renewcommand\bar\overline
0210 \begin{prop}[Induction Metric]
0211   The size of a VCPU is the length of its queue.
0212   \begin{equation}
0213     \label{eq:metric}
0214     \metric{(\tau,n,\bar\tau)}={\len{\bar\tau}}
0215   \end{equation}
0216   The size of a PCPU is double the number of VCPUs in the queue, plus
0217   the active VPCU if any.
0218   \begin{equation}
0219     \label{eq:metricV}
0220     \metric{(V,\bar V)}=2\sum_{v\in\bar V}{\metric{v}}+\len V
0221   \end{equation}
0222   The metric on a PCPU is the sum of the metrics on each queued VCPU,
0223   plus one if the PCPU is not idle.  Notably,
0224   $\metric{(0,0)}=0$, in other words, the idle PCPU is the lowest
0225   metric.
0226 \end{prop}
0227 
0228 \begin{lma}\label{lma:nonzerometricV}
0229   If $V\wake{\tau'}V'$ then $\metric {V'}>0$.
0230 \end{lma}
0231 \begin{proof}
0232   In the case of rule~(\ref{vcpu:w1}) the VCPU transition is
0233   $\vcpu{\tau,n,\ldots}\wake{\tau'}\vcpu{\tau,n,\ldots,\tau'}$,
0234   therefore the number of queued tasks is non-zero.  In the case of
0235   rule~(\ref{vcpu:w2}) the transition is
0236   $\vcpu{\tau,n,\ldots,\tau',\ldots}\wake{\tau'}\vcpu{\tau,n,\ldots,\tau',\ldots}$
0237   and the task is already queued, therefore the metric is unchanged,
0238   and cannot be zero.
0239 \end{proof}
0240 
0241 \begin{lma}\label{lma:nonzerometric}
0242   If a VCPU is on a PCPU queue then it has non-zero metric.
0243 \end{lma}
0244 \begin{proof}
0245   The only way a VCPU can arrive on a PCPU queue is through
0246   rules~(\ref{pcpu:w1}) or (\ref{pcpu:w2}), both of which require a
0247   derivation of $V\wake{\tau'}V'$, and by
0248   lemma~\ref{lma:nonzerometricV} this means $\metric{V'}>0$.
0249 \end{proof}
0250 
0251 \begin{lma}
0252   \label{lma:indstepV}
0253   If $V\sched V'$ then $\metric{V'}<\metric{V}$.
0254 \end{lma}
0255 \begin{proof}
0256   In all three rules (\ref{vcpu:s1}), (\ref{vcpu:s2}), and
0257   (\ref{vcpu:s3}), the length of the queue is reduced by one,
0258   therefore, $\metric{V'}<\metric{V}$.
0259 \end{proof}
0260 
0261 \begin{lma}\label{lma:indstep}
0262   If $P\sched P'$ then $\metric{P'}<\metric{P}$.
0263 \end{lma}
0264 \begin{proof}
0265   First consider rule~(\ref{pcpu:s1}) where
0266   $\pcpu{V,V',\ldots}\sched\pcpu{V'',\ldots}$.  Working backwards,
0267   \begin{flalign*}
0268     \metric{\pcpu{V'',\ldots}} &< \metric{\pcpu{V,V',\ldots}} \\
0269     2\paren{\cdots} + 1 &< 2\paren{\metric{V'}+\cdots}+\len V \\
0270     1 &< 2\cdot\metric{V'} + \len V
0271   \end{flalign*}
0272   since by lemma~\ref{lma:nonzerometric}, $\metric{V'}>0$, this
0273   inequality is true regardless of $\len V$.
0274 
0275   The next rule is (\ref{pcpu:s2}) where
0276   $\pcpu{V,V',\ldots}\sched\pcpu{V'',V'',\ldots}$.  By inversion we
0277   find that $V'\sched V''$ and $V''=\vcpu{\tau,n,\tau',\ldots}$.
0278   Using lemma~\ref{lma:indstepV} we know that $\metric{V''}<\metric{V'}$.
0279   Working backwards,
0280   \begin{flalign*}
0281     \metric{\pcpu{V'',V'',\ldots}} &< \metric{\pcpu{V,V',\ldots}} \\
0282     2\paren{\metric{V''}+\cdots} + 1 &< 2\paren{\metric{V'}+\cdots}+\len V \\
0283     2\cdot\metric{V''} + 1 &< 2\cdot\metric{V'} + \len V
0284   \end{flalign*}
0285   Since $\metric{V''}<\metric{V'}$, this inequality is always true even
0286   if $\len V=0$.
0287 
0288   Finally, rule~(\ref{pcpu:s3}) where $\pcpu{V,0}\sched\pcpu{0,0}$
0289   leads to $\metric{\pcpu{0,0}}<\metric{\pcpu{V,0}}$ which unfolds
0290   into $0<1$.
0291 \end{proof}
0292 
0293 \begin{thm}[Exhaustion]\label{thm:exhaust}
0294   $P\msched (0,0)$
0295 \end{thm}
0296 \begin{proof}[Proof by induction on \metric{P}]
0297   The base case where $\metric{P}=0$ implies $P=(0,0)$ and by
0298   property~(\ref{msched:refl}) you have $(0,0)\msched (0,0)$.  The
0299   interesting property is (\ref{msched:trans}).  By inversion,
0300   $P\sched P'$ and $P'\msched P''$.  By lemma~\ref{lma:indstep},
0301   $\metric{P'}<\metric{P}$.  Therefore, by induction, $P'\msched
0302   (0,0)$.  Using property~(\ref{msched:trans}) and $P\sched P'$, we
0303   arrive at $P\msched (0,0)$.
0304 \end{proof}
0305 
0306 \newpage
0307 \section{VCPU}
0308 \newcommand\algorithmsize\small
0309 \paragraph{Notation.} A Sporadic Server Main VCPU $V$, for the purposes
0310 of these algorithms, consists of budget $V_b$, initial capacity $V_C$,
0311 period $V_T$, queue of replenishments $V_R$ ordered by time, and
0312 current usage $V_u$.  I/O VCPUs have $V_b, V_u$ along with eligibility
0313 time $V_e$, utilization $V_U$, a single replenishment $V_r$, and
0314 boolean status of ``budgeted''.  $C_{max}$ is defined as $V_T\cdot
0315 V_U$ for a given I/O VCPU.  A replenishment $r$ is a pair consisting
0316 of a time $r_t$ and some amount of budget $r_b$.
0317 
0318 The scheduler relies on four VCPU-specific functions: {\tt
0319   end-of-timeslice}, {\tt update-budget}, {\tt next-event}, and {\tt
0320   unblock}.  The first three are used by Algorithm~\ref{alg:schedule}.
0321 The wakeup routine invokes {\tt unblock}.
0322 
0323 \begin{algorithm}[!htb]
0324   \caption{\tt schedule}\label{alg:schedule}
0325   \begin{algorithmic}[1]\algorithmsize
0326     \REQUIRE $V$ is current VCPU.
0327     \REQUIRE $\bar V$ is set of runnable VCPUs.
0328     \REQUIRE $t_{cur}$ is current time.
0329     \REQUIRE $t_{prev}$ is previous time of scheduling.
0330 
0331     \STATE Let $\Delta t=t_{cur}-t_{prev}$ and let $T_{prev}=V_T$.
0332     \STATE Invoke {\tt end-of-timeslice} on $V$ with $\Delta t$.
0333 
0334     \STATE Find $V_{next}\in\bar V$ with highest priority and
0335     non-zero budget. Invoke {\tt update-budget} on each candidate VCPU
0336     before checking its budget.
0337 
0338     \IF{there is no satisfactory $V_{next}$}
0339     \STATE Enter idle mode and go to step~\ref{sched:repltimer}.
0340     \ENDIF
0341 
0342     \STATE Let $T_{next}$ be the period of $V_{next}$.
0343 
0344     \STATE Select next thread for $V_{next}$.
0345     \IF{$V_{next}$ has empty runqueue}
0346     \STATE Let $\bar V'=\bar V\setminus\{V_{next}\}$
0347     \STATE $V_{next}$ is no longer runnable.
0348     \ELSE
0349     \STATE Let $\bar V'=\bar V$.
0350     \ENDIF
0351 
0352     \STATE Initially let $\Delta t'$ be equal to the budget of $V_{next}$.
0353     \FOR{\label{sched:repltimer}each VCPU $v\in\bar V$ with higher priority than $V_{next}$}
0354     \STATE Let $t_e$ be the result of {\tt next-event} on $v$.
0355     \IF{$t_e$ is valid \AND $t_e-t_{cur}<\Delta t'$}\STATE Set $\Delta t':=t_e-t_{cur}$.\ENDIF
0356     \ENDFOR
0357     \STATE Set timer to go off after $\Delta t'$ has elapsed.
0358     \STATE Set $t_{prev}:=t_{cur}$ for next time.
0359     \STATE $V$ is no longer running.  $V_{next}$, if valid, is now running.
0360     \STATE Switch to $V_{next}$ or idle.
0361     \ENSURE $\bar V'$ is now the set of runnable VCPUs.
0362   \end{algorithmic}
0363 \end{algorithm}
0364 
0365 Algorithm~\ref{alg:schedule} is the entry point into the scheduler
0366 architecture.  It performs the general work of informing the current
0367 VCPU about its usage, finding the next VCPU to run, and arranging the
0368 system timer to interrupt when the next important event occurs.  The
0369 VCPU-specific functionality is delegated into the hooks {\tt
0370   end-of-timeslice}, {\tt update-budget}, and {\tt next-event}.
0371 
0372 \begin{algorithm}[!htb]
0373   \caption {\tt wakeup}\label{alg:wakeup}
0374   \begin{algorithmic}[1]\algorithmsize
0375     \REQUIRE Task $\tau$.
0376     \REQUIRE $CUR$ is currently running VCPU.
0377     \REQUIRE $V$ is VCPU associated with task $\tau$.
0378     \STATE Place $\tau$ on runqueue inside $V$.
0379     \STATE Place $V$ on runqueue.
0380     \STATE Invoke {\tt unblock} on $V$.
0381     \STATE Invoke {\tt update-budget} on $V$.
0382     \IF{$V_b>0$ \AND ($CUR$ is idle \OR $CUR_T>V_T$)}
0383     \STATE Preempt and invoke scheduler.
0384     \ENDIF
0385   \end{algorithmic}
0386 \end{algorithm}
0387 
0388 To cause a task and its associated VCPU to become runnable, use
0389 Algorithm~\ref{alg:wakeup}.  This takes care of putting the task and
0390 VCPU on their corresponding runqueue, and then invokes any
0391 VCPU-specific functionality in hooks {\tt unblock} and {\tt
0392   update-budget}.  Finally, it can preempt the running VCPU if the
0393 newly woken one is higher priority.
0394 
0395 \begin{algorithm}[!htb]
0396   \caption{\tt MAIN-VCPU-end-of-timeslice}\label{alg:vcpu_eot}
0397   \begin{algorithmic}[1]\algorithmsize
0398     \REQUIRE VCPU $V$
0399     \REQUIRE Time interval consumed $\Delta t$
0400     \STATE Set $V_u:=V_u+\Delta t$.
0401     \STATE Invoke {\tt budget-check} on $V$.
0402     \IF[Blocked or preempted]{$capacity(V)>0$}
0403     \IF[Blocked]{$V$ is \NOT runnable}
0404     \STATE Invoke {\tt split-check} on $V$.
0405     \ENDIF
0406     \STATE Set $V_b:=capacity(V)$.
0407     \ELSE
0408     \STATE Set $V_b:=0$.
0409     \ENDIF
0410   \end{algorithmic}
0411 \end{algorithm}
0412 
0413 \begin{algorithm}[!htb]
0414   \caption{\tt MAIN-VCPU-update-budget}\label{alg:vcpu_upbudg}
0415   \begin{algorithmic}[1]\algorithmsize
0416     \REQUIRE VCPU $V$
0417     \REQUIRE Current time $t_{cur}$
0418     \STATE Set $V_b:=max\{capacity(V), 0\}$.
0419   \end{algorithmic}
0420 \end{algorithm}
0421 
0422 \begin{algorithm}[!htb]
0423   \caption{\tt MAIN-VCPU-next-event}\label{alg:vcpu_nextevent}
0424   \begin{algorithmic}[1]\algorithmsize
0425     \REQUIRE VCPU $V$
0426     \REQUIRE Current time $t_{cur}$
0427     \RETURN $\min\{r_t \mid r\in V_R\wedge t_{cur}<r_t\}$ \OR ``No event.''
0428   \end{algorithmic}
0429 \end{algorithm}
0430 
0431 \begin{algorithm}[!htb]
0432   \caption{\tt MAIN-VCPU-init}
0433   \begin{algorithmic}[1]\algorithmsize
0434     \STATE $add(V_R,V_C,t_{cur})$.
0435   \end{algorithmic}
0436   \label{alg:vcpu_init}
0437 \end{algorithm}
0438 
0439 The Sporadic Server policy for Main VPUs is based on that described by
0440 Stanovich et al~\cite{stanovich10}. In Algorithm~\ref{alg:vcpu_eot}
0441 the VCPU has reached the end of a timeslice, so the usage counter is
0442 updated and {\tt budget-check} is invoked to update the replenishment
0443 queue.  If the VCPU has been blocked, then a partially used
0444 replenishment may need to be split into two pieces.  The $capacity(V)$
0445 formula determines the amount of running time a VCPU can obtain at the
0446 current moment.  This formula is defined as
0447 \begin{flalign*}
0448   head(V)&=\min_{r_t} \{r\in V_R\}\\
0449   second(V)&=\min_{r_t} \{r\in V_R \mid r \neq head(V)\}\\
0450   capacity(V)&=
0451   \begin{cases}
0452     0 & \text{if }head_t(V) > t_{cur} \\
0453     head_b(V) - V_u & \text{otherwise}
0454   \end{cases}
0455 \end{flalign*}
0456 where $head(V)$ is the earliest replenishment, and $second(V)$ is the
0457 one that follows.  In Algorithm~\ref{alg:vcpu_upbudg} the capacity is
0458 integrated into the VCPU framework by writing the current value into
0459 $V_b$. For a non-running VCPU, the next possible time to run is
0460 determined by finding the next replenishment in the queue that has yet
0461 to occur, this is expressed in Algorithm~\ref{alg:vcpu_nextevent}.
0462 When a Main VCPU unblocks, it invokes {\tt unblock-check} which
0463 updates the earliest replenishment time to the present and performs
0464 any merges that become possible.  Note that when Main VCPUs are
0465 created the initial replenishment must be set to the current time for
0466 the amount $V_C$ (Algorithm~\ref{alg:vcpu_init}).
0467 
0468 \begin{algorithm}[!htb]
0469   \caption{\tt IO-VCPU-end-of-timeslice}\label{alg:iovcpu_eot}
0470   \begin{algorithmic}[1]\algorithmsize
0471     \REQUIRE I/O VCPU $V$
0472     \REQUIRE Time interval consumed $\Delta t$
0473     \STATE Set $V_b:=\max\{0,V_b-\Delta t\}$.
0474     \STATE Set $V_u:=V_u+\Delta t$.
0475     \IF[Blocked or budget exhausted]{$V$ is \NOT runnable \OR $V_b=0$}
0476     \STATE Set $V_e:=V_e+V_u/V_U$.
0477     \IF{$V_r$ is unused}
0478     \STATE Set $V_r:=r$ where $r_t=V_e$ and $r_b=C_{max}$.
0479     \ELSE
0480     \STATE Set $V_{r_t}:=V_e$.
0481     \ENDIF
0482     \STATE Set $V_u:=0$.
0483     \STATE Set $V_b:=0$.
0484     \IF[Blocked]{$V$ is \NOT runnable}
0485     \STATE Set $V$ as \NOT ``budgeted.''
0486     \ENDIF
0487     \ENDIF
0488   \end{algorithmic}
0489 \end{algorithm}
0490 
0491 \begin{algorithm}[!htb]
0492   \caption{\tt IO-VCPU-update-budget}\label{alg:iovcpu_upbudg}
0493   \begin{algorithmic}[1]\algorithmsize
0494     \REQUIRE I/O VCPU $V$
0495     \REQUIRE Current time $t_{cur}$
0496     \IF{$V_r$ is valid \AND $V_{r_t}\leq t_{cur}$}
0497     \STATE Set $V_b:=V_{r_b}$.
0498     \STATE Invalidate $V_r$.
0499     \ENDIF
0500     \ENSURE $0\leq V_b\leq C_{max}$
0501   \end{algorithmic}
0502 \end{algorithm}
0503 
0504 \begin{algorithm}[!htb]
0505   \caption{\tt IO-VCPU-next-event}\label{alg:iovcpu_nextevent}
0506   \begin{algorithmic}[1]\algorithmsize
0507     \REQUIRE I/O VCPU $V$
0508     \REQUIRE Current time $t_{cur}$
0509     \IF{$V_r$ is valid \AND $t_{cur}<V_{r_t}$}
0510     \RETURN $V_{r_t}$.
0511     \ELSE
0512     \RETURN No event.
0513     \ENDIF
0514   \end{algorithmic}
0515 \end{algorithm}
0516 
0517 \begin{algorithm}[!htb]
0518   \caption{\tt IO-VCPU-unblock}\label{alg:iovcpu_unblock}
0519   \begin{algorithmic}[1]\algorithmsize
0520     \REQUIRE I/O VCPU $V$ associated with I/O task.
0521     \REQUIRE Main VCPU $M$ waiting for result of I/O task.
0522     \REQUIRE $t_{cur}$ is current time.
0523     \IF{$M_T<V_T$ \OR \NOT ($V$ is running \OR $V$ is runnable)}
0524     \STATE Set $V_T:=M_T$.
0525     \ENDIF
0526     \IF{$V$ is \NOT running \AND $V_e<t_{cur}$}
0527     \STATE Set $V_e:=t_{cur}$.\COMMENT{I/O VCPU was inactive}
0528     \ENDIF
0529     \IF{$V_r$ is invalid}
0530     \IF{$V$ is \NOT ``budgeted''}
0531     \STATE Set $V_r$ to replenish for $C_{max}$ budget at time $V_e$.
0532     \ENDIF
0533     \ELSE
0534     \STATE Set $V_{r_b}:=C_{max}$.
0535     \ENDIF
0536     \STATE Set $V$ as ``budgeted.''
0537   \end{algorithmic}
0538 \end{algorithm}
0539 
0540 The I/O VCPU algorithm is known as Priority Inheritance
0541 Bandwidth-Preserving Server (PIBS).  It is expressed here as a set of
0542 hooks into the VCPU scheduling framework.  When an I/O VCPU finishes a
0543 timeslice, it updates its budget and usage amounts as shown in
0544 Algorithm~\ref{alg:iovcpu_eot}.  Then if it was blocked or out of
0545 budget, the eligibility time is advanced and a replenishment is set
0546 for that time.  Since there is only a single replenishment for an I/O
0547 VCPU, the budget can be updated easily in
0548 Algorithm~\ref{alg:iovcpu_upbudg} by checking the time.  Similarly,
0549 the only possible event for a non-running I/O VCPU comes from its
0550 single replenishment, in Algorithm~\ref{alg:iovcpu_nextevent}.
0551 
0552 When an I/O VCPU unblocks that means a Main VCPU requires some I/O
0553 task performed on its behalf.  Therefore, the I/O VCPU adjusts its
0554 priority according to the period of that Main VCPU.  This is performed
0555 with a simple comparison of priorities in
0556 Algorithm~\ref{alg:iovcpu_unblock}.  Though this method could result
0557 in the I/O VCPU maintaining a higher priority than it deserves over
0558 some periods of time, if the jobs are short then that effect should be
0559 minimized.  A stricter approach would track the precise moment when a
0560 higher priority VCPU was satisfied and would lower the I/O VCPU to the
0561 level of the next highest VCPU waiting.  However, this requires early
0562 de-multiplexing in order to figure out when the I/O VCPU task has
0563 finished processing all I/O for a given Main VCPU, and introduces a
0564 loop into an algorithm that is otherwise constant-bounded.  In order
0565 to prevent the I/O VCPU eligibility time from falling behind
0566 real-time, it is updated to the current time if the I/O VCPU is not
0567 running.  Then a replenishment is posted for the I/O VCPU of $C_{max}$
0568 budget at the eligibility time.  The purpose of the ``budgeted'' state
0569 is to prevent repeated job requests from replenishing the I/O VCPU
0570 beyond $C_{max}$ in budget.  The ``budgeted'' state is only reset when
0571 the I/O VCPU blocks, therefore, the replenishment can only be posted
0572 in this way once per eligibility period.
0573 
0574 \begin{algorithm}[!htb]
0575   \caption{\tt budget-check}
0576   \begin{algorithmic}[1]\algorithmsize
0577     \REQUIRE VCPU $V$.
0578     \IF{$capacity(V) \leq 0$}
0579     \WHILE[Exhaust and reschedule replenishments]{$head_b(V) \leq V_u$}
0580     \STATE Set $V_u:=V_u-head_b(V)$.
0581     \STATE Let $r=head(V)$.
0582     \STATE $pop(V_R)$.
0583     \STATE Set $r_t:=r_t+V_T$.
0584     \STATE $add(V_R,r)$.
0585     \ENDWHILE
0586     \IF[$V_u$ is overrun]{$V_u>0$}
0587     \STATE Set $head_t(V) := head_t(V) + V_u$.
0588     \IF[Merge]{$head_t(V)+head_b(V) \geq second_t(V)$}
0589     \STATE Let $b=head_b(V)$ and $t=head_t(V)$.
0590     \STATE $pop(V_R)$.
0591     \STATE Set $head_b(V):=head_b(V)+b$ 
0592     \STATE Set $head_t(V):=t$.
0593     \ENDIF
0594     \ENDIF
0595     \IF{$capacity(V)=0$}
0596     \STATE Put $V$ in background mode.
0597     \IF{$V$ is runnable}
0598     \STATE $V$ will go into foreground mode at time $head_t(V)$.
0599     \ENDIF
0600     \ENDIF
0601     \ENDIF
0602   \end{algorithmic}
0603   \label{alg:budget_check}
0604 \end{algorithm}
0605 
0606 \begin{algorithm}[!htb]
0607   \caption{\tt split-check}
0608   \begin{algorithmic}[1]\algorithmsize
0609     \REQUIRE VCPU $V$.
0610     \REQUIRE Current time $t_{cur}$.
0611     \IF{$V_u>0$ \AND $head_t(V)\leq t_{cur}$}
0612     \STATE Let $remnant=head_b(V)-V_u$.
0613     \ENSURE $capacity(V)=remnant$.
0614     \IF[Push remnant into next]{$V_R$ is full}
0615     \STATE $pop(V_R)$.
0616     \STATE Set $head_b(V):=head_b(V)+remnant$.
0617     \ELSE
0618     \STATE Set $head_b(V):=remnant$.
0619     \ENSURE $capacity(V)=capacity(V)-V_u$.
0620     \ENDIF
0621     \STATE $add(V_r, V_u, head_t(V)+V_T)$.
0622     \STATE Set $V_u:=0$.
0623     \ENSURE $capacity(V)=capacity(V)$.
0624     \ENDIF
0625   \end{algorithmic}
0626   \label{alg:split_check}
0627 \end{algorithm}
0628 
0629 \begin{algorithm}[!htb]
0630   \caption{\tt unblock-check}
0631   \begin{algorithmic}[1]\algorithmsize
0632     \REQUIRE VCPU $V$.
0633     \REQUIRE Current time $t_{cur}$.
0634     \IF{$capacity(V) > 0$}
0635     \STATE $V$ should be in foreground mode.
0636     \STATE Set $head_t(V):=t_{cur}$.
0637     \COMMENT{Advance earliest replenishment to now.}
0638     \WHILE{$\left|V_R\right|>1$}
0639     \STATE Let $b:=head_b(V)$.
0640     \IF[Merge]{$second_t(V)\leq t_{cur}+b-V_u$}
0641     \STATE $pop(V_R)$.
0642     \STATE Set $head_b(V):=head_b(V)+b$ and set $head_t(V):=t_{cur}$.
0643     \ELSE
0644     \RETURN
0645     \ENDIF
0646     \ENDWHILE
0647     \ELSE
0648     \STATE $V$ will go into foreground mode at time $head_t(V)$.
0649     \ENDIF
0650   \end{algorithmic}
0651   \label{alg:unblock_check}
0652 \end{algorithm}
0653 
0654 Algorithms~\ref{alg:budget_check}, \ref{alg:split_check}, and
0655 \ref{alg:unblock_check} are based on Stanovich et
0656 al~\cite{stanovich10}.  These listings include fixes to minor errors
0657 we discovered in the original description.
0658 
0659 \end{document}