"Fossies" - the Fresh Open Source Software Archive

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

    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 int stress_set_malloc_bytes(const char *opt)
   28 {
   29     size_t malloc_bytes;
   30 
   31     malloc_bytes = (size_t)get_uint64_byte_memory(opt, 1);
   32     check_range_bytes("malloc-bytes", malloc_bytes,
   33         MIN_MALLOC_BYTES, MAX_MEM_LIMIT);
   34     return set_setting("malloc-bytes", TYPE_ID_SIZE_T, &malloc_bytes);
   35 }
   36 
   37 int stress_set_malloc_max(const char *opt)
   38 {
   39     size_t malloc_max;
   40 
   41     malloc_max = (size_t)get_uint64_byte(opt);
   42     check_range("malloc-max", malloc_max,
   43         MIN_MALLOC_MAX, MAX_MALLOC_MAX);
   44     return set_setting("malloc-max", TYPE_ID_SIZE_T, &malloc_max);
   45 }
   46 
   47 int stress_set_malloc_threshold(const char *opt)
   48 {
   49     size_t malloc_threshold;
   50 
   51     malloc_threshold = (size_t)get_uint64_byte(opt);
   52     check_range("malloc-threshold", malloc_threshold,
   53         MIN_MALLOC_THRESHOLD, MAX_MALLOC_THRESHOLD);
   54     return set_setting("malloc-threshold", TYPE_ID_SIZE_T, &malloc_threshold);
   55 }
   56 
   57 /*
   58  *  stress_alloc_size()
   59  *  get a new allocation size, ensuring
   60  *  it is never zero bytes.
   61  */
   62 static inline size_t stress_alloc_size(const size_t malloc_bytes)
   63 {
   64     const size_t len = mwc64() % malloc_bytes;
   65 
   66     return len ? len : 1;
   67 }
   68 
   69 /*
   70  *  stress_malloc()
   71  *  stress malloc by performing a mix of
   72  *  allocation and frees
   73  */
   74 static int stress_malloc(const args_t *args)
   75 {
   76     pid_t pid;
   77     uint32_t restarts = 0, nomems = 0;
   78     size_t malloc_bytes = DEFAULT_MALLOC_BYTES;
   79     size_t malloc_max = DEFAULT_MALLOC_MAX;
   80 #if defined(__GNUC__) && defined(M_MMAP_THRESHOLD) && defined(HAVE_MALLOPT)
   81     size_t malloc_threshold = DEFAULT_MALLOC_THRESHOLD;
   82 #endif
   83 
   84     if (!get_setting("malloc-bytes", &malloc_bytes)) {
   85         if (g_opt_flags & OPT_FLAGS_MAXIMIZE)
   86             malloc_bytes = MAX_MALLOC_BYTES;
   87         if (g_opt_flags & OPT_FLAGS_MINIMIZE)
   88             malloc_bytes = MIN_MALLOC_BYTES;
   89     }
   90 
   91     malloc_bytes /= args->num_instances;
   92     if (malloc_bytes < MIN_MALLOC_BYTES)
   93         malloc_bytes = MIN_MALLOC_BYTES;
   94 
   95     if (!get_setting("malloc-max", &malloc_max)) {
   96         if (g_opt_flags & OPT_FLAGS_MAXIMIZE)
   97             malloc_max = MAX_MALLOC_MAX;
   98         if (g_opt_flags & OPT_FLAGS_MINIMIZE)
   99             malloc_max = MIN_MALLOC_MAX;
  100     }
  101 
  102 #if defined(__GNUC__) && defined(M_MMAP_THRESHOLD) && defined(HAVE_MALLOPT)
  103     if (get_setting("malloc-threshold", &malloc_threshold))
  104         (void)mallopt(M_MMAP_THRESHOLD, (int)malloc_threshold);
  105 #endif
  106 
  107 again:
  108     pid = fork();
  109     if (pid < 0) {
  110         if (g_keep_stressing_flag &&
  111             ((errno == EAGAIN) || (errno == ENOMEM)))
  112             goto again;
  113         pr_err("%s: fork failed: errno=%d: (%s)\n",
  114             args->name, errno, strerror(errno));
  115     } else if (pid > 0) {
  116         int status, ret;
  117 
  118         (void)setpgid(pid, g_pgrp);
  119         stress_parent_died_alarm();
  120 
  121         /* Parent, wait for child */
  122         ret = waitpid(pid, &status, 0);
  123         if (ret < 0) {
  124             if (errno != EINTR)
  125                 pr_dbg("%s: waitpid(): errno=%d (%s)\n",
  126                     args->name, errno, strerror(errno));
  127             (void)kill(pid, SIGTERM);
  128             (void)kill(pid, SIGKILL);
  129             (void)waitpid(pid, &status, 0);
  130         } else if (WIFSIGNALED(status)) {
  131             pr_dbg("%s: child died: %s (instance %d)\n",
  132                 args->name, stress_strsignal(WTERMSIG(status)),
  133                 args->instance);
  134             /* If we got killed by OOM killer, re-start */
  135             if (WTERMSIG(status) == SIGKILL) {
  136                 if (g_opt_flags & OPT_FLAGS_OOMABLE) {
  137                     log_system_mem_info();
  138                     pr_dbg("%s: assuming killed by OOM "
  139                         "killer, bailing out "
  140                         "(instance %d)\n",
  141                         args->name, args->instance);
  142                     _exit(0);
  143                 } else {
  144                         log_system_mem_info();
  145                         pr_dbg("%s: assuming killed by OOM "
  146                             "killer, restarting again "
  147                             "(instance %d)\n",
  148                             args->name, args->instance);
  149                         restarts++;
  150                         goto again;
  151                 }
  152             }
  153         }
  154     } else if (pid == 0) {
  155         void *addr[malloc_max];
  156         size_t j;
  157 
  158         (void)setpgid(0, g_pgrp);
  159         (void)memset(addr, 0, sizeof(addr));
  160 
  161         /* Make sure this is killable by OOM killer */
  162         set_oom_adjustment(args->name, true);
  163 
  164         do {
  165             const unsigned int rnd = mwc32();
  166             const unsigned int i = rnd % malloc_max;
  167             const unsigned int action = (rnd >> 12) & 1;
  168             const unsigned int do_calloc = (rnd >> 14) & 0x1f;
  169 
  170             /*
  171              * With many instances running it is wise to
  172              * double check before the next allocation as
  173              * sometimes process start up is delayed for
  174              * some time and we should bail out before
  175              * exerting any more memory pressure
  176              */
  177             if (!g_keep_stressing_flag)
  178                 goto abort;
  179 
  180             if (addr[i]) {
  181                 /* 50% free, 50% realloc */
  182                 if (action) {
  183                     free(addr[i]);
  184                     addr[i] = NULL;
  185                     inc_counter(args);
  186                 } else {
  187                     void *tmp;
  188                     const size_t len = stress_alloc_size(malloc_bytes);
  189 
  190                     tmp = realloc(addr[i], len);
  191                     if (tmp) {
  192                         addr[i] = tmp;
  193                         (void)mincore_touch_pages(addr[i], len);
  194                         inc_counter(args);
  195                     }
  196                 }
  197             } else {
  198                 /* 50% free, 50% alloc */
  199                 if (action) {
  200                     size_t len = stress_alloc_size(malloc_bytes);
  201 
  202                     if (do_calloc == 0) {
  203                         size_t n = ((rnd >> 15) % 17) + 1;
  204                         addr[i] = calloc(n, len / n);
  205                         len = n * (len / n);
  206                     } else {
  207                         addr[i] = malloc(len);
  208                     }
  209                     if (addr[i]) {
  210                         inc_counter(args);
  211                         (void)mincore_touch_pages(addr[i], len);
  212                     }
  213                 }
  214             }
  215         } while (keep_stressing());
  216 abort:
  217         for (j = 0; j < malloc_max; j++) {
  218             free(addr[j]);
  219         }
  220     }
  221     if (restarts + nomems > 0)
  222         pr_dbg("%s: OOM restarts: %" PRIu32
  223             ", out of memory restarts: %" PRIu32 ".\n",
  224             args->name, restarts, nomems);
  225 
  226     return EXIT_SUCCESS;
  227 }
  228 
  229 stressor_info_t stress_malloc_info = {
  230     .stressor = stress_malloc,
  231     .class = CLASS_CPU_CACHE | CLASS_MEMORY | CLASS_VM | CLASS_OS
  232 };