[Cbe-oss-dev] [PATCH 5/6] spufs: add placement computation for scheduling of affinity contexts

Andre Detsch adetsch at br.ibm.com
Mon Feb 12 12:16:45 EST 2007


Subject: spufs: add placement computation for scheduling of affinity contexts
From: Andre Detsch <adetsch at br.ibm.com>

This patch provides the spu affinity placement logic for the spufs scheduler.
Each time a gang is going to be scheduled, the placement of a reference
context is defined. The placement of all other contexts with affinity from
the gang is defined based on this reference context location and on a
precomputed displacement offset.

Signed-off-by: Andre Detsch <adetsch at br.ibm.com>


Index: linux-2.6.20/arch/powerpc/platforms/cell/spufs/sched.c
===================================================================
--- linux-2.6.20.orig/arch/powerpc/platforms/cell/spufs/sched.c
+++ linux-2.6.20/arch/powerpc/platforms/cell/spufs/sched.c
@@ -141,6 +141,8 @@ static void spu_bind_context(struct spu 
 {
 	pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid,
 		 spu->number, spu->node);
+	if (ctx->aff_flags & (AFF_HAS_SPU_AFFINITY | AFF_HAS_MEM_AFFINITY))
+		atomic_inc(&ctx->gang->aff_sched_count);
 	spu->ctx = ctx;
 	spu->flags = 0;
 	ctx->spu = spu;
@@ -177,6 +179,11 @@ static int spu_unbind_context(struct spu
 	pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__,
 		 spu->pid, spu->number, spu->node);
 
+	if (ctx->aff_flags & (AFF_HAS_SPU_AFFINITY | AFF_HAS_MEM_AFFINITY)) {
+		if (atomic_dec_and_test(&ctx->gang->aff_sched_count))
+			ctx->gang->aff_ref_point_location = NULL;
+	}
+
 	spu_switch_notify(spu, NULL);
 	spu_unmap_mappings(ctx);
 	spu_save(&ctx->csa, spu);
@@ -413,3 +420,126 @@ void __exit spu_sched_exit(void)
 	}
 	kfree(spu_prio);
 }
+
+static void aff_merge_remaining_ctxs(struct spu_gang *gang)
+{
+	struct spu_context *ctx;
+
+	list_for_each_entry(ctx, &gang->aff_list_head, aff_list) {
+		if (list_empty(&ctx->aff_list)) {
+			list_add(&ctx->aff_list, &gang->aff_list_head);
+			ctx->aff_flags |= AFF_HAS_SPU_AFFINITY;
+		}
+	}
+	gang->aff_flags |= AFF_MERGED;
+}
+
+static void aff_set_rel_displ(struct spu_gang *gang)
+{
+	struct spu_context *ctx;
+	int displacement;
+
+	displacement = -1;
+	list_for_each_entry_reverse(ctx, &gang->aff_ref_point->aff_list,
+								aff_list) {
+		if (&ctx->aff_list == &gang->aff_list_head)
+			break;
+		ctx->aff_rel_displ = displacement--;
+	}
+
+	displacement = 0;
+	list_for_each_entry(ctx, gang->aff_ref_point->aff_list.prev, aff_list) {
+		if (&ctx->aff_list == &gang->aff_list_head)
+			break;
+		ctx->aff_rel_displ = displacement++;
+	}
+
+	gang->aff_flags |= AFF_REL_DISPL_SET;
+}
+
+static struct spu *
+aff_ref_location(int mem_aff, int group_size, int prio, int lowest_rel_displ)
+{
+	struct spu *spu;
+	int node;
+
+	/* TODO: A better algorithm could be used to find a good spu to be
+	 *       used as reference location for the ctxs chain.
+	 *       Also, a isolated SPU should never be chosen here.
+	 */
+	for (node = 0; node < MAX_NUMNODES; node++) {
+		list_for_each_entry(spu, &be_spu_info[node].available_spus,
+							available_list) {
+			if (!mem_aff || spu->has_mem_affinity)
+				return spu;
+		}
+	}
+	BUG_ON(1);
+	return NULL;
+}
+
+static void aff_set_ref_point_location(struct spu_gang *gang)
+{
+	int mem_aff, gs, lowest_rel_displ;
+	struct spu_context *ctx;
+	struct spu *tmp;
+
+	mem_aff = gang->aff_ref_point->aff_flags & AFF_HAS_MEM_AFFINITY;
+	lowest_rel_displ = 0;
+	gs = 0;
+	list_for_each_entry(tmp, &gang->aff_list_head, aff_list)
+		gs++;
+
+	list_for_each_entry_reverse(ctx, &gang->aff_ref_point->aff_list,
+								aff_list) {
+		if (&ctx->aff_list == &gang->aff_list_head)
+			break;
+		lowest_rel_displ = ctx->aff_rel_displ;
+	}
+
+	gang->aff_ref_point_location = aff_ref_location(mem_aff, gs, ctx->prio,
+							lowest_rel_displ);
+}
+
+static struct spu* ctx_location(struct spu *ref, int rel_displ)
+{
+	struct spu *spu;
+
+	/* TODO: skip isolated SPUs */
+	if (rel_displ >= 0) {
+		list_for_each_entry(spu, ref->aff_list.prev, aff_list) {
+			if (rel_displ == 0)
+				return spu;
+			rel_displ--;
+		}
+	} else {
+		list_for_each_entry_reverse(spu, ref->aff_list.next, aff_list) {
+			if (rel_displ == 0)
+				return spu;
+			rel_displ++;
+		}
+	}
+	return NULL;
+}
+
+/**
+ * affinity_check is called each time a context is going to be scheduled.
+ * It returns the spu ptr on which the context must run.
+ */
+struct spu* affinity_check(struct spu_context *ctx)
+{
+	struct spu_gang *gang;
+
+	if (list_empty(&ctx->aff_list))
+		return NULL;
+	gang = ctx->gang;
+	if (!gang->aff_ref_point_location) {
+		if (!gang->aff_flags & AFF_MERGED)
+			aff_merge_remaining_ctxs(gang);
+		if (!gang->aff_flags & AFF_REL_DISPL_SET)
+			aff_set_rel_displ(gang);
+		aff_set_ref_point_location(gang);
+	}
+	BUG_ON(!gang->aff_ref_point_location);
+	return ctx_location(gang->aff_ref_point_location, ctx->aff_rel_displ);
+}
Index: linux-2.6.20/arch/powerpc/platforms/cell/spufs/spufs.h
===================================================================
--- linux-2.6.20.orig/arch/powerpc/platforms/cell/spufs/spufs.h
+++ linux-2.6.20/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -85,6 +85,7 @@ struct spu_context {
 
 	struct list_head aff_list;
 	int aff_flags;
+	int aff_rel_displ;
 };
 
 /* Flag bits for spu_context aff_flags */
@@ -102,6 +103,8 @@ struct spu_gang {
 	struct list_head aff_list_head;
 	struct mutex aff_mutex;
 	int aff_flags;
+	struct spu *aff_ref_point_location;
+	atomic_t aff_sched_count;
 };
 
 /* Flag bits for spu_gang aff_flags */
@@ -182,6 +185,9 @@ int put_spu_gang(struct spu_gang *gang);
 void spu_gang_remove_ctx(struct spu_gang *gang, struct spu_context *ctx);
 void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx);
 
+/* affinity */
+struct spu *affinity_check(struct spu_context *ctx);
+
 /* context management */
 static inline void spu_acquire(struct spu_context *ctx)
 {
Index: linux-2.6.20/arch/powerpc/platforms/cell/spufs/gang.c
===================================================================
--- linux-2.6.20.orig/arch/powerpc/platforms/cell/spufs/gang.c
+++ linux-2.6.20/arch/powerpc/platforms/cell/spufs/gang.c
@@ -39,6 +39,7 @@ struct spu_gang *alloc_spu_gang(void)
 	INIT_LIST_HEAD(&gang->list);
 	INIT_LIST_HEAD(&gang->aff_list_head);
 
+	gang->aff_ref_point_location = NULL;
 out:
 	return gang;
 }
@@ -77,8 +78,10 @@ void spu_gang_remove_ctx(struct spu_gang
 	WARN_ON(ctx->gang != gang);
 	list_del_init(&ctx->gang_list);
 	gang->contexts--;
-	if (ctx->aff_flags & (AFF_HAS_SPU_AFFINITY | AFF_HAS_MEM_AFFINITY))
+	if (ctx->aff_flags & (AFF_HAS_SPU_AFFINITY | AFF_HAS_MEM_AFFINITY)) {
 		list_del(&ctx->aff_list);
+		gang->aff_flags &= ~AFF_REL_DISPL_SET;
+	}
 	mutex_unlock(&gang->mutex);
 
 	put_spu_gang(gang);

--
Andre Detsch



More information about the cbe-oss-dev mailing list