[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 6/6] xen, tools: Add new hypercalls/tools to examine heap
Introduce two dom0_ops and a userspace tool used to probe Xen's heap availability and examine which nodes a domain's memory resides within. availheap takes a zone and a node value and returns the current number of free pages in that area of the heap. Using -1 as wildcards, one can probe total free pages in a zone, or node. getnodestat examines the page ownership of a domain. By walking the domain's page list we can determine from which nodes a domain's memory hails. (bebop) tmp # xen_numastat -H -d -1 HEAPINFO: TOTAL_FREE_PAGES: 578057 HEAPINFO: NR_ZONES: 3 HEAPINFO: NR_NODES: 2 HEAPINFO: ZONE_XEN: NODE0: FREE_PAGES: 3507 HEAPINFO: ZONE_XEN: NODE1: FREE_PAGES: 0 HEAPINFO: ZONE_DOM: NODE0: FREE_PAGES: 0 HEAPINFO: ZONE_DOM: NODE1: FREE_PAGES: 107094 HEAPINFO: ZONE_DMA: NODE0: FREE_PAGES: 467456 HEAPINFO: ZONE_DMA: NODE1: FREE_PAGES: 0 DOM0: NODE0: PAGES: 43773 DOM0: NODE1: PAGES: 21768 DOM8: NODE0: PAGES: 5 DOM8: NODE1: PAGES: 262144 -- Ryan Harper Software Engineer; Linux Technology Center IBM Corp., Austin, Tx (512) 838-9253 T/L: 678-9253 ryanh@xxxxxxxxxx diffstat output: b/tools/xen_numastat/Makefile | 35 +++++ b/tools/xen_numastat/xen_numastat.1 | 22 +++ b/tools/xen_numastat/xen_numastat.c | 215 ++++++++++++++++++++++++++++++++++++ tools/Makefile | 1 tools/libxc/xc_domain.c | 45 +++++++ tools/libxc/xenctrl.h | 15 ++ xen/common/dom0_ops.c | 72 ++++++++++++ xen/common/page_alloc.c | 5 xen/include/public/dom0_ops.h | 22 +++ xen/include/xen/mm.h | 5 10 files changed, 432 insertions(+), 5 deletions(-) Signed-off-by: Ryan Harper <ryanh@xxxxxxxxxx> --- diff -r 4d529088b115 tools/Makefile --- a/tools/Makefile Mon Jul 31 10:52:38 2006 -0500 +++ b/tools/Makefile Mon Jul 31 10:53:35 2006 -0500 @@ -13,6 +13,7 @@ SUBDIRS-y += console SUBDIRS-y += console SUBDIRS-y += xenmon SUBDIRS-y += guest-headers +SUBDIRS-y += xen_numastat SUBDIRS-$(VTPM_TOOLS) += vtpm_manager SUBDIRS-$(VTPM_TOOLS) += vtpm SUBDIRS-y += xenstat diff -r 4d529088b115 tools/libxc/xc_domain.c --- a/tools/libxc/xc_domain.c Mon Jul 31 10:52:38 2006 -0500 +++ b/tools/libxc/xc_domain.c Mon Jul 31 10:53:35 2006 -0500 @@ -524,6 +524,51 @@ int xc_domain_iomem_permission(int xc_ha op.u.iomem_permission.allow_access = allow_access; return do_dom0_op(xc_handle, &op); +} + +int xc_availheap(int xc_handle, + int zone, + int node, + uint32_t *nr_zones, + uint32_t *nr_nodes, + uint64_t *pages) +{ + DECLARE_DOM0_OP; + int rc = 0; + + op.cmd = DOM0_AVAILHEAP; + op.u.availheap.zone = zone; + op.u.availheap.node = node; + + rc = do_dom0_op(xc_handle, &op); + if ( rc >= 0 ) { + if (nr_zones) + *nr_zones = op.u.availheap.nr_zones; + if (nr_nodes) + *nr_nodes = op.u.availheap.nr_nodes; + *pages = op.u.availheap.pages; + } + + return rc; +} + +int xc_domain_getnodestat(int xc_handle, + uint32_t domid, + uint32_t node, + uint64_t *pages) +{ + DECLARE_DOM0_OP; + int rc = 0; + + op.cmd = DOM0_GETDOMNODESTAT; + op.u.getdomnodestat.domain = (domid_t) domid; + op.u.getdomnodestat.node = node; + + rc = do_dom0_op(xc_handle, &op); + if ( rc >= 0 ) + *pages = op.u.getdomnodestat.pages; + + return rc; } /* diff -r 4d529088b115 tools/libxc/xenctrl.h --- a/tools/libxc/xenctrl.h Mon Jul 31 10:52:38 2006 -0500 +++ b/tools/libxc/xenctrl.h Mon Jul 31 10:53:35 2006 -0500 @@ -541,6 +541,21 @@ int xc_get_pfn_type_batch(int xc_handle, /* Get current total pages allocated to a domain. */ long xc_get_tot_pages(int xc_handle, uint32_t domid); +/** + * This function retrieves the the number of pages in the + * specified domain that are on the specified node. + * + * @parm xc_handle a handle to an open hypervisor interface + * @parm domid the domain to query, -1 for per-node free list + * @parm node the node to query + * @parm *pages caller variable to put output + * @return 0 on success, <0 on failure. + */ +int xc_domain_getnodestat(int xc_handle, uint32_t domid, uint32_t node, + uint64_t *pages); + +int xc_availheap(int xc_handle, int zone, int node, + uint32_t *nr_zones, uint32_t *nr_nodes, uint64_t *pages); /* * Trace Buffer Operations diff -r 4d529088b115 xen/common/dom0_ops.c --- a/xen/common/dom0_ops.c Mon Jul 31 10:52:38 2006 -0500 +++ b/xen/common/dom0_ops.c Mon Jul 31 10:53:35 2006 -0500 @@ -22,6 +22,7 @@ #include <public/dom0_ops.h> #include <public/sched_ctl.h> #include <acm/acm_hooks.h> +#include <asm/numa.h> extern long arch_do_dom0_op( struct dom0_op *op, XEN_GUEST_HANDLE(dom0_op_t) u_dom0_op); @@ -712,6 +713,77 @@ long do_dom0_op(XEN_GUEST_HANDLE(dom0_op } break; + case DOM0_AVAILHEAP: + { + ret = -EINVAL; + if ( op->u.availheap.node >= num_online_nodes() ) + break; + if ( op->u.availheap.zone >= NR_ZONES ) + break; + + /* indicate the number of zones/nodes queried. + * NB: -1 is wild card for all zones/nodes */ + ( op->u.availheap.zone < 0 ) ? + (op->u.availheap.nr_zones=NR_ZONES) : + (op->u.availheap.nr_zones=1); + + ( op->u.availheap.node < 0 ) ? + (op->u.availheap.nr_nodes=num_online_nodes()) : + (op->u.availheap.nr_nodes=1); + + op->u.availheap.pages = + avail_heap_pages(op->u.availheap.zone, op->u.availheap.node); + + if ( copy_to_guest(u_dom0_op, op, 1) ) + ret = -EFAULT; + else + ret = 0; + } + break; + + case DOM0_GETDOMNODESTAT: + { + struct domain *d; + struct page_info *pg; + + ret = -EINVAL; + if ( op->u.getdomnodestat.node >= num_online_nodes() ) + break; + + ret = -ESRCH; + d = find_domain_by_id(op->u.getdomnodestat.domain); + + if ( d != NULL ) + { + /* clear out pages count */ + op->u.getdomnodestat.pages = 0; + + /* walk domain's page list and count pages on node */ + spin_lock(&d->page_alloc_lock); + list_for_each_entry(pg, &d->page_list, list) + { + if ( phys_to_nid(page_to_maddr(pg)) == + (int) op->u.getdomnodestat.node ) + op->u.getdomnodestat.pages++; + } + list_for_each_entry(pg, &d->xenpage_list, list) + { + if ( phys_to_nid(page_to_maddr(pg)) == + (int) op->u.getdomnodestat.node ) + op->u.getdomnodestat.pages++; + } + spin_unlock(&d->page_alloc_lock); + + put_domain(d); + + if ( copy_to_guest(u_dom0_op, op, 1) ) + ret = -EFAULT; + else + ret = 0; + } + } + break; + default: ret = arch_do_dom0_op(op, u_dom0_op); break; diff -r 4d529088b115 xen/common/page_alloc.c --- a/xen/common/page_alloc.c Mon Jul 31 10:52:38 2006 -0500 +++ b/xen/common/page_alloc.c Mon Jul 31 10:53:35 2006 -0500 @@ -241,11 +241,6 @@ unsigned long alloc_boot_pages(unsigned * BINARY BUDDY ALLOCATOR */ -#define MEMZONE_XEN 0 -#define MEMZONE_DOM 1 -#define MEMZONE_DMADOM 2 -#define NR_ZONES 3 - #define pfn_dom_zone_type(_pfn) \ (((_pfn) <= MAX_DMADOM_PFN) ? MEMZONE_DMADOM : MEMZONE_DOM) diff -r 4d529088b115 xen/include/public/dom0_ops.h --- a/xen/include/public/dom0_ops.h Mon Jul 31 10:52:38 2006 -0500 +++ b/xen/include/public/dom0_ops.h Mon Jul 31 10:53:35 2006 -0500 @@ -543,6 +543,26 @@ struct dom0_settimeoffset { }; typedef struct dom0_settimeoffset dom0_settimeoffset_t; DEFINE_XEN_GUEST_HANDLE(dom0_settimeoffset_t); + +#define DOM0_GETDOMNODESTAT 51 +typedef struct dom0_getdomnodestat { + int domain; /* domain to query, -1 to query per-node free list */ + int32_t node; /* node to query */ + uint64_t pages; /* number of pages on node */ +} dom0_getdomnodestat_t; +DEFINE_XEN_GUEST_HANDLE(dom0_getdomnodestat_t); + +#define DOM0_AVAILHEAP 52 +typedef struct dom0_availheap { + /* in */ + int zone; /* query available pages in zone, -1 for all */ + int node; /* query available pages in node, -1 for all */ + /* out */ + uint32_t nr_zones; /* number of zones queried */ + uint32_t nr_nodes; /* number of nodes queried */ + uint64_t pages; +} dom0_availheap_t; +DEFINE_XEN_GUEST_HANDLE(dom0_availheap_t); struct dom0_op { uint32_t cmd; @@ -587,6 +607,8 @@ struct dom0_op { struct dom0_hypercall_init hypercall_init; struct dom0_domain_setup domain_setup; struct dom0_settimeoffset settimeoffset; + struct dom0_getdomnodestat getdomnodestat; + struct dom0_availheap availheap; uint8_t pad[128]; } u; }; diff -r 4d529088b115 xen/include/xen/mm.h --- a/xen/include/xen/mm.h Mon Jul 31 10:52:38 2006 -0500 +++ b/xen/include/xen/mm.h Mon Jul 31 10:53:35 2006 -0500 @@ -32,6 +32,11 @@ #include <xen/types.h> #include <xen/list.h> #include <xen/spinlock.h> + +#define MEMZONE_XEN 0 +#define MEMZONE_DOM 1 +#define MEMZONE_DMADOM 2 +#define NR_ZONES 3 struct domain; struct page_info; diff -r 4d529088b115 tools/xen_numastat/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/xen_numastat/Makefile Mon Jul 31 10:53:35 2006 -0500 @@ -0,0 +1,35 @@ +INSTALL = install +INSTALL_PROG = $(INSTALL) -m0755 +INSTALL_DIR = $(INSTALL) -d -m0755 +INSTALL_DATA = $(INSTALL) -m0644 + +XEN_ROOT=../.. +include $(XEN_ROOT)/tools/Rules.mk + +CFLAGS += -Wall -Werror -g + +CFLAGS += -I $(XEN_XC) +CFLAGS += -I $(XEN_LIBXC) + +HDRS = $(wildcard *.h) +OBJS = $(patsubst %.c,%.o,$(wildcard *.c)) + +BIN = xen_numastat +MAN1 = $(wildcard *.1) +LIBBIN = + +all: build +build: $(BIN) + +install: build + [ -d $(DESTDIR)/usr/bin ] || $(INSTALL_DIR) $(DESTDIR)/usr/bin + $(INSTALL_PROG) $(BIN) $(DESTDIR)/usr/bin + [ -d $(DESTDIR)/usr/share/man/man1 ] || \ + $(INSTALL_DIR) $(DESTDIR)/usr/share/man/man1 + $(INSTALL_DATA) $(MAN1) $(DESTDIR)/usr/share/man/man1 + +clean: + $(RM) *.a *.so *.o $(BIN) + +%: %.c $(HDRS) Makefile + $(CC) $(CFLAGS) -o $@ $< -L$(XEN_LIBXC) -lxenctrl diff -r 4d529088b115 tools/xen_numastat/xen_numastat.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/xen_numastat/xen_numastat.1 Mon Jul 31 10:53:35 2006 -0500 @@ -0,0 +1,22 @@ +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.35. +.TH XEN_NUMASTAT "1" "May 2006" "Usage: xen_numastat [OPTION]" "User Commands" +.SH NAME +xen_numastat - Displays NUMA statistics about machine and domains +.SH SYNOPSIS +.B xen_numastat +[\fIOPTIONS\fR] +.SH DESCRIPTION +Displays NUMA statistics about machine and domains +.TP +\fB\-h\fR, \fB\-\-help\fR +display this help and exit +.TP +\fB\-H\fR, \fB\-\-heapinfo\fR +display info about Xen HEAP +.TP +\fB\-d\fR, \fB\-\-domid\fR <D> +display NUMA info about domain D +.TP +\fB\-p\fR, \fB\-\-physinfo\fR +display NUMA info about this machine +.PP diff -r 4d529088b115 tools/xen_numastat/xen_numastat.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/xen_numastat/xen_numastat.c Mon Jul 31 10:53:35 2006 -0500 @@ -0,0 +1,215 @@ +/*\ + * Copyright (C) International Business Machines Corp., 2006 + * Author(s): Ryan Harper <ryanh@xxxxxxxxxx> + * + * Xen Domain NUMA statistics tool + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License. + * + * This program 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 General Public License for more details. * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +\*/ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <err.h> +#include <errno.h> +#include <xenctrl.h> +#include <getopt.h> +#include <inttypes.h> + +#define DOMAIN 0 +#define PHYSICAL 1 +/* this is a bit arbitrary, might be nice to query from xen */ +#define MAX_DOMAINS 256 + +/* taken from xen/include/xen/mm.h */ +#define MEMZONE_XEN 0 +#define MEMZONE_DOM 1 +#define MEMZONE_DMADOM 2 + +static void usage(const char *program) { + printf("Usage: %s [OPTION]\n" + "Displays NUMA statistics about machine and domains \n" + "\n" + " -h, --help display this help and exit\n" + " -H, --heapinfo display info about Xen HEAP\n" + " -d, --domid <D> display NUMA info about domain D\n" + " -p, --physinfo display NUMA info about this machine\n" + , program); +} + +int str_to_domid(const char* domidstr) { + char *end = NULL; + int domid; + + domid = strtol(domidstr, &end, 10); + if (end && *end) { + fprintf(stderr, "Invalid DOMID `%s'\n", domidstr); + fprintf(stderr, "*end -> %c\n", *end); + exit(EINVAL); + } + + return domid; +} + +void display_dominfo(int xc_handle, int domid, int nr_nodes) +{ + xc_domaininfo_t *dominfo =NULL; + uint64_t pages; + unsigned int i, j, num_domains = 1; + + /* malloc a large buffer for info */ + if ( !(dominfo = malloc(MAX_DOMAINS * sizeof(xc_domaininfo_t))) ) + err(errno, "failed to malloc memory"); + + /* get actual number of domains */ + num_domains = xc_domain_getinfolist(xc_handle, 0, MAX_DOMAINS, dominfo); + + for (i=0; i<num_domains; i++) { + /* show all domains, or only requested domain */ + if (domid == -1 || domid == dominfo[i].domain) { + /* print domain per-node info */ + for (j=0; j < nr_nodes; j++) { + if (xc_domain_getnodestat(xc_handle, + dominfo[i].domain, j, &pages) < 0) + err(errno, "xc_domain_getnodestat()"); + printf("DOM%d: NODE%d: PAGES: %"PRIu64"\n", + dominfo[i].domain, j, pages); + } + } + } + + free(dominfo); +} + +void display_heapinfo(int xc_handle) +{ + int i,j; + uint32_t nr_zones, nr_nodes; + uint64_t pages; + char zone[8]; + + /* get zones/nodes and total free pages */ + if( xc_availheap(xc_handle, -1, -1, &nr_zones, &nr_nodes, &pages) ) + err(errno, "xc_availheap()"); + + printf("HEAPINFO: TOTAL_FREE_PAGES: %"PRIu64"\n", pages); + printf("HEAPINFO: NR_ZONES: %d\n", nr_zones); + printf("HEAPINFO: NR_NODES: %d\n", nr_nodes); + + for (i=0; i<nr_zones; i++) { + switch(i) { + case MEMZONE_XEN: + sprintf(zone, "XEN"); + break; + case MEMZONE_DOM: + sprintf(zone, "DOM"); + break; + case MEMZONE_DMADOM: + sprintf(zone, "DMA"); + break; + } + for (j=0; j<nr_nodes; j++) { + if( xc_availheap(xc_handle, i, j, NULL, NULL, &pages) ) + err(errno, "xc_availheap()"); + printf("HEAPINFO: ZONE_%s: NODE%d: FREE_PAGES: %"PRIu64"\n", + zone, j, pages); + } + } +} + +void display_physinfo(int xc_handle, xc_physinfo_t *info) +{ + + printf("PHYSINFO: NR_NODES: %d\n", info->nr_nodes); + +} + +int main(int argc, char * argv[]) +{ + + char *sopt = "d:Hhp"; + int ch; + int opt_ind=0, heapinfo=0, dominfo=0, physinfo=0, domid=-1; + int xc_handle, rc; + xc_physinfo_t info; + xc_memory_chunk_t *chunks; + xc_node_to_cpu_t *map; + struct option lopt[] = { + { "domid", 1, 0, 'd' }, + { "heapinfo", 0, 0, 'H' }, + { "help", 0, 0, 'h' }, + { "physinfo", 0, 0, 'p' }, + { 0, 0, 0, 0 } + }; + + while((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) { + switch(ch) { + case 'd': + /* convert domid */ + domid = str_to_domid(optarg); + dominfo = 1; + break; + case 'H': + heapinfo = 1; + break; + case 'h': + usage(argv[0]); + exit(0); + break; + case 'p': + physinfo = 1; + break; + } + } + + /* display help if no options are passed */ + if (dominfo == 0 && physinfo == 0 && heapinfo == 0) { + usage(argv[0]); + exit(0); + } + + /* set up */ + xc_handle = xc_interface_open(); + if (xc_handle == -1) + err(errno, "xc_interface_open()"); + + /* make space for mem chunks */ + chunks = (xc_memory_chunk_t *) + malloc( sizeof(xc_memory_chunk_t) * PUBLIC_MAXCHUNKS ); + set_xen_guest_handle(info.memory_chunks, chunks); + + /* make space for node_to_cpu mapping */ + map = (xc_node_to_cpu_t *) + malloc( sizeof(xc_node_to_cpu_t) * PUBLIC_MAX_NUMNODES ); + set_xen_guest_handle(info.node_to_cpu, map); + + /* get the machine physinfo */ + rc = xc_physinfo(xc_handle, &info); + if (rc < 0) + err(errno, "xc_physinfo()"); + + if (physinfo > 0) + display_physinfo(xc_handle, &info); + if (heapinfo > 0) + display_heapinfo(xc_handle); + if (dominfo > 0) + display_dominfo(xc_handle, domid, info.nr_nodes); + + /* free malloc'd memory */ + free(chunks); + free(map); + + xc_interface_close(xc_handle); + + return 0; +} _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |