127b27ec6Sopenharmony_ci/*
227b27ec6Sopenharmony_ci * compress_functions.c
327b27ec6Sopenharmony_ci * Copyright  : Kyle Harper
427b27ec6Sopenharmony_ci * License    : Follows same licensing as the lz4.c/lz4.h program at any given time.  Currently, BSD 2.
527b27ec6Sopenharmony_ci * Description: A program to demonstrate the various compression functions involved in when using LZ4_compress_default().  The idea
627b27ec6Sopenharmony_ci *              is to show how each step in the call stack can be used directly, if desired.  There is also some benchmarking for
727b27ec6Sopenharmony_ci *              each function to demonstrate the (probably lack of) performance difference when jumping the stack.
827b27ec6Sopenharmony_ci *              (If you're new to lz4, please read simple_buffer.c to understand the fundamentals)
927b27ec6Sopenharmony_ci *
1027b27ec6Sopenharmony_ci *              The call stack (before theoretical compiler optimizations) for LZ4_compress_default is as follows:
1127b27ec6Sopenharmony_ci *                LZ4_compress_default
1227b27ec6Sopenharmony_ci *                  LZ4_compress_fast
1327b27ec6Sopenharmony_ci *                    LZ4_compress_fast_extState
1427b27ec6Sopenharmony_ci *                      LZ4_compress_generic
1527b27ec6Sopenharmony_ci *
1627b27ec6Sopenharmony_ci *              LZ4_compress_default()
1727b27ec6Sopenharmony_ci *                This is the recommended function for compressing data.  It will serve as the baseline for comparison.
1827b27ec6Sopenharmony_ci *              LZ4_compress_fast()
1927b27ec6Sopenharmony_ci *                Despite its name, it's not a "fast" version of compression.  It simply decides if HEAPMODE is set and either
2027b27ec6Sopenharmony_ci *                allocates memory on the heap for a struct or creates the struct directly on the stack.  Stack access is generally
2127b27ec6Sopenharmony_ci *                faster but this function itself isn't giving that advantage, it's just some logic for compile time.
2227b27ec6Sopenharmony_ci *              LZ4_compress_fast_extState()
2327b27ec6Sopenharmony_ci *                This simply accepts all the pointers and values collected thus far and adds logic to determine how
2427b27ec6Sopenharmony_ci *                LZ4_compress_generic should be invoked; specifically: can the source fit into a single pass as determined by
2527b27ec6Sopenharmony_ci *                LZ4_64Klimit.
2627b27ec6Sopenharmony_ci *              LZ4_compress_generic()
2727b27ec6Sopenharmony_ci *                As the name suggests, this is the generic function that ultimately does most of the heavy lifting.  Calling this
2827b27ec6Sopenharmony_ci *                directly can help avoid some test cases and branching which might be useful in some implementation-specific
2927b27ec6Sopenharmony_ci *                situations, but you really need to know what you're doing AND what you're asking lz4 to do!  You also need a
3027b27ec6Sopenharmony_ci *                wrapper function because this function isn't exposed with lz4.h.
3127b27ec6Sopenharmony_ci *
3227b27ec6Sopenharmony_ci *              The call stack for decompression functions is shallow.  There are 2 options:
3327b27ec6Sopenharmony_ci *                LZ4_decompress_safe  ||  LZ4_decompress_fast
3427b27ec6Sopenharmony_ci *                  LZ4_decompress_generic
3527b27ec6Sopenharmony_ci *
3627b27ec6Sopenharmony_ci *               LZ4_decompress_safe
3727b27ec6Sopenharmony_ci *                 This is the recommended function for decompressing data.  It is considered safe because the caller specifies
3827b27ec6Sopenharmony_ci *                 both the size of the compressed buffer to read as well as the maximum size of the output (decompressed) buffer
3927b27ec6Sopenharmony_ci *                 instead of just the latter.
4027b27ec6Sopenharmony_ci *               LZ4_decompress_fast
4127b27ec6Sopenharmony_ci *                 Again, despite its name it's not a "fast" version of decompression.  It simply frees the caller of sending the
4227b27ec6Sopenharmony_ci *                 size of the compressed buffer (it will simply be read-to-end, hence it's non-safety).
4327b27ec6Sopenharmony_ci *               LZ4_decompress_generic
4427b27ec6Sopenharmony_ci *                 This is the generic function that both of the LZ4_decompress_* functions above end up calling.  Calling this
4527b27ec6Sopenharmony_ci *                 directly is not advised, period.  Furthermore, it is a static inline function in lz4.c, so there isn't a symbol
4627b27ec6Sopenharmony_ci *                 exposed for anyone using lz4.h to utilize.
4727b27ec6Sopenharmony_ci *
4827b27ec6Sopenharmony_ci *               Special Note About Decompression:
4927b27ec6Sopenharmony_ci *               Using the LZ4_decompress_safe() function protects against malicious (user) input.  If you are using data from a
5027b27ec6Sopenharmony_ci *               trusted source, or if your program is the producer (P) as well as its consumer (C) in a PC or MPMC setup, you can
5127b27ec6Sopenharmony_ci *               safely use the LZ4_decompress_fast function.
5227b27ec6Sopenharmony_ci */
5327b27ec6Sopenharmony_ci
5427b27ec6Sopenharmony_ci/* Since lz4 compiles with c99 and not gnu/std99 we need to enable POSIX linking for time.h structs and functions. */
5527b27ec6Sopenharmony_ci#if __STDC_VERSION__ >= 199901L
5627b27ec6Sopenharmony_ci#define _XOPEN_SOURCE 600
5727b27ec6Sopenharmony_ci#else
5827b27ec6Sopenharmony_ci#define _XOPEN_SOURCE 500
5927b27ec6Sopenharmony_ci#endif
6027b27ec6Sopenharmony_ci#define _POSIX_C_SOURCE 199309L
6127b27ec6Sopenharmony_ci
6227b27ec6Sopenharmony_ci/* Includes, for Power! */
6327b27ec6Sopenharmony_ci#define LZ4_DISABLE_DEPRECATE_WARNINGS   /* LZ4_decompress_fast */
6427b27ec6Sopenharmony_ci#include "lz4.h"
6527b27ec6Sopenharmony_ci#include <stdio.h>    /* for printf() */
6627b27ec6Sopenharmony_ci#include <stdlib.h>   /* for exit() */
6727b27ec6Sopenharmony_ci#include <string.h>   /* for atoi() memcmp() */
6827b27ec6Sopenharmony_ci#include <stdint.h>   /* for uint_types */
6927b27ec6Sopenharmony_ci#include <inttypes.h> /* for PRIu64 */
7027b27ec6Sopenharmony_ci#include <time.h>     /* for clock_gettime() */
7127b27ec6Sopenharmony_ci#include <locale.h>   /* for setlocale() */
7227b27ec6Sopenharmony_ci
7327b27ec6Sopenharmony_ci/* We need to know what one billion is for clock timing. */
7427b27ec6Sopenharmony_ci#define BILLION 1000000000L
7527b27ec6Sopenharmony_ci
7627b27ec6Sopenharmony_ci/* Create a crude set of test IDs so we can switch on them later  (Can't switch() on a char[] or char*). */
7727b27ec6Sopenharmony_ci#define ID__LZ4_COMPRESS_DEFAULT        1
7827b27ec6Sopenharmony_ci#define ID__LZ4_COMPRESS_FAST           2
7927b27ec6Sopenharmony_ci#define ID__LZ4_COMPRESS_FAST_EXTSTATE  3
8027b27ec6Sopenharmony_ci#define ID__LZ4_COMPRESS_GENERIC        4
8127b27ec6Sopenharmony_ci#define ID__LZ4_DECOMPRESS_SAFE         5
8227b27ec6Sopenharmony_ci#define ID__LZ4_DECOMPRESS_FAST         6
8327b27ec6Sopenharmony_ci
8427b27ec6Sopenharmony_ci
8527b27ec6Sopenharmony_ci
8627b27ec6Sopenharmony_ci/*
8727b27ec6Sopenharmony_ci * Easy show-error-and-bail function.
8827b27ec6Sopenharmony_ci */
8927b27ec6Sopenharmony_civoid run_screaming(const char *message, const int code) {
9027b27ec6Sopenharmony_ci  printf("%s\n", message);
9127b27ec6Sopenharmony_ci  exit(code);
9227b27ec6Sopenharmony_ci}
9327b27ec6Sopenharmony_ci
9427b27ec6Sopenharmony_ci
9527b27ec6Sopenharmony_ci/*
9627b27ec6Sopenharmony_ci * Centralize the usage function to keep main cleaner.
9727b27ec6Sopenharmony_ci */
9827b27ec6Sopenharmony_civoid usage(const char *message) {
9927b27ec6Sopenharmony_ci  printf("Usage: ./argPerformanceTesting <iterations>\n");
10027b27ec6Sopenharmony_ci  run_screaming(message, 1);
10127b27ec6Sopenharmony_ci  return;
10227b27ec6Sopenharmony_ci}
10327b27ec6Sopenharmony_ci
10427b27ec6Sopenharmony_ci
10527b27ec6Sopenharmony_ci
10627b27ec6Sopenharmony_ci/*
10727b27ec6Sopenharmony_ci * Runs the benchmark for LZ4_compress_* based on function_id.
10827b27ec6Sopenharmony_ci */
10927b27ec6Sopenharmony_ciuint64_t bench(
11027b27ec6Sopenharmony_ci    const char *known_good_dst,
11127b27ec6Sopenharmony_ci    const int function_id,
11227b27ec6Sopenharmony_ci    const int iterations,
11327b27ec6Sopenharmony_ci    const char *src,
11427b27ec6Sopenharmony_ci    char *dst,
11527b27ec6Sopenharmony_ci    const size_t src_size,
11627b27ec6Sopenharmony_ci    const size_t max_dst_size,
11727b27ec6Sopenharmony_ci    const size_t comp_size
11827b27ec6Sopenharmony_ci  ) {
11927b27ec6Sopenharmony_ci  uint64_t time_taken = 0;
12027b27ec6Sopenharmony_ci  int rv = 0;
12127b27ec6Sopenharmony_ci  const int warm_up = 5000;
12227b27ec6Sopenharmony_ci  struct timespec start, end;
12327b27ec6Sopenharmony_ci  const int acceleration = 1;
12427b27ec6Sopenharmony_ci  LZ4_stream_t state;
12527b27ec6Sopenharmony_ci
12627b27ec6Sopenharmony_ci  // Select the right function to perform the benchmark on.  We perform 5000 initial loops to warm the cache and ensure that dst
12727b27ec6Sopenharmony_ci  // remains matching to known_good_dst between successive calls.
12827b27ec6Sopenharmony_ci  switch(function_id) {
12927b27ec6Sopenharmony_ci    case ID__LZ4_COMPRESS_DEFAULT:
13027b27ec6Sopenharmony_ci      printf("Starting benchmark for function: LZ4_compress_default()\n");
13127b27ec6Sopenharmony_ci      for(int junk=0; junk<warm_up; junk++)
13227b27ec6Sopenharmony_ci        rv = LZ4_compress_default(src, dst, src_size, max_dst_size);
13327b27ec6Sopenharmony_ci      if (rv < 1)
13427b27ec6Sopenharmony_ci        run_screaming("Couldn't run LZ4_compress_default()... error code received is in exit code.", rv);
13527b27ec6Sopenharmony_ci      if (memcmp(known_good_dst, dst, max_dst_size) != 0)
13627b27ec6Sopenharmony_ci        run_screaming("According to memcmp(), the compressed dst we got doesn't match the known_good_dst... ruh roh.", 1);
13727b27ec6Sopenharmony_ci      clock_gettime(CLOCK_MONOTONIC, &start);
13827b27ec6Sopenharmony_ci      for (int i=1; i<=iterations; i++)
13927b27ec6Sopenharmony_ci        LZ4_compress_default(src, dst, src_size, max_dst_size);
14027b27ec6Sopenharmony_ci      break;
14127b27ec6Sopenharmony_ci
14227b27ec6Sopenharmony_ci    case ID__LZ4_COMPRESS_FAST:
14327b27ec6Sopenharmony_ci      printf("Starting benchmark for function: LZ4_compress_fast()\n");
14427b27ec6Sopenharmony_ci      for(int junk=0; junk<warm_up; junk++)
14527b27ec6Sopenharmony_ci        rv = LZ4_compress_fast(src, dst, src_size, max_dst_size, acceleration);
14627b27ec6Sopenharmony_ci      if (rv < 1)
14727b27ec6Sopenharmony_ci        run_screaming("Couldn't run LZ4_compress_fast()... error code received is in exit code.", rv);
14827b27ec6Sopenharmony_ci      if (memcmp(known_good_dst, dst, max_dst_size) != 0)
14927b27ec6Sopenharmony_ci        run_screaming("According to memcmp(), the compressed dst we got doesn't match the known_good_dst... ruh roh.", 1);
15027b27ec6Sopenharmony_ci      clock_gettime(CLOCK_MONOTONIC, &start);
15127b27ec6Sopenharmony_ci      for (int i=1; i<=iterations; i++)
15227b27ec6Sopenharmony_ci        LZ4_compress_fast(src, dst, src_size, max_dst_size, acceleration);
15327b27ec6Sopenharmony_ci      break;
15427b27ec6Sopenharmony_ci
15527b27ec6Sopenharmony_ci    case ID__LZ4_COMPRESS_FAST_EXTSTATE:
15627b27ec6Sopenharmony_ci      printf("Starting benchmark for function: LZ4_compress_fast_extState()\n");
15727b27ec6Sopenharmony_ci      for(int junk=0; junk<warm_up; junk++)
15827b27ec6Sopenharmony_ci        rv = LZ4_compress_fast_extState(&state, src, dst, src_size, max_dst_size, acceleration);
15927b27ec6Sopenharmony_ci      if (rv < 1)
16027b27ec6Sopenharmony_ci        run_screaming("Couldn't run LZ4_compress_fast_extState()... error code received is in exit code.", rv);
16127b27ec6Sopenharmony_ci      if (memcmp(known_good_dst, dst, max_dst_size) != 0)
16227b27ec6Sopenharmony_ci        run_screaming("According to memcmp(), the compressed dst we got doesn't match the known_good_dst... ruh roh.", 1);
16327b27ec6Sopenharmony_ci      clock_gettime(CLOCK_MONOTONIC, &start);
16427b27ec6Sopenharmony_ci      for (int i=1; i<=iterations; i++)
16527b27ec6Sopenharmony_ci        LZ4_compress_fast_extState(&state, src, dst, src_size, max_dst_size, acceleration);
16627b27ec6Sopenharmony_ci      break;
16727b27ec6Sopenharmony_ci
16827b27ec6Sopenharmony_ci//    Disabled until LZ4_compress_generic() is exposed in the header.
16927b27ec6Sopenharmony_ci//    case ID__LZ4_COMPRESS_GENERIC:
17027b27ec6Sopenharmony_ci//      printf("Starting benchmark for function: LZ4_compress_generic()\n");
17127b27ec6Sopenharmony_ci//      LZ4_resetStream((LZ4_stream_t*)&state);
17227b27ec6Sopenharmony_ci//      for(int junk=0; junk<warm_up; junk++) {
17327b27ec6Sopenharmony_ci//        LZ4_resetStream((LZ4_stream_t*)&state);
17427b27ec6Sopenharmony_ci//        //rv = LZ4_compress_generic_wrapper(&state, src, dst, src_size, max_dst_size, notLimited, byU16, noDict, noDictIssue, acceleration);
17527b27ec6Sopenharmony_ci//        LZ4_compress_generic_wrapper(&state, src, dst, src_size, max_dst_size, acceleration);
17627b27ec6Sopenharmony_ci//      }
17727b27ec6Sopenharmony_ci//      if (rv < 1)
17827b27ec6Sopenharmony_ci//        run_screaming("Couldn't run LZ4_compress_generic()... error code received is in exit code.", rv);
17927b27ec6Sopenharmony_ci//      if (memcmp(known_good_dst, dst, max_dst_size) != 0)
18027b27ec6Sopenharmony_ci//        run_screaming("According to memcmp(), the compressed dst we got doesn't match the known_good_dst... ruh roh.", 1);
18127b27ec6Sopenharmony_ci//      for (int i=1; i<=iterations; i++) {
18227b27ec6Sopenharmony_ci//        LZ4_resetStream((LZ4_stream_t*)&state);
18327b27ec6Sopenharmony_ci//        //LZ4_compress_generic_wrapper(&state, src, dst, src_size, max_dst_size, notLimited, byU16, noDict, noDictIssue, acceleration);
18427b27ec6Sopenharmony_ci//        LZ4_compress_generic_wrapper(&state, src, dst, src_size, max_dst_size, acceleration);
18527b27ec6Sopenharmony_ci//      }
18627b27ec6Sopenharmony_ci//      break;
18727b27ec6Sopenharmony_ci
18827b27ec6Sopenharmony_ci    case ID__LZ4_DECOMPRESS_SAFE:
18927b27ec6Sopenharmony_ci      printf("Starting benchmark for function: LZ4_decompress_safe()\n");
19027b27ec6Sopenharmony_ci      for(int junk=0; junk<warm_up; junk++)
19127b27ec6Sopenharmony_ci        rv = LZ4_decompress_safe(src, dst, comp_size, src_size);
19227b27ec6Sopenharmony_ci      if (rv < 1)
19327b27ec6Sopenharmony_ci        run_screaming("Couldn't run LZ4_decompress_safe()... error code received is in exit code.", rv);
19427b27ec6Sopenharmony_ci      if (memcmp(known_good_dst, dst, src_size) != 0)
19527b27ec6Sopenharmony_ci        run_screaming("According to memcmp(), the compressed dst we got doesn't match the known_good_dst... ruh roh.", 1);
19627b27ec6Sopenharmony_ci      clock_gettime(CLOCK_MONOTONIC, &start);
19727b27ec6Sopenharmony_ci      for (int i=1; i<=iterations; i++)
19827b27ec6Sopenharmony_ci        LZ4_decompress_safe(src, dst, comp_size, src_size);
19927b27ec6Sopenharmony_ci      break;
20027b27ec6Sopenharmony_ci
20127b27ec6Sopenharmony_ci    case ID__LZ4_DECOMPRESS_FAST:
20227b27ec6Sopenharmony_ci      printf("Starting benchmark for function: LZ4_decompress_fast()\n");
20327b27ec6Sopenharmony_ci      for(int junk=0; junk<warm_up; junk++)
20427b27ec6Sopenharmony_ci        rv = LZ4_decompress_fast(src, dst, src_size);
20527b27ec6Sopenharmony_ci      if (rv < 1)
20627b27ec6Sopenharmony_ci        run_screaming("Couldn't run LZ4_decompress_fast()... error code received is in exit code.", rv);
20727b27ec6Sopenharmony_ci      if (memcmp(known_good_dst, dst, src_size) != 0)
20827b27ec6Sopenharmony_ci        run_screaming("According to memcmp(), the compressed dst we got doesn't match the known_good_dst... ruh roh.", 1);
20927b27ec6Sopenharmony_ci      clock_gettime(CLOCK_MONOTONIC, &start);
21027b27ec6Sopenharmony_ci      for (int i=1; i<=iterations; i++)
21127b27ec6Sopenharmony_ci        LZ4_decompress_fast(src, dst, src_size);
21227b27ec6Sopenharmony_ci      break;
21327b27ec6Sopenharmony_ci
21427b27ec6Sopenharmony_ci    default:
21527b27ec6Sopenharmony_ci      run_screaming("The test specified isn't valid.  Please check your code.", 1);
21627b27ec6Sopenharmony_ci      break;
21727b27ec6Sopenharmony_ci  }
21827b27ec6Sopenharmony_ci
21927b27ec6Sopenharmony_ci  // Stop timer and return time taken.
22027b27ec6Sopenharmony_ci  clock_gettime(CLOCK_MONOTONIC, &end);
22127b27ec6Sopenharmony_ci  time_taken = BILLION *(end.tv_sec - start.tv_sec) + end.tv_nsec - start.tv_nsec;
22227b27ec6Sopenharmony_ci
22327b27ec6Sopenharmony_ci  return time_taken;
22427b27ec6Sopenharmony_ci}
22527b27ec6Sopenharmony_ci
22627b27ec6Sopenharmony_ci
22727b27ec6Sopenharmony_ci
22827b27ec6Sopenharmony_ci/*
22927b27ec6Sopenharmony_ci * main()
23027b27ec6Sopenharmony_ci * We will demonstrate the use of each function for simplicity sake.  Then we will run 2 suites of benchmarking:
23127b27ec6Sopenharmony_ci * Test suite A)  Uses generic Lorem Ipsum text which should be generally compressible insomuch as basic human text is
23227b27ec6Sopenharmony_ci *                compressible for such a small src_size
23327b27ec6Sopenharmony_ci * Test Suite B)  For the sake of testing, see what results we get if the data is drastically easier to compress.  IF there are
23427b27ec6Sopenharmony_ci *                indeed losses and IF more compressible data is faster to process, this will exacerbate the findings.
23527b27ec6Sopenharmony_ci */
23627b27ec6Sopenharmony_ciint main(int argc, char **argv) {
23727b27ec6Sopenharmony_ci  // Get and verify options.  There's really only 1:  How many iterations to run.
23827b27ec6Sopenharmony_ci  int iterations = 1000000;
23927b27ec6Sopenharmony_ci  if (argc > 1)
24027b27ec6Sopenharmony_ci    iterations = atoi(argv[1]);
24127b27ec6Sopenharmony_ci  if (iterations < 1)
24227b27ec6Sopenharmony_ci    usage("Argument 1 (iterations) must be > 0.");
24327b27ec6Sopenharmony_ci
24427b27ec6Sopenharmony_ci  // First we will create 2 sources (char *) of 2000 bytes each.  One normal text, the other highly-compressible text.
24527b27ec6Sopenharmony_ci  const char *src    = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed luctus purus et risus vulputate, et mollis orci ullamcorper. Nulla facilisi. Fusce in ligula sed purus varius aliquet interdum vitae justo. Proin quis diam velit. Nulla varius iaculis auctor. Cras volutpat, justo eu dictum pulvinar, elit sem porttitor metus, et imperdiet metus sapien et ante. Nullam nisi nulla, ornare eu tristique eu, dignissim vitae diam. Nulla sagittis porta libero, a accumsan felis sagittis scelerisque.  Integer laoreet eleifend congue. Etiam rhoncus leo vel dolor fermentum, quis luctus nisl iaculis. Praesent a erat sapien. Aliquam semper mi in lorem ultrices ultricies. Lorem ipsum dolor sit amet, consectetur adipiscing elit. In feugiat risus sed enim ultrices, at sodales nulla tristique. Maecenas eget pellentesque justo, sed pellentesque lectus. Fusce sagittis sit amet elit vel varius. Donec sed ligula nec ligula vulputate rutrum sed ut lectus. Etiam congue pharetra leo vitae cursus. Morbi enim ante, porttitor ut varius vel, tincidunt quis justo. Nunc iaculis, risus id ultrices semper, metus est efficitur ligula, vel posuere risus nunc eget purus. Ut lorem turpis, condimentum at sem sed, porta aliquam turpis. In ut sapien a nulla dictum tincidunt quis sit amet lorem. Fusce at est egestas, luctus neque eu, consectetur tortor. Phasellus eleifend ultricies nulla ac lobortis.  Morbi maximus quam cursus vehicula iaculis. Maecenas cursus vel justo ut rutrum. Curabitur magna orci, dignissim eget dapibus vitae, finibus id lacus. Praesent rhoncus mattis augue vitae bibendum. Praesent porta mauris non ultrices fermentum. Quisque vulputate ipsum in sodales pulvinar. Aliquam nec mollis felis. Donec vitae augue pulvinar, congue nisl sed, pretium purus. Fusce lobortis mi ac neque scelerisque semper. Pellentesque vel est vitae magna aliquet aliquet. Nam non dolor. Nulla facilisi. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Morbi ac lacinia felis metus.";
24627b27ec6Sopenharmony_ci  const char *hc_src = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
24727b27ec6Sopenharmony_ci  // Set and derive sizes.  Since we're using strings, use strlen() + 1 for \0.
24827b27ec6Sopenharmony_ci  const size_t src_size = strlen(src) + 1;
24927b27ec6Sopenharmony_ci  const size_t max_dst_size = LZ4_compressBound(src_size);
25027b27ec6Sopenharmony_ci  int bytes_returned = 0;
25127b27ec6Sopenharmony_ci  // Now build allocations for the data we'll be playing with.
25227b27ec6Sopenharmony_ci  char *dst               = calloc(1, max_dst_size);
25327b27ec6Sopenharmony_ci  char *known_good_dst    = calloc(1, max_dst_size);
25427b27ec6Sopenharmony_ci  char *known_good_hc_dst = calloc(1, max_dst_size);
25527b27ec6Sopenharmony_ci  if (dst == NULL || known_good_dst == NULL || known_good_hc_dst == NULL)
25627b27ec6Sopenharmony_ci    run_screaming("Couldn't allocate memory for the destination buffers.  Sad :(", 1);
25727b27ec6Sopenharmony_ci
25827b27ec6Sopenharmony_ci  // Create known-good buffers to verify our tests with other functions will produce the same results.
25927b27ec6Sopenharmony_ci  bytes_returned = LZ4_compress_default(src, known_good_dst, src_size, max_dst_size);
26027b27ec6Sopenharmony_ci  if (bytes_returned < 1)
26127b27ec6Sopenharmony_ci    run_screaming("Couldn't create a known-good destination buffer for comparison... this is bad.", 1);
26227b27ec6Sopenharmony_ci  const size_t src_comp_size = bytes_returned;
26327b27ec6Sopenharmony_ci  bytes_returned = LZ4_compress_default(hc_src, known_good_hc_dst, src_size, max_dst_size);
26427b27ec6Sopenharmony_ci  if (bytes_returned < 1)
26527b27ec6Sopenharmony_ci    run_screaming("Couldn't create a known-good (highly compressible) destination buffer for comparison... this is bad.", 1);
26627b27ec6Sopenharmony_ci  const size_t hc_src_comp_size = bytes_returned;
26727b27ec6Sopenharmony_ci
26827b27ec6Sopenharmony_ci
26927b27ec6Sopenharmony_ci  /* LZ4_compress_default() */
27027b27ec6Sopenharmony_ci  // This is the default function so we don't need to demonstrate how to use it.  See basics.c if you need more basal information.
27127b27ec6Sopenharmony_ci
27227b27ec6Sopenharmony_ci  /* LZ4_compress_fast() */
27327b27ec6Sopenharmony_ci  // Using this function is identical to LZ4_compress_default except we need to specify an "acceleration" value.  Defaults to 1.
27427b27ec6Sopenharmony_ci  memset(dst, 0, max_dst_size);
27527b27ec6Sopenharmony_ci  bytes_returned = LZ4_compress_fast(src, dst, src_size, max_dst_size, 1);
27627b27ec6Sopenharmony_ci  if (bytes_returned < 1)
27727b27ec6Sopenharmony_ci    run_screaming("Failed to compress src using LZ4_compress_fast.  echo $? for return code.", bytes_returned);
27827b27ec6Sopenharmony_ci  if (memcmp(dst, known_good_dst, bytes_returned) != 0)
27927b27ec6Sopenharmony_ci    run_screaming("According to memcmp(), the value we got in dst from LZ4_compress_fast doesn't match the known-good value.  This is bad.", 1);
28027b27ec6Sopenharmony_ci
28127b27ec6Sopenharmony_ci  /* LZ4_compress_fast_extState() */
28227b27ec6Sopenharmony_ci  // Using this function directly requires that we build an LZ4_stream_t struct ourselves.  We do NOT have to reset it ourselves.
28327b27ec6Sopenharmony_ci  memset(dst, 0, max_dst_size);
28427b27ec6Sopenharmony_ci  LZ4_stream_t state;
28527b27ec6Sopenharmony_ci  bytes_returned = LZ4_compress_fast_extState(&state, src, dst, src_size, max_dst_size, 1);
28627b27ec6Sopenharmony_ci  if (bytes_returned < 1)
28727b27ec6Sopenharmony_ci    run_screaming("Failed to compress src using LZ4_compress_fast_extState.  echo $? for return code.", bytes_returned);
28827b27ec6Sopenharmony_ci  if (memcmp(dst, known_good_dst, bytes_returned) != 0)
28927b27ec6Sopenharmony_ci    run_screaming("According to memcmp(), the value we got in dst from LZ4_compress_fast_extState doesn't match the known-good value.  This is bad.", 1);
29027b27ec6Sopenharmony_ci
29127b27ec6Sopenharmony_ci  /* LZ4_compress_generic */
29227b27ec6Sopenharmony_ci  // When you can exactly control the inputs and options of your LZ4 needs, you can use LZ4_compress_generic and fixed (const)
29327b27ec6Sopenharmony_ci  // values for the enum types such as dictionary and limitations.  Any other direct-use is probably a bad idea.
29427b27ec6Sopenharmony_ci  //
29527b27ec6Sopenharmony_ci  // That said, the LZ4_compress_generic() function is 'static inline' and does not have a prototype in lz4.h to expose a symbol
29627b27ec6Sopenharmony_ci  // for it.  In other words: we can't access it directly.  I don't want to submit a PR that modifies lz4.c/h.  Yann and others can
29727b27ec6Sopenharmony_ci  // do that if they feel it's worth expanding this example.
29827b27ec6Sopenharmony_ci  //
29927b27ec6Sopenharmony_ci  // I will, however, leave a skeleton of what would be required to use it directly:
30027b27ec6Sopenharmony_ci  /*
30127b27ec6Sopenharmony_ci    memset(dst, 0, max_dst_size);
30227b27ec6Sopenharmony_ci    // LZ4_stream_t state:  is already declared above.  We can reuse it BUT we have to reset the stream ourselves between each call.
30327b27ec6Sopenharmony_ci    LZ4_resetStream((LZ4_stream_t *)&state);
30427b27ec6Sopenharmony_ci    // Since src size is small we know the following enums will be used:  notLimited (0), byU16 (2), noDict (0), noDictIssue (0).
30527b27ec6Sopenharmony_ci    bytes_returned = LZ4_compress_generic(&state, src, dst, src_size, max_dst_size, notLimited, byU16, noDict, noDictIssue, 1);
30627b27ec6Sopenharmony_ci    if (bytes_returned < 1)
30727b27ec6Sopenharmony_ci      run_screaming("Failed to compress src using LZ4_compress_generic.  echo $? for return code.", bytes_returned);
30827b27ec6Sopenharmony_ci    if (memcmp(dst, known_good_dst, bytes_returned) != 0)
30927b27ec6Sopenharmony_ci      run_screaming("According to memcmp(), the value we got in dst from LZ4_compress_generic doesn't match the known-good value.  This is bad.", 1);
31027b27ec6Sopenharmony_ci  */
31127b27ec6Sopenharmony_ci
31227b27ec6Sopenharmony_ci
31327b27ec6Sopenharmony_ci  /* Benchmarking */
31427b27ec6Sopenharmony_ci  /* Now we'll run a few rudimentary benchmarks with each function to demonstrate differences in speed based on the function used.
31527b27ec6Sopenharmony_ci   * Remember, we cannot call LZ4_compress_generic() directly (yet) so it's disabled.
31627b27ec6Sopenharmony_ci   */
31727b27ec6Sopenharmony_ci  // Suite A - Normal Compressibility
31827b27ec6Sopenharmony_ci  char *dst_d = calloc(1, src_size);
31927b27ec6Sopenharmony_ci  memset(dst, 0, max_dst_size);
32027b27ec6Sopenharmony_ci  printf("\nStarting suite A:  Normal compressible text.\n");
32127b27ec6Sopenharmony_ci  uint64_t time_taken__default       = bench(known_good_dst, ID__LZ4_COMPRESS_DEFAULT,       iterations, src,            dst,   src_size, max_dst_size, src_comp_size);
32227b27ec6Sopenharmony_ci  uint64_t time_taken__fast          = bench(known_good_dst, ID__LZ4_COMPRESS_FAST,          iterations, src,            dst,   src_size, max_dst_size, src_comp_size);
32327b27ec6Sopenharmony_ci  uint64_t time_taken__fast_extstate = bench(known_good_dst, ID__LZ4_COMPRESS_FAST_EXTSTATE, iterations, src,            dst,   src_size, max_dst_size, src_comp_size);
32427b27ec6Sopenharmony_ci  //uint64_t time_taken__generic       = bench(known_good_dst, ID__LZ4_COMPRESS_GENERIC,       iterations, src,            dst,   src_size, max_dst_size, src_comp_size);
32527b27ec6Sopenharmony_ci  uint64_t time_taken__decomp_safe   = bench(src,            ID__LZ4_DECOMPRESS_SAFE,        iterations, known_good_dst, dst_d, src_size, max_dst_size, src_comp_size);
32627b27ec6Sopenharmony_ci  uint64_t time_taken__decomp_fast   = bench(src,            ID__LZ4_DECOMPRESS_FAST,        iterations, known_good_dst, dst_d, src_size, max_dst_size, src_comp_size);
32727b27ec6Sopenharmony_ci  // Suite B - Highly Compressible
32827b27ec6Sopenharmony_ci  memset(dst, 0, max_dst_size);
32927b27ec6Sopenharmony_ci  printf("\nStarting suite B:  Highly compressible text.\n");
33027b27ec6Sopenharmony_ci  uint64_t time_taken_hc__default       = bench(known_good_hc_dst, ID__LZ4_COMPRESS_DEFAULT,       iterations, hc_src,            dst,   src_size, max_dst_size, hc_src_comp_size);
33127b27ec6Sopenharmony_ci  uint64_t time_taken_hc__fast          = bench(known_good_hc_dst, ID__LZ4_COMPRESS_FAST,          iterations, hc_src,            dst,   src_size, max_dst_size, hc_src_comp_size);
33227b27ec6Sopenharmony_ci  uint64_t time_taken_hc__fast_extstate = bench(known_good_hc_dst, ID__LZ4_COMPRESS_FAST_EXTSTATE, iterations, hc_src,            dst,   src_size, max_dst_size, hc_src_comp_size);
33327b27ec6Sopenharmony_ci  //uint64_t time_taken_hc__generic       = bench(known_good_hc_dst, ID__LZ4_COMPRESS_GENERIC,       iterations, hc_src,            dst,   src_size, max_dst_size, hc_src_comp_size);
33427b27ec6Sopenharmony_ci  uint64_t time_taken_hc__decomp_safe   = bench(hc_src,            ID__LZ4_DECOMPRESS_SAFE,        iterations, known_good_hc_dst, dst_d, src_size, max_dst_size, hc_src_comp_size);
33527b27ec6Sopenharmony_ci  uint64_t time_taken_hc__decomp_fast   = bench(hc_src,            ID__LZ4_DECOMPRESS_FAST,        iterations, known_good_hc_dst, dst_d, src_size, max_dst_size, hc_src_comp_size);
33627b27ec6Sopenharmony_ci
33727b27ec6Sopenharmony_ci  // Report and leave.
33827b27ec6Sopenharmony_ci  setlocale(LC_ALL, "");
33927b27ec6Sopenharmony_ci  const char *format        = "|%-14s|%-30s|%'14.9f|%'16d|%'14d|%'13.2f%%|\n";
34027b27ec6Sopenharmony_ci  const char *header_format = "|%-14s|%-30s|%14s|%16s|%14s|%14s|\n";
34127b27ec6Sopenharmony_ci  const char *separator     = "+--------------+------------------------------+--------------+----------------+--------------+--------------+\n";
34227b27ec6Sopenharmony_ci  printf("\n");
34327b27ec6Sopenharmony_ci  printf("%s", separator);
34427b27ec6Sopenharmony_ci  printf(header_format, "Source", "Function Benchmarked", "Total Seconds", "Iterations/sec", "ns/Iteration", "% of default");
34527b27ec6Sopenharmony_ci  printf("%s", separator);
34627b27ec6Sopenharmony_ci  printf(format, "Normal Text", "LZ4_compress_default()",       (double)time_taken__default       / BILLION, (int)(iterations / ((double)time_taken__default       /BILLION)), (int)time_taken__default       / iterations, (double)time_taken__default       * 100 / time_taken__default);
34727b27ec6Sopenharmony_ci  printf(format, "Normal Text", "LZ4_compress_fast()",          (double)time_taken__fast          / BILLION, (int)(iterations / ((double)time_taken__fast          /BILLION)), (int)time_taken__fast          / iterations, (double)time_taken__fast          * 100 / time_taken__default);
34827b27ec6Sopenharmony_ci  printf(format, "Normal Text", "LZ4_compress_fast_extState()", (double)time_taken__fast_extstate / BILLION, (int)(iterations / ((double)time_taken__fast_extstate /BILLION)), (int)time_taken__fast_extstate / iterations, (double)time_taken__fast_extstate * 100 / time_taken__default);
34927b27ec6Sopenharmony_ci  //printf(format, "Normal Text", "LZ4_compress_generic()",       (double)time_taken__generic       / BILLION, (int)(iterations / ((double)time_taken__generic       /BILLION)), (int)time_taken__generic       / iterations, (double)time_taken__generic       * 100 / time_taken__default);
35027b27ec6Sopenharmony_ci  printf(format, "Normal Text", "LZ4_decompress_safe()",        (double)time_taken__decomp_safe   / BILLION, (int)(iterations / ((double)time_taken__decomp_safe   /BILLION)), (int)time_taken__decomp_safe   / iterations, (double)time_taken__decomp_safe   * 100 / time_taken__default);
35127b27ec6Sopenharmony_ci  printf(format, "Normal Text", "LZ4_decompress_fast()",        (double)time_taken__decomp_fast   / BILLION, (int)(iterations / ((double)time_taken__decomp_fast   /BILLION)), (int)time_taken__decomp_fast   / iterations, (double)time_taken__decomp_fast   * 100 / time_taken__default);
35227b27ec6Sopenharmony_ci  printf(header_format, "", "", "", "", "", "");
35327b27ec6Sopenharmony_ci  printf(format, "Compressible", "LZ4_compress_default()",       (double)time_taken_hc__default       / BILLION, (int)(iterations / ((double)time_taken_hc__default       /BILLION)), (int)time_taken_hc__default       / iterations, (double)time_taken_hc__default       * 100 / time_taken_hc__default);
35427b27ec6Sopenharmony_ci  printf(format, "Compressible", "LZ4_compress_fast()",          (double)time_taken_hc__fast          / BILLION, (int)(iterations / ((double)time_taken_hc__fast          /BILLION)), (int)time_taken_hc__fast          / iterations, (double)time_taken_hc__fast          * 100 / time_taken_hc__default);
35527b27ec6Sopenharmony_ci  printf(format, "Compressible", "LZ4_compress_fast_extState()", (double)time_taken_hc__fast_extstate / BILLION, (int)(iterations / ((double)time_taken_hc__fast_extstate /BILLION)), (int)time_taken_hc__fast_extstate / iterations, (double)time_taken_hc__fast_extstate * 100 / time_taken_hc__default);
35627b27ec6Sopenharmony_ci  //printf(format, "Compressible", "LZ4_compress_generic()",       (double)time_taken_hc__generic       / BILLION, (int)(iterations / ((double)time_taken_hc__generic       /BILLION)), (int)time_taken_hc__generic       / iterations, (double)time_taken_hc__generic       * 100 / time_taken_hc__default);
35727b27ec6Sopenharmony_ci  printf(format, "Compressible", "LZ4_decompress_safe()",        (double)time_taken_hc__decomp_safe   / BILLION, (int)(iterations / ((double)time_taken_hc__decomp_safe   /BILLION)), (int)time_taken_hc__decomp_safe   / iterations, (double)time_taken_hc__decomp_safe   * 100 / time_taken_hc__default);
35827b27ec6Sopenharmony_ci  printf(format, "Compressible", "LZ4_decompress_fast()",        (double)time_taken_hc__decomp_fast   / BILLION, (int)(iterations / ((double)time_taken_hc__decomp_fast   /BILLION)), (int)time_taken_hc__decomp_fast   / iterations, (double)time_taken_hc__decomp_fast   * 100 / time_taken_hc__default);
35927b27ec6Sopenharmony_ci  printf("%s", separator);
36027b27ec6Sopenharmony_ci  printf("\n");
36127b27ec6Sopenharmony_ci  printf("All done, ran %d iterations per test.\n", iterations);
36227b27ec6Sopenharmony_ci  return 0;
36327b27ec6Sopenharmony_ci}
364