From: Steven Rostedt <rostedt@goodmis.org>
To: Slavomir Kaslev <kaslevs@vmware.com>
Cc: linux-trace-devel@vger.kernel.org, slavomir.kaslev@gmail.com
Subject: Re: [RFC PATCH v6 05/11] trace-cmd: Add VM kernel tracing over vsockets transport
Date: Thu, 14 Feb 2019 15:03:48 -0500 [thread overview]
Message-ID: <20190214150348.0f44293e@gandalf.local.home> (raw)
In-Reply-To: <20190214141335.28144-6-kaslevs@vmware.com>
On Thu, 14 Feb 2019 16:13:29 +0200
Slavomir Kaslev <kaslevs@vmware.com> wrote:
> void start_threads(enum trace_type type, struct common_record_context *ctx)
> {
> struct buffer_instance *instance;
> - int *brass = NULL;
> int total_cpu_count = 0;
> int i = 0;
> int ret;
>
> - for_all_instances(instance)
> + for_all_instances(instance) {
> + /* Start the connection now to find out how many CPUs we need */
> + if (instance->flags & BUFFER_FL_GUEST)
> + connect_to_agent(instance);
> total_cpu_count += instance->cpu_count;
> + }
>
> /* make a thread for every CPU we have */
> - pids = malloc(sizeof(*pids) * total_cpu_count * (buffers + 1));
> + pids = calloc(total_cpu_count * (buffers + 1), sizeof(*pids));
> if (!pids)
> - die("Failed to allocat pids for %d cpus", total_cpu_count);
> -
> - memset(pids, 0, sizeof(*pids) * total_cpu_count * (buffers + 1));
> + die("Failed to allocate pids for %d cpus", total_cpu_count);
>
> for_all_instances(instance) {
> + int *brass = NULL;
> int x, pid;
>
> - if (host) {
> + if (instance->flags & BUFFER_FL_AGENT) {
> + setup_agent(instance, ctx);
> + } else if (instance->flags & BUFFER_FL_GUEST) {
> + setup_guest(instance);
> + } else if (host) {
> instance->msg_handle = setup_connection(instance, ctx);
> if (!instance->msg_handle)
> die("Failed to make connection");
> @@ -3139,13 +3444,14 @@ static void print_stat(struct buffer_instance *instance)
> {
> int cpu;
>
> + if (quiet)
> + return;
Hmm, this looks unrelated to this patch, and looks like it should have
been in a patch by itself. As a clean up.
> +
> if (!is_top_instance(instance))
> - if (!quiet)
> - printf("\nBuffer: %s\n\n", instance->name);
> + printf("\nBuffer: %s\n\n", instance->name);
>
> for (cpu = 0; cpu < instance->cpu_count; cpu++)
> - if (!quiet)
> - trace_seq_do_printf(&instance->s_print[cpu]);
> + trace_seq_do_printf(&instance->s_print[cpu]);
> }
>
> enum {
> @@ -3171,7 +3477,44 @@ static void add_options(struct tracecmd_output *handle, struct common_record_con
> tracecmd_add_option(handle, TRACECMD_OPTION_TRACECLOCK, 0, NULL);
> add_option_hooks(handle);
> add_uname(handle);
> +}
> +
> +static void write_guest_file(struct buffer_instance *instance)
> +{
> + struct tracecmd_output *handle;
> + int cpu_count = instance->cpu_count;
> + char *file;
> + char **temp_files;
> + int i, fd;
> +
> + file = get_guest_file(output_file, instance->name);
> + fd = open(file, O_RDWR);
> + if (fd < 0)
> + die("error opening %s", file);
> + put_temp_file(file);
> +
> + handle = tracecmd_get_output_handle_fd(fd);
> + if (!handle)
> + die("error writing to %s", file);
>
> + temp_files = malloc(sizeof(*temp_files) * cpu_count);
> + if (!temp_files)
> + die("failed to allocate temp_files for %d cpus",
> + cpu_count);
> +
> + for (i = 0; i < cpu_count; i++) {
> + temp_files[i] = get_temp_file(instance, i);
> + if (!temp_files[i])
> + die("failed to allocate memory");
> + }
> +
> + if (tracecmd_write_cpu_data(handle, cpu_count, temp_files) < 0)
> + die("failed to write CPU data");
> + tracecmd_output_close(handle);
> +
> + for (i = 0; i < cpu_count; i++)
> + put_temp_file(temp_files[i]);
> + free(temp_files);
> }
>
> static void record_data(struct common_record_context *ctx)
> @@ -3185,7 +3528,9 @@ static void record_data(struct common_record_context *ctx)
> int i;
>
> for_all_instances(instance) {
> - if (instance->msg_handle)
> + if (instance->flags & BUFFER_FL_GUEST)
> + write_guest_file(instance);
> + else if (host && instance->msg_handle)
> finish_network(instance->msg_handle);
> else
> local = true;
> @@ -4404,6 +4749,7 @@ void trace_stop(int argc, char **argv)
> c = getopt(argc-1, argv+1, "hatB:");
> if (c == -1)
> break;
> +
> switch (c) {
> case 'h':
> usage(argv);
> @@ -4566,6 +4912,63 @@ static void init_common_record_context(struct common_record_context *ctx,
> #define IS_STREAM(ctx) ((ctx)->curr_cmd == CMD_stream)
> #define IS_PROFILE(ctx) ((ctx)->curr_cmd == CMD_profile)
> #define IS_RECORD(ctx) ((ctx)->curr_cmd == CMD_record)
> +#define IS_AGENT(ctx) ((ctx)->curr_cmd == CMD_record_agent)
> +
> +static void add_argv(struct buffer_instance *instance, char *arg, bool prepend)
> +{
> + instance->argv = realloc(instance->argv,
> + (instance->argc + 1) * sizeof(char *));
> + if (!instance->argv)
> + die("Can not allocate instance args");
> + if (prepend) {
> + memmove(instance->argv + 1, instance->argv,
> + instance->argc * sizeof(*instance->argv));
> + instance->argv[0] = arg;
> + } else {
> + instance->argv[instance->argc] = arg;
> + }
> + instance->argc++;
> +}
> +
> +static void add_arg(struct buffer_instance *instance,
> + int c, const char *opts,
> + struct option *long_options, char *optarg)
> +{
> + char *ptr;
> + char *arg;
> + int ret;
> + int i;
> +
> + /* Short or long arg */
> + if (!(c & 0x80)) {
> + ret = asprintf(&arg, "-%c", c);
> + if (ret < 0)
> + die("Can not allocate argument");
> + ptr = strstr(opts, arg+1);
> + if (!ptr)
> + return; /* Not found? */
This leaks arg, as arg was allocated with asprintf(). Need a
"free(arg)" here.
> + add_argv(instance, arg, false);
> + if (ptr[1] == ':')
> + add_argv(instance, optarg, false);
> + return;
> + }
> + for (i = 0; long_options[i].name; i++) {
> + if (c == long_options[i].val) {
> + ret = asprintf(&arg, "--%s", long_options[i].name);
> + if (ret < 0)
> + die("Can not allocate argument");
> + add_argv(instance, arg, false);
> + if (long_options[i].has_arg) {
> + arg = strdup(optarg);
> + if (!arg)
> + die("Can not allocate arguments");
> + add_argv(instance, arg, false);
> + return;
> + }
> + }
> + }
> + /* Not found? */
> +}
>
> static void parse_record_options(int argc,
> char **argv,
> @@ -4607,10 +5010,20 @@ static void parse_record_options(int argc,
> if (IS_EXTRACT(ctx))
> opts = "+haf:Fp:co:O:sr:g:l:n:P:N:tb:B:ksiT";
> else
> - opts = "+hae:f:Fp:cC:dDGo:O:s:r:vg:l:n:P:N:tb:R:B:ksSiTm:M:H:q";
> + opts = "+hae:f:FA:p:cC:dDGo:O:s:r:vg:l:n:P:N:tb:R:B:ksSiTm:M:H:q";
> c = getopt_long (argc-1, argv+1, opts, long_options, &option_index);
> if (c == -1)
> break;
> +
> + /*
> + * If the current instance is to record a guest, then save
> + * all the arguments for this instance.
> + */
> + if (c != 'B' && c != 'A' && ctx->instance->flags & BUFFER_FL_GUEST) {
> + add_arg(ctx->instance, c, opts, long_options, optarg);
> + continue;
> + }
> +
> switch (c) {
> case 'h':
> usage(argv);
> @@ -4663,6 +5076,26 @@ static void parse_record_options(int argc,
> add_trigger(event, optarg);
> break;
>
> + case 'A': {
> + char *name = NULL;
> + int cid = -1, port = -1;
> +
> + if (!IS_RECORD(ctx))
> + die("-A is only allowed for record operations");
> +
> + name = parse_guest_name(optarg, &cid, &port);
> + if (!name || cid == -1)
> + die("guest %s not found", optarg);
> + if (port == -1)
> + port = TRACE_AGENT_DEFAULT_PORT;
> +
> + ctx->instance = create_instance(name);
> + ctx->instance->flags |= BUFFER_FL_GUEST;
> + ctx->instance->cid = cid;
> + ctx->instance->port = port;
> + add_instance(ctx->instance, 0);
> + break;
> + }
> case 'F':
> test_set_event_pid();
> filter_task = 1;
> @@ -4733,6 +5166,8 @@ static void parse_record_options(int argc,
> ctx->disable = 1;
> break;
> case 'o':
> + if (IS_AGENT(ctx))
> + die("-o incompatible with agent recording");
> if (host)
> die("-o incompatible with -N");
> if (IS_START(ctx))
> @@ -4794,6 +5229,8 @@ static void parse_record_options(int argc,
> case 'N':
> if (!IS_RECORD(ctx))
> die("-N only available with record");
> + if (IS_AGENT(ctx))
> + die("-N incompatible with agent recording");
> if (ctx->output)
> die("-N incompatible with -o");
> host = optarg;
> @@ -4890,6 +5327,16 @@ static void parse_record_options(int argc,
> }
> }
>
> + /* If --date is specified, prepend it to all guest VM flags */
> + if (ctx->date) {
> + struct buffer_instance *instance;
> +
> + for_all_instances(instance) {
> + if (instance->flags & BUFFER_FL_GUEST)
> + add_argv(instance, "--date", true);
> + }
> + }
> +
> if (!ctx->filtered && ctx->instance->filter_mod)
> add_func(&ctx->instance->filter_funcs,
> ctx->instance->filter_mod, "*");
> @@ -4920,7 +5367,8 @@ static enum trace_type get_trace_cmd_type(enum trace_cmd cmd)
> {CMD_stream, TRACE_TYPE_STREAM},
> {CMD_extract, TRACE_TYPE_EXTRACT},
> {CMD_profile, TRACE_TYPE_STREAM},
> - {CMD_start, TRACE_TYPE_START}
> + {CMD_start, TRACE_TYPE_START},
> + {CMD_record_agent, TRACE_TYPE_RECORD}
> };
>
> for (int i = 0; i < ARRAY_SIZE(trace_type_per_command); i++) {
> @@ -4952,12 +5400,28 @@ static void finalize_record_trace(struct common_record_context *ctx)
> if (instance->flags & BUFFER_FL_KEEP)
> write_tracing_on(instance,
> instance->tracing_on_init_val);
> + if (instance->flags & BUFFER_FL_AGENT)
> + tracecmd_output_close(instance->network_handle);
> }
>
> if (host)
> tracecmd_output_close(ctx->instance->network_handle);
> }
>
> +static bool has_local_instances(void)
> +{
> + struct buffer_instance *instance;
> +
> + for_all_instances(instance) {
> + if (instance->flags & BUFFER_FL_GUEST)
> + continue;
> + if (host && instance->msg_handle)
> + continue;
> + return true;
> + }
> + return false;
> +}
> +
> /*
> * This function contains common code for the following commands:
> * record, start, stream, profile.
> @@ -4986,7 +5450,6 @@ static void record_trace(int argc, char **argv,
>
> /* Save the state of tracing_on before starting */
> for_all_instances(instance) {
> -
> if (!ctx->manual && instance->flags & BUFFER_FL_PROFILE)
> enable_profile(instance);
>
> @@ -5003,14 +5466,16 @@ static void record_trace(int argc, char **argv,
>
> page_size = getpagesize();
>
> - fset = set_ftrace(!ctx->disable, ctx->total_disable);
> + if (!(ctx->instance->flags & BUFFER_FL_GUEST))
> + fset = set_ftrace(!ctx->disable, ctx->total_disable);
> tracecmd_disable_all_tracing(1);
>
> for_all_instances(instance)
> set_clock(instance);
>
> /* Record records the date first */
> - if (IS_RECORD(ctx) && ctx->date)
> + if (ctx->date &&
> + ((IS_RECORD(ctx) && has_local_instances()) || IS_AGENT(ctx)))
> ctx->date2ts = get_date_to_ts();
>
> for_all_instances(instance) {
> @@ -5045,9 +5510,13 @@ static void record_trace(int argc, char **argv,
> exit(0);
> }
>
> - if (ctx->run_command)
> + if (ctx->run_command) {
> run_cmd(type, (argc - optind) - 1, &argv[optind + 1]);
> - else {
> + } else if (ctx->instance && (ctx->instance->flags & BUFFER_FL_AGENT)) {
> + update_task_filter();
> + tracecmd_enable_tracing();
> + tracecmd_msg_wait_close(ctx->instance->msg_handle);
> + } else {
> update_task_filter();
> tracecmd_enable_tracing();
> /* We don't ptrace ourself */
> @@ -5057,6 +5526,8 @@ static void record_trace(int argc, char **argv,
> printf("Hit Ctrl^C to stop recording\n");
> while (!finished)
> trace_or_sleep(type);
> +
> + tell_guests_to_stop();
> }
>
> tracecmd_disable_tracing();
> @@ -5068,6 +5539,9 @@ static void record_trace(int argc, char **argv,
> if (!keep)
> tracecmd_disable_all_tracing(0);
>
> + if (!latency)
> + wait_threads();
> +
> if (IS_RECORD(ctx)) {
> record_data(ctx);
> delete_thread_data();
> @@ -5202,3 +5676,40 @@ void trace_record(int argc, char **argv)
> record_trace(argc, argv, &ctx);
> exit(0);
> }
> +
> +int trace_record_agent(struct tracecmd_msg_handle *msg_handle,
> + int cpus, int *fds,
> + int argc, char **argv)
> +{
> + struct common_record_context ctx;
> + char **argv_plus;
> +
> + /* Reset optind for getopt_long */
> + optind = 1;
> + /*
> + * argc is the number of elements in argv, but we need to convert
> + * argc and argv into "trace-cmd", "record", argv.
> + * where argc needs to grow by two.
> + */
> + argv_plus = calloc(argc + 2, sizeof(char *));
> + if (!argv_plus)
> + return -ENOMEM;
> +
> + argv_plus[0] = "trace-cmd";
> + argv_plus[1] = "record";
> + memmove(argv_plus + 2, argv, argc * sizeof(char *));
> + argc += 2;
> +
> + parse_record_options(argc, argv_plus, CMD_record_agent, &ctx);
> + if (ctx.run_command)
> + return -EINVAL;
> +
> + ctx.instance->fds = fds;
> + ctx.instance->flags |= BUFFER_FL_AGENT;
> + ctx.instance->msg_handle = msg_handle;
> + msg_handle->version = V3_PROTOCOL;
> + record_trace(argc, argv, &ctx);
> +
> + free(argv_plus);
> + return 0;
> +}
> diff --git a/tracecmd/trace-usage.c b/tracecmd/trace-usage.c
> index 9ea1906..e845f50 100644
> --- a/tracecmd/trace-usage.c
> +++ b/tracecmd/trace-usage.c
> @@ -231,11 +231,22 @@ static struct usage_help usage_help[] = {
> "listen on a network socket for trace clients",
> " %s listen -p port[-D][-o file][-d dir][-l logfile]\n"
> " Creates a socket to listen for clients.\n"
> - " -D create it in daemon mode.\n"
> + " -p port number to listen on.\n"
> + " -D run in daemon mode.\n"
> " -o file name to use for clients.\n"
> " -d directory to store client files.\n"
> " -l logfile to write messages to.\n"
> },
> +#ifdef VSOCK
> + {
> + "agent",
In the future, it would be nice to allow agents to work with networks
as well (in case vsock isn't available, but also across machines, where
we would do a p2p to synchronize time stamps.
-- Steve
> + "listen on a vsocket for trace clients",
> + " %s agent -p port[-D]\n"
> + " Creates a vsocket to listen for clients.\n"
> + " -p port number to listen on.\n"
> + " -D run in daemon mode.\n"
> + },
> +#endif
> {
> "list",
> "list the available events, plugins or options",
next prev parent reply other threads:[~2019-02-14 20:03 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-02-14 14:13 [RFC PATCH v6 00/11] Add VM kernel tracing over vsockets and FIFOs Slavomir Kaslev
2019-02-14 14:13 ` [RFC PATCH v6 01/11] trace-cmd: Detect if vsockets are available Slavomir Kaslev
2019-02-14 14:13 ` [RFC PATCH v6 02/11] trace-cmd: Add tracecmd_create_recorder_virt function Slavomir Kaslev
2019-02-14 14:13 ` [RFC PATCH v6 03/11] trace-cmd: Add TRACE_REQ and TRACE_RESP messages Slavomir Kaslev
2019-02-14 18:51 ` Steven Rostedt
2019-02-14 14:13 ` [RFC PATCH v6 04/11] trace-cmd: Add buffer instance flags for tracing in guest and agent context Slavomir Kaslev
2019-02-14 20:05 ` Steven Rostedt
2019-02-18 14:24 ` Slavomir Kaslev
2019-02-14 14:13 ` [RFC PATCH v6 05/11] trace-cmd: Add VM kernel tracing over vsockets transport Slavomir Kaslev
2019-02-14 20:03 ` Steven Rostedt [this message]
2019-02-18 14:26 ` Slavomir Kaslev
2019-02-18 14:28 ` Slavomir Kaslev
2019-02-14 14:13 ` [RFC PATCH v6 06/11] trace-cmd: Use splice(2) for vsockets if available Slavomir Kaslev
2019-02-14 14:13 ` [RFC PATCH v6 07/11] trace-cmd: Add `trace-cmd setup-guest` command Slavomir Kaslev
2019-02-14 20:41 ` Steven Rostedt
2019-02-18 14:37 ` Slavomir Kaslev
2019-02-18 17:44 ` Steven Rostedt
2019-02-18 20:07 ` Slavomir Kaslev
2019-02-18 20:54 ` Slavomir Kaslev
2019-02-14 14:13 ` [RFC PATCH v6 08/11] trace-cmd: Try to autodetect number of guest CPUs in setup-guest if not specified Slavomir Kaslev
2019-02-14 14:13 ` [RFC PATCH v6 09/11] trace-cmd: Add setup-guest flag for attaching FIFOs to the guest VM config Slavomir Kaslev
2019-02-14 14:13 ` [RFC PATCH v6 10/11] trace-cmd: Add splice() recording from FIFO without additional pipe buffer Slavomir Kaslev
2019-02-14 21:07 ` Steven Rostedt
2019-02-14 14:13 ` [RFC PATCH v6 11/11] trace-cmd: Add VM tracing over FIFOs transport Slavomir Kaslev
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190214150348.0f44293e@gandalf.local.home \
--to=rostedt@goodmis.org \
--cc=kaslevs@vmware.com \
--cc=linux-trace-devel@vger.kernel.org \
--cc=slavomir.kaslev@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).