summaryrefslogtreecommitdiff
path: root/util/cbfstool/cbfscomptool.c
diff options
context:
space:
mode:
authorPatrick Georgi <pgeorgi@chromium.org>2017-01-11 15:26:58 +0100
committerPatrick Georgi <pgeorgi@google.com>2017-01-12 21:40:25 +0100
commitc88d16baaf3e88029b40d43eb254e90613b95187 (patch)
treeb1b4e8fc15ec880db97d42cfbfb7adcd85d445ff /util/cbfstool/cbfscomptool.c
parent8474e7d7e83e92f3d7118311e2e35dc86dcc3ef5 (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.c189
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;
+}