"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-vm-addr.c" (15 Mar 2019, 11772 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-vm-addr.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.09.54_vs_0.09.55.

    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 #define MIN_VM_ADDR_BYTES   (8 * MB)
   28 #define MAX_VM_ADDR_BYTES   (64 * MB)
   29 #define NO_MEM_RETRIES_MAX  (100)
   30 
   31 /*
   32  *  the VM stress test has diffent methods of vm stressor
   33  */
   34 typedef size_t (*stress_vm_addr_func)(uint8_t *buf, const size_t sz);
   35 
   36 typedef struct {
   37     const char *name;
   38     const stress_vm_addr_func func;
   39 } stress_vm_addr_method_info_t;
   40 
   41 static const stress_vm_addr_method_info_t vm_addr_methods[];
   42 
   43 /*
   44  *  keep_stressing()
   45  *  returns true if we can keep on running a stressor
   46  */
   47 static bool HOT OPTIMIZE3 keep_stressing_vm(const args_t *args)
   48 {
   49     return (LIKELY(g_keep_stressing_flag) &&
   50             LIKELY(!args->max_ops || (get_counter(args) < args->max_ops)));
   51 }
   52 
   53 /*
   54  *  reverse64
   55  *  generic fast-ish 64 bit reverse
   56  */
   57 static uint64_t reverse64(register uint64_t x)
   58 {
   59     x = (((x & 0xaaaaaaaaaaaaaaaaULL) >> 1)  | ((x & 0x5555555555555555ULL) << 1));
   60     x = (((x & 0xccccccccccccccccULL) >> 2)  | ((x & 0x3333333333333333ULL) << 2));
   61     x = (((x & 0xf0f0f0f0f0f0f0f0ULL) >> 4)  | ((x & 0x0f0f0f0f0f0f0f0fULL) << 4));
   62     x = (((x & 0xff00ff00ff00ff00ULL) >> 8)  | ((x & 0x00ff00ff00ff00ffULL) << 8));
   63     x = (((x & 0xffff0000ffff0000ULL) >> 16) | ((x & 0x0000ffff0000ffffULL) << 16));
   64     return ((x >> 32) | (x << 32));
   65 }
   66 
   67 /*
   68  *  stress_vm_addr_pwr2()
   69  *  set data on power of 2 addresses
   70  */
   71 static size_t TARGET_CLONES stress_vm_addr_pwr2(
   72     uint8_t *buf,
   73     const size_t sz)
   74 {
   75     size_t n, errs = 0;
   76     uint8_t rnd = mwc8();
   77 
   78     for (n = 1; n < sz; n++) {
   79         *(buf + n) = rnd;
   80     }
   81     for (n = 1; n < sz; n++) {
   82         if (*(buf + n) != rnd)
   83             errs++;
   84     }
   85     return errs;
   86 }
   87 
   88 /*
   89  *  stress_vm_addr_pwr2inv()
   90  *  set data on inverted power of 2 addresses
   91  */
   92 static size_t TARGET_CLONES stress_vm_addr_pwr2inv(
   93     uint8_t *buf,
   94     const size_t sz)
   95 {
   96     size_t mask = sz - 1, n, errs = 0;
   97     uint8_t rnd = mwc8();
   98 
   99     for (n = 1; n < sz; n++) {
  100         *(buf + (n ^ mask)) = rnd;
  101     }
  102     for (n = 1; n < sz; n++) {
  103         if (*(buf + (n ^ mask)) != rnd)
  104             errs++;
  105     }
  106     return errs;
  107 }
  108 
  109 /*
  110  *  stress_vm_addr_gray()
  111  *  set data on gray coded addresses,
  112  *  each address changes by just 1 bit
  113  */
  114 static size_t TARGET_CLONES stress_vm_addr_gray(
  115     uint8_t *buf,
  116     const size_t sz)
  117 {
  118     size_t mask = sz - 1, n, errs = 0;
  119     uint8_t rnd = mwc8();
  120 
  121     for (n = 0; n < sz; n++) {
  122         size_t gray = ((n >> 1) ^ n) & mask;
  123         *(buf + gray) = rnd;
  124     }
  125     for (n = 0; n < sz; n++) {
  126         size_t gray = ((n >> 1) ^ n) & mask;
  127         if (*(buf + gray) != rnd)
  128             errs++;
  129     }
  130     return errs;
  131 }
  132 
  133 /*
  134  *  stress_vm_addr_grayinv()
  135  *  set data on inverted gray coded addresses,
  136  *  each address changes by as many bits possible
  137  */
  138 static size_t TARGET_CLONES stress_vm_addr_grayinv(
  139     uint8_t *buf,
  140     const size_t sz)
  141 {
  142     size_t mask = sz - 1, n, errs = 0;
  143     uint8_t rnd = mwc8();
  144 
  145     for (n = 0; n < sz; n++) {
  146         size_t gray = (((n >> 1) ^ n) ^ mask) & mask;
  147         *(buf + gray) = rnd;
  148     }
  149     for (n = 0; n < sz; n++) {
  150         size_t gray = (((n >> 1) ^ n) ^ mask) & mask;
  151         if (*(buf + gray) != rnd)
  152             errs++;
  153     }
  154     return errs;
  155 }
  156 
  157 /*
  158  *  stress_vm_addr_rev()
  159  *  set data on reverse address bits, for example
  160  *  a 32 bit address range becomes:
  161  *  0x00000001 -> 0x1000000
  162  *  0x00000002 -> 0x2000000
  163  */
  164 static size_t TARGET_CLONES stress_vm_addr_rev(
  165     uint8_t *buf,
  166     const size_t sz)
  167 {
  168     size_t mask = sz - 1, n, errs = 0, shift;
  169     uint8_t rnd = mwc8();
  170 
  171     for (shift = 0, n = sz; n; shift++, n <<= 1)
  172         ;
  173 
  174     for (n = 0; n < sz; n++) {
  175         size_t i = reverse64(n << shift) & mask;
  176         *(buf + i) = rnd;
  177     }
  178     for (n = 0; n < sz; n++) {
  179         size_t i = reverse64(n << shift) & mask;
  180         if (*(buf + i) != rnd)
  181             errs++;
  182     }
  183     return errs;
  184 }
  185 
  186 /*
  187  *  stress_vm_addr_revinv()
  188  *  set data on inverted reverse address bits, for example
  189  *  a 32 bit address range becomes:
  190  *  0x00000001 -> 0xeffffff
  191  *  0x00000002 -> 0xdffffff
  192  */
  193 static size_t TARGET_CLONES stress_vm_addr_revinv(
  194     uint8_t *buf,
  195     const size_t sz)
  196 {
  197     size_t mask = sz - 1, n, errs = 0, shift;
  198     uint8_t rnd = mwc8();
  199 
  200     for (shift = 0, n = sz; n; shift++, n <<= 1)
  201         ;
  202 
  203     for (n = 0; n < sz; n++) {
  204         size_t i = (reverse64(n << shift) ^ mask) & mask;
  205         *(buf + i) = rnd;
  206     }
  207     for (n = 0; n < sz; n++) {
  208         size_t i = (reverse64(n << shift) ^ mask) & mask;
  209         if (*(buf + i) != rnd)
  210             errs++;
  211     }
  212     return errs;
  213 }
  214 
  215 /*
  216  *  stress_vm_addr_inc()
  217  *  set data on incrementing addresses
  218  */
  219 static size_t TARGET_CLONES stress_vm_addr_inc(
  220     uint8_t *buf,
  221     const size_t sz)
  222 {
  223     size_t n, errs = 0;
  224     uint8_t rnd = mwc8();
  225 
  226     for (n = 0; n < sz; n++) {
  227         *(buf + n) = rnd;
  228     }
  229     for (n = 0; n < sz; n++) {
  230         if (*(buf + n) != rnd)
  231             errs++;
  232     }
  233     return errs;
  234 }
  235 
  236 /*
  237  *  stress_vm_addr_inc()
  238  *  set data on inverted incrementing addresses
  239  */
  240 static size_t TARGET_CLONES stress_vm_addr_incinv(
  241     uint8_t *buf,
  242     const size_t sz)
  243 {
  244     size_t mask = sz - 1, n, errs = 0;
  245     uint8_t rnd = mwc8();
  246 
  247     for (n = 0; n < sz; n++) {
  248         size_t i = (n ^ mask) & mask;
  249         *(buf + i) = rnd;
  250     }
  251     for (n = 0; n < sz; n++) {
  252         size_t i = (n ^ mask) & mask;
  253         if (*(buf + i) != rnd)
  254             errs++;
  255     }
  256     return errs;
  257 }
  258 
  259 /*
  260  *  stress_vm_addr_dec()
  261  *  set data on decrementing addresses
  262  */
  263 static size_t TARGET_CLONES stress_vm_addr_dec(
  264     uint8_t *buf,
  265     const size_t sz)
  266 {
  267     size_t n, errs = 0;
  268     uint8_t rnd = mwc8();
  269 
  270     for (n = sz; n; n--) {
  271         *(buf + n - 1) = rnd;
  272     }
  273     for (n = sz; n; n--) {
  274         if (*(buf + n - 1) != rnd)
  275             errs++;
  276     }
  277     return errs;
  278 }
  279 
  280 /*
  281  *  stress_vm_addr_dec()
  282  *  set data on inverted decrementing addresses
  283  */
  284 static size_t TARGET_CLONES stress_vm_addr_decinv(
  285     uint8_t *buf,
  286     const size_t sz)
  287 {
  288     size_t mask = sz - 1, n, errs = 0;
  289     uint8_t rnd = mwc8();
  290 
  291     for (n = sz; n; n--) {
  292         size_t i = ((n - 1) ^ mask) & mask;
  293         *(buf + i) = rnd;
  294     }
  295     for (n = sz; n; n--) {
  296         size_t i = ((n - 1) ^ mask) & mask;
  297         if (*(buf + i) != rnd)
  298             errs++;
  299     }
  300     return errs;
  301 }
  302 
  303 /*
  304  *  stress_vm_addr_all()
  305  *  work through all vm stressors sequentially
  306  */
  307 static size_t stress_vm_addr_all(
  308     uint8_t *buf,
  309     const size_t sz)
  310 {
  311     static int i = 1;
  312     size_t bit_errors = 0;
  313 
  314     bit_errors = vm_addr_methods[i].func(buf, sz);
  315     i++;
  316     if (vm_addr_methods[i].func == NULL)
  317         i = 1;
  318 
  319     return bit_errors;
  320 }
  321 
  322 static const stress_vm_addr_method_info_t vm_addr_methods[] = {
  323     { "all",    stress_vm_addr_all },
  324     { "pwr2",   stress_vm_addr_pwr2 },
  325     { "pwr2inv",    stress_vm_addr_pwr2inv },
  326     { "gray",   stress_vm_addr_gray },
  327     { "grayinv",    stress_vm_addr_grayinv },
  328     { "rev",    stress_vm_addr_rev },
  329     { "revinv", stress_vm_addr_revinv },
  330     { "inc",    stress_vm_addr_inc },
  331     { "incinv", stress_vm_addr_incinv },
  332     { "dec",    stress_vm_addr_dec },
  333     { "decinv", stress_vm_addr_decinv },
  334     { NULL,     NULL  }
  335 };
  336 
  337 /*
  338  *  stress_set_vm_addr_method()
  339  *      set default vm stress method
  340  */
  341 int stress_set_vm_addr_method(const char *name)
  342 {
  343     stress_vm_addr_method_info_t const *info;
  344 
  345     for (info = vm_addr_methods; info->func; info++) {
  346         if (!strcmp(info->name, name)) {
  347             set_setting("vm-addr-method", TYPE_ID_UINTPTR_T, &info);
  348             return 0;
  349         }
  350     }
  351 
  352     (void)fprintf(stderr, "vm-addr-method must be one of:");
  353     for (info = vm_addr_methods; info->func; info++) {
  354         (void)fprintf(stderr, " %s", info->name);
  355     }
  356     (void)fprintf(stderr, "\n");
  357 
  358     return -1;
  359 }
  360 
  361 /*
  362  *  stress_vm_addr()
  363  *  stress virtual memory addressing
  364  */
  365 static int stress_vm_addr(const args_t *args)
  366 {
  367     uint64_t *bit_error_count = MAP_FAILED;
  368     uint32_t restarts = 0, nomems = 0;
  369     uint8_t *buf = NULL;
  370     pid_t pid;
  371         const size_t page_size = args->page_size;
  372     size_t retries;
  373     int err = 0, ret = EXIT_SUCCESS;
  374     const stress_vm_addr_method_info_t *vm_addr_method = &vm_addr_methods[0];
  375     stress_vm_addr_func func;
  376 
  377     (void)get_setting("vm-addr-method", &vm_addr_method);
  378 
  379     func = vm_addr_method->func;
  380     pr_dbg("%s using method '%s'\n", args->name, vm_addr_method->name);
  381 
  382     for (retries = 0; (retries < 100) && g_keep_stressing_flag; retries++) {
  383         bit_error_count = (uint64_t *)
  384             mmap(NULL, page_size, PROT_READ | PROT_WRITE,
  385                 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
  386         err = errno;
  387         if (bit_error_count != MAP_FAILED)
  388             break;
  389         (void)shim_usleep(100);
  390     }
  391 
  392     /* Cannot allocate a single page for bit error counter */
  393     if (bit_error_count == MAP_FAILED) {
  394         if (g_keep_stressing_flag) {
  395             pr_err("%s: could not mmap bit error counter: "
  396                 "retry count=%zu, errno=%d (%s)\n",
  397                 args->name, retries, err, strerror(err));
  398         }
  399         return EXIT_NO_RESOURCE;
  400     }
  401 
  402     *bit_error_count = 0ULL;
  403 
  404 again:
  405     if (!g_keep_stressing_flag)
  406         goto clean_up;
  407     pid = fork();
  408     if (pid < 0) {
  409         if (errno == EAGAIN)
  410             goto again;
  411         pr_err("%s: fork failed: errno=%d: (%s)\n",
  412             args->name, errno, strerror(errno));
  413     } else if (pid > 0) {
  414         int status, waitret;
  415 
  416         /* Parent, wait for child */
  417         (void)setpgid(pid, g_pgrp);
  418         waitret = waitpid(pid, &status, 0);
  419         if (waitret < 0) {
  420             if (errno != EINTR)
  421                 pr_dbg("%s: waitpid(): errno=%d (%s)\n",
  422                     args->name, errno, strerror(errno));
  423             (void)kill(pid, SIGTERM);
  424             (void)kill(pid, SIGKILL);
  425             (void)waitpid(pid, &status, 0);
  426         } else if (WIFSIGNALED(status)) {
  427             pr_dbg("%s: child died: %s (instance %d)\n",
  428                 args->name, stress_strsignal(WTERMSIG(status)),
  429                 args->instance);
  430             /* If we got killed by OOM killer, re-start */
  431             if (WTERMSIG(status) == SIGKILL) {
  432                 log_system_mem_info();
  433                 pr_dbg("%s: assuming killed by OOM killer, "
  434                     "restarting again (instance %d)\n",
  435                     args->name, args->instance);
  436                 restarts++;
  437                 goto again;
  438             }
  439         }
  440     } else if (pid == 0) {
  441         int no_mem_retries = 0;
  442         void *vm_base_addr;
  443         size_t buf_sz;
  444 
  445         (void)setpgid(0, g_pgrp);
  446         stress_parent_died_alarm();
  447 
  448         /* Make sure this is killable by OOM killer */
  449         set_oom_adjustment(args->name, true);
  450 
  451         buf_sz = MIN_VM_ADDR_BYTES;
  452 
  453         do {
  454             vm_base_addr = (void *)buf_sz;
  455 
  456             if (no_mem_retries >= NO_MEM_RETRIES_MAX) {
  457                 pr_err("%s: gave up trying to mmap, no available memory\n",
  458                     args->name);
  459                 break;
  460             }
  461 
  462             buf = (uint8_t *)mmap(vm_base_addr, buf_sz,
  463                 PROT_READ | PROT_WRITE,
  464                 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  465             if (buf == MAP_FAILED) {
  466                 buf = NULL;
  467                 no_mem_retries++;
  468                 (void)shim_usleep(100000);
  469                 goto next;  /* Try again */
  470             }
  471 
  472             no_mem_retries = 0;
  473             *bit_error_count += func(buf, buf_sz);
  474             (void)munmap((void *)buf, buf_sz);
  475 next:
  476             buf_sz <<= 1;
  477             if (buf_sz > MAX_VM_ADDR_BYTES)
  478                 buf_sz = MIN_VM_ADDR_BYTES;
  479             inc_counter(args);
  480         } while (keep_stressing_vm(args));
  481 
  482         _exit(EXIT_SUCCESS);
  483     }
  484 clean_up:
  485     if (*bit_error_count > 0) {
  486         pr_fail("%s: detected %" PRIu64 " bit errors while "
  487             "stressing memory\n",
  488             args->name, *bit_error_count);
  489         ret = EXIT_FAILURE;
  490     }
  491     (void)munmap((void *)bit_error_count, page_size);
  492 
  493     if (restarts + nomems > 0)
  494         pr_dbg("%s: OOM restarts: %" PRIu32
  495             ", out of memory restarts: %" PRIu32 ".\n",
  496             args->name, restarts, nomems);
  497 
  498     return ret;
  499 }
  500 
  501 stressor_info_t stress_vm_addr_info = {
  502     .stressor = stress_vm_addr,
  503     .class = CLASS_VM | CLASS_MEMORY | CLASS_OS
  504 };