aboutsummaryrefslogtreecommitdiffstats
path: root/schedcat/sched/edf/rta.py
blob: a461b6a9999178a0ba5007f761b3dd24c89c4691 (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
"""
Implementation of Bertogna and Cirinei's response time analysis test.

    "Response-Time Analysis for Globally Scheduled Symmetric
     Multiprocessor Platforms"
    M. Bertogna and M. Cirinei,
    Proceedings of the 28th IEEE International Real-Time Systems Symposium,
    pages 149--160, 2007.

"""

from __future__ import division
from math import floor


def rta_interfering_workload(length, ti):
    "Equ. (4) and (8)"
    interval = length + ti.deadline - ti.cost - ti.rta_slack
    jobs = int(floor(interval / ti.period))
    return jobs * ti.cost + min(ti.cost, interval % ti.period)

def edf_interfering_workload(length, ti):
    "Equs. (5) and (9)"
    # implicit floor by integer division
    jobs = int(floor(length / ti.period))
    return jobs * ti.cost + \
        min(ti.cost, max(0, length % ti.period - ti.rta_slack))

def response_estimate(tk, tasks, no_cpus, response_time):
    cumulative_work = 0
    delay_limit = response_time - tk.cost + 1
    for ti in tasks:
        if ti != tk:
            cumulative_work += min(rta_interfering_workload(response_time, ti),
                                   edf_interfering_workload(tk.deadline, ti),
                                   delay_limit)
    return tk.cost + int(floor(cumulative_work / no_cpus))

def rta_fixpoint(tk, tasks, no_cpus, min_delta=None):
    """If the fixpoint search converges too slowly, then
    use min_delta to enforce a minimum step size."""
    # response time iteration, start with cost
    last, resp = tk.cost, response_estimate(tk, tasks, no_cpus, tk.cost)

    while last != resp and resp <= tk.deadline:
        if resp > last and resp - last < min_delta:
            resp = min(last + min_delta, tk.deadline)
        last, resp = resp, response_estimate(tk, tasks, no_cpus, resp)

    return resp

def is_schedulable(no_cpus, tasks, round_limit=25, min_fixpoint_step=0):
    """"Iteratively improve slack bound for each task until either the system
        is deemed to be feasible, no more improvements could be found, or
        the round limit (if given) is reached.
    """
    for t in tasks:
        t.rta_slack = 0
    updated     = True
    schedulable = False
    round       = 0

    while updated and not schedulable \
            and (not round_limit or round < round_limit):
        round += 1
        schedulable = True
        updated     = False
        for tk in tasks:
            # compute new response time bound
            response     = rta_fixpoint(tk, tasks, no_cpus,
                                        min_delta=min_fixpoint_step)
            if response <= tk.deadline:
                # this is a valid response time
                new_slack = tk.deadline - response
                if new_slack != tk.rta_slack:
                    tk.rta_slack = new_slack
                    updated = True
            else:
                # this one is currently not schedulable
                schedulable = False
    return schedulable

def bound_response_times(no_cpus, tasks, *args, **kargs):
    if is_schedulable(no_cpus, tasks, *args, **kargs):
        for t in tasks:
            t.response_time = t.deadline - t.rta_slack
        return True
    else:
        return False