aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2007-06-28 20:57:52 -0400
committerPaul Mackerras <paulus@samba.org>2007-07-03 01:24:44 -0400
commitfe443ef2ac421c9c652e251e8733e2479d8e411a (patch)
tree60914cfaf29232b9c3d4f555eac3b19b85a84254
parent379018022071489a7dffee74db2a267465dab561 (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.c15
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c54
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h4
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;
61out_free: 70out_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
51struct spu_prio_array { 47struct 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;
60static struct task_struct *spusched_task; 56static struct task_struct *spusched_task;
61static struct timer_list spusched_timer; 57static 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 */
91void 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
63static inline int node_allowed(int node) 99static 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
425static void spusched_tick(struct spu_context *ctx) 461static 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 */
37enum { 35enum {
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);
197int spu_activate(struct spu_context *ctx, unsigned long flags); 194int spu_activate(struct spu_context *ctx, unsigned long flags);
198void spu_deactivate(struct spu_context *ctx); 195void spu_deactivate(struct spu_context *ctx);
199void spu_yield(struct spu_context *ctx); 196void spu_yield(struct spu_context *ctx);
197void spu_set_timeslice(struct spu_context *ctx);
200int __init spu_sched_init(void); 198int __init spu_sched_init(void);
201void __exit spu_sched_exit(void); 199void __exit spu_sched_exit(void);
202 200