mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
During migration there are a lot of mmap/munmap calls, because xc_get_pfn_type_batch() exceeds the default hypercall bounce buffer cache size, and needs to allocate every time it is called. munmap() is slow, especially in a PV Dom0 (takes an emulation fault), so is best avoided. Eventually it'd be good if the memory pool from xmalloc_tlsf.c was reused here, but for now make it handle the commonly encountered sizes (so far up to 4 pages). Signed-off-by: Edwin Török <edwin.torok@citrix.com> Signed-off-by: Frediano Ziglio <frediano.ziglio@citrix.com> Reviewed-by: Anthony PERARD <anthony.perard@vates.tech>
206 lines
5.0 KiB
C
206 lines
5.0 KiB
C
/*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation;
|
|
* version 2.1 of the License.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <pthread.h>
|
|
#include <xen-tools/common-macros.h>
|
|
|
|
#include "private.h"
|
|
|
|
#define DBGPRINTF(_m...) \
|
|
xtl_log(xcall->logger, XTL_DEBUG, -1, "xencall:buffer", _m)
|
|
|
|
pthread_mutex_t cache_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
static void cache_lock(xencall_handle *xcall)
|
|
{
|
|
int saved_errno = errno;
|
|
if ( xcall->flags & XENCALL_OPENFLAG_NON_REENTRANT )
|
|
return;
|
|
pthread_mutex_lock(&cache_mutex);
|
|
/* Ignore pthread errors. */
|
|
errno = saved_errno;
|
|
}
|
|
|
|
static void cache_unlock(xencall_handle *xcall)
|
|
{
|
|
int saved_errno = errno;
|
|
if ( xcall->flags & XENCALL_OPENFLAG_NON_REENTRANT )
|
|
return;
|
|
pthread_mutex_unlock(&cache_mutex);
|
|
/* Ignore pthread errors. */
|
|
errno = saved_errno;
|
|
}
|
|
|
|
static void *cache_alloc(xencall_handle *xcall, size_t nr_pages)
|
|
{
|
|
void *p = NULL;
|
|
|
|
if ( nr_pages == 0 )
|
|
return NULL;
|
|
|
|
cache_lock(xcall);
|
|
|
|
xcall->buffer_total_allocations++;
|
|
xcall->buffer_current_allocations++;
|
|
if ( xcall->buffer_current_allocations > xcall->buffer_maximum_allocations )
|
|
xcall->buffer_maximum_allocations = xcall->buffer_current_allocations;
|
|
|
|
if ( nr_pages > ARRAY_SIZE(xcall->buffer_cache) )
|
|
{
|
|
xcall->buffer_cache_toobig++;
|
|
}
|
|
else if ( xcall->buffer_cache_nr[nr_pages-1] > 0 )
|
|
{
|
|
p = xcall->buffer_cache[nr_pages-1][--xcall->buffer_cache_nr[nr_pages-1]];
|
|
xcall->buffer_cache_hits++;
|
|
}
|
|
else
|
|
{
|
|
xcall->buffer_cache_misses++;
|
|
}
|
|
|
|
cache_unlock(xcall);
|
|
|
|
return p;
|
|
}
|
|
|
|
static int cache_free(xencall_handle *xcall, void *p, size_t nr_pages)
|
|
{
|
|
int rc = 0;
|
|
|
|
if ( nr_pages == 0 )
|
|
return 0;
|
|
|
|
cache_lock(xcall);
|
|
|
|
xcall->buffer_total_releases++;
|
|
xcall->buffer_current_allocations--;
|
|
|
|
if ( nr_pages && nr_pages <= ARRAY_SIZE(xcall->buffer_cache) &&
|
|
xcall->buffer_cache_nr[nr_pages-1] < BUFFER_CACHE_SIZE )
|
|
{
|
|
xcall->buffer_cache[nr_pages-1][xcall->buffer_cache_nr[nr_pages-1]++] = p;
|
|
rc = 1;
|
|
}
|
|
|
|
cache_unlock(xcall);
|
|
|
|
return rc;
|
|
}
|
|
|
|
void buffer_release_cache(xencall_handle *xcall)
|
|
{
|
|
void *p;
|
|
|
|
cache_lock(xcall);
|
|
|
|
DBGPRINTF("total allocations:%d total releases:%d",
|
|
xcall->buffer_total_allocations,
|
|
xcall->buffer_total_releases);
|
|
DBGPRINTF("current allocations:%d maximum allocations:%d",
|
|
xcall->buffer_current_allocations,
|
|
xcall->buffer_maximum_allocations);
|
|
for ( unsigned int i = 0; i < ARRAY_SIZE(xcall->buffer_cache_nr); ++i )
|
|
{
|
|
DBGPRINTF("cache current size[%u pages]:%d", i+1,
|
|
xcall->buffer_cache_nr[i]);
|
|
}
|
|
DBGPRINTF("cache hits:%d misses:%d toobig:%d",
|
|
xcall->buffer_cache_hits,
|
|
xcall->buffer_cache_misses,
|
|
xcall->buffer_cache_toobig);
|
|
|
|
for ( unsigned int i = 0; i < ARRAY_SIZE(xcall->buffer_cache_nr); ++i )
|
|
{
|
|
while ( xcall->buffer_cache_nr[i] > 0 )
|
|
{
|
|
p = xcall->buffer_cache[i][--xcall->buffer_cache_nr[i]];
|
|
osdep_free_pages(xcall, p, i + 1);
|
|
}
|
|
}
|
|
|
|
cache_unlock(xcall);
|
|
}
|
|
|
|
void *xencall_alloc_buffer_pages(xencall_handle *xcall, size_t nr_pages)
|
|
{
|
|
void *p = cache_alloc(xcall, nr_pages);
|
|
|
|
if ( !p )
|
|
p = osdep_alloc_pages(xcall, nr_pages);
|
|
|
|
if (!p)
|
|
return NULL;
|
|
|
|
memset(p, 0, nr_pages * PAGE_SIZE);
|
|
|
|
return p;
|
|
}
|
|
|
|
void xencall_free_buffer_pages(xencall_handle *xcall, void *p, size_t nr_pages)
|
|
{
|
|
if ( p == NULL )
|
|
return;
|
|
|
|
if ( !cache_free(xcall, p, nr_pages) )
|
|
osdep_free_pages(xcall, p, nr_pages);
|
|
}
|
|
|
|
struct allocation_header {
|
|
int nr_pages;
|
|
int pad[3];
|
|
};
|
|
|
|
void *xencall_alloc_buffer(xencall_handle *xcall, size_t size)
|
|
{
|
|
size_t actual_size = ROUNDUP(size + sizeof(struct allocation_header),
|
|
PAGE_SIZE);
|
|
int nr_pages = actual_size >> PAGE_SHIFT;
|
|
struct allocation_header *hdr;
|
|
|
|
hdr = xencall_alloc_buffer_pages(xcall, nr_pages);
|
|
if ( hdr == NULL )
|
|
return NULL;
|
|
|
|
hdr->nr_pages = nr_pages;
|
|
|
|
return (void *)(hdr+1);
|
|
}
|
|
|
|
void xencall_free_buffer(xencall_handle *xcall, void *p)
|
|
{
|
|
struct allocation_header *hdr;
|
|
|
|
if (p == NULL)
|
|
return;
|
|
|
|
hdr = p;
|
|
--hdr;
|
|
|
|
xencall_free_buffer_pages(xcall, hdr, hdr->nr_pages);
|
|
}
|
|
|
|
/*
|
|
* Local variables:
|
|
* mode: C
|
|
* c-file-style: "BSD"
|
|
* c-basic-offset: 4
|
|
* tab-width: 4
|
|
* indent-tabs-mode: nil
|
|
* End:
|
|
*/
|