aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c24
-rw-r--r--arch/powerpc/platforms/cell/spufs/context.c3
-rw-r--r--arch/powerpc/platforms/cell/spufs/fault.c8
-rw-r--r--arch/powerpc/platforms/cell/spufs/file.c32
-rw-r--r--arch/powerpc/platforms/cell/spufs/run.c10
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c22
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h63
-rw-r--r--include/asm-powerpc/spu.h10
8 files changed, 94 insertions, 78 deletions
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index c563066e640..caaf2bf78ca 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -553,6 +553,7 @@ static int __init create_spu(void *data)
int ret;
static int number;
unsigned long flags;
+ struct timespec ts;
ret = -ENOMEM;
spu = kzalloc(sizeof (*spu), GFP_KERNEL);
@@ -586,8 +587,9 @@ static int __init create_spu(void *data)
spin_unlock_irqrestore(&spu_list_lock, flags);
mutex_unlock(&spu_mutex);
- spu->stats.utilization_state = SPU_UTIL_IDLE;
- spu->stats.tstamp = jiffies;
+ spu->stats.util_state = SPU_UTIL_IDLE_LOADED;
+ ktime_get_ts(&ts);
+ spu->stats.tstamp = timespec_to_ns(&ts);
goto out;
@@ -608,12 +610,20 @@ static const char *spu_state_names[] = {
static unsigned long long spu_acct_time(struct spu *spu,
enum spu_utilization_state state)
{
+ struct timespec ts;
unsigned long long time = spu->stats.times[state];
- if (spu->stats.utilization_state == state)
- time += jiffies - spu->stats.tstamp;
+ /*
+ * If the spu is idle or the context is stopped, utilization
+ * statistics are not updated. Apply the time delta from the
+ * last recorded state of the spu.
+ */
+ if (spu->stats.util_state == state) {
+ ktime_get_ts(&ts);
+ time += timespec_to_ns(&ts) - spu->stats.tstamp;
+ }
- return jiffies_to_msecs(time);
+ return time / NSEC_PER_MSEC;
}
@@ -623,11 +633,11 @@ static ssize_t spu_stat_show(struct sys_device *sysdev, char *buf)
return sprintf(buf, "%s %llu %llu %llu %llu "
"%llu %llu %llu %llu %llu %llu %llu %llu\n",
- spu_state_names[spu->stats.utilization_state],
+ spu_state_names[spu->stats.util_state],
spu_acct_time(spu, SPU_UTIL_USER),
spu_acct_time(spu, SPU_UTIL_SYSTEM),
spu_acct_time(spu, SPU_UTIL_IOWAIT),
- spu_acct_time(spu, SPU_UTIL_IDLE),
+ spu_acct_time(spu, SPU_UTIL_IDLE_LOADED),
spu->stats.vol_ctx_switch,
spu->stats.invol_ctx_switch,
spu->stats.slb_flt,
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c
index 6d7bd60f538..0e5e55f53c8 100644
--- a/arch/powerpc/platforms/cell/spufs/context.c
+++ b/arch/powerpc/platforms/cell/spufs/context.c
@@ -59,8 +59,7 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang)
spu_gang_add_ctx(gang, ctx);
ctx->cpus_allowed = current->cpus_allowed;
spu_set_timeslice(ctx);
- ctx->stats.execution_state = SPUCTX_UTIL_USER;
- ctx->stats.tstamp = jiffies;
+ ctx->stats.util_state = SPU_UTIL_IDLE_LOADED;
atomic_inc(&nr_spu_contexts);
goto out;
diff --git a/arch/powerpc/platforms/cell/spufs/fault.c b/arch/powerpc/platforms/cell/spufs/fault.c
index f53a0743747..917eab4be48 100644
--- a/arch/powerpc/platforms/cell/spufs/fault.c
+++ b/arch/powerpc/platforms/cell/spufs/fault.c
@@ -179,16 +179,14 @@ int spufs_handle_class1(struct spu_context *ctx)
if (!(dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)))
return 0;
- spuctx_switch_state(ctx, SPUCTX_UTIL_IOWAIT);
+ spuctx_switch_state(ctx, SPU_UTIL_IOWAIT);
pr_debug("ctx %p: ea %016lx, dsisr %016lx state %d\n", ctx, ea,
dsisr, ctx->state);
ctx->stats.hash_flt++;
- if (ctx->state == SPU_STATE_RUNNABLE) {
+ if (ctx->state == SPU_STATE_RUNNABLE)
ctx->spu->stats.hash_flt++;
- spu_switch_state(ctx->spu, SPU_UTIL_IOWAIT);
- }
/* we must not hold the lock when entering spu_handle_mm_fault */
spu_release(ctx);
@@ -226,7 +224,7 @@ int spufs_handle_class1(struct spu_context *ctx)
} else
spufs_handle_dma_error(ctx, ea, SPE_EVENT_SPE_DATA_STORAGE);
- spuctx_switch_state(ctx, SPUCTX_UTIL_SYSTEM);
+ spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
return ret;
}
EXPORT_SYMBOL_GPL(spufs_handle_class1);
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
index fe164112b3d..9351db9472d 100644
--- a/arch/powerpc/platforms/cell/spufs/file.c
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -2079,14 +2079,26 @@ static const char *ctx_state_names[] = {
};
static unsigned long long spufs_acct_time(struct spu_context *ctx,
- enum spuctx_execution_state state)
+ enum spu_utilization_state state)
{
- unsigned long time = ctx->stats.times[state];
+ struct timespec ts;
+ unsigned long long time = ctx->stats.times[state];
- if (ctx->stats.execution_state == state)
- time += jiffies - ctx->stats.tstamp;
+ /*
+ * In general, utilization statistics are updated by the controlling
+ * thread as the spu context moves through various well defined
+ * state transitions, but if the context is lazily loaded its
+ * utilization statistics are not updated as the controlling thread
+ * is not tightly coupled with the execution of the spu context. We
+ * calculate and apply the time delta from the last recorded state
+ * of the spu context.
+ */
+ if (ctx->spu && ctx->stats.util_state == state) {
+ ktime_get_ts(&ts);
+ time += timespec_to_ns(&ts) - ctx->stats.tstamp;
+ }
- return jiffies_to_msecs(time);
+ return time / NSEC_PER_MSEC;
}
static unsigned long long spufs_slb_flts(struct spu_context *ctx)
@@ -2121,11 +2133,11 @@ static int spufs_show_stat(struct seq_file *s, void *private)
spu_acquire(ctx);
seq_printf(s, "%s %llu %llu %llu %llu "
"%llu %llu %llu %llu %llu %llu %llu %llu\n",
- ctx_state_names[ctx->stats.execution_state],
- spufs_acct_time(ctx, SPUCTX_UTIL_USER),
- spufs_acct_time(ctx, SPUCTX_UTIL_SYSTEM),
- spufs_acct_time(ctx, SPUCTX_UTIL_IOWAIT),
- spufs_acct_time(ctx, SPUCTX_UTIL_LOADED),
+ ctx_state_names[ctx->stats.util_state],
+ spufs_acct_time(ctx, SPU_UTIL_USER),
+ spufs_acct_time(ctx, SPU_UTIL_SYSTEM),
+ spufs_acct_time(ctx, SPU_UTIL_IOWAIT),
+ spufs_acct_time(ctx, SPU_UTIL_IDLE_LOADED),
ctx->stats.vol_ctx_switch,
ctx->stats.invol_ctx_switch,
spufs_slb_flts(ctx),
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
index 58ae13b7de8..8c91b3f9315 100644
--- a/arch/powerpc/platforms/cell/spufs/run.c
+++ b/arch/powerpc/platforms/cell/spufs/run.c
@@ -126,6 +126,8 @@ out:
static int spu_run_init(struct spu_context *ctx, u32 * npc)
{
+ spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
+
if (ctx->flags & SPU_CREATE_ISOLATE) {
unsigned long runcntl;
@@ -151,6 +153,8 @@ static int spu_run_init(struct spu_context *ctx, u32 * npc)
ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
}
+ spuctx_switch_state(ctx, SPU_UTIL_USER);
+
return 0;
}
@@ -161,6 +165,8 @@ static int spu_run_fini(struct spu_context *ctx, u32 * npc,
*status = ctx->ops->status_read(ctx);
*npc = ctx->ops->npc_read(ctx);
+
+ spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED);
spu_release(ctx);
if (signal_pending(current))
@@ -328,6 +334,9 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx,
ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status));
if (unlikely(ret))
break;
+
+ spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
+
if ((status & SPU_STATUS_STOPPED_BY_STOP) &&
(status >> SPU_STOP_STATUS_SHIFT == 0x2104)) {
ret = spu_process_callback(ctx);
@@ -356,6 +365,7 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx,
(ctx->state == SPU_STATE_RUNNABLE))
ctx->stats.libassist++;
+
ctx->ops->master_stop(ctx);
ret = spu_run_fini(ctx, npc, &status);
spu_yield(ctx);
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index fe789308dd1..ecd9e95116a 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -229,6 +229,7 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx)
{
pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid,
spu->number, spu->node);
+ spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
ctx->stats.slb_flt_base = spu->stats.slb_flt;
ctx->stats.class2_intr_base = spu->stats.class2_intr;
@@ -251,7 +252,8 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx)
spu_cpu_affinity_set(spu, raw_smp_processor_id());
spu_switch_notify(spu, ctx);
ctx->state = SPU_STATE_RUNNABLE;
- spu_switch_state(spu, SPU_UTIL_SYSTEM);
+
+ spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED);
}
/**
@@ -263,8 +265,7 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
{
pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__,
spu->pid, spu->number, spu->node);
-
- spu_switch_state(spu, SPU_UTIL_IDLE);
+ spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
spu_switch_notify(spu, NULL);
spu_unmap_mappings(ctx);
@@ -279,7 +280,6 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
spu_associate_mm(spu, NULL);
spu->pid = 0;
ctx->ops = &spu_backing_ops;
- ctx->spu = NULL;
spu->flags = 0;
spu->ctx = NULL;
@@ -287,6 +287,10 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
(spu->stats.slb_flt - ctx->stats.slb_flt_base);
ctx->stats.class2_intr +=
(spu->stats.class2_intr - ctx->stats.class2_intr_base);
+
+ /* This maps the underlying spu state to idle */
+ spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED);
+ ctx->spu = NULL;
}
/**
@@ -455,8 +459,6 @@ static struct spu *find_victim(struct spu_context *ctx)
*/
int spu_activate(struct spu_context *ctx, unsigned long flags)
{
- spuctx_switch_state(ctx, SPUCTX_UTIL_SYSTEM);
-
do {
struct spu *spu;
@@ -551,7 +553,6 @@ static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio)
void spu_deactivate(struct spu_context *ctx)
{
__spu_deactivate(ctx, 1, MAX_PRIO);
- spuctx_switch_state(ctx, SPUCTX_UTIL_USER);
}
/**
@@ -566,12 +567,7 @@ void spu_yield(struct spu_context *ctx)
{
if (!(ctx->flags & SPU_CREATE_NOSCHED)) {
mutex_lock(&ctx->state_mutex);
- if (__spu_deactivate(ctx, 0, MAX_PRIO))
- spuctx_switch_state(ctx, SPUCTX_UTIL_USER);
- else {
- spuctx_switch_state(ctx, SPUCTX_UTIL_LOADED);
- spu_switch_state(ctx->spu, SPU_UTIL_USER);
- }
+ __spu_deactivate(ctx, 0, MAX_PRIO);
mutex_unlock(&ctx->state_mutex);
}
}
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
index 34d5f9f8b4a..fdace928437 100644
--- a/arch/powerpc/platforms/cell/spufs/spufs.h
+++ b/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -40,19 +40,6 @@ enum {
struct spu_context_ops;
struct spu_gang;
-/*
- * This is the state for spu utilization reporting to userspace.
- * Because this state is visible to userspace it must never change and needs
- * to be kept strictly separate from any internal state kept by the kernel.
- */
-enum spuctx_execution_state {
- SPUCTX_UTIL_USER = 0,
- SPUCTX_UTIL_SYSTEM,
- SPUCTX_UTIL_IOWAIT,
- SPUCTX_UTIL_LOADED,
- SPUCTX_UTIL_MAX
-};
-
struct spu_context {
struct spu *spu; /* pointer to a physical SPU */
struct spu_state csa; /* SPU context save area. */
@@ -104,9 +91,9 @@ struct spu_context {
/* statistics */
struct {
/* updates protected by ctx->state_mutex */
- enum spuctx_execution_state execution_state;
- unsigned long tstamp; /* time of last ctx switch */
- unsigned long times[SPUCTX_UTIL_MAX];
+ enum spu_utilization_state util_state;
+ unsigned long long tstamp; /* time of last state switch */
+ unsigned long long times[SPU_UTIL_MAX];
unsigned long long vol_ctx_switch;
unsigned long long invol_ctx_switch;
unsigned long long min_flt;
@@ -293,30 +280,34 @@ extern int spufs_coredump_num_notes;
* line.
*/
static inline void spuctx_switch_state(struct spu_context *ctx,
- enum spuctx_execution_state new_state)
+ enum spu_utilization_state new_state)
{
- WARN_ON(!mutex_is_locked(&ctx->state_mutex));
+ unsigned long long curtime;
+ signed long long delta;
+ struct timespec ts;
+ struct spu *spu;
+ enum spu_utilization_state old_state;
- if (ctx->stats.execution_state != new_state) {
- unsigned long curtime = jiffies;
+ ktime_get_ts(&ts);
+ curtime = timespec_to_ns(&ts);
+ delta = curtime - ctx->stats.tstamp;
- ctx->stats.times[ctx->stats.execution_state] +=
- curtime - ctx->stats.tstamp;
- ctx->stats.tstamp = curtime;
- ctx->stats.execution_state = new_state;
- }
-}
-
-static inline void spu_switch_state(struct spu *spu,
- enum spuctx_execution_state new_state)
-{
- if (spu->stats.utilization_state != new_state) {
- unsigned long curtime = jiffies;
-
- spu->stats.times[spu->stats.utilization_state] +=
- curtime - spu->stats.tstamp;
+ WARN_ON(!mutex_is_locked(&ctx->state_mutex));
+ WARN_ON(delta < 0);
+
+ spu = ctx->spu;
+ old_state = ctx->stats.util_state;
+ ctx->stats.util_state = new_state;
+ ctx->stats.tstamp = curtime;
+
+ /*
+ * Update the physical SPU utilization statistics.
+ */
+ if (spu) {
+ ctx->stats.times[old_state] += delta;
+ spu->stats.times[old_state] += delta;
+ spu->stats.util_state = new_state;
spu->stats.tstamp = curtime;
- spu->stats.utilization_state = new_state;
}
}
diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h
index a034f03b810..12442acdc76 100644
--- a/include/asm-powerpc/spu.h
+++ b/include/asm-powerpc/spu.h
@@ -107,10 +107,10 @@ struct spu_runqueue;
struct device_node;
enum spu_utilization_state {
- SPU_UTIL_SYSTEM,
SPU_UTIL_USER,
+ SPU_UTIL_SYSTEM,
SPU_UTIL_IOWAIT,
- SPU_UTIL_IDLE,
+ SPU_UTIL_IDLE_LOADED,
SPU_UTIL_MAX
};
@@ -167,9 +167,9 @@ struct spu {
struct {
/* protected by interrupt reentrancy */
- enum spu_utilization_state utilization_state;
- unsigned long tstamp; /* time of last ctx switch */
- unsigned long times[SPU_UTIL_MAX];
+ enum spu_utilization_state util_state;
+ unsigned long long tstamp;
+ unsigned long long times[SPU_UTIL_MAX];
unsigned long long vol_ctx_switch;
unsigned long long invol_ctx_switch;
unsigned long long min_flt;