>From 901fe4364deb69a6a803f540f03c1d8cf418dbc0 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Fri, 9 Jun 2017 13:44:22 -0400 Subject: [PATCH 7/7] xen-numa: Add a heatmap. - 'heatmap' outputs an PGM file of where the MFNs of a guest reside. Use ImageMagick to convert this file to PNG: Also there is an third optional parameter to change the width of the file. And a fourth optional to inverse the colors. That can help as ImageMagick looks to be ignoring the PGM spec and printing 0 as white instead of as black. The heatmap illustrates a picture of 0..max_gpfns and the colors are the N NODEs. For two nodes we should see three colors - NODE0, NODE1, and holes. For example to use it: -bash-4.1# /xen-numa heatmap 1 1600 1 > /isos/heatmap-32gb-xl-vnuma.pgm See http://char.us.oracle.com/isos/heatmap-32gb-xl-vnuma.png http://char.us.oracle.com/isos/heatmap-32gb-xm-vnuma.png Signed-off-by: Konrad Rzeszutek Wilk --- tools/misc/xen-numa.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/tools/misc/xen-numa.c b/tools/misc/xen-numa.c index a0af262..b52def8 100644 --- a/tools/misc/xen-numa.c +++ b/tools/misc/xen-numa.c @@ -462,6 +462,130 @@ static struct ops node_ops = { .free = node_free, }; +/* ------------------------- */ + +static int setup_pgm(struct ops *ops) +{ + int rc = setup_node(ops); + + if ( !rc ) + { + struct node_args *n; + + n = ops->priv; + /* We don't want the percentage counter to show up, so.. */ + n->stride = 0; + } + + return rc; +} + +static int find_pfn(struct ops *ops, struct node_data *n, unsigned long pfn) +{ + struct groups *g; + unsigned int inverted = ops->arg4 ? : 0; + int rc; + + if ( !n->groups ) + return -ENOENT; + + if ( n->nid >= 0 ) + rc = inverted ? ops->nodes_nr - n->nid : n->nid; + else + rc = inverted ? 0 : ops->nodes_nr; + + for ( g = n->groups; g; g = g->next ) + { + if ( g->start == pfn ) + return rc; + + if ( pfn >= g->start && pfn <= g->start + g->len - 1 ) + return rc; + } + return -ENOENT; +} + +static void end_pgm(struct ops *ops) +{ + struct node_args *args = ops->priv; + unsigned long pfn; + unsigned long w, h; + unsigned long count; + unsigned int inverted = ops->arg4 ? : 0; + int rc; + + if ( !args ) + { + fprintf(stderr, "We lost our collected data!\n"); + return; + } + w = ops->arg3 ? : 1600; + h = (float)ops->max_gpfn / w; + + while ( ops->max_gpfn > (w*h) ) + h++; + + count = w*h; + fprintf(stdout,"P2\n%ld %ld\n", w, h); + fprintf(stdout, "%d\n", ops->nodes_nr); + + for ( pfn = 0; pfn < ops->max_gpfn; pfn++ ) + { + int node; + + rc = -ENOENT; + for ( node = 0; node < ops->nodes_nr; node++ ) + { + rc = find_pfn(ops, &args->nodes_data[node], pfn); + if ( rc >= 0 ) /* Found! */ + break; + if ( rc != -ENOENT ) /* Uh oh. Not good */ + break; + } + if ( rc == -ENOENT ) + rc = find_pfn(ops, &args->empty, pfn); + + if ( rc < 0 ) + { + if ( rc == -ENOENT ) + rc = inverted ? 0 : ops->nodes_nr; + else + goto out; + } + fprintf(stdout, "%d ", rc); + if ( pfn && (pfn % w ) == 0 ) + fprintf(stdout, "\n"); + + } + count -= pfn; + + rc = inverted ? 0 : ops->nodes_nr; + for ( pfn = 0; pfn < count; pfn++ ) + { + fprintf(stdout, "%d ", rc); + if ( (pfn % w ) == 0 ) + fprintf(stdout, "\n"); + } + + out: + node_free(ops); + free(args->nodes_data); + free(args); + ops->priv = NULL; +} + +static struct ops print_pgm_ops = { + .help = " heatmap - Output an PGM file of PFNs with NODE values.\n" \ + " First optional parameter to define width, and\n" \ + " second to invert colors.\n", + .name = "heatmap", + .setup = setup_pgm, + .iterate = node_iterate, + .end = end_pgm, + .free = node_free, +}; +/* ------------------------- */ + static struct ops *callback_ops[] = { &print_pfns_ops, &print_mfn_op, -- 2.9.4