Perf already captures the tracing metadata as a part of data section in perf.data
When trace_dat_fp is set, write trace.dat compatible metadata sections using the perf provided raw buffers. Sections written: - Initial format header (magic, version, endian, long_size, page_size, compression, options_offset placeholder) - Section 16: HEADER INFO (header_page + header_event) - Section 17: FTRACE EVENT FORMATS - Section 18: EVENT FORMATS (per system/event format files) - Section 19: KALLSYMS - Section 21: CMDLINES - Section 15: STRINGS (written last after all sections) Signed-off-by: Tanushree Shah <[email protected]> --- tools/perf/util/trace-event-read.c | 259 ++++++++++++++++++++++++++++- 1 file changed, 252 insertions(+), 7 deletions(-) diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index ecbbb93f0185..815577703c2e 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c @@ -19,6 +19,7 @@ #include "trace-event.h" #include "debug.h" #include "util.h" +#include "trace-dat.h" static int input_fd; @@ -145,10 +146,9 @@ static char *read_string(void) static int read_proc_kallsyms(struct tep_handle *pevent) { unsigned int size; + char *buf; size = read4(pevent); - if (!size) - return 0; /* * Just skip it, now that we configure libtraceevent to use the * tools/perf/ symbol resolver. @@ -160,11 +160,56 @@ static int read_proc_kallsyms(struct tep_handle *pevent) * payload", so that older tools can continue reading it and interpret * it as "no kallsyms payload is present". */ - lseek(input_fd, size, SEEK_CUR); + /* Write kallsyms section with empty payload if no data */ + if (!size) { + if (trace_dat_fp) { + unsigned short section_id = TRACE_DAT_SECTION_KALLSYMS; + unsigned short flags = 0; + unsigned long long section_size = sizeof(unsigned int); + unsigned int kallsyms_data = 0; + unsigned int string_id = STRID_KALLSYMS; + + trace_dat_kallsyms_offset = ftell(trace_dat_fp); + if (!fwrite(§ion_id, sizeof(unsigned short), 1, trace_dat_fp) || + !fwrite(&flags, sizeof(unsigned short), 1, trace_dat_fp) || + !fwrite(&string_id, sizeof(unsigned int), 1, trace_dat_fp) || + !fwrite(§ion_size, sizeof(unsigned long long), 1, trace_dat_fp) || + !fwrite(&kallsyms_data, sizeof(unsigned int), 1, trace_dat_fp)) + return -EIO; + } + return 0; + } + buf = malloc(size); + if (buf == NULL) + return -1; + if (read(input_fd, buf, size) < 0) { + free(buf); + return -1; + } trace_data_size += size; + /* Write kallsyms section with data */ + if (trace_dat_fp) { + unsigned short section_id = TRACE_DAT_SECTION_KALLSYMS; + unsigned int string_id = STRID_KALLSYMS; + unsigned long long section_size = sizeof(unsigned int) + size; + unsigned short flags = 0; + + trace_dat_kallsyms_offset = ftell(trace_dat_fp); + if (!fwrite(§ion_id, sizeof(unsigned short), 1, trace_dat_fp) || + !fwrite(&flags, sizeof(unsigned short), 1, trace_dat_fp) || + !fwrite(&string_id, sizeof(unsigned int), 1, trace_dat_fp) || + !fwrite(§ion_size, sizeof(unsigned long long), 1, trace_dat_fp) || + !fwrite(&size, sizeof(unsigned int), 1, trace_dat_fp) || + !fwrite(buf, 1, size, trace_dat_fp)) { + free(buf); + return -EIO; + } + } + free(buf); return 0; } + static int read_ftrace_printk(struct tep_handle *pevent) { unsigned int size; @@ -195,6 +240,13 @@ static int read_ftrace_printk(struct tep_handle *pevent) static int read_header_files(struct tep_handle *pevent) { unsigned long long size; + unsigned long long header_page_size; + unsigned long long header_event_size; + char *header_event; + unsigned short section_id; + unsigned short flags; + unsigned int string_id; + unsigned long long section_size; char *header_page; char buf[BUFSIZ]; int ret = 0; @@ -209,6 +261,7 @@ static int read_header_files(struct tep_handle *pevent) size = read8(pevent); + header_page_size = size; header_page = malloc(size); if (header_page == NULL) return -1; @@ -227,19 +280,59 @@ static int read_header_files(struct tep_handle *pevent) */ tep_set_long_size(pevent, tep_get_header_page_size(pevent)); } - free(header_page); - if (do_read(buf, 13) < 0) + if (do_read(buf, 13) < 0) { + free(header_page); return -1; + } if (memcmp(buf, "header_event", 13) != 0) { pr_debug("did not read header event"); + free(header_page); return -1; } size = read8(pevent); - skip(size); + if (trace_dat_fp) { + header_event_size = size; + header_event = malloc(size); + if (header_event == NULL) { + free(header_page); + return -1; + } + if (do_read(header_event, size) < 0) { + free(header_page); + free(header_event); + return -1; + } + /* Write header_page and header_event to trace.dat */ + section_id = TRACE_DAT_SECTION_HEADER; + flags = 0; + string_id = STRID_HEADERS; + section_size = 12 + 8 + header_page_size + 13 + 8 + + header_event_size; + + trace_dat_header_info_offset = ftell(trace_dat_fp); + if (!fwrite(§ion_id, sizeof(unsigned short), 1, trace_dat_fp) || + !fwrite(&flags, sizeof(unsigned short), 1, trace_dat_fp) || + !fwrite(&string_id, sizeof(unsigned int), 1, trace_dat_fp) || + !fwrite(§ion_size, sizeof(unsigned long long), 1, trace_dat_fp) || + !fwrite("header_page\0", 1, 12, trace_dat_fp) || + !fwrite(&header_page_size, sizeof(unsigned long long), 1, trace_dat_fp) || + !fwrite(header_page, 1, header_page_size, trace_dat_fp) || + !fwrite("header_event\0", 1, 13, trace_dat_fp) || + !fwrite(&header_event_size, sizeof(unsigned long long), 1, trace_dat_fp) || + !fwrite(header_event, 1, header_event_size, trace_dat_fp)) { + free(header_page); + free(header_event); + return -EIO; + } + free(header_event); + } else { + skip(size); + } + free(header_page); return ret; } @@ -259,6 +352,13 @@ static int read_ftrace_file(struct tep_handle *pevent, unsigned long long size) pr_debug("error reading ftrace file.\n"); goto out; } + if (trace_dat_fp) { + if (!fwrite(&size, sizeof(unsigned long long), 1, trace_dat_fp) || + !fwrite(buf, 1, size, trace_dat_fp)) { + free(buf); + return -EIO; + } + } ret = parse_ftrace_file(pevent, buf, size); if (ret < 0) @@ -283,6 +383,13 @@ static int read_event_file(struct tep_handle *pevent, char *sys, ret = do_read(buf, size); if (ret < 0) goto out; + if (trace_dat_fp) { + if (!fwrite(&size, sizeof(unsigned long long), 1, trace_dat_fp) || + !fwrite(buf, 1, size, trace_dat_fp)) { + free(buf); + return -EIO; + } + } ret = parse_event_file(pevent, buf, size, sys); if (ret < 0) @@ -298,8 +405,31 @@ static int read_ftrace_files(struct tep_handle *pevent) int count; int i; int ret; + long section_size_pos = 0; + long count_pos = 0; + unsigned long long section_size = 0; + long end_pos; count = read4(pevent); + /* Write ftrace formats section to trace.dat output file */ + if (trace_dat_fp) { + unsigned short section_id = TRACE_DAT_SECTION_FTRACE; + unsigned short flags = 0; + unsigned int string_id = STRID_FTRACE_FORMATS; + + trace_dat_ftrace_format_offset = ftell(trace_dat_fp); + + if (!fwrite(§ion_id, sizeof(unsigned short), 1, trace_dat_fp) || + !fwrite(&flags, sizeof(unsigned short), 1, trace_dat_fp) || + !fwrite(&string_id, sizeof(unsigned int), 1, trace_dat_fp)) + return -EIO; + section_size_pos = ftell(trace_dat_fp); + if (!fwrite(§ion_size, sizeof(unsigned long long), 1, trace_dat_fp)) + return -EIO; + count_pos = ftell(trace_dat_fp); + if (!fwrite(&count, sizeof(unsigned int), 1, trace_dat_fp)) + return -EIO; + } for (i = 0; i < count; i++) { size = read8(pevent); @@ -307,6 +437,16 @@ static int read_ftrace_files(struct tep_handle *pevent) if (ret) return ret; } + /* Fill in section size after writing all ftrace files */ + if (trace_dat_fp) { + end_pos = ftell(trace_dat_fp); + section_size = end_pos - count_pos; + fseek(trace_dat_fp, section_size_pos, SEEK_SET); + if (!fwrite(§ion_size, sizeof(unsigned long long), 1, trace_dat_fp)) + return -EIO; + fseek(trace_dat_fp, end_pos, SEEK_SET); + } + return 0; } @@ -318,8 +458,30 @@ static int read_event_files(struct tep_handle *pevent) int count; int i,x; int ret; + long section_size_pos = 0; + long sys_count_pos = 0; + unsigned long long section_size = 0; + long end_pos; systems = read4(pevent); + /* Write event formats section to trace.dat output file */ + if (trace_dat_fp) { + unsigned short section_id = TRACE_DAT_SECTION_EVENTS; + unsigned short flags = 0; + unsigned int string_id = STRID_EVENT_FORMATS; + + trace_dat_events_format_offset = ftell(trace_dat_fp); + if (!fwrite(§ion_id, sizeof(unsigned short), 1, trace_dat_fp) || + !fwrite(&flags, sizeof(unsigned short), 1, trace_dat_fp) || + !fwrite(&string_id, sizeof(unsigned int), 1, trace_dat_fp)) + return -EIO; + section_size_pos = ftell(trace_dat_fp); + if (!fwrite(§ion_size, sizeof(unsigned long long), 1, trace_dat_fp)) + return -EIO; + sys_count_pos = ftell(trace_dat_fp); + if (!fwrite(&systems, sizeof(unsigned int), 1, trace_dat_fp)) + return -EIO; + } for (i = 0; i < systems; i++) { sys = read_string(); @@ -327,6 +489,11 @@ static int read_event_files(struct tep_handle *pevent) return -1; count = read4(pevent); + if (trace_dat_fp) { + if (!fwrite(sys, 1, strlen(sys) + 1, trace_dat_fp) || + !fwrite(&count, sizeof(unsigned int), 1, trace_dat_fp)) + return -EIO; + } for (x=0; x < count; x++) { size = read8(pevent); @@ -338,6 +505,16 @@ static int read_event_files(struct tep_handle *pevent) } free(sys); } + /* Fill in section size after writing all event files */ + if (trace_dat_fp) { + end_pos = ftell(trace_dat_fp); + section_size = end_pos - sys_count_pos; + fseek(trace_dat_fp, section_size_pos, SEEK_SET); + if (!fwrite(§ion_size, sizeof(unsigned long long), 1, trace_dat_fp)) + return -EIO; + fseek(trace_dat_fp, end_pos, SEEK_SET); + } + return 0; } @@ -349,8 +526,25 @@ static int read_saved_cmdline(struct tep_handle *pevent) /* it can have 0 size */ size = read8(pevent); - if (!size) + /* Write cmdlines section with empty payload if no data */ + if (!size) { + if (trace_dat_fp) { + unsigned short section_id = TRACE_DAT_SECTION_CMDLINE; + unsigned short flags = 0; + unsigned int string_id = STRID_CMDLINES; + unsigned long long section_size = sizeof(unsigned long long); + unsigned long long section_data = 0; + + trace_dat_cmdline_offset = ftell(trace_dat_fp); + if (!fwrite(§ion_id, sizeof(unsigned short), 1, trace_dat_fp) || + !fwrite(&flags, sizeof(unsigned short), 1, trace_dat_fp) || + !fwrite(&string_id, sizeof(unsigned int), 1, trace_dat_fp) || + !fwrite(§ion_size, sizeof(unsigned long long), 1, trace_dat_fp) || + !fwrite(§ion_data, sizeof(unsigned long long), 1, trace_dat_fp)) + return -EIO; + } return 0; + } buf = malloc(size + 1); if (buf == NULL) { @@ -363,6 +557,23 @@ static int read_saved_cmdline(struct tep_handle *pevent) pr_debug("error reading saved cmdlines\n"); goto out; } + /* Write cmdlines section with data */ + if (trace_dat_fp) { + unsigned short section_id = TRACE_DAT_SECTION_CMDLINE; + unsigned short flags = 0; + unsigned int string_id = STRID_CMDLINES; + unsigned long long section_size = sizeof(unsigned long long) + size; + + trace_dat_cmdline_offset = ftell(trace_dat_fp); + if (!fwrite(§ion_id, sizeof(unsigned short), 1, trace_dat_fp) || + !fwrite(&flags, sizeof(unsigned short), 1, trace_dat_fp) || + !fwrite(&string_id, sizeof(unsigned int), 1, trace_dat_fp) || + !fwrite(§ion_size, sizeof(unsigned long long), 1, trace_dat_fp) || + !fwrite(&size, sizeof(unsigned long long), 1, trace_dat_fp) || + !fwrite(buf, 1, size, trace_dat_fp)) + return -EIO; + } + buf[ret] = '\0'; parse_saved_cmdline(pevent, buf, size); @@ -387,6 +598,7 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe) int file_page_size; struct tep_handle *pevent = NULL; int err; + char magic_buf[10]; repipe = __repipe; input_fd = fd; @@ -398,12 +610,17 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe) return -1; } + if (trace_dat_fp) + memcpy(magic_buf, buf, 3); + if (do_read(buf, 7) < 0) return -1; if (memcmp(buf, "tracing", 7) != 0) { pr_debug("not a trace file (missing 'tracing' tag)"); return -1; } + if (trace_dat_fp) + memcpy(magic_buf + 3, buf, 7); version = read_string(); if (version == NULL) @@ -440,6 +657,28 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe) tep_set_long_size(pevent, file_long_size); tep_set_page_size(pevent, file_page_size); + /* Write initial file header to trace.dat */ + if (trace_dat_fp) { + unsigned char endian = file_bigendian; + unsigned char long_size = file_long_size; + unsigned int page_size = file_page_size; + unsigned long long placeholder = 0; + char trace_dat_version = TRACE_DAT_VERSION; + + if (!fwrite(magic_buf, 1, 10, trace_dat_fp) || /* magic + "tracing" */ + !fwrite(&trace_dat_version, 1, 2, trace_dat_fp) || + !fwrite(&endian, 1, 1, trace_dat_fp) || + !fwrite(&long_size, 1, 1, trace_dat_fp) || + !fwrite(&page_size, sizeof(unsigned int), 1, trace_dat_fp) || + !fwrite("none", 1, 4, trace_dat_fp) || + !fwrite("\0", 1, 1, trace_dat_fp) || + !fwrite("\0", 1, 1, trace_dat_fp)) + return -EIO; + trace_dat_options_offset = ftell(trace_dat_fp); + if (!fwrite(&placeholder, sizeof(unsigned long long), 1, trace_dat_fp)) + return -EIO; + } + err = read_header_files(pevent); if (err) goto out; @@ -460,6 +699,12 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe) if (err) goto out; } + /* Write strings section to trace.dat output file */ + if (trace_dat_fp) { + err = trace_dat__write_strings_section(); + if (err) + goto out; + } size = trace_data_size; repipe = false; -- 2.53.0
