"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-zlib.c" (15 Mar 2019, 27985 Bytes) of package /linux/privat/stress-ng-0.09.56.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "stress-zlib.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.09.55_vs_0.09.56.

    1 /*
    2  * Copyright (C) 2013-2019 Canonical, Ltd.
    3  *
    4  * This program is free software; you can redistribute it and/or
    5  * modify it under the terms of the GNU General Public License
    6  * as published by the Free Software Foundation; either version 2
    7  * of the License, or (at your option) any later version.
    8  *
    9  * This program is distributed in the hope that it will be useful,
   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12  * GNU General Public License for more details.
   13  *
   14  * You should have received a copy of the GNU General Public License
   15  * along with this program; if not, write to the Free Software
   16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
   17  *
   18  * This code is a complete clean re-write of the stress tool by
   19  * Colin Ian King <colin.king@canonical.com> and attempts to be
   20  * backwardly compatible with the stress tool by Amos Waterland
   21  * <apw@rossby.metr.ou.edu> but has more stress tests and more
   22  * functionality.
   23  *
   24  */
   25 #include "stress-ng.h"
   26 
   27 #if defined(HAVE_LIB_Z)
   28 
   29 #include "zlib.h"
   30 
   31 #define DATA_SIZE_1K    (KB)        /* Must be a multiple of 8 bytes */
   32 #define DATA_SIZE_4K    (KB * 4)    /* Must be a multiple of 8 bytes */
   33 #define DATA_SIZE_16K   (KB * 16)   /* Must be a multiple of 8 bytes */
   34 #define DATA_SIZE_64K   (KB * 64)   /* Must be a multiple of 8 bytes */
   35 #define DATA_SIZE_128K  (KB * 128)  /* Must be a multiple of 8 bytes */
   36 
   37 #define DATA_SIZE DATA_SIZE_64K
   38 
   39 typedef void (*stress_zlib_rand_data_func)(const args_t *args, uint32_t *data, const int size);
   40 
   41 typedef struct {
   42     const char *name;           /* human readable form of random data generation selection */
   43     const stress_zlib_rand_data_func func;  /* the random data generation function */
   44 } stress_zlib_rand_data_info_t;
   45 
   46 typedef struct {
   47     uint64_t    xsum;
   48     bool        error;
   49     bool        pipe_broken;
   50     bool        interrupted;
   51 } xsum_t;
   52     
   53 static stress_zlib_rand_data_info_t zlib_rand_data_methods[];
   54 static volatile bool pipe_broken = false;
   55 static sigjmp_buf jmpbuf;
   56 
   57 static const char *const lorem_ipsum[] = {
   58     "Lorem ipsum dolor sit amet, consectetur adipiscing elit. ",
   59     "Nullam imperdiet quam at ultricies finibus. ",
   60     "Nunc venenatis euismod velit sit amet ornare.",
   61     "Quisque et orci eu eros convallis luctus at facilisis ex. ",
   62     "Quisque fringilla nulla felis, sed mollis est feugiat nec. ",
   63     "Vivamus at urna sit amet velit suscipit iaculis. ",
   64     "Curabitur mauris ipsum, gravida in laoreet ac, dignissim id lacus. ",
   65     "Proin dignissim, erat nec interdum commodo, nulla mi tempor dui, quis scelerisque odio nisi in tortor. ",
   66     "Mauris dignissim ex auctor nulla lobortis semper. ",
   67     "Mauris sit amet tempus risus, ac tincidunt lectus. ",
   68     "Maecenas sollicitudin porttitor nisi ac faucibus. ",
   69     "Cras eu sollicitudin arcu. ",
   70     "In sed fringilla eros, vitae fringilla tortor. ",
   71     "Phasellus mollis feugiat tortor, a ornare nunc auctor porttitor. ",
   72     "Fusce malesuada ut felis vitae vestibulum. ",
   73     "Donec sit amet hendrerit massa, vitae ultrices augue. ",
   74     "Proin volutpat velit ipsum, id imperdiet risus placerat ut. ",
   75     "Cras vitae risus ipsum.  ",
   76     "Sed lobortis quam in dictum pulvinar. ",
   77     "In non accumsan justo. ",
   78     "Ut pretium pulvinar gravida. ",
   79     "Proin ultricies nisi libero, a convallis dui vestibulum eu. ",
   80     "Aliquam in molestie magna, et ullamcorper turpis. ",
   81     "Donec id pharetra sem.  "
   82     "Duis dui massa, fringilla id mattis nec, consequat eget felis. ",
   83     "Integer a lobortis ipsum, quis ornare felis. ",
   84     "Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. ",
   85     "Nulla sed cursus nibh. ",
   86     "Quisque at ex dolor. ",
   87     "Mauris viverra risus pellentesque nisl dictum rutrum. ",
   88     "Aliquam non est quis enim dictum tristique. ",
   89     "Fusce feugiat hendrerit hendrerit. ",
   90     "Ut egestas sed erat et egestas. ",
   91     "Pellentesque convallis erat sed sapien pellentesque vulputate. ",
   92     "Praesent non sapien aliquet risus varius suscipit. ",
   93     "Curabitur eu felis dignissim, hendrerit magna vitae, condimentum nunc. ",
   94     "Donec ut tincidunt sem. ",
   95     "Sed in leo et metus ultricies semper quis quis ex. ",
   96     "Sed fringilla porta mi vitae condimentum. ",
   97     "In vitae metus libero."
   98 };
   99 
  100 /*
  101  *  stress_sigpipe_handler()
  102  *      SIGFPE handler
  103  */
  104 static void MLOCKED_TEXT stress_sigpipe_handler(int signum)
  105 {
  106     (void)signum;
  107 
  108     pipe_broken = true;
  109 }
  110 
  111 static void MLOCKED_TEXT stress_bad_read_handler(int signum)
  112 {
  113     (void)signum;
  114 
  115     siglongjmp(jmpbuf, 1);
  116 }
  117 
  118 /*
  119  *  stress_rand_data_bcd()
  120  *  fill buffer with random binary coded decimal digits
  121  */
  122 static void stress_rand_data_bcd(const args_t *args, uint32_t *data, const int size)
  123 {
  124     register uint8_t *ptr = (uint8_t *)data;
  125     const uint8_t *end = ptr + size;
  126 
  127     (void)args;
  128 
  129     while (ptr < end) {
  130         uint8_t rndval = mwc8() % 100;
  131 
  132         /* Not the most efficient but it works */
  133         *ptr++ = (rndval % 10) | ((rndval / 10) << 4);
  134     }
  135 }
  136 
  137 /*
  138  *  stress_rand_data_utf8()
  139  *  fill buffer with random bytes converted into utf8
  140  */
  141 static void stress_rand_data_utf8(const args_t *args, uint32_t *data, const int size)
  142 {
  143     const int n = size / sizeof(uint16_t);
  144     register uint8_t *ptr = (uint8_t *)data;
  145     const uint8_t *end = ptr + n;
  146 
  147     (void)args;
  148 
  149     while (ptr < end) {
  150         uint8_t ch = mwc8();
  151     
  152         if (ch <= 0x7f)
  153             *ptr++ = ch;
  154         else {
  155             if (UNLIKELY(ptr < end - 1)) {
  156                 *ptr++ = ((ch >> 6) & 0x1f) | 0xc0;
  157                 *ptr++ = (ch & 0x3f) | 0x80;
  158             } else {
  159                 /* no more space, zero pad */
  160                 *ptr = 0;
  161             }
  162         }
  163     }
  164 }
  165 
  166 /*
  167  *  stress_rand_data_binary()
  168  *  fill buffer with random binary data
  169  */
  170 static void stress_rand_data_binary(const args_t *args, uint32_t *data, const int size)
  171 {
  172     const int n = size / sizeof(*data);
  173     register int i;
  174 
  175     (void)args;
  176 
  177     for (i = 0; i < n; i++, data++)
  178         *data = mwc32();
  179 }
  180 
  181 /*
  182  *  stress_rand_data_text()
  183  *  fill buffer with random ASCII text
  184  */
  185 static void stress_rand_data_text(const args_t *args, uint32_t *data, const int size)
  186 {
  187     (void)args;
  188 
  189     stress_strnrnd((char *)data, size);
  190 }
  191 
  192 /*
  193  *  stress_rand_data_01()
  194  *  fill buffer with random ASCII 0 or 1
  195  */
  196 static void stress_rand_data_01(const args_t *args, uint32_t *data, const int size)
  197 {
  198     unsigned char *ptr = (unsigned char *)data;
  199     register int i;
  200 
  201     (void)args;
  202 
  203     for (i = 0; i < size; i += 8, ptr += 8) {
  204         uint8_t v = mwc8();
  205 
  206         *(ptr + 0) = '0' + (v & 1);
  207         v >>= 1;
  208         *(ptr + 1) = '0' + (v & 1);
  209         v >>= 1;
  210         *(ptr + 2) = '0' + (v & 1);
  211         v >>= 1;
  212         *(ptr + 3) = '0' + (v & 1);
  213         v >>= 1;
  214         *(ptr + 4) = '0' + (v & 1);
  215         v >>= 1;
  216         *(ptr + 5) = '0' + (v & 1);
  217         v >>= 1;
  218         *(ptr + 6) = '0' + (v & 1);
  219         v >>= 1;
  220         *(ptr + 7) = '0' + (v & 1);
  221     }
  222 }
  223 
  224 /*
  225  *  stress_rand_data_digits()
  226  *  fill buffer with random ASCII '0' .. '9'
  227  */
  228 static void stress_rand_data_digits(const args_t *args, uint32_t *data, const int size)
  229 {
  230     unsigned char *ptr = (unsigned char *)data;
  231     register int i;
  232 
  233     (void)args;
  234 
  235     for (i = 0; i < size; i++, ptr++)
  236         *ptr = '0' + (mwc32() % 10);
  237 }
  238 
  239 /*
  240  *  stress_rand_data_00_ff()
  241  *  fill buffer with random 0x00 or 0xff
  242  */
  243 static void stress_rand_data_00_ff(const args_t *args, uint32_t *data, const int size)
  244 {
  245     unsigned char *ptr = (unsigned char *)data;
  246     register int i;
  247 
  248     (void)args;
  249 
  250     for (i = 0; i < size; i += 8, ptr += 8) {
  251         uint8_t v = mwc8();
  252 
  253         *(ptr + 0) = (v & 1) ? 0x00 : 0xff;
  254         *(ptr + 1) = (v & 2) ? 0x00 : 0xff;
  255         *(ptr + 2) = (v & 4) ? 0x00 : 0xff;
  256         *(ptr + 3) = (v & 8) ? 0x00 : 0xff;
  257         *(ptr + 4) = (v & 16) ? 0x00 : 0xff;
  258         *(ptr + 5) = (v & 32) ? 0x00 : 0xff;
  259         *(ptr + 6) = (v & 64) ? 0x00 : 0xff;
  260         *(ptr + 7) = (v & 128) ? 0x00 : 0xff;
  261     }
  262 }
  263 
  264 /*
  265  *  stress_rand_data_nybble()
  266  *  fill buffer with 0x00..0x0f
  267  */
  268 static void stress_rand_data_nybble(const args_t *args, uint32_t *data, const int size)
  269 {
  270     unsigned char *ptr = (unsigned char *)data;
  271     register int i;
  272 
  273     (void)args;
  274 
  275     for (i = 0; i < size; i += 8, ptr += 8) {
  276         uint32_t v = mwc32();
  277 
  278         *(ptr + 0) = v & 0xf;
  279         v >>= 4;
  280         *(ptr + 1) = v & 0xf;
  281         v >>= 4;
  282         *(ptr + 2) = v & 0xf;
  283         v >>= 4;
  284         *(ptr + 3) = v & 0xf;
  285         v >>= 4;
  286         *(ptr + 4) = v & 0xf;
  287         v >>= 4;
  288         *(ptr + 5) = v & 0xf;
  289         v >>= 4;
  290         *(ptr + 6) = v & 0xf;
  291         v >>= 4;
  292         *(ptr + 7) = v & 0xf;
  293     }
  294 }
  295 
  296 /*
  297  *  stress_rand_data_rarely_1()
  298  *  fill buffer with data that is 1 in every 32 bits 1
  299  */
  300 static void stress_rand_data_rarely_1(const args_t *args, uint32_t *data, const int size)
  301 {
  302     const int n = size / sizeof(*data);
  303     register int i;
  304 
  305     (void)args;
  306 
  307     for (i = 0; i < n; i++, data++)
  308         *data = 1 << (mwc32() & 0x1f);
  309 }
  310 
  311 /*
  312  *  stress_rand_data_rarely_0()
  313  *  fill buffer with data that is 1 in every 32 bits 0
  314  */
  315 static void stress_rand_data_rarely_0(const args_t *args, uint32_t *data, const int size)
  316 {
  317     const int n = size / sizeof(*data);
  318     register int i;
  319 
  320     (void)args;
  321 
  322     for (i = 0; i < n; i++, data++)
  323         *data = ~(1 << (mwc32() & 0x1f));
  324 }
  325 
  326 /*
  327  *  stress_rand_data_fixed()
  328  *  fill buffer with data that is 0x04030201
  329  */
  330 static void stress_rand_data_fixed(const args_t *args, uint32_t *data, const int size)
  331 {
  332     const int n = size / sizeof(*data);
  333     register int i;
  334 
  335     (void)args;
  336 
  337     for (i = 0; i < n; i++, data++)
  338         *data = 0x04030201;
  339 }
  340 
  341 /*
  342  *  stress_rand_data_double()
  343  *  fill buffer with double precision floating point binary data
  344  */
  345 static void stress_rand_data_double(const args_t *args, uint32_t *data, const int size)
  346 {
  347     const int n = size / sizeof(double);
  348     uint8_t *ptr = (uint8_t *)data;
  349     register int i;
  350     static double theta = 0.0;
  351     double dtheta = M_PI / 180.0;
  352 
  353     (void)args;
  354 
  355     for (i = 0; i < n; i++) {
  356         double s = sin(theta);
  357         (void)memcpy(ptr, &s, sizeof(double));
  358         theta += dtheta;
  359         dtheta += 0.001;
  360         ptr += sizeof(double);
  361     }
  362 }
  363 
  364 /*
  365  *  stress_rand_data_gray()
  366  *  fill buffer with gray code of incrementing 16 bit values 
  367  *
  368  */
  369 static void stress_rand_data_gray(const args_t *args, uint32_t *data, const int size)
  370 {
  371     const int n = size / sizeof(uint16_t);
  372     static uint16_t val = 0;
  373     register uint16_t v = val;
  374     register uint16_t *ptr = (uint16_t *)data;
  375     register int i;
  376 
  377     (void)args;
  378 
  379     for (i = 0; i < n; i++, v++) {
  380         *(ptr++) = (v >> 1) ^ i;
  381     }
  382     val = v;
  383 }
  384 
  385 
  386 /*
  387  *  stress_rand_data_parity()
  388  *  fill buffer with 7 bit data + 1 parity bit
  389  */
  390 static void stress_rand_data_parity(const args_t *args, uint32_t *data, const int size)
  391 {
  392     uint8_t *ptr = (uint8_t *)data;
  393     register int i;
  394 
  395     (void)args;
  396 
  397     for (i = 0; i < size; i++, ptr++) {
  398         uint8_t v = mwc8();
  399         uint8_t p = v & 0xfe;
  400         p ^= p >> 4;
  401         p &= 0xf;
  402         p = (0x6996 >> p) & 1;
  403         *ptr = v | p;
  404     }
  405 }
  406 
  407 
  408 #define PINK_MAX_ROWS   (12)
  409 #define PINK_BITS       (16)
  410 #define PINK_SHIFT      ((sizeof(uint64_t) * 8) - PINK_BITS)
  411 
  412 #if !defined(HAVE_BUILTIN_CTZ)
  413 /*
  414  *  stress_builtin_ctz()
  415  *  implementation of count trailing zeros ctz, this will
  416  *  be optimized down to 1 instruction on x86 targets
  417  */
  418 static inline uint32_t stress_builtin_ctz(register uint32_t x)
  419 {
  420     register unsigned int n;
  421     if (!x)
  422         return 32;
  423 
  424     n = 0;
  425     if ((x & 0x0000ffff) == 0) {
  426         n += 16;
  427         x >>= 16;
  428     }
  429     if ((x & 0x000000ff) == 0) {
  430         n += 8;
  431         x >>= 8;
  432     }
  433     if ((x & 0x0000000f) == 0) {
  434         n += 4;
  435         x >>= 4;
  436     }
  437     if ((x & 0x00000003) == 0) {
  438         n += 2;
  439         x >>= 2;
  440     }
  441     if ((x & 0x00000001) == 0) {
  442         n += 1;
  443     }
  444     return n;
  445 }
  446 #endif
  447 
  448 /*
  449  *  stress_rand_data_pink()
  450  *  fill buffer with pink noise 0..255 using an
  451  *  the Gardner method with the McCartney
  452  *  selection tree optimization
  453  */
  454 static void stress_rand_data_pink(const args_t *args, uint32_t *data, const int size)
  455 {
  456     int i;
  457     unsigned char *ptr = (unsigned char *)data;
  458     size_t idx = 0;
  459     const size_t mask = (1 << PINK_MAX_ROWS) - 1;
  460     uint64_t sum = 0;
  461     const uint64_t max = (PINK_MAX_ROWS + 1) * (1 << (PINK_BITS - 1));
  462     uint64_t rows[PINK_MAX_ROWS];
  463     const float scalar = 256.0 / max;
  464 
  465     (void)args;
  466     (void)memset(rows, 0, sizeof(rows));
  467 
  468     for (i = 0; i < size; i++) {
  469         int64_t rnd;
  470 
  471         idx = (idx + 1) & mask;
  472         if (idx) {
  473 #if defined(HAVE_BUILTIN_CTZ)
  474             const size_t j = __builtin_ctz(idx);
  475 #else
  476             const size_t j = stress_builtin_ctz(idx);
  477 #endif
  478 
  479             sum -= rows[j];
  480             rnd = (int64_t)mwc64() >> PINK_SHIFT;
  481             sum += rnd;
  482             rows[j] = rnd;
  483         }
  484         rnd = (int64_t)mwc64() >> PINK_SHIFT;
  485         *(ptr++) = (int)((scalar * ((int64_t)sum + rnd)) + 128.0);
  486     }
  487 }
  488 
  489 /*
  490  *  stress_rand_data_brown()
  491  *  fills buffer with brown noise.
  492  */
  493 static void stress_rand_data_brown(const args_t *args, uint32_t *data, const int size)
  494 {
  495     static uint8_t val = 127;
  496     register int i;
  497     register uint8_t *ptr = (unsigned char *)data;
  498 
  499     (void)args;
  500 
  501     for (i = 0; i < size; i++) {
  502         val += ((mwc8() % 31) - 15);
  503         *(ptr++) = val;
  504     }
  505 }
  506 
  507 
  508 /*
  509  *  stress_rand_data_latin()
  510  *  fill buffer with random latin Lorum Ipsum text.
  511  */
  512 static void stress_rand_data_latin(const args_t *args, uint32_t *data, const int size)
  513 {
  514     register int i;
  515     static const char *ptr = NULL;
  516     char *dataptr = (char *)data;
  517 
  518     (void)args;
  519 
  520     if (!ptr)
  521         ptr = lorem_ipsum[mwc32() % SIZEOF_ARRAY(lorem_ipsum)];
  522 
  523     for (i = 0; i < size; i++) {
  524         if (!*ptr)
  525             ptr = lorem_ipsum[mwc32() % SIZEOF_ARRAY(lorem_ipsum)];
  526 
  527         *dataptr++ = *ptr++;
  528     }
  529 }
  530 
  531 
  532 /*
  533  *  stress_rand_data_objcode()
  534  *  fill buffer with object code data from stress-ng
  535  */
  536 static void stress_rand_data_objcode(const args_t *args, uint32_t *const data, const int size)
  537 {
  538     const int n = size / sizeof(*data);
  539     register int i;
  540     static bool use_rand_data = false;
  541     struct sigaction sigsegv_orig, sigbus_orig;
  542     char *text = NULL, *dataptr, *text_start, *text_end;
  543     const size_t text_len = stress_text_addr(&text_start, &text_end);
  544 
  545     if (use_rand_data) {
  546         stress_rand_data_binary(args, data, size);
  547         return;
  548     }
  549 
  550     /* Try and install sighandlers */
  551     if (stress_sighandler(args->name, SIGSEGV, stress_bad_read_handler, &sigsegv_orig) < 0) {
  552         use_rand_data = true;
  553         stress_rand_data_binary(args, data, size);
  554         return;
  555     }
  556     if (stress_sighandler(args->name, SIGBUS, stress_bad_read_handler, &sigbus_orig) < 0) {
  557         use_rand_data = true;
  558         (void)stress_sigrestore(args->name, SIGSEGV, &sigsegv_orig);
  559         stress_rand_data_binary(args, data, size);
  560         return;
  561     }
  562 
  563     /*
  564      *  Some architectures may generate faults on reads
  565      *  from specific text pages, so trap these and
  566      *  fall back to stress_rand_data_binary.
  567      */
  568     if (sigsetjmp(jmpbuf, 1) != 0) {
  569         (void)stress_sigrestore(args->name, SIGSEGV, &sigsegv_orig);
  570         (void)stress_sigrestore(args->name, SIGBUS, &sigbus_orig);
  571         stress_rand_data_binary(args, data, size);
  572         return;
  573     }
  574 
  575     /* Start in random place in stress-ng text segment */
  576     text = text_len ? text_start + (mwc64() % text_len) : text_start;
  577 
  578     for (dataptr = (char *)data, i = 0; i < n; i++, dataptr++) {
  579         *dataptr = *text;
  580         if (text++ >= text_end)
  581             text = text_start;
  582     }
  583     (void)stress_sigrestore(args->name, SIGSEGV, &sigsegv_orig);
  584     (void)stress_sigrestore(args->name, SIGBUS, &sigbus_orig);
  585 }
  586 
  587 /*
  588  *  stress_rand_data_zero()
  589  *  fill buffer with zeros
  590  */
  591 static void stress_rand_data_zero(const args_t *args, uint32_t *data, const int size)
  592 {
  593     (void)args;
  594     (void)memset(data, 0, size);
  595 }
  596 
  597 
  598 static const stress_zlib_rand_data_func rand_data_funcs[] = {
  599     stress_rand_data_00_ff,
  600     stress_rand_data_01,
  601     stress_rand_data_digits,
  602     stress_rand_data_bcd,
  603     stress_rand_data_binary,
  604     stress_rand_data_brown,
  605     stress_rand_data_double,
  606     stress_rand_data_fixed,
  607     stress_rand_data_gray,
  608     stress_rand_data_latin,
  609     stress_rand_data_nybble,
  610     stress_rand_data_objcode,
  611     stress_rand_data_parity,
  612     stress_rand_data_pink,
  613     stress_rand_data_rarely_1,
  614     stress_rand_data_rarely_0,
  615     stress_rand_data_text,
  616     stress_rand_data_utf8,
  617     stress_rand_data_zero,
  618 };
  619 
  620 /*
  621  *  stress_zlib_random_test()
  622  *  randomly select data generation function
  623  */
  624 static HOT OPTIMIZE3 void stress_zlib_random_test(const args_t *args, uint32_t *data, const int size)
  625 {
  626     rand_data_funcs[mwc32() % SIZEOF_ARRAY(rand_data_funcs)](args, data, size);
  627 }
  628 
  629 
  630 /*
  631  * Table of zlib data methods
  632  */
  633 static stress_zlib_rand_data_info_t zlib_rand_data_methods[] = {
  634     { "random", stress_zlib_random_test }, /* Special "random" test */
  635 
  636     { "00ff",   stress_rand_data_00_ff },
  637     { "ascii01",    stress_rand_data_01 },
  638     { "asciidigits",stress_rand_data_digits },
  639     { "bcd",    stress_rand_data_bcd },
  640     { "binary", stress_rand_data_binary },
  641     { "brown",  stress_rand_data_brown },
  642     { "double", stress_rand_data_double },
  643     { "gray",   stress_rand_data_gray },
  644     { "fixed",  stress_rand_data_fixed },
  645     { "latin",  stress_rand_data_latin },
  646     { "nybble", stress_rand_data_nybble },
  647     { "objcode",    stress_rand_data_objcode },
  648     { "parity", stress_rand_data_parity },
  649     { "pink",   stress_rand_data_pink },
  650     { "rarely1",    stress_rand_data_rarely_1 },
  651     { "rarely0",    stress_rand_data_rarely_0 },
  652     { "text",   stress_rand_data_text },
  653     { "utf8",   stress_rand_data_utf8 },
  654     { "zero",   stress_rand_data_zero },
  655     { NULL,     NULL }
  656 };
  657 
  658 /*
  659  *  stress_set_zlib_level
  660  *  set zlib compression level, 0..9,
  661  *  0 = no compression, 1 = fastest, 9 = best compression
  662  */
  663 int stress_set_zlib_level(const char *opt)
  664 {
  665         uint32_t zlib_level;
  666 
  667         zlib_level = get_uint32(opt);
  668         check_range("zlib-level", zlib_level, 0, Z_BEST_COMPRESSION);
  669         return set_setting("zlib-level", TYPE_ID_UINT32, &zlib_level);
  670 }
  671 
  672 /*
  673  *  stress_set_zlib_method()
  674  *  set the default zlib random data method
  675  */
  676 int stress_set_zlib_method(const char *opt)
  677 {
  678     stress_zlib_rand_data_info_t *info;
  679 
  680     for (info = zlib_rand_data_methods; info->func; info++) {
  681         if (!strcmp(info->name, opt)) {
  682             set_setting("zlib-method", TYPE_ID_UINTPTR_T, &info);
  683             return 0;
  684         }
  685     }
  686 
  687     (void)fprintf(stderr, "zlib-method must be one of:");
  688     for (info = zlib_rand_data_methods; info->func; info++) {
  689         (void)fprintf(stderr, " %s", info->name);
  690     }
  691     (void)fprintf(stderr, "\n");
  692 
  693     return -1;
  694 }
  695 
  696 /*
  697  *  stress_zlib_err()
  698  *  turn a zlib error to something human readable
  699  */
  700 static const char *stress_zlib_err(const int zlib_err)
  701 {
  702     static char buf[1024];
  703 
  704     switch (zlib_err) {
  705     case Z_OK:
  706         return "no error";
  707     case Z_ERRNO:
  708         (void)snprintf(buf, sizeof(buf), "system error, errno=%d (%s)\n",
  709             errno, strerror(errno));
  710         return buf;
  711     case Z_STREAM_ERROR:
  712         return "invalid compression level";
  713     case Z_DATA_ERROR:
  714         return "invalid or incomplete deflate data";
  715     case Z_MEM_ERROR:
  716         return "out of memory";
  717     case Z_VERSION_ERROR:
  718         return "zlib version mismatch";
  719     default:
  720         (void)snprintf(buf, sizeof(buf), "unknown zlib error %d\n", zlib_err);
  721         return buf;
  722     }
  723 }
  724 
  725 
  726 /*
  727  *  stress_zlib_inflate()
  728  *  inflate compressed data out of the read
  729  *  end of a pipe fd
  730  */
  731 static int stress_zlib_inflate(
  732         const args_t *args,
  733         const int fd,
  734         const int xsum_fd)
  735 {
  736     int ret, err = 0;
  737     z_stream stream_inf;
  738     uint64_t xsum_chars = 0;
  739     unsigned char in[DATA_SIZE];
  740     unsigned char out[DATA_SIZE];
  741     xsum_t xsum;
  742 
  743     xsum.xsum = 0;
  744     xsum.error = false;
  745     xsum.pipe_broken = false;
  746     xsum.interrupted = false;
  747 
  748     stream_inf.zalloc = Z_NULL;
  749     stream_inf.zfree = Z_NULL;
  750     stream_inf.opaque = Z_NULL;
  751     stream_inf.avail_in = 0;
  752     stream_inf.next_in = Z_NULL;
  753 
  754     ret = inflateInit(&stream_inf);
  755     if (ret != Z_OK) {
  756         pr_fail("%s: zlib inflateInit error: %s\n",
  757             args->name, stress_zlib_err(ret));
  758         xsum.error = true;
  759         goto xsum_error;
  760     }
  761 
  762     do {
  763         ssize_t sz;
  764 
  765         sz = read(fd, in, DATA_SIZE);
  766         if (sz < 0) {
  767             if ((errno != EINTR) && (errno != EPIPE)) {
  768                 pr_fail("%s: zlib inflate pipe read error: "
  769                     "errno=%d (%s)\n",
  770                     args->name, errno, strerror(errno));
  771                 (void)inflateEnd(&stream_inf);
  772                 xsum.error = true;
  773                 goto xsum_error;
  774             } else {
  775                 if (errno == EINTR)
  776                     xsum.interrupted = true;
  777                 if (errno == EPIPE)
  778                     xsum.pipe_broken = true;
  779                 break;
  780             }
  781         }
  782 
  783         if (sz == 0) {
  784             xsum.pipe_broken = true;
  785             break;
  786         }
  787 
  788         stream_inf.avail_in = sz;
  789         stream_inf.next_in = in;
  790 
  791         do {
  792             stream_inf.avail_out = DATA_SIZE;
  793             stream_inf.next_out = out;
  794 
  795             ret = inflate(&stream_inf, Z_NO_FLUSH);
  796             switch (ret) {
  797             case Z_NEED_DICT:
  798             case Z_DATA_ERROR:
  799             case Z_MEM_ERROR:
  800                 (void)inflateEnd(&stream_inf);
  801                 goto xsum_error;
  802             }
  803 
  804             if (g_opt_flags & OPT_FLAGS_VERIFY) {
  805                 size_t i;
  806 
  807                 for (i = 0; i < DATA_SIZE - stream_inf.avail_out; i++) {
  808                     xsum.xsum += (uint64_t)out[i];
  809                     xsum_chars++;
  810                 }
  811             }
  812         } while (stream_inf.avail_out == 0);
  813     } while (ret != Z_STREAM_END);
  814 
  815     /*
  816     if (g_opt_flags & OPT_FLAGS_VERIFY) {
  817         pr_dbg("%s: inflate xsum value %" PRIu64
  818             ", xsum_chars %" PRIu64 "\n",
  819             args->name, xsum.xsum, xsum_chars);
  820     }
  821     */
  822     (void)inflateEnd(&stream_inf);
  823 
  824     if (write(xsum_fd, &xsum, sizeof(xsum)) < 0) {
  825         pr_fail("%s: zlib inflate pipe write error: "
  826             "errno=%d (%s)\n",
  827             args->name, err, strerror(err));
  828     }
  829     return ((ret == Z_OK) || (ret == Z_STREAM_END)) ?
  830         EXIT_SUCCESS : EXIT_FAILURE;
  831 
  832 xsum_error:
  833     xsum.error = true;
  834     if (write(xsum_fd, &xsum, sizeof(xsum)) < 0) {
  835         pr_fail("%s: zlib inflate pipe write error: "
  836             "errno=%d (%s)\n",
  837             args->name, err, strerror(err));
  838     }
  839     return EXIT_FAILURE;
  840 }
  841 
  842 /*
  843  *  stress_zlib_deflate()
  844  *  compress random data and write it down the
  845  *  write end of a pipe fd
  846  */
  847 static int stress_zlib_deflate(
  848         const args_t *args,
  849         const int fd,
  850         const int xsum_fd,
  851         const int zlib_level)
  852 {
  853     int ret, err = 0;
  854     bool do_run;
  855     z_stream stream_def;
  856     uint64_t bytes_in = 0, bytes_out = 0;
  857     uint64_t xsum_chars = 0;
  858     int flush = Z_FINISH;
  859     stress_zlib_rand_data_info_t *opt_zlib_rand_data_func = &zlib_rand_data_methods[0];
  860     double t1, t2;
  861     xsum_t xsum;
  862 
  863     (void)get_setting("zlib-method", &opt_zlib_rand_data_func);
  864 
  865     xsum.xsum = 0;
  866     xsum.error = false;
  867     xsum.pipe_broken = false;
  868     xsum.interrupted = false;
  869 
  870     stream_def.zalloc = Z_NULL;
  871     stream_def.zfree = Z_NULL;
  872     stream_def.opaque = Z_NULL;
  873 
  874     t1 = time_now();
  875     ret = deflateInit(&stream_def, zlib_level);
  876     if (ret != Z_OK) {
  877         pr_fail("%s: zlib deflateInit error: %s\n",
  878             args->name, stress_zlib_err(ret));
  879         xsum.error = true;
  880         ret = EXIT_FAILURE;
  881         goto xsum_error;
  882     }
  883 
  884     do {
  885         uint32_t in[DATA_SIZE / sizeof(uint32_t)];
  886         unsigned char *xsum_in = (unsigned char *)in;
  887 
  888         opt_zlib_rand_data_func->func(args, in, DATA_SIZE);
  889 
  890         stream_def.avail_in = DATA_SIZE;
  891         stream_def.next_in = (unsigned char *)in;
  892 
  893         if (g_opt_flags & OPT_FLAGS_VERIFY) {
  894             for (int i = 0; i < (int)(DATA_SIZE / sizeof(unsigned char)); i++) {
  895                 xsum.xsum += (uint64_t)xsum_in[i];
  896                 xsum_chars++;
  897             }
  898         }
  899 
  900         do_run = keep_stressing();
  901         flush = do_run ? Z_NO_FLUSH : Z_FINISH;
  902         bytes_in += DATA_SIZE;
  903 
  904         do {
  905             unsigned char out[DATA_SIZE];
  906             int def_size, rc;
  907 
  908             stream_def.avail_out = DATA_SIZE;
  909             stream_def.next_out = out;
  910             rc = deflate(&stream_def, flush);
  911 
  912             if (rc == Z_STREAM_ERROR) {
  913                 pr_fail("%s: zlib deflate error: %s\n",
  914                     args->name, stress_zlib_err(rc));
  915                 (void)deflateEnd(&stream_def);
  916                 ret = EXIT_FAILURE;
  917                 goto xsum_error;
  918             }
  919             def_size = DATA_SIZE - stream_def.avail_out;
  920             bytes_out += def_size;
  921             if (write(fd, out, def_size) != def_size) {
  922                 if ((errno != EINTR) && (errno != EPIPE) && (errno != 0)) {
  923                     pr_fail("%s: write error: errno=%d (%s)\n",
  924                         args->name, errno, strerror(errno));
  925                     (void)deflateEnd(&stream_def);
  926                     ret = EXIT_FAILURE;
  927                     goto xsum_error;
  928                 } else {
  929                     if (errno == EINTR)
  930                         xsum.interrupted = true;
  931                     if (errno == EPIPE)
  932                         xsum.pipe_broken = true;
  933                     (void)deflateEnd(&stream_def);
  934                     goto finish;
  935                 }
  936             }
  937             inc_counter(args);
  938         } while (stream_def.avail_out == 0);
  939     } while (flush != Z_FINISH);
  940 
  941 finish:
  942     t2 = time_now();
  943     pr_inf("%s: instance %" PRIu32 ": compression ratio: %5.2f%% (%.2f MB/sec)\n",
  944         args->name, args->instance,
  945         bytes_in ? 100.0 * (double)bytes_out / (double)bytes_in : 0,
  946         (t2 - t1 > 0.0) ? (bytes_in / (t2 - t1)) / MB : 0.0);
  947 
  948     /*
  949     if (g_opt_flags & OPT_FLAGS_VERIFY) {
  950         pr_dbg("%s: deflate xsum value %" PRIu64
  951             ", xsum_chars %" PRIu64 "\n",
  952             args->name, xsum.xsum, xsum_chars);
  953     }
  954     */
  955 
  956     (void)deflateEnd(&stream_def);
  957     ret = EXIT_SUCCESS;
  958 xsum_error:
  959     if (write(xsum_fd, &xsum, sizeof(xsum)) < 0 ) {
  960         pr_fail("%s: zlib deflate pipe write error: "
  961             "errno=%d (%s)\n",
  962             args->name, err, strerror(err));
  963     }
  964 
  965     return ret;
  966 }
  967 
  968 /*
  969  *  stress_zlib()
  970  *  stress cpu with compression and decompression
  971  */
  972 static int stress_zlib(const args_t *args)
  973 {
  974     int ret = EXIT_SUCCESS, fds[2], deflate_xsum_fds[2], inflate_xsum_fds[2], status;
  975     int err = 0;
  976     pid_t pid;
  977     xsum_t deflate_xsum, inflate_xsum;
  978     uint32_t zlib_level = Z_BEST_COMPRESSION;   /* best compression */
  979     ssize_t n;
  980     bool bad_xsum_reads = false;
  981     bool error = false;
  982     bool interrupted = false;
  983 
  984     (void)memset(&deflate_xsum, 0, sizeof(deflate_xsum));
  985     (void)memset(&inflate_xsum, 0, sizeof(inflate_xsum));
  986 
  987     if (stress_sighandler(args->name, SIGPIPE, stress_sigpipe_handler, NULL) < 0)
  988         return EXIT_FAILURE;
  989 
  990     (void)get_setting("zlib-level", &zlib_level);
  991 
  992     if (pipe(fds) < 0) {
  993         pr_err("%s: pipe failed, errno=%d (%s)\n",
  994             args->name, errno, strerror(errno));
  995         return EXIT_FAILURE;
  996     }
  997 
  998     if (pipe(deflate_xsum_fds) < 0) {
  999         pr_err("%s: deflate xsum pipe failed, errno=%d (%s)\n",
 1000             args->name, errno, strerror(errno));
 1001         (void)close(fds[0]);
 1002         (void)close(fds[1]);
 1003         return EXIT_FAILURE;
 1004     }
 1005 
 1006     if (pipe(inflate_xsum_fds) < 0) {
 1007         pr_err("%s: inflate xsum pipe failed, errno=%d (%s)\n",
 1008             args->name, errno, strerror(errno));
 1009         (void)close(fds[0]);
 1010         (void)close(fds[1]);
 1011         (void)close(deflate_xsum_fds[0]);
 1012         (void)close(deflate_xsum_fds[1]);
 1013         return EXIT_FAILURE;
 1014     }
 1015 
 1016     pid = fork();
 1017     if (pid < 0) {
 1018         (void)close(fds[0]);
 1019         (void)close(fds[1]);
 1020         (void)close(deflate_xsum_fds[0]);
 1021         (void)close(deflate_xsum_fds[1]);
 1022         (void)close(inflate_xsum_fds[0]);
 1023         (void)close(inflate_xsum_fds[1]);
 1024         pr_err("%s: fork failed, errno=%d (%s)\n",
 1025             args->name, errno, strerror(errno));
 1026         return EXIT_FAILURE;
 1027     } else if (pid == 0) {
 1028         (void)setpgid(0, g_pgrp);
 1029         stress_parent_died_alarm();
 1030 
 1031         (void)close(fds[1]);
 1032         ret = stress_zlib_inflate(args, fds[0], inflate_xsum_fds[1]);
 1033         (void)close(fds[0]);
 1034         _exit(ret);
 1035     } else {
 1036         (void)close(fds[0]);
 1037         ret = stress_zlib_deflate(args, fds[1], deflate_xsum_fds[1], (int)zlib_level);
 1038         (void)close(fds[1]);
 1039     }
 1040 
 1041     n = read(deflate_xsum_fds[0], &deflate_xsum, sizeof(deflate_xsum));
 1042     if (n != sizeof(deflate_xsum)) {
 1043         bad_xsum_reads = true;
 1044         if ((errno != EINTR) && (errno != EPIPE)) {
 1045             pr_fail("%s: zlib deflate xsum read pipe error: errno=%d (%s)\n",
 1046                 args->name, err, strerror(err));
 1047         }
 1048     } else {
 1049         pipe_broken |= deflate_xsum.pipe_broken;
 1050         interrupted |= deflate_xsum.interrupted;
 1051         error       |= deflate_xsum.error;
 1052     }
 1053 
 1054     n = read(inflate_xsum_fds[0], &inflate_xsum, sizeof(inflate_xsum));
 1055     if (n != sizeof(inflate_xsum)) {
 1056         bad_xsum_reads = true;
 1057         if ((errno != EINTR) && (errno != EPIPE)) {
 1058             pr_fail("%s: zlib inflate xsum read pipe error: errno=%d (%s)\n",
 1059                 args->name, err, strerror(err));
 1060         }
 1061     } else {
 1062         pipe_broken |= inflate_xsum.pipe_broken;
 1063         interrupted |= inflate_xsum.interrupted;
 1064         error       |= inflate_xsum.error;
 1065     }
 1066 
 1067     if (pipe_broken || bad_xsum_reads || interrupted || error) {
 1068         pr_inf("%s: cannot verify inflate/deflate checksums:%s%s%s%s%s%s%s\n",
 1069             args->name,
 1070             interrupted ? " interrupted" : "",
 1071             (interrupted & pipe_broken) ? " and" : "",
 1072             pipe_broken ? " broken pipe" : "",
 1073             ((interrupted | pipe_broken)) & error ? " and" : "",
 1074             error ? " unexpected error" : "",
 1075             ((interrupted | pipe_broken | error) & bad_xsum_reads) ? " and" : "",
 1076             bad_xsum_reads ? " could not read checksums" : "");
 1077     } else {
 1078         if ((g_opt_flags & OPT_FLAGS_VERIFY) &&
 1079             (deflate_xsum.xsum != inflate_xsum.xsum)) {
 1080             pr_fail("%s: zlib xsum values do NOT match "
 1081                 "deflate xsum %" PRIu64
 1082                 " vs inflate xsum %" PRIu64 "\n",
 1083                 args->name, deflate_xsum.xsum, inflate_xsum.xsum);
 1084             ret = EXIT_FAILURE;
 1085         }
 1086     }
 1087 
 1088     (void)close(deflate_xsum_fds[0]);
 1089     (void)close(deflate_xsum_fds[1]);
 1090     (void)close(inflate_xsum_fds[0]);
 1091     (void)close(inflate_xsum_fds[1]);
 1092 
 1093     (void)kill(pid, SIGKILL);
 1094     (void)waitpid(pid, &status, 0);
 1095 
 1096     return ret;
 1097 }
 1098 
 1099 static void stress_zlib_set_default(void)
 1100 {
 1101     stress_set_zlib_method("random");
 1102 }
 1103 
 1104 stressor_info_t stress_zlib_info = {
 1105     .stressor = stress_zlib,
 1106     .set_default = stress_zlib_set_default,
 1107     .class = CLASS_CPU | CLASS_CPU_CACHE | CLASS_MEMORY
 1108 };
 1109 #else
 1110 stressor_info_t stress_zlib_info = {
 1111     .stressor = stress_not_implemented,
 1112     .class = CLASS_CPU | CLASS_CPU_CACHE | CLASS_MEMORY
 1113 };
 1114 #endif