Transcendent memory ("tmem") for Xen.

Tmem, when called from a tmem-capable (paravirtualized) guest, makes
use of otherwise unutilized ("fallow") memory to create and manage
pools of pages that can be accessed from the guest either as
"ephemeral" pages or as "persistent" pages.  In either case, the pages
are not directly addressible by the guest, only copied to and fro via
the tmem interface.  Ephemeral pages are a nice place for a guest to
put recently evicted clean pages that it might need again; these pages
can be reclaimed synchronously by Xen for other guests or other uses.
Persistent pages are a nice place for a guest to put "swap" pages to
avoid sending them to disk.  These pages retain data as long as the
guest lives, but count against the guest memory allocation.

Tmem pages may optionally be compressed and, in certain cases, can be
shared between guests.  Tmem also handles concurrency nicely and
provides limited QoS settings to combat malicious DoS attempts.
Save/restore and live migration support is not yet provided.

Tmem is primarily targeted for an x86 64-bit hypervisor.  On a 32-bit
x86 hypervisor, it has limited functionality and testing due to
limitations of the xen heap.  Nearly all of tmem is
architecture-independent; three routines remain to be ported to ia64
and it should work on that architecture too.  It is also structured to
be portable to non-Xen environments.

Tmem defaults off (for now) and must be enabled with a "tmem" xen boot
option (and does nothing unless a tmem-capable guest is running).  The
"tmem_compress" boot option enables compression which takes about 10x
more CPU but approximately doubles the number of pages that can be
stored.

Tmem can be controlled via several "xm" commands and many interesting
tmem statistics can be obtained.  A README and internal specification
will follow, but lots of useful prose about tmem, as well as Linux
patches, can be found at http://oss.oracle.com/projects/tmem .

Signed-off-by: Dan Magenheimer <dan.magenheimer@oracle.com>
This commit is contained in:
Keir Fraser committed 2009-05-26 11:05:04 +01:00
1 parent ff811c2bc4
commit 6009f4ddb2
49 files changed
+5638 -39

No files matched your search

+57
View File
@@ -19,6 +19,7 @@
#include "xenctrl.h"
#include <xen/elfnote.h>
#include <xen/tmem.h>
#include "xc_dom.h"
#include <xen/hvm/hvm_info_table.h>
#include <xen/hvm/params.h>
@@ -1506,6 +1507,50 @@ static PyObject *dom_op(XcObject *self, PyObject *args,
return zero;
}
static PyObject *pyxc_tmem_control(XcObject *self,
PyObject *args,
PyObject *kwds)
{
int32_t pool_id;
uint32_t subop;
uint32_t cli_id;
uint32_t arg1;
uint32_t arg2;
char *buf;
char _buffer[32768], *buffer = _buffer;
int rc;
static char *kwd_list[] = { "pool_id", "subop", "cli_id", "arg1", "arg2", "buf", NULL };
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiiiis", kwd_list,
&pool_id, &subop, &cli_id, &arg1, &arg2, &buf) )
return NULL;
if ( (subop == TMEMC_LIST) && (arg1 > 32768) )
arg1 = 32768;
if ( (rc = xc_tmem_control(self->xc_handle, pool_id, subop, cli_id, arg1, arg2, buffer)) < 0 )
return Py_BuildValue("i", rc);
switch (subop) {
case TMEMC_LIST:
return Py_BuildValue("s", buffer);
case TMEMC_FLUSH:
return Py_BuildValue("i", rc);
case TMEMC_THAW:
case TMEMC_FREEZE:
case TMEMC_DESTROY:
case TMEMC_SET_WEIGHT:
case TMEMC_SET_CAP:
case TMEMC_SET_COMPRESS:
default:
break;
}
Py_INCREF(zero);
return zero;
}
static PyMethodDef pyxc_methods[] = {
{ "handle",
(PyCFunction)pyxc_handle,
@@ -1965,6 +2010,18 @@ static PyMethodDef pyxc_methods[] = {
" dom [int]: Identifier of domain.\n" },
#endif
{ "tmem_control",
(PyCFunction)pyxc_tmem_control,
METH_VARARGS | METH_KEYWORDS, "\n"
"Do various control on a tmem pool.\n"
" pool_id [int]: Identifier of the tmem pool (-1 == all).\n"
" subop [int]: Supplementary Operation.\n"
" cli_id [int]: Client identifier (-1 == all).\n"
" arg1 [int]: Argument.\n"
" arg2 [int]: Argument.\n"
" buf [str]: Buffer.\n\n"
"Returns: [int] 0 or [str] tmem info on success; exception on error.\n" },
{ NULL, NULL, 0, NULL }
};
+73 -1
View File
@@ -925,7 +925,15 @@ class XendAPI(object):
('dmesg', 'String'),
('dmesg_clear', 'String'),
('get_log', 'String'),
('send_debug_keys', None)]
('send_debug_keys', None),
('tmem_thaw', None),
('tmem_freeze', None),
('tmem_flush', None),
('tmem_destroy', None),
('tmem_list', None),
('tmem_set_weight', None),
('tmem_set_cap', None),
('tmem_set_compress', None)]
host_funcs = [('get_by_name_label', None),
('list_methods', None)]
@@ -1061,6 +1069,70 @@ class XendAPI(object):
'PSCSIs': XendPSCSI.get_all()}
return xen_api_success(record)
def host_tmem_thaw(self, _, host_ref, cli_id):
node = XendNode.instance()
try:
node.tmem_thaw(cli_id)
except Exception, e:
return xen_api_error(e)
return xen_api_success_void()
def host_tmem_freeze(self, _, host_ref, cli_id):
node = XendNode.instance()
try:
node.tmem_freeze(cli_id)
except Exception, e:
return xen_api_error(e)
return xen_api_success_void()
def host_tmem_flush(self, _, host_ref, cli_id, pages):
node = XendNode.instance()
try:
node.tmem_flush(cli_id, pages)
except Exception, e:
return xen_api_error(e)
return xen_api_success_void()
def host_tmem_destroy(self, _, host_ref, cli_id):
node = XendNode.instance()
try:
node.tmem_destroy(cli_id)
except Exception, e:
return xen_api_error(e)
return xen_api_success_void()
def host_tmem_list(self, _, host_ref, cli_id, use_long):
node = XendNode.instance()
try:
info = node.tmem_list(cli_id, use_long)
except Exception, e:
return xen_api_error(e)
return xen_api_success(info)
def host_tmem_set_weight(self, _, host_ref, cli_id, value):
node = XendNode.instance()
try:
node.tmem_set_weight(cli_id, value)
except Exception, e:
return xen_api_error(e)
return xen_api_success_void()
def host_tmem_set_cap(self, _, host_ref, cli_id, value):
node = XendNode.instance()
try:
node.tmem_set_cap(cli_id, value)
except Exception, e:
return xen_api_error(e)
return xen_api_success_void()
def host_tmem_set_compress(self, _, host_ref, cli_id, value):
node = XendNode.instance()
try:
node.tmem_set_compress(cli_id, value)
except Exception, e:
return xen_api_error(e)
return xen_api_success_void()
# class methods
def host_get_all(self, session):
return xen_api_success((XendNode.instance().uuid,))
+26
View File
@@ -141,3 +141,29 @@ XS_VMROOT = "/vm/"
NR_PCI_DEV = 32
AUTO_PHP_SLOT = NR_PCI_DEV
AUTO_PHP_SLOT_STR = "%02x" % NR_PCI_DEV
#
# tmem
#
TMEM_CONTROL = 0
TMEM_NEW_POOL = 1
TMEM_DESTROY_POOL = 2
TMEM_NEW_PAGE = 3
TMEM_PUT_PAGE = 4
TMEM_GET_PAGE = 5
TMEM_FLUSH_PAGE = 6
TMEM_FLUSH_OBJECT = 7
TMEM_READ = 8
TMEM_WRITE = 9
TMEM_XCHG = 10
TMEMC_THAW = 0
TMEMC_FREEZE = 1
TMEMC_FLUSH = 2
TMEMC_DESTROY = 3
TMEMC_LIST = 4
TMEMC_SET_WEIGHT = 5
TMEMC_SET_CAP = 6
TMEMC_SET_COMPRESS = 7
+64
View File
@@ -26,6 +26,7 @@ from xen.util import pci as PciUtil
from xen.util import vscsi_util
from xen.xend import XendAPIStore
from xen.xend import osdep
from xen.xend.XendConstants import *
import uuid, arch
from XendPBD import XendPBD
@@ -940,6 +941,69 @@ class XendNode:
def info_dict(self):
return dict(self.info())
# tmem
def tmem_list(self, cli_id, use_long):
pool_id = -1
subop = TMEMC_LIST
arg1 = 32768
arg2 = use_long
buf = ''
return self.xc.tmem_control(pool_id, subop, cli_id, arg1, arg2, buf)
def tmem_thaw(self, cli_id):
pool_id = -1
subop = TMEMC_THAW
arg1 = 0
arg2 = 0
buf = ''
return self.xc.tmem_control(pool_id, subop, cli_id, arg1, arg2, buf)
def tmem_freeze(self, cli_id):
pool_id = -1
subop = TMEMC_FREEZE
arg1 = 0
arg2 = 0
buf = ''
return self.xc.tmem_control(pool_id, subop, cli_id, arg1, arg2, buf)
def tmem_flush(self, cli_id, pages):
pool_id = -1
subop = TMEMC_FLUSH
arg1 = pages
arg2 = 0
buf = ''
return self.xc.tmem_control(pool_id, subop, cli_id, arg1, arg2, buf)
def tmem_destroy(self, cli_id):
pool_id = -1
subop = TMEMC_DESTROY
arg1 = 0
arg2 = 0
buf = ''
return self.xc.tmem_control(pool_id, subop, cli_id, arg1, arg2, buf)
def tmem_set_weight(self, cli_id, arg1):
pool_id = -1
subop = TMEMC_SET_WEIGHT
arg2 = 0
buf = ''
return self.xc.tmem_control(pool_id, subop, cli_id, arg1, arg2, buf)
def tmem_set_cap(self, cli_id, arg1):
pool_id = -1
subop = TMEMC_SET_CAP
arg2 = 0
buf = ''
return self.xc.tmem_control(pool_id, subop, cli_id, arg1, arg2, buf)
def tmem_set_compress(self, cli_id, arg1):
pool_id = -1
subop = TMEMC_SET_COMPRESS
arg2 = 0
buf = ''
return self.xc.tmem_control(pool_id, subop, cli_id, arg1, arg2, buf)
def instance():
global inst
try:
+17
View File
@@ -26,6 +26,7 @@ import XendOptions
from XendLogging import log
from XendError import VmError
import osdep
from xen.xend.XendConstants import *
RETRY_LIMIT = 20
RETRY_LIMIT_INCR = 5
@@ -109,6 +110,9 @@ def free(need_mem, dominfo):
last_free = None
rlimit = RETRY_LIMIT
# stop tmem from absorbing any more memory (must THAW when done!)
xc.tmem_control(0,TMEMC_FREEZE,-1, 0, 0, "")
# If unreasonable memory size is required, we give up waiting
# for ballooning or scrubbing, as if had retried.
physinfo = xc.physinfo()
@@ -122,6 +126,17 @@ def free(need_mem, dominfo):
if need_mem >= max_free_mem:
retries = rlimit
freeable_mem = free_mem + scrub_mem
if freeable_mem < need_mem and need_mem < max_free_mem:
# flush memory from tmem to scrub_mem and reobtain physinfo
need_tmem_kb = need_mem - freeable_mem
tmem_kb = xc.tmem_control(0,TMEMC_FLUSH,-1, need_tmem_kb, 0, "")
log.debug("Balloon: tmem relinquished %d KiB of %d KiB requested.",
tmem_kb, need_tmem_kb)
physinfo = xc.physinfo()
free_mem = physinfo['free_memory']
scrub_mem = physinfo['scrub_memory']
# Check whethercurrent machine is a numa system and the new
# created hvm has all its vcpus in the same node, if all the
# conditions above are fit. We will wait until all the pages
@@ -216,4 +231,6 @@ def free(need_mem, dominfo):
' be shrunk any further'))
finally:
# allow tmem to accept pages again
xc.tmem_control(0,TMEMC_THAW,-1, 0, 0, "")
del xc
+5 -1
View File
@@ -198,7 +198,11 @@ class XMLRPCServer:
self.server.register_function(fn, "xend.domain.%s" % name[7:])
# Functions in XendNode and XendDmesg
for type, lst, n in [(XendNode, ['info', 'pciinfo', 'send_debug_keys'],
for type, lst, n in [(XendNode,
['info', 'pciinfo', 'send_debug_keys',
'tmem_list', 'tmem_freeze', 'tmem_thaw',
'tmem_flush', 'tmem_destroy', 'tmem_set_weight',
'tmem_set_cap', 'tmem_set_compress'],
'node'),
(XendDmesg, ['info', 'clear'], 'node.dmesg')]:
inst = type.instance()
+222 -2
View File
@@ -199,6 +199,15 @@ SUBCOMMAND_HELP = {
'scsi-list' : ('<Domain> [--long]',
'List all SCSI devices currently attached.'),
# tmem
'tmem-list' : ('[-l|--long] [<Domain>|-a|--all]', 'List tmem pools.'),
'tmem-thaw' : ('[<Domain>|-a|--all]', 'Thaw tmem pools.'),
'tmem-freeze' : ('[<Domain>|-a|--all]', 'Freeze tmem pools.'),
'tmem-destroy' : ('[<Domain>|-a|--all]', 'Destroy tmem pools.'),
'tmem-set' : ('[<Domain>|-a|--all] [weight=<weight>] [cap=<cap>] '
'[compress=<compress>]',
'Change tmem settings.'),
# security
'addlabel' : ('<label> {dom <ConfigFile>|res <resource>|mgt <managed domain>}\n'
@@ -283,6 +292,21 @@ SUBCOMMAND_OPTIONS = {
'info': (
('-c', '--config', 'List Xend configuration parameters'),
),
'tmem-list': (
('-l', '--long', 'List tmem stats.'),
),
'tmem-thaw': (
('-a', '--all', 'Thaw all tmem.'),
),
'tmem-freeze': (
('-a', '--all', 'Freeze all tmem.'),
),
'tmem-destroy': (
('-a', '--all', 'Destroy all tmem.'),
),
'tmem-set': (
('-a', '--all', 'Operate on all tmem.'),
),
}
common_commands = [
@@ -397,9 +421,17 @@ acm_commands = [
"getpolicy",
]
tmem_commands = [
"tmem-list",
"tmem-thaw",
"tmem-freeze",
"tmem-destroy",
"tmem-set",
]
all_commands = (domain_commands + host_commands + scheduler_commands +
device_commands + vnet_commands + acm_commands +
['shell', 'event-monitor'])
tmem_commands + ['shell', 'event-monitor'])
##
@@ -2837,7 +2869,188 @@ def xm_network_show(args):
print format2 % r
def xm_tmem_list(args):
try:
(options, params) = getopt.gnu_getopt(args, 'la', ['long','all'])
except getopt.GetoptError, opterr:
err(opterr)
usage('tmem-list')
use_long = False
for (k, v) in options:
if k in ['-l', '--long']:
use_long = True
all = False
for (k, v) in options:
if k in ['-a', '--all']:
all = True
if not all and len(params) == 0:
err('You must specify -a or --all or a domain id.')
usage('tmem-list')
if all:
domid = -1
else:
try:
domid = int(params[0])
params = params[1:]
except:
err('Unrecognized domain id: %s' % params[0])
usage('tmem-list')
if serverType == SERVER_XEN_API:
print server.xenapi.host.tmem_list(domid,use_long)
else:
print server.xend.node.tmem_list(domid,use_long)
def parse_tmem_args(args, name):
try:
(options, params) = getopt.gnu_getopt(args, 'a', ['all'])
except getopt.GetoptError, opterr:
err(opterr)
usage(name)
all = False
for (k, v) in options:
if k in ['-a', '--all']:
all = True
if not all and len(params) == 0:
err('You must specify -a or --all or a domain id.')
usage(name)
if all:
domid = -1
else:
try:
domid = int(params[0])
params = params[1:]
except:
err('Unrecognized domain id: %s' % params[0])
usage(name)
return domid, params
def xm_tmem_destroy(args):
(domid, _) = parse_tmem_args(args, 'tmem-destroy')
if serverType == SERVER_XEN_API:
server.xenapi.host.tmem_destroy(domid)
else:
server.xend.node.tmem_destroy(domid)
def xm_tmem_thaw(args):
(domid, _) = parse_tmem_args(args, 'tmem-thaw')
if serverType == SERVER_XEN_API:
server.xenapi.host.tmem_thaw(domid)
else:
server.xend.node.tmem_thaw(domid)
def xm_tmem_freeze(args):
(domid, _) = parse_tmem_args(args, 'tmem-freeze')
if serverType == SERVER_XEN_API:
server.xenapi.host.tmem_freeze(domid)
else:
server.xend.node.tmem_freeze(domid)
def xm_tmem_flush(args):
try:
(options, params) = getopt.gnu_getopt(args, 'a', ['all'])
except getopt.GetoptError, opterr:
err(opterr)
usage(name)
all = False
for (k, v) in options:
if k in ['-a', '--all']:
all = True
if not all and len(params) == 0:
err('You must specify -a or --all or a domain id.')
usage('tmem-flush')
if all:
domid = -1
else:
try:
domid = int(params[0])
params = params[1:]
except:
err('Unrecognized domain id: %s' % params[0])
usage('tmem-flush')
pages = -1
for (k, v) in options:
if k in ['-p', '--pages']:
pages = v
if serverType == SERVER_XEN_API:
server.xenapi.host.tmem_flush(domid,pages)
else:
server.xend.node.tmem_flush(domid,pages)
def xm_tmem_set(args):
try:
(options, params) = getopt.gnu_getopt(args, 'a', ['all'])
except getopt.GetoptError, opterr:
err(opterr)
usage(name)
all = False
for (k, v) in options:
if k in ['-a', '--all']:
all = True
if not all and len(params) == 0:
err('You must specify -a or --all or a domain id.')
usage('tmem-set')
if all:
domid = -1
else:
try:
domid = int(params[0])
params = params[1:]
except:
err('Unrecognized domain id: %s' % params[0])
usage('tmem-set')
weight = None
cap = None
compress = None
for item in params:
if item.startswith('weight='):
try:
weight = int(item[7:])
except:
err('weight should be a integer')
usage('tmem-set')
if item.startswith('cap='):
cap = int(item[4:])
if item.startswith('compress='):
compress = int(item[9:])
if weight is None and cap is None and compress is None:
err('Unrecognized tmem configuration option: %s' % item)
usage('tmem-set')
if serverType == SERVER_XEN_API:
if weight is not None:
server.xenapi.host.tmem_set_weight(domid, weight)
if cap is not None:
server.xenapi.host.tmem_set_cap(domid, cap)
if compress is not None:
server.xenapi.host.tmem_set_compress(domid, compress)
else:
if weight is not None:
server.xend.node.tmem_set_weight(domid, weight)
if cap is not None:
server.xend.node.tmem_set_cap(domid, cap)
if compress is not None:
server.xend.node.tmem_set_compress(domid, compress)
commands = {
"shell": xm_shell,
"event-monitor": xm_event_monitor,
@@ -2912,6 +3125,13 @@ commands = {
"scsi-attach": xm_scsi_attach,
"scsi-detach": xm_scsi_detach,
"scsi-list": xm_scsi_list,
# tmem
"tmem-thaw": xm_tmem_thaw,
"tmem-freeze": xm_tmem_freeze,
"tmem-flush": xm_tmem_flush,
"tmem-destroy": xm_tmem_destroy,
"tmem-list": xm_tmem_list,
"tmem-set": xm_tmem_set,
}
## The commands supported by a separate argument parser in xend.xm.
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.