From patchwork Wed Dec 10 19:40:48 2008 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andre Detsch X-Patchwork-Id: 13314 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from ozlabs.org (localhost [127.0.0.1]) by ozlabs.org (Postfix) with ESMTP id 58FA2474F5 for ; Thu, 11 Dec 2008 06:45:27 +1100 (EST) X-Original-To: cbe-oss-dev@ozlabs.org Delivered-To: cbe-oss-dev@ozlabs.org Received: from igw1.br.ibm.com (igw1.br.ibm.com [32.104.18.24]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id BBEBEDDFB5 for ; Thu, 11 Dec 2008 06:40:54 +1100 (EST) Received: from d24relay01.br.ibm.com (unknown [9.8.31.16]) by igw1.br.ibm.com (Postfix) with ESMTP id 06CDC32C06C for ; Wed, 10 Dec 2008 17:36:49 -0200 (BRDT) Received: from d24av01.br.ibm.com (d24av01.br.ibm.com [9.18.232.46]) by d24relay01.br.ibm.com (8.13.8/8.13.8/NCO v9.1) with ESMTP id mBAKeOdY3747964 for ; Wed, 10 Dec 2008 17:40:24 -0300 Received: from d24av01.br.ibm.com (loopback [127.0.0.1]) by d24av01.br.ibm.com (8.12.11.20060308/8.13.3) with ESMTP id mBAJeoqU017679 for ; Wed, 10 Dec 2008 17:40:50 -0200 Received: from [9.8.13.23] ([9.8.13.23]) by d24av01.br.ibm.com (8.12.11.20060308/8.12.11) with ESMTP id mBAJegsd017084 for ; Wed, 10 Dec 2008 17:40:50 -0200 From: Andre Detsch To: cbe-oss-dev@ozlabs.org Date: Wed, 10 Dec 2008 17:40:48 -0200 User-Agent: KMail/1.9.6 References: <200812101719.42964.adetsch@br.ibm.com> In-Reply-To: <200812101719.42964.adetsch@br.ibm.com> MIME-Version: 1.0 Content-Disposition: inline Message-Id: <200812101740.48939.adetsch@br.ibm.com> Subject: [Cbe-oss-dev] [PATCH 11/18] powerpc/spufs: Implement SPU affinity on top of gang scheduling X-BeenThere: cbe-oss-dev@ozlabs.org X-Mailman-Version: 2.1.11 Precedence: list List-Id: Discussion about Open Source Software for the Cell Broadband Engine List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: cbe-oss-dev-bounces+patchwork-incoming=ozlabs.org@ozlabs.org Errors-To: cbe-oss-dev-bounces+patchwork-incoming=ozlabs.org@ozlabs.org SPU affinity, originally implemented before we had gang scheduling, was disabled after gang scheduling was introduced. This patch re-enables SPU affinity, making it fit the new scheduling algorithm. Signed-off-by: Andre Detsch --- arch/powerpc/platforms/cell/spufs/sched.c | 185 ++++++++++++++--------------- arch/powerpc/platforms/cell/spufs/spufs.h | 1 - 2 files changed, 88 insertions(+), 98 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 3bc0308..5289cdb 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -349,16 +349,58 @@ static void aff_set_offsets(struct spu_gang *gang) gang->aff_flags |= AFF_OFFSETS_SET; } -static struct spu *aff_ref_location(struct spu_context *ctx, int mem_aff, - int group_size, int lowest_offset) + +static inline int is_spu_available(struct spu *spu, struct spu_gang *gang) +{ + return spu->alloc_state == SPU_FREE && (!spu->gang || spu->gang == gang); +} + +static struct spu *ctx_location(struct spu *ref, int offset, + struct spu_gang *gang, int reserve) +{ + struct spu *spu; + + if (!offset) + return ref; + + if (offset > 0) { + offset--; + list_for_each_entry(spu, &ref->aff_list, aff_list) { + if ((reserve && is_spu_available(spu, gang)) || + (!reserve && spu->gang == gang)) + if (!offset--) + return spu; + } + } else { + offset++; + list_for_each_entry_reverse(spu, &ref->aff_list, aff_list) { + if ((reserve && is_spu_available(spu, gang)) || + (!reserve && spu->gang == gang)) + if (!offset++) + return spu; + } + } + + return NULL; +} + +static int aff_place_gang(struct spu_gang *gang) { struct spu *spu; int node, n; + struct spu_context *ctx; + int mem_aff; + + + BUG_ON(list_empty(&gang->aff_list_head)); + + if (!(gang->aff_flags & AFF_MERGED)) + aff_merge_remaining_ctxs(gang); + if (!(gang->aff_flags & AFF_OFFSETS_SET)) + aff_set_offsets(gang); + + mem_aff = gang->aff_ref_ctx->flags & SPU_CREATE_AFFINITY_MEM; - /* - * TODO: A better algorithm could be used to find a good spu to be - * used as reference location for the ctxs chain. - */ node = cpu_to_node(raw_smp_processor_id()); for (n = 0; n < MAX_NUMNODES; n++, node++) { /* @@ -373,109 +415,51 @@ static struct spu *aff_ref_location(struct spu_context *ctx, int mem_aff, int available_spus; node = (node < MAX_NUMNODES) ? node : 0; - if (!node_allowed(ctx->gang, node)) + if (!node_allowed(gang, node)) continue; available_spus = 0; mutex_lock(&cbe_spu_info[node].list_mutex); list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) { - if (spu->ctx && spu->ctx->gang && !spu->ctx->aff_offset - && spu->ctx->gang->aff_ref_spu) - available_spus -= spu->ctx->gang->contexts; - available_spus++; + if (is_spu_available(spu, gang)) + available_spus++; } - if (available_spus < ctx->gang->contexts) { + if (available_spus < gang->contexts) { mutex_unlock(&cbe_spu_info[node].list_mutex); continue; } list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) { if ((!mem_aff || spu->has_mem_affinity) && - sched_spu(spu)) { - mutex_unlock(&cbe_spu_info[node].list_mutex); - return spu; - } + is_spu_available(spu, gang)) + gang->aff_ref_spu = spu; } - mutex_unlock(&cbe_spu_info[node].list_mutex); - } - return NULL; -} -static void aff_set_ref_point_location(struct spu_gang *gang) -{ - int mem_aff, gs, lowest_offset; - struct spu_context *ctx; - struct spu *tmp; - - mem_aff = gang->aff_ref_ctx->flags & SPU_CREATE_AFFINITY_MEM; - lowest_offset = 0; - gs = 0; + if (!gang->aff_ref_spu) { + list_for_each_entry(spu, &cbe_spu_info[node].spus, + cbe_list) { + if (is_spu_available(spu, gang)) + gang->aff_ref_spu = spu; + } + } - list_for_each_entry(tmp, &gang->aff_list_head, aff_list) - gs++; + list_for_each_entry(ctx, &gang->list, gang_list) { + spu = ctx_location(gang->aff_ref_spu, ctx->aff_offset, + gang, 1); + BUG_ON(!spu); + spu->gang = gang; + } - list_for_each_entry_reverse(ctx, &gang->aff_ref_ctx->aff_list, - aff_list) { - if (&ctx->aff_list == &gang->aff_list_head) - break; - lowest_offset = ctx->aff_offset; + mutex_unlock(&cbe_spu_info[node].list_mutex); + return 1; } - - gang->aff_ref_spu = aff_ref_location(gang->aff_ref_ctx, mem_aff, gs, - lowest_offset); + return 0; } -static struct spu *ctx_location(struct spu *ref, int offset, int node) -{ - struct spu *spu; - - spu = NULL; - if (offset >= 0) { - list_for_each_entry(spu, ref->aff_list.prev, aff_list) { - BUG_ON(spu->node != node); - if (offset == 0) - break; - if (sched_spu(spu)) - offset--; - } - } else { - list_for_each_entry_reverse(spu, ref->aff_list.next, aff_list) { - BUG_ON(spu->node != node); - if (offset == 0) - break; - if (sched_spu(spu)) - offset++; - } - } - - return spu; -} -/* - * affinity_check is called each time a context is going to be scheduled. - * It returns the spu ptr on which the context must run. - */ static int has_affinity(struct spu_gang *gang) { - if (list_empty(&gang->aff_list_head)) - return 0; - - /* - * TODO: fix SPU Affinity to work with gang scheduling. - */ - - if (atomic_read(&gang->aff_sched_count) == 0) - gang->aff_ref_spu = NULL; - - if (!gang->aff_ref_spu) { - if (!(gang->aff_flags & AFF_MERGED)) - aff_merge_remaining_ctxs(gang); - if (!(gang->aff_flags & AFF_OFFSETS_SET)) - aff_set_offsets(gang); - aff_set_ref_point_location(gang); - } - - return gang->aff_ref_spu != NULL; + return !list_empty(&gang->aff_list_head); } /** @@ -491,17 +475,9 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx) spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); - if (spu->ctx->flags & SPU_CREATE_NOSCHED) + if (spu->ctx->flags & SPU_CREATE_NOSCHED) atomic_dec(&cbe_spu_info[spu->node].reserved_spus); - if (ctx->gang) - /* - * If ctx->gang->aff_sched_count is positive, SPU affinity is - * being considered in this gang. Using atomic_dec_if_positive - * allow us to skip an explicit check for affinity in this gang - */ - atomic_dec_if_positive(&ctx->gang->aff_sched_count); - spu_switch_notify(spu, NULL); spu_unmap_mappings(ctx); spu_save(&ctx->csa, spu); @@ -591,6 +567,16 @@ static struct spu *spu_bind(struct spu_gang *gang, if (node == SPU_PLACE_ALL) node = cpu_to_node(raw_smp_processor_id()); + if (gang->aff_ref_spu) { + mutex_lock(&cbe_spu_info[gang->aff_ref_spu->node].list_mutex); + spu = ctx_location(gang->aff_ref_spu, ctx->aff_offset, gang, 0); + BUG_ON(!spu); + BUG_ON(spu->alloc_state != SPU_FREE); + BUG_ON(spu->gang != gang); + mutex_unlock(&cbe_spu_info[gang->aff_ref_spu->node].list_mutex); + goto found; + } + for (n = 0; n < MAX_NUMNODES; n++, node++) { node = (node < MAX_NUMNODES) ? node : 0; if (!node_allowed(gang, node)) @@ -660,6 +646,7 @@ static void spu_unschedule(struct spu_gang *gang) mutex_unlock(&cbe_spu_info[node].list_mutex); mutex_unlock(&ctx->state_mutex); } + gang->aff_ref_spu = NULL; } static int spu_get_idle(struct spu_gang *gang, int node) @@ -670,7 +657,10 @@ static int spu_get_idle(struct spu_gang *gang, int node) spu_context_nospu_trace(spu_get_idle__enter, gang); - /* TO DO: SPU affinity scheduling. */ + if (has_affinity(gang) && (!gang->aff_ref_spu)) { + if (aff_place_gang(gang)) + goto spu_get_idle_out; + } mode = SPU_RESERVE; @@ -690,6 +680,7 @@ spu_get_idle_top: continue; mutex_lock(&cbe_spu_info[lnode].list_mutex); + list_for_each_entry(spu, &cbe_spu_info[lnode].spus, cbe_list) { switch (mode) { case SPU_RESERVE : diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index bbbfc6a..468ee37 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -177,7 +177,6 @@ struct spu_gang { struct mutex aff_mutex; int aff_flags; struct spu *aff_ref_spu; - atomic_t aff_sched_count; /* spu scheduler statistics for zombie ctxts */ struct {