"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-madvise.c" (15 Mar 2019, 6628 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-madvise.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 #if defined(HAVE_MADVISE)
   28 
   29 #define NUM_MEM_RETRIES_MAX (256)
   30 #define NUM_POISON_MAX      (2)
   31 #define NUM_SOFT_OFFLINE_MAX    (2)
   32 
   33 static sigjmp_buf jmp_env;
   34 static uint64_t sigbus_count;
   35 
   36 static const int madvise_options[] = {
   37 #if defined(MADV_NORMAL)
   38     MADV_NORMAL,
   39 #endif
   40 #if defined(MADV_RANDOM)
   41     MADV_RANDOM,
   42 #endif
   43 #if defined(MADV_SEQUENTIAL)
   44     MADV_SEQUENTIAL,
   45 #endif
   46 #if defined(MADV_WILLNEED)
   47     MADV_WILLNEED,
   48 #endif
   49 #if defined(MADV_DONTNEED)
   50     MADV_DONTNEED,
   51 #endif
   52 #if defined(MADV_REMOVE)
   53     MADV_REMOVE,
   54 #endif
   55 #if defined(MADV_DONTFORK)
   56     MADV_DONTFORK,
   57 #endif
   58 #if defined(MADV_DOFORK)
   59     MADV_DOFORK,
   60 #endif
   61 #if defined(MADV_MERGEABLE)
   62     MADV_MERGEABLE,
   63 #endif
   64 #if defined(MADV_UNMERGEABLE)
   65     MADV_UNMERGEABLE,
   66 #endif
   67 #if defined(MADV_SOFT_OFFLINE)
   68     MADV_SOFT_OFFLINE,
   69 #endif
   70 #if defined(MADV_HUGEPAGE)
   71     MADV_HUGEPAGE,
   72 #endif
   73 #if defined(MADV_NOHUGEPAGE)
   74     MADV_NOHUGEPAGE,
   75 #endif
   76 #if defined(MADV_DONTDUMP)
   77     MADV_DONTDUMP,
   78 #endif
   79 #if defined(MADV_DODUMP)
   80     MADV_DODUMP,
   81 #endif
   82 #if defined(MADV_FREE)
   83     MADV_FREE,
   84 #endif
   85 #if defined(MADV_HWPOISON)
   86     MADV_HWPOISON,
   87 #endif
   88 #if defined(MADV_WIPEONFORK)
   89     MADV_WIPEONFORK,
   90 #endif
   91 #if defined(MADV_KEEPONFORK)
   92     MADV_KEEPONFORK,
   93 #endif
   94 #if defined(MADV_INHERIT_ZERO)
   95     MADV_INHERIT_ZERO,
   96 #endif
   97 };
   98 
   99 /*
  100  *  stress_sigbus_handler()
  101  *     SIGBUS handler
  102  */
  103 static void MLOCKED_TEXT stress_sigbus_handler(int signum)
  104 {
  105     (void)signum;
  106 
  107     sigbus_count++;
  108 
  109     siglongjmp(jmp_env, 1); /* bounce back */
  110 }
  111 
  112 /*
  113  *  stress_random_advise()
  114  *  get a random advise option
  115  */
  116 static int stress_random_advise(const args_t *args)
  117 {
  118     const int idx = mwc32() % SIZEOF_ARRAY(madvise_options);
  119     const int advise = madvise_options[idx];
  120 #if defined(MADV_HWPOISON) || defined(MADV_SOFT_OFFLINE)
  121     static int poison_count;
  122 #if defined(MADV_NORMAL)
  123     const int madv_normal = MADV_NORMAL;
  124 #else
  125     const int madv_normal = 0;
  126 #endif
  127 #endif
  128 
  129 #if defined(MADV_HWPOISON)
  130     if (advise == MADV_HWPOISON) {
  131         /*
  132          * Try for another madvise option if
  133          * we've poisoned too many pages.
  134          * We really need to use this sparingly
  135          * else we run out of free memory
  136          */
  137         if ((args->instance > 0) ||
  138             (poison_count >= NUM_POISON_MAX))
  139             return madv_normal;
  140         poison_count++;
  141     }
  142 #else
  143     (void)args;
  144 #endif
  145 
  146 #if defined(MADV_SOFT_OFFLINE)
  147     if (advise == MADV_SOFT_OFFLINE) {
  148         static int soft_offline_count;
  149 
  150         /* ..and minimize number of soft offline pages */
  151         if ((soft_offline_count >= NUM_SOFT_OFFLINE_MAX) ||
  152             (poison_count >= NUM_POISON_MAX))
  153             return madv_normal;
  154         soft_offline_count++;
  155     }
  156 #endif
  157     return advise;
  158 }
  159 
  160 /*
  161  *  stress_madvise()
  162  *  stress madvise
  163  */
  164 static int stress_madvise(const args_t *args)
  165 {
  166     const size_t page_size = args->page_size;
  167     NOCLOBBER size_t sz = 4 *  MB;
  168     int fd = -1;
  169     NOCLOBBER int ret;
  170     NOCLOBBER int flags = MAP_PRIVATE;
  171     NOCLOBBER int num_mem_retries = 0;
  172     char filename[PATH_MAX];
  173     char page[page_size];
  174     size_t n;
  175 
  176 #if defined(MAP_POPULATE)
  177     flags |= MAP_POPULATE;
  178 #endif
  179     ret = sigsetjmp(jmp_env, 1);
  180     if (ret) {
  181         pr_fail_err("sigsetjmp");
  182         return EXIT_FAILURE;
  183     }
  184     if (stress_sighandler(args->name, SIGBUS, stress_sigbus_handler, NULL) < 0)
  185         return EXIT_FAILURE;
  186 
  187     sz &= ~(page_size - 1);
  188 
  189     /* Make sure this is killable by OOM killer */
  190     set_oom_adjustment(args->name, true);
  191 
  192     (void)memset(page, 0xa5, page_size);
  193 
  194     ret = stress_temp_dir_mk_args(args);
  195     if (ret < 0)
  196         return exit_status(-ret);
  197 
  198     (void)stress_temp_filename_args(args,
  199         filename, sizeof(filename), mwc32());
  200 
  201     if ((fd = open(filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) {
  202         ret = exit_status(errno);
  203         pr_fail_err("open");
  204         (void)unlink(filename);
  205         (void)stress_temp_dir_rm_args(args);
  206         return ret;
  207     }
  208 
  209     (void)unlink(filename);
  210     for (n = 0; n < sz; n += page_size) {
  211         ret = write(fd, page, sizeof(page));
  212         (void)ret;
  213     }
  214 
  215     do {
  216         NOCLOBBER void *buf;
  217 
  218         if (num_mem_retries >= NUM_MEM_RETRIES_MAX) {
  219             pr_err("%s: gave up trying to mmap, no available memory\n",
  220                 args->name);
  221             break;
  222         }
  223 
  224         if (!g_keep_stressing_flag)
  225             break;
  226 
  227         if (mwc1()) {
  228             buf = mmap(NULL, sz, PROT_READ | PROT_WRITE, flags, fd, 0);
  229         } else {
  230             buf = mmap(NULL, sz, PROT_READ | PROT_WRITE,
  231                 flags | MAP_ANONYMOUS, 0, 0);
  232         }
  233         if (buf == MAP_FAILED) {
  234             /* Force MAP_POPULATE off, just in case */
  235 #if defined(MAP_POPULATE)
  236             flags &= ~MAP_POPULATE;
  237 #endif
  238             num_mem_retries++;
  239             if (num_mem_retries > 1)
  240                 (void)shim_usleep(100000);
  241             continue;   /* Try again */
  242         }
  243         ret = sigsetjmp(jmp_env, 1);
  244         if (ret) {
  245             (void)munmap((void *)buf, sz);
  246             /* Try again */
  247             continue;
  248         }
  249 
  250         (void)memset(buf, 0xff, sz);
  251 
  252         (void)madvise_random(buf, sz);
  253         (void)mincore_touch_pages(buf, sz);
  254 
  255         for (n = 0; n < sz; n += page_size) {
  256             const int advise = stress_random_advise(args);
  257 
  258             (void)shim_madvise(buf + n, page_size, advise);
  259             (void)shim_msync(buf + n, page_size, MS_ASYNC);
  260         }
  261         for (n = 0; n < sz; n += page_size) {
  262             size_t m = (mwc64() % sz) & ~(page_size - 1);
  263             const int advise = stress_random_advise(args);
  264 
  265             (void)shim_madvise(buf + m, page_size, advise);
  266             (void)shim_msync(buf + m, page_size, MS_ASYNC);
  267         }
  268         (void)munmap((void *)buf, sz);
  269         inc_counter(args);
  270     } while (keep_stressing());
  271 
  272     (void)close(fd);
  273     (void)stress_temp_dir_rm_args(args);
  274 
  275     if (sigbus_count)
  276         pr_inf("%s: caught %" PRIu64 " SIGBUS signals\n",
  277             args->name, sigbus_count);
  278     return EXIT_SUCCESS;
  279 }
  280 
  281 stressor_info_t stress_madvise_info = {
  282     .stressor = stress_madvise,
  283     .class = CLASS_VM | CLASS_OS
  284 };
  285 #else
  286 stressor_info_t stress_madvise_info = {
  287     .stressor = stress_not_implemented,
  288     .class = CLASS_VM | CLASS_OS
  289 };
  290 #endif