Compress some methadata of the trace.dat file. If there is compression support, chose file version 7 and compress these parts of the file: - ftrace events format - format of recorded events - information of the mapping of function addresses to the function names - trace_printk() format strings - information of the mapping a PID to a process name A new compression header is added in the file, right after the page size information. Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@xxxxxxxxx> --- lib/trace-cmd/trace-output.c | 190 ++++++++++++++++++++++++++++++----- 1 file changed, 167 insertions(+), 23 deletions(-) diff --git a/lib/trace-cmd/trace-output.c b/lib/trace-cmd/trace-output.c index edff7961..9d603cfe 100644 --- a/lib/trace-cmd/trace-output.c +++ b/lib/trace-cmd/trace-output.c @@ -58,6 +58,13 @@ struct tracecmd_output { bool quiet; unsigned long file_state; unsigned long file_version; + + bool compress; + unsigned int compress_size; + unsigned int commpress_capacity; + char *compress_buffer; + struct tracecmd_compress_proto *compress_proto; + struct list_head options; struct tracecmd_msg_handle *msg_handle; char *trace_clock; @@ -75,9 +82,31 @@ struct list_event_system { char *name; }; +static stsize_t write_compress(struct tracecmd_output *handle, const void *data, tsize_t size) +{ + char *buf; + int extend; + + if (handle->commpress_capacity < handle->compress_size + size) { + extend = (handle->compress_size + size) - handle->commpress_capacity; + extend = extend < BUFSIZ ? BUFSIZ : extend; + buf = realloc(handle->compress_buffer, handle->commpress_capacity + extend); + if (!buf) + return -ENOMEM; + handle->compress_buffer = buf; + handle->commpress_capacity += extend; + } + memcpy(&handle->compress_buffer[handle->compress_size], data, size); + handle->compress_size += size; + return 0; +} + static stsize_t do_write_check(struct tracecmd_output *handle, const void *data, tsize_t size) { + if (handle->compress) + return write_compress(handle, data, size); + if (handle->msg_handle) return tracecmd_msg_data_send(handle->msg_handle, data, size); @@ -109,6 +138,70 @@ static unsigned long long convert_endian_8(struct tracecmd_output *handle, return tep_read_number(handle->pevent, &val, 8); } +static stsize_t write_compress_data(struct tracecmd_output *handle) +{ + unsigned int size; + char *buf; + int endian4; + int ret; + + size = tracecmd_get_compress_size(handle->compress_proto, handle->compress_size); + buf = malloc(size); + if (!buf) + return -ENOMEM; + + ret = tracecmd_compress_data(handle->compress_proto, handle->compress_buffer, + handle->compress_size, buf, &size); + if (ret < 0) + goto out; + /* Write compressed data size */ + endian4 = convert_endian_4(handle, size); + ret = do_write_check(handle, &endian4, 4); + if (ret < 0) + goto out; + /* Write uncompressed data size */ + endian4 = convert_endian_4(handle, handle->compress_size); + ret = do_write_check(handle, &endian4, 4); + if (ret < 0) + goto out; + /* Write uncompressed the data */ + ret = do_write_check(handle, buf, size); +out: + free(buf); + return ret; +} + +static inline void compression_reset(struct tracecmd_output *handle) +{ + if (handle->file_version < 7 || !handle->compress_proto) + return; + free(handle->compress_buffer); + handle->compress_buffer = NULL; + handle->commpress_capacity = 0; + handle->compress_size = 0; +} + +static inline int compression_start(struct tracecmd_output *handle) +{ + if (handle->file_version < 7 || !handle->compress_proto) + return 0; + compression_reset(handle); + handle->compress = true; + return 0; +} + +static inline int compression_end(struct tracecmd_output *handle) +{ + int ret; + + if (handle->file_version < 7 || !handle->compress_proto) + return 0; + handle->compress = false; + ret = write_compress_data(handle); + compression_reset(handle); + return ret; +} + /** * tracecmd_set_quiet - Set if to print output to the screen * @quiet: If non zero, print no output to the screen @@ -659,13 +752,17 @@ static int read_ftrace_files(struct tracecmd_output *handle) } create_event_list_item(handle, &systems, &list); - + compression_start(handle); ret = copy_event_system(handle, systems); + if (!ret) + ret = compression_end(handle); + else + compression_reset(handle); free_list_events(systems); - handle->file_state = TRACECMD_FILE_FTRACE_EVENTS; - + if (!ret) + handle->file_state = TRACECMD_FILE_FTRACE_EVENTS; return ret; } @@ -715,6 +812,7 @@ static int read_event_files(struct tracecmd_output *handle, for (slist = systems; slist; slist = slist->next) count++; + compression_start(handle); ret = -1; endian4 = convert_endian_4(handle, count); if (do_write_check(handle, &endian4, 4)) @@ -730,8 +828,14 @@ static int read_event_files(struct tracecmd_output *handle, ret = copy_event_system(handle, slist); } - handle->file_state = TRACECMD_FILE_ALL_EVENTS; + if (!ret) + ret = compression_end(handle); out_free: + if (!ret) + handle->file_state = TRACECMD_FILE_ALL_EVENTS; + else + compression_reset(handle); + free_list_events(systems); return ret; @@ -793,20 +897,20 @@ static int read_proc_kallsyms(struct tracecmd_output *handle, if (kallsyms) path = kallsyms; - + compression_start(handle); ret = stat(path, &st); if (ret < 0) { /* not found */ size = 0; endian4 = convert_endian_4(handle, size); - if (do_write_check(handle, &endian4, 4)) - return -1; - return 0; + ret = do_write_check(handle, &endian4, 4); + goto out; } size = get_size(path); endian4 = convert_endian_4(handle, size); - if (do_write_check(handle, &endian4, 4)) - return -1; + ret = do_write_check(handle, &endian4, 4); + if (ret) + goto out; set_proc_kptr_restrict(0); check_size = copy_file(handle, path); @@ -814,13 +918,18 @@ static int read_proc_kallsyms(struct tracecmd_output *handle, errno = EINVAL; tracecmd_warning("error in size of file '%s'", path); set_proc_kptr_restrict(1); - return -1; + ret = -1; + goto out; } set_proc_kptr_restrict(1); - handle->file_state = TRACECMD_FILE_KALLSYMS; - - return 0; + ret = compression_end(handle); +out: + if (!ret) + handle->file_state = TRACECMD_FILE_KALLSYMS; + else + compression_reset(handle); + return ret; } static int read_ftrace_printk(struct tracecmd_output *handle) @@ -840,6 +949,7 @@ static int read_ftrace_printk(struct tracecmd_output *handle) if (!path) return -1; + compression_start(handle); ret = stat(path, &st); if (ret < 0) { /* not found */ @@ -861,11 +971,14 @@ static int read_ftrace_printk(struct tracecmd_output *handle) } out: - handle->file_state = TRACECMD_FILE_PRINTK; put_tracing_file(path); + if (compression_end(handle)) + return -1; + handle->file_state = TRACECMD_FILE_PRINTK; return 0; fail: put_tracing_file(path); + compression_reset(handle); return -1; } @@ -911,16 +1024,40 @@ out_free: static int select_file_version(struct tracecmd_output *handle, struct tracecmd_input *ihandle, unsigned long file_version) { - if (ihandle) + if (ihandle) { handle->file_version = tracecmd_get_file_version(ihandle); - else if (file_version > 0) + } else if (file_version > 0) { handle->file_version = file_version; - else - handle->file_version = FILE_VERSION; + } else { + handle->compress_proto = tracecmd_compress_proto_select(); + if (handle->compress_proto) + handle->file_version = 7; + else + handle->file_version = 6; + } return 0; } +static int write_compression_header(struct tracecmd_output *handle) +{ + const char *name = NULL; + const char *ver = NULL; + char *buf; + int ret; + + ret = tracecmd_compress_proto_get_name(handle->compress_proto, &name, &ver); + if (ret < 0 || !name || !ver) + return -1; + ret = asprintf(&buf, "%s %s", name, ver); + if (ret < 0) + return -1; + ret = do_write_check(handle, buf, strlen(buf) + 1); + + free(buf); + return ret; +} + static struct tracecmd_output * create_file_fd(int fd, struct tracecmd_input *ihandle, const char *tracing_dir, @@ -996,7 +1133,8 @@ create_file_fd(int fd, struct tracecmd_input *ihandle, if (do_write_check(handle, &endian4, 4)) goto out_free; handle->file_state = TRACECMD_FILE_INIT; - + if (handle->file_version >= 7 && write_compression_header(handle)) + goto out_free; if (ihandle) return handle; @@ -1329,11 +1467,17 @@ int tracecmd_write_cmdlines(struct tracecmd_output *handle) handle->file_state); return ret; } + compression_start(handle); + ret = save_tracing_file_data(handle, "saved_cmdlines"); - if (ret < 0) + if (ret < 0) { + compression_reset(handle); return ret; - handle->file_state = TRACECMD_FILE_CMD_LINES; - return 0; + } + ret = compression_end(handle); + if (!ret) + handle->file_state = TRACECMD_FILE_CMD_LINES; + return ret; } struct tracecmd_output *tracecmd_create_file_latency(const char *output_file, int cpus, -- 2.30.2