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.
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
_______________________________________________
freebsd-virtualization@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-virtualization
To unsubscribe, send any mail to 
"freebsd-virtualization-unsubscr...@freebsd.org"

Reply via email to