--- save/arch/ia64/kernel/entry.S 2006-03-15 11:07:38.000000000 +0100 +++ linux-2.6.16/arch/ia64/kernel/entry.S 2006-04-03 12:48:03.000000000 +0200 @@ -1619,5 +1619,6 @@ sys_call_table: data8 sys_ni_syscall // reserved for pselect data8 sys_ni_syscall // 1295 reserved for ppoll data8 sys_unshare + data8 sys_trap_statistics // 1297 .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls --- save/arch/ia64/kernel/ivt.S 2006-03-30 16:19:18.000000000 +0200 +++ linux-2.6.16/arch/ia64/kernel/ivt.S 2006-04-03 14:58:20.000000000 +0200 @@ -108,6 +108,36 @@ ENTRY(vhpt_miss) movl r18=PAGE_SHIFT mov r25=cr.itir #endif +#if 0 + /* + * Increment the VHPT miss counter - must be identity mapped. + */ + LOAD_PHYSICAL(p0, r17, fault_statistics + VHPT_idx * _ENTRY_SIZE_) + movl r21=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff) + movl r19=PAGE_OFFSET + movl r20=PAGE_SHIFT << 2 // ... and protection key == 0 + movl r22=PAGE_KERNEL + ;; + or r19=r19,r17 // __va(&fault_statistics[VHPT_idx] + and r21=r21,r17 // Clear ed, reserved bits, and PTE control bits + ;; + mov cr.ifa=r19 + mov cr.itir=r20 + or r21=r21,r22 // Insert control bits + ;; + itc.d r21 + ;; + srlz.d + // Unsafe: the translation can be killed in the mean time + ld8.bias.nta r17=[r19] // = fault_statistics[VHPT_idx] + ;; + add r17=1,r17 + mov cr.ifa=r16 // Restore + mov cr.itir=r25 + ;; + // Unsafe: the translation can be killed in the mean time + st8 [r19]=r17 // Not atomic increment - who cares? +#endif ;; rsm psr.dt // use physical addressing for data mov r31=pr // save the predicate registers @@ -132,6 +162,17 @@ ENTRY(vhpt_miss) (p7) dep r17=r17,r19,(PAGE_SHIFT-3),3 // put region number bits in place srlz.d + /* + * Increment the VHPT miss counter. + */ + LOAD_PHYSICAL(p0, r19, fault_statistics + VHPT_idx * _ENTRY_SIZE_) + ;; + ld8.bias.nta r28=[r19] + ;; + add r28=1,r28 + ;; + st8 [r19]=r28 // Not atomic increment - who cares? + LOAD_PHYSICAL(p6, r19, swapper_pg_dir) // region 5 is rooted at swapper_pg_dir .pred.rel "mutex", p6, p7 @@ -197,11 +238,12 @@ ENTRY(vhpt_miss) ;; #ifdef CONFIG_SMP /* - * Tell the assemblers dependency-violation checker that the above "itc" instructions - * cannot possibly affect the following loads: + * We make sure the visibility of itc.* to generated purges (like ptc.ga) + * before we re-read the *pgd ... PTE. + * Having itc.i-d a new translation, there is no need for srlz.i, the rfi below + * will do the serialization. */ - dv_serialize_data - +(p7) srlz.d /* * Re-check pagetable entry. If they changed, we may have received a ptc.g * between reading the pagetable and the "itc". If so, flush the entry we @@ -229,9 +271,34 @@ ENTRY(vhpt_miss) mov r27=PAGE_SHIFT<<2 ;; (p6) ptc.l r22,r27 // purge PTE page translation + /* + * Increment the VHPT miss - purge PTE page counter. + * It is the next long. Accessed via its physical address. + */ + dv_serialize_data + LOAD_PHYSICAL(p6, r19, fault_statistics + (VHPT_idx + 1) * _ENTRY_SIZE_) + ;; +(p6) ld8.bias.nta r17=[r19] + ;; +(p6) add r17=1,r17 + ;; +(p6) st8 [r19]=r17 // Not atomic increment - who cares? + (p7) cmp.ne.or.andcm p6,p7=r25,r18 // did *pte change ;; (p6) ptc.l r16,r27 // purge translation + /* + * Increment the VHPT miss - purge PTE page counter. + * It is in the 2nd next long. Accessed via its physical address. + */ + dv_serialize_data + LOAD_PHYSICAL(p6, r19, fault_statistics + (VHPT_idx + 2) * _ENTRY_SIZE_) + ;; +(p6) ld8.bias.nta r17=[r19] + ;; +(p6) add r17=1,r17 + ;; +(p6) st8 [r19]=r17 // Not atomic increment - who cares? #endif mov pr=r31,-1 // restore predicate registers @@ -266,16 +333,36 @@ ENTRY(itlb_miss) ;; #ifdef CONFIG_SMP /* - * Tell the assemblers dependency-violation checker that the above "itc" instructions - * cannot possibly affect the following loads: + * We make sure the visibility of itc.i to generated purges (like ptc.ga) + * before we re-read the PTE. + * There is no need for srlz.i, the rfi below will do the serialization. */ - dv_serialize_data - + srlz.d ld8 r19=[r17] // read *pte again and see if same mov r20=PAGE_SHIFT<<2 // setup page size for purge ;; cmp.ne p7,p0=r18,r19 ;; + /* + * Increment the ITLB miss counters. + */ + rsm psr.dt // use physical addressing for data + ;; + srlz.d + LOAD_PHYSICAL(p0, r19, fault_statistics + ITLB_idx * _ENTRY_SIZE_) + ;; + ld8.bias.nta r28=[r19] + ;; + add r28=1,r28 + ;; + st8 [r19]=r28,8 // Not atomic increment - who cares? + ;; +(p7) ld8.bias.nta r28=[r19] // Next long: ITLB miss - purged + ;; +(p7) add r28=1,r28 + ;; +(p7) st8 [r19]=r28 // Not atomic increment - who cares? + (p7) ptc.l r16,r20 #endif mov pr=r31,-1 @@ -310,16 +397,35 @@ dtlb_fault: ;; #ifdef CONFIG_SMP /* - * Tell the assemblers dependency-violation checker that the above "itc" instructions - * cannot possibly affect the following loads: + * We make sure the visibility of itc.d to generated purges (like ptc.ga) + * before we re-read the PTE. */ - dv_serialize_data - + srlz.d ld8 r19=[r17] // read *pte again and see if same mov r20=PAGE_SHIFT<<2 // setup page size for purge ;; cmp.ne p7,p0=r18,r19 ;; + /* + * Increment the DTLB miss counters. + */ + rsm psr.dt // use physical addressing for data + ;; + srlz.d + LOAD_PHYSICAL(p0, r19, fault_statistics + DTLB_idx * _ENTRY_SIZE_) + ;; + ld8.bias.nta r28=[r19] + ;; + add r28=1,r28 + ;; + st8 [r19]=r28,8 // Not atomic increment - who cares? + ;; +(p7) ld8.bias.nta r28=[r19] // Next long: DTLB miss - purged + ;; +(p7) add r28=1,r28 + ;; +(p7) st8 [r19]=r28 // Not atomic increment - who cares? + (p7) ptc.l r16,r20 #endif mov pr=r31,-1 @@ -589,6 +695,26 @@ ENTRY(dirty_bit) * very same dirty bit as we wanted to => our new translation is correct) */ (p7) ptc.l r16,r24 + /* + * Increment the DIRTY trap counters. + */ + rsm psr.dt // use physical addressing for data + ;; + srlz.d + LOAD_PHYSICAL(p0, r19, fault_statistics + DIRTY_idx * _ENTRY_SIZE_) + ;; + ld8.bias.nta r27=[r19] + ;; + add r27=1,r27 + ;; + st8 [r19]=r27,8 // Not atomic increment - who cares? + ;; +(p7) ld8.bias.nta r27=[r19] // Next long: DIRTY - purged + ;; +(p7) add r27=1,r27 + ;; +(p7) st8 [r19]=r27 // Not atomic increment - who cares? + mov b0=r29 // restore b0 mov ar.ccv=r28 #else @@ -650,6 +776,26 @@ ENTRY(iaccess_bit) mov r24=PAGE_SHIFT << 2 ;; (p7) ptc.l r16,r24 + /* + * Increment the I-ACCESS trap counters. + */ + rsm psr.dt // use physical addressing for data + ;; + srlz.d + LOAD_PHYSICAL(p0, r19, fault_statistics + IACC_idx * _ENTRY_SIZE_) + ;; + ld8.bias.nta r27=[r19] + ;; + add r27=1,r27 + ;; + st8 [r19]=r27,8 // Not atomic increment - who cares? + ;; +(p7) ld8.bias.nta r27=[r19] // Next long: I-ACCESS - purged + ;; +(p7) add r27=1,r27 + ;; +(p7) st8 [r19]=r27 // Not atomic increment - who cares? + mov b0=r29 // restore b0 mov ar.ccv=r28 #else @@ -700,6 +846,26 @@ ENTRY(daccess_bit) mov r24=PAGE_SHIFT << 2 ;; (p7) ptc.l r16,r24 + /* + * Increment the D-ACCESS trap counters. + */ + rsm psr.dt // use physical addressing for data + ;; + srlz.d + LOAD_PHYSICAL(p0, r19, fault_statistics + DACC_idx * _ENTRY_SIZE_) + ;; + ld8.bias.nta r27=[r19] + ;; + add r27=1,r27 + ;; + st8 [r19]=r27,8 // Not atomic increment - who cares? + ;; +(p7) ld8.bias.nta r27=[r19] // Next long: D-ACCESS - purged + ;; +(p7) add r27=1,r27 + ;; +(p7) st8 [r19]=r27 // Not atomic increment - who cares? + mov b0=r29 // restore b0 mov ar.ccv=r28 #else --- save/kernel/sched.c 2006-03-15 11:09:03.000000000 +0100 +++ linux-2.6.16/kernel/sched.c 2006-04-03 15:06:57.000000000 +0200 @@ -199,6 +192,26 @@ struct prio_array { struct list_head queue[MAX_PRIO]; }; + +long fault_statistics[MAX_TRAP_idx]; + + +/* + * Read / clear trap statistics + */ +asmlinkage long sys_trap_statistics(int index) +{ + if (index >= 0 && index < MAX_TRAP_idx) + return fault_statistics[index]; + if (index == -1){ + for (index = 0; index < MAX_TRAP_idx; index++) + fault_statistics[index] = 0; + return 0; + } + return -EINVAL; +} + + /* * This is the main, per-CPU runqueue data structure. * --- save/include/asm-ia64/system.h 2006-03-15 11:08:53.000000000 +0100 +++ linux-2.6.16/include/asm-ia64/system.h 2006-04-03 14:26:19.000000000 +0200 @@ -262,4 +262,28 @@ void sched_cacheflush(void); #endif /* __ASSEMBLY__ */ + +/* + * For trap statistics + */ +#define VHPT_idx 0 // VHPT miss counter +#define VHPT_HASH_PTC_idx 1 // VHPT miss - hash purged +#define VHPT_PTE_PTC_idx 2 // VHPT miss - PTE purged +#define ITLB_idx 3 // ITLB miss counter +#define ITLB_PTC_idx 4 // ITLB miss - purged +#define DTLB_idx 5 // DTLB miss counter +#define DTLB_PTC_idx 6 // DTLB miss - purged +#define DIRTY_idx 7 // DIRTY trap counter +#define DIRTY_PTC_idx 8 // DIRTY - purged +#define IACC_idx 9 // I-ACCESS trap counter +#define IACC_PTC_idx 10 // I-ACCESS - purged +#define DACC_idx 11 // D-ACCESS trap counter +#define DACC_PTC_idx 12 // D-ACCESS - purged + + +#define MAX_TRAP_idx 13 + +#define _ENTRY_SIZE_ 8 + + #endif /* _ASM_IA64_SYSTEM_H */ --- save/include/asm-ia64/unistd.h 2006-03-15 11:08:53.000000000 +0100 +++ linux-2.6.16/include/asm-ia64/unistd.h 2006-04-03 12:46:40.000000000 +0200 @@ -290,7 +290,7 @@ #include -#define NR_syscalls 273 /* length of syscall table */ +#define NR_syscalls 274 /* length of syscall table */ #define __ARCH_WANT_SYS_RT_SIGACTION