Scheduling Fixed-Priority Tasks with Preemption Threshold
Scheduling fixed-priority tasks with preemption threshold 全文翻译、代码解析
专有名词
名词 | 翻译 | 简介 |
---|---|---|
Preemption Threshold | 抢占阈值 | 指任务执行后被赋予的优先级 |
Priority | 优先级 | 抢占其他任务的优先级 |
Busy Period | 忙周期 | 从所有任务开始到所有实例结束的时间 |
Schedulability | 可调度性 | 不超时完成周期性任务的能力 |
模型
-
任务模型
周期性或非周期性任务 τ 1 , τ 2 , . . . , τ n \tau_1,\tau_2,...,\tau_n τ1,τ2,...,τn。 τ i \tau_i τi表示任务,使用三元组 ( C i , T i , D i ) (C_i,T_i,D_i) (Ci,Ti,Di)表示,其中 C i C_i Ci表示任务所需时钟周期个数, T i T_i Ti表示任务 τ i \tau_i τi两个实例之间的最小间隔, D i D_i Di表示任务截止时限。
上述建立在假设:1. 任务独立;2. 任务不会自身阻塞,除非计算结束;3. 上下文切换开销不计
每个任务分配优先级 π i \pi_i πi,满足 π i ∈ [ 1 , N ] \pi_i\in[1, N] πi∈[1,N],以及抢占阈值 γ i ∈ [ π i , N ] \gamma_i\in[\pi_i, N] γi∈[πi,N]。值越大优先级越高。
-
运行时模型
固定优先级的抢占调度,带抢占阈值。
当任务 τ i \tau_i τi执行时,另一任务 π j > γ i \pi_j>\gamma_i πj>γi时才允许抢占。
问题描述
对于一组任务, Γ = { τ i = < C i , T i , D i > ∣ 1 ⩽ i ⩽ n } \varGamma=\left\{\tau_i=\left< C_i,T_i,D_i\right>|1\leqslant i\leqslant n\right\} Γ={τi=⟨Ci,Ti,Di⟩∣1⩽i⩽n},是否能寻找一组优先级和抢占阈值 { < π i , γ i > ∣ 1 ⩽ i ⩽ n } \left\{\left<\pi_i,\gamma_i\right>|1\leqslant i\leqslant n\right\} {⟨πi,γi⟩∣1⩽i⩽n}使得 Γ \varGamma Γ可调度,即最坏情况下的响应时间不超过deadline。
调度性分析
阻塞时间分析
阻塞来自于低优先级但高抢占阈值,高优先级但是抢占阈值不高的任务无法执行,被阻塞住。
定义抢占保护空间为 [ π i , γ i ] [\pi_i,\gamma_i] [πi,γi]
引理1:已经开始执行且没结束的任务之间的保护空间不重叠。
证明:已经开始执行的任务,其优先级应该高于其他所有未完成任务的抢占阈值。(可能只考虑单个处理机的情况)
引理2:一个任务
τ
i
\tau_i
τi至多被1个低优先级任务
τ
j
\tau_j
τj阻塞,且必须是其抢占阈值更高,即
γ
j
⩾
π
i
\gamma_j\geqslant\pi_i
γj⩾πi。
证明:简单讲,由于引理1中保护空间不重叠,所以最多被一个这种任务所阻塞。没开始执行的任务之间不会相互进行阻塞。
最大阻塞时间:
B
(
τ
i
)
=
max
j
{
C
j
∣
γ
j
⩾
π
i
⩾
π
j
}
(1)
B\left(\tau_i \right) =\underset{j}{\max}\left\{ C_j|\gamma_j\geqslant \pi_i\geqslant \pi_j \right\} \tag{1}
B(τi)=jmax{Cj∣γj⩾πi⩾πj}(1)
忙周期分析
忙周期研究了多线程的抢占调度。最坏响应时间依据忙周期计算。
忙周期开始时间:1. 多个高优先级任务的实例同时到达0时刻;2. 贡献最大阻塞时间的任务在时间0时刻之前刚刚开始执行。
传统固定优先级的忙周期
w
i
(
q
)
w_i\left(q\right)
wi(q)可以通过下式迭代计算:
w
i
(
q
)
=
q
C
i
+
∑
∀
j
,
π
j
>
π
i
⌈
w
i
(
q
)
T
j
⌉
C
j
(2)
w_i\left(q\right) =qC_i+\sum_{\forall j,\pi_j>\pi_i}{\lceil \frac{w_i\left( q \right)}{T_j} \rceil}C_j \tag{2}
wi(q)=qCi+∀j,πj>πi∑⌈Tjwi(q)⌉Cj(2)
q
q
q是
τ
i
\tau_i
τi的实例。
忙周期长度由下式计算:
W
i
=
min
q
∈
{
1
,
2
,
3
,
.
.
.
}
W
i
(
q
)
,
W
i
(
q
)
⩽
q
T
i
(3)
W_i=\underset{q\in \left\{ 1,2,3,... \right\}}{\min}W_i\left( q \right) ,W_i\left( q \right) \leqslant qT_i \tag{3}
Wi=q∈{1,2,3,...}minWi(q),Wi(q)⩽qTi(3)
其中
W
i
(
q
)
W_i\left( q \right)
Wi(q)是满足
(
2
)
(2)
(2)式的最小的
w
i
(
q
)
w_i\left(q\right)
wi(q)。
作者扩展了原始的level-i的忙周期分析,分成了两个部分:
- 第一部分:从时刻0开始到任务 τ i \tau_i τi开始执行(即第一次获取cpu)。
- 第二部分:正好从第一个忙周期开始,并在实例完成时停止。
使用 S i ( q ) \mathcal{S}_i\left( q \right) Si(q)来表示任务 τ i \tau_i τi的实例 q q q的开始时间,用 F i ( q ) \mathcal{F}_i\left( q \right) Fi(q)表示忙周期的结束。另外,用 ( q − 1 ) T i \left( q-1 \right) T_i (q−1)Ti表示任务 τ i \tau_i τi的实例 q q q的到达时间。那么对于实例 q = 1 , 2 , 3 , . . . q=1,2,3,... q=1,2,3,...,可以计算出 S i ( q ) \mathcal{S}_i\left( q \right) Si(q)和 F i ( q ) \mathcal{F}_i\left( q \right) Fi(q),当 q = m q=m q=m时,有 F i ( q ) ⩽ q T i \mathcal{F}_i\left( q \right) \leqslant qT_i Fi(q)⩽qTi(因为假定了任务实例的最长间隔为 T i T_i Ti,那么第 m m m个实例的结束时间肯定小于 q T i qT_i qTi)。
最差响应时间可以通过下式计算:
R
i
=
max
q
∈
[
1
,
2
,
.
.
.
,
m
]
(
F
i
(
q
)
−
(
q
−
1
)
T
i
)
(4)
\mathcal{R}_i=\underset{q\in\left[1,2,...,m\right]}{\max}\left(\mathcal{F}_i\left( q \right) -\left( q-1 \right) T_i \right) \tag{4}
Ri=q∈[1,2,...,m]max(Fi(q)−(q−1)Ti)(4)
计算最差情况的开始时间(Computing Worst-case Start Time, S i ( q ) \mathcal{S}_i\left( q \right) Si(q))
为什么会有最差开始时间,因为可能受到低优先级但高抢占阈值/高优先级的任务阻塞。低优先级的阻塞任务至多会有1个,原因已经在引理2中解释过。所有高优先级任务以及
τ
i
\tau_i
τi自身在实例
q
q
q之前的实例应该要在
S
i
(
q
)
\mathcal{S}_i\left( q \right)
Si(q)之前完成,因此
F
i
(
q
)
\mathcal{F}_i\left( q \right)
Fi(q)可以通过下列式子迭代获得:
S
i
(
q
)
=
B
(
τ
i
)
+
(
q
−
1
)
C
i
+
∑
∀
j
,
π
j
>
π
i
(
1
+
⌊
S
i
(
q
)
T
j
⌋
)
C
j
(5)
\mathcal{S}_i\left( q \right) =B\left( \tau_i \right) +\left( q-1 \right) C_i+\sum_{\forall j,\pi_j>\pi_i}{\left( 1+\lfloor \frac{\mathcal{S}_i\left( q \right)}{T_j} \rfloor \right) C_j} \tag{5}
Si(q)=B(τi)+(q−1)Ci+∀j,πj>πi∑(1+⌊TjSi(q)⌋)Cj(5)
其中 B ( τ i ) B\left( \tau_i \right) B(τi)是 τ i \tau_i τi的最大阻塞时间(某个低优先级高抢占阈值的阻塞时间), ( q − 1 ) C i \left( q-1 \right) C_i (q−1)Ci是前 q − 1 q-1 q−1个任务的计算时间, ∑ ∀ j , π j > π i ( 1 + ⌊ S i ( q ) T j ⌋ ) C j \sum_{\forall j,\pi_j>\pi_i}{\left( 1+\lfloor \frac{\mathcal{S}_i\left( q \right)}{T_j} \rfloor \right) C_j} ∑∀j,πj>πi(1+⌊TjSi(q)⌋)Cj则是其他优先级高于本任务的总计算时间。
计算最差情况的结束时间(Computing Worst-case Finish Time, F i ( q ) \mathcal{F}_i\left( q \right) Fi(q))
最差时间肯定要依托于最差开始时间,但也要考虑干扰因素。首先根据抢占阈值定义,在
τ
i
\tau_i
τi开始前,只有优先级高于
π
i
\pi_i
πi的任务才能抢占它;在
τ
i
\tau_i
τi结束前,只有优先级高于
γ
i
\gamma_i
γi的任务才能抢占他。最差情况可以如下计算:
F
i
(
q
)
=
S
(
τ
i
)
+
C
i
+
∑
∀
j
,
π
j
>
γ
i
(
⌈
F
i
(
q
)
T
j
⌉
−
(
1
+
⌊
S
(
τ
i
)
T
j
⌋
)
)
C
j
(6)
\mathcal{F}_i\left( q \right) =\mathcal{S} \left( \tau_i \right) +C_i+\sum_{\forall j,\pi_j>\gamma_i}{\left( \lceil \frac{\mathcal{F}_i\left( q \right)}{T_j} \rceil -\left( 1+\lfloor \frac{\mathcal{S} \left( \tau_i \right)}{T_j} \rfloor \right) \right) C_j} \tag{6}
Fi(q)=S(τi)+Ci+∀j,πj>γi∑(⌈TjFi(q)⌉−(1+⌊TjS(τi)⌋))Cj(6)
其中 S i ( q ) \mathcal{S}_i\left( q \right) Si(q)是最差开始时间, C i C_i Ci是此任务消耗的时间, ∑ ∀ j , π j > γ i ( ⌈ F i ( q ) T j ⌉ − ( 1 + ⌊ S ( τ i ) T j ⌋ ) ) C j \sum_{\forall j,\pi_j>\gamma_i}{\left( \lceil \frac{\mathcal{F}_i\left( q \right)}{T_j} \rceil -\left( 1+\lfloor \frac{\mathcal{S} \left( \tau_i \right)}{T_j} \rfloor \right) \right) C_j} ∑∀j,πj>γi(⌈TjFi(q)⌉−(1+⌊TjS(τi)⌋))Cj则指的是其他可能抢占 τ i \tau_i τi的任务在此周期最大的计算时间。
带预定义优先级的抢占阈值分配
本节用一种算法为有预定优先级的任务分配抢占阈值,保住可调度性。首先这种固定优先级的调度模型有一些特性能帮助我们缩小搜索空间。
引理3:将任务
τ
i
\tau_i
τi的抢占阈值从
γ
1
\gamma_1
γ1改为
γ
2
\gamma_2
γ2只影响
τ
i
\tau_i
τi的最差响应时间,以及优先级在
γ
1
\gamma_1
γ1到
γ
2
\gamma_2
γ2之间的任务。
结合公式
(
4
)
(4)
(4)和公式
(
6
)
(6)
(6)可以得出这个结论,并有下面的推论:
推论4:任务
τ
i
\tau_i
τi的最差响应时间不会受到更高优先级任务(即
π
j
>
π
i
\pi_j > \pi_i
πj>πi)的抢占阈值的影响。
这个推论表明,任务的可调度性与更高优先级任务的抢占阈值无关,因此阈值分配应该要从最低的任务开始,直到最高的任务。除此外,这个推论也可以帮助最佳抢占阈值的确定。
定理5:假设有
n
n
n个任务的任务集
Γ
=
{
τ
i
=
<
C
i
,
T
i
,
D
i
>
∣
1
⩽
i
⩽
n
}
\varGamma =\left\{ \tau _i=\left< C_i,T_i,D_i \right> |1\leqslant i\leqslant n \right\}
Γ={τi=⟨Ci,Ti,Di⟩∣1⩽i⩽n},其带有优先级和抢占阈值
{
<
π
i
,
γ
i
>
∣
1
⩽
i
⩽
n
}
\left\{\left<\pi_i,\gamma_i\right>|1\leqslant i\leqslant n\right\}
{⟨πi,γi⟩∣1⩽i⩽n}。如果只将
τ
j
\tau_j
τj的抢占阈值从
γ
j
\gamma_j
γj改为
γ
j
′
(
γ
j
′
<
γ
j
)
\gamma_{j}^{\prime}\left(\gamma_{j}^{\prime} < \gamma_j\right)
γj′(γj′<γj)时,任务
τ
j
\tau_j
τj仍然可以调度,那么整个系统在
τ
j
\tau_j
τj在
γ
j
′
\gamma_{j}^{\prime}
γj′下可调度。
证明:当
τ
j
\tau_j
τj的抢占阈值从
γ
i
\gamma_i
γi改为
γ
i
′
(
γ
i
′
<
γ
i
)
\gamma_{i}^{\prime}\left(\gamma_{i}^{\prime} < \gamma_i\right)
γi′(γi′<γi)时,在抢占保护区间
[
π
i
,
γ
i
]
[\pi_i,\gamma_i]
[πi,γi]之外的任务的最差响应时间不会变化。在抢占保护区间
[
π
i
,
γ
i
′
]
[\pi_i,\gamma_{i}^{\prime}]
[πi,γi′]之内的任务的最差响应时间也不变化。
[
γ
i
,
γ
i
′
]
[\gamma_{i},\gamma_{i}^{\prime}]
[γi,γi′]的任务不会有更差的响应时间。除此外,若已知
γ
i
′
\gamma_{i}^{\prime}
γi′可调度,那么整个系统也能在新的抢占阈值下调度。
引理6:给定优先级
π
i
\pi_i
πi,如果设置其抢占阈值为
γ
i
\gamma_i
γi等于系统最高的优先级都不能使其可调度,那么这个任务集就是不可调度的。
证明:比较公式
(
6
)
(6)
(6)和公式
(
2
)
(2)
(2),可以看到抢占阈值可以防止来自高优先级任务的干扰,缩短其相应时间,提高可调度性。如果设定其抢占阈值为最高优先级都不能调度,那任务集理所当然无法调度。
算法1给出了伪代码,推论4建议我们从优先级最低的任务开始阈值分配,因为可调度性分析只取决于优先级比当前任务低的任务的抢占阈值。在搜索特定任务的最佳抢占阈值时,引理3意味着从它的优先级开始搜索,直到到系统中的最高优先级,并停在第一个使任务可调度的优先级,即使任务可调度的最小抢占阈值。此外,引理6还告诉我们什么时候可以说系统不可调度并停止算法。
算法假设任务编号为
1
,
.
.
.
,
n
1,...,n
1,...,n,任务预定的优先级也按此顺序排列。函数
W
C
R
T
(
t
a
s
k
,
t
h
r
e
s
h
o
l
d
)
WCRT(task,threshold)
WCRT(task,threshold)将根据任务特性
(
C
,
T
,
D
)
(C,T,D)
(C,T,D),计算出任务最坏的响应时间。
算法1的复杂度为 O ( n 2 ) \mathcal{O}( n^2 ) O(n2)。
算法1:抢占阈值分配算法
Algorithm: Assign Preemption Thresholds
//Assumes that task priorities are already known
(1) for (
i
i
i :=
1
1
1 to
n
n
n)
(2)
γ
i
=
π
i
\gamma_i = \pi_i
γi=πi //Calculate worst-case response time of T;
(3)
R
i
=
W
C
R
T
(
τ
i
,
γ
i
)
\mathcal{R}_i = WCRT(\tau_i,\gamma_i)
Ri=WCRT(τi,γi);
(4) while
R
i
>
D
i
\mathcal{R}_i > D_i
Ri>Di do // while not schedulable
(5)
γ
i
\gamma_i
γi++; // increase threshold
(6) if
γ
i
>
n
\gamma_i > n
γi>n then
(7) return
F
A
I
L
FAIL
FAIL; // systen mot schedulable
(8) endif
(9)
R
i
=
W
C
R
T
(
τ
i
,
γ
i
)
\mathcal{R}_i = WCRT(\tau_i,\gamma_i)
Ri=WCRT(τi,γi);
(10) end
(11) end
(12) return
S
U
C
C
E
S
S
SUCCESS
SUCCESS
优先级和抢占阈值的优化分配
本节讨论给定任务集确定最优优先级和抢占阈值的一般问题,利用分支定界(branch-and-bound)算法来进行搜索。目前能否找到有效算法是一个未解决的问题,因为抢占阈值的搜索引入了一个新的维度。
搜索算法通过对“好”优先级排序执行启发式搜索,然后当优先级排序完成时,使用前一节中提供的算法来查找可行的阈值分配。如果找到一个可行的阈值分配,那么就完成了分配。如果不是,算法就回溯到另一个优先级排序。
该算法的工作原理是将任务集分为两部分:一个是排序的部分,由优先级较低的任务组成;另一个是未排序的部分,包含剩余的优先级较高的任务。最初,排序部分为空,所有任务都在未排序部分。通过在每个阶段选择一个启发式的候选list,它递归的从未排序list移动1个任务到排序list,当所有任务都在排序list中时,将生成完整的优先级排序,并调用阈值分配。
在考虑下一个要移动到排序list中的候选对象时,依次检查未排序list中的所有任务。如果这些任务中的任何一个在没有阈值的抢占式优先级调度下都是可调度的,那么它被选择移动到排序list中。如果没有任务是可调度的,则根据稍后定义的启发式函数对任务进行排序。搜索优先级排序然后以最佳优先方式进行。
算法2:搜索
S
e
a
r
c
h
(
T
a
s
k
S
e
t
,
P
r
i
o
r
i
t
y
)
Search(TaskSet, Priority)
Search(TaskSet,Priority)
/* Terminating Condition* /
(1) if
(
P
r
i
o
r
i
t
y
=
=
N
+
1
)
(Priority == N+1)
(Priority==N+1) then
/* Call the algorithm in Figure 2 for optimal
preemption threshold assignment */
(2) if
(
A
s
s
i
g
n
T
h
r
e
s
h
o
l
d
s
(
)
=
=
S
U
C
C
E
S
S
)
(AssignThresholds() == SUCCESS)
(AssignThresholds()==SUCCESS) then
(3) return
S
U
C
C
E
S
S
SUCCESS
SUCCESS
(4) else return
F
A
I
L
FAIL
FAIL
(5) endif
(6) endif
(7) foreach
τ
k
\tau_k
τk in
T
a
s
k
S
e
t
TaskSet
TaskSet do
(8)
D
e
l
a
y
k
:
=
W
C
R
T
(
τ
k
)
−
D
k
Delay_k := WCRT(\tau_k) - D_k
Delayk:=WCRT(τk)−Dk;
(9) if
D
e
l
a
y
k
⩽
0
Delay_k\leqslant 0
Delayk⩽0 then
(10)
τ
k
:
=
P
r
i
o
r
i
t
y
\tau_k:=Priority
τk:=Priority;
(11) if
S
e
a
r
c
h
(
T
a
s
k
S
e
t
τ
k
,
P
r
i
o
r
i
t
y
+
1
)
=
=
S
U
C
C
E
S
S
Search(TaskSet_{\tau_k}, Priority+1) == SUCCESS
Search(TaskSetτk,Priority+1)==SUCCESS then
(12) return
S
U
C
C
E
S
S
SUCCESS
SUCCESS
(13) else
(14) return
F
A
I
L
FAIL
FAIL
(15) endif
(16) endif
(17) end
/* Not schedulable without preemption threshold */
/* Sort the task set by ascending order of Latenessk */
(18)
S
o
r
t
e
d
L
i
s
t
=
G
e
n
e
r
a
t
e
L
i
s
t
(
T
a
s
k
S
e
t
)
SortedList = GenerateList(TaskSet)
SortedList=GenerateList(TaskSet);
/* Rejine SortedList, eliminating those tasks that are
unschedulable even with preemption threshold equal to N */
(19)
R
e
f
i
n
e
(
S
o
r
t
e
d
L
i
s
t
)
Refine(SortedList)
Refine(SortedList);
/* Recursively perform depth jirst search */
(20) foreach
τ
i
\tau_i
τi in
S
o
r
t
e
d
L
i
s
t
SortedList
SortedList do
(22)
t
a
u
k
:
=
P
r
i
o
r
i
t
y
tau_k:=Priority
tauk:=Priority;
(21) if
S
e
a
r
c
h
(
T
a
s
k
S
e
t
τ
i
,
P
r
i
o
r
i
t
y
+
1
)
=
=
S
U
C
C
E
S
S
Search(TaskSet_{\tau_i}, Priority+1) == SUCCESS
Search(TaskSetτi,Priority+1)==SUCCESS then
(23) return
S
U
C
C
E
S
S
SUCCESS
SUCCESS
(24) endif
(25) end
(26) return
F
A
I
L
FAIL
FAIL
剪枝不可行路径
从上面的算法描述中,我们可以看到,需要多个分支的唯一情况是当未排序部分的所有任务都是不可调度的(在没有阈值的抢占优先级调度下)。在响应时间分析中,可以通过为任务分配高于其优先级的抢占阈值来改善最坏情况下的响应时间。由于我们不知道未排序的高优先级部分的优先级顺序,因此我们无法确定使任务可调度的抢占阈值。因此,我们无法知道将哪个任务移动到排序部分将使解最优。因此,留给我们的唯一选择就是尝试所有的任务。
然而,我们注意到,如果一个任务是不可调度的,通过将其抢占阈值分配给最高优先级
N
N
N,那么下一个优先级的任务将没有可能的解决方案(即,它必须具有比未排序列表中的某些任务更高的优先级)。因此,我们可以把它从我们应该尝试的选择中剔除。因此,我们通过使用抢占阈值等于
N
N
N的最坏情况响应时间作为边界函数来减少搜索空间。
启发式函数
在剔除不可行的路径后,我们还要决定我们的试验顺序。一个好的启发式策略可以减少实际实现中的搜索时间。在这里,我们提出一个最短延迟优先的策略。我们将延迟定义为当任务的抢占阈值等于其优先级时,任务的截止日期与最坏情况响应时间之差:
L
a
t
e
n
e
s
s
i
=
R
i
−
D
i
(7)
Lateness_i=\mathcal{R}_i-\mathcal{D}_i \tag{7}
Latenessi=Ri−Di(7)
其中 R i \mathcal{R}_i Ri是使用不带抢占阈值的抢占优先级策略计算的。此策略的设计注意到,通过增加其抢占阈值来减少特定任务的最坏情况响应时间,可能会以增加其优先级和其抢占阈值之间的其他任务的最坏情况响应时间为代价(这将要求将其抢占阈值设置得更高,等等)。我们选择延迟最小的任务,希望它是需要最小抢占阈值的任务,为其他任务留下更大的空闲。
算法2给出了优先级排序和抢占阈值设置最优组合的搜索算法的伪代码。它有两个参数: T a s k S e t TaskSet TaskSet,它是未排序的部分(包含所有等待分配优先级的任务), P r i o r i t y Priority Priority,它是下一个要分配的优先级。已分配优先级的任务单独保存,以便在算法结束时分配抢占阈值。伪代码中使用了四个函数: A s s i g n T h r e s h o l d s ( ) AssignThresholds() AssignThresholds()是图2中的算法; W C R T ( τ k ) WCRT(\tau_k) WCRT(τk)将计算不带阈值的抢占式优先级调度和当前部分优先级排序下任务的最坏情况响应时间; G e n e r a t e L i s t ( T a s k S e t ) GenerateList(TaskSet) GenerateList(TaskSet)将生成 T a s k S e t TaskSet TaskSet中按延迟升序排列的任务list,定义如式 ( 7 ) (7) (7); R e f i n e ( s o r t e d l i s t ) Refine(sortedlist) Refine(sortedlist)将消除不可调度的任务,即将它们的抢占阈值设置为任务链表中可能的最高优先级 N N N也不能调度的任务。