diff options
author | Christoph Hellwig <hch@lst.de> | 2007-06-28 20:57:52 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-07-03 01:24:44 -0400 |
commit | fe443ef2ac421c9c652e251e8733e2479d8e411a (patch) | |
tree | 60914cfaf29232b9c3d4f555eac3b19b85a84254 | |
parent | 379018022071489a7dffee74db2a267465dab561 (diff) |
[POWERPC] spusched: Dynamic timeslicing for SCHED_OTHER
Enable preemptive scheduling for non-RT contexts.
We use the same algorithms as the CPU scheduler to calculate the time
slice length, and for now we also use the same timeslice length as the
CPU scheduler. This might be not enough for good performance and can be
changed after some benchmarking.
Note that currently we do not boost the priority for contexts waiting
on the runqueue for a long time, so contexts with a higher nice value
could starve ones with less priority. This could easily be fixed once
the rework of the spu lists that Luke and I discussed is done.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/context.c | 15 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/sched.c | 54 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/spufs.h | 4 |
3 files changed, 58 insertions, 15 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index f084667e4f50..c5ec7cfc24b5 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c | |||
@@ -53,10 +53,19 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang) | |||
53 | INIT_LIST_HEAD(&ctx->rq); | 53 | INIT_LIST_HEAD(&ctx->rq); |
54 | if (gang) | 54 | if (gang) |
55 | spu_gang_add_ctx(gang, ctx); | 55 | spu_gang_add_ctx(gang, ctx); |
56 | ctx->rt_priority = current->rt_priority; | 56 | |
57 | /* | ||
58 | * We do our own priority calculations, so we normally want | ||
59 | * ->static_prio to start with. Unfortunately thies field | ||
60 | * contains junk for threads with a realtime scheduling | ||
61 | * policy so we have to look at ->prio in this case. | ||
62 | */ | ||
63 | if (rt_prio(current->prio)) | ||
64 | ctx->prio = current->prio; | ||
65 | else | ||
66 | ctx->prio = current->static_prio; | ||
57 | ctx->policy = current->policy; | 67 | ctx->policy = current->policy; |
58 | ctx->prio = current->prio; | 68 | spu_set_timeslice(ctx); |
59 | ctx->time_slice = SPU_DEF_TIMESLICE; | ||
60 | goto out; | 69 | goto out; |
61 | out_free: | 70 | out_free: |
62 | kfree(ctx); | 71 | kfree(ctx); |
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index d673353b6d33..1b2916bdc1c8 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c | |||
@@ -44,10 +44,6 @@ | |||
44 | #include <asm/spu_priv1.h> | 44 | #include <asm/spu_priv1.h> |
45 | #include "spufs.h" | 45 | #include "spufs.h" |
46 | 46 | ||
47 | #define SPU_TIMESLICE (HZ) | ||
48 | |||
49 | #define SPUSCHED_TICK (HZ / 100) | ||
50 | |||
51 | struct spu_prio_array { | 47 | struct spu_prio_array { |
52 | DECLARE_BITMAP(bitmap, MAX_PRIO); | 48 | DECLARE_BITMAP(bitmap, MAX_PRIO); |
53 | struct list_head runq[MAX_PRIO]; | 49 | struct list_head runq[MAX_PRIO]; |
@@ -60,6 +56,46 @@ static struct spu_prio_array *spu_prio; | |||
60 | static struct task_struct *spusched_task; | 56 | static struct task_struct *spusched_task; |
61 | static struct timer_list spusched_timer; | 57 | static struct timer_list spusched_timer; |
62 | 58 | ||
59 | /* | ||
60 | * Priority of a normal, non-rt, non-niced'd process (aka nice level 0). | ||
61 | */ | ||
62 | #define NORMAL_PRIO 120 | ||
63 | |||
64 | /* | ||
65 | * Frequency of the spu scheduler tick. By default we do one SPU scheduler | ||
66 | * tick for every 10 CPU scheduler ticks. | ||
67 | */ | ||
68 | #define SPUSCHED_TICK (10) | ||
69 | |||
70 | /* | ||
71 | * These are the 'tuning knobs' of the scheduler: | ||
72 | * | ||
73 | * Minimum timeslice is 5 msecs (or 10 jiffies, whichever is larger), | ||
74 | * default timeslice is 100 msecs, maximum timeslice is 800 msecs. | ||
75 | */ | ||
76 | #define MIN_SPU_TIMESLICE max(5 * HZ / 100, 10) | ||
77 | #define DEF_SPU_TIMESLICE (100 * HZ / 100) | ||
78 | |||
79 | #define MAX_USER_PRIO (MAX_PRIO - MAX_RT_PRIO) | ||
80 | #define SCALE_PRIO(x, prio) \ | ||
81 | max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO / 2), MIN_SPU_TIMESLICE) | ||
82 | |||
83 | /* | ||
84 | * scale user-nice values [ -20 ... 0 ... 19 ] to time slice values: | ||
85 | * [800ms ... 100ms ... 5ms] | ||
86 | * | ||
87 | * The higher a thread's priority, the bigger timeslices | ||
88 | * it gets during one round of execution. But even the lowest | ||
89 | * priority thread gets MIN_TIMESLICE worth of execution time. | ||
90 | */ | ||
91 | void spu_set_timeslice(struct spu_context *ctx) | ||
92 | { | ||
93 | if (ctx->prio < NORMAL_PRIO) | ||
94 | ctx->time_slice = SCALE_PRIO(DEF_SPU_TIMESLICE * 4, ctx->prio); | ||
95 | else | ||
96 | ctx->time_slice = SCALE_PRIO(DEF_SPU_TIMESLICE, ctx->prio); | ||
97 | } | ||
98 | |||
63 | static inline int node_allowed(int node) | 99 | static inline int node_allowed(int node) |
64 | { | 100 | { |
65 | cpumask_t mask; | 101 | cpumask_t mask; |
@@ -265,8 +301,8 @@ static struct spu *find_victim(struct spu_context *ctx) | |||
265 | list_for_each_entry(spu, &spu_prio->active_list[node], list) { | 301 | list_for_each_entry(spu, &spu_prio->active_list[node], list) { |
266 | struct spu_context *tmp = spu->ctx; | 302 | struct spu_context *tmp = spu->ctx; |
267 | 303 | ||
268 | if (tmp->rt_priority < ctx->rt_priority && | 304 | if (tmp->prio > ctx->prio && |
269 | (!victim || tmp->rt_priority < victim->rt_priority)) | 305 | (!victim || tmp->prio > victim->prio)) |
270 | victim = spu->ctx; | 306 | victim = spu->ctx; |
271 | } | 307 | } |
272 | mutex_unlock(&spu_prio->active_mutex[node]); | 308 | mutex_unlock(&spu_prio->active_mutex[node]); |
@@ -333,7 +369,7 @@ int spu_activate(struct spu_context *ctx, unsigned long flags) | |||
333 | * If this is a realtime thread we try to get it running by | 369 | * If this is a realtime thread we try to get it running by |
334 | * preempting a lower priority thread. | 370 | * preempting a lower priority thread. |
335 | */ | 371 | */ |
336 | if (!spu && ctx->rt_priority) | 372 | if (!spu && rt_prio(ctx->prio)) |
337 | spu = find_victim(ctx); | 373 | spu = find_victim(ctx); |
338 | if (spu) { | 374 | if (spu) { |
339 | spu_bind_context(spu, ctx); | 375 | spu_bind_context(spu, ctx); |
@@ -424,7 +460,7 @@ void spu_yield(struct spu_context *ctx) | |||
424 | 460 | ||
425 | static void spusched_tick(struct spu_context *ctx) | 461 | static void spusched_tick(struct spu_context *ctx) |
426 | { | 462 | { |
427 | if (ctx->policy != SCHED_RR || --ctx->time_slice) | 463 | if (ctx->policy == SCHED_FIFO || --ctx->time_slice) |
428 | return; | 464 | return; |
429 | 465 | ||
430 | /* | 466 | /* |
@@ -448,7 +484,7 @@ static void spusched_tick(struct spu_context *ctx) | |||
448 | */ | 484 | */ |
449 | wake_up(&ctx->stop_wq); | 485 | wake_up(&ctx->stop_wq); |
450 | } | 486 | } |
451 | ctx->time_slice = SPU_DEF_TIMESLICE; | 487 | spu_set_timeslice(ctx); |
452 | mutex_unlock(&ctx->state_mutex); | 488 | mutex_unlock(&ctx->state_mutex); |
453 | } else { | 489 | } else { |
454 | ctx->time_slice++; | 490 | ctx->time_slice++; |
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 8068171dfa9c..fddc59c204b5 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h | |||
@@ -31,8 +31,6 @@ | |||
31 | #include <asm/spu_csa.h> | 31 | #include <asm/spu_csa.h> |
32 | #include <asm/spu_info.h> | 32 | #include <asm/spu_info.h> |
33 | 33 | ||
34 | #define SPU_DEF_TIMESLICE 100 | ||
35 | |||
36 | /* The magic number for our file system */ | 34 | /* The magic number for our file system */ |
37 | enum { | 35 | enum { |
38 | SPUFS_MAGIC = 0x23c9b64e, | 36 | SPUFS_MAGIC = 0x23c9b64e, |
@@ -82,7 +80,6 @@ struct spu_context { | |||
82 | struct list_head rq; | 80 | struct list_head rq; |
83 | unsigned int time_slice; | 81 | unsigned int time_slice; |
84 | unsigned long sched_flags; | 82 | unsigned long sched_flags; |
85 | unsigned long rt_priority; | ||
86 | int policy; | 83 | int policy; |
87 | int prio; | 84 | int prio; |
88 | }; | 85 | }; |
@@ -197,6 +194,7 @@ void spu_acquire_saved(struct spu_context *ctx); | |||
197 | int spu_activate(struct spu_context *ctx, unsigned long flags); | 194 | int spu_activate(struct spu_context *ctx, unsigned long flags); |
198 | void spu_deactivate(struct spu_context *ctx); | 195 | void spu_deactivate(struct spu_context *ctx); |
199 | void spu_yield(struct spu_context *ctx); | 196 | void spu_yield(struct spu_context *ctx); |
197 | void spu_set_timeslice(struct spu_context *ctx); | ||
200 | int __init spu_sched_init(void); | 198 | int __init spu_sched_init(void); |
201 | void __exit spu_sched_exit(void); | 199 | void __exit spu_sched_exit(void); |
202 | 200 | ||