aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c44
-rw-r--r--arch/powerpc/platforms/cell/spufs/fault.c10
-rw-r--r--arch/powerpc/platforms/cell/spufs/run.c3
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c10
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h13
-rw-r--r--include/asm-powerpc/spu.h17
6 files changed, 95 insertions, 2 deletions
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index 174bd9f911db..e4d0c9f42abd 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -585,6 +585,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;
+
goto out;
out_free_irqs:
@@ -597,6 +600,45 @@ out:
return ret;
}
+static const char *spu_state_names[] = {
+ "user", "system", "iowait", "idle"
+};
+
+static unsigned long long spu_acct_time(struct spu *spu,
+ enum spu_utilization_state state)
+{
+ unsigned long long time = spu->stats.times[state];
+
+ if (spu->stats.utilization_state == state)
+ time += jiffies - spu->stats.tstamp;
+
+ return jiffies_to_msecs(time);
+}
+
+
+static ssize_t spu_stat_show(struct sys_device *sysdev, char *buf)
+{
+ struct spu *spu = container_of(sysdev, struct spu, sysdev);
+
+ 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_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->stats.vol_ctx_switch,
+ spu->stats.invol_ctx_switch,
+ spu->stats.slb_flt,
+ spu->stats.hash_flt,
+ spu->stats.min_flt,
+ spu->stats.maj_flt,
+ spu->stats.class2_intr,
+ spu->stats.libassist);
+}
+
+static SYSDEV_ATTR(stat, 0644, spu_stat_show, NULL);
+
static int __init init_spu_base(void)
{
int i, ret = 0;
@@ -622,6 +664,8 @@ static int __init init_spu_base(void)
xmon_register_spus(&spu_full_list);
+ spu_add_sysdev_attr(&attr_stat);
+
return 0;
out_unregister_sysdev_class:
diff --git a/arch/powerpc/platforms/cell/spufs/fault.c b/arch/powerpc/platforms/cell/spufs/fault.c
index 3a9e49a24ec0..e064d0c0d80e 100644
--- a/arch/powerpc/platforms/cell/spufs/fault.c
+++ b/arch/powerpc/platforms/cell/spufs/fault.c
@@ -187,6 +187,10 @@ int spufs_handle_class1(struct spu_context *ctx)
dsisr, ctx->state);
ctx->stats.hash_flt++;
+ 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);
@@ -212,6 +216,12 @@ int spufs_handle_class1(struct spu_context *ctx)
ctx->stats.min_flt++;
else
ctx->stats.maj_flt++;
+ if (ctx->state == SPU_STATE_RUNNABLE) {
+ if (flt == VM_FAULT_MINOR)
+ ctx->spu->stats.min_flt++;
+ else
+ ctx->spu->stats.maj_flt++;
+ }
if (ctx->spu)
ctx->ops->restart_dma(ctx);
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
index 05cf815dbdad..58ae13b7de84 100644
--- a/arch/powerpc/platforms/cell/spufs/run.c
+++ b/arch/powerpc/platforms/cell/spufs/run.c
@@ -352,7 +352,8 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx,
SPU_STATUS_SINGLE_STEP)));
if ((status & SPU_STATUS_STOPPED_BY_STOP) &&
- (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100))
+ (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100) &&
+ (ctx->state == SPU_STATE_RUNNABLE))
ctx->stats.libassist++;
ctx->ops->master_stop(ctx);
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index 9fb3133268f6..e5b4dd1db286 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -251,6 +251,7 @@ 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);
}
/**
@@ -263,6 +264,8 @@ 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);
+
spu_switch_notify(spu, NULL);
spu_unmap_mappings(ctx);
spu_save(&ctx->csa, spu);
@@ -426,6 +429,7 @@ static struct spu *find_victim(struct spu_context *ctx)
spu_remove_from_active_list(spu);
spu_unbind_context(spu, victim);
victim->stats.invol_ctx_switch++;
+ spu->stats.invol_ctx_switch++;
mutex_unlock(&victim->state_mutex);
/*
* We need to break out of the wait loop in spu_run
@@ -526,6 +530,7 @@ static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio)
spu_remove_from_active_list(spu);
spu_unbind_context(spu, ctx);
ctx->stats.vol_ctx_switch++;
+ spu->stats.vol_ctx_switch++;
spu_free(spu);
if (new)
wake_up(&new->stop_wq);
@@ -572,8 +577,10 @@ void spu_yield(struct spu_context *ctx)
mutex_lock(&ctx->state_mutex);
if (__spu_deactivate(ctx, 0, MAX_PRIO))
spuctx_switch_state(ctx, SPUCTX_UTIL_USER);
- else
+ else {
spuctx_switch_state(ctx, SPUCTX_UTIL_LOADED);
+ spu_switch_state(ctx->spu, SPU_UTIL_USER);
+ }
mutex_unlock(&ctx->state_mutex);
}
}
@@ -603,6 +610,7 @@ static void spusched_tick(struct spu_context *ctx)
__spu_remove_from_active_list(spu);
spu_unbind_context(spu, ctx);
ctx->stats.invol_ctx_switch++;
+ spu->stats.invol_ctx_switch++;
spu_free(spu);
wake_up(&new->stop_wq);
/*
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
index cd2b54f6e378..08b3530288ac 100644
--- a/arch/powerpc/platforms/cell/spufs/spufs.h
+++ b/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -307,4 +307,17 @@ static inline void spuctx_switch_state(struct spu_context *ctx,
}
}
+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;
+ spu->stats.tstamp = curtime;
+ spu->stats.utilization_state = new_state;
+ }
+}
+
#endif
diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h
index 5957fcdda04c..eedc828cef2d 100644
--- a/include/asm-powerpc/spu.h
+++ b/include/asm-powerpc/spu.h
@@ -106,6 +106,14 @@ struct spu_context;
struct spu_runqueue;
struct device_node;
+enum spu_utilization_state {
+ SPU_UTIL_SYSTEM,
+ SPU_UTIL_USER,
+ SPU_UTIL_IOWAIT,
+ SPU_UTIL_IDLE,
+ SPU_UTIL_MAX
+};
+
struct spu {
const char *name;
unsigned long local_store_phys;
@@ -159,8 +167,17 @@ 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];
+ unsigned long long vol_ctx_switch;
+ unsigned long long invol_ctx_switch;
+ unsigned long long min_flt;
+ unsigned long long maj_flt;
+ unsigned long long hash_flt;
unsigned long long slb_flt;
unsigned long long class2_intr;
+ unsigned long long libassist;
} stats;
};