Subject: 1.0 performance patch
To: None <port-sparc@NetBSD.ORG>
From: Paul Kranenburg <pk@cs.few.eur.nl>
List: port-sparc
Date: 03/04/1995 11:23:29
For those of you running NetBSD/sparc 1.0 I've put together a source patch to
avoid cache aliasing, This will improve performance a bit.

This is not an "official" patch; use at your own risk.

NOTE: install /usr/libexec/ld.so first, *before* booting a new kernel.

===================================================================
RCS file: /tmp/CVS/src/gnu/usr.bin/ld/rtld/rtld.c,v
retrieving revision 1.21.2.2
diff -c -r1.21.2.2 rtld.c
*** 1.21.2.2	1994/08/12 08:46:02
--- rtld.c	1995/02/10 10:59:42
***************
*** 479,485 ****
  		return NULL;
  	}
  
! 	if ((addr = mmap(0, hdr.a_text + hdr.a_data,
  	     PROT_READ|PROT_EXEC,
  	     MAP_COPY, fd, 0)) == (caddr_t)-1) {
  		(void)close(fd);
--- 479,485 ----
  		return NULL;
  	}
  
! 	if ((addr = mmap(0, hdr.a_text + hdr.a_data + hdr.a_bss,
  	     PROT_READ|PROT_EXEC,
  	     MAP_COPY, fd, 0)) == (caddr_t)-1) {
  		(void)close(fd);
===================================================================
RCS file: /tmp/CVS/src/sys/arch/sparc/include/pmap.h,v
retrieving revision 1.5.2.1
diff -c -r1.5.2.1 pmap.h
*** 1.5.2.1	1994/08/17 06:19:34
--- pmap.h	1995/02/09 20:11:33
***************
*** 152,157 ****
--- 152,158 ----
  
  #define PMAP_ACTIVATE(pmap, pcb, iscurproc)
  #define PMAP_DEACTIVATE(pmap, pcb)
+ #define PMAP_PREFER(pa, va)		pmap_prefer((pa), (va))
  
  /*
   * Since PTEs also contain type bits, we have to have some way
===================================================================
RCS file: /tmp/CVS/src/sys/arch/sparc/sparc/pmap.c,v
retrieving revision 1.13.2.2
diff -c -r1.13.2.2 pmap.c
*** 1.13.2.2	1994/10/24 04:22:06
--- pmap.c	1995/02/10 11:03:05
***************
*** 2830,2835 ****
--- 2830,2872 ----
  }
  
  /*
+  * Find first virtual address >= va that doesn't cause
+  * a cache alias on physical address pa.
+  */
+ vm_offset_t
+ pmap_prefer(pa, va)
+ 	register vm_offset_t pa;
+ 	register vm_offset_t va;
+ {
+ 	register struct pvlist	*pv;
+ 	register long		m, d;
+ 
+ #if 0
+ 	if (cputyp == CPU_SUN4M)
+ 		/* does the sun4m have the cache alias problem? */
+ 		return va;
+ 
+ 	m = CACHE_ALIAS_DIST;
+ #endif
+ 	m = 0x10000;
+ 
+ 	if (!managed(pa))
+ 		return va;
+ 
+ 	pv = pvhead(pa);
+ 	if (pv->pv_pmap == NULL)
+ 		/* Unusable, tell caller to try another one */
+ 		return (vm_offset_t)-1;
+ 
+ 	d = (long)(pv->pv_va & (m - 1)) - (long)(va & (m - 1));
+ 	if (d < 0)
+ 		va += m;
+ 	va += d;
+ 
+ 	return va;
+ }
+ 
+ /*
   * For /dev/mem.
   */
  int
===================================================================
RCS file: /tmp/CVS/src/sys/vm/vm_mmap.c,v
retrieving revision 1.31.2.1
diff -c -r1.31.2.1 vm_mmap.c
*** 1.31.2.1	1994/09/16 19:33:27
--- vm_mmap.c	1995/02/09 20:10:38
***************
*** 724,731 ****
  			vm_offset_t off;
  
  			/* locate and allocate the target address space */
! 			rv = vm_map_find(map, NULL, (vm_offset_t)0,
! 					 addr, size, fitit);
  			if (rv != KERN_SUCCESS) {
  				vm_object_deallocate(object);
  				goto out;
--- 724,772 ----
  			vm_offset_t off;
  
  			/* locate and allocate the target address space */
! 			if (fitit) {
! 				/*
! 				 * We cannot call vm_map_find() because
! 				 * a proposed address may be vetoed by
! 				 * the pmap module.
! 				 * So we look for space ourselves, validate
! 				 * it and insert it into the map. 
! 				 */
! 				vm_map_lock(map);
! 			again:
! 				if (vm_map_findspace(map, *addr, size,
! 						     addr) == 1) {
! 					rv = KERN_NO_SPACE;
! 				} else {
! 					vm_object_prefer(object, foff, addr);
! 					rv = vm_map_insert(map, NULL,
! 							(vm_offset_t)0,
! 							*addr, *addr+size);
! 					if (rv == KERN_NO_SPACE)
! 						/*
! 						 * Modified address didn't fit
! 						 * after all, the gap must
! 						 * have been to small.
! 						 */
! 						goto again;
! 				}
! 				vm_map_unlock(map);
! 			} else {
! 				rv = vm_map_find(map, NULL, (vm_offset_t)0,
! 					 addr, size, 0);
! 
! 				/*
! 				 * Check against PMAP preferred address. If
! 				 * there's a mismatch, these pages should not
! 				 * be shared with others. <howto?>
! 				 */
! 				if (rv == KERN_SUCCESS) {
! 					vm_offset_t	paddr = *addr;
! 					vm_object_prefer(object, foff, &paddr);
! 					if (paddr != *addr)
! 						printf("vm_mmap: pmap botch!\n");
! 				}
! 			}
  			if (rv != KERN_SUCCESS) {
  				vm_object_deallocate(object);
  				goto out;
===================================================================
RCS file: /tmp/CVS/src/sys/vm/vm_object.c,v
retrieving revision 1.24.2.1
diff -c -r1.24.2.1 vm_object.c
*** 1.24.2.1	1994/10/06 05:05:13
--- vm_object.c	1995/02/09 20:08:48
***************
*** 1403,1408 ****
--- 1403,1448 ----
  }
  
  /*
+  *	vm_object_prefer:
+  *
+  *	Return optimal virtual address for new mapping of this object.
+  *
+  *	The object must *not* be locked.
+  */
+ void
+ vm_object_prefer(object, offset, addr)
+ 	register vm_object_t	object;
+ 	register vm_offset_t	offset;
+ 	register vm_offset_t	*addr;
+ {
+ 	register vm_page_t	p;
+ 	register vm_offset_t	paddr;
+ 
+ 	if (object == NULL)
+ 		return;
+ 
+ #ifdef PMAP_PREFER
+ 	vm_object_lock(object);
+ 	/*
+ 	 * Look for the first page that the pmap layer has something
+ 	 * to say about. Since an object maps a contiguous range of
+ 	 * virutal addresses, this will determine the preferred origin
+ 	 * of the proposed mapping.
+ 	 */
+ 	for (p = object->memq.tqh_first; p != NULL; p = p->listq.tqe_next) {
+ 		if (p->flags & (PG_FAKE | PG_FICTITIOUS))
+ 			continue;
+ 		paddr = PMAP_PREFER(VM_PAGE_TO_PHYS(p), *addr+p->offset-offset);
+ 		if (paddr == (vm_offset_t)-1)
+ 			continue;
+ 		*addr = paddr - (p->offset - offset);
+ 		break;
+ 	}
+ 	vm_object_unlock(object);
+ #endif
+ }
+ 
+ /*
   *	vm_object_print:	[ debug ]
   */
  void