diff options
| author | Jonathan Herman <hermanjl@cs.unc.edu> | 2011-09-22 19:28:49 -0400 |
|---|---|---|
| committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2011-09-22 19:28:49 -0400 |
| commit | cacc44020cbd35ff421b62f047608ebbf09fa88d (patch) | |
| tree | 90cd7c77131198e36b26c8bf859a336571114c09 | |
| parent | 06051baff7db5e0c1b80d7b2a873b022191cdcec (diff) | |
Checkpoint commit for work redistribution
| -rw-r--r-- | litmus/Kconfig | 60 | ||||
| -rw-r--r-- | litmus/sched_mc.c | 86 |
2 files changed, 121 insertions, 25 deletions
diff --git a/litmus/Kconfig b/litmus/Kconfig index b8f6a9159eb2..d629a2843584 100644 --- a/litmus/Kconfig +++ b/litmus/Kconfig | |||
| @@ -23,14 +23,42 @@ config PLUGIN_PFAIR | |||
| 23 | 23 | ||
| 24 | If unsure, say Yes. | 24 | If unsure, say Yes. |
| 25 | 25 | ||
| 26 | config MERGE_TIMERS | ||
| 27 | bool "Timer-merging Support" | ||
| 28 | depends on HIGH_RES_TIMERS | ||
| 29 | default y | ||
| 30 | help | ||
| 31 | Include support for merging timers. | ||
| 32 | |||
| 33 | config MERGE_TIMERS_WINDOW | ||
| 34 | int "Timer-merging Window (in nanoseconds)" | ||
| 35 | depends on MERGE_TIMERS | ||
| 36 | default 1000 | ||
| 37 | help | ||
| 38 | Window within which seperate timers may be merged. | ||
| 39 | |||
| 40 | config RELEASE_MASTER | ||
| 41 | bool "Release-master Support" | ||
| 42 | depends on ARCH_HAS_SEND_PULL_TIMERS | ||
| 43 | default n | ||
| 44 | help | ||
| 45 | In GSN-EDF, allow one processor to act as a dedicated interrupt | ||
| 46 | processor that services all timer interrupts, but that does not schedule | ||
| 47 | real-time tasks. See RTSS'09 paper for details | ||
| 48 | (http://www.cs.unc.edu/~anderson/papers.html). | ||
| 49 | |||
| 50 | menu "Mixed Criticality" | ||
| 51 | |||
| 26 | config PLUGIN_MC | 52 | config PLUGIN_MC |
| 27 | bool "Mixed Criticality Scheduler" | 53 | bool "Mixed Criticality Scheduler" |
| 28 | depends on X86 && SYSFS | 54 | depends on X86 && SYSFS |
| 29 | default y | 55 | default y |
| 30 | help | 56 | help |
| 31 | Included the mixed criticality scheduler. | 57 | Include the mixed criticality scheduler. This plugin depends |
| 58 | on the global release-master processor for its _REDIRECT and | ||
| 59 | _RELEASE_MASTER options. | ||
| 32 | 60 | ||
| 33 | If unsure, say Yes. | 61 | If unsure, say Yes. |
| 34 | 62 | ||
| 35 | config PLUGIN_MC_LEVEL_A_MAX_TASKS | 63 | config PLUGIN_MC_LEVEL_A_MAX_TASKS |
| 36 | int "Maximum level A tasks" | 64 | int "Maximum level A tasks" |
| @@ -38,18 +66,24 @@ config PLUGIN_MC_LEVEL_A_MAX_TASKS | |||
| 38 | range 1 128 | 66 | range 1 128 |
| 39 | default 32 | 67 | default 32 |
| 40 | help | 68 | help |
| 41 | The maximum number of level A tasks allowed (per-cpu) in level A. | 69 | The maximum number of level A tasks allowed (per-cpu) in level A. |
| 42 | 70 | ||
| 43 | config RELEASE_MASTER | 71 | config PLUGIN_MC_RELEASE_MASTER |
| 44 | bool "Release-master Support" | 72 | bool "Release-master support for MC" |
| 45 | depends on ARCH_HAS_SEND_PULL_TIMERS | 73 | depends on PLUGIN_MC && RELEASE_MASTER |
| 46 | default n | 74 | default y |
| 47 | help | 75 | help |
| 48 | Allow one processor to act as a dedicated interrupt processor | 76 | Send all timer interrupts to the system-wide release-master CPU. |
| 49 | that services all timer interrupts, but that does not schedule | 77 | |
| 50 | real-time tasks. See RTSS'09 paper for details | 78 | config PLUGIN_MC_REDIRECT |
| 51 | (http://www.cs.unc.edu/~anderson/papers.html). | 79 | bool "Redirect Work to Release-master" |
| 52 | Currently only supported by GSN-EDF. | 80 | depends on PLUGIN_MC && RELEASE_MASTER |
| 81 | default y | ||
| 82 | help | ||
| 83 | Allow processors to send work involving global state to the | ||
| 84 | release-master cpu in order to avoid excess overheads during | ||
| 85 | partitioned decisions. | ||
| 86 | endmenu | ||
| 53 | 87 | ||
| 54 | endmenu | 88 | endmenu |
| 55 | 89 | ||
diff --git a/litmus/sched_mc.c b/litmus/sched_mc.c index 0ec03b3949d2..fa2cd7ee606b 100644 --- a/litmus/sched_mc.c +++ b/litmus/sched_mc.c | |||
| @@ -40,6 +40,7 @@ typedef struct { | |||
| 40 | int usable; | 40 | int usable; |
| 41 | struct hrtimer timer; | 41 | struct hrtimer timer; |
| 42 | struct bheap_node* node; | 42 | struct bheap_node* node; |
| 43 | atomic_t dirty; | ||
| 43 | } crit_entry_t; | 44 | } crit_entry_t; |
| 44 | 45 | ||
| 45 | /** | 46 | /** |
| @@ -56,6 +57,10 @@ typedef struct { | |||
| 56 | struct task_struct* linked; | 57 | struct task_struct* linked; |
| 57 | raw_spinlock_t lock; | 58 | raw_spinlock_t lock; |
| 58 | crit_entry_t crit_entries[NUM_CRIT_LEVELS]; | 59 | crit_entry_t crit_entries[NUM_CRIT_LEVELS]; |
| 60 | #ifdef CONFIG_PLUGIN_MC_REDIRECT | ||
| 61 | struct list_head redir; | ||
| 62 | raw_spinlock_t redir_lock; | ||
| 63 | #endif | ||
| 59 | } cpu_entry_t; | 64 | } cpu_entry_t; |
| 60 | 65 | ||
| 61 | /** | 66 | /** |
| @@ -71,6 +76,9 @@ typedef struct { | |||
| 71 | } domain_data_t; | 76 | } domain_data_t; |
| 72 | 77 | ||
| 73 | static cpu_entry_t* cpus[NR_CPUS]; | 78 | static cpu_entry_t* cpus[NR_CPUS]; |
| 79 | #ifdef CONFIG_RELEASE_MASTER | ||
| 80 | static int interrupt_cpu; | ||
| 81 | #endif | ||
| 74 | 82 | ||
| 75 | #define domain_data(dom) (container_of(dom, domain_data_t, domain)) | 83 | #define domain_data(dom) (container_of(dom, domain_data_t, domain)) |
| 76 | #define is_global(dom) (domain_data(dom)->heap) | 84 | #define is_global(dom) (domain_data(dom)->heap) |
| @@ -279,8 +287,7 @@ static void link_task_to_cpu(cpu_entry_t *entry, struct task_struct *task) | |||
| 279 | * @dom Domain from which to draw higher priority task | 287 | * @dom Domain from which to draw higher priority task |
| 280 | * @ce CPU criticality level to preempt | 288 | * @ce CPU criticality level to preempt |
| 281 | * | 289 | * |
| 282 | * Caller must hold the lock for @dom and @ce's CPU lock. Returns 1 if | 290 | * Caller must hold the lock for @dom and @ce's CPU lock. |
| 283 | * a physically preemption occurred. | ||
| 284 | */ | 291 | */ |
| 285 | static void preempt(domain_t *dom, crit_entry_t *ce) | 292 | static void preempt(domain_t *dom, crit_entry_t *ce) |
| 286 | { | 293 | { |
| @@ -302,10 +309,34 @@ static void preempt(domain_t *dom, crit_entry_t *ce) | |||
| 302 | } | 309 | } |
| 303 | } | 310 | } |
| 304 | 311 | ||
| 312 | #ifdef CONFIG_PLUGIN_MC_REDIRECT | ||
| 313 | /** | ||
| 314 | * fix_global_levels() - Execute redirected job arrivals on this cpu. | ||
| 315 | */ | ||
| 316 | static void fix_global_levels(void) | ||
| 317 | { | ||
| 318 | int c; | ||
| 319 | cpu_entry_t *e; | ||
| 320 | struct list_head *pos, *safe; | ||
| 321 | struct task_struct *t; | ||
| 322 | |||
| 323 | for_each_online_cpu(c) { | ||
| 324 | e = cpus[c]; | ||
| 325 | raw_spin_lock(&e->redir_lock); | ||
| 326 | list_for_each_safe(pos, safe, &e->redir) { | ||
| 327 | t = list_entry(pos, struct task_struct, rt_param.list); | ||
| 328 | list_del(pos); | ||
| 329 | job_arrival(t); | ||
| 330 | } | ||
| 331 | raw_spin_unlock(&e->redir_lock); | ||
| 332 | } | ||
| 333 | } | ||
| 334 | #endif | ||
| 335 | |||
| 305 | /** | 336 | /** |
| 306 | * update_crit_levels() - Update criticality entries for the new cpu state. | 337 | * update_crit_levels() - Update criticality entries for the new cpu state. |
| 307 | * This should be called after a new task has been linked to @entry. | 338 | * This should be called after a new task has been linked to @entry. |
| 308 | * Assumes the caller holds @entry->lock, but this method will release it. | 339 | * The caller must hold the @entry->lock, but this method will release it. |
| 309 | */ | 340 | */ |
| 310 | static void update_crit_levels(cpu_entry_t *entry) | 341 | static void update_crit_levels(cpu_entry_t *entry) |
| 311 | { | 342 | { |
| @@ -314,24 +345,36 @@ static void update_crit_levels(cpu_entry_t *entry) | |||
| 314 | struct task_struct *tasks[NUM_CRIT_LEVELS]; | 345 | struct task_struct *tasks[NUM_CRIT_LEVELS]; |
| 315 | enum crit_level level = entry_level(entry); | 346 | enum crit_level level = entry_level(entry); |
| 316 | 347 | ||
| 317 | /* Remove tasks from entries */ | 348 | /* Remove lower priority tasks from the entry */ |
| 318 | for (i = level + 1; i < NUM_CRIT_LEVELS; i++) { | 349 | for (i = level + 1; i < NUM_CRIT_LEVELS; i++) { |
| 319 | ce = &entry->crit_entries[i]; | 350 | ce = &entry->crit_entries[i]; |
| 320 | tasks[i] = ce->linked; | 351 | tasks[i] = ce->linked; |
| 321 | ce->usable = 0; | 352 | ce->usable = 0; |
| 322 | if (ce->linked) { | 353 | if (ce->linked) |
| 323 | link_task_to_crit(ce, NULL); | 354 | link_task_to_crit(ce, NULL); |
| 324 | } | ||
| 325 | } | 355 | } |
| 326 | 356 | /* Need to unlock so we can access domains */ | |
| 327 | raw_spin_unlock(&entry->lock); | 357 | raw_spin_unlock(&entry->lock); |
| 328 | 358 | ||
| 329 | /* Put tasks back into system */ | 359 | /* Re-admit tasks to the system */ |
| 330 | for (i = level + 1; i < NUM_CRIT_LEVELS; i++) { | 360 | for (i = level + 1; i < NUM_CRIT_LEVELS; i++) { |
| 331 | ce = &entry->crit_entries[i]; | 361 | ce = &entry->crit_entries[i]; |
| 332 | if (tasks[i]) { | 362 | TRACE("Checking %s\n", ce->domain->name); |
