[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH v2 4/4] xentrace: Implement cpu mask range parsing of human values (-c).



Instead of just using -c 0x<some hex value> we can
also use -c <starting cpu>-<end cpu> or -c <cpu1>,<cpu2>
or a combination of them.

That should make it easier to trace the right CPU if
using this along with 'xl vcpu-list'.

The code has been lifted from the Linux kernel, see file
lib/bitmap.c, function __bitmap_parselist.

To make the old behavior and the new function work, we check
to see if the arguments have '0x' in them. If they do
we use the old style parsing (limited to 32 CPUs). If that
does not exist we use the new parsing.

Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx>
---
 tools/xentrace/xentrace.8 |   21 +++++-
 tools/xentrace/xentrace.c |  155 ++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 165 insertions(+), 11 deletions(-)

diff --git a/tools/xentrace/xentrace.8 b/tools/xentrace/xentrace.8
index c176a96..9beb72d 100644
--- a/tools/xentrace/xentrace.8
+++ b/tools/xentrace/xentrace.8
@@ -36,11 +36,26 @@ all new records to the output
 set the time, p, (in milliseconds) to sleep between polling the buffers
 for new data.
 .TP
-.B -c, --cpu-mask=c
-set bitmask of CPUs to trace. It is limited to 32-bits.
+.B -c, --cpu-mask=[\fIc\fP|\fICPU-LIST\fP]
+set bitmask of CPUs to trace. It is limited to 32-bits if using hex digits.
 If not specified, the cpu-mask of all of the available CPUs will be
-constructed.
+constructed. If using the \fICPU-LIST\fP it expects decimal numbers, which
+may be specified as follows:
 
+.RS 4
+.ie n .IP """0-3""" 4
+.el .IP "``0-3''" 4
+.IX Item "0-3"
+Trace only on CPUs 0 through 3
+.ie n .IP """0,2,5-7""" 4
+.el .IP "``0,2,5-7''" 4
+.IX Item "0,2,5-7"
+Trace only on CPUs 0, 2, and 5 through 7.
+.RE
+.Sp
+
+If this option is not specified, xentrace will trace all of the physical
+CPUs on the machine.
 .TP
 .B -e, --evt-mask=e
 set event capture mask. If not specified the TRC_ALL will be used.
diff --git a/tools/xentrace/xentrace.c b/tools/xentrace/xentrace.c
index 03b5537..45b0597 100644
--- a/tools/xentrace/xentrace.c
+++ b/tools/xentrace/xentrace.c
@@ -23,6 +23,7 @@
 #include <string.h>
 #include <getopt.h>
 #include <assert.h>
+#include <ctype.h>
 #include <sys/poll.h>
 #include <sys/statvfs.h>
 
@@ -31,6 +32,7 @@
 
 #include <xenctrl.h>
 #include "xc_private.h"
+#include "xc_bitops.h" /* for set_bit */
 
 /***** Compile time configuration of defaults ********************************/
 
@@ -45,6 +47,7 @@ typedef struct settings_st {
     unsigned long poll_sleep; /* milliseconds to sleep between polls */
     uint32_t evt_mask;
     xc_cpumap_t cpu_mask;
+    char *cpu_mask_str;
     unsigned long tbuf_size;
     unsigned long disk_rsvd;
     unsigned long timeout;
@@ -809,7 +812,7 @@ static void usage(void)
 "Usage: xentrace [OPTION...] [output file]\n" \
 "Tool to capture Xen trace buffer data\n" \
 "\n" \
-"  -c, --cpu-mask=c        Set cpu-mask\n" \
+"  -c, --cpu-mask=c        Set cpu-mask using hex and CPU ranges\n" \
 "  -e, --evt-mask=e        Set evt-mask\n" \
 "  -s, --poll-sleep=p      Set sleep time, p, in milliseconds between\n" \
 "                          polling the trace buffer for new data\n" \
@@ -958,6 +961,126 @@ static int parse_cpumask(const char *arg)
     return 0;
 }
 
+#define ZERO_DIGIT '0'
+
+static int parse_cpumask_range(const char *arg)
+{
+    xc_cpumap_t map;
+    unsigned int a, b, buflen = strlen(arg);
+    int c, c_old, totaldigits, nmaskbits;
+    int in_range;
+
+    if ( !buflen )
+    {
+        fprintf(stderr, "Invalid option argument: %s\n", arg);
+        usage(); /* does exit */
+    }
+    nmaskbits = xc_get_max_cpus(xch);
+    if ( nmaskbits <= 0 )
+    {
+        fprintf(stderr, "Failed to get max number of CPUs! rc: %d\n", 
nmaskbits);
+        usage();
+    }
+    map = xc_cpumap_alloc(xch);
+    if ( !map )
+    {
+        fprintf(stderr, "Out of memory!\n");
+        usage();
+    }
+    c = c_old = totaldigits = 0;
+    do {
+        in_range = 0;
+        a = b = 0;
+        while ( buflen )
+        {
+            c_old = c;
+            c = *arg++;
+            buflen--;
+
+            if ( isspace(c) )
+                continue;
+
+            if ( totaldigits && c && isspace(c_old) )
+            {
+                fprintf(stderr, "No embedded whitespaces allowed in: %s\n", 
arg);
+                goto err_out;
+            }
+
+            /* A '\0' or a ',' signal the end of a cpu# or range */
+            if ( c == '\0' || c == ',' )
+                break;
+
+            if ( c == '-' )
+            {
+                if ( in_range )
+                        goto err_out;
+                b = 0;
+                in_range = 1;
+                continue;
+            }
+            if ( !isdigit(c) )
+            {
+                fprintf(stderr, "Only digits allowed in: %s\n", arg);
+                goto err_out;
+            }
+            b = b * 10 + (c - ZERO_DIGIT);
+            if ( !in_range )
+                a = b;
+            totaldigits++;
+        }
+        if ( !(a <= b) )
+        {
+            fprintf(stderr, "Wrong order of %d and %d\n", a, b);
+            goto err_out;
+        }
+        if ( b >= nmaskbits )
+        {
+            fprintf(stderr, "Specified higher value then there are CPUS!\n");
+            goto err_out;
+        }
+        while ( a <= b )
+        {
+            set_bit(a, (unsigned long *) map);
+            a++;
+        }
+    } while ( buflen && c == ',' );
+
+    opts.cpu_mask = map;
+    return 0;
+ err_out:
+    free(map);
+    usage();
+    return 0; /* Never reached */
+}
+
+static int check_for_hex(const char *s)
+{
+    int buflen;
+    int c_old, c;
+
+    buflen = strlen(s);
+    c_old = c = 0;
+    do {
+            c = *s++;
+            buflen--;
+
+            if ( isspace(c) && c_old != ZERO_DIGIT )
+                continue;
+
+            if ( c == '\0' )
+                return -1;
+
+            if ( c == ZERO_DIGIT )
+                c_old = c;
+
+            if ( c == 'x' && c_old == ZERO_DIGIT )
+                return 1;
+
+     } while ( buflen );
+
+    return 0;
+}
+
 /* parse command line arguments */
 static void parse_args(int argc, char **argv)
 {
@@ -989,14 +1112,25 @@ static void parse_args(int argc, char **argv)
             break;
 
         case 'c': /* set new cpu mask for filtering*/
-            /* Set opts.cpu_mask later as we don't have 'xch' set yet. */
-            if ( parse_cpumask(optarg) )
             {
-                perror("Not enough memory!");
-                exit(EXIT_FAILURE);
+                int ret = check_for_hex(optarg);
+
+                if ( ret < 0 )
+                    usage();
+
+                if ( ret )
+                    ret = parse_cpumask(optarg);
+                else
+                    /* Set opts.cpu_mask later as we don't have 'xch' set 
yet.*/
+                    opts.cpu_mask_str = strdup(optarg);
+
+                if ( ret )
+                {
+                    perror("Not enough memory!");
+                    exit(EXIT_FAILURE);
+                }
+                break;
             }
-            break;
-        
         case 'e': /* set new event mask for filtering*/
             parse_evtmask(optarg);
             break;
@@ -1060,6 +1194,7 @@ int main(int argc, char **argv)
     opts.poll_sleep = POLL_SLEEP_MILLIS;
     opts.evt_mask = 0;
     opts.cpu_mask = NULL;
+    opts.cpu_mask_str = NULL;
     opts.disk_rsvd = 0;
     opts.disable_tracing = 1;
     opts.start_disabled = 0;
@@ -1077,7 +1212,11 @@ int main(int argc, char **argv)
     if ( opts.evt_mask != 0 )
         set_evt_mask(opts.evt_mask);
 
-
+    if ( opts.cpu_mask_str )
+    {
+        parse_cpumask_range(opts.cpu_mask_str);
+        free(opts.cpu_mask_str);
+    }
     set_cpu_mask(opts.cpu_mask);
     /* We don't use it pass this point. */
     free(opts.cpu_mask);
-- 
1.7.7.6


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.