Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=2eb1b12049844a8ebc670e0e4fc908bc3f8933d3
Commit:     2eb1b12049844a8ebc670e0e4fc908bc3f8933d3
Parent:     72cb360839f88c02ccf38f1df214316e05886ff3
Author:     Christoph Hellwig <[EMAIL PROTECTED]>
AuthorDate: Tue Feb 13 21:54:29 2007 +0100
Committer:  Arnd Bergmann <[EMAIL PROTECTED]>
CommitDate: Tue Feb 13 21:55:43 2007 +0100

    [POWERPC] spu sched: static timeslicing for SCHED_RR contexts
    
    For SCHED_RR tasks we can do some really trivial timeslicing.  Basically
    we fire up a time for every scheduler tick that searches for a higher
    or same priority thread that is on the runqueue and if there is one
    context switches to it.  Because we can't lock spus from timer context
    we actually run this from a delayed runqueue instead of a timer.
    
    A nice optimization would be to skip the actual priority bitmap search
    when there are less contexts than physical spus available.  To implement
    this I need a so far unpublished patch from Andre, and it will be added
    after we have that patch in.
    
    Note that right now we only do the time slicing for SCHED_RR tasks.
    The code would work for SCHED_OTHER tasks aswell, but their prio
    value is defered from the one the PPU thread has at time of spu_run,
    and using this for spu scheduling decisions would make the code very
    unfair.  SCHED_OTHER support will be enabled once we the spu scheduler
    knows how to calculcate cpu_context.prio (very soon)
    
    Signed-off-by: Christoph Hellwig <[EMAIL PROTECTED]>
    Signed-off-by: Arnd Bergmann <[EMAIL PROTECTED]>
---
 arch/powerpc/platforms/cell/spufs/context.c |    2 +
 arch/powerpc/platforms/cell/spufs/run.c     |    9 ++++-
 arch/powerpc/platforms/cell/spufs/sched.c   |   43 ++++++++++++++++++++++++++-
 arch/powerpc/platforms/cell/spufs/spufs.h   |    5 +++
 4 files changed, 56 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/platforms/cell/spufs/context.c 
b/arch/powerpc/platforms/cell/spufs/context.c
index d581f4e..04ad2e3 100644
--- a/arch/powerpc/platforms/cell/spufs/context.c
+++ b/arch/powerpc/platforms/cell/spufs/context.c
@@ -54,7 +54,9 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang)
        if (gang)
                spu_gang_add_ctx(gang, ctx);
        ctx->rt_priority = current->rt_priority;
+       ctx->policy = current->policy;
        ctx->prio = current->prio;
+       INIT_DELAYED_WORK(&ctx->sched_work, spu_sched_tick);
        goto out;
 out_free:
        kfree(ctx);
diff --git a/arch/powerpc/platforms/cell/spufs/run.c 
b/arch/powerpc/platforms/cell/spufs/run.c
index a973e79..353a8fa 100644
--- a/arch/powerpc/platforms/cell/spufs/run.c
+++ b/arch/powerpc/platforms/cell/spufs/run.c
@@ -164,8 +164,10 @@ static inline int spu_run_init(struct spu_context *ctx, 
u32 * npc)
                        (SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE);
                if (runcntl == 0)
                        runcntl = SPU_RUNCNTL_RUNNABLE;
-       } else
+       } else {
+               spu_start_tick(ctx);
                ctx->ops->npc_write(ctx, *npc);
+       }
 
        ctx->ops->runcntl_write(ctx, runcntl);
        return ret;
@@ -176,6 +178,7 @@ static inline int spu_run_fini(struct spu_context *ctx, u32 
* npc,
 {
        int ret = 0;
 
+       spu_stop_tick(ctx);
        *status = ctx->ops->status_read(ctx);
        *npc = ctx->ops->npc_read(ctx);
        spu_release(ctx);
@@ -329,8 +332,10 @@ long spufs_run_spu(struct file *file, struct spu_context 
*ctx,
                }
                if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
                        ret = spu_reacquire_runnable(ctx, npc, &status);
-                       if (ret)
+                       if (ret) {
+                               spu_stop_tick(ctx);
                                goto out2;
+                       }
                        continue;
                }
                ret = spu_process_events(ctx);
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c 
b/arch/powerpc/platforms/cell/spufs/sched.c
index ba4b01e..2f25e68 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -44,7 +44,7 @@
 #include <asm/spu_priv1.h>
 #include "spufs.h"
 
-#define SPU_MIN_TIMESLICE      (100 * HZ / 1000)
+#define SPU_TIMESLICE  (HZ)
 
 struct spu_prio_array {
        DECLARE_BITMAP(bitmap, MAX_PRIO);
@@ -55,6 +55,7 @@ struct spu_prio_array {
 };
 
 static struct spu_prio_array *spu_prio;
+static struct workqueue_struct *spu_sched_wq;
 
 static inline int node_allowed(int node)
 {
@@ -68,6 +69,40 @@ static inline int node_allowed(int node)
        return 1;
 }
 
+void spu_start_tick(struct spu_context *ctx)
+{
+       if (ctx->policy == SCHED_RR)
+               queue_delayed_work(spu_sched_wq, &ctx->sched_work, 
SPU_TIMESLICE);
+}
+
+void spu_stop_tick(struct spu_context *ctx)
+{
+       if (ctx->policy == SCHED_RR)
+               cancel_delayed_work(&ctx->sched_work);
+}
+
+void spu_sched_tick(struct work_struct *work)
+{
+       struct spu_context *ctx =
+               container_of(work, struct spu_context, sched_work.work);
+       struct spu *spu;
+       int rearm = 1;
+
+       mutex_lock(&ctx->state_mutex);
+       spu = ctx->spu;
+       if (spu) {
+               int best = sched_find_first_bit(spu_prio->bitmap);
+               if (best <= ctx->prio) {
+                       spu_deactivate(ctx);
+                       rearm = 0;
+               }
+       }
+       mutex_unlock(&ctx->state_mutex);
+
+       if (rearm)
+               spu_start_tick(ctx);
+}
+
 /**
  * spu_add_to_active_list - add spu to active list
  * @spu:       spu to add to the active list
@@ -437,10 +472,15 @@ int __init spu_sched_init(void)
 {
        int i;
 
+       spu_sched_wq = create_singlethread_workqueue("spusched");
+       if (!spu_sched_wq)
+               return 1;
+
        spu_prio = kzalloc(sizeof(struct spu_prio_array), GFP_KERNEL);
        if (!spu_prio) {
                printk(KERN_WARNING "%s: Unable to allocate priority queue.\n",
                       __FUNCTION__);
+                      destroy_workqueue(spu_sched_wq);
                return 1;
        }
        for (i = 0; i < MAX_PRIO; i++) {
@@ -471,4 +511,5 @@ void __exit spu_sched_exit(void)
                mutex_unlock(&spu_prio->active_mutex[node]);
        }
        kfree(spu_prio);
+       destroy_workqueue(spu_sched_wq);
 }
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h 
b/arch/powerpc/platforms/cell/spufs/spufs.h
index 85b182d..0c43789 100644
--- a/arch/powerpc/platforms/cell/spufs/spufs.h
+++ b/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -82,8 +82,10 @@ struct spu_context {
 
        /* scheduler fields */
        struct list_head rq;
+       struct delayed_work sched_work;
        unsigned long sched_flags;
        unsigned long rt_priority;
+       int policy;
        int prio;
 };
 
@@ -195,6 +197,9 @@ enum {
 int spu_activate(struct spu_context *ctx, unsigned long flags);
 void spu_deactivate(struct spu_context *ctx);
 void spu_yield(struct spu_context *ctx);
+void spu_start_tick(struct spu_context *ctx);
+void spu_stop_tick(struct spu_context *ctx);
+void spu_sched_tick(struct work_struct *work);
 int __init spu_sched_init(void);
 void __exit spu_sched_exit(void);
 
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to