aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIan Campbell <ian.campbell@citrix.com>2011-02-01 19:26:36 +0000
committerIan Campbell <ian.campbell@citrix.com>2011-02-01 19:26:36 +0000
commit04d1f61a1fd9e86f4aafc6333b223b736a488b58 (patch)
tree7d595ae7fa88ca36c3967f733c19e02d7fa39395
parent3ddd6a650bd220252584fdd111fa284ed062363b (diff)
downloadxen-04d1f61a1fd9e86f4aafc6333b223b736a488b58.tar.gz
xen-04d1f61a1fd9e86f4aafc6333b223b736a488b58.tar.bz2
xen-04d1f61a1fd9e86f4aafc6333b223b736a488b58.zip
libxc: maintain a small, per-handle, cache of hypercall buffer memory
Constantly m(un)locking memory can have significant overhead on systems with large numbers of CPUs. This was previously fixed by 20841:fbe8f32fa257 but this was dropped during the transition to hypercall buffers. Introduce a small cache of single page hypercall buffer allocations which can be resused to avoid this overhead. Add some statistics tracking to the hypercall buffer allocations. The cache size of 4 was chosen based on these statistics since they indicated that 2 pages was sufficient to satisfy all concurrent single page hypercall buffer allocations seen during "xl create", "xl shutdown" and "xl destroy" of both a PV and HVM guest therefore 4 pages should cover the majority of important cases. This fixes http://bugzilla.xensource.com/bugzilla/show_bug.cgi?id=1719. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Reported-by: Zheng, Shaohui <shaohui.zheng@intel.com> Tested-by: Haitao Shan <maillists.shan@gmail.com> Committed-by: Ian Jackson <ian.jackson@eu.citrix.com>
-rw-r--r--tools/libxc/xc_hcall_buf.c142
-rw-r--r--tools/libxc/xc_private.c12
-rw-r--r--tools/libxc/xc_private.h27
3 files changed, 162 insertions, 19 deletions
diff --git a/tools/libxc/xc_hcall_buf.c b/tools/libxc/xc_hcall_buf.c
index 032997f125..d817d90ca1 100644
--- a/tools/libxc/xc_hcall_buf.c
+++ b/tools/libxc/xc_hcall_buf.c
@@ -18,6 +18,7 @@
#include <stdlib.h>
#include <malloc.h>
+#include <pthread.h>
#include "xc_private.h"
#include "xg_private.h"
@@ -28,31 +29,137 @@ xc_hypercall_buffer_t XC__HYPERCALL_BUFFER_NAME(HYPERCALL_BUFFER_NULL) = {
HYPERCALL_BUFFER_INIT_NO_BOUNCE
};
+pthread_mutex_t hypercall_buffer_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void hypercall_buffer_cache_lock(xc_interface *xch)
+{
+ if ( xch->flags & XC_OPENFLAG_NON_REENTRANT )
+ return;
+ pthread_mutex_lock(&hypercall_buffer_cache_mutex);
+}
+
+static void hypercall_buffer_cache_unlock(xc_interface *xch)
+{
+ if ( xch->flags & XC_OPENFLAG_NON_REENTRANT )
+ return;
+ pthread_mutex_unlock(&hypercall_buffer_cache_mutex);
+}
+
+static void *hypercall_buffer_cache_alloc(xc_interface *xch, int nr_pages)
+{
+ void *p = NULL;
+
+ hypercall_buffer_cache_lock(xch);
+
+ xch->hypercall_buffer_total_allocations++;
+ xch->hypercall_buffer_current_allocations++;
+ if ( xch->hypercall_buffer_current_allocations > xch->hypercall_buffer_maximum_allocations )
+ xch->hypercall_buffer_maximum_allocations = xch->hypercall_buffer_current_allocations;
+
+ if ( nr_pages > 1 )
+ {
+ xch->hypercall_buffer_cache_toobig++;
+ }
+ else if ( xch->hypercall_buffer_cache_nr > 0 )
+ {
+ p = xch->hypercall_buffer_cache[--xch->hypercall_buffer_cache_nr];
+ xch->hypercall_buffer_cache_hits++;
+ }
+ else
+ {
+ xch->hypercall_buffer_cache_misses++;
+ }
+
+ hypercall_buffer_cache_unlock(xch);
+
+ return p;
+}
+
+static int hypercall_buffer_cache_free(xc_interface *xch, void *p, int nr_pages)
+{
+ int rc = 0;
+
+ hypercall_buffer_cache_lock(xch);
+
+ xch->hypercall_buffer_total_releases++;
+ xch->hypercall_buffer_current_allocations--;
+
+ if ( nr_pages == 1 && xch->hypercall_buffer_cache_nr < HYPERCALL_BUFFER_CACHE_SIZE )
+ {
+ xch->hypercall_buffer_cache[xch->hypercall_buffer_cache_nr++] = p;
+ rc = 1;
+ }
+
+ hypercall_buffer_cache_unlock(xch);
+
+ return rc;
+}
+
+static void do_hypercall_buffer_free_pages(void *ptr, int nr_pages)
+{
+#ifndef __sun__
+ (void) munlock(ptr, nr_pages * PAGE_SIZE);
+#endif
+
+ free(ptr);
+}
+
+void xc__hypercall_buffer_cache_release(xc_interface *xch)
+{
+ void *p;
+
+ hypercall_buffer_cache_lock(xch);
+
+ DBGPRINTF("hypercall buffer: total allocations:%d total releases:%d",
+ xch->hypercall_buffer_total_allocations,
+ xch->hypercall_buffer_total_releases);
+ DBGPRINTF("hypercall buffer: current allocations:%d maximum allocations:%d",
+ xch->hypercall_buffer_current_allocations,
+ xch->hypercall_buffer_maximum_allocations);
+ DBGPRINTF("hypercall buffer: cache current size:%d",
+ xch->hypercall_buffer_cache_nr);
+ DBGPRINTF("hypercall buffer: cache hits:%d misses:%d toobig:%d",
+ xch->hypercall_buffer_cache_hits,
+ xch->hypercall_buffer_cache_misses,
+ xch->hypercall_buffer_cache_toobig);
+
+ while ( xch->hypercall_buffer_cache_nr > 0 )
+ {
+ p = xch->hypercall_buffer_cache[--xch->hypercall_buffer_cache_nr];
+ do_hypercall_buffer_free_pages(p, 1);
+ }
+
+ hypercall_buffer_cache_unlock(xch);
+}
+
void *xc__hypercall_buffer_alloc_pages(xc_interface *xch, xc_hypercall_buffer_t *b, int nr_pages)
{
size_t size = nr_pages * PAGE_SIZE;
- void *p;
+ void *p = hypercall_buffer_cache_alloc(xch, nr_pages);
+
+ if ( !p ) {
#if defined(_POSIX_C_SOURCE) && !defined(__sun__)
- int ret;
- ret = posix_memalign(&p, PAGE_SIZE, size);
- if (ret != 0)
- return NULL;
+ int ret;
+ ret = posix_memalign(&p, PAGE_SIZE, size);
+ if (ret != 0)
+ return NULL;
#elif defined(__NetBSD__) || defined(__OpenBSD__)
- p = valloc(size);
+ p = valloc(size);
#else
- p = memalign(PAGE_SIZE, size);
+ p = memalign(PAGE_SIZE, size);
#endif
- if (!p)
- return NULL;
+ if (!p)
+ return NULL;
#ifndef __sun__
- if ( mlock(p, size) < 0 )
- {
- free(p);
- return NULL;
- }
+ if ( mlock(p, size) < 0 )
+ {
+ free(p);
+ return NULL;
+ }
#endif
+ }
b->hbuf = p;
@@ -65,11 +172,8 @@ void xc__hypercall_buffer_free_pages(xc_interface *xch, xc_hypercall_buffer_t *b
if ( b->hbuf == NULL )
return;
-#ifndef __sun__
- (void) munlock(b->hbuf, nr_pages * PAGE_SIZE);
-#endif
-
- free(b->hbuf);
+ if ( !hypercall_buffer_cache_free(xch, b->hbuf, nr_pages) )
+ do_hypercall_buffer_free_pages(b->hbuf, nr_pages);
}
struct allocation_header {
diff --git a/tools/libxc/xc_private.c b/tools/libxc/xc_private.c
index 72ee07fd34..09c8f23ca5 100644
--- a/tools/libxc/xc_private.c
+++ b/tools/libxc/xc_private.c
@@ -126,6 +126,16 @@ static struct xc_interface_core *xc_interface_open_common(xentoollog_logger *log
xch->error_handler = logger; xch->error_handler_tofree = 0;
xch->dombuild_logger = dombuild_logger; xch->dombuild_logger_tofree = 0;
+ xch->hypercall_buffer_cache_nr = 0;
+
+ xch->hypercall_buffer_total_allocations = 0;
+ xch->hypercall_buffer_total_releases = 0;
+ xch->hypercall_buffer_current_allocations = 0;
+ xch->hypercall_buffer_maximum_allocations = 0;
+ xch->hypercall_buffer_cache_hits = 0;
+ xch->hypercall_buffer_cache_misses = 0;
+ xch->hypercall_buffer_cache_toobig = 0;
+
xch->ops_handle = XC_OSDEP_OPEN_ERROR;
xch->ops = NULL;
@@ -172,6 +182,8 @@ static int xc_interface_close_common(xc_interface *xch)
{
int rc = 0;
+ xc__hypercall_buffer_cache_release(xch);
+
xtl_logger_destroy(xch->dombuild_logger_tofree);
xtl_logger_destroy(xch->error_handler_tofree);
diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h
index b01ca2419d..3687561df0 100644
--- a/tools/libxc/xc_private.h
+++ b/tools/libxc/xc_private.h
@@ -75,6 +75,28 @@ struct xc_interface_core {
FILE *dombuild_logger_file;
const char *currently_progress_reporting;
+ /*
+ * A simple cache of unused, single page, hypercall buffers
+ *
+ * Protected by a global lock.
+ */
+#define HYPERCALL_BUFFER_CACHE_SIZE 4
+ int hypercall_buffer_cache_nr;
+ void *hypercall_buffer_cache[HYPERCALL_BUFFER_CACHE_SIZE];
+
+ /*
+ * Hypercall buffer statistics. All protected by the global
+ * hypercall_buffer_cache lock.
+ */
+ int hypercall_buffer_total_allocations;
+ int hypercall_buffer_total_releases;
+ int hypercall_buffer_current_allocations;
+ int hypercall_buffer_maximum_allocations;
+ int hypercall_buffer_cache_hits;
+ int hypercall_buffer_cache_misses;
+ int hypercall_buffer_cache_toobig;
+
+ /* Low lovel OS interface */
xc_osdep_info_t osdep;
xc_osdep_ops *ops; /* backend operations */
xc_osdep_handle ops_handle; /* opaque data for xc_osdep_ops */
@@ -158,6 +180,11 @@ void xc__hypercall_bounce_post(xc_interface *xch, xc_hypercall_buffer_t *bounce)
#define xc_hypercall_bounce_post(_xch, _name) xc__hypercall_bounce_post(_xch, HYPERCALL_BUFFER(_name))
/*
+ * Release hypercall buffer cache
+ */
+void xc__hypercall_buffer_cache_release(xc_interface *xch);
+
+/*
* Hypercall interfaces.
*/