reducing the memory redirections needed for vnet use.

Julian Elischer julian at elischer.org
Mon Sep 21 07:55:00 UTC 2009


I've been running the folllowing set of diffs as a proof of
concept change for a couple of months now. The diff is to cache
the vnet address fixup constant in the pcpu area.

This means that the address of V_xxx is now (%fs:pcpu_offset)+symbol  (*)
  the cost in the machine dependent part of the scheduler is minimal 
and I have never been able to measure the difference in context times 
(though I didn't try that hard). The important partof this however is
not so oonbvious. If we wanted to have per-vnet-per-cpu memory for
per cpu stats collection in vnets, then this approach becomes the
blueprint as to how that must be done.  Obviously memory to hold all 
the data needs to be allocated, but once that is donem the pcpu
specific section of the memory need sto be selected by teh scheduerl 
as teh thread moves between cpus. This patch shows where that would 
occur, and also, where it would be stored.


In the patch the preprocessor variable VNET_PCPU_DATA
should be ignored as it is just my personal way of turning the feature 
on and off for testing.

(*) I'm not convinced that the equivalent cannot be done in a single
instruction addressing mode on some cpus.. certainly I think it may
have been possible on the 68000 family from memory.
-------------- next part --------------
Index: kern/kern_synch.c
===================================================================
--- kern/kern_synch.c	(revision 197380)
+++ kern/kern_synch.c	(working copy)
@@ -65,6 +65,10 @@
 
 #include <machine/cpu.h>
 
+#if defined(VIMAGE) && defined(VNET_PCPU_DATA)
+#include <net/vnet.h>
+#endif
+
 #ifdef XEN
 #include <vm/vm.h>
 #include <vm/vm_param.h>
@@ -447,6 +451,14 @@
 	PT_UPDATES_FLUSH();
 #endif
 	sched_switch(td, newtd, flags);
+#if defined(VIMAGE) && defined(VNET_PCPU_DATA)
+	if (td->td_vnet) {
+		PCPU_SET(vnet_data_adj, td->td_vnet->vnet_data_base);
+	} else {
+		/* Added to a vnet symbol, gives something near 0 */
+		PCPU_SET(vnet_data_adj, -VNET_START);
+	}
+#endif
 	KTR_STATE1(KTR_SCHED, "thread", sched_tdname(td), "running",
 	    "prio:%d", td->td_priority);
 
Index: kern/kern_fork.c
===================================================================
--- kern/kern_fork.c	(revision 197380)
+++ kern/kern_fork.c	(working copy)
@@ -540,7 +540,7 @@
 	td2->td_sigmask = td->td_sigmask;
 	td2->td_flags = TDF_INMEM;
 
-#ifdef VIMAGE
+#ifdef VIMAGE /* if we ever make curvnet always valid, change this. */
 	td2->td_vnet = NULL;
 	td2->td_vnet_lpush = NULL;
 #endif
@@ -817,6 +817,10 @@
 
 	td = curthread;
 	p = td->td_proc;
+#if defined(VIMAGE) && defined(VNET_PCPU_DATA)
+	/* if we ever make curvnet always valid, change this. */
+	PCPU_SET(vnet_data_adj, (uintptr_t)NULL);
+#endif
 	KASSERT(p->p_state == PRS_NORMAL, ("executing process is still new"));
 
 	CTR4(KTR_PROC, "fork_exit: new thread %p (td_sched %p, pid %d, %s)",
Index: net/vnet.c
===================================================================
--- net/vnet.c	(revision 197380)
+++ net/vnet.c	(working copy)
@@ -145,15 +145,7 @@
  * module will find every network stack instance with proper default values.
  */
 
-/*
- * Location of the kernel's 'set_vnet' linker set.
- */
-extern uintptr_t	*__start_set_vnet;
-extern uintptr_t	*__stop_set_vnet;
 
-#define	VNET_START	(uintptr_t)&__start_set_vnet
-#define	VNET_STOP	(uintptr_t)&__stop_set_vnet
-
 /*
  * Number of bytes of data in the 'set_vnet' linker set, and hence the total
  * size of all kernel virtualized global variables, and the malloc(9) type
Index: net/vnet.h
===================================================================
--- net/vnet.h	(revision 197380)
+++ net/vnet.h	(working copy)
@@ -92,6 +92,14 @@
 #include <sys/sx.h>
 
 /*
+ * Location of the kernel's 'set_vnet' linker set.
+ */
+extern uintptr_t	*__start_set_vnet;
+extern uintptr_t	*__stop_set_vnet;
+ 
+#define VNET_START	(uintptr_t)&__start_set_vnet
+#define VNET_STOP	(uintptr_t)&__stop_set_vnet
+/*
  * Functions to allocate and destroy virtual network stacks.
  */
 struct vnet *vnet_alloc(void);
@@ -107,6 +115,28 @@
  * Various macros -- get and set the current network stack, but also
  * assertions.
  */
+#ifdef VNET_PCPU_DATA
+
+#define VNET_PCPU_SET(a, b)  PCPU_SET(a, b)
+
+#define CURVNET_DO_RESTORE() do {					\
+	if ((curvnet = saved_vnet) == NULL) {				\
+		PCPU_SET(vnet_data_adj, (uintptr_t)NULL);		\
+	} else {							\
+		PCPU_SET(vnet_data_adj, saved_vnet->vnet_data_base);	\
+	}								\
+} while (0)
+
+#else
+
+#define VNET_PCPU_SET(a, b)						
+
+#define CURVNET_DO_RESTORE() do {					\
+	curvnet = saved_vnet;						\
+} while (0)
+
+#endif
+
 #ifdef VNET_DEBUG
 #define	VNET_ASSERT(condition)						\
 	if (!(condition)) {						\
@@ -120,34 +150,44 @@
 	struct vnet *saved_vnet = curvnet;				\
 	const char *saved_vnet_lpush = curthread->td_vnet_lpush;	\
 	curvnet = arg;							\
+	VNET_PCPU_SET(vnet_data_adj, curvnet->vnet_data_base);		\
 	curthread->td_vnet_lpush = __FUNCTION__;
  
-#define	CURVNET_SET_VERBOSE(arg)					\
+#define	CURVNET_SET_VERBOSE(arg) 					\
 	CURVNET_SET_QUIET(arg)						\
 	if (saved_vnet)							\
-		printf("CURVNET_SET(%p) in %s() on cpu %d, prev %p in %s()\n", \
+		printf("CURVNET_SET(%p) in %s() on cpu %d,"		\
+		    " prev %p in %s()\n",				\
 		       curvnet,	curthread->td_vnet_lpush, curcpu,	\
 		       saved_vnet, saved_vnet_lpush);
 
 #define	CURVNET_SET(arg)	CURVNET_SET_VERBOSE(arg)
  
-#define	CURVNET_RESTORE()						\
+#define	CURVNET_RESTORE() do {						\
 	VNET_ASSERT(saved_vnet == NULL ||				\
 		    saved_vnet->vnet_magic_n == VNET_MAGIC_N);		\
-	curvnet = saved_vnet;						\
-	curthread->td_vnet_lpush = saved_vnet_lpush;
+	CURVNET_DO_RESTORE();						\
+	curthread->td_vnet_lpush = saved_vnet_lpush;			\
+} while (0)
+
 #else /* !VNET_DEBUG */
+
 #define	VNET_ASSERT(condition)
 
 #define	CURVNET_SET(arg)						\
-	struct vnet *saved_vnet = curvnet;				\
-	curvnet = arg;	
+struct vnet *saved_vnet = curvnet;					\
+ do {									\
+	curvnet = arg;							\
+	VNET_PCPU_SET(vnet_data_adj, curvnet->vnet_data_base);		\
+} while (0)
  
 #define	CURVNET_SET_VERBOSE(arg)	CURVNET_SET(arg)
 #define	CURVNET_SET_QUIET(arg)		CURVNET_SET(arg)
  
-#define	CURVNET_RESTORE()						\
-	curvnet = saved_vnet;
+#define	CURVNET_RESTORE() do {						\
+	CURVNET_DO_RESTORE();						\
+} while (0)
+
 #endif /* VNET_DEBUG */
 
 extern struct vnet *vnet0;
@@ -205,8 +245,13 @@
 #define	VNET_VNET_PTR(vnet, n)		_VNET_PTR((vnet)->vnet_data_base, n)
 #define	VNET_VNET(vnet, n)		(*VNET_VNET_PTR((vnet), n))
 
+#ifdef VNET_PCPU_DATA
+#define VNET(n)   _VNET(PCPU_GET(vnet_data_adj), n)
+#define VNET_PTR(n) _VNET_PTR(PCPU_GET(vnet_data_adj), n)
+#else
 #define	VNET_PTR(n)		VNET_VNET_PTR(curvnet, n)
 #define	VNET(n)			VNET_VNET(curvnet, n)
+#endif
 
 /*
  * Virtual network stack allocator interfaces from the kernel linker.
@@ -324,6 +369,7 @@
 #define	CURVNET_SET(arg)
 #define	CURVNET_SET_QUIET(arg)
 #define	CURVNET_RESTORE()
+#define VNET_PCPU_SET(a, b)						
 
 #define	VNET_LIST_RLOCK()
 #define	VNET_LIST_RLOCK_NOSLEEP()
Index: ddb/db_sym.c
===================================================================
--- ddb/db_sym.c	(revision 197380)
+++ ddb/db_sym.c	(working copy)
@@ -64,12 +64,6 @@
 static int db_cpu = -1;
 
 #ifdef VIMAGE
-extern uintptr_t	*__start_set_vnet;
-extern uintptr_t	*__stop_set_vnet;
-
-#define	VNET_START	(uintptr_t)&__start_set_vnet
-#define	VNET_STOP	(uintptr_t)&__stop_set_vnet
-
 static void *db_vnet = NULL;
 #endif
 
Index: sys/pcpu.h
===================================================================
--- sys/pcpu.h	(revision 197380)
+++ sys/pcpu.h	(working copy)
@@ -161,6 +161,11 @@
 	 */
 	uintptr_t	pc_dynamic;
 
+#define VNET_PCPU_DATA 1 /* also in vnet.h */
+#if defined(VIMAGE) && defined(VNET_PCPU_DATA)  /* maybe always here? */
+	uintptr_t		pc_vnet_data_adj;  /* offset to per vnet data area */
+#endif
+
 	/*
 	 * Keep MD fields last, so that CPU-specific variations on a
 	 * single architecture don't result in offset variations of


More information about the freebsd-virtualization mailing list