* CSV output @ 2023-03-12 7:07 Julia Lawall 2023-03-13 16:15 ` Steven Rostedt 0 siblings, 1 reply; 8+ messages in thread From: Julia Lawall @ 2023-03-12 7:07 UTC (permalink / raw) To: linux-trace-users Would it be possible with libtraceevent to get some kind of CSV output? Ie something that is very easy or some other tool to parse, without having to spend a lot of time removing spaces? thanks, julia ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: CSV output 2023-03-12 7:07 CSV output Julia Lawall @ 2023-03-13 16:15 ` Steven Rostedt 2023-03-13 17:40 ` Julia Lawall 0 siblings, 1 reply; 8+ messages in thread From: Steven Rostedt @ 2023-03-13 16:15 UTC (permalink / raw) To: Julia Lawall; +Cc: linux-trace-users On Sun, 12 Mar 2023 08:07:01 +0100 (CET) Julia Lawall <julia.lawall@inria.fr> wrote: > Would it be possible with libtraceevent to get some kind of CSV output? > Ie something that is very easy or some other tool to parse, without having > to spend a lot of time removing spaces? > You mean to convert a trace.dat file into a csv output? I guess I don't know what you want to convert to CSV output. I once made this, but never pushed it out. It adds "trace-cmd sqldump" where you pass it a trace.dat file and it returns an mysqldump formatted file, where each event is a table, its fields are columns, and the instances of the events are rows. This output (in theory, and use to work but I haven't tested it) allows you to pull in the trace.dat data into a mysql database. Is this something you are looking for? (I just forward ported it to the latest trace-cmd). -- Steve commit c78bbfa863b0d5ed9053945ebae87aa20ca5a1df Author: Steven Rostedt (VMware) <rostedt@goodmis.org> Date: Tue Jan 14 12:51:58 2020 -0500 trace-cmd: Add sqldump TBD Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org> diff --git a/tracecmd/Makefile b/tracecmd/Makefile index 66387526bc4b..1a65d94196aa 100644 --- a/tracecmd/Makefile +++ b/tracecmd/Makefile @@ -37,6 +37,7 @@ TRACE_CMD_OBJS += trace-dump.o TRACE_CMD_OBJS += trace-clear.o TRACE_CMD_OBJS += trace-vm.o TRACE_CMD_OBJS += trace-convert.o +TRACE_CMD_OBJS += trace-sqldump.o TRACE_CMD_OBJS += trace-agent.o TRACE_CMD_OBJS += trace-tsync.o TRACE_CMD_OBJS += trace-setup-guest.o diff --git a/tracecmd/include/trace-local.h b/tracecmd/include/trace-local.h index ae208fb6b593..1172c94fc52a 100644 --- a/tracecmd/include/trace-local.h +++ b/tracecmd/include/trace-local.h @@ -126,6 +126,12 @@ int trace_record_agent(struct tracecmd_msg_handle *msg_handle, bool use_fifos, struct tracecmd_time_sync *tsync, unsigned long long trace_id, int rcid, const char *host); +int trace_sql_record(struct tracecmd_input *handle, struct tep_record *record); + +int trace_sql_init(struct tracecmd_input *handle); + +int trace_sql_finish(struct tracecmd_input *handle); + struct hook_list; void trace_init_profile(struct tracecmd_input *handle, struct hook_list *hooks, diff --git a/tracecmd/trace-cmd.c b/tracecmd/trace-cmd.c index 9646921ca268..8de506885948 100644 --- a/tracecmd/trace-cmd.c +++ b/tracecmd/trace-cmd.c @@ -130,6 +130,7 @@ struct command { */ struct command commands[] = { {"report", trace_report}, + {"sqldump", trace_report}, {"snapshot", trace_snapshot}, {"hist", trace_hist}, {"mem", trace_mem}, diff --git a/tracecmd/trace-read.c b/tracecmd/trace-read.c index 52ba818e13b6..9902c7b28212 100644 --- a/tracecmd/trace-read.c +++ b/tracecmd/trace-read.c @@ -73,6 +73,10 @@ struct pid_list { int free; } *pid_list; +static const char *command; + +#define IS_SQLDUMP (strcmp(command, "sqldump") == 0) + struct pid_list *comm_list; static unsigned int page_size; @@ -1152,6 +1156,27 @@ static int process_record(struct tracecmd_input *handle, struct tep_record *reco return 0; } +static int process_sql_record(struct tracecmd_input *handle, struct tep_record *record, + int cpu, void *data) +{ + struct handle_list *handles = tracecmd_get_private(handle); + unsigned long long *last_timestamp = data; + + if (skip_record(handles, record, cpu)) + return 0; + + if (tscheck && *last_timestamp > record->ts) { + errno = 0; + warning("WARNING: Record on cpu %d went backwards: %lld to %lld delta: -%lld\n", + cpu, *last_timestamp, record->ts, *last_timestamp - record->ts); + } + *last_timestamp = record->ts; + + trace_sql_record(handle, record); + + return 0; +} + enum output_type { OUTPUT_NORMAL, OUTPUT_STAT_ONLY, @@ -1166,6 +1191,7 @@ static void read_data_info(struct list_head *handle_list, enum output_type otype struct handle_list *handles; struct tracecmd_input **handle_array; unsigned long long last_timestamp = 0; + bool sqldump = IS_SQLDUMP; int nr_handles = 0; int first = 1; int ret; @@ -1196,7 +1222,8 @@ static void read_data_info(struct list_head *handle_list, enum output_type otype first = 0; } print_handle_file(handles); - printf("cpus=%d\n", cpus); + if (!sqldump) + printf("cpus=%d\n", cpus); /* Latency trace is just all ASCII */ if (ret > 0) { @@ -1222,13 +1249,15 @@ static void read_data_info(struct list_head *handle_list, enum output_type otype continue; } - init_wakeup(handles->handle); - if (last_hook) - last_hook->next = tracecmd_hooks(handles->handle); - else - hooks = tracecmd_hooks(handles->handle); - if (profile) - trace_init_profile(handles->handle, hooks, global); + if (!sqldump) { + init_wakeup(handles->handle); + if (last_hook) + last_hook->next = tracecmd_hooks(handles->handle); + else + hooks = tracecmd_hooks(handles->handle); + if (profile) + trace_init_profile(handles->handle, hooks, global); + } /* If this file has buffer instances, get the handles for them */ instances = tracecmd_buffer_instances(handles->handle); @@ -1263,10 +1292,6 @@ static void read_data_info(struct list_head *handle_list, enum output_type otype } } } - - if (otype != OUTPUT_NORMAL) - return; - if (align_ts) { list_for_each_entry(handles, handle_list, list) { tracecmd_add_ts_offset(handles->handle, -first_ts); @@ -1285,8 +1310,25 @@ static void read_data_info(struct list_head *handle_list, enum output_type otype map_vcpus(handle_array, nr_handles); - tracecmd_iterate_events_multi(handle_array, nr_handles, - process_record, &last_timestamp); + if (sqldump) { + struct tracecmd_input *handle; + int i; + + for (i = 0; i < nr_handles; i++) { + handle = handle_array[i]; + + trace_sql_init(handle); + + tracecmd_iterate_events(handle, NULL, 0,process_sql_record, + &last_timestamp); + + trace_sql_finish(handle); + } + } else { + + tracecmd_iterate_events_multi(handle_array, nr_handles, + process_record, &last_timestamp); + } free(handle_array); @@ -1559,9 +1601,12 @@ void trace_report (int argc, char **argv) if (argc < 2) usage(argv); - if (strcmp(argv[1], "report") != 0) + if ((strcmp(argv[1], "report") != 0) && + (strcmp(argv[1], "sqldump") != 0)) usage(argv); + command = argv[1]; + signal(SIGINT, sig_end); trace_set_loglevel(TEP_LOG_ERROR); @@ -1743,9 +1788,13 @@ void trace_report (int argc, char **argv) tracecmd_set_debug(true); break; case OPT_profile: + if (IS_SQLDUMP) + usage(argv); profile = 1; break; case OPT_uname: + if (IS_SQLDUMP) + usage(argv); show_uname = 1; break; case OPT_version: @@ -1965,6 +2014,10 @@ void trace_report (int argc, char **argv) /* and version overrides uname! */ if (show_version) otype = OUTPUT_VERSION_ONLY; + + if (IS_SQLDUMP && otype != OUTPUT_NORMAL) + usage(argv); + read_data_info(&handle_list, otype, global, align_ts); list_for_each_entry(handles, &handle_list, list) { diff --git a/tracecmd/trace-sqldump.c b/tracecmd/trace-sqldump.c new file mode 100644 index 000000000000..b7ce99d28642 --- /dev/null +++ b/tracecmd/trace-sqldump.c @@ -0,0 +1,268 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 VMware Inc, Steven Rostedt + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> + +#include "trace-cmd.h" +#include "trace-local.h" + +extern void breakpoint(void); + +struct event_table { + struct tep_event *event; + struct tep_format_field **event_fields; + int *event_field_len; + size_t cnt; + FILE *fp; +}; + +static struct tep_format_field **event_common_fields; +static int nr_event_common_fields; + +static struct event_table *event_table; +static int event_table_size; + +int trace_sql_init(struct tracecmd_input *handle) +{ + struct tep_handle *tep; + struct tep_event **event_list; + struct tep_event *event; + struct event_table *et; + unsigned int max_id = 0; + int i, f; + + tep = tracecmd_get_tep(handle); + if (!tep) + return -1; + + event_list = tep_list_events(tep, TEP_EVENT_SORT_ID); + if (!event_list) + return -1; + + for (i = 0; event_list[i]; i++) { + event = event_list[i]; + + if (event->id > max_id) + max_id = event->id; + } + + event_table = calloc(max_id + 1, sizeof(*event_table)); + event_table_size = max_id + 1; + + for (i = 0; event_list[i]; i++) { + int e; + + event = event_list[i]; + + if (event->id == 302) + breakpoint(); + + et = &event_table[event->id]; + et->event = event; + + if (!event_common_fields) { + event_common_fields = tep_event_common_fields(event); + if (!event_common_fields) + goto fail; + for (f = 0; event_common_fields[f]; f++) + ; + nr_event_common_fields = f + 1; + } + + et->event_fields = tep_event_fields(event); + if (!et->event_fields) + goto fail; + + for (e = 0; et->event_fields[e]; e++) + ; + et->event_field_len = calloc(e, sizeof(*et->event_field_len)); + if (!et->event_field_len) + goto fail; + + et->fp = tmpfile(); + if (!et->fp) + goto fail; + } + return 0; + fail: + die("done!\n"); + return -1; +} + +static void write_string(FILE *fp, const char *str, int len) +{ + if (!len) + len = strlen(str); + + fputc('\'', fp); + fwrite(str, len, 1, fp); + fputc('\'', fp); +} + +static void write_data(FILE *fp, struct tep_format_field *field, + struct tep_record *record, int *elen) +{ + struct tep_handle *tep = field->event->tep; + unsigned int offset, len; + unsigned long long val; + char *data = record->data; + char buffer[64]; + + if (field->flags & TEP_FIELD_IS_ARRAY) { + offset = field->offset; + len = field->size; + + if (field->flags & TEP_FIELD_IS_DYNAMIC) { + val = tep_read_number(tep, data + offset, len); + offset = val; + len = offset >> 16; + offset &= 0xffff; + } + if (field->flags & TEP_FIELD_IS_STRING) { + int l = strlen(data + offset); + + if (l < len) + len = l; + write_string(fp, data + offset, len); + } else { + write_string(fp, "ARRAY", 0); + len = 5; + } + if (elen && (*elen) < len) + *elen = len; + return; + } + val = tep_read_number(tep, data + field->offset, + field->size); + sprintf(buffer, "%lld", val); + fwrite(buffer, strlen(buffer), 1, fp); + +} + +int trace_sql_record(struct tracecmd_input *handle, struct tep_record *record) +{ + struct tep_handle *tep = tracecmd_get_tep(handle); + struct tep_event *event = tep_find_event_by_record(tep, record); + struct event_table *et = &event_table[event->id]; + char buffer[64]; + int i; + + if (event->id > event_table_size || !et->event) + return -1; + + if (event->id == 302) + breakpoint(); + + if (et->cnt++) + fwrite(",(", 2, 1, et->fp); + else + fwrite("(", 1, 1, et->fp); + + i = sprintf(buffer, "%lld", record->ts); + fwrite(buffer, i, 1, et->fp); + + for (i = 0; event_common_fields[i]; i++) { + fwrite(",", 1, 1, et->fp); + write_data(et->fp, event_common_fields[i], record, NULL); + } + + for (i = 0; et->event_fields[i]; i++) { + fwrite(",", 1, 1, et->fp); + write_data(et->fp, et->event_fields[i], record, + &et->event_field_len[i]); + } + + fwrite(")", 1, 1, et->fp); + + return 0; +} + +static void write_header(struct tep_format_field *field, int flen) +{ + + printf("`%s` ", field->name); + + if (field->flags & TEP_FIELD_IS_ARRAY) { + if (field->flags & TEP_FIELD_IS_STRING) { + if (field->flags & TEP_FIELD_IS_DYNAMIC) { + if (flen) + printf("VARCHAR(%d)", flen); + else + printf("VARCHAR(64)"); + } else { + printf("CHAR(%d)", field->size); + } + } else { + printf("CHAR(5)"); + } + } else { + printf("BIGINT"); + } + + printf(" NOT NULL"); +} + +static void print_sql_header(struct event_table *et) +{ + const char *name = et->event->name; + int i; + + printf("\n---\n--- Table structure for table `%s`\n---\n\n", name); + printf("DROP TABLE IF EXISTS `%s`;\n", name); + + printf("CREATE TABLE `%s` (\n", name); + + printf(" `common_timestamp` BIGINT NOT NULL"); + + for (i = 0; event_common_fields[i]; i++) { + printf(",\n "); + write_header(event_common_fields[i], 0); + } + + for (i = 0; et->event_fields[i]; i++) { + printf(",\n "); + write_header(et->event_fields[i], et->event_field_len[i]); + } + + printf("\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"); + printf("\n---\n--- Dumping data for table `%s`\n---\n\n", name); + printf("LOCK TABLES `%s` WRITE;\n", name); + printf("INSERT INTO `%s` VALUES ", name); + + fflush(stdout); + fflush(et->fp); +} + +int trace_sql_finish(struct tracecmd_input *handle) +{ + struct event_table *et; + char buffer[BUFSIZ]; + int i, r; + int fd; + + for (i = 0; i < event_table_size; i++) { + et = &event_table[i]; + if (!et->cnt) + continue; + + print_sql_header(et); + + fd = fileno(et->fp); + lseek(fd, 0, SEEK_SET); + do { + r = read(fd, buffer, BUFSIZ); + if (r > 0) + write(1, buffer, r); + } while (r > 0); + fclose(et->fp); + printf(";\n"); + printf("UNLOCK TABLES;\n"); + } + + return 0; +} ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: CSV output 2023-03-13 16:15 ` Steven Rostedt @ 2023-03-13 17:40 ` Julia Lawall 2023-03-13 17:53 ` Steven Rostedt 0 siblings, 1 reply; 8+ messages in thread From: Julia Lawall @ 2023-03-13 17:40 UTC (permalink / raw) To: Steven Rostedt; +Cc: linux-trace-users On Mon, 13 Mar 2023, Steven Rostedt wrote: > On Sun, 12 Mar 2023 08:07:01 +0100 (CET) > Julia Lawall <julia.lawall@inria.fr> wrote: > > > Would it be possible with libtraceevent to get some kind of CSV output? > > Ie something that is very easy or some other tool to parse, without having > > to spend a lot of time removing spaces? > > > > You mean to convert a trace.dat file into a csv output? > > I guess I don't know what you want to convert to CSV output. Thanks for the patch. But actually, I was hoping for something like this: cpus=96 <...>-20420,074,3057.962369,sched_process_exec,/tmp/tmp2abf06.sh,20420,20420 <...>-20420,074,3057.963487,sched_switch,tmp2abf06.sh,20420,120,D,swapper/74,0,120 <idle>-0,034,3057.963602,sched_waking,kworker/u192,6,500,120,075 <idle>-0,075,3057.963632,sched_wakeup,kworker/u192,6,500,120,075 <idle>-0,075,3057.963637,sched_switch,swapper/75,0,120,R,kworker/u192,6,500,120 kworker/u192,6-500,075,3057.963656,sched_waking,tmp2abf06.sh,20420,120,074 kworker/u192,6-500,075,3057.963665,sched_switch,kworker/u192,6,500,120,W,swapper/75,0,120 <idle>-0,074,3057.963686,sched_wakeup,tmp2abf06.sh,20420,120,074 <idle>-0,074,3057.963691,sched_switch,swapper/74,0,120,R,tmp2abf06.sh,20420,120 It still remains human readable (more or less, with practice), but there are not a lot of spaces that a parser has to get rid of. The separator character would have to be something that can't occur in a command name. thanks, julia > > I once made this, but never pushed it out. > > It adds "trace-cmd sqldump" where you pass it a trace.dat file and it > returns an mysqldump formatted file, where each event is a table, its fields > are columns, and the instances of the events are rows. This output (in > theory, and use to work but I haven't tested it) allows you to pull in the > trace.dat data into a mysql database. > > Is this something you are looking for? (I just forward ported it to the > latest trace-cmd). > > -- Steve > > > commit c78bbfa863b0d5ed9053945ebae87aa20ca5a1df > Author: Steven Rostedt (VMware) <rostedt@goodmis.org> > Date: Tue Jan 14 12:51:58 2020 -0500 > > trace-cmd: Add sqldump > > TBD > > Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org> > > diff --git a/tracecmd/Makefile b/tracecmd/Makefile > index 66387526bc4b..1a65d94196aa 100644 > --- a/tracecmd/Makefile > +++ b/tracecmd/Makefile > @@ -37,6 +37,7 @@ TRACE_CMD_OBJS += trace-dump.o > TRACE_CMD_OBJS += trace-clear.o > TRACE_CMD_OBJS += trace-vm.o > TRACE_CMD_OBJS += trace-convert.o > +TRACE_CMD_OBJS += trace-sqldump.o > TRACE_CMD_OBJS += trace-agent.o > TRACE_CMD_OBJS += trace-tsync.o > TRACE_CMD_OBJS += trace-setup-guest.o > diff --git a/tracecmd/include/trace-local.h b/tracecmd/include/trace-local.h > index ae208fb6b593..1172c94fc52a 100644 > --- a/tracecmd/include/trace-local.h > +++ b/tracecmd/include/trace-local.h > @@ -126,6 +126,12 @@ int trace_record_agent(struct tracecmd_msg_handle *msg_handle, > bool use_fifos, struct tracecmd_time_sync *tsync, > unsigned long long trace_id, int rcid, const char *host); > > +int trace_sql_record(struct tracecmd_input *handle, struct tep_record *record); > + > +int trace_sql_init(struct tracecmd_input *handle); > + > +int trace_sql_finish(struct tracecmd_input *handle); > + > struct hook_list; > > void trace_init_profile(struct tracecmd_input *handle, struct hook_list *hooks, > diff --git a/tracecmd/trace-cmd.c b/tracecmd/trace-cmd.c > index 9646921ca268..8de506885948 100644 > --- a/tracecmd/trace-cmd.c > +++ b/tracecmd/trace-cmd.c > @@ -130,6 +130,7 @@ struct command { > */ > struct command commands[] = { > {"report", trace_report}, > + {"sqldump", trace_report}, > {"snapshot", trace_snapshot}, > {"hist", trace_hist}, > {"mem", trace_mem}, > diff --git a/tracecmd/trace-read.c b/tracecmd/trace-read.c > index 52ba818e13b6..9902c7b28212 100644 > --- a/tracecmd/trace-read.c > +++ b/tracecmd/trace-read.c > @@ -73,6 +73,10 @@ struct pid_list { > int free; > } *pid_list; > > +static const char *command; > + > +#define IS_SQLDUMP (strcmp(command, "sqldump") == 0) > + > struct pid_list *comm_list; > > static unsigned int page_size; > @@ -1152,6 +1156,27 @@ static int process_record(struct tracecmd_input *handle, struct tep_record *reco > return 0; > } > > +static int process_sql_record(struct tracecmd_input *handle, struct tep_record *record, > + int cpu, void *data) > +{ > + struct handle_list *handles = tracecmd_get_private(handle); > + unsigned long long *last_timestamp = data; > + > + if (skip_record(handles, record, cpu)) > + return 0; > + > + if (tscheck && *last_timestamp > record->ts) { > + errno = 0; > + warning("WARNING: Record on cpu %d went backwards: %lld to %lld delta: -%lld\n", > + cpu, *last_timestamp, record->ts, *last_timestamp - record->ts); > + } > + *last_timestamp = record->ts; > + > + trace_sql_record(handle, record); > + > + return 0; > +} > + > enum output_type { > OUTPUT_NORMAL, > OUTPUT_STAT_ONLY, > @@ -1166,6 +1191,7 @@ static void read_data_info(struct list_head *handle_list, enum output_type otype > struct handle_list *handles; > struct tracecmd_input **handle_array; > unsigned long long last_timestamp = 0; > + bool sqldump = IS_SQLDUMP; > int nr_handles = 0; > int first = 1; > int ret; > @@ -1196,7 +1222,8 @@ static void read_data_info(struct list_head *handle_list, enum output_type otype > first = 0; > } > print_handle_file(handles); > - printf("cpus=%d\n", cpus); > + if (!sqldump) > + printf("cpus=%d\n", cpus); > > /* Latency trace is just all ASCII */ > if (ret > 0) { > @@ -1222,13 +1249,15 @@ static void read_data_info(struct list_head *handle_list, enum output_type otype > continue; > } > > - init_wakeup(handles->handle); > - if (last_hook) > - last_hook->next = tracecmd_hooks(handles->handle); > - else > - hooks = tracecmd_hooks(handles->handle); > - if (profile) > - trace_init_profile(handles->handle, hooks, global); > + if (!sqldump) { > + init_wakeup(handles->handle); > + if (last_hook) > + last_hook->next = tracecmd_hooks(handles->handle); > + else > + hooks = tracecmd_hooks(handles->handle); > + if (profile) > + trace_init_profile(handles->handle, hooks, global); > + } > > /* If this file has buffer instances, get the handles for them */ > instances = tracecmd_buffer_instances(handles->handle); > @@ -1263,10 +1292,6 @@ static void read_data_info(struct list_head *handle_list, enum output_type otype > } > } > } > - > - if (otype != OUTPUT_NORMAL) > - return; > - > if (align_ts) { > list_for_each_entry(handles, handle_list, list) { > tracecmd_add_ts_offset(handles->handle, -first_ts); > @@ -1285,8 +1310,25 @@ static void read_data_info(struct list_head *handle_list, enum output_type otype > > map_vcpus(handle_array, nr_handles); > > - tracecmd_iterate_events_multi(handle_array, nr_handles, > - process_record, &last_timestamp); > + if (sqldump) { > + struct tracecmd_input *handle; > + int i; > + > + for (i = 0; i < nr_handles; i++) { > + handle = handle_array[i]; > + > + trace_sql_init(handle); > + > + tracecmd_iterate_events(handle, NULL, 0,process_sql_record, > + &last_timestamp); > + > + trace_sql_finish(handle); > + } > + } else { > + > + tracecmd_iterate_events_multi(handle_array, nr_handles, > + process_record, &last_timestamp); > + } > > free(handle_array); > > @@ -1559,9 +1601,12 @@ void trace_report (int argc, char **argv) > if (argc < 2) > usage(argv); > > - if (strcmp(argv[1], "report") != 0) > + if ((strcmp(argv[1], "report") != 0) && > + (strcmp(argv[1], "sqldump") != 0)) > usage(argv); > > + command = argv[1]; > + > signal(SIGINT, sig_end); > > trace_set_loglevel(TEP_LOG_ERROR); > @@ -1743,9 +1788,13 @@ void trace_report (int argc, char **argv) > tracecmd_set_debug(true); > break; > case OPT_profile: > + if (IS_SQLDUMP) > + usage(argv); > profile = 1; > break; > case OPT_uname: > + if (IS_SQLDUMP) > + usage(argv); > show_uname = 1; > break; > case OPT_version: > @@ -1965,6 +2014,10 @@ void trace_report (int argc, char **argv) > /* and version overrides uname! */ > if (show_version) > otype = OUTPUT_VERSION_ONLY; > + > + if (IS_SQLDUMP && otype != OUTPUT_NORMAL) > + usage(argv); > + > read_data_info(&handle_list, otype, global, align_ts); > > list_for_each_entry(handles, &handle_list, list) { > diff --git a/tracecmd/trace-sqldump.c b/tracecmd/trace-sqldump.c > new file mode 100644 > index 000000000000..b7ce99d28642 > --- /dev/null > +++ b/tracecmd/trace-sqldump.c > @@ -0,0 +1,268 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (C) 2020 VMware Inc, Steven Rostedt > + */ > + > +#include <stdio.h> > +#include <stdlib.h> > +#include <unistd.h> > +#include <sys/types.h> > + > +#include "trace-cmd.h" > +#include "trace-local.h" > + > +extern void breakpoint(void); > + > +struct event_table { > + struct tep_event *event; > + struct tep_format_field **event_fields; > + int *event_field_len; > + size_t cnt; > + FILE *fp; > +}; > + > +static struct tep_format_field **event_common_fields; > +static int nr_event_common_fields; > + > +static struct event_table *event_table; > +static int event_table_size; > + > +int trace_sql_init(struct tracecmd_input *handle) > +{ > + struct tep_handle *tep; > + struct tep_event **event_list; > + struct tep_event *event; > + struct event_table *et; > + unsigned int max_id = 0; > + int i, f; > + > + tep = tracecmd_get_tep(handle); > + if (!tep) > + return -1; > + > + event_list = tep_list_events(tep, TEP_EVENT_SORT_ID); > + if (!event_list) > + return -1; > + > + for (i = 0; event_list[i]; i++) { > + event = event_list[i]; > + > + if (event->id > max_id) > + max_id = event->id; > + } > + > + event_table = calloc(max_id + 1, sizeof(*event_table)); > + event_table_size = max_id + 1; > + > + for (i = 0; event_list[i]; i++) { > + int e; > + > + event = event_list[i]; > + > + if (event->id == 302) > + breakpoint(); > + > + et = &event_table[event->id]; > + et->event = event; > + > + if (!event_common_fields) { > + event_common_fields = tep_event_common_fields(event); > + if (!event_common_fields) > + goto fail; > + for (f = 0; event_common_fields[f]; f++) > + ; > + nr_event_common_fields = f + 1; > + } > + > + et->event_fields = tep_event_fields(event); > + if (!et->event_fields) > + goto fail; > + > + for (e = 0; et->event_fields[e]; e++) > + ; > + et->event_field_len = calloc(e, sizeof(*et->event_field_len)); > + if (!et->event_field_len) > + goto fail; > + > + et->fp = tmpfile(); > + if (!et->fp) > + goto fail; > + } > + return 0; > + fail: > + die("done!\n"); > + return -1; > +} > + > +static void write_string(FILE *fp, const char *str, int len) > +{ > + if (!len) > + len = strlen(str); > + > + fputc('\'', fp); > + fwrite(str, len, 1, fp); > + fputc('\'', fp); > +} > + > +static void write_data(FILE *fp, struct tep_format_field *field, > + struct tep_record *record, int *elen) > +{ > + struct tep_handle *tep = field->event->tep; > + unsigned int offset, len; > + unsigned long long val; > + char *data = record->data; > + char buffer[64]; > + > + if (field->flags & TEP_FIELD_IS_ARRAY) { > + offset = field->offset; > + len = field->size; > + > + if (field->flags & TEP_FIELD_IS_DYNAMIC) { > + val = tep_read_number(tep, data + offset, len); > + offset = val; > + len = offset >> 16; > + offset &= 0xffff; > + } > + if (field->flags & TEP_FIELD_IS_STRING) { > + int l = strlen(data + offset); > + > + if (l < len) > + len = l; > + write_string(fp, data + offset, len); > + } else { > + write_string(fp, "ARRAY", 0); > + len = 5; > + } > + if (elen && (*elen) < len) > + *elen = len; > + return; > + } > + val = tep_read_number(tep, data + field->offset, > + field->size); > + sprintf(buffer, "%lld", val); > + fwrite(buffer, strlen(buffer), 1, fp); > + > +} > + > +int trace_sql_record(struct tracecmd_input *handle, struct tep_record *record) > +{ > + struct tep_handle *tep = tracecmd_get_tep(handle); > + struct tep_event *event = tep_find_event_by_record(tep, record); > + struct event_table *et = &event_table[event->id]; > + char buffer[64]; > + int i; > + > + if (event->id > event_table_size || !et->event) > + return -1; > + > + if (event->id == 302) > + breakpoint(); > + > + if (et->cnt++) > + fwrite(",(", 2, 1, et->fp); > + else > + fwrite("(", 1, 1, et->fp); > + > + i = sprintf(buffer, "%lld", record->ts); > + fwrite(buffer, i, 1, et->fp); > + > + for (i = 0; event_common_fields[i]; i++) { > + fwrite(",", 1, 1, et->fp); > + write_data(et->fp, event_common_fields[i], record, NULL); > + } > + > + for (i = 0; et->event_fields[i]; i++) { > + fwrite(",", 1, 1, et->fp); > + write_data(et->fp, et->event_fields[i], record, > + &et->event_field_len[i]); > + } > + > + fwrite(")", 1, 1, et->fp); > + > + return 0; > +} > + > +static void write_header(struct tep_format_field *field, int flen) > +{ > + > + printf("`%s` ", field->name); > + > + if (field->flags & TEP_FIELD_IS_ARRAY) { > + if (field->flags & TEP_FIELD_IS_STRING) { > + if (field->flags & TEP_FIELD_IS_DYNAMIC) { > + if (flen) > + printf("VARCHAR(%d)", flen); > + else > + printf("VARCHAR(64)"); > + } else { > + printf("CHAR(%d)", field->size); > + } > + } else { > + printf("CHAR(5)"); > + } > + } else { > + printf("BIGINT"); > + } > + > + printf(" NOT NULL"); > +} > + > +static void print_sql_header(struct event_table *et) > +{ > + const char *name = et->event->name; > + int i; > + > + printf("\n---\n--- Table structure for table `%s`\n---\n\n", name); > + printf("DROP TABLE IF EXISTS `%s`;\n", name); > + > + printf("CREATE TABLE `%s` (\n", name); > + > + printf(" `common_timestamp` BIGINT NOT NULL"); > + > + for (i = 0; event_common_fields[i]; i++) { > + printf(",\n "); > + write_header(event_common_fields[i], 0); > + } > + > + for (i = 0; et->event_fields[i]; i++) { > + printf(",\n "); > + write_header(et->event_fields[i], et->event_field_len[i]); > + } > + > + printf("\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"); > + printf("\n---\n--- Dumping data for table `%s`\n---\n\n", name); > + printf("LOCK TABLES `%s` WRITE;\n", name); > + printf("INSERT INTO `%s` VALUES ", name); > + > + fflush(stdout); > + fflush(et->fp); > +} > + > +int trace_sql_finish(struct tracecmd_input *handle) > +{ > + struct event_table *et; > + char buffer[BUFSIZ]; > + int i, r; > + int fd; > + > + for (i = 0; i < event_table_size; i++) { > + et = &event_table[i]; > + if (!et->cnt) > + continue; > + > + print_sql_header(et); > + > + fd = fileno(et->fp); > + lseek(fd, 0, SEEK_SET); > + do { > + r = read(fd, buffer, BUFSIZ); > + if (r > 0) > + write(1, buffer, r); > + } while (r > 0); > + fclose(et->fp); > + printf(";\n"); > + printf("UNLOCK TABLES;\n"); > + } > + > + return 0; > +} > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: CSV output 2023-03-13 17:40 ` Julia Lawall @ 2023-03-13 17:53 ` Steven Rostedt 2023-03-13 17:59 ` Julia Lawall 0 siblings, 1 reply; 8+ messages in thread From: Steven Rostedt @ 2023-03-13 17:53 UTC (permalink / raw) To: Julia Lawall; +Cc: linux-trace-users On Mon, 13 Mar 2023 18:40:16 +0100 (CET) Julia Lawall <julia.lawall@inria.fr> wrote: > Thanks for the patch. But actually, I was hoping for something like this: > > cpus=96 > <...>-20420,074,3057.962369,sched_process_exec,/tmp/tmp2abf06.sh,20420,20420 > <...>-20420,074,3057.963487,sched_switch,tmp2abf06.sh,20420,120,D,swapper/74,0,120 > <idle>-0,034,3057.963602,sched_waking,kworker/u192,6,500,120,075 > <idle>-0,075,3057.963632,sched_wakeup,kworker/u192,6,500,120,075 > <idle>-0,075,3057.963637,sched_switch,swapper/75,0,120,R,kworker/u192,6,500,120 > kworker/u192,6-500,075,3057.963656,sched_waking,tmp2abf06.sh,20420,120,074 > kworker/u192,6-500,075,3057.963665,sched_switch,kworker/u192,6,500,120,W,swapper/75,0,120 > <idle>-0,074,3057.963686,sched_wakeup,tmp2abf06.sh,20420,120,074 > <idle>-0,074,3057.963691,sched_switch,swapper/74,0,120,R,tmp2abf06.sh,20420,120 > > It still remains human readable (more or less, with practice), but there > are not a lot of spaces that a parser has to get rid of. The separator > character would have to be something that can't occur in a command name. Should be rather trivial to implement. Better yet, I'm hoping to get some time to finish looking at the python updates that were sent to me, and where it could be possible to just allow you to override the output with a python script. -- Steve ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: CSV output 2023-03-13 17:53 ` Steven Rostedt @ 2023-03-13 17:59 ` Julia Lawall 2023-03-13 18:24 ` Steven Rostedt 0 siblings, 1 reply; 8+ messages in thread From: Julia Lawall @ 2023-03-13 17:59 UTC (permalink / raw) To: Steven Rostedt; +Cc: linux-trace-users On Mon, 13 Mar 2023, Steven Rostedt wrote: > On Mon, 13 Mar 2023 18:40:16 +0100 (CET) > Julia Lawall <julia.lawall@inria.fr> wrote: > > > Thanks for the patch. But actually, I was hoping for something like this: > > > > cpus=96 > > <...>-20420,074,3057.962369,sched_process_exec,/tmp/tmp2abf06.sh,20420,20420 > > <...>-20420,074,3057.963487,sched_switch,tmp2abf06.sh,20420,120,D,swapper/74,0,120 > > <idle>-0,034,3057.963602,sched_waking,kworker/u192,6,500,120,075 > > <idle>-0,075,3057.963632,sched_wakeup,kworker/u192,6,500,120,075 > > <idle>-0,075,3057.963637,sched_switch,swapper/75,0,120,R,kworker/u192,6,500,120 > > kworker/u192,6-500,075,3057.963656,sched_waking,tmp2abf06.sh,20420,120,074 > > kworker/u192,6-500,075,3057.963665,sched_switch,kworker/u192,6,500,120,W,swapper/75,0,120 > > <idle>-0,074,3057.963686,sched_wakeup,tmp2abf06.sh,20420,120,074 > > <idle>-0,074,3057.963691,sched_switch,swapper/74,0,120,R,tmp2abf06.sh,20420,120 > > > > It still remains human readable (more or less, with practice), but there > > are not a lot of spaces that a parser has to get rid of. The separator > > character would have to be something that can't occur in a command name. > > Should be rather trivial to implement. > > Better yet, I'm hoping to get some time to finish looking at the python > updates that were sent to me, and where it could be possible to just allow > you to override the output with a python script. OK, no hurry. I looked into the plugins, but they seem to control only part of the output and it seems that one would be needed for every type of event. I could try writing python, if there is an example. thanks, julia ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: CSV output 2023-03-13 17:59 ` Julia Lawall @ 2023-03-13 18:24 ` Steven Rostedt 2023-03-15 19:39 ` Alexander Aring 0 siblings, 1 reply; 8+ messages in thread From: Steven Rostedt @ 2023-03-13 18:24 UTC (permalink / raw) To: Julia Lawall; +Cc: linux-trace-users On Mon, 13 Mar 2023 18:59:50 +0100 (CET) Julia Lawall <julia.lawall@inria.fr> wrote: > > Better yet, I'm hoping to get some time to finish looking at the python > > updates that were sent to me, and where it could be possible to just allow > > you to override the output with a python script. > > OK, no hurry. I looked into the plugins, but they seem to control only > part of the output and it seems that one would be needed for every type of > event. I could try writing python, if there is an example. The python plugins are currently broken, and we started adding more features to the plugins to control the output a bit more. -- Steve ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: CSV output 2023-03-13 18:24 ` Steven Rostedt @ 2023-03-15 19:39 ` Alexander Aring 2023-03-15 20:24 ` Julia Lawall 0 siblings, 1 reply; 8+ messages in thread From: Alexander Aring @ 2023-03-15 19:39 UTC (permalink / raw) To: Steven Rostedt; +Cc: Julia Lawall, linux-trace-users Hi, On Mon, Mar 13, 2023 at 2:26 PM Steven Rostedt <rostedt@goodmis.org> wrote: > > On Mon, 13 Mar 2023 18:59:50 +0100 (CET) > Julia Lawall <julia.lawall@inria.fr> wrote: > > > > Better yet, I'm hoping to get some time to finish looking at the python > > > updates that were sent to me, and where it could be possible to just allow > > > you to override the output with a python script. > > > > OK, no hurry. I looked into the plugins, but they seem to control only > > part of the output and it seems that one would be needed for every type of > > event. I could try writing python, if there is an example. > > The python plugins are currently broken, and we started adding more > features to the plugins to control the output a bit more. what about the python bindings (under trace-cmd/python/) to parse trace files and using the python csv module? I guess the python bindings are something different than the python plugins and they are still working? - Alex ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: CSV output 2023-03-15 19:39 ` Alexander Aring @ 2023-03-15 20:24 ` Julia Lawall 0 siblings, 0 replies; 8+ messages in thread From: Julia Lawall @ 2023-03-15 20:24 UTC (permalink / raw) To: Alexander Aring; +Cc: Steven Rostedt, linux-trace-users [-- Attachment #1: Type: text/plain, Size: 1222 bytes --] On Wed, 15 Mar 2023, Alexander Aring wrote: > Hi, > > On Mon, Mar 13, 2023 at 2:26 PM Steven Rostedt <rostedt@goodmis.org> wrote: > > > > On Mon, 13 Mar 2023 18:59:50 +0100 (CET) > > Julia Lawall <julia.lawall@inria.fr> wrote: > > > > > > Better yet, I'm hoping to get some time to finish looking at the python > > > > updates that were sent to me, and where it could be possible to just allow > > > > you to override the output with a python script. > > > > > > OK, no hurry. I looked into the plugins, but they seem to control only > > > part of the output and it seems that one would be needed for every type of > > > event. I could try writing python, if there is an example. > > > > The python plugins are currently broken, and we started adding more > > features to the plugins to control the output a bit more. > > what about the python bindings (under trace-cmd/python/) to parse > trace files and using the python csv module? I guess the python What do you mean by parse? My only goal is to reduce running time, so parsing the existing output to produce a csv file won't be a benefit. thanks, julia > bindings are something different than the python plugins and they are > still working? > > - Alex > > ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2023-03-15 20:24 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2023-03-12 7:07 CSV output Julia Lawall 2023-03-13 16:15 ` Steven Rostedt 2023-03-13 17:40 ` Julia Lawall 2023-03-13 17:53 ` Steven Rostedt 2023-03-13 17:59 ` Julia Lawall 2023-03-13 18:24 ` Steven Rostedt 2023-03-15 19:39 ` Alexander Aring 2023-03-15 20:24 ` Julia Lawall
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox