diff options
-rw-r--r-- | arch/powerpc/platforms/cell/spu_base.c | 44 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/fault.c | 10 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/run.c | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/sched.c | 10 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/spufs.h | 13 | ||||
-rw-r--r-- | include/asm-powerpc/spu.h | 17 |
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) | |||
585 | spin_unlock_irqrestore(&spu_list_lock, flags); | 585 | spin_unlock_irqrestore(&spu_list_lock, flags); |
586 | mutex_unlock(&spu_mutex); | 586 | mutex_unlock(&spu_mutex); |
587 | 587 | ||
588 | spu->stats.utilization_state = SPU_UTIL_IDLE; | ||
589 | spu->stats.tstamp = jiffies; | ||
590 | |||
588 | goto out; | 591 | goto out; |
589 | 592 | ||
590 | out_free_irqs: | 593 | out_free_irqs: |
@@ -597,6 +600,45 @@ out: | |||
597 | return ret; | 600 | return ret; |
598 | } | 601 | } |
599 | 602 | ||
603 | static const char *spu_state_names[] = { | ||
604 | "user", "system", "iowait", "idle" | ||
605 | }; | ||
606 | |||
607 | static unsigned long long spu_acct_time(struct spu *spu, | ||
608 | enum spu_utilization_state state) | ||
609 | { | ||
610 | unsigned long long time = spu->stats.times[state]; | ||
611 | |||
612 | if (spu->stats.utilization_state == state) | ||
613 | time += jiffies - spu->stats.tstamp; | ||
614 | |||
615 | return jiffies_to_msecs(time); | ||
616 | } | ||
617 | |||
618 | |||
619 | static ssize_t spu_stat_show(struct sys_device *sysdev, char *buf) | ||
620 | { | ||
621 | struct spu *spu = container_of(sysdev, struct spu, sysdev); | ||
622 | |||
623 | return sprintf(buf, "%s %llu %llu %llu %llu " | ||
624 | "%llu %llu %llu %llu %llu %llu %llu %llu\n", | ||
625 | spu_state_names[spu->stats.utilization_state], | ||
626 | spu_acct_time(spu, SPU_UTIL_USER), | ||
627 | spu_acct_time(spu, SPU_UTIL_SYSTEM), | ||
628 | spu_acct_time(spu, SPU_UTIL_IOWAIT), | ||
629 | spu_acct_time(spu, SPU_UTIL_IDLE), | ||
630 | spu->stats.vol_ctx_switch, | ||
631 | spu->stats.invol_ctx_switch, | ||
632 | spu->stats.slb_flt, | ||
633 | spu->stats.hash_flt, | ||
634 | spu->stats.min_flt, | ||
635 | spu->stats.maj_flt, | ||
636 | spu->stats.class2_intr, | ||
637 | spu->stats.libassist); | ||
638 | } | ||
639 | |||
640 | static SYSDEV_ATTR(stat, 0644, spu_stat_show, NULL); | ||
641 | |||
600 | static int __init init_spu_base(void) | 642 | static int __init init_spu_base(void) |
601 | { | 643 | { |
602 | int i, ret = 0; | 644 | int i, ret = 0; |
@@ -622,6 +664,8 @@ static int __init init_spu_base(void) | |||
622 | 664 | ||
623 | xmon_register_spus(&spu_full_list); | 665 | xmon_register_spus(&spu_full_list); |
624 | 666 | ||
667 | spu_add_sysdev_attr(&attr_stat); | ||
668 | |||
625 | return 0; | 669 | return 0; |
626 | 670 | ||
627 | out_unregister_sysdev_class: | 671 | 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) | |||
187 | dsisr, ctx->state); | 187 | dsisr, ctx->state); |
188 | 188 | ||
189 | ctx->stats.hash_flt++; | 189 | ctx->stats.hash_flt++; |
190 | if (ctx->state == SPU_STATE_RUNNABLE) { | ||
191 | ctx->spu->stats.hash_flt++; | ||
192 | spu_switch_state(ctx->spu, SPU_UTIL_IOWAIT); | ||
193 | } | ||
190 | 194 | ||
191 | /* we must not hold the lock when entering spu_handle_mm_fault */ | 195 | /* we must not hold the lock when entering spu_handle_mm_fault */ |
192 | spu_release(ctx); | 196 | spu_release(ctx); |
@@ -212,6 +216,12 @@ int spufs_handle_class1(struct spu_context *ctx) | |||
212 | ctx->stats.min_flt++; | 216 | ctx->stats.min_flt++; |
213 | else | 217 | else |
214 | ctx->stats.maj_flt++; | 218 | ctx->stats.maj_flt++; |
219 | if (ctx->state == SPU_STATE_RUNNABLE) { | ||
220 | if (flt == VM_FAULT_MINOR) | ||
221 | ctx->spu->stats.min_flt++; | ||
222 | else | ||
223 | ctx->spu->stats.maj_flt++; | ||
224 | } | ||
215 | 225 | ||
216 | if (ctx->spu) | 226 | if (ctx->spu) |
217 | ctx->ops->restart_dma(ctx); | 227 | 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, | |||
352 | SPU_STATUS_SINGLE_STEP))); | 352 | SPU_STATUS_SINGLE_STEP))); |
353 | 353 | ||
354 | if ((status & SPU_STATUS_STOPPED_BY_STOP) && | 354 | if ((status & SPU_STATUS_STOPPED_BY_STOP) && |
355 | (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100)) | 355 | (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100) && |
356 | (ctx->state == SPU_STATE_RUNNABLE)) | ||
356 | ctx->stats.libassist++; | 357 | ctx->stats.libassist++; |
357 | 358 | ||
358 | ctx->ops->master_stop(ctx); | 359 | 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) | |||
251 | spu_cpu_affinity_set(spu, raw_smp_processor_id()); | 251 | spu_cpu_affinity_set(spu, raw_smp_processor_id()); |
252 | spu_switch_notify(spu, ctx); | 252 | spu_switch_notify(spu, ctx); |
253 | ctx->state = SPU_STATE_RUNNABLE; | 253 | ctx->state = SPU_STATE_RUNNABLE; |
254 | spu_switch_state(spu, SPU_UTIL_SYSTEM); | ||
254 | } | 255 | } |
255 | 256 | ||
256 | /** | 257 | /** |
@@ -263,6 +264,8 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx) | |||
263 | pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__, | 264 | pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__, |
264 | spu->pid, spu->number, spu->node); | 265 | spu->pid, spu->number, spu->node); |
265 | 266 | ||
267 | spu_switch_state(spu, SPU_UTIL_IDLE); | ||
268 | |||
266 | spu_switch_notify(spu, NULL); | 269 | spu_switch_notify(spu, NULL); |
267 | spu_unmap_mappings(ctx); | 270 | spu_unmap_mappings(ctx); |
268 | spu_save(&ctx->csa, spu); | 271 | spu_save(&ctx->csa, spu); |
@@ -426,6 +429,7 @@ static struct spu *find_victim(struct spu_context *ctx) | |||
426 | spu_remove_from_active_list(spu); | 429 | spu_remove_from_active_list(spu); |
427 | spu_unbind_context(spu, victim); | 430 | spu_unbind_context(spu, victim); |
428 | victim->stats.invol_ctx_switch++; | 431 | victim->stats.invol_ctx_switch++; |
432 | spu->stats.invol_ctx_switch++; | ||
429 | mutex_unlock(&victim->state_mutex); | 433 | mutex_unlock(&victim->state_mutex); |
430 | /* | 434 | /* |
431 | * We need to break out of the wait loop in spu_run | 435 | * 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) | |||
526 | spu_remove_from_active_list(spu); | 530 | spu_remove_from_active_list(spu); |
527 | spu_unbind_context(spu, ctx); | 531 | spu_unbind_context(spu, ctx); |
528 | ctx->stats.vol_ctx_switch++; | 532 | ctx->stats.vol_ctx_switch++; |
533 | spu->stats.vol_ctx_switch++; | ||
529 | spu_free(spu); | 534 | spu_free(spu); |
530 | if (new) | 535 | if (new) |
531 | wake_up(&new->stop_wq); | 536 | wake_up(&new->stop_wq); |
@@ -572,8 +577,10 @@ void spu_yield(struct spu_context *ctx) | |||
572 | mutex_lock(&ctx->state_mutex); | 577 | mutex_lock(&ctx->state_mutex); |
573 | if (__spu_deactivate(ctx, 0, MAX_PRIO)) | 578 | if (__spu_deactivate(ctx, 0, MAX_PRIO)) |
574 | spuctx_switch_state(ctx, SPUCTX_UTIL_USER); | 579 | spuctx_switch_state(ctx, SPUCTX_UTIL_USER); |
575 | else | 580 | else { |
576 | spuctx_switch_state(ctx, SPUCTX_UTIL_LOADED); | 581 | spuctx_switch_state(ctx, SPUCTX_UTIL_LOADED); |
582 | spu_switch_state(ctx->spu, SPU_UTIL_USER); | ||
583 | } | ||
577 | mutex_unlock(&ctx->state_mutex); | 584 | mutex_unlock(&ctx->state_mutex); |
578 | } | 585 | } |
579 | } | 586 | } |
@@ -603,6 +610,7 @@ static void spusched_tick(struct spu_context *ctx) | |||
603 | __spu_remove_from_active_list(spu); | 610 | __spu_remove_from_active_list(spu); |
604 | spu_unbind_context(spu, ctx); | 611 | spu_unbind_context(spu, ctx); |
605 | ctx->stats.invol_ctx_switch++; | 612 | ctx->stats.invol_ctx_switch++; |
613 | spu->stats.invol_ctx_switch++; | ||
606 | spu_free(spu); | 614 | spu_free(spu); |
607 | wake_up(&new->stop_wq); | 615 | wake_up(&new->stop_wq); |
608 | /* | 616 | /* |
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, | |||
307 | } | 307 | } |
308 | } | 308 | } |
309 | 309 | ||
310 | static inline void spu_switch_state(struct spu *spu, | ||
311 | enum spuctx_execution_state new_state) | ||
312 | { | ||
313 | if (spu->stats.utilization_state != new_state) { | ||
314 | unsigned long curtime = jiffies; | ||
315 | |||
316 | spu->stats.times[spu->stats.utilization_state] += | ||
317 | curtime - spu->stats.tstamp; | ||
318 | spu->stats.tstamp = curtime; | ||
319 | spu->stats.utilization_state = new_state; | ||
320 | } | ||
321 | } | ||
322 | |||
310 | #endif | 323 | #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; | |||
106 | struct spu_runqueue; | 106 | struct spu_runqueue; |
107 | struct device_node; | 107 | struct device_node; |
108 | 108 | ||
109 | enum spu_utilization_state { | ||
110 | SPU_UTIL_SYSTEM, | ||
111 | SPU_UTIL_USER, | ||
112 | SPU_UTIL_IOWAIT, | ||
113 | SPU_UTIL_IDLE, | ||
114 | SPU_UTIL_MAX | ||
115 | }; | ||
116 | |||
109 | struct spu { | 117 | struct spu { |
110 | const char *name; | 118 | const char *name; |
111 | unsigned long local_store_phys; | 119 | unsigned long local_store_phys; |
@@ -159,8 +167,17 @@ struct spu { | |||
159 | 167 | ||
160 | struct { | 168 | struct { |
161 | /* protected by interrupt reentrancy */ | 169 | /* protected by interrupt reentrancy */ |
170 | enum spu_utilization_state utilization_state; | ||
171 | unsigned long tstamp; /* time of last ctx switch */ | ||
172 | unsigned long times[SPU_UTIL_MAX]; | ||
173 | unsigned long long vol_ctx_switch; | ||
174 | unsigned long long invol_ctx_switch; | ||
175 | unsigned long long min_flt; | ||
176 | unsigned long long maj_flt; | ||
177 | unsigned long long hash_flt; | ||
162 | unsigned long long slb_flt; | 178 | unsigned long long slb_flt; |
163 | unsigned long long class2_intr; | 179 | unsigned long long class2_intr; |
180 | unsigned long long libassist; | ||
164 | } stats; | 181 | } stats; |
165 | }; | 182 | }; |
166 | 183 | ||