diff options
author | Christoph Hellwig <hch@lst.de> | 2007-06-28 20:58:03 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-07-03 01:24:46 -0400 |
commit | e9f8a0b65ac716fd7974159240ce34bddea780b3 (patch) | |
tree | 70e9541861443fc378adc8cc924522e9eb73ab33 | |
parent | 65de66f0b8bcb7431d9df82cf32b002062b3a611 (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.c | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/context.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/fault.c | 19 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/file.c | 79 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/run.c | 4 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/sched.c | 19 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/spufs.h | 51 | ||||
-rw-r--r-- | include/asm-powerpc/spu.h | 6 |
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 | */ |
36 | static int spu_handle_mm_fault(struct mm_struct *mm, unsigned long ea, unsigned long dsisr) | 36 | static 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 | } |
211 | EXPORT_SYMBOL_GPL(spufs_handle_class1); | 224 | EXPORT_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 | ||
2062 | static const char *ctx_state_names[] = { | ||
2063 | "user", "system", "iowait", "loaded" | ||
2064 | }; | ||
2065 | |||
2066 | static 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 | |||
2077 | static 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 | |||
2089 | static 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 | |||
2102 | static 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 | |||
2126 | static 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 | |||
2131 | static 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 | |||
2062 | struct tree_descr spufs_dir_contents[] = { | 2139 | struct 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 | */ |
426 | int spu_activate(struct spu_context *ctx, unsigned long flags) | 436 | int 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 { | |||
40 | struct spu_context_ops; | 40 | struct spu_context_ops; |
41 | struct spu_gang; | 41 | struct 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 | */ | ||
48 | enum 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 | |||
43 | struct spu_context { | 56 | struct 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 | ||
92 | struct spu_gang { | 123 | struct spu_gang { |
@@ -256,4 +287,24 @@ struct spufs_coredump_reader { | |||
256 | extern struct spufs_coredump_reader spufs_coredump_read[]; | 287 | extern struct spufs_coredump_reader spufs_coredump_read[]; |
257 | extern int spufs_coredump_num_notes; | 288 | extern 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 | */ | ||
295 | static 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 | ||
161 | struct spu *spu_alloc(void); | 167 | struct spu *spu_alloc(void); |