aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--litmus/Kconfig39
-rw-r--r--litmus/edf_common.c45
2 files changed, 82 insertions, 2 deletions
diff --git a/litmus/Kconfig b/litmus/Kconfig
index 68459d4dca41..7de5b81d5d0b 100644
--- a/litmus/Kconfig
+++ b/litmus/Kconfig
@@ -79,6 +79,45 @@ config SCHED_CPU_AFFINITY
79 79
80 Say Yes if unsure. 80 Say Yes if unsure.
81 81
82choice
83 prompt "EDF Tie-Break Behavior"
84 default EDF_HASH_TIE_BREAK
85 help
86 Allows the configuration of tie-breaking behavior when the deadlines
87 of two EDF-scheduled tasks are equal.
88
89config EDF_HASH_TIE_BREAK
90 bool "Hash-based Tie Breaks"
91 help
92 Break ties between two jobs, A and B, with equal deadlines by using a
93 uniform hash; i.e.: hash(A.pid, A.job_num) < hash(B.pid, B.job_num).
94
95 This is particularly useful in overloaded systems that process
96 synchronous task sets of tasks with equal relative deadlines (ex.
97 media players). Hashing reduces the likelihood that the same task
98 loses repeated tie-break rounds, always suffering worst-case
99 response time.
100
101 Warning: It may be harder to reproduce bugs since PIDs change each
102 time a task is run.
103
104 NOTES:
105 * This feature can increase response-time jitter, but should improve
106 average case response time.
107 * Tie-break falls back to PIDs in unlikely event two hashes collide.
108
109config EDF_PID_TIE_BREAK
110 bool "PID-based Tie Breaks"
111 help
112 Break ties based upon OS-assigned process IDs. Use this option if
113 required by algorithm's real-time analysis or per-task response-time
114 jitter must be minimized in overload conditions.
115
116 NOTES:
117 * This tie-breaking method was default in Litmus 2012.2 and before.
118
119endchoice
120
82endmenu 121endmenu
83 122
84menu "Tracing" 123menu "Tracing"
diff --git a/litmus/edf_common.c b/litmus/edf_common.c
index 9b44dc2d8d1e..a603d06afe15 100644
--- a/litmus/edf_common.c
+++ b/litmus/edf_common.c
@@ -14,6 +14,35 @@
14 14
15#include <litmus/edf_common.h> 15#include <litmus/edf_common.h>
16 16
17#include <linux/hash.h>
18
19#ifdef CONFIG_EDF_HASH_TIE_BREAK
20static inline long edf_hash(struct task_struct *t)
21{
22 long key;
23 /* pid is 32 bits, so normally we would shove that into the
24 * upper 32-bits and and put the job number in the bottom
25 * and hash the 64-bit number with hash_64(). Sadly,
26 * in testing, hash_64() doesn't distribute keys were the
27 * upper bits are close together (as would be the case with
28 * pids) and job numbers are equal (as would be the case with
29 * synchronous task sets with all relative deadlines equal).
30 *
31 * A 2006 Linux patch proposed the following solution
32 * (but for some reason it wasn't accepted...).
33 *
34 * At least this workaround works for 32-bit systems as well.
35 */
36
37 /* This would be nice, but hash_64() has problems.
38 key = ((long)t->pid << 32) | ((long)tsk_rt(t)->job_params.job_no & 0xFFFFFFFF);
39 return hash_64(key, 0);
40 */
41
42 return hash_32(hash_32((u32)tsk_rt(t)->job_params.job_no, 32) ^ t->pid, 32);
43}
44#endif
45
17/* edf_higher_prio - returns true if first has a higher EDF priority 46/* edf_higher_prio - returns true if first has a higher EDF priority
18 * than second. Deadline ties are broken by PID. 47 * than second. Deadline ties are broken by PID.
19 * 48 *
@@ -25,6 +54,10 @@ int edf_higher_prio(struct task_struct* first,
25 struct task_struct *first_task = first; 54 struct task_struct *first_task = first;
26 struct task_struct *second_task = second; 55 struct task_struct *second_task = second;
27 56
57#ifdef CONFIG_EDF_HASH_TIE_BREAK
58 long fhash, shash;
59#endif
60
28 /* There is no point in comparing a task to itself. */ 61 /* There is no point in comparing a task to itself. */
29 if (first && first == second) { 62 if (first && first == second) {
30 TRACE_TASK(first, 63 TRACE_TASK(first,
@@ -63,7 +96,6 @@ int edf_higher_prio(struct task_struct* first,
63 96
64#endif 97#endif
65 98
66
67 return !is_realtime(second_task) || 99 return !is_realtime(second_task) ||
68 100
69 /* is the deadline of the first task earlier? 101 /* is the deadline of the first task earlier?
@@ -75,13 +107,22 @@ int edf_higher_prio(struct task_struct* first,
75 * Then break by PID. 107 * Then break by PID.
76 */ 108 */
77 (get_deadline(first_task) == get_deadline(second_task) && 109 (get_deadline(first_task) == get_deadline(second_task) &&
110#ifdef CONFIG_EDF_HASH_TIE_BREAK
111 /* assignment within less-than compare is intentional */
112 ((fhash = edf_hash(first_task)) < (shash = edf_hash(second_task)) ||
113 (fhash == shash &&
114#endif
78 (first_task->pid < second_task->pid || 115 (first_task->pid < second_task->pid ||
79 116
80 /* If the PIDs are the same then the task with the inherited 117 /* If the PIDs are the same then the task with the inherited
81 * priority wins. 118 * priority wins.
82 */ 119 */
83 (first_task->pid == second_task->pid && 120 (first_task->pid == second_task->pid &&
84 !second->rt_param.inh_task))); 121 !second->rt_param.inh_task))
122#ifdef CONFIG_EDF_HASH_TIE_BREAK
123 ))
124#endif
125 );
85} 126}
86 127
87int edf_ready_order(struct bheap_node* a, struct bheap_node* b) 128int edf_ready_order(struct bheap_node* a, struct bheap_node* b)