"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.60/stress-memrate.c" (22 Jun 2019, 10093 Bytes) of package /linux/privat/stress-ng-0.09.60.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-memrate.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.09.59.1_vs_0.09.60.

    1 /*
    2  * Copyright (C) 2016-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 static const help_t help[] = {
   28     { NULL, "memrate N",        "start N workers exercised memory read/writes" },
   29     { NULL, "memrate-ops N",    "stop after N memrate bogo operations" },
   30     { NULL, "memrate-bytes N",  "size of memory buffer being exercised" },
   31     { NULL, "memrate-rd-mbs N", "read rate from buffer in megabytes per second" },
   32     { NULL, "memrate-wr-mbs N", "write rate to buffer in megabytes per second" },
   33     { NULL, NULL,           NULL }
   34 };
   35 
   36 typedef uint64_t (*memrate_func_t)(void *start, void *end, uint64_t rd_mbs, uint64_t wr_mbs);
   37 
   38 typedef struct {
   39     const char  *name;
   40     memrate_func_t  func;
   41 } memrate_info_t;
   42 
   43 typedef struct {
   44     double      duration;
   45     double      mbytes;
   46 } memrate_stats_t;
   47 
   48 static int stress_set_memrate_bytes(const char *opt)
   49 {
   50     uint64_t memrate_bytes;
   51 
   52     memrate_bytes = get_uint64_byte(opt);
   53     check_range_bytes("memrate-bytes", memrate_bytes,
   54         MIN_MEMRATE_BYTES, MAX_MEMRATE_BYTES);
   55     return set_setting("memrate-bytes", TYPE_ID_UINT64, &memrate_bytes);
   56 }
   57 
   58 static int stress_set_memrate_rd_mbs(const char *opt)
   59 {
   60     uint64_t memrate_rd_mbs;
   61 
   62     memrate_rd_mbs = get_uint64(opt);
   63     check_range_bytes("memrate-rd-mbs", memrate_rd_mbs,
   64         1, 1000000);
   65     return set_setting("memrate-rd-mbs", TYPE_ID_UINT64, &memrate_rd_mbs);
   66 }
   67 
   68 static int stress_set_memrate_wr_mbs(const char *opt)
   69 {
   70     uint64_t memrate_wr_mbs;
   71 
   72     memrate_wr_mbs = get_uint64(opt);
   73     check_range_bytes("memrate-wr-mbs", memrate_wr_mbs,
   74         1, 1000000);
   75     return set_setting("memrate-wr-mbs", TYPE_ID_UINT64, &memrate_wr_mbs);
   76 }
   77 
   78 #define STRESS_MEMRATE_READ(size)               \
   79 static uint64_t stress_memrate_read##size(          \
   80     void *start,                        \
   81     void *end,                      \
   82     uint64_t rd_mbs,                    \
   83     uint64_t wr_mbs)                    \
   84 {                               \
   85     register volatile uint##size##_t *ptr;          \
   86     double t1;                      \
   87     const double dur = 1.0 / (double)rd_mbs;        \
   88     double total_dur = 0.0;                 \
   89                                 \
   90     (void)wr_mbs;                       \
   91                                 \
   92     t1 = time_now();                    \
   93     for (ptr = start; ptr < (uint##size##_t *)end;) {   \
   94         double t2, dur_remainder;               \
   95         int32_t i;                  \
   96                                 \
   97         if (!g_keep_stressing_flag)         \
   98             break;                  \
   99         for (i = 0; (i < (int32_t)MB) &&        \
  100              (ptr < (uint##size##_t *)end);     \
  101              ptr += 8, i += size) {         \
  102             (void)(ptr[0]);             \
  103             (void)(ptr[1]);             \
  104             (void)(ptr[2]);             \
  105             (void)(ptr[3]);             \
  106             (void)(ptr[4]);             \
  107             (void)(ptr[5]);             \
  108             (void)(ptr[6]);             \
  109             (void)(ptr[7]);             \
  110         }                       \
  111         t2 = time_now();                \
  112         total_dur += dur;               \
  113         dur_remainder = total_dur - (t2 - t1);      \
  114                                 \
  115         if (dur_remainder >= 0.0) {             \
  116             struct timespec t;          \
  117                                 \
  118             t.tv_sec = (time_t)dur_remainder;       \
  119             t.tv_nsec = (dur_remainder -        \
  120                 (long)dur_remainder) * 1000000000;  \
  121             (void)nanosleep(&t, NULL);      \
  122         }                       \
  123     }                           \
  124     return ((volatile void *)ptr - start) / MB;     \
  125 }
  126 
  127 STRESS_MEMRATE_READ(64)
  128 STRESS_MEMRATE_READ(32)
  129 STRESS_MEMRATE_READ(16)
  130 STRESS_MEMRATE_READ(8)
  131 
  132 #define STRESS_MEMRATE_WRITE(size)              \
  133 static uint64_t stress_memrate_write##size(         \
  134     void *start,                        \
  135     void *end,                      \
  136     uint64_t rd_mbs,                    \
  137     uint64_t wr_mbs)                    \
  138 {                               \
  139     register volatile uint##size##_t *ptr;          \
  140     double t1;                      \
  141     const double dur = 1.0 / (double)wr_mbs;        \
  142     double total_dur = 0.0;                 \
  143                                 \
  144     (void)rd_mbs;                       \
  145                                 \
  146     t1 = time_now();                    \
  147     for (ptr = start; ptr < (uint##size##_t *)end;) {   \
  148         double t2, dur_remainder;               \
  149         int32_t i;                  \
  150                                 \
  151         if (!g_keep_stressing_flag)         \
  152             break;                  \
  153         for (i = 0; (i < (int32_t)MB) &&        \
  154              (ptr < (uint##size##_t *)end);     \
  155              ptr += 8, i += size) {         \
  156             ptr[0] = i;             \
  157             ptr[1] = i;             \
  158             ptr[2] = i;             \
  159             ptr[3] = i;             \
  160             ptr[4] = i;             \
  161             ptr[5] = i;             \
  162             ptr[6] = i;             \
  163             ptr[7] = i;             \
  164         }                       \
  165         t2 = time_now();                \
  166         total_dur += dur;               \
  167         dur_remainder = total_dur - (t2 - t1);      \
  168                                 \
  169         if (dur_remainder >= 0.0) {         \
  170             struct timespec t;          \
  171                                 \
  172             t.tv_sec = (time_t)dur_remainder;   \
  173             t.tv_nsec = (dur_remainder -        \
  174                 (long)dur_remainder) * 1000000000;\
  175             (void)nanosleep(&t, NULL);      \
  176         }                       \
  177     }                           \
  178     return ((volatile void *)ptr - start) / MB;     \
  179 }
  180 
  181 STRESS_MEMRATE_WRITE(64)
  182 STRESS_MEMRATE_WRITE(32)
  183 STRESS_MEMRATE_WRITE(16)
  184 STRESS_MEMRATE_WRITE(8)
  185 
  186 static memrate_info_t memrate_info[] = {
  187     { "write64",    stress_memrate_write64 },
  188     { "read64", stress_memrate_read64 },
  189     { "write32",    stress_memrate_write32 },
  190     { "read32", stress_memrate_read32 },
  191     { "write16",    stress_memrate_write16 },
  192     { "read16", stress_memrate_read16 },
  193     { "write8", stress_memrate_write8 },
  194     { "read8",  stress_memrate_read8 }
  195 };
  196 
  197 static void OPTIMIZE3 stress_memrate_init_data(
  198     void *start,
  199     void *end)
  200 {
  201     register volatile uint32_t *ptr;
  202 
  203     for (ptr = start; ptr < (uint32_t *)end; ptr++)
  204         *ptr = mwc32();
  205 }
  206 
  207 static inline void *stress_memrate_mmap(const args_t *args, uint64_t sz)
  208 {
  209     void *ptr;
  210 
  211     ptr = mmap(NULL, (size_t)sz, PROT_READ | PROT_WRITE,
  212 #if defined(MAP_POPULATE)
  213         MAP_POPULATE |
  214 #endif
  215 #if defined(HAVE_MADVISE)
  216         MAP_PRIVATE |
  217 #else
  218         MAP_SHARED |
  219 #endif
  220         MAP_ANONYMOUS, -1, 0);
  221     /* Coverity Scan believes NULL can be returned, doh */
  222     if (!ptr || (ptr == MAP_FAILED)) {
  223         pr_err("%s: cannot allocate %" PRIu64 " bytes\n",
  224             args->name, sz);
  225         ptr = MAP_FAILED;
  226     } else {
  227 #if defined(HAVE_MADVISE)
  228         int ret, advice = MADV_NORMAL;
  229 
  230         (void)get_setting("memrate-madvise", &advice);
  231 
  232         ret = madvise(ptr, sz, advice);
  233         (void)ret;
  234 #endif
  235     }
  236     return ptr;
  237 }
  238 
  239 /*
  240  *  stress_memrate()
  241  *  stress cache/memory/CPU with memrate stressors
  242  */
  243 static int stress_memrate(const args_t *args)
  244 {
  245     int rc;
  246     uint64_t memrate_bytes  = DEFAULT_MEMRATE_BYTES;
  247     uint64_t memrate_rd_mbs = ~0;
  248     uint64_t memrate_wr_mbs = ~0;
  249     size_t i;
  250     pid_t pid;
  251     memrate_stats_t *stats;
  252     size_t stats_size;
  253     const size_t memrate_items = SIZEOF_ARRAY(memrate_info);
  254     bool lock = false;
  255 
  256     (void)get_setting("memrate-bytes", &memrate_bytes);
  257     (void)get_setting("memrate-rd-mbs", &memrate_rd_mbs);
  258     (void)get_setting("memrate-wr-mbs", &memrate_wr_mbs);
  259 
  260     stats_size = memrate_items * sizeof(memrate_stats_t);
  261     stats_size = (stats_size + args->page_size - 1) & ~(args->page_size - 1);
  262 
  263     stats = (memrate_stats_t *)mmap(NULL, stats_size,
  264         PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
  265     if (stats == MAP_FAILED)
  266         return EXIT_NO_RESOURCE;
  267     for (i = 0; i < memrate_items; i++) {
  268         stats[i].duration = 0.0;
  269         stats[i].mbytes = 0.0;
  270     }
  271 
  272     memrate_bytes = (memrate_bytes + 63) & ~(63);
  273 again:
  274     if (!g_keep_stressing_flag) {
  275         rc = EXIT_NO_RESOURCE;
  276         goto err;
  277     }
  278 
  279     pid = fork();
  280     if (pid < 0) {
  281         if ((errno == EAGAIN) || (errno == ENOMEM))
  282             goto again;
  283     } else if (pid > 0) {
  284         int status, waitret;
  285 
  286         /* Parent, wait for child */
  287         (void)setpgid(pid, g_pgrp);
  288         waitret = shim_waitpid(pid, &status, 0);
  289         if (waitret < 0) {
  290             if (errno != EINTR)
  291                 pr_dbg("%s: waitpid(): errno=%d (%s)\n",
  292                     args->name, errno, strerror(errno));
  293             (void)kill(pid, SIGTERM);
  294             (void)kill(pid, SIGKILL);
  295             (void)shim_waitpid(pid, &status, 0);
  296         } else if (WIFSIGNALED(status)) {
  297             pr_dbg("%s: child died: %s (instance %d)\n",
  298                 args->name, stress_strsignal(WTERMSIG(status)),
  299                 args->instance);
  300             /* If we got killed by OOM killer, re-start */
  301             if (WTERMSIG(status) == SIGKILL) {
  302                 log_system_mem_info();
  303                 pr_dbg("%s: assuming killed by OOM killer, "
  304                     "restarting again (instance %d)\n",
  305                     args->name, args->instance);
  306                 goto again;
  307             }
  308         }
  309     } else {
  310         /* Child */
  311         void *buffer, *buffer_end;
  312 
  313         (void)setpgid(0, g_pgrp);
  314         stress_parent_died_alarm();
  315 
  316         /* Make sure this is killable by OOM killer */
  317         set_oom_adjustment(args->name, true);
  318 
  319         buffer = stress_memrate_mmap(args, memrate_bytes);
  320         if (buffer == MAP_FAILED)
  321             _exit(EXIT_NO_RESOURCE);
  322         buffer_end = (uint8_t *)buffer + memrate_bytes;
  323 
  324         stress_memrate_init_data(buffer, buffer_end);
  325 
  326         do {
  327             for (i = 0; keep_stressing() && (i < memrate_items); i++) {
  328                 double t1, t2;
  329                 memrate_info_t *info = &memrate_info[i];
  330 
  331                 t1 = time_now();
  332                 stats[i].mbytes += info->func(buffer, buffer_end,
  333                     memrate_rd_mbs, memrate_wr_mbs);
  334                 t2 = time_now();
  335                 stats[i].duration += (t2 - t1);
  336 
  337                 if (!keep_stressing())
  338                     break;
  339             }
  340 
  341             inc_counter(args);
  342         } while (keep_stressing());
  343 
  344         (void)munmap(buffer, memrate_bytes);
  345         _exit(EXIT_SUCCESS);
  346     }
  347 
  348     pr_lock(&lock);
  349     for (i = 0; i < memrate_items; i++) {
  350         if (stats[i].duration > 0.001)
  351             pr_inf_lock(&lock, "%s: %7.7s: %.2f MB/sec\n",
  352                 args->name, memrate_info[i].name,
  353                 stats[i].mbytes / stats[i].duration);
  354         else
  355             pr_inf_lock(&lock, "%s: %7.7s: interrupted early\n",
  356                 args->name, memrate_info[i].name);
  357     }
  358     pr_unlock(&lock);
  359 
  360     rc = EXIT_SUCCESS;
  361 err:
  362     (void)munmap((void *)stats, stats_size);
  363 
  364     return rc;
  365 }
  366 
  367 static const opt_set_func_t opt_set_funcs[] = {
  368     { OPT_memrate_bytes,    stress_set_memrate_bytes },
  369     { OPT_memrate_rd_mbs,   stress_set_memrate_rd_mbs },
  370     { OPT_memrate_wr_mbs,   stress_set_memrate_wr_mbs },
  371     { 0,            NULL }
  372 };
  373 
  374 stressor_info_t stress_memrate_info = {
  375     .stressor = stress_memrate,
  376     .class = CLASS_MEMORY,
  377     .opt_set_funcs = opt_set_funcs,
  378     .help = help
  379 };