Linux MIPS Architecture development
 help / color / mirror / Atom feed
* Cache flush statistics patch to c-mips32.c
@ 2003-04-02 19:16 Hartvig Ekner
  2003-04-02 20:05 ` Ralf Baechle
  0 siblings, 1 reply; 2+ messages in thread
From: Hartvig Ekner @ 2003-04-02 19:16 UTC (permalink / raw)
  To: Linux MIPS mailing list


[-- Attachment #1.1: Type: text/plain, Size: 1159 bytes --]

Below is a patch with some cache statistics counters added to c-mips32.c.
They are turned on by the local define DEBUG_COUNTERS in case somebody wants to
play with them.

A sample output:

[root@au01 root]# more /proc/cmips32_cache_stats

Cache statistics from c-mips32.c:

mips32_flush_cache_all_pc:      83384    mips32_flush_cache_all_sc:          0
mips32_flush_cache_range_pc:    37276    mips32_flush_cache_range_sc:        0
mips32_flush_cache_mm_pc:        2121    mips32_flush_cache_mm_sc:           0
mips32_flush_cache_page_pc:     36282    mips32_flush_cache_page_sc:         0

mips32_flush_icache_all:            0    mips32_flush_icache_page_s:         0
mips32_flush_icache_range:          4    mips32_flush_icache_page:       93545
mips32_flush_data_cache_page:   31905    mips32_flush_cache_sigtramp:     2467

dma_cache_wback_inv_pc:          7029    dma_cache_wback_inv_sc:             0
dma_cache_inv_pc:                   0    dma_cache_inv_sc:                   0


These counts are from a system which has just booted, nothing else. While running
some programs, the flush_cache_all is called up to 400 times pr. second (!).

/Hartvig


[-- Attachment #1.2: Type: text/html, Size: 2498 bytes --]

[-- Attachment #2: cmips32_patch --]
[-- Type: text/plain, Size: 12169 bytes --]

Index: c-mips32.c
===================================================================
RCS file: /home/cvs/linux/arch/mips/mm/c-mips32.c,v
retrieving revision 1.3.2.17
diff -u -r1.3.2.17 c-mips32.c
--- c-mips32.c	31 Mar 2003 23:29:06 -0000	1.3.2.17
+++ c-mips32.c	2 Apr 2003 19:01:35 -0000
@@ -17,6 +17,10 @@
  *
  * MIPS32 CPU variant specific MMU/Cache routines.
  */
+
+#undef	DEBUG_CACHE		/* Control debug printk's	*/
+#undef	DEBUG_COUNTERS		/* Control statistics counters	*/
+
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -32,6 +36,40 @@
 #include <asm/system.h>
 #include <asm/mmu_context.h>
 
+
+#ifndef	DEBUG_COUNTERS
+#define	DEBUG_INCCNT(cnt)
+#else
+
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+
+#define	DEBUG_INCCNT(cnt)	cnt++
+
+static int cnt_mips32_flush_cache_all_sc = 0;	/* All the bean counters */
+static int cnt_mips32_flush_cache_all_pc = 0;
+static int cnt_mips32_flush_cache_range_sc = 0;
+static int cnt_mips32_flush_cache_range_pc = 0;
+static int cnt_mips32_flush_cache_mm_sc = 0;
+static int cnt_mips32_flush_cache_mm_pc = 0;
+static int cnt_mips32_flush_cache_page_sc = 0;
+static int cnt_mips32_flush_cache_page_pc = 0;
+
+static int cnt_mips32_flush_icache_all = 0;
+static int cnt_mips32_flush_icache_page_s = 0;
+static int cnt_mips32_flush_icache_range = 0;
+static int cnt_mips32_flush_icache_page = 0;
+static int cnt_mips32_flush_data_cache_page = 0;
+static int cnt_mips32_flush_cache_sigtramp = 0;
+
+static int cnt_dma_cache_wback_inv_pc = 0;
+static int cnt_dma_cache_wback_inv_sc = 0;
+static int cnt_dma_cache_inv_pc = 0;
+static int cnt_dma_cache_inv_sc = 0;
+
+#endif
+
+
 /* Primary cache parameters. */
 int icache_size, dcache_size; 			/* Size in bytes */
 int ic_lsize, dc_lsize;				/* LineSize in bytes */
@@ -42,7 +80,6 @@
 #include <asm/cacheops.h>
 #include <asm/mips32_cache.h>
 
-#undef DEBUG_CACHE
 
 /*
  * Dummy cache handling routines for machines without boardcaches
@@ -62,6 +99,8 @@
 {
 	unsigned long flags;
 
+	DEBUG_INCCNT(cnt_mips32_flush_cache_all_sc);
+
 	local_irq_save(flags);
 	blast_dcache(); blast_icache(); blast_scache();
 	local_irq_restore(flags);
@@ -71,6 +110,8 @@
 {
 	unsigned long flags;
 
+	DEBUG_INCCNT(cnt_mips32_flush_cache_all_pc);
+
 	local_irq_save(flags);
 	blast_dcache(); blast_icache();
 	local_irq_restore(flags);
@@ -84,6 +125,8 @@
 	struct vm_area_struct *vma;
 	unsigned long flags;
 
+	DEBUG_INCCNT(cnt_mips32_flush_cache_range_sc);
+
 	if (cpu_context(smp_processor_id(), mm) == 0)
 		return;
 
@@ -119,6 +162,8 @@
 				     unsigned long start,
 				     unsigned long end)
 {
+	DEBUG_INCCNT(cnt_mips32_flush_cache_range_pc);
+
 	if (cpu_context(smp_processor_id(), mm) != 0) {
 		unsigned long flags;
 
@@ -138,6 +183,8 @@
  */
 static void mips32_flush_cache_mm_sc(struct mm_struct *mm)
 {
+	DEBUG_INCCNT(cnt_mips32_flush_cache_mm_sc);
+
 	if (cpu_context(smp_processor_id(), mm) != 0) {
 #ifdef DEBUG_CACHE
 		printk("cmm[%d]", cpu_context(smp_processor_id(), mm));
@@ -148,6 +195,8 @@
 
 static void mips32_flush_cache_mm_pc(struct mm_struct *mm)
 {
+	DEBUG_INCCNT(cnt_mips32_flush_cache_mm_pc);
+
 	if (cpu_context(smp_processor_id(), mm) != 0) {
 #ifdef DEBUG_CACHE
 		printk("cmm[%d]", cpu_context(smp_processor_id(), mm));
@@ -164,6 +213,8 @@
 	pmd_t *pmdp;
 	pte_t *ptep;
 
+	DEBUG_INCCNT(cnt_mips32_flush_cache_page_sc);
+
 	/*
 	 * If ownes no valid ASID yet, cannot possibly have gotten
 	 * this page into the cache.
@@ -212,6 +263,8 @@
 	pmd_t *pmdp;
 	pte_t *ptep;
 
+	DEBUG_INCCNT(cnt_mips32_flush_cache_page_pc);
+
 	/*
 	 * If ownes no valid ASID yet, cannot possibly have gotten
 	 * this page into the cache.
@@ -251,17 +304,20 @@
 	}
 }
 
-static void mips32_flush_data_cache_page(unsigned long addr)
+static void mips32_flush_icache_all(void)
 {
-	if (sc_lsize)
-		blast_scache_page(addr);
-	else
-		blast_dcache_page(addr);
+	DEBUG_INCCNT(cnt_mips32_flush_icache_all);
+
+	if (mips_cpu.icache.flags | MIPS_CACHE_VTAG_CACHE) {
+		blast_icache();
+	}
 }
 
 static void
 mips32_flush_icache_page_s(struct vm_area_struct *vma, struct page *page)
 {
+	DEBUG_INCCNT(cnt_mips32_flush_icache_page_s);
+
 	/*
 	 * We did an scache flush therefore PI is already clean.
 	 */
@@ -270,12 +326,16 @@
 static void
 mips32_flush_icache_range(unsigned long start, unsigned long end)
 {
+	DEBUG_INCCNT(cnt_mips32_flush_icache_range);
+
 	flush_cache_all();
 }
 
 static void
 mips32_flush_icache_page(struct vm_area_struct *vma, struct page *page)
 {
+	DEBUG_INCCNT(cnt_mips32_flush_icache_page);
+
 	/*
 	 * If there's no context yet, or the page isn't executable, no icache 
 	 * flush is needed.
@@ -290,15 +350,45 @@
 	flush_cache_all();
 }
 
+static void mips32_flush_data_cache_page(unsigned long addr)
+{
+	DEBUG_INCCNT(cnt_mips32_flush_data_cache_page);
+
+	if (sc_lsize)
+		blast_scache_page(addr);
+	else
+		blast_dcache_page(addr);
+}
+
+
+/*
+ * While we're protected against bad userland addresses we don't care
+ * very much about what happens in that case.  Usually a segmentation
+ * fault will dump the process later on anyway ...
+ */
+static void mips32_flush_cache_sigtramp(unsigned long addr)
+{
+	DEBUG_INCCNT(cnt_mips32_flush_cache_sigtramp);
+
+	protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
+	protected_flush_icache_line(addr & ~(ic_lsize - 1));
+}
+
+
 /*
  * Writeback and invalidate the primary cache dcache before DMA.
  */
+
+#ifdef	CONFIG_NONCOHERENT_IO
+
 static void
 mips32_dma_cache_wback_inv_pc(unsigned long addr, unsigned long size)
 {
 	unsigned long end, a;
 	unsigned long flags;
 
+	DEBUG_INCCNT(cnt_dma_cache_wback_inv_pc);
+
 	if (size >= dcache_size) {
 		blast_dcache();
 	} else {
@@ -320,6 +410,8 @@
 {
 	unsigned long end, a;
 
+	DEBUG_INCCNT(cnt_dma_cache_wback_inv_sc);
+
 	if (size >= scache_size) {
 		blast_scache();
 		return;
@@ -340,6 +432,8 @@
 	unsigned long end, a;
 	unsigned long flags;
 
+	DEBUG_INCCNT(cnt_dma_cache_inv_pc);
+
 	if (size >= dcache_size) {
 		blast_dcache();
 	} else {
@@ -362,6 +456,8 @@
 {
 	unsigned long end, a;
 
+	DEBUG_INCCNT(cnt_dma_cache_inv_sc);
+
 	if (size >= scache_size) {
 		blast_scache();
 		return;
@@ -379,26 +475,11 @@
 static void
 mips32_dma_cache_wback(unsigned long addr, unsigned long size)
 {
-	panic("mips32_dma_cache called - should not happen.");
+	panic("mips32_dma_cache_wback called - should not happen.");
 }
 
-/*
- * While we're protected against bad userland addresses we don't care
- * very much about what happens in that case.  Usually a segmentation
- * fault will dump the process later on anyway ...
- */
-static void mips32_flush_cache_sigtramp(unsigned long addr)
-{
-	protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
-	protected_flush_icache_line(addr & ~(ic_lsize - 1));
-}
+#endif
 
-static void mips32_flush_icache_all(void)
-{
-	if (mips_cpu.icache.flags | MIPS_CACHE_VTAG_CACHE) {
-		blast_icache();
-	}
-}
 
 /* Detect and size the various caches. */
 static void __init probe_icache(unsigned long config)
@@ -586,36 +667,40 @@
 
 static void __init setup_noscache_funcs(void)
 {
-	_clear_page = (void *)mips32_clear_page_dc;
-	_copy_page = (void *)mips32_copy_page_dc;
-	_flush_cache_all = mips32_flush_cache_all_pc;
-	___flush_cache_all = mips32_flush_cache_all_pc;
-	_flush_cache_mm = mips32_flush_cache_mm_pc;
-	_flush_cache_range = mips32_flush_cache_range_pc;
-	_flush_cache_page = mips32_flush_cache_page_pc;
+	_clear_page = (void *) mips32_clear_page_dc;
+	_copy_page  = (void *) mips32_copy_page_dc;
+	_flush_cache_all     = mips32_flush_cache_all_pc;
+	___flush_cache_all   = mips32_flush_cache_all_pc;
+	_flush_cache_mm      = mips32_flush_cache_mm_pc;
+	_flush_cache_range   = mips32_flush_cache_range_pc;
+	_flush_cache_page    = mips32_flush_cache_page_pc;
 
-	_flush_icache_page = mips32_flush_icache_page;
+	_flush_icache_page   = mips32_flush_icache_page;
 
+#ifdef	CONFIG_NONCOHERENT_IO
 	_dma_cache_wback_inv = mips32_dma_cache_wback_inv_pc;
-	_dma_cache_wback = mips32_dma_cache_wback;
-	_dma_cache_inv = mips32_dma_cache_inv_pc;
+	_dma_cache_wback     = mips32_dma_cache_wback;
+	_dma_cache_inv       = mips32_dma_cache_inv_pc;
+#endif
 }
 
 static void __init setup_scache_funcs(void)
 {
-        _flush_cache_all = mips32_flush_cache_all_sc;
-        ___flush_cache_all = mips32_flush_cache_all_sc;
-	_flush_cache_mm = mips32_flush_cache_mm_sc;
-	_flush_cache_range = mips32_flush_cache_range_sc;
-	_flush_cache_page = mips32_flush_cache_page_sc;
-	_clear_page = (void *)mips32_clear_page_sc;
-	_copy_page = (void *)mips32_copy_page_sc;
+	_clear_page = (void *) mips32_clear_page_sc;
+	_copy_page  = (void *) mips32_copy_page_sc;
+        _flush_cache_all     = mips32_flush_cache_all_sc;
+        ___flush_cache_all   = mips32_flush_cache_all_sc;
+	_flush_cache_mm      = mips32_flush_cache_mm_sc;
+	_flush_cache_range   = mips32_flush_cache_range_sc;
+	_flush_cache_page    = mips32_flush_cache_page_sc;
 
-	_flush_icache_page = mips32_flush_icache_page_s;
+	_flush_icache_page   = mips32_flush_icache_page_s;
 
+#ifdef	CONFIG_NONCOHERENT_IO
 	_dma_cache_wback_inv = mips32_dma_cache_wback_inv_sc;
-	_dma_cache_wback = mips32_dma_cache_wback;
-	_dma_cache_inv = mips32_dma_cache_inv_sc;
+	_dma_cache_wback     = mips32_dma_cache_wback;
+	_dma_cache_inv       = mips32_dma_cache_inv_sc;
+#endif
 }
 
 typedef int (*probe_func_t)(unsigned long);
@@ -669,10 +754,89 @@
 	shm_align_mask = max_t(unsigned long, mips_cpu.dcache.sets * dc_lsize,
 	                       PAGE_SIZE) - 1;
 
-	_flush_cache_sigtramp = mips32_flush_cache_sigtramp;
-	_flush_icache_range = mips32_flush_icache_range;	/* Ouch */
+	_flush_icache_all      = mips32_flush_icache_all;
+	_flush_icache_range    = mips32_flush_icache_range;	/* Ouch */
 	_flush_data_cache_page = mips32_flush_data_cache_page;
-	_flush_icache_all = mips32_flush_icache_all;
+	_flush_cache_sigtramp  = mips32_flush_cache_sigtramp;
 
 	__flush_cache_all();
 }
+
+
+
+#ifdef	DEBUG_COUNTERS
+
+static int cmips32_read_proc(char *buf, char **start, off_t fpos,
+			 int length, int *eof, void *data)
+{
+	int	len;
+	char	*p = buf;
+
+	p += sprintf(p, "\nCache statistics from c-mips32.c:\n\n");
+
+	p += sprintf(p, "mips32_flush_cache_all_pc:   %8d    "
+	                "mips32_flush_cache_all_sc:   %8d\n",
+			cnt_mips32_flush_cache_all_pc,
+			cnt_mips32_flush_cache_all_sc);
+	p += sprintf(p, "mips32_flush_cache_range_pc: %8d    "
+	                "mips32_flush_cache_range_sc: %8d\n",
+			cnt_mips32_flush_cache_range_pc,
+			cnt_mips32_flush_cache_range_sc);
+	p += sprintf(p, "mips32_flush_cache_mm_pc:    %8d    "
+	                "mips32_flush_cache_mm_sc:    %8d\n",
+			cnt_mips32_flush_cache_mm_pc,
+			cnt_mips32_flush_cache_mm_sc);
+	p += sprintf(p, "mips32_flush_cache_page_pc:  %8d    "
+	                "mips32_flush_cache_page_sc:  %8d\n\n",
+			cnt_mips32_flush_cache_page_pc,
+			cnt_mips32_flush_cache_page_sc);
+
+	p += sprintf(p, "mips32_flush_icache_all:     %8d    "
+			"mips32_flush_icache_page_s:  %8d\n",
+			cnt_mips32_flush_icache_all,
+			cnt_mips32_flush_icache_page_s);
+	p += sprintf(p, "mips32_flush_icache_range:   %8d    "
+			"mips32_flush_icache_page:    %8d\n",
+			cnt_mips32_flush_icache_range,
+			cnt_mips32_flush_icache_page);
+	p += sprintf(p, "mips32_flush_data_cache_page:%8d    "
+			"mips32_flush_cache_sigtramp: %8d\n\n",
+			cnt_mips32_flush_data_cache_page,
+			cnt_mips32_flush_cache_sigtramp);
+
+	p += sprintf(p, "dma_cache_wback_inv_pc:      %8d    "
+			"dma_cache_wback_inv_sc:      %8d\n",
+			cnt_dma_cache_wback_inv_pc,
+			cnt_dma_cache_wback_inv_sc);
+	p += sprintf(p, "dma_cache_inv_pc:            %8d    "
+			"dma_cache_inv_sc:            %8d\n\n",
+			cnt_dma_cache_inv_pc,
+			cnt_dma_cache_inv_sc);
+
+	len = p - buf;
+	if (fpos >= len) {
+		/* Nothing to return... */
+		*start = buf;
+		*eof = 1;
+		return 0;
+	}
+
+	*start = buf + fpos;
+	if ((len -= fpos) > length)
+		return length;
+
+	*eof = 1;
+	return len;
+}
+
+static int __init cmips32_init_module(void)
+{
+	create_proc_read_entry ("cmips32_cache_stats", 0, NULL,
+		cmips32_read_proc, NULL);
+
+	return 0;
+}
+
+module_init(cmips32_init_module);
+
+#endif

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: Cache flush statistics patch to c-mips32.c
  2003-04-02 19:16 Cache flush statistics patch to c-mips32.c Hartvig Ekner
@ 2003-04-02 20:05 ` Ralf Baechle
  0 siblings, 0 replies; 2+ messages in thread
From: Ralf Baechle @ 2003-04-02 20:05 UTC (permalink / raw)
  To: Hartvig Ekner; +Cc: Linux MIPS mailing list

On Wed, Apr 02, 2003 at 09:16:20PM +0200, Hartvig Ekner wrote:

> Below is a patch with some cache statistics counters added to c-mips32.c.
> They are turned on by the local define DEBUG_COUNTERS in case somebody wants to
> play with them.
> 
> A sample output:
> 
> [root@au01 root]# more /proc/cmips32_cache_stats
> 
> Cache statistics from c-mips32.c:
> 
> mips32_flush_cache_all_pc:      83384    mips32_flush_cache_all_sc:          0
> mips32_flush_cache_range_pc:    37276    mips32_flush_cache_range_sc:        0
> mips32_flush_cache_mm_pc:        2121    mips32_flush_cache_mm_sc:           0
> mips32_flush_cache_page_pc:     36282    mips32_flush_cache_page_sc:         0
> 
> mips32_flush_icache_all:            0    mips32_flush_icache_page_s:         0
> mips32_flush_icache_range:          4    mips32_flush_icache_page:       93545
> mips32_flush_data_cache_page:   31905    mips32_flush_cache_sigtramp:     2467
> 
> dma_cache_wback_inv_pc:          7029    dma_cache_wback_inv_sc:             0
> dma_cache_inv_pc:                   0    dma_cache_inv_sc:                   0

As already mentioned, c-mips32.c is a pretty lousy piece of code.  It's
basically a cut'n'paste from an ancient, rotten version of r4xx0.c.  So
it also includes wrecked support for R4000SC-style second level caches,
that's all the _sc functions above which aren't called ever.  As of like
an hour ago I've removed all this dead code.

Similarly flush_icache_all, it's only used for processors that have a
virtually indexed virtually tagged I-cache.  Currently there only two of
these processors do exist, the one is Sibyte's SB1 core which is used in
the BCM1250 SOC and the other is MIPS's upcoming 20kc core.

> These counts are from a system which has just booted, nothing else. While
> running some programs, the flush_cache_all is called up to 400 times pr.
> second (!).

Flush_cache_all is invoked by the overkill implementation of sys_cacheflush.
These calls are usually done only by certain code constructs and the only
common user is glibc.  The part of glibc using cacheflush(2) is the
dynamic linker so the penalty for longer running processes is getting
lower.

Anyway, c-mips32.c is frightening for processors with alias-free caches
such as the virtually indexed 16kb 4-way caches of your Au1500.  For
example flush_cache_all() and flush_dcache_page() should be empty and
flush_cache_page() only needs to do something at all for pages that do
contain code etc.  There's a major speedup hidden there.

  Ralf

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2003-04-02 20:05 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-04-02 19:16 Cache flush statistics patch to c-mips32.c Hartvig Ekner
2003-04-02 20:05 ` Ralf Baechle

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox