Subject: FP exception statistics

From: Atsushi Nemoto <[email-masked]>
Date: Wed, 21 Nov 2001 16:03:47 +0900 (JST)

Sometimes I want to know what kind of (and how many times) FP
exceptions occurred in run time.  Here is a patch to provide us these
informations via /proc/cpuinfo.

Any comments are welcome.  (This patch is not tested on SMP)

diff -ur linux-sgi-cvs/arch/mips/config.in linux.new/arch/mips/config.in
--- linux-sgi-cvs/arch/mips/config.in	Wed Nov 21 10:31:56 2001
+++ linux.new/arch/mips/config.in	Wed Nov 21 15:45:44 2001
@@ -359,6 +359,7 @@
 else
    bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN
 fi
+bool 'Support for FPU Exception statistics' CONFIG_MIPS_FPE_STATS
 
 if [ "$CONFIG_PROC_FS" = "y" ]; then
    define_bool CONFIG_KCORE_ELF y
diff -ur linux-sgi-cvs/arch/mips/kernel/proc.c linux.new/arch/mips/kernel/proc.c
--- linux-sgi-cvs/arch/mips/kernel/proc.c	Mon Oct 22 10:29:56 2001
+++ linux.new/arch/mips/kernel/proc.c	Wed Nov 21 15:43:24 2001
@@ -19,6 +19,10 @@
 #ifndef CONFIG_CPU_HAS_LLSC
 unsigned long ll_ops, sc_ops;
 #endif
+#ifdef CONFIG_MIPS_FPE_STATS
+unsigned int fpu_exceptions[6];
+static char fpe_types[6] = {'I', 'U', 'O', 'Z', 'V', 'E'};
+#endif
 
 /*
  * BUFFER is PAGE_SIZE bytes long.
@@ -61,6 +65,9 @@
 		mach_nec_vr41xx_names};
 	unsigned int version = read_32bit_cp0_register(CP0_PRID);
 	int len;
+#ifdef CONFIG_MIPS_FPE_STATS
+	int i;
+#endif
 
 	len = sprintf(buffer, "cpu\t\t\t: MIPS\n");
 	len += sprintf(buffer + len, "cpu model\t\t: %s V%d.%d\n",
@@ -101,6 +108,14 @@
 		       ll_ops);
 	len += sprintf(buffer + len, "sc emulations\t\t: %lu\n",
 		       sc_ops);
+#endif
+#ifdef CONFIG_MIPS_FPE_STATS
+	len += sprintf(buffer + len, "fpu exceptions\t\t:");
+	for (i = 0; i < sizeof(fpu_exceptions) / sizeof(fpu_exceptions[0]); i++) {
+		len += sprintf(buffer + len, " %u(%c)",
+			       fpu_exceptions[i], fpe_types[i]);
+	}
+	len += sprintf(buffer + len, "\n");
 #endif
 	return len;
 }
diff -ur linux-sgi-cvs/arch/mips/kernel/traps.c linux.new/arch/mips/kernel/traps.c
--- linux-sgi-cvs/arch/mips/kernel/traps.c	Wed Nov 21 10:31:57 2001
+++ linux.new/arch/mips/kernel/traps.c	Wed Nov 21 15:46:15 2001
@@ -461,6 +461,18 @@
  */
 asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
 {
+#ifdef CONFIG_MIPS_FPE_STATS
+	extern unsigned int fpu_exceptions[];
+	unsigned char fpe;
+	int i;
+	fpe = ((fcr31 & FPU_CSR_ALL_X) / FPU_CSR_INE_X) &
+		((fcr31 | ~FPU_CSR_ALL_E) / FPU_CSR_INE_E);
+	for (i = 0; i < 6; i++) {
+		if (fpe & (1 << i))
+			fpu_exceptions[i]++;
+	}
+#endif
+
 	if (fcr31 & FPU_CSR_UNI_X) {
 		extern void save_fp(struct task_struct *);
 		extern void restore_fp(struct task_struct *);
---
Atsushi Nemoto

---

From: Ralf Baechle <[email-masked]>
Date: Wed, 21 Nov 2001 19:25:30 +1100

> Any comments are welcome.  (This patch is not tested on SMP)

It get's atomicity wrong.  I suggest to make such statistics a per thread
thing.  That'll not only solve the SMP issues but also make sure processes
running in parallel won't influence the result.

  Ralf

---

From: Atsushi Nemoto <[email-masked]>
Date: Wed, 21 Nov 2001 20:29:06 +0900 (JST)

>>>>> On Wed, 21 Nov 2001 19:25:30 +1100, Ralf Baechle <[email-masked]> said:
ralf> It get's atomicity wrong.  I suggest to make such statistics a
ralf> per thread thing.  That'll not only solve the SMP issues but
ralf> also make sure processes running in parallel won't influence the
ralf> result.

Thank you for the comment.

Yes, my patch provides "CPU" statistics (not "thread" statistics).
Counting per thread might be useful in some case, but counting
globally (like "unaligned_instructions" or "ll_ops" counter) is enough
for me.

---
Atsushi Nemoto

---

From: Ralf Baechle <[email-masked]>
Date: Thu, 22 Nov 2001 00:00:40 +1100

> globally (like "unaligned_instructions" or "ll_ops" counter) is enough

Those are certainly unlucky examples for performance counter interfaces.
We have further problems to solve in that area.  Many current cpus
implement performance counters and right now Linux/MIPS doesn't use or
support those at all.  Unfortunately performance counter implementations
differ wildly.  We have to deciede about an interface that's supportable
by all the hardware out there.

  Ralf