[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v4 4/9] sysctl: Make XEN_SYSCTL_numainfo a little more efficient
Make sysctl NUMA topology query use fewer copies by combining some fields into a single structure and copying distances for each node in a single copy. Instead of using max_node_index for passing number of nodes keep this value in num_nodes: almost all uses of max_node_index required adding or subtracting one to eventually get to number of nodes anyway. Replace INVALID_NUMAINFO_ID with XEN_INVALID_MEM_SZ and add XEN_INVALID_NODE_DIST. Signed-off-by: Boris Ostrovsky <boris.ostrovsky@xxxxxxxxxx> --- Changes in v4: * Split this patch from CPU topology changes * Replace max_node_index with num_nodes (for the same reason as in previous patch) * No buffer allocation in sysctl, copy data node-by-node * Replaced INVALID_NUMAINFO_ID with XEN_INVALID_MEM_SZ, added XEN_INVALID_NODE_DIST tools/libxl/libxl.c | 50 ++++++++++++------------- tools/python/xen/lowlevel/xc/xc.c | 56 ++++++++++++++--------------- xen/common/sysctl.c | 72 +++++++++++++++++++++---------------- xen/include/public/sysctl.h | 32 +++++++++++------ 4 files changed, 113 insertions(+), 97 deletions(-) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index 6660133..8a6f979 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -5093,9 +5093,8 @@ libxl_numainfo *libxl_get_numainfo(libxl_ctx *ctx, int *nr) { GC_INIT(ctx); xc_numainfo_t ninfo; - DECLARE_HYPERCALL_BUFFER(xc_node_to_memsize_t, memsize); - DECLARE_HYPERCALL_BUFFER(xc_node_to_memfree_t, memfree); - DECLARE_HYPERCALL_BUFFER(uint32_t, node_dists); + DECLARE_HYPERCALL_BUFFER(xen_sysctl_meminfo_t, meminfo); + DECLARE_HYPERCALL_BUFFER(uint8_t, distance); libxl_numainfo *ret = NULL; int i, j, max_nodes; @@ -5107,51 +5106,50 @@ libxl_numainfo *libxl_get_numainfo(libxl_ctx *ctx, int *nr) goto out; } - memsize = xc_hypercall_buffer_alloc - (ctx->xch, memsize, sizeof(*memsize) * max_nodes); - memfree = xc_hypercall_buffer_alloc - (ctx->xch, memfree, sizeof(*memfree) * max_nodes); - node_dists = xc_hypercall_buffer_alloc - (ctx->xch, node_dists, sizeof(*node_dists) * max_nodes * max_nodes); - if ((memsize == NULL) || (memfree == NULL) || (node_dists == NULL)) { + meminfo = xc_hypercall_buffer_alloc(ctx->xch, meminfo, + sizeof(*meminfo) * max_nodes); + distance = xc_hypercall_buffer_alloc(ctx->xch, distance, + sizeof(*distance) * + max_nodes * max_nodes); + if ((meminfo == NULL) || (distance == NULL)) { LIBXL__LOG_ERRNOVAL(ctx, XTL_ERROR, ENOMEM, "Unable to allocate hypercall arguments"); goto fail; } - set_xen_guest_handle(ninfo.node_to_memsize, memsize); - set_xen_guest_handle(ninfo.node_to_memfree, memfree); - set_xen_guest_handle(ninfo.node_to_node_distance, node_dists); - ninfo.max_node_index = max_nodes - 1; + set_xen_guest_handle(ninfo.meminfo, meminfo); + set_xen_guest_handle(ninfo.distance, distance); + ninfo.num_nodes = max_nodes; if (xc_numainfo(ctx->xch, &ninfo) != 0) { LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "getting numainfo"); goto fail; } - if (ninfo.max_node_index < max_nodes - 1) - max_nodes = ninfo.max_node_index + 1; + if (ninfo.num_nodes < max_nodes) + max_nodes = ninfo.num_nodes; *nr = max_nodes; ret = libxl__zalloc(NOGC, sizeof(libxl_numainfo) * max_nodes); for (i = 0; i < max_nodes; i++) - ret[i].dists = libxl__calloc(NOGC, max_nodes, sizeof(*node_dists)); + ret[i].dists = libxl__calloc(NOGC, max_nodes, sizeof(*distance)); for (i = 0; i < max_nodes; i++) { -#define V(mem, i) (mem[i] == INVALID_NUMAINFO_ID) ? \ - LIBXL_NUMAINFO_INVALID_ENTRY : mem[i] - ret[i].size = V(memsize, i); - ret[i].free = V(memfree, i); +#define V(val, invalid) (val == invalid) ? \ + LIBXL_NUMAINFO_INVALID_ENTRY : val + ret[i].size = V(meminfo[i].memsize, XEN_INVALID_MEM_SZ); + ret[i].free = V(meminfo[i].memfree, XEN_INVALID_MEM_SZ); ret[i].num_dists = max_nodes; - for (j = 0; j < ret[i].num_dists; j++) - ret[i].dists[j] = V(node_dists, i * max_nodes + j); + for (j = 0; j < ret[i].num_dists; j++) { + unsigned idx = i * max_nodes + j; + ret[i].dists[j] = V(distance[idx], XEN_INVALID_NODE_DIST); + } #undef V } fail: - xc_hypercall_buffer_free(ctx->xch, memsize); - xc_hypercall_buffer_free(ctx->xch, memfree); - xc_hypercall_buffer_free(ctx->xch, node_dists); + xc_hypercall_buffer_free(ctx->xch, meminfo); + xc_hypercall_buffer_free(ctx->xch, distance); out: GC_FREE; diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c index 2fd93e0..edbaf60 100644 --- a/tools/python/xen/lowlevel/xc/xc.c +++ b/tools/python/xen/lowlevel/xc/xc.c @@ -1302,55 +1302,53 @@ out: static PyObject *pyxc_numainfo(XcObject *self) { -#define MAX_NODE_INDEX 31 +#define MAX_NODES 32 xc_numainfo_t ninfo = { 0 }; - int i, j, max_node_index; + unsigned i, j, num_nodes; uint64_t free_heap; PyObject *ret_obj = NULL, *node_to_node_dist_list_obj; PyObject *node_to_memsize_obj, *node_to_memfree_obj; PyObject *node_to_dma32_mem_obj, *node_to_node_dist_obj; - DECLARE_HYPERCALL_BUFFER(xc_node_to_memsize_t, node_memsize); - DECLARE_HYPERCALL_BUFFER(xc_node_to_memfree_t, node_memfree); - DECLARE_HYPERCALL_BUFFER(xc_node_to_node_dist_t, nodes_dist); + DECLARE_HYPERCALL_BUFFER(xen_sysctl_meminfo_t, meminfo); + DECLARE_HYPERCALL_BUFFER(uint8_t, distance); - node_memsize = xc_hypercall_buffer_alloc(self->xc_handle, node_memsize, sizeof(*node_memsize)*(MAX_NODE_INDEX+1)); - if ( node_memsize == NULL ) + meminfo = xc_hypercall_buffer_alloc(self->xc_handle, meminfo, + sizeof(*meminfo) * MAX_NODES); + if ( meminfo == NULL ) goto out; - node_memfree = xc_hypercall_buffer_alloc(self->xc_handle, node_memfree, sizeof(*node_memfree)*(MAX_NODE_INDEX+1)); - if ( node_memfree == NULL ) - goto out; - nodes_dist = xc_hypercall_buffer_alloc(self->xc_handle, nodes_dist, sizeof(*nodes_dist)*(MAX_NODE_INDEX+1)*(MAX_NODE_INDEX+1)); - if ( nodes_dist == NULL ) + distance = xc_hypercall_buffer_alloc(self->xc_handle, distance, + sizeof(*distance) * MAX_NODES * MAX_NODES); + if ( distance == NULL ) goto out; - set_xen_guest_handle(ninfo.node_to_memsize, node_memsize); - set_xen_guest_handle(ninfo.node_to_memfree, node_memfree); - set_xen_guest_handle(ninfo.node_to_node_distance, nodes_dist); - ninfo.max_node_index = MAX_NODE_INDEX; + set_xen_guest_handle(ninfo.meminfo, meminfo); + set_xen_guest_handle(ninfo.distance, distance); + ninfo.num_nodes = MAX_NODES; if ( xc_numainfo(self->xc_handle, &ninfo) != 0 ) goto out; - max_node_index = ninfo.max_node_index; - if ( max_node_index > MAX_NODE_INDEX ) - max_node_index = MAX_NODE_INDEX; + num_nodes = ninfo.num_nodes; + if ( num_nodes > MAX_NODES ) + num_nodes = MAX_NODES; /* Construct node-to-* lists. */ node_to_memsize_obj = PyList_New(0); node_to_memfree_obj = PyList_New(0); node_to_dma32_mem_obj = PyList_New(0); node_to_node_dist_list_obj = PyList_New(0); - for ( i = 0; i <= max_node_index; i++ ) + for ( i = 0; i < num_nodes; i++ ) { PyObject *pyint; + unsigned invalid_node; /* Total Memory */ - pyint = PyInt_FromLong(node_memsize[i] >> 20); /* MB */ + pyint = PyInt_FromLong(meminfo[i].memsize >> 20); /* MB */ PyList_Append(node_to_memsize_obj, pyint); Py_DECREF(pyint); /* Free Memory */ - pyint = PyInt_FromLong(node_memfree[i] >> 20); /* MB */ + pyint = PyInt_FromLong(meminfo[i].memfree >> 20); /* MB */ PyList_Append(node_to_memfree_obj, pyint); Py_DECREF(pyint); @@ -1362,10 +1360,11 @@ static PyObject *pyxc_numainfo(XcObject *self) /* Node to Node Distance */ node_to_node_dist_obj = PyList_New(0); - for ( j = 0; j <= max_node_index; j++ ) + invalid_node = (meminfo[i].memsize == XEN_INVALID_MEM_SZ); + for ( j = 0; j < num_nodes; j++ ) { - uint32_t dist = nodes_dist[i*(max_node_index+1) + j]; - if ( dist == ~0u ) + uint8_t dist = distance[i * num_nodes + j]; + if ( invalid_node || (dist == XEN_INVALID_NODE_DIST) ) { PyList_Append(node_to_node_dist_obj, Py_None); } @@ -1380,7 +1379,7 @@ static PyObject *pyxc_numainfo(XcObject *self) Py_DECREF(node_to_node_dist_obj); } - ret_obj = Py_BuildValue("{s:i}", "max_node_index", max_node_index); + ret_obj = Py_BuildValue("{s:i}", "max_node_index", num_nodes + 1); PyDict_SetItemString(ret_obj, "node_memsize", node_to_memsize_obj); Py_DECREF(node_to_memsize_obj); @@ -1396,9 +1395,8 @@ static PyObject *pyxc_numainfo(XcObject *self) Py_DECREF(node_to_node_dist_list_obj); out: - xc_hypercall_buffer_free(self->xc_handle, node_memsize); - xc_hypercall_buffer_free(self->xc_handle, node_memfree); - xc_hypercall_buffer_free(self->xc_handle, nodes_dist); + xc_hypercall_buffer_free(self->xc_handle, meminfo); + xc_hypercall_buffer_free(self->xc_handle, distance); return ret_obj ? ret_obj : pyxc_error_to_exception(self->xc_handle); #undef MAX_NODE_INDEX } diff --git a/xen/common/sysctl.c b/xen/common/sysctl.c index fe48ee8..2d11a76 100644 --- a/xen/common/sysctl.c +++ b/xen/common/sysctl.c @@ -274,49 +274,59 @@ long do_sysctl(XEN_GUEST_HANDLE_PARAM(xen_sysctl_t) u_sysctl) case XEN_SYSCTL_numainfo: { - uint32_t i, j, max_node_index, last_online_node; + uint32_t i, j, num_nodes; xen_sysctl_numainfo_t *ni = &op->u.numainfo; - last_online_node = last_node(node_online_map); - max_node_index = min_t(uint32_t, ni->max_node_index, last_online_node); - ni->max_node_index = last_online_node; + if ( guest_handle_is_null(ni->meminfo) || + guest_handle_is_null(ni->distance) ) + { + ret = -EINVAL; + break; + } - for ( i = 0; i <= max_node_index; i++ ) + num_nodes = last_node(node_online_map) + 1; + if ( ni->num_nodes != num_nodes ) { - if ( !guest_handle_is_null(ni->node_to_memsize) ) + uint32_t array_sz = ni->num_nodes; + + ni->num_nodes = num_nodes; + if ( __copy_field_to_guest(u_sysctl, op, + u.numainfo.num_nodes) ) { - uint64_t memsize = node_online(i) ? - node_spanned_pages(i) << PAGE_SHIFT : 0ul; - if ( copy_to_guest_offset(ni->node_to_memsize, i, &memsize, 1) ) - break; + ret = -EFAULT; + break; + } + num_nodes = min_t(uint32_t, array_sz, num_nodes); + } + + for ( i = 0; i < num_nodes; i++ ) + { + xen_sysctl_meminfo_t meminfo; + uint8_t distance[MAX_NUMNODES]; + + if ( node_online(i) ) + { + meminfo.memsize = node_spanned_pages(i) << PAGE_SHIFT; + meminfo.memfree = avail_node_heap_pages(i) << PAGE_SHIFT; } - if ( !guest_handle_is_null(ni->node_to_memfree) ) + else + meminfo.memsize = meminfo.memfree = XEN_INVALID_MEM_SZ; + + for ( j = 0; j < num_nodes; j++ ) { - uint64_t memfree = node_online(i) ? - avail_node_heap_pages(i) << PAGE_SHIFT : 0ul; - if ( copy_to_guest_offset(ni->node_to_memfree, i, &memfree, 1) ) - break; + distance[j] = __node_distance(i, j); + if ( distance[j] == NUMA_NO_DISTANCE ) + distance[j] = XEN_INVALID_NODE_DIST; } - if ( !guest_handle_is_null(ni->node_to_node_distance) ) + if ( copy_to_guest_offset(ni->distance, i * num_nodes, + distance, num_nodes) || + copy_to_guest_offset(ni->meminfo, i, &meminfo, 1) ) { - for ( j = 0; j <= max_node_index; j++) - { - uint32_t distance = ~0u; - if ( node_online(i) && node_online(j) ) - distance = __node_distance(i, j); - if ( copy_to_guest_offset( - ni->node_to_node_distance, - i*(max_node_index+1) + j, &distance, 1) ) - break; - } - if ( j <= max_node_index ) - break; + ret = -EFAULT; + break; } } - - ret = ((i <= max_node_index) || copy_to_guest(u_sysctl, op, 1)) - ? -EFAULT : 0; } break; diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h index f20da69..c544c76 100644 --- a/xen/include/public/sysctl.h +++ b/xen/include/public/sysctl.h @@ -495,23 +495,33 @@ typedef struct xen_sysctl_cputopoinfo xen_sysctl_cputopoinfo_t; DEFINE_XEN_GUEST_HANDLE(xen_sysctl_cputopoinfo_t); /* XEN_SYSCTL_numainfo */ -#define INVALID_NUMAINFO_ID (~0U) +#define XEN_INVALID_MEM_SZ (~0U) +#define XEN_INVALID_NODE_DIST ((uint8_t)~0) + +struct xen_sysctl_meminfo { + uint64_t memsize; + uint64_t memfree; +}; +typedef struct xen_sysctl_meminfo xen_sysctl_meminfo_t; +DEFINE_XEN_GUEST_HANDLE(xen_sysctl_meminfo_t); + struct xen_sysctl_numainfo { /* - * IN: maximum addressable entry in the caller-provided arrays. - * OUT: largest node identifier in the system. - * If OUT is greater than IN then the arrays are truncated! + * IN: size of caller-provided arrays. + * OUT: number of nodes in the system. */ - uint32_t max_node_index; + uint32_t num_nodes; - /* NB. Entries are 0 if node is not present. */ - XEN_GUEST_HANDLE_64(uint64) node_to_memsize; - XEN_GUEST_HANDLE_64(uint64) node_to_memfree; + /* + * OUT: max_node_index-sized array. Entries are XEN_INVALID_MEM_SZ + * if node is not present. + */ + XEN_GUEST_HANDLE_64(xen_sysctl_meminfo_t) meminfo; /* - * Array, of size (max_node_index+1)^2, listing memory access distances + * OUT: Array, of size (max_node_index+1)^2, listing memory access distances * between nodes. If an entry has no node distance information (e.g., node - * not present) then the value ~0u is written. + * not present) then the value XEN_INVALID_NODE_DIST is written. * * Note that the array rows must be indexed by multiplying by the minimum * of the caller-provided max_node_index and the returned value of @@ -522,7 +532,7 @@ struct xen_sysctl_numainfo { * in the system is larger than the caller can handle, then a 2-d array of * the maximum size handleable by the caller is constructed. */ - XEN_GUEST_HANDLE_64(uint32) node_to_node_distance; + XEN_GUEST_HANDLE_64(uint8) distance; }; typedef struct xen_sysctl_numainfo xen_sysctl_numainfo_t; DEFINE_XEN_GUEST_HANDLE(xen_sysctl_numainfo_t); -- 1.7.1 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |