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