[POWERPC] spufs: Add spu stats in sysfs
Export spu statistics in sysfs. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com> Signed-off-by: Jeremy Kerr <jk@ozlabs.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
This commit is contained in:
parent
27449971e6
commit
fe2f896d67
|
@ -585,6 +585,9 @@ static int __init create_spu(void *data)
|
||||||
spin_unlock_irqrestore(&spu_list_lock, flags);
|
spin_unlock_irqrestore(&spu_list_lock, flags);
|
||||||
mutex_unlock(&spu_mutex);
|
mutex_unlock(&spu_mutex);
|
||||||
|
|
||||||
|
spu->stats.utilization_state = SPU_UTIL_IDLE;
|
||||||
|
spu->stats.tstamp = jiffies;
|
||||||
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
out_free_irqs:
|
out_free_irqs:
|
||||||
|
@ -597,6 +600,45 @@ out:
|
||||||
return ret;
|
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)
|
static int __init init_spu_base(void)
|
||||||
{
|
{
|
||||||
int i, ret = 0;
|
int i, ret = 0;
|
||||||
|
@ -622,6 +664,8 @@ static int __init init_spu_base(void)
|
||||||
|
|
||||||
xmon_register_spus(&spu_full_list);
|
xmon_register_spus(&spu_full_list);
|
||||||
|
|
||||||
|
spu_add_sysdev_attr(&attr_stat);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_unregister_sysdev_class:
|
out_unregister_sysdev_class:
|
||||||
|
|
|
@ -187,6 +187,10 @@ int spufs_handle_class1(struct spu_context *ctx)
|
||||||
dsisr, ctx->state);
|
dsisr, ctx->state);
|
||||||
|
|
||||||
ctx->stats.hash_flt++;
|
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 */
|
/* we must not hold the lock when entering spu_handle_mm_fault */
|
||||||
spu_release(ctx);
|
spu_release(ctx);
|
||||||
|
@ -212,6 +216,12 @@ int spufs_handle_class1(struct spu_context *ctx)
|
||||||
ctx->stats.min_flt++;
|
ctx->stats.min_flt++;
|
||||||
else
|
else
|
||||||
ctx->stats.maj_flt++;
|
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)
|
if (ctx->spu)
|
||||||
ctx->ops->restart_dma(ctx);
|
ctx->ops->restart_dma(ctx);
|
||||||
|
|
|
@ -352,7 +352,8 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx,
|
||||||
SPU_STATUS_SINGLE_STEP)));
|
SPU_STATUS_SINGLE_STEP)));
|
||||||
|
|
||||||
if ((status & SPU_STATUS_STOPPED_BY_STOP) &&
|
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->stats.libassist++;
|
||||||
|
|
||||||
ctx->ops->master_stop(ctx);
|
ctx->ops->master_stop(ctx);
|
||||||
|
|
|
@ -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_cpu_affinity_set(spu, raw_smp_processor_id());
|
||||||
spu_switch_notify(spu, ctx);
|
spu_switch_notify(spu, ctx);
|
||||||
ctx->state = SPU_STATE_RUNNABLE;
|
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__,
|
pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__,
|
||||||
spu->pid, spu->number, spu->node);
|
spu->pid, spu->number, spu->node);
|
||||||
|
|
||||||
|
spu_switch_state(spu, SPU_UTIL_IDLE);
|
||||||
|
|
||||||
spu_switch_notify(spu, NULL);
|
spu_switch_notify(spu, NULL);
|
||||||
spu_unmap_mappings(ctx);
|
spu_unmap_mappings(ctx);
|
||||||
spu_save(&ctx->csa, spu);
|
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_remove_from_active_list(spu);
|
||||||
spu_unbind_context(spu, victim);
|
spu_unbind_context(spu, victim);
|
||||||
victim->stats.invol_ctx_switch++;
|
victim->stats.invol_ctx_switch++;
|
||||||
|
spu->stats.invol_ctx_switch++;
|
||||||
mutex_unlock(&victim->state_mutex);
|
mutex_unlock(&victim->state_mutex);
|
||||||
/*
|
/*
|
||||||
* We need to break out of the wait loop in spu_run
|
* 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_remove_from_active_list(spu);
|
||||||
spu_unbind_context(spu, ctx);
|
spu_unbind_context(spu, ctx);
|
||||||
ctx->stats.vol_ctx_switch++;
|
ctx->stats.vol_ctx_switch++;
|
||||||
|
spu->stats.vol_ctx_switch++;
|
||||||
spu_free(spu);
|
spu_free(spu);
|
||||||
if (new)
|
if (new)
|
||||||
wake_up(&new->stop_wq);
|
wake_up(&new->stop_wq);
|
||||||
|
@ -572,8 +577,10 @@ void spu_yield(struct spu_context *ctx)
|
||||||
mutex_lock(&ctx->state_mutex);
|
mutex_lock(&ctx->state_mutex);
|
||||||
if (__spu_deactivate(ctx, 0, MAX_PRIO))
|
if (__spu_deactivate(ctx, 0, MAX_PRIO))
|
||||||
spuctx_switch_state(ctx, SPUCTX_UTIL_USER);
|
spuctx_switch_state(ctx, SPUCTX_UTIL_USER);
|
||||||
else
|
else {
|
||||||
spuctx_switch_state(ctx, SPUCTX_UTIL_LOADED);
|
spuctx_switch_state(ctx, SPUCTX_UTIL_LOADED);
|
||||||
|
spu_switch_state(ctx->spu, SPU_UTIL_USER);
|
||||||
|
}
|
||||||
mutex_unlock(&ctx->state_mutex);
|
mutex_unlock(&ctx->state_mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -603,6 +610,7 @@ static void spusched_tick(struct spu_context *ctx)
|
||||||
__spu_remove_from_active_list(spu);
|
__spu_remove_from_active_list(spu);
|
||||||
spu_unbind_context(spu, ctx);
|
spu_unbind_context(spu, ctx);
|
||||||
ctx->stats.invol_ctx_switch++;
|
ctx->stats.invol_ctx_switch++;
|
||||||
|
spu->stats.invol_ctx_switch++;
|
||||||
spu_free(spu);
|
spu_free(spu);
|
||||||
wake_up(&new->stop_wq);
|
wake_up(&new->stop_wq);
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -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
|
#endif
|
||||||
|
|
|
@ -106,6 +106,14 @@ struct spu_context;
|
||||||
struct spu_runqueue;
|
struct spu_runqueue;
|
||||||
struct device_node;
|
struct device_node;
|
||||||
|
|
||||||
|
enum spu_utilization_state {
|
||||||
|
SPU_UTIL_SYSTEM,
|
||||||
|
SPU_UTIL_USER,
|
||||||
|
SPU_UTIL_IOWAIT,
|
||||||
|
SPU_UTIL_IDLE,
|
||||||
|
SPU_UTIL_MAX
|
||||||
|
};
|
||||||
|
|
||||||
struct spu {
|
struct spu {
|
||||||
const char *name;
|
const char *name;
|
||||||
unsigned long local_store_phys;
|
unsigned long local_store_phys;
|
||||||
|
@ -159,8 +167,17 @@ struct spu {
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
/* protected by interrupt reentrancy */
|
/* 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 slb_flt;
|
||||||
unsigned long long class2_intr;
|
unsigned long long class2_intr;
|
||||||
|
unsigned long long libassist;
|
||||||
} stats;
|
} stats;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue