diff mbox series

[v5,36/40] trace-cmd library: Refactor the logic for writing CPU trace data

Message ID 20210610113426.257931-37-tz.stoyanov@gmail.com (mailing list archive)
State Superseded
Headers show
Series Add trace file compression | expand

Commit Message

Tzvetomir Stoyanov (VMware) June 10, 2021, 11:34 a.m. UTC
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(-)
diff mbox series

Patch

diff --git a/lib/trace-cmd/include/trace-cmd-local.h b/lib/trace-cmd/include/trace-cmd-local.h
index 628af16d..e8c7968f 100644
--- a/lib/trace-cmd/include/trace-cmd-local.h
+++ b/lib/trace-cmd/include/trace-cmd-local.h
@@ -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 */
diff --git a/lib/trace-cmd/trace-output.c b/lib/trace-cmd/trace-output.c
index cbe641fd..a3ccfba5 100644
--- a/lib/trace-cmd/trace-output.c
+++ b/lib/trace-cmd/trace-output.c
@@ -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)
 {