diff options
author | Patrick Georgi <pgeorgi@chromium.org> | 2017-01-11 15:26:58 +0100 |
---|---|---|
committer | Patrick Georgi <pgeorgi@google.com> | 2017-01-12 21:40:25 +0100 |
commit | c88d16baaf3e88029b40d43eb254e90613b95187 (patch) | |
tree | b1b4e8fc15ec880db97d42cfbfb7adcd85d445ff /util/cbfstool/cbfscomptool.c | |
parent | 8474e7d7e83e92f3d7118311e2e35dc86dcc3ef5 (diff) |
util/cbfstool: Add cbfs-compression-tool
cbfs-compression-tool provides a way to benchmark the compression
algorithms as used by cbfstool (and coreboot) and allows to
pre-compress data for later consumption by cbfstool (once it supports
the format).
For an impression, the benchmark's results on my machine:
measuring 'none'
compressing 10485760 bytes to 10485760 took 0 seconds
measuring 'LZMA'
compressing 10485760 bytes to 1736 took 2 seconds
measuring 'LZ4'
compressing 10485760 bytes to 41880 took 0 seconds
And a possible use for external compression, parallel and non-parallel
(60MB in 53 files compressed to 650KB on a machine with 40 threads):
$ time (ls -1 *.* |xargs -n 1 -P $(nproc) -I '{}' cbfs-compression-tool compress '{}' out/'{}' LZMA)
real 0m0.786s
user 0m11.440s
sys 0m0.044s
$ time (ls -1 *.* |xargs -n 1 -P 1 -I '{}' cbfs-compression-tool compress '{}' out/'{}' LZMA)
real 0m10.444s
user 0m10.280s
sys 0m0.064s
Change-Id: I40be087e85d09a895b1ed277270350ab65a4d6d4
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Reviewed-on: https://review.coreboot.org/18099
Tested-by: build bot (Jenkins)
Reviewed-by: Martin Roth <martinroth@google.com>
Diffstat (limited to 'util/cbfstool/cbfscomptool.c')
-rw-r--r-- | util/cbfstool/cbfscomptool.c | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/util/cbfstool/cbfscomptool.c b/util/cbfstool/cbfscomptool.c new file mode 100644 index 0000000000..1aa1699588 --- /dev/null +++ b/util/cbfstool/cbfscomptool.c @@ -0,0 +1,189 @@ +/* + * cbfs-compression-tool, CLI utility for dealing with CBFS compressed data + * + * Copyright (C) 2017 Google, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "common.h" + +void usage(void); +int benchmark(void); +int compress(char *infile, char *outfile, char *algoname); + +const char *usage_text = "cbfs-compression-tool benchmark\n" + " runs benchmarks for all implemented algorithms\n" + "cbfs-compression-tool compress inFile outFile algo\n" + " compresses inFile with algo and stores in outFile\n" + "\n" + "'compress' file format:\n" + " 4 bytes little endian: algorithm ID (as used in CBFS)\n" + " 4 bytes little endian: uncompressed size\n" + " ...: compressed data stream\n"; + +void usage() +{ + puts(usage_text); +} + +int benchmark() +{ + const int bufsize = 10*1024*1024; + char *data = malloc(bufsize); + if (!data) { + fprintf(stderr, "out of memory\n"); + return 1; + } + char *compressed_data = malloc(bufsize); + if (!compressed_data) { + fprintf(stderr, "out of memory\n"); + return 1; + } + int i, l = strlen(usage_text) + 1; + for (i = 0; i + l < bufsize; i += l) { + memcpy(data + i, usage_text, l); + } + memset(data + i, 0, bufsize - i); + const struct typedesc_t *algo; + for (algo = &types_cbfs_compression[0]; algo->name != NULL; algo++) { + int outsize = bufsize; + printf("measuring '%s'\n", algo->name); + comp_func_ptr comp = compression_function(algo->type); + if (comp == NULL) { + printf("no handler associated with algorithm\n"); + return 1; + } + + struct timespec t_s, t_e; + clock_gettime(CLOCK_MONOTONIC, &t_s); + + if (comp(data, bufsize, compressed_data, &outsize)) { + printf("compression failed"); + return 1; + } + + clock_gettime(CLOCK_MONOTONIC, &t_e); + printf("compressing %d bytes to %d took %ld seconds\n", + bufsize, outsize, + t_e.tv_sec - t_s.tv_sec); + } + return 0; +} + +int compress(char *infile, char *outfile, char *algoname) +{ + int err = 1; + FILE *fin = NULL; + FILE *fout = NULL; + void *indata = NULL; + + const struct typedesc_t *algo = &types_cbfs_compression[0]; + while (algo->name != NULL) { + if (strcmp(algo->name, algoname) == 0) break; + algo++; + } + if (algo->name == NULL) { + fprintf(stderr, "algo '%s' is not supported.\n", algoname); + } + + comp_func_ptr comp = compression_function(algo->type); + if (comp == NULL) { + printf("no handler associated with algorithm\n"); + return 1; + } + + fin = fopen(infile, "rb"); + if (!fin) { + fprintf(stderr, "could not open '%s'\n", infile); + return 1; + } + fout = fopen(outfile, "wb"); + if (!fout) { + fprintf(stderr, "could not open '%s' for writing\n", outfile); + goto out; + } + + if (fseek(fin, 0, SEEK_END) != 0) { + fprintf(stderr, "could not seek in input\n"); + goto out; + } + long insize = ftell(fin); + if (insize < 0) { + fprintf(stderr, "could not determine input size\n"); + goto out; + } + rewind(fin); + + indata = malloc(insize); + if (!indata) { + fprintf(stderr, "out of memory\n"); + goto out; + } + + void *outdata = malloc(insize); + if (!outdata) { + fprintf(stderr, "out of memory\n"); + goto out; + } + int outsize; + + int remsize = insize; + while (remsize > 0) { + int readsz = fread(indata, 1, remsize, fin); + if (readsz < 0) { + fprintf(stderr, "failed to read input with %d bytes left\n", remsize); + goto out; + } + remsize -= readsz; + } + + comp(indata, insize, outdata, &outsize); + + char header[8]; + header[0] = algo->type & 0xff; + header[1] = (algo->type >> 8) & 0xff; + header[2] = (algo->type >> 16) & 0xff; + header[3] = (algo->type >> 24) & 0xff; + header[4] = insize & 0xff; + header[5] = (insize >> 8) & 0xff; + header[6] = (insize >> 16) & 0xff; + header[7] = (insize >> 24) & 0xff; + if (fwrite(header, 8, 1, fout) != 1) { + fprintf(stderr, "failed writing header\n"); + goto out; + } + if (fwrite(outdata, outsize, 1, fout) != 1) { + fprintf(stderr, "failed writing compressed data\n"); + goto out; + } + + err = 0; +out: + if (fin) fclose(fin); + if (fout) fclose(fout); + if (indata) free(indata); + return err; +} + +int main(int argc, char **argv) +{ + if ((argc == 2) && (strcmp(argv[1], "benchmark") == 0)) + return benchmark(); + if ((argc == 5) && (strcmp(argv[1], "compress") == 0)) + return compress(argv[2], argv[3], argv[4]); + usage(); + return 1; +} |