[POWERPC] spufs: Add spu stats in sysfs
authorChristoph Hellwig <hch@lst.de>
Fri, 29 Jun 2007 00:58:07 +0000 (10:58 +1000)
committerPaul Mackerras <paulus@samba.org>
Tue, 3 Jul 2007 05:24:46 +0000 (15:24 +1000)
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>
arch/powerpc/platforms/cell/spu_base.c
arch/powerpc/platforms/cell/spufs/fault.c
arch/powerpc/platforms/cell/spufs/run.c
arch/powerpc/platforms/cell/spufs/sched.c
arch/powerpc/platforms/cell/spufs/spufs.h
include/asm-powerpc/spu.h

index 174bd9f911db0dca50118744fc62b0df617cb6f2..e4d0c9f42abdba0b0034ed8ad87c591fff7f6b7a 100644 (file)
@@ -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:
index 3a9e49a24ec00fafeda4601b2abfa8c4084a4120..e064d0c0d80e6fac6240e86a4f94e0fd0785ca2b 100644 (file)
@@ -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);
index 05cf815dbdadc185df29527880ab406698b9053a..58ae13b7de84cd50677a740f87d2d25dc0cba7ee 100644 (file)
@@ -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);
index 9fb3133268f63054a34fc42d75aa948d1893c37c..e5b4dd1db286e8c834e9d64ca12b6237fc932d6f 100644 (file)
@@ -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);
                        /*
index cd2b54f6e37899e8d3d17c840557003f7deefc50..08b3530288ac34d222ba165f72338d27ebc88d5d 100644 (file)
@@ -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
index 5957fcdda04cfc8cc162949570e6a6fd52aa477b..eedc828cef2dc31a9fcbec613a99590017e1da9c 100644 (file)
@@ -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;
 };