@@ -53,10 +53,23 @@ int in_uncompress_block(struct tracecmd_input *handle);
void out_set_file_state(struct tracecmd_output *handle, int new_state);
void out_save_options_offset(struct tracecmd_output *handle);
+unsigned long long out_copy_fd_compress(struct tracecmd_output *handle,
+ int fd, unsigned long long max,
+ unsigned long long *write_size);
+
int write_buffers_description_v7(struct tracecmd_output *handle);
int write_buffers_description_v6(struct tracecmd_output *handle);
long long do_write_check(struct tracecmd_output *handle, const void *data, long long size);
+struct cpu_data_source {
+ int fd;
+ int size;
+ off64_t offset;
+};
+
+int out_write_cpu_data(struct tracecmd_output *handle, int cpus,
+ struct cpu_data_source *data);
+
#endif /* _TRACE_CMD_LOCAL_H */
@@ -286,18 +286,26 @@ static unsigned long get_size(const char *file)
return size;
}
-static tsize_t copy_file_fd(struct tracecmd_output *handle, int fd)
+static tsize_t copy_file_fd(struct tracecmd_output *handle, int fd, unsigned long long max)
{
+ tsize_t rsize = 0;
tsize_t size = 0;
char buf[BUFSIZ];
stsize_t r;
do {
- r = read(fd, buf, BUFSIZ);
+ if (max > 0 && (max - size) < BUFSIZ)
+ rsize = (max - size);
+ else
+ rsize = BUFSIZ;
+
+ r = read(fd, buf, rsize);
if (r > 0) {
size += r;
if (do_write_check(handle, buf, r))
return 0;
+ if (max > 0 && size >= max)
+ break;
}
} while (r > 0);
@@ -315,47 +323,61 @@ static tsize_t copy_file(struct tracecmd_output *handle,
tracecmd_warning("Can't read '%s'", file);
return 0;
}
- size = copy_file_fd(handle, fd);
+ size = copy_file_fd(handle, fd, 0);
close(fd);
return size;
}
#define COMPRESS_CHUNK_SIZE (1*1024*1024)
-static tsize_t copy_file_compress(struct tracecmd_output *handle,
- const char *file, unsigned long long *write_size)
+__hidden unsigned long long out_copy_fd_compress(struct tracecmd_output *handle,
+ int fd, unsigned long long max,
+ unsigned long long *write_size)
{
unsigned long long rsize = 0;
unsigned long long wsize = 0;
- tsize_t size;
+ unsigned long long size;
int ret;
- int fd;
-
- fd = open(file, O_RDONLY);
- if (fd < 0) {
- tracecmd_warning("Can't read '%s'", file);
- return 0;
- }
if (handle->file_version >= 7) {
+ rsize = max;
ret = tracecmd_compress_copy_from(handle->compress, fd,
COMPRESS_CHUNK_SIZE, &rsize, &wsize);
- if (ret < 0) {
- tracecmd_warning("Can't compress '%s'", file);
- close(fd);
+ if (ret < 0)
return 0;
- }
+
size = rsize;
- *write_size = wsize;
+ if (write_size)
+ *write_size = wsize;
} else {
- size = copy_file_fd(handle, fd);
- *write_size = size;
+ size = copy_file_fd(handle, fd, max);
+ if (write_size)
+ *write_size = size;
}
- close(fd);
return size;
}
+static tsize_t copy_file_compress(struct tracecmd_output *handle,
+ const char *file, unsigned long long *write_size)
+{
+ int ret;
+ int fd;
+
+ fd = open(file, O_RDONLY);
+ if (fd < 0) {
+ tracecmd_warning("Can't read '%s'", file);
+ return 0;
+ }
+
+ ret = out_copy_fd_compress(handle, fd, 0, write_size);
+ if (!ret)
+ tracecmd_warning("Can't compress '%s'", file);
+
+ close(fd);
+ return ret;
+}
+
/*
* Finds the path to the debugfs/tracing
* Allocates the string and stores it.
@@ -467,7 +489,7 @@ static int read_header_files(struct tracecmd_output *handle)
endian8 = convert_endian_8(handle, size);
if (do_write_check(handle, &endian8, 8))
goto out_close;
- check_size = copy_file_fd(handle, fd);
+ check_size = copy_file_fd(handle, fd, 0);
close(fd);
if (size != check_size) {
tracecmd_warning("wrong size for '%s' size=%lld read=%lld", path, size, check_size);
@@ -493,7 +515,7 @@ static int read_header_files(struct tracecmd_output *handle)
endian8 = convert_endian_8(handle, size);
if (do_write_check(handle, &endian8, 8))
goto out_close;
- check_size = copy_file_fd(handle, fd);
+ check_size = copy_file_fd(handle, fd, 0);
close(fd);
if (size != check_size) {
tracecmd_warning("wrong size for '%s'", path);
@@ -1671,8 +1693,8 @@ struct data_file_write {
off64_t doffset;
};
-int tracecmd_write_cpu_data(struct tracecmd_output *handle,
- int cpus, char * const *cpu_data_files)
+__hidden int out_write_cpu_data(struct tracecmd_output *handle,
+ int cpus, struct cpu_data_source *data)
{
struct data_file_write *data_files = NULL;
off64_t offset;
@@ -1680,8 +1702,6 @@ int tracecmd_write_cpu_data(struct tracecmd_output *handle,
unsigned long long read_size;
unsigned long long write_size;
char *clock = NULL;
- char *file;
- struct stat st;
int ret;
int i;
@@ -1705,14 +1725,7 @@ int tracecmd_write_cpu_data(struct tracecmd_output *handle,
/* Write 0 for trace data offset and size and store offsets of these fields */
for (i = 0; i < cpus; i++) {
- file = cpu_data_files[i];
- ret = stat(file, &st);
- if (ret < 0) {
- tracecmd_warning("can not stat '%s'", file);
- goto out_free;
- }
- data_files[i].file_size = st.st_size;
-
+ data_files[i].file_size = data[i].size;
endian8 = 0;
data_files[i].doffset = lseek64(handle->fd, 0, SEEK_CUR);
if (do_write_check(handle, &endian8, 8))
@@ -1736,13 +1749,19 @@ int tracecmd_write_cpu_data(struct tracecmd_output *handle,
if (!tracecmd_get_quiet(handle))
fprintf(stderr, "CPU%d data recorded at offset=0x%llx\n",
i, (unsigned long long) data_files[i].data_offset);
-
- read_size = copy_file_compress(handle, cpu_data_files[i], &write_size);
- if (read_size != data_files[i].file_size) {
- errno = EINVAL;
- tracecmd_warning("did not match size of %lld to %lld",
- read_size, data_files[i].file_size);
+ offset = lseek64(data[i].fd, data[i].offset, SEEK_SET);
+ if (offset == (off64_t)-1)
goto out_free;
+ if (data[i].size) {
+ read_size = out_copy_fd_compress(handle, data[i].fd, data[i].size, &write_size);
+ if (read_size != data_files[i].file_size) {
+ errno = EINVAL;
+ tracecmd_warning("did not match size of %lld to %lld",
+ read_size, data_files[i].file_size);
+ goto out_free;
+ }
+ } else {
+ write_size = 0;
}
/* Write the real CPU data offset inthe file */
offset = lseek64(handle->fd, data_files[i].doffset, SEEK_SET);
@@ -1775,6 +1794,47 @@ int tracecmd_write_cpu_data(struct tracecmd_output *handle,
return -1;
}
+int tracecmd_write_cpu_data(struct tracecmd_output *handle,
+ int cpus, char * const *cpu_data_files)
+{
+ struct cpu_data_source *data;
+ struct stat st;
+ int ret;
+ int i;
+
+ data = calloc(cpus, sizeof(struct cpu_data_source));
+ if (!data)
+ return -1;
+ for (i = 0; i < cpus; i++)
+ data[i].fd = -1;
+ for (i = 0; i < cpus; i++) {
+ ret = stat(cpu_data_files[i], &st);
+ if (ret < 0) {
+ tracecmd_warning("can not stat '%s'", cpu_data_files[i]);
+ break;
+ }
+ data[i].fd = open(cpu_data_files[i], O_RDONLY);
+ if (data[i].fd < 0) {
+ tracecmd_warning("Can't read '%s'", data[i].fd);
+ break;
+ }
+
+ data[i].size = st.st_size;
+ data[i].offset = 0;
+ }
+
+ if (i < cpus)
+ ret = -1;
+ else
+ ret = out_write_cpu_data(handle, cpus, data);
+ for (i = 0; i < cpus; i++) {
+ if (data[i].fd >= 0)
+ close(data[i].fd);
+ }
+ free(data);
+ return ret;
+}
+
int tracecmd_append_cpu_data(struct tracecmd_output *handle,
int cpus, char * const *cpu_data_files)
{
Refactored the internal library logic for writing trace CPU data in the trace file. The existing logic copies trace data from a temporary file into the trace file. In order to reuse the code, modify it to support copying the trace data not only from temporary file, but from given fd at given offset. These changes will be used in extending the tracecmd_copy API. Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com> --- lib/trace-cmd/include/trace-cmd-local.h | 13 +++ lib/trace-cmd/trace-output.c | 142 +++++++++++++++++------- 2 files changed, 114 insertions(+), 41 deletions(-)