aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2007-06-28 20:58:03 -0400
committerPaul Mackerras <paulus@samba.org>2007-07-03 01:24:46 -0400
commite9f8a0b65ac716fd7974159240ce34bddea780b3 (patch)
tree70e9541861443fc378adc8cc924522e9eb73ab33
parent65de66f0b8bcb7431d9df82cf32b002062b3a611 (diff)
[POWERPC] spufs: Add stat file to spufs
Export per-context statistics in spufs. 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>
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c3
-rw-r--r--arch/powerpc/platforms/cell/spufs/context.c2
-rw-r--r--arch/powerpc/platforms/cell/spufs/fault.c19
-rw-r--r--arch/powerpc/platforms/cell/spufs/file.c79
-rw-r--r--arch/powerpc/platforms/cell/spufs/run.c4
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c19
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h51
-rw-r--r--include/asm-powerpc/spu.h6
8 files changed, 178 insertions, 5 deletions
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index cadcc64a8657..174bd9f911db 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -183,7 +183,7 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
183 spu->slb_replace = 0; 183 spu->slb_replace = 0;
184 184
185 spu_restart_dma(spu); 185 spu_restart_dma(spu);
186 186 spu->stats.slb_flt++;
187 return 0; 187 return 0;
188} 188}
189 189
@@ -332,6 +332,7 @@ spu_irq_class_2(int irq, void *data)
332 if (stat & 0x10) /* SPU mailbox threshold */ 332 if (stat & 0x10) /* SPU mailbox threshold */
333 spu->wbox_callback(spu); 333 spu->wbox_callback(spu);
334 334
335 spu->stats.class2_intr++;
335 return stat ? IRQ_HANDLED : IRQ_NONE; 336 return stat ? IRQ_HANDLED : IRQ_NONE;
336} 337}
337 338
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c
index f623d963fdc7..6d7bd60f5380 100644
--- a/arch/powerpc/platforms/cell/spufs/context.c
+++ b/arch/powerpc/platforms/cell/spufs/context.c
@@ -59,6 +59,8 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang)
59 spu_gang_add_ctx(gang, ctx); 59 spu_gang_add_ctx(gang, ctx);
60 ctx->cpus_allowed = current->cpus_allowed; 60 ctx->cpus_allowed = current->cpus_allowed;
61 spu_set_timeslice(ctx); 61 spu_set_timeslice(ctx);
62 ctx->stats.execution_state = SPUCTX_UTIL_USER;
63 ctx->stats.tstamp = jiffies;
62 64
63 atomic_inc(&nr_spu_contexts); 65 atomic_inc(&nr_spu_contexts);
64 goto out; 66 goto out;
diff --git a/arch/powerpc/platforms/cell/spufs/fault.c b/arch/powerpc/platforms/cell/spufs/fault.c
index 0f75c07e29d8..3a9e49a24ec0 100644
--- a/arch/powerpc/platforms/cell/spufs/fault.c
+++ b/arch/powerpc/platforms/cell/spufs/fault.c
@@ -33,7 +33,8 @@
33 * function. Currently, there are a few corner cases that we haven't had 33 * function. Currently, there are a few corner cases that we haven't had
34 * to handle fortunately. 34 * to handle fortunately.
35 */ 35 */
36static int spu_handle_mm_fault(struct mm_struct *mm, unsigned long ea, unsigned long dsisr) 36static int spu_handle_mm_fault(struct mm_struct *mm, unsigned long ea,
37 unsigned long dsisr, unsigned *flt)
37{ 38{
38 struct vm_area_struct *vma; 39 struct vm_area_struct *vma;
39 unsigned long is_write; 40 unsigned long is_write;
@@ -73,7 +74,8 @@ good_area:
73 goto bad_area; 74 goto bad_area;
74 } 75 }
75 ret = 0; 76 ret = 0;
76 switch (handle_mm_fault(mm, vma, ea, is_write)) { 77 *flt = handle_mm_fault(mm, vma, ea, is_write);
78 switch (*flt) {
77 case VM_FAULT_MINOR: 79 case VM_FAULT_MINOR:
78 current->min_flt++; 80 current->min_flt++;
79 break; 81 break;
@@ -153,6 +155,7 @@ int spufs_handle_class1(struct spu_context *ctx)
153{ 155{
154 u64 ea, dsisr, access; 156 u64 ea, dsisr, access;
155 unsigned long flags; 157 unsigned long flags;
158 unsigned flt = 0;
156 int ret; 159 int ret;
157 160
158 /* 161 /*
@@ -178,9 +181,13 @@ int spufs_handle_class1(struct spu_context *ctx)
178 if (!(dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED))) 181 if (!(dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)))
179 return 0; 182 return 0;
180 183
184 spuctx_switch_state(ctx, SPUCTX_UTIL_IOWAIT);
185
181 pr_debug("ctx %p: ea %016lx, dsisr %016lx state %d\n", ctx, ea, 186 pr_debug("ctx %p: ea %016lx, dsisr %016lx state %d\n", ctx, ea,
182 dsisr, ctx->state); 187 dsisr, ctx->state);
183 188
189 ctx->stats.hash_flt++;
190
184 /* we must not hold the lock when entering spu_handle_mm_fault */ 191 /* we must not hold the lock when entering spu_handle_mm_fault */
185 spu_release(ctx); 192 spu_release(ctx);
186 193
@@ -192,7 +199,7 @@ int spufs_handle_class1(struct spu_context *ctx)
192 199
193 /* hashing failed, so try the actual fault handler */ 200 /* hashing failed, so try the actual fault handler */
194 if (ret) 201 if (ret)
195 ret = spu_handle_mm_fault(current->mm, ea, dsisr); 202 ret = spu_handle_mm_fault(current->mm, ea, dsisr, &flt);
196 203
197 spu_acquire(ctx); 204 spu_acquire(ctx);
198 /* 205 /*
@@ -201,11 +208,17 @@ int spufs_handle_class1(struct spu_context *ctx)
201 * In case of unhandled error report the problem to user space. 208 * In case of unhandled error report the problem to user space.
202 */ 209 */
203 if (!ret) { 210 if (!ret) {
211 if (flt == VM_FAULT_MINOR)
212 ctx->stats.min_flt++;
213 else
214 ctx->stats.maj_flt++;
215
204 if (ctx->spu) 216 if (ctx->spu)
205 ctx->ops->restart_dma(ctx); 217 ctx->ops->restart_dma(ctx);
206 } else 218 } else
207 spufs_handle_dma_error(ctx, ea, SPE_EVENT_SPE_DATA_STORAGE); 219 spufs_handle_dma_error(ctx, ea, SPE_EVENT_SPE_DATA_STORAGE);
208 220
221 spuctx_switch_state(ctx, SPUCTX_UTIL_SYSTEM);
209 return ret; 222 return ret;
210} 223}
211EXPORT_SYMBOL_GPL(spufs_handle_class1); 224EXPORT_SYMBOL_GPL(spufs_handle_class1);
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
index 2bb51ca51a6c..30f7b077f347 100644
--- a/arch/powerpc/platforms/cell/spufs/file.c
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -2059,6 +2059,83 @@ static const struct file_operations spufs_tid_fops = {
2059 .release = single_release, 2059 .release = single_release,
2060}; 2060};
2061 2061
2062static const char *ctx_state_names[] = {
2063 "user", "system", "iowait", "loaded"
2064};
2065
2066static unsigned long long spufs_acct_time(struct spu_context *ctx,
2067 enum spuctx_execution_state state)
2068{
2069 unsigned long time = ctx->stats.times[state];
2070
2071 if (ctx->stats.execution_state == state)
2072 time += jiffies - ctx->stats.tstamp;
2073
2074 return jiffies_to_msecs(time);
2075}
2076
2077static unsigned long long spufs_slb_flts(struct spu_context *ctx)
2078{
2079 unsigned long long slb_flts = ctx->stats.slb_flt;
2080
2081 if (ctx->state == SPU_STATE_RUNNABLE) {
2082 slb_flts += (ctx->spu->stats.slb_flt -
2083 ctx->stats.slb_flt_base);
2084 }
2085
2086 return slb_flts;
2087}
2088
2089static unsigned long long spufs_class2_intrs(struct spu_context *ctx)
2090{
2091 unsigned long long class2_intrs = ctx->stats.class2_intr;
2092
2093 if (ctx->state == SPU_STATE_RUNNABLE) {
2094 class2_intrs += (ctx->spu->stats.class2_intr -
2095 ctx->stats.class2_intr_base);
2096 }
2097
2098 return class2_intrs;
2099}
2100
2101
2102static int spufs_show_stat(struct seq_file *s, void *private)
2103{
2104 struct spu_context *ctx = s->private;
2105
2106 spu_acquire(ctx);
2107 seq_printf(s, "%s %llu %llu %llu %llu "
2108 "%llu %llu %llu %llu %llu %llu %llu %llu\n",
2109 ctx_state_names[ctx->stats.execution_state],
2110 spufs_acct_time(ctx, SPUCTX_UTIL_USER),
2111 spufs_acct_time(ctx, SPUCTX_UTIL_SYSTEM),
2112 spufs_acct_time(ctx, SPUCTX_UTIL_IOWAIT),
2113 spufs_acct_time(ctx, SPUCTX_UTIL_LOADED),
2114 ctx->stats.vol_ctx_switch,
2115 ctx->stats.invol_ctx_switch,
2116 spufs_slb_flts(ctx),
2117 ctx->stats.hash_flt,
2118 ctx->stats.min_flt,
2119 ctx->stats.maj_flt,
2120 spufs_class2_intrs(ctx),
2121 ctx->stats.libassist);
2122 spu_release(ctx);
2123 return 0;
2124}
2125
2126static int spufs_stat_open(struct inode *inode, struct file *file)
2127{
2128 return single_open(file, spufs_show_stat, SPUFS_I(inode)->i_ctx);
2129}
2130
2131static const struct file_operations spufs_stat_fops = {
2132 .open = spufs_stat_open,
2133 .read = seq_read,
2134 .llseek = seq_lseek,
2135 .release = single_release,
2136};
2137
2138
2062struct tree_descr spufs_dir_contents[] = { 2139struct tree_descr spufs_dir_contents[] = {
2063 { "capabilities", &spufs_caps_fops, 0444, }, 2140 { "capabilities", &spufs_caps_fops, 0444, },
2064 { "mem", &spufs_mem_fops, 0666, }, 2141 { "mem", &spufs_mem_fops, 0666, },
@@ -2093,6 +2170,7 @@ struct tree_descr spufs_dir_contents[] = {
2093 { "dma_info", &spufs_dma_info_fops, 0444, }, 2170 { "dma_info", &spufs_dma_info_fops, 0444, },
2094 { "proxydma_info", &spufs_proxydma_info_fops, 0444, }, 2171 { "proxydma_info", &spufs_proxydma_info_fops, 0444, },
2095 { "tid", &spufs_tid_fops, 0444, }, 2172 { "tid", &spufs_tid_fops, 0444, },
2173 { "stat", &spufs_stat_fops, 0444, },
2096 {}, 2174 {},
2097}; 2175};
2098 2176
@@ -2117,6 +2195,7 @@ struct tree_descr spufs_dir_nosched_contents[] = {
2117 { "phys-id", &spufs_id_ops, 0666, }, 2195 { "phys-id", &spufs_id_ops, 0666, },
2118 { "object-id", &spufs_object_id_ops, 0666, }, 2196 { "object-id", &spufs_object_id_ops, 0666, },
2119 { "tid", &spufs_tid_fops, 0444, }, 2197 { "tid", &spufs_tid_fops, 0444, },
2198 { "stat", &spufs_stat_fops, 0444, },
2120 {}, 2199 {},
2121}; 2200};
2122 2201
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
index 4e0db6ae0d5e..c69f63dd5f0a 100644
--- a/arch/powerpc/platforms/cell/spufs/run.c
+++ b/arch/powerpc/platforms/cell/spufs/run.c
@@ -351,6 +351,10 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx,
351 SPU_STATUS_STOPPED_BY_HALT | 351 SPU_STATUS_STOPPED_BY_HALT |
352 SPU_STATUS_SINGLE_STEP))); 352 SPU_STATUS_SINGLE_STEP)));
353 353
354 if ((status & SPU_STATUS_STOPPED_BY_STOP) &&
355 ((status >> SPU_STOP_STATUS_SHIFT) & 0x2100))
356 ctx->stats.libassist++;
357
354 ctx->ops->master_stop(ctx); 358 ctx->ops->master_stop(ctx);
355 ret = spu_run_fini(ctx, npc, &status); 359 ret = spu_run_fini(ctx, npc, &status);
356 spu_yield(ctx); 360 spu_yield(ctx);
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index 9fc09306c9ae..bb16c22360d5 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -229,6 +229,10 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx)
229{ 229{
230 pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid, 230 pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid,
231 spu->number, spu->node); 231 spu->number, spu->node);
232
233 ctx->stats.slb_flt_base = spu->stats.slb_flt;
234 ctx->stats.class2_intr_base = spu->stats.class2_intr;
235
232 spu->ctx = ctx; 236 spu->ctx = ctx;
233 spu->flags = 0; 237 spu->flags = 0;
234 ctx->spu = spu; 238 ctx->spu = spu;
@@ -275,6 +279,11 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
275 ctx->spu = NULL; 279 ctx->spu = NULL;
276 spu->flags = 0; 280 spu->flags = 0;
277 spu->ctx = NULL; 281 spu->ctx = NULL;
282
283 ctx->stats.slb_flt +=
284 (spu->stats.slb_flt - ctx->stats.slb_flt_base);
285 ctx->stats.class2_intr +=
286 (spu->stats.class2_intr - ctx->stats.class2_intr_base);
278} 287}
279 288
280/** 289/**
@@ -400,6 +409,7 @@ static struct spu *find_victim(struct spu_context *ctx)
400 } 409 }
401 spu_remove_from_active_list(spu); 410 spu_remove_from_active_list(spu);
402 spu_unbind_context(spu, victim); 411 spu_unbind_context(spu, victim);
412 victim->stats.invol_ctx_switch++;
403 mutex_unlock(&victim->state_mutex); 413 mutex_unlock(&victim->state_mutex);
404 /* 414 /*
405 * We need to break out of the wait loop in spu_run 415 * We need to break out of the wait loop in spu_run
@@ -425,6 +435,7 @@ static struct spu *find_victim(struct spu_context *ctx)
425 */ 435 */
426int spu_activate(struct spu_context *ctx, unsigned long flags) 436int spu_activate(struct spu_context *ctx, unsigned long flags)
427{ 437{
438 spuctx_switch_state(ctx, SPUCTX_UTIL_SYSTEM);
428 439
429 if (ctx->spu) 440 if (ctx->spu)
430 return 0; 441 return 0;
@@ -492,6 +503,7 @@ static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio)
492 if (new || force) { 503 if (new || force) {
493 spu_remove_from_active_list(spu); 504 spu_remove_from_active_list(spu);
494 spu_unbind_context(spu, ctx); 505 spu_unbind_context(spu, ctx);
506 ctx->stats.vol_ctx_switch++;
495 spu_free(spu); 507 spu_free(spu);
496 if (new) 508 if (new)
497 wake_up(&new->stop_wq); 509 wake_up(&new->stop_wq);
@@ -521,6 +533,7 @@ void spu_deactivate(struct spu_context *ctx)
521 } 533 }
522 534
523 __spu_deactivate(ctx, 1, MAX_PRIO); 535 __spu_deactivate(ctx, 1, MAX_PRIO);
536 spuctx_switch_state(ctx, SPUCTX_UTIL_USER);
524} 537}
525 538
526/** 539/**
@@ -535,7 +548,10 @@ void spu_yield(struct spu_context *ctx)
535{ 548{
536 if (!(ctx->flags & SPU_CREATE_NOSCHED)) { 549 if (!(ctx->flags & SPU_CREATE_NOSCHED)) {
537 mutex_lock(&ctx->state_mutex); 550 mutex_lock(&ctx->state_mutex);
538 __spu_deactivate(ctx, 0, MAX_PRIO); 551 if (__spu_deactivate(ctx, 0, MAX_PRIO))
552 spuctx_switch_state(ctx, SPUCTX_UTIL_USER);
553 else
554 spuctx_switch_state(ctx, SPUCTX_UTIL_LOADED);
539 mutex_unlock(&ctx->state_mutex); 555 mutex_unlock(&ctx->state_mutex);
540 } 556 }
541} 557}
@@ -564,6 +580,7 @@ static void spusched_tick(struct spu_context *ctx)
564 580
565 __spu_remove_from_active_list(spu); 581 __spu_remove_from_active_list(spu);
566 spu_unbind_context(spu, ctx); 582 spu_unbind_context(spu, ctx);
583 ctx->stats.invol_ctx_switch++;
567 spu_free(spu); 584 spu_free(spu);
568 wake_up(&new->stop_wq); 585 wake_up(&new->stop_wq);
569 /* 586 /*
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
index 7f5d0b2fdea3..cd2b54f6e378 100644
--- a/arch/powerpc/platforms/cell/spufs/spufs.h
+++ b/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -40,6 +40,19 @@ enum {
40struct spu_context_ops; 40struct spu_context_ops;
41struct spu_gang; 41struct spu_gang;
42 42
43/*
44 * This is the state for spu utilization reporting to userspace.
45 * Because this state is visible to userspace it must never change and needs
46 * to be kept strictly separate from any internal state kept by the kernel.
47 */
48enum spuctx_execution_state {
49 SPUCTX_UTIL_USER = 0,
50 SPUCTX_UTIL_SYSTEM,
51 SPUCTX_UTIL_IOWAIT,
52 SPUCTX_UTIL_LOADED,
53 SPUCTX_UTIL_MAX
54};
55
43struct spu_context { 56struct spu_context {
44 struct spu *spu; /* pointer to a physical SPU */ 57 struct spu *spu; /* pointer to a physical SPU */
45 struct spu_state csa; /* SPU context save area. */ 58 struct spu_state csa; /* SPU context save area. */
@@ -87,6 +100,24 @@ struct spu_context {
87 cpumask_t cpus_allowed; 100 cpumask_t cpus_allowed;
88 int policy; 101 int policy;
89 int prio; 102 int prio;
103
104 /* statistics */
105 struct {
106 /* updates protected by ctx->state_mutex */
107 enum spuctx_execution_state execution_state;
108 unsigned long tstamp; /* time of last ctx switch */
109 unsigned long times[SPUCTX_UTIL_MAX];
110 unsigned long long vol_ctx_switch;
111 unsigned long long invol_ctx_switch;
112 unsigned long long min_flt;
113 unsigned long long maj_flt;
114 unsigned long long hash_flt;
115 unsigned long long slb_flt;
116 unsigned long long slb_flt_base; /* # at last ctx switch */
117 unsigned long long class2_intr;
118 unsigned long long class2_intr_base; /* # at last ctx switch */
119 unsigned long long libassist;
120 } stats;
90}; 121};
91 122
92struct spu_gang { 123struct spu_gang {
@@ -256,4 +287,24 @@ struct spufs_coredump_reader {
256extern struct spufs_coredump_reader spufs_coredump_read[]; 287extern struct spufs_coredump_reader spufs_coredump_read[];
257extern int spufs_coredump_num_notes; 288extern int spufs_coredump_num_notes;
258 289
290/*
291 * This function is a little bit too large for an inline, but
292 * as fault.c is built into the kernel we can't move it out of
293 * line.
294 */
295static inline void spuctx_switch_state(struct spu_context *ctx,
296 enum spuctx_execution_state new_state)
297{
298 WARN_ON(!mutex_is_locked(&ctx->state_mutex));
299
300 if (ctx->stats.execution_state != new_state) {
301 unsigned long curtime = jiffies;
302
303 ctx->stats.times[ctx->stats.execution_state] +=
304 curtime - ctx->stats.tstamp;
305 ctx->stats.tstamp = curtime;
306 ctx->stats.execution_state = new_state;
307 }
308}
309
259#endif 310#endif
diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h
index 5f894b61e2d4..5957fcdda04c 100644
--- a/include/asm-powerpc/spu.h
+++ b/include/asm-powerpc/spu.h
@@ -156,6 +156,12 @@ struct spu {
156 u64 shadow_int_mask_RW[3]; 156 u64 shadow_int_mask_RW[3];
157 157
158 struct sys_device sysdev; 158 struct sys_device sysdev;
159
160 struct {
161 /* protected by interrupt reentrancy */
162 unsigned long long slb_flt;
163 unsigned long long class2_intr;
164 } stats;
159}; 165};
160 166
161struct spu *spu_alloc(void); 167struct spu *spu_alloc(void);