|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v3 3/3] xentrace: Implement cpu mask range parsing of human values (-c).
On 03/24/2015 03:39 PM, Konrad Rzeszutek Wilk wrote:
> 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. Also it can include just
> singular CPUs: -c <cpu1>, or ranges without an
> start or end (and xentrace will figure out the values), such
> as: -c -<cpu2> (which will include cpu0, cpu1, and cpu2) or
> -c <cpu2>- (which will include cpu2 and up to MAX_CPUS).
>
> 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>
> [v4: Fix per George's review]
> ---
> tools/xentrace/xentrace.8 | 34 ++++++++-
> tools/xentrace/xentrace.c | 190
> ++++++++++++++++++++++++++++++++++++++--------
> 2 files changed, 188 insertions(+), 36 deletions(-)
>
> diff --git a/tools/xentrace/xentrace.8 b/tools/xentrace/xentrace.8
> index c176a96..eb6fba8 100644
> --- a/tools/xentrace/xentrace.8
> +++ b/tools/xentrace/xentrace.8
> @@ -36,10 +36,36 @@ 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.
> -If not specified, the cpu-mask of all of the available CPUs will be
> -constructed.
> +.B -c, --cpu-mask=[\fIc\fP|\fICPU-LIST\fP]
> +This can either be a hex value (of the form 0xNNNN...), or a set of cpu
> +ranges as described below. Hex values are limited to 32 bits. If not
> +specified, the cpu-mask of all of the available CPUs will be
> +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.
> +.ie n .IP """-3""" 4
> +.el .IP "``-3''" 4
> +.IX Item "-3"
> +Trace only on CPUs 0 through 3
> +.ie n .IP """-3,7""" 4
> +.el .IP "``-3,7''" 4
> +.IX Item "-3,7"
> +Trace only on CPUs 0 through 3 and 7
> +.ie n .IP """3-""" 4
> +.el .IP "``3-''" 4
> +.IX Item "-3-"
> +Trace only on CPUs 3 up to maximum numbers of CPUs the host has.
> +.RE
> +.Sp
>
> .TP
> .B -e, --evt-mask=e
> diff --git a/tools/xentrace/xentrace.c b/tools/xentrace/xentrace.c
> index 40504ec..3dd5c01 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>
>
> @@ -54,6 +55,7 @@ typedef struct settings_st {
> uint32_t evt_mask;
> xc_cpumap_t cpu_mask;
> int cpu_bits;
> + char *cpu_mask_str;
> unsigned long tbuf_size;
> unsigned long disk_rsvd;
> unsigned long timeout;
> @@ -545,25 +547,6 @@ void print_cpu_mask(xc_cpumap_t mask, int bits)
>
> static void set_cpu_mask(xc_cpumap_t mask, int bits)
> {
> - int i;
> -
> - if ( bits <= 0 )
> - {
> - bits = xc_get_max_cpus(xc_handle);
> - if ( bits <= 0 )
> - goto out;
> - }
> - if ( !mask )
> - {
> - mask = xc_cpumap_alloc(xc_handle);
> - if ( !mask )
> - goto out;
> -
> - /* Set it to include _all_ CPUs. */
> - for ( i = 0; i < XC_DIV_ROUND_UP(bits, 8); i++ )
> - mask[i] = 0xff;
> - }
> - /* And this will limit it to the exact amount of bits. */
> if ( xc_tbuf_set_cpu_mask(xc_handle, mask, bits) )
> goto out;
>
> @@ -822,7 +805,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 either hex or 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" \
> @@ -976,6 +959,156 @@ 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;
> + const char *s;
> +
> + if ( !buflen )
> + {
> + fprintf(stderr, "Invalid option argument: %s\n", arg);
> + errno = EINVAL;
> + return EXIT_FAILURE;
> + }
I think we need blank lines between these if() statements
> + nmaskbits = xc_get_max_cpus(xc_handle);
[space]
> + if ( nmaskbits <= 0 )
> + {
> + fprintf(stderr, "Failed to get max number of CPUs! rc: %d\n",
> nmaskbits);
> + return EXIT_FAILURE;
> + }
[space]
> + map = xc_cpumap_alloc(xc_handle);
[space] &c
> + if ( !map )
> + {
> + fprintf(stderr, "Out of memory!\n");
> + return EXIT_FAILURE;
> + }
> + c = c_old = totaldigits = 0;
> + s = arg;
> + do {
> + in_range = 0;
> + a = b = 0;
> + /* The buflen can become zero in the '} while(..) below. */
> + while ( buflen )
> + {
> + c_old = c;
> + c = *s++;
> + buflen--;
> +
> + if ( isspace(c) )
> + continue;
> +
> + if ( totaldigits && c && isspace(c_old) )
> + {
> + fprintf(stderr, "No embedded whitespaces allowed in: %s\n",
> arg);
> + goto err_out;
> + }
Why are we even bothering to handle spaces here? Who would put
xentrace -c " 0-3,5" /tmp/foo
and why would we want to accept that input?
Not handling initial whitespace lets us get rid of totaldigits and c_old
as well.
> +
> + /* A '\0' or a ',' signal the end of a cpu# or range */
> + if ( c == '\0' || c == ',' )
> + break;
Can c=='\0' ever be true here? Isn't that why we do all the accounting
w/ buflen?
[snip]
> +
> +/**
> + * Figure out which of the CPU types the user has provided - either the hex
> + * variant or the cpu-list. Once done set the CPU mask.
> + */
> +static int figure_cpu_mask(void)
> +{
> + int ret = EXIT_FAILURE;
> +
> + if ( opts.cpu_mask_str )
I think we should move this if into main(), similar to opts.evt_mask.
> + {
> + if ( strlen(opts.cpu_mask_str) < 1 )
> + {
> + errno = ENOSPC;
> + goto out;
> + }
> + if ( strncmp("0x", opts.cpu_mask_str, 2) == 0 )
> + ret = parse_cpumask(opts.cpu_mask_str);
> + else
> + ret = parse_cpumask_range(opts.cpu_mask_str);
Would it make sense to add an "all" option here?
Also -- I think it might make sense to allocate the cpumask in this
function, and then have parse_cpumask* set the bits it wants. Then we
have a nice symmetric alloc and free.
> + }
> + else
And we can get rid of this else.
> + {
> + int i, bits;
> + xc_cpumap_t mask;
> +
> + bits = xc_get_max_cpus(xc_handle);
> + if ( bits <= 0 )
> + goto out;
> +
> + mask = xc_cpumap_alloc(xc_handle);
> + if ( !mask )
> + goto out;
> +
> + /* Set it to include _all_ CPUs. */
> + for ( i = 0; i < XC_DIV_ROUND_UP(bits, 8); i++ )
> + mask[i] = 0xff;
> +
> + opts.cpu_mask = mask;
> + opts.cpu_bits = bits;
> + ret = 0;
> + }
> + if ( ret != EXIT_FAILURE )
> + set_cpu_mask(opts.cpu_mask, opts.cpu_bits);
> + out:
> + /* We don't use it pass this point. */
> + free(opts.cpu_mask_str);
I guess we also want to free opts.cpu_mask
> + return ret;
> +}
> +
> /* parse command line arguments */
> static void parse_args(int argc, char **argv)
> {
> @@ -1006,15 +1139,9 @@ static void parse_args(int argc, char **argv)
> opts.poll_sleep = argtol(optarg, 0);
> 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);
> - }
> + case 'c': /* set new cpu mask for filtering (when xch is set). */
> + opts.cpu_mask_str = strdup(optarg);
> break;
> -
> case 'e': /* set new event mask for filtering*/
> parse_evtmask(optarg);
> break;
> @@ -1079,6 +1206,7 @@ int main(int argc, char **argv)
> opts.evt_mask = 0;
> opts.cpu_mask = NULL;
> opts.cpu_bits = 0;
> + opts.cpu_mask_str = NULL;
> opts.disk_rsvd = 0;
> opts.disable_tracing = 1;
> opts.start_disabled = 0;
> @@ -1096,10 +1224,8 @@ int main(int argc, char **argv)
> if ( opts.evt_mask != 0 )
> set_evt_mask(opts.evt_mask);
>
> -
> - set_cpu_mask(opts.cpu_mask, opts.cpu_bits);
> - /* We don't use it pass this point. */
> - free(opts.cpu_mask);
> + if (figure_cpu_mask())
> + usage(); /* calls exit. */
if (opts.cpu_mask_string)
figure_cpu_mask();
Thanks,
-George
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |