Commit 27ec41d3 authored by Andre Detsch's avatar Andre Detsch Committed by Arnd Bergmann
Browse files

[CELL] spufs: add spu stats in sysfs and ctx stat file in spufs



This patch exports per-context statistics in spufs as long as spu
statistics in sysfs.

It was formed by merging:
"spufs: add spu stats in sysfs"   From: Christoph Hellwig
"spufs: add stat file to spufs"   From: Christoph Hellwig
"spufs: fix libassist accounting" From: Jeremy Kerr
"spusched: fix spu utilization statistics" From: Luke Browning
And some adjustments by myself, after suggestions on cbe-oss-dev.

Having separate patches was making the review process harder
than it should, as we end up integrating spus and ctx statistics
accounting much more than it was on the first implementation.

Signed-off-by: default avatarAndre Detsch <adetsch@br.ibm.com>
Signed-off-by: default avatarJeremy Kerr <jk@ozlabs.org>
Signed-off-by: default avatarArnd Bergmann <arnd.bergmann@de.ibm.com>
parent e840cfe6
Loading
Loading
Loading
Loading
+17 −7
Original line number Diff line number Diff line
@@ -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,
+1 −2
Original line number Diff line number Diff line
@@ -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;
+3 −5
Original line number Diff line number Diff line
@@ -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);
+22 −10
Original line number Diff line number Diff line
@@ -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),
+10 −0
Original line number Diff line number Diff line
@@ -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);
Loading