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@xxxxxxxxx> --- 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 --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@xxxxxxxxx> + * + */ +#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(); } -- 2.30.2