aboutsummaryrefslogtreecommitdiffstats
path: root/schedcat/sched/edf/da.py
blob: 15fe974d01c5d6f9d5c72285533326c0d4fc1fbb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
"""Global EDF soft real-time test and tardiness bounds, based on Devi & Anderson's work.
"""

from __future__ import division

from math import ceil

from schedcat.util.quantor import forall

def tardiness_x(no_cpus, tasks):
    """This function computes the X part of Uma Devi's G-EDF tardiness bound, as
       given in Corollary 4.11 on page 109 of Uma's thesis..

       This function assumes full preemptivity.
    """
    if not tasks:
        return 0
    U = tasks.utilization()
    if no_cpus == 1:
        if U <= 1:
            return 0
        else:
            return None
    by_util = [t.utilization() for t in tasks]
    by_util.sort(reverse=True)
    by_cost = [t.cost for t in tasks]
    by_cost.sort(reverse=True)

    Lambda = int(ceil(U)) - 1
    emin   = by_cost[-1]

    reduced_capacity = no_cpus - sum(by_util[0:Lambda - 1])
    if reduced_capacity <= 0:
        # bad: tardiness is not bounded
        return None

    reduced_cost = max(0, sum(by_cost[0:Lambda]) - emin)
    return int(ceil(reduced_cost / reduced_capacity))

def np_tardiness_x(no_cpus, tasks):
    """This function computes the X part of Uma Devi's G-EDF tardiness bound, as
       given in Corollary 4.3 in Uma's thesis, page 110.
    """
    if not tasks:
        return 0
    U = tasks.utilization()
    # by_util is mu in Uma's theorem
    by_util = [t.utilization() for t in tasks]
    by_util.sort(reverse=True)
    # by_cost is epsilon in Uma's theorem
    by_cost = [t.cost for t in tasks]
    by_cost.sort(reverse=True)

    Lambda = int(ceil(U)) - 1
    emin   = by_cost[-1]

    reduced_capacity = no_cpus - sum(by_util[0:Lambda - 1])
    if reduced_capacity <= 0:
        # bad: tardiness is not bounded
        return None

    block_idx = no_cpus - Lambda - 1
    reduced_cost = sum(by_cost[0:Lambda]) + sum(by_cost[0:block_idx]) - emin
    return int(ceil(reduced_cost / reduced_capacity))

def task_tardiness_bound(no_cpus, tasks, preemptive=True):
    x = 0
    # first check if the bound formulas are valid
    if not has_bounded_tardiness(no_cpus, tasks):
        return None
    if no_cpus > 1:
        if preemptive:
            x = tardiness_x(no_cpus, tasks)
        else:
            x = np_tardiness_x(no_cpus, tasks)
    else:
        x = 0
    return x

def has_bounded_tardiness(no_cpus, tasks):
    return tasks.utilization() <= no_cpus and \
        forall(tasks)(lambda t: t.period >= t.cost)

def bound_response_times(no_cpus, tasks, preemptive=True):
    # DA's work applies to implicit-deadline tasks
    assert forall(tasks)(lambda t: t.implicit_deadline())

    x = task_tardiness_bound(no_cpus, tasks, preemptive)
    if x is None:
        return False
    else:
        for t in tasks:
            t.response_time = t.deadline + t.cost + x
        return True