"Fossies" - the Fresh Open Source Software Archive

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