diff mbox series

[02/10] trace-cmd library: Add support for compression algorithms

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

Commit Message

Tzvetomir Stoyanov (VMware) April 22, 2021, 7:38 a.m. UTC
Added infrastructure to trace-cmd library for compression. Introduced
various new APIs to work with this new functionality:
 tracecmd_compress_proto_get()
 tracecmd_compress_protos_get()
 tracecmd_compress_proto_get_name()
 tracecmd_compress_proto_select()
 tracecmd_compress_proto_register()
 tracecmd_compress_data()
 tracecmd_uncompress_data()
 tracecmd_get_compress_size()

The compression algorithms are not part of this patch.

Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com>
---
 lib/trace-cmd/Makefile                        |   1 +
 .../include/private/trace-cmd-private.h       |  22 ++
 lib/trace-cmd/include/trace-cmd-local.h       |   2 +
 lib/trace-cmd/trace-compress.c                | 287 ++++++++++++++++++
 lib/trace-cmd/trace-util.c                    |   3 +
 5 files changed, 315 insertions(+)
 create mode 100644 lib/trace-cmd/trace-compress.c
diff mbox series

Patch

diff --git a/lib/trace-cmd/Makefile b/lib/trace-cmd/Makefile
index 17600318..bab4322d 100644
--- a/lib/trace-cmd/Makefile
+++ b/lib/trace-cmd/Makefile
@@ -25,6 +25,7 @@  ifeq ($(VSOCK_DEFINED), 1)
 OBJS += trace-timesync-ptp.o
 OBJS += trace-timesync-kvm.o
 endif
+OBJS += trace-compress.o
 
 # Additional util objects
 OBJS += trace-blk-hack.o
diff --git a/lib/trace-cmd/include/private/trace-cmd-private.h b/lib/trace-cmd/include/private/trace-cmd-private.h
index 5d35b197..c562fc5d 100644
--- a/lib/trace-cmd/include/private/trace-cmd-private.h
+++ b/lib/trace-cmd/include/private/trace-cmd-private.h
@@ -471,6 +471,28 @@  void tracecmd_tsync_free(struct tracecmd_time_sync *tsync);
 int tracecmd_write_guest_time_shift(struct tracecmd_output *handle,
 				    struct tracecmd_time_sync *tsync);
 
+/* --- Compression --- */
+struct tracecmd_compress_proto;
+struct tracecmd_compress_proto *tracecmd_compress_proto_get(const char *name, const char *version);
+struct tracecmd_compress_proto *tracecmd_compress_proto_select(void);
+int tracecmd_compress_proto_register(const char *name, const char *version, int weight,
+				     int (*compress)(char *in, unsigned int in_bytes,
+						     char *out, unsigned int *out_bytes),
+				     int (*uncompress)(char *in, unsigned int in_bytes,
+						       char *out, unsigned int *out_bytes),
+				     unsigned int (*comress_size)(unsigned int bytes),
+				     bool (*is_supported)(const char *name, const char *version));
+int tracecmd_compress_protos_get(char ***names, char ***versions);
+int tracecmd_compress_proto_get_name(struct tracecmd_compress_proto *proto,
+				     const char **name, const char **version);
+int tracecmd_compress_data(struct tracecmd_compress_proto *proto,
+			   char *in, unsigned int in_bytes,
+			   char *out, unsigned int *out_bytes);
+int tracecmd_uncompress_data(struct tracecmd_compress_proto *proto,
+			     char *in, unsigned int in_bytes,
+			     char *out, unsigned int *out_bytes);
+unsigned int tracecmd_get_compress_size(struct tracecmd_compress_proto *proto, unsigned int bytes);
+
 /* --- Plugin handling --- */
 extern struct tep_plugin_option trace_ftrace_options[];
 
diff --git a/lib/trace-cmd/include/trace-cmd-local.h b/lib/trace-cmd/include/trace-cmd-local.h
index 5578f00d..c8c51ff0 100644
--- a/lib/trace-cmd/include/trace-cmd-local.h
+++ b/lib/trace-cmd/include/trace-cmd-local.h
@@ -30,5 +30,7 @@  void tracecmd_fatal(const char *fmt, ...);
 #endif
 #endif
 
+int tracecmd_compress_init(void);
+void tracecmd_compress_free(void);
 
 #endif /* _TRACE_CMD_LOCAL_H */
diff --git a/lib/trace-cmd/trace-compress.c b/lib/trace-cmd/trace-compress.c
new file mode 100644
index 00000000..c59c8bdb
--- /dev/null
+++ b/lib/trace-cmd/trace-compress.c
@@ -0,0 +1,287 @@ 
+// SPDX-License-Identifier: LGPL-2.1
+/*
+ * Copyright (C) 2021, VMware, Tzvetomir Stoyanov tz.stoyanov@gmail.com>
+ *
+ */
+#include <stdlib.h>
+#include <sys/time.h>
+
+#include "trace-cmd-private.h"
+#include "trace-cmd-local.h"
+
+struct tracecmd_compress_proto {
+	struct tracecmd_compress_proto *next;
+	char *proto_name;
+	char *proto_version;
+	int weight;
+
+	int (*comress_block)(char *in, unsigned int in_bytes,
+			     char *out, unsigned int *out_bytes);
+	int (*uncompress_block)(char *in, unsigned int in_bytes,
+				char *out, unsigned int *out_bytes);
+	unsigned int (*comress_size)(unsigned int bytes);
+	bool (*is_supported)(const char *name, const char *version);
+};
+
+static struct tracecmd_compress_proto *proto_list;
+
+/**
+ * tracecmd_compress_init - initialize the library with available compression algorithms
+ *
+ * Returns 0. If no compression algorithms are available, a warning is printed.
+ */
+int tracecmd_compress_init(void)
+{
+	struct timeval time;
+	int count = 0;
+
+	gettimeofday(&time, NULL);
+	srand((time.tv_sec * 1000) + (time.tv_usec / 1000));
+
+/* toDo: add here initialization of compression protocols */
+
+	if (!count)
+		tracecmd_warning("No compression support available");
+
+	return 0;
+}
+
+/**
+ * tracecmd_compress_proto_get - get handler to compression algorithm from name and version
+ * @name: name of the compression algorithm.
+ * @version: version of the compression algorithm.
+ *
+ * Returns a handler to compression algorithm, or NULL if algorithm with given name and version is
+ * not found.
+ */
+struct tracecmd_compress_proto *tracecmd_compress_proto_get(const char *name, const char *version)
+{
+	struct tracecmd_compress_proto *proto = proto_list;
+
+	if (!name)
+		return NULL;
+
+	while (proto) {
+		if (proto->is_supported && proto->is_supported(name, version))
+			return proto;
+		proto = proto->next;
+	}
+	return NULL;
+}
+
+/**
+ * tracecmd_compress_proto_select - select compression algorithm
+ *
+ * The algorithm with the lowest weight is selected.
+ * Returns a handler to compression algorithm, or NULL if no algorithms are available.
+ */
+struct tracecmd_compress_proto *tracecmd_compress_proto_select(void)
+{
+	struct tracecmd_compress_proto *proto = proto_list;
+	struct tracecmd_compress_proto *selected = NULL;
+
+	while (proto) {
+		if (!selected || selected->weight > proto->weight)
+			selected = proto;
+		proto = proto->next;
+	}
+
+	return selected;
+}
+
+/**
+ * tracecmd_compress_proto_get_name - get name and version of compression algorithm
+ * @proto: handler to compression algorithm.
+ * @name: return, name of the compression algorithm.
+ * @version: return, version of the compression algorithm.
+ *
+ * Returns 0 on success, or -1 in case of an error. If 0 is returned, the name and version of the
+ * algorithm are stored in @name and @version. The returned strings must *not* be freed.
+ */
+int tracecmd_compress_proto_get_name(struct tracecmd_compress_proto *proto,
+				     const char **name, const char **version)
+{
+	if (!proto)
+		return -1;
+	if (name)
+		*name = proto->proto_name;
+	if (version)
+		*version = proto->proto_version;
+	return 0;
+}
+
+/**
+ * tracecmd_compress_proto_register - register a new compression algorithm
+ * @name: name of the compression algorithm.
+ * @version: version of the compression algorithm.
+ * @weight: weight of the compression algorithm, lower is better.
+ * @compress: compression hook, called to compress a memory block.
+ * @uncompress: uncompression hook, called to uncompress a memory block.
+ * @comress_size: hook, called to get the required minimum size of the buffer for compression
+ *		  given number of bytes.
+ * @is_supported: check hook, called to check if compression with given name and version is
+ *		  supported by this plugin.
+ *
+ * Returns 0 on success, or -1 in case of an error. If algorithm with given name and version is
+ * already registered, -1 is returned.
+ */
+int tracecmd_compress_proto_register(const char *name, const char *version, int weight,
+				     int (*compress)(char *in, unsigned int in_bytes,
+						     char *out, unsigned int *out_bytes),
+				     int (*uncompress)(char *in, unsigned int in_bytes,
+						       char *out, unsigned int *out_bytes),
+				     unsigned int (*comress_size)(unsigned int bytes),
+				     bool (*is_supported)(const char *name, const char *version))
+{
+	struct tracecmd_compress_proto *new;
+
+	if (!name || !compress || !uncompress)
+		return -1;
+	if (tracecmd_compress_proto_get(name, version))
+		return -1;
+
+	new = calloc(1, sizeof(*new));
+	if (!new)
+		return -1;
+
+	new->proto_name = strdup(name);
+	if (!new->proto_name)
+		goto error;
+	new->proto_version = strdup(version);
+	if (!new->proto_version)
+		goto error;
+	new->comress_block = compress;
+	new->uncompress_block = uncompress;
+	new->comress_size = comress_size;
+	new->is_supported = is_supported;
+	new->weight = weight;
+	new->next = proto_list;
+	proto_list = new;
+	return 0;
+
+error:
+	free(new->proto_name);
+	free(new->proto_version);
+	free(new);
+	return -1;
+}
+
+/**
+ * tracecmd_compress_free - free the library resources, related to available compression algorithms
+ *
+ */
+void tracecmd_compress_free(void)
+{
+	struct tracecmd_compress_proto *proto = proto_list;
+	struct tracecmd_compress_proto *del;
+
+	while (proto) {
+		del = proto;
+		proto = proto->next;
+		free(del->proto_name);
+		free(del->proto_version);
+		free(del);
+	}
+	proto_list = NULL;
+}
+
+/**
+ * tracecmd_compress_data - compress a memory block
+ * @proto: handle to compression algorithm that will be used to compress the data.
+ * @in: pointer to the data that will be compressed.
+ * @in_bytes: number of bytes in @in.
+ * @out: pre-allocated memory to store the compressed data. It must be at least the size returned
+ *	by tracecmd_get_compress_size().
+ * @out_bytes: size of the allocated memory in @out. On successful return, @out_bytes is updated
+ *	       with the size of the compressed data.
+ *
+ * Returns 0 on success, or -1 in case of an error.
+ */
+int tracecmd_compress_data(struct tracecmd_compress_proto *proto,
+			   char *in, unsigned int in_bytes,
+			   char *out, unsigned int *out_bytes)
+{
+	if (proto && proto->comress_block)
+		return proto->comress_block(in, in_bytes, out, out_bytes);
+	return -1;
+}
+
+/**
+ * tracecmd_uncompress_data - uncompress a memory block
+ * @proto: handle to compression algorithm that will be used to uncompress the data.
+ * @in: pointer to the data that will be uncompressed.
+ * @in_bytes: number of bytes in @in.
+ * @out: pre-allocated memory to store the uncompressed data.
+ * @out_bytes: size of the allocated memory in @out. On successful return, @out_bytes is updated
+ *	       with the size of the uncompressed data.
+ *
+ * Returns 0 on success, or -1 in case of an error.
+ */
+int tracecmd_uncompress_data(struct tracecmd_compress_proto *proto,
+			     char *in, unsigned int in_bytes,
+			     char *out, unsigned int *out_bytes)
+{
+	if (proto && proto->uncompress_block)
+		return proto->uncompress_block(in, in_bytes, out, out_bytes);
+	return -1;
+}
+
+/**
+ * tracecmd_get_compress_size - get the buffer size, required to compress given data
+ * @proto: handle to compression algorithm that will be used to compress the data.
+ * @bytes: number of bytes that will be compressed.
+ *
+ * Returns the required size of the buffer for compression of @bytes, or 0 in case of an error
+ */
+unsigned int tracecmd_get_compress_size(struct tracecmd_compress_proto *proto, unsigned int bytes)
+{
+	if (proto && proto->comress_size)
+		return proto->comress_size(bytes);
+	return -1;
+}
+
+
+/**
+ * tracecmd_compress_protos_get - get a list of all supported compression algorithms and versions
+ * @names: return, array with names of all supported compression algorithms
+ * @versions: return, array with versions of all supported compression algorithms
+ *
+ * On success, the size of @names and @versions arrays is returned. Those arrays are allocated by
+ * the API and must be freed with free() by the caller. Both arrays are with same size, each name
+ * from @names corresponds to a version from @versions.
+ * On error -1 is returned and @names and @versions arrays are not allocated.
+ */
+int tracecmd_compress_protos_get(char ***names, char ***versions)
+{
+	struct tracecmd_compress_proto *proto = proto_list;
+	char **n = NULL;
+	char **v = NULL;
+	int c, i;
+
+	for (c = 0; proto; proto = proto->next)
+		;
+
+	if (c < 1)
+		return c;
+
+	n = calloc(c, sizeof(char *));
+	if (!n)
+		goto error;
+	v = calloc(c, sizeof(char *));
+	if (!n)
+		goto error;
+
+	for (i = 0; proto; proto = proto->next) {
+		n[i] = proto->proto_name;
+		v[i] = proto->proto_version;
+	}
+
+	names = &n;
+	versions = &v;
+	return c;
+
+error:
+	free(n);
+	free(v);
+	return -1;
+}
diff --git a/lib/trace-cmd/trace-util.c b/lib/trace-cmd/trace-util.c
index 3ef10eae..a42499fe 100644
--- a/lib/trace-cmd/trace-util.c
+++ b/lib/trace-cmd/trace-util.c
@@ -592,9 +592,12 @@  bool tracecmd_is_version_supported(unsigned int version)
 
 int tracecmd_lib_init(void)
 {
+
+	tracecmd_compress_init();
 	return 0;
 }
 
 void tracecmd_lib_free(void)
 {
+	tracecmd_compress_free();
 }