aboutsummaryrefslogtreecommitdiffstats
path: root/schedcat/overheads/jlfp.py
blob: d7f866c9681db7de8c54a8ea7f2e2d30c2c64a9e (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
from __future__ import division

from math import ceil, floor

def charge_initial_load(oheads, taskset):
    """Increase WCET to reflect the cost of establishing a warm cache.
    Note: assumes that .wss (working set size) has been populated in each task.
    """
    if oheads:
        for ti in taskset:
            load = oheads.initial_cache_load(ti.wss)
            assert load >= 0 # negative overheads make no sense
            ti.cost += load
            if ti.density() > 1:
                # infeasible
                return False
    return taskset

def preemption_centric_irq_costs(oheads, dedicated_irq, taskset):
    n      = len(taskset)
    qlen   = oheads.quantum_length
    tck    = oheads.tick(n)
    ev_lat = oheads.release_latency(n)

    # tick interrupt
    utick = tck / qlen

    urel  = 0.0
    if not dedicated_irq:
        rel   = oheads.release(n)
        for ti in taskset:
            urel += (rel / ti.period)

    # cost of preemption
    cpre_numerator = tck + ev_lat * utick
    if not dedicated_irq:
        cpre_numerator += n * rel + ev_lat * urel

    uscale = 1.0 - utick - urel

    return (uscale, cpre_numerator / uscale)

def charge_scheduling_overheads(oheads, num_cpus, dedicated_irq, taskset):
    if not oheads:
        return taskset

    uscale, cpre = preemption_centric_irq_costs(oheads, dedicated_irq, taskset)

    if uscale <= 0:
        # interrupt overload
        return False

    n   = len(taskset)
    wss = taskset.max_wss()

    sched = 2 * (oheads.schedule(n) + oheads.ctx_switch(n)) \
            + oheads.cache_affinity_loss(wss)

    irq_latency = oheads.release_latency(n)

    if dedicated_irq:
        unscaled = 2 * cpre + oheads.ipi_latency(n) + oheads.release(n)
    elif num_cpus > 1:
        unscaled = 2 * cpre + oheads.ipi_latency(n)
    else:
        unscaled = 2 * cpre

    for ti in taskset:
        ti.period   -= irq_latency
        ti.deadline -= irq_latency
        ti.cost      = ((ti.cost + sched) / uscale) + unscaled
        if ti.density() > 1:
            return False

    return taskset

def quantize_params(taskset):
    """After applying overheads, use this function to make
        task parameters integral again."""

    for t in taskset:
        t.cost     = int(ceil(t.cost))
        t.period   = int(floor(t.period))
        t.deadline = int(floor(t.deadline))
        if not min(t.period, t.deadline) or t.density() > 1:
            return False

    return taskset